mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 06:42:12 +00:00
Merge remote-tracking branch 'origin/polybackend'
This commit is contained in:
commit
eaab122076
73 changed files with 3991 additions and 10161 deletions
|
@ -462,7 +462,8 @@ set( PLAT_WIN32_SOURCES
|
|||
win32/gl_sysfb.cpp
|
||||
win32/base_sysfb.cpp
|
||||
win32/win32basevideo.cpp
|
||||
win32/win32glvideo.cpp)
|
||||
win32/win32glvideo.cpp
|
||||
win32/win32polyvideo.cpp)
|
||||
|
||||
if (HAVE_VULKAN)
|
||||
set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} win32/win32vulkanvideo.cpp )
|
||||
|
@ -634,7 +635,7 @@ file( GLOB HEADER_FILES
|
|||
rendering/polyrenderer/*.h
|
||||
rendering/polyrenderer/math/*.h
|
||||
rendering/polyrenderer/drawers/*.h
|
||||
rendering/polyrenderer/scene/*.h
|
||||
rendering/polyrenderer/backend/*.h
|
||||
rendering/hwrenderer/data/*.h
|
||||
rendering/hwrenderer/dynlights/*.h
|
||||
rendering/hwrenderer/models/*.h
|
||||
|
@ -706,24 +707,7 @@ set ( SWRENDER_SOURCES
|
|||
)
|
||||
|
||||
set( POLYRENDER_SOURCES
|
||||
rendering/polyrenderer/poly_renderer.cpp
|
||||
rendering/polyrenderer/poly_renderthread.cpp
|
||||
rendering/polyrenderer/scene/poly_scene.cpp
|
||||
rendering/polyrenderer/scene/poly_portal.cpp
|
||||
rendering/polyrenderer/scene/poly_cull.cpp
|
||||
rendering/polyrenderer/scene/poly_decal.cpp
|
||||
rendering/polyrenderer/scene/poly_particle.cpp
|
||||
rendering/polyrenderer/scene/poly_plane.cpp
|
||||
rendering/polyrenderer/scene/poly_playersprite.cpp
|
||||
rendering/polyrenderer/scene/poly_wall.cpp
|
||||
rendering/polyrenderer/scene/poly_wallsprite.cpp
|
||||
rendering/polyrenderer/scene/poly_sprite.cpp
|
||||
rendering/polyrenderer/scene/poly_model.cpp
|
||||
rendering/polyrenderer/scene/poly_sky.cpp
|
||||
rendering/polyrenderer/scene/poly_light.cpp
|
||||
rendering/polyrenderer/drawers/poly_buffer.cpp
|
||||
rendering/polyrenderer/drawers/poly_triangle.cpp
|
||||
rendering/polyrenderer/drawers/poly_draw_args.cpp
|
||||
rendering/polyrenderer/drawers/screen_triangle.cpp
|
||||
rendering/polyrenderer/math/gpu_types.cpp
|
||||
)
|
||||
|
@ -822,6 +806,14 @@ if (HAVE_VULKAN)
|
|||
set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES})
|
||||
endif()
|
||||
|
||||
set (POLYBACKEND_SOURCES
|
||||
rendering/polyrenderer/backend/poly_framebuffer.cpp
|
||||
rendering/polyrenderer/backend/poly_buffers.cpp
|
||||
rendering/polyrenderer/backend/poly_hwtexture.cpp
|
||||
rendering/polyrenderer/backend/poly_renderstate.cpp
|
||||
)
|
||||
set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${POLYBACKEND_SOURCES})
|
||||
|
||||
set (PCH_SOURCES
|
||||
am_map.cpp
|
||||
playsim/bots/b_bot.cpp
|
||||
|
@ -1397,7 +1389,7 @@ source_group("Rendering\\Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMA
|
|||
source_group("Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/math/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/drawers/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/scene/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/backend/.+")
|
||||
source_group("Render Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+")
|
||||
source_group("Render Data\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/models/.+")
|
||||
source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h)
|
||||
|
|
|
@ -294,9 +294,11 @@ class FTexture
|
|||
friend class FMaterial;
|
||||
friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class
|
||||
friend class VkRenderState;
|
||||
friend class PolyRenderState;
|
||||
friend struct FTexCoordInfo;
|
||||
friend class OpenGLRenderer::FHardwareTexture;
|
||||
friend class VkHardwareTexture;
|
||||
friend class PolyHardwareTexture;
|
||||
friend class FMultiPatchTexture;
|
||||
friend class FSkyBox;
|
||||
friend class FBrightmapTexture;
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
EXTERN_CVAR(Bool, vid_hidpi)
|
||||
EXTERN_CVAR(Int, vid_defwidth)
|
||||
EXTERN_CVAR(Int, vid_defheight)
|
||||
EXTERN_CVAR(Int, vid_enablevulkan)
|
||||
EXTERN_CVAR(Int, vid_preferbackend)
|
||||
EXTERN_CVAR(Bool, vk_debug)
|
||||
|
||||
CVAR(Bool, mvk_debug, false, 0)
|
||||
|
@ -348,7 +348,7 @@ class CocoaVideo : public IVideo
|
|||
public:
|
||||
CocoaVideo()
|
||||
{
|
||||
ms_isVulkanEnabled = vid_enablevulkan == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11
|
||||
ms_isVulkanEnabled = vid_preferbackend == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11
|
||||
}
|
||||
|
||||
~CocoaVideo()
|
||||
|
@ -955,3 +955,20 @@ bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
|
|||
return result == VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
void I_PolyPresentInit()
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void I_PolyPresentUnlock(int x, int y, int w, int h)
|
||||
{
|
||||
}
|
||||
|
||||
void I_PolyPresentDeinit()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@
|
|||
#include "rendering/vulkan/system/vk_framebuffer.h"
|
||||
#endif
|
||||
|
||||
#include "rendering/polyrenderer/backend/poly_framebuffer.h"
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
// TYPES -------------------------------------------------------------------
|
||||
|
@ -73,7 +75,7 @@ EXTERN_CVAR (Int, vid_adapter)
|
|||
EXTERN_CVAR (Int, vid_displaybits)
|
||||
EXTERN_CVAR (Int, vid_defwidth)
|
||||
EXTERN_CVAR (Int, vid_defheight)
|
||||
EXTERN_CVAR (Int, vid_enablevulkan)
|
||||
EXTERN_CVAR (Int, vid_preferbackend)
|
||||
EXTERN_CVAR (Bool, cl_capfps)
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
@ -113,6 +115,7 @@ namespace Priv
|
|||
|
||||
SDL_Window *window;
|
||||
bool vulkanEnabled;
|
||||
bool softpolyEnabled;
|
||||
bool fullscreenSwitch;
|
||||
|
||||
void CreateWindow(uint32_t extraFlags)
|
||||
|
@ -230,6 +233,101 @@ bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
|
|||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
SDL_Surface* polysurface = nullptr;
|
||||
}
|
||||
|
||||
void I_PolyPresentInit()
|
||||
{
|
||||
assert(Priv::softpolyEnabled);
|
||||
assert(Priv::window != nullptr);
|
||||
}
|
||||
|
||||
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch)
|
||||
{
|
||||
if (!polysurface || polysurface->w != w || polysurface->h != h)
|
||||
{
|
||||
if (polysurface)
|
||||
{
|
||||
SDL_FreeSurface(polysurface);
|
||||
polysurface = nullptr;
|
||||
}
|
||||
polysurface = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
|
||||
SDL_SetSurfaceBlendMode(polysurface, SDL_BLENDMODE_NONE);
|
||||
}
|
||||
|
||||
SDL_LockSurface(polysurface);
|
||||
pitch = polysurface->pitch;
|
||||
return (uint8_t*)polysurface->pixels;
|
||||
}
|
||||
|
||||
void I_PolyPresentUnlock(int x, int y, int width, int height)
|
||||
{
|
||||
SDL_UnlockSurface(polysurface);
|
||||
|
||||
SDL_Surface* windowsurface = SDL_GetWindowSurface(Priv::window);
|
||||
int ClientWidth = windowsurface->w;
|
||||
int ClientHeight = windowsurface->h;
|
||||
|
||||
SDL_Rect clearrects[4];
|
||||
int count = 0;
|
||||
if (y > 0)
|
||||
{
|
||||
clearrects[count].x = 0;
|
||||
clearrects[count].y = 0;
|
||||
clearrects[count].w = ClientWidth;
|
||||
clearrects[count].h = y;
|
||||
count++;
|
||||
}
|
||||
if (y + height < ClientHeight)
|
||||
{
|
||||
clearrects[count].x = 0;
|
||||
clearrects[count].y = y + height;
|
||||
clearrects[count].w = ClientWidth;
|
||||
clearrects[count].h = ClientHeight - clearrects[count].y;
|
||||
count++;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
clearrects[count].x = 0;
|
||||
clearrects[count].y = y;
|
||||
clearrects[count].w = x;
|
||||
clearrects[count].h = height;
|
||||
count++;
|
||||
}
|
||||
if (x + width < ClientWidth)
|
||||
{
|
||||
clearrects[count].x = x + width;
|
||||
clearrects[count].y = y;
|
||||
clearrects[count].w = ClientWidth - clearrects[count].x;
|
||||
clearrects[count].h = height;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
SDL_FillRects(windowsurface, clearrects, count, SDL_MapRGBA(windowsurface->format, 0, 0, 0, 255));
|
||||
|
||||
SDL_Rect dstrect;
|
||||
dstrect.x = x;
|
||||
dstrect.y = y;
|
||||
dstrect.w = width;
|
||||
dstrect.h = height;
|
||||
SDL_BlitScaled(polysurface, nullptr, windowsurface, &dstrect);
|
||||
|
||||
SDL_UpdateWindowSurface(Priv::window);
|
||||
}
|
||||
|
||||
void I_PolyPresentDeinit()
|
||||
{
|
||||
if (polysurface)
|
||||
{
|
||||
SDL_FreeSurface(polysurface);
|
||||
polysurface = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SDLVideo::SDLVideo ()
|
||||
{
|
||||
|
@ -246,8 +344,9 @@ SDLVideo::SDLVideo ()
|
|||
}
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
Priv::vulkanEnabled = vid_enablevulkan == 1
|
||||
Priv::vulkanEnabled = vid_preferbackend == 1
|
||||
&& Priv::Vulkan_GetDrawableSize && Priv::Vulkan_GetInstanceExtensions && Priv::Vulkan_CreateSurface;
|
||||
Priv::softpolyEnabled = vid_preferbackend == 2;
|
||||
|
||||
if (Priv::vulkanEnabled)
|
||||
{
|
||||
|
@ -258,6 +357,10 @@ SDLVideo::SDLVideo ()
|
|||
Priv::vulkanEnabled = false;
|
||||
}
|
||||
}
|
||||
else if (Priv::softpolyEnabled)
|
||||
{
|
||||
Priv::CreateWindow(SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -294,6 +397,11 @@ DFrameBuffer *SDLVideo::CreateFrameBuffer ()
|
|||
}
|
||||
#endif
|
||||
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
fb = new PolyFrameBuffer(nullptr, fullscreen);
|
||||
}
|
||||
|
||||
if (fb == nullptr)
|
||||
{
|
||||
fb = new OpenGLRenderer::OpenGLFrameBuffer(0, fullscreen);
|
||||
|
@ -325,6 +433,11 @@ int SystemBaseFrameBuffer::GetClientWidth()
|
|||
{
|
||||
int width = 0;
|
||||
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
return SDL_GetWindowSurface(Priv::window)->w;
|
||||
}
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
Priv::Vulkan_GetDrawableSize(Priv::window, &width, nullptr);
|
||||
|
@ -336,6 +449,11 @@ int SystemBaseFrameBuffer::GetClientWidth()
|
|||
int SystemBaseFrameBuffer::GetClientHeight()
|
||||
{
|
||||
int height = 0;
|
||||
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
return SDL_GetWindowSurface(Priv::window)->h;
|
||||
}
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
|
|
|
@ -44,7 +44,7 @@ FLightBuffer::FLightBuffer()
|
|||
// Hack alert: On Intel's GL driver SSBO's perform quite worse than UBOs.
|
||||
// We only want to disable using SSBOs for lights but not disable the feature entirely.
|
||||
// Note that using an uniform buffer here will limit the number of lights per surface so it isn't done for NVidia and AMD.
|
||||
if (screen->IsVulkan() || ((screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && !strstr(screen->vendorstring, "Intel")))
|
||||
if (screen->IsVulkan() || screen->IsPoly() || ((screen->hwcaps & RFL_SHADER_STORAGE_BUFFER) && !strstr(screen->vendorstring, "Intel")))
|
||||
{
|
||||
mBufferType = true;
|
||||
mBlockAlign = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef __I_VIDEO_H__
|
||||
#define __I_VIDEO_H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class DFrameBuffer;
|
||||
|
||||
|
@ -22,6 +23,11 @@ void I_ShutdownGraphics();
|
|||
|
||||
extern IVideo *Video;
|
||||
|
||||
void I_PolyPresentInit();
|
||||
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch);
|
||||
void I_PolyPresentUnlock(int x, int y, int w, int h);
|
||||
void I_PolyPresentDeinit();
|
||||
|
||||
|
||||
// Pause a bit.
|
||||
// [RH] Despite the name, it apparently never waited for the VBL, even in
|
||||
|
|
143
src/rendering/polyrenderer/backend/poly_buffers.cpp
Normal file
143
src/rendering/polyrenderer/backend/poly_buffers.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
|
||||
#include "poly_buffers.h"
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
PolyBuffer *PolyBuffer::First = nullptr;
|
||||
|
||||
PolyBuffer::PolyBuffer()
|
||||
{
|
||||
Next = First;
|
||||
First = this;
|
||||
if (Next) Next->Prev = this;
|
||||
}
|
||||
|
||||
PolyBuffer::~PolyBuffer()
|
||||
{
|
||||
if (Next) Next->Prev = Prev;
|
||||
if (Prev) Prev->Next = Next;
|
||||
else First = Next;
|
||||
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
if (fb && !mData.empty())
|
||||
fb->FrameDeleteList.Buffers.push_back(std::move(mData));
|
||||
}
|
||||
|
||||
void PolyBuffer::ResetAll()
|
||||
{
|
||||
for (PolyBuffer *cur = PolyBuffer::First; cur; cur = cur->Next)
|
||||
cur->Reset();
|
||||
}
|
||||
|
||||
void PolyBuffer::Reset()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyBuffer::SetData(size_t size, const void *data, bool staticdata)
|
||||
{
|
||||
mData.resize(size);
|
||||
map = mData.data();
|
||||
if (data)
|
||||
memcpy(map, data, size);
|
||||
buffersize = size;
|
||||
}
|
||||
|
||||
void PolyBuffer::SetSubData(size_t offset, size_t size, const void *data)
|
||||
{
|
||||
memcpy(static_cast<uint8_t*>(map) + offset, data, size);
|
||||
}
|
||||
|
||||
void PolyBuffer::Resize(size_t newsize)
|
||||
{
|
||||
mData.resize(newsize);
|
||||
buffersize = newsize;
|
||||
map = mData.data();
|
||||
}
|
||||
|
||||
void PolyBuffer::Map()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyBuffer::Unmap()
|
||||
{
|
||||
}
|
||||
|
||||
void *PolyBuffer::Lock(unsigned int size)
|
||||
{
|
||||
if (mData.size() < (size_t)size)
|
||||
Resize(size);
|
||||
return map;
|
||||
}
|
||||
|
||||
void PolyBuffer::Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
||||
{
|
||||
VertexFormat = GetPolyFrameBuffer()->GetRenderState()->GetVertexFormat(numBindingPoints, numAttributes, stride, attrs);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyVertexInputAssembly::Load(PolyTriangleThreadData *thread, const void *vertices, int index)
|
||||
{
|
||||
const uint8_t *vertex = static_cast<const uint8_t*>(vertices) + mStride * index;
|
||||
const float *attrVertex = reinterpret_cast<const float*>(vertex + mOffsets[VATTR_VERTEX]);
|
||||
const float *attrTexcoord = reinterpret_cast<const float*>(vertex + mOffsets[VATTR_TEXCOORD]);
|
||||
const uint8_t *attrColor = reinterpret_cast<const uint8_t*>(vertex + mOffsets[VATTR_COLOR]);
|
||||
const uint32_t* attrNormal = reinterpret_cast<const uint32_t*>(vertex + mOffsets[VATTR_NORMAL]);
|
||||
const uint32_t* attrNormal2 = reinterpret_cast<const uint32_t*>(vertex + mOffsets[VATTR_NORMAL2]);
|
||||
|
||||
thread->mainVertexShader.aPosition = { attrVertex[0], attrVertex[1], attrVertex[2], 1.0f };
|
||||
thread->mainVertexShader.aTexCoord = { attrTexcoord[0], attrTexcoord[1] };
|
||||
|
||||
if ((UseVertexData & 1) == 0)
|
||||
{
|
||||
const auto &c = thread->mainVertexShader.Data.uVertexColor;
|
||||
thread->mainVertexShader.aColor = MAKEARGB(
|
||||
static_cast<uint32_t>(c.W * 255.0f + 0.5f),
|
||||
static_cast<uint32_t>(c.X * 255.0f + 0.5f),
|
||||
static_cast<uint32_t>(c.Y * 255.0f + 0.5f),
|
||||
static_cast<uint32_t>(c.Z * 255.0f + 0.5f)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t r = attrColor[0];
|
||||
uint32_t g = attrColor[1];
|
||||
uint32_t b = attrColor[2];
|
||||
uint32_t a = attrColor[3];
|
||||
thread->mainVertexShader.aColor = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
|
||||
if ((UseVertexData & 2) == 0)
|
||||
{
|
||||
const auto &n = thread->mainVertexShader.Data.uVertexNormal;
|
||||
thread->mainVertexShader.aNormal = Vec4f(n.X, n.Y, n.Z, 1.0);
|
||||
thread->mainVertexShader.aNormal2 = thread->mainVertexShader.aNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = *attrNormal;
|
||||
int n2 = *attrNormal2;
|
||||
float x = ((n << 22) >> 22) / 512.0f;
|
||||
float y = ((n << 12) >> 22) / 512.0f;
|
||||
float z = ((n << 2) >> 22) / 512.0f;
|
||||
float x2 = ((n2 << 22) >> 22) / 512.0f;
|
||||
float y2 = ((n2 << 12) >> 22) / 512.0f;
|
||||
float z2 = ((n2 << 2) >> 22) / 512.0f;
|
||||
thread->mainVertexShader.aNormal = Vec4f(x, y, z, 0.0f);
|
||||
thread->mainVertexShader.aNormal2 = Vec4f(x2, y2, z2, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyDataBuffer::BindRange(FRenderState *state, size_t start, size_t length)
|
||||
{
|
||||
static_cast<PolyRenderState*>(state)->Bind(this, (uint32_t)start, (uint32_t)length);
|
||||
}
|
79
src/rendering/polyrenderer/backend/poly_buffers.h
Normal file
79
src/rendering/polyrenderer/backend/poly_buffers.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "utility/tarray.h"
|
||||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// silence bogus warning C4250: 'PolyVertexBuffer': inherits 'PolyBuffer::PolyBuffer::SetData' via dominance
|
||||
// According to internet infos, the warning is erroneously emitted in this case.
|
||||
#pragma warning(disable:4250)
|
||||
#endif
|
||||
|
||||
class PolyBuffer : virtual public IBuffer
|
||||
{
|
||||
public:
|
||||
PolyBuffer();
|
||||
~PolyBuffer();
|
||||
|
||||
static void ResetAll();
|
||||
void Reset();
|
||||
|
||||
void SetData(size_t size, const void *data, bool staticdata) override;
|
||||
void SetSubData(size_t offset, size_t size, const void *data) override;
|
||||
void Resize(size_t newsize) override;
|
||||
|
||||
void Map() override;
|
||||
void Unmap() override;
|
||||
|
||||
void *Lock(unsigned int size) override;
|
||||
void Unlock() override;
|
||||
|
||||
private:
|
||||
static PolyBuffer *First;
|
||||
PolyBuffer *Prev = nullptr;
|
||||
PolyBuffer *Next = nullptr;
|
||||
std::vector<uint32_t> mData;
|
||||
};
|
||||
|
||||
class PolyVertexInputAssembly : public PolyInputAssembly
|
||||
{
|
||||
public:
|
||||
size_t mOffsets[VATTR_MAX] = {};
|
||||
size_t mStride = 0;
|
||||
|
||||
int NumBindingPoints;
|
||||
size_t Stride;
|
||||
std::vector<FVertexBufferAttribute> Attrs;
|
||||
int UseVertexData;
|
||||
|
||||
void Load(PolyTriangleThreadData *thread, const void *vertices, int index) override;
|
||||
};
|
||||
|
||||
class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer
|
||||
{
|
||||
public:
|
||||
PolyVertexBuffer() { }
|
||||
void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override;
|
||||
|
||||
PolyVertexInputAssembly *VertexFormat = nullptr;
|
||||
};
|
||||
|
||||
class PolyIndexBuffer : public IIndexBuffer, public PolyBuffer
|
||||
{
|
||||
public:
|
||||
PolyIndexBuffer() { }
|
||||
};
|
||||
|
||||
class PolyDataBuffer : public IDataBuffer, public PolyBuffer
|
||||
{
|
||||
public:
|
||||
PolyDataBuffer(int bindingpoint, bool ssbo, bool needresize) : bindingpoint(bindingpoint)
|
||||
{
|
||||
}
|
||||
|
||||
void BindRange(FRenderState *state, size_t start, size_t length) override;
|
||||
|
||||
int bindingpoint;
|
||||
};
|
578
src/rendering/polyrenderer/backend/poly_framebuffer.cpp
Normal file
578
src/rendering/polyrenderer/backend/poly_framebuffer.cpp
Normal file
|
@ -0,0 +1,578 @@
|
|||
|
||||
#include "v_video.h"
|
||||
#include "m_png.h"
|
||||
#include "templates.h"
|
||||
#include "r_videoscale.h"
|
||||
#include "actor.h"
|
||||
#include "i_time.h"
|
||||
#include "g_game.h"
|
||||
#include "gamedata/fonts/v_text.h"
|
||||
|
||||
#include "rendering/i_video.h"
|
||||
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/utility/hw_vrmodes.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hwrenderer/models/hw_models.h"
|
||||
#include "hwrenderer/scene/hw_skydome.h"
|
||||
#include "hwrenderer/scene/hw_fakeflat.h"
|
||||
#include "hwrenderer/scene/hw_drawinfo.h"
|
||||
#include "hwrenderer/scene/hw_portal.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "hwrenderer/data/flatvertices.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
#include "hwrenderer/dynlights/hw_lightbuffer.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
|
||||
#include "swrenderer/r_swscene.h"
|
||||
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_buffers.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "poly_hwtexture.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
void Draw2D(F2DDrawer *drawer, FRenderState &state);
|
||||
void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown);
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawvoxels)
|
||||
EXTERN_CVAR(Int, gl_tonemap)
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
EXTERN_CVAR(Bool, cl_capfps)
|
||||
EXTERN_CVAR(Bool, gl_no_skyclear)
|
||||
|
||||
extern bool NoInterpolateView;
|
||||
extern int rendered_commandbuffers;
|
||||
extern int current_rendered_commandbuffers;
|
||||
|
||||
extern bool gpuStatActive;
|
||||
extern bool keepGpuStatActive;
|
||||
extern FString gpuStatOutput;
|
||||
|
||||
PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen)
|
||||
{
|
||||
I_PolyPresentInit();
|
||||
}
|
||||
|
||||
PolyFrameBuffer::~PolyFrameBuffer()
|
||||
{
|
||||
// screen is already null at this point, but PolyHardwareTexture::ResetAll needs it during clean up. Is there a better way we can do this?
|
||||
auto tmp = screen;
|
||||
screen = this;
|
||||
|
||||
PolyHardwareTexture::ResetAll();
|
||||
PolyBuffer::ResetAll();
|
||||
PPResource::ResetAll();
|
||||
|
||||
delete mVertexData;
|
||||
delete mSkyData;
|
||||
delete mViewpoints;
|
||||
delete mLights;
|
||||
mShadowMap.Reset();
|
||||
|
||||
screen = tmp;
|
||||
|
||||
I_PolyPresentDeinit();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::InitializeState()
|
||||
{
|
||||
vendorstring = "Poly";
|
||||
hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
|
||||
glslversion = 4.50f;
|
||||
uniformblockalignment = 1;
|
||||
maxuniformblock = 0x7fffffff;
|
||||
|
||||
mRenderState.reset(new PolyRenderState());
|
||||
|
||||
mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight());
|
||||
mSkyData = new FSkyVertexBuffer;
|
||||
mViewpoints = new HWViewpointBuffer;
|
||||
mLights = new FLightBuffer();
|
||||
|
||||
PolyTriangleDrawer::SetLightBuffer(GetDrawCommands(), mLightBuffer->Memory());
|
||||
|
||||
CheckCanvas();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::CheckCanvas()
|
||||
{
|
||||
if (!mCanvas || mCanvas->GetWidth() != GetWidth() || mCanvas->GetHeight() != GetHeight())
|
||||
{
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
mCanvas.reset(new DCanvas(0, 0, true));
|
||||
mCanvas->Resize(GetWidth(), GetHeight(), false);
|
||||
mDepthStencil.reset();
|
||||
mDepthStencil.reset(new PolyDepthStencil(GetWidth(), GetHeight()));
|
||||
|
||||
mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil());
|
||||
}
|
||||
}
|
||||
|
||||
const DrawerCommandQueuePtr &PolyFrameBuffer::GetDrawCommands()
|
||||
{
|
||||
if (!mDrawCommands)
|
||||
mDrawCommands = std::make_shared<DrawerCommandQueue>(&mFrameMemory);
|
||||
return mDrawCommands;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::FlushDrawCommands()
|
||||
{
|
||||
if (mDrawCommands)
|
||||
{
|
||||
DrawerThreads::Execute(mDrawCommands);
|
||||
mDrawCommands.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::Update()
|
||||
{
|
||||
twoD.Reset();
|
||||
Flush3D.Reset();
|
||||
|
||||
Flush3D.Clock();
|
||||
|
||||
Draw2D();
|
||||
Clear2D();
|
||||
|
||||
Flush3D.Unclock();
|
||||
|
||||
FlushDrawCommands();
|
||||
|
||||
if (mCanvas)
|
||||
{
|
||||
int w = mCanvas->GetWidth();
|
||||
int h = mCanvas->GetHeight();
|
||||
int pixelsize = 4;
|
||||
const uint8_t *src = (const uint8_t*)mCanvas->GetPixels();
|
||||
int pitch = 0;
|
||||
uint8_t *dst = I_PolyPresentLock(w, h, cur_vsync, pitch);
|
||||
if (dst)
|
||||
{
|
||||
#if 1
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(&mFrameMemory);
|
||||
copyqueue->Push<MemcpyCommand>(dst, pitch / pixelsize, src, w, h, w, pixelsize);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
#else
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(dst + y * pitch, src + y * w * pixelsize, w * pixelsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
I_PolyPresentUnlock(mOutputLetterbox.left, mOutputLetterbox.top, mOutputLetterbox.width, mOutputLetterbox.height);
|
||||
}
|
||||
}
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mFrameMemory.Clear();
|
||||
FrameDeleteList.Buffers.clear();
|
||||
FrameDeleteList.Images.clear();
|
||||
|
||||
CheckCanvas();
|
||||
|
||||
Super::Update();
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height)
|
||||
{
|
||||
if (!V_IsHardwareRenderer())
|
||||
{
|
||||
Super::WriteSavePic(player, file, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
sector_t *PolyFrameBuffer::RenderView(player_t *player)
|
||||
{
|
||||
// To do: this is virtually identical to FGLRenderer::RenderView and should be merged.
|
||||
|
||||
mRenderState->SetVertexBuffer(mVertexData);
|
||||
mVertexData->Reset();
|
||||
|
||||
sector_t *retsec;
|
||||
if (!V_IsHardwareRenderer())
|
||||
{
|
||||
if (!swdrawer) swdrawer.reset(new SWSceneDrawer);
|
||||
retsec = swdrawer->RenderView(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
hw_ClearFakeFlat();
|
||||
|
||||
iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0;
|
||||
|
||||
checkBenchActive();
|
||||
|
||||
// reset statistics counters
|
||||
ResetProfilingData();
|
||||
|
||||
// Get this before everything else
|
||||
if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.;
|
||||
else r_viewpoint.TicFrac = I_GetTimeFrac();
|
||||
|
||||
mLights->Clear();
|
||||
mViewpoints->Clear();
|
||||
|
||||
// NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below.
|
||||
bool saved_niv = NoInterpolateView;
|
||||
NoInterpolateView = false;
|
||||
|
||||
// Shader start time does not need to be handled per level. Just use the one from the camera to render from.
|
||||
GetRenderState()->CheckTimer(player->camera->Level->ShaderStartTime);
|
||||
// prepare all camera textures that have been used in the last frame.
|
||||
// This must be done for all levels, not just the primary one!
|
||||
for (auto Level : AllLevels())
|
||||
{
|
||||
Level->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov)
|
||||
{
|
||||
RenderTextureView(camtex, camera, fov);
|
||||
});
|
||||
}
|
||||
NoInterpolateView = saved_niv;
|
||||
|
||||
// now render the main view
|
||||
float fovratio;
|
||||
float ratio = r_viewwindow.WidescreenRatio;
|
||||
if (r_viewwindow.WidescreenRatio >= 1.3f)
|
||||
{
|
||||
fovratio = 1.333333f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fovratio = ratio;
|
||||
}
|
||||
|
||||
retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
}
|
||||
All.Unclock();
|
||||
return retsec;
|
||||
}
|
||||
|
||||
sector_t *PolyFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen)
|
||||
{
|
||||
// To do: this is virtually identical to FGLRenderer::RenderViewpoint and should be merged.
|
||||
|
||||
R_SetupFrame(mainvp, r_viewwindow, camera);
|
||||
|
||||
if (mainview && toscreen)
|
||||
UpdateShadowMap();
|
||||
|
||||
// Update the attenuation flag of all light defaults for each viewpoint.
|
||||
// This function will only do something if the setting differs.
|
||||
FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE));
|
||||
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
|
||||
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
|
||||
for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix)
|
||||
{
|
||||
const auto &eye = vrmode->mEyes[eye_ix];
|
||||
SetViewportRects(bounds);
|
||||
|
||||
if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao
|
||||
{
|
||||
//mRenderState->SetRenderTarget(GetBuffers()->SceneColor.View.get(), GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), Poly_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples());
|
||||
bool useSSAO = (gl_ssao != 0);
|
||||
GetRenderState()->SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
|
||||
GetRenderState()->EnableDrawBuffers(GetRenderState()->GetPassDrawBufferCount());
|
||||
}
|
||||
|
||||
auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr);
|
||||
auto &vp = di->Viewpoint;
|
||||
|
||||
di->Set3DViewport(*GetRenderState());
|
||||
di->SetViewArea();
|
||||
auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr);
|
||||
di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint)
|
||||
|
||||
// Stereo mode specific perspective projection
|
||||
di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio);
|
||||
// Stereo mode specific viewpoint adjustment
|
||||
vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees);
|
||||
di->SetupView(*GetRenderState(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false);
|
||||
|
||||
// std::function until this can be done better in a cross-API fashion.
|
||||
di->ProcessScene(toscreen, [&](HWDrawInfo *di, int mode) {
|
||||
DrawScene(di, mode);
|
||||
});
|
||||
|
||||
if (mainview)
|
||||
{
|
||||
PostProcess.Clock();
|
||||
if (toscreen) di->EndDrawScene(mainvp.sector, *GetRenderState()); // do not call this for camera textures.
|
||||
|
||||
if (GetRenderState()->GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers
|
||||
{
|
||||
GetRenderState()->SetPassType(NORMAL_PASS);
|
||||
GetRenderState()->EnableDrawBuffers(1);
|
||||
}
|
||||
|
||||
//mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture
|
||||
|
||||
PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, *GetRenderState()); });
|
||||
|
||||
PostProcess.Unclock();
|
||||
}
|
||||
di->EndDrawInfo();
|
||||
|
||||
#if 0
|
||||
if (vrmode->mEyeCount > 1)
|
||||
mBuffers->BlitToEyeTexture(eye_ix);
|
||||
#endif
|
||||
}
|
||||
|
||||
return mainvp.sector;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV)
|
||||
{
|
||||
// This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene.
|
||||
FMaterial *mat = FMaterial::ValidateTexture(tex, false);
|
||||
auto BaseLayer = static_cast<PolyHardwareTexture*>(mat->GetLayer(0, 0));
|
||||
|
||||
int width = mat->TextureWidth();
|
||||
int height = mat->TextureHeight();
|
||||
DCanvas *image = BaseLayer->GetImage(tex, 0, 0);
|
||||
PolyDepthStencil *depthStencil = BaseLayer->GetDepthStencil(tex);
|
||||
mRenderState->SetRenderTarget(image, depthStencil);
|
||||
|
||||
IntRect bounds;
|
||||
bounds.left = bounds.top = 0;
|
||||
bounds.width = MIN(mat->GetWidth(), image->GetWidth());
|
||||
bounds.height = MIN(mat->GetHeight(), image->GetHeight());
|
||||
|
||||
FRenderViewpoint texvp;
|
||||
RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false);
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil());
|
||||
|
||||
tex->SetUpdated(true);
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode)
|
||||
{
|
||||
// To do: this is virtually identical to FGLRenderer::DrawScene and should be merged.
|
||||
|
||||
static int recursion = 0;
|
||||
static int ssao_portals_available = 0;
|
||||
const auto &vp = di->Viewpoint;
|
||||
|
||||
bool applySSAO = false;
|
||||
if (drawmode == DM_MAINVIEW)
|
||||
{
|
||||
ssao_portals_available = gl_ssao_portals;
|
||||
applySSAO = true;
|
||||
}
|
||||
else if (drawmode == DM_OFFSCREEN)
|
||||
{
|
||||
ssao_portals_available = 0;
|
||||
}
|
||||
else if (drawmode == DM_PORTAL && ssao_portals_available > 0)
|
||||
{
|
||||
applySSAO = true;
|
||||
ssao_portals_available--;
|
||||
}
|
||||
|
||||
if (vp.camera != nullptr)
|
||||
{
|
||||
ActorRenderFlags savedflags = vp.camera->renderflags;
|
||||
di->CreateScene(drawmode == DM_MAINVIEW);
|
||||
vp.camera->renderflags = savedflags;
|
||||
}
|
||||
else
|
||||
{
|
||||
di->CreateScene(false);
|
||||
}
|
||||
|
||||
GetRenderState()->SetDepthMask(true);
|
||||
if (!gl_no_skyclear) mPortalState->RenderFirstSkyPortal(recursion, di, *GetRenderState());
|
||||
|
||||
di->RenderScene(*GetRenderState());
|
||||
|
||||
if (applySSAO && GetRenderState()->GetPassType() == GBUFFER_PASS)
|
||||
{
|
||||
//mPostprocess->AmbientOccludeScene(di->VPUniforms.mProjectionMatrix.get()[5]);
|
||||
//mViewpoints->Bind(*GetRenderState(), di->vpIndex);
|
||||
}
|
||||
|
||||
// Handle all portals after rendering the opaque objects but before
|
||||
// doing all translucent stuff
|
||||
recursion++;
|
||||
mPortalState->EndFrame(di, *GetRenderState());
|
||||
recursion--;
|
||||
di->RenderTranslucent(*GetRenderState());
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
|
||||
{
|
||||
afterBloomDrawEndScene2D();
|
||||
}
|
||||
|
||||
uint32_t PolyFrameBuffer::GetCaps()
|
||||
{
|
||||
if (!V_IsHardwareRenderer())
|
||||
return Super::GetCaps();
|
||||
|
||||
// describe our basic feature set
|
||||
ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS |
|
||||
RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP;
|
||||
if (r_drawvoxels)
|
||||
FlagSet |= RFF_VOXELS;
|
||||
|
||||
if (gl_tonemap != 5) // not running palette tonemap shader
|
||||
FlagSet |= RFF_TRUECOLOR;
|
||||
|
||||
return (uint32_t)FlagSet;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::SetVSync(bool vsync)
|
||||
{
|
||||
cur_vsync = vsync;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::CleanForRestart()
|
||||
{
|
||||
// force recreation of the SW scene drawer to ensure it gets a new set of resources.
|
||||
swdrawer.reset();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
|
||||
{
|
||||
auto tex = mat->tex;
|
||||
if (tex->isSWCanvas()) return;
|
||||
|
||||
// Textures that are already scaled in the texture lump will not get replaced by hires textures.
|
||||
int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled()) ? CTF_CheckHires : 0;
|
||||
auto base = static_cast<PolyHardwareTexture*>(mat->GetLayer(0, translation));
|
||||
|
||||
base->Precache(mat, translation, flags);
|
||||
}
|
||||
|
||||
IHardwareTexture *PolyFrameBuffer::CreateHardwareTexture()
|
||||
{
|
||||
return new PolyHardwareTexture();
|
||||
}
|
||||
|
||||
FModelRenderer *PolyFrameBuffer::CreateModelRenderer(int mli)
|
||||
{
|
||||
return new FHWModelRenderer(nullptr, *GetRenderState(), mli);
|
||||
}
|
||||
|
||||
IVertexBuffer *PolyFrameBuffer::CreateVertexBuffer()
|
||||
{
|
||||
return new PolyVertexBuffer();
|
||||
}
|
||||
|
||||
IIndexBuffer *PolyFrameBuffer::CreateIndexBuffer()
|
||||
{
|
||||
return new PolyIndexBuffer();
|
||||
}
|
||||
|
||||
IDataBuffer *PolyFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize)
|
||||
{
|
||||
IDataBuffer *buffer = new PolyDataBuffer(bindingpoint, ssbo, needsresize);
|
||||
if (bindingpoint == LIGHTBUF_BINDINGPOINT)
|
||||
mLightBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::SetTextureFilterMode()
|
||||
{
|
||||
TextureFilterChanged();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::TextureFilterChanged()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::StartPrecaching()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::BlurScene(float amount)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::UpdatePalette()
|
||||
{
|
||||
}
|
||||
|
||||
FTexture *PolyFrameBuffer::WipeStartScreen()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
|
||||
auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1);
|
||||
auto systex = static_cast<PolyHardwareTexture*>(tex->GetSystemTexture());
|
||||
|
||||
systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeStartScreen");
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
FTexture *PolyFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
Draw2D();
|
||||
Clear2D();
|
||||
|
||||
auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1);
|
||||
auto systex = static_cast<PolyHardwareTexture*>(tex->GetSystemTexture());
|
||||
|
||||
systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeEndScreen");
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
TArray<uint8_t> PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma)
|
||||
{
|
||||
int w = SCREENWIDTH;
|
||||
int h = SCREENHEIGHT;
|
||||
|
||||
IntRect box;
|
||||
box.left = 0;
|
||||
box.top = 0;
|
||||
box.width = w;
|
||||
box.height = h;
|
||||
//mPostprocess->DrawPresentTexture(box, true, true);
|
||||
|
||||
TArray<uint8_t> ScreenshotBuffer(w * h * 3, true);
|
||||
//CopyScreenToBuffer(w, h, ScreenshotBuffer.Data());
|
||||
|
||||
pitch = w * 3;
|
||||
color_type = SS_RGB;
|
||||
gamma = 1.0f;
|
||||
return ScreenshotBuffer;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::BeginFrame()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
CheckCanvas();
|
||||
|
||||
swrenderer::R_InitFuzzTable(GetCanvas()->GetPitch());
|
||||
static int next_random = 0;
|
||||
swrenderer::fuzzpos = (swrenderer::fuzzpos + swrenderer::fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE;
|
||||
next_random++;
|
||||
if (next_random == FUZZ_RANDOM_X_SIZE)
|
||||
next_random = 0;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::Draw2D()
|
||||
{
|
||||
::Draw2D(&m2DDrawer, *mRenderState);
|
||||
}
|
||||
|
||||
unsigned int PolyFrameBuffer::GetLightBufferBlockSize() const
|
||||
{
|
||||
return mLights->GetBlockSize();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::UpdateShadowMap()
|
||||
{
|
||||
}
|
90
src/rendering/polyrenderer/backend/poly_framebuffer.h
Normal file
90
src/rendering/polyrenderer/backend/poly_framebuffer.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "gl_sysfb.h"
|
||||
#include "rendering/swrenderer/r_memory.h"
|
||||
#include "rendering/swrenderer/drawers/r_thread.h"
|
||||
#include "rendering/polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
struct FRenderViewpoint;
|
||||
class PolyDataBuffer;
|
||||
class PolyRenderState;
|
||||
class SWSceneDrawer;
|
||||
|
||||
class PolyFrameBuffer : public SystemBaseFrameBuffer
|
||||
{
|
||||
typedef SystemBaseFrameBuffer Super;
|
||||
|
||||
public:
|
||||
RenderMemory *GetFrameMemory() { return &mFrameMemory; }
|
||||
PolyRenderState *GetRenderState() { return mRenderState.get(); }
|
||||
DCanvas *GetCanvas() override { return mCanvas.get(); }
|
||||
PolyDepthStencil *GetDepthStencil() { return mDepthStencil.get(); }
|
||||
const DrawerCommandQueuePtr &GetDrawCommands();
|
||||
void FlushDrawCommands();
|
||||
|
||||
unsigned int GetLightBufferBlockSize() const;
|
||||
|
||||
std::unique_ptr<SWSceneDrawer> swdrawer;
|
||||
|
||||
PolyFrameBuffer(void *hMonitor, bool fullscreen);
|
||||
~PolyFrameBuffer();
|
||||
|
||||
void Update();
|
||||
|
||||
bool IsPoly() override { return true; }
|
||||
|
||||
void InitializeState() override;
|
||||
|
||||
void CleanForRestart() override;
|
||||
void PrecacheMaterial(FMaterial *mat, int translation) override;
|
||||
void UpdatePalette() override;
|
||||
uint32_t GetCaps() override;
|
||||
void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override;
|
||||
sector_t *RenderView(player_t *player) override;
|
||||
void SetTextureFilterMode() override;
|
||||
void TextureFilterChanged() override;
|
||||
void StartPrecaching() override;
|
||||
void BeginFrame() override;
|
||||
void BlurScene(float amount) override;
|
||||
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D) override;
|
||||
|
||||
IHardwareTexture *CreateHardwareTexture() override;
|
||||
FModelRenderer *CreateModelRenderer(int mli) override;
|
||||
IVertexBuffer *CreateVertexBuffer() override;
|
||||
IIndexBuffer *CreateIndexBuffer() override;
|
||||
IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override;
|
||||
|
||||
FTexture *WipeStartScreen() override;
|
||||
FTexture *WipeEndScreen() override;
|
||||
|
||||
TArray<uint8_t> GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override;
|
||||
|
||||
void SetVSync(bool vsync) override;
|
||||
void Draw2D() override;
|
||||
|
||||
struct DeleteList
|
||||
{
|
||||
std::vector<std::vector<uint32_t>> Buffers;
|
||||
std::vector<std::unique_ptr<DCanvas>> Images;
|
||||
} FrameDeleteList;
|
||||
|
||||
private:
|
||||
sector_t *RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen);
|
||||
void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV);
|
||||
void DrawScene(HWDrawInfo *di, int drawmode);
|
||||
void UpdateShadowMap();
|
||||
|
||||
void CheckCanvas();
|
||||
|
||||
IDataBuffer *mLightBuffer = nullptr;
|
||||
|
||||
std::unique_ptr<PolyRenderState> mRenderState;
|
||||
std::unique_ptr<DCanvas> mCanvas;
|
||||
std::unique_ptr<PolyDepthStencil> mDepthStencil;
|
||||
std::shared_ptr<DrawerCommandQueue> mDrawCommands;
|
||||
RenderMemory mFrameMemory;
|
||||
|
||||
bool cur_vsync = false;
|
||||
};
|
||||
|
||||
inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast<PolyFrameBuffer*>(screen); }
|
169
src/rendering/polyrenderer/backend/poly_hwtexture.cpp
Normal file
169
src/rendering/polyrenderer/backend/poly_hwtexture.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
|
||||
#include "templates.h"
|
||||
#include "c_cvars.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "hwrenderer/textures/hw_material.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hwrenderer/scene/hw_renderstate.h"
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_hwtexture.h"
|
||||
|
||||
PolyHardwareTexture *PolyHardwareTexture::First = nullptr;
|
||||
|
||||
PolyHardwareTexture::PolyHardwareTexture()
|
||||
{
|
||||
Next = First;
|
||||
First = this;
|
||||
if (Next) Next->Prev = this;
|
||||
}
|
||||
|
||||
PolyHardwareTexture::~PolyHardwareTexture()
|
||||
{
|
||||
if (Next) Next->Prev = Prev;
|
||||
if (Prev) Prev->Next = Next;
|
||||
else First = Next;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::ResetAll()
|
||||
{
|
||||
for (PolyHardwareTexture *cur = PolyHardwareTexture::First; cur; cur = cur->Next)
|
||||
cur->Reset();
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::Reset()
|
||||
{
|
||||
if (auto fb = GetPolyFrameBuffer())
|
||||
{
|
||||
auto &deleteList = fb->FrameDeleteList;
|
||||
if (mCanvas) deleteList.Images.push_back(std::move(mCanvas));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::Precache(FMaterial *mat, int translation, int flags)
|
||||
{
|
||||
int numLayers = mat->GetLayers();
|
||||
GetImage(mat->tex, translation, flags);
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
FTexture *layer;
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mat->GetLayer(i, 0, &layer));
|
||||
systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0);
|
||||
}
|
||||
}
|
||||
|
||||
DCanvas *PolyHardwareTexture::GetImage(const FMaterialState &state)
|
||||
{
|
||||
FTexture *tex = state.mMaterial->tex;
|
||||
if (tex->isHardwareCanvas()) static_cast<FCanvasTexture*>(tex)->NeedUpdate();
|
||||
|
||||
if (!mCanvas)
|
||||
{
|
||||
FMaterial *mat = state.mMaterial;
|
||||
int clampmode = state.mClampMode;
|
||||
int translation = state.mTranslation;
|
||||
|
||||
if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER;
|
||||
if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX;
|
||||
else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE;
|
||||
|
||||
// Textures that are already scaled in the texture lump will not get replaced by hires textures.
|
||||
int flags = state.mMaterial->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled() && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0;
|
||||
|
||||
return GetImage(tex, translation, flags);
|
||||
}
|
||||
|
||||
return mCanvas.get();
|
||||
}
|
||||
|
||||
DCanvas *PolyHardwareTexture::GetImage(FTexture *tex, int translation, int flags)
|
||||
{
|
||||
if (!mCanvas)
|
||||
CreateImage(tex, translation, flags);
|
||||
return mCanvas.get();
|
||||
}
|
||||
|
||||
PolyDepthStencil *PolyHardwareTexture::GetDepthStencil(FTexture *tex)
|
||||
{
|
||||
if (!mDepthStencil)
|
||||
{
|
||||
int w = tex->GetWidth();
|
||||
int h = tex->GetHeight();
|
||||
mDepthStencil.reset(new PolyDepthStencil(w, h));
|
||||
}
|
||||
return mDepthStencil.get();
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::AllocateBuffer(int w, int h, int texelsize)
|
||||
{
|
||||
if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h)
|
||||
{
|
||||
mCanvas.reset(new DCanvas(0, 0, texelsize == 4));
|
||||
mCanvas->Resize(w, h, false);
|
||||
bufferpitch = mCanvas->GetPitch();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *PolyHardwareTexture::MapBuffer()
|
||||
{
|
||||
return mCanvas->GetPixels();
|
||||
}
|
||||
|
||||
unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::CreateWipeTexture(int w, int h, const char *name)
|
||||
{
|
||||
if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h)
|
||||
{
|
||||
mCanvas.reset(new DCanvas(0, 0, true));
|
||||
mCanvas->Resize(w, h, false);
|
||||
}
|
||||
|
||||
auto fb = static_cast<PolyFrameBuffer*>(screen);
|
||||
|
||||
fb->FlushDrawCommands();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
uint32_t* dest = (uint32_t*)mCanvas->GetPixels();
|
||||
uint32_t* src = (uint32_t*)fb->GetCanvas()->GetPixels();
|
||||
int dpitch = mCanvas->GetPitch();
|
||||
int spitch = fb->GetCanvas()->GetPitch();
|
||||
int pixelsize = 4;
|
||||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(dest + dpitch * (h - 1 - y), src + spitch * y, w * pixelsize);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
|
||||
{
|
||||
mCanvas.reset(new DCanvas(0, 0, true));
|
||||
|
||||
if (!tex->isHardwareCanvas())
|
||||
{
|
||||
if (translation <= 0)
|
||||
{
|
||||
translation = -translation;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto remap = TranslationToTable(translation);
|
||||
translation = remap == nullptr ? 0 : remap->GetUniqueIndex();
|
||||
}
|
||||
|
||||
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData);
|
||||
mCanvas->Resize(texbuffer.mWidth, texbuffer.mHeight, false);
|
||||
memcpy(mCanvas->GetPixels(), texbuffer.mBuffer, texbuffer.mWidth * texbuffer.mHeight * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
int w = tex->GetWidth();
|
||||
int h = tex->GetHeight();
|
||||
mCanvas->Resize(w, h, false);
|
||||
}
|
||||
}
|
48
src/rendering/polyrenderer/backend/poly_hwtexture.h
Normal file
48
src/rendering/polyrenderer/backend/poly_hwtexture.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef LoadImage
|
||||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
#define SHADED_TEXTURE -1
|
||||
#define DIRECT_PALETTE -2
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hwrenderer/textures/hw_ihwtexture.h"
|
||||
#include "volk/volk.h"
|
||||
|
||||
struct FMaterialState;
|
||||
class PolyBuffer;
|
||||
|
||||
class PolyHardwareTexture : public IHardwareTexture
|
||||
{
|
||||
public:
|
||||
PolyHardwareTexture();
|
||||
~PolyHardwareTexture();
|
||||
|
||||
static void ResetAll();
|
||||
void Reset();
|
||||
|
||||
void Precache(FMaterial *mat, int translation, int flags);
|
||||
|
||||
DCanvas *GetImage(const FMaterialState &state);
|
||||
DCanvas *GetImage(FTexture *tex, int translation, int flags);
|
||||
PolyDepthStencil *GetDepthStencil(FTexture *tex);
|
||||
|
||||
// Software renderer stuff
|
||||
void AllocateBuffer(int w, int h, int texelsize) override;
|
||||
uint8_t *MapBuffer() override;
|
||||
unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override;
|
||||
|
||||
// Wipe screen
|
||||
void CreateWipeTexture(int w, int h, const char *name);
|
||||
|
||||
private:
|
||||
void CreateImage(FTexture *tex, int translation, int flags);
|
||||
|
||||
static PolyHardwareTexture *First;
|
||||
PolyHardwareTexture *Prev = nullptr;
|
||||
PolyHardwareTexture *Next = nullptr;
|
||||
std::unique_ptr<DCanvas> mCanvas;
|
||||
std::unique_ptr<PolyDepthStencil> mDepthStencil;
|
||||
};
|
360
src/rendering/polyrenderer/backend/poly_renderstate.cpp
Normal file
360
src/rendering/polyrenderer/backend/poly_renderstate.cpp
Normal file
|
@ -0,0 +1,360 @@
|
|||
|
||||
#include "polyrenderer/backend/poly_renderstate.h"
|
||||
#include "polyrenderer/backend/poly_framebuffer.h"
|
||||
#include "polyrenderer/backend/poly_hwtexture.h"
|
||||
#include "templates.h"
|
||||
#include "doomstat.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "hwrenderer/scene/hw_skydome.h"
|
||||
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
||||
#include "hwrenderer/dynlights/hw_lightbuffer.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hwrenderer/utility/hw_clock.h"
|
||||
#include "hwrenderer/data/flatvertices.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
|
||||
static PolyDrawMode dtToDrawMode[] =
|
||||
{
|
||||
PolyDrawMode::Points,
|
||||
PolyDrawMode::Lines,
|
||||
PolyDrawMode::Triangles,
|
||||
PolyDrawMode::TriangleFan,
|
||||
PolyDrawMode::TriangleStrip,
|
||||
};
|
||||
|
||||
PolyRenderState::PolyRenderState()
|
||||
{
|
||||
mIdentityMatrix.loadIdentity();
|
||||
Reset();
|
||||
}
|
||||
|
||||
void PolyRenderState::ClearScreen()
|
||||
{
|
||||
screen->mViewpoints->Set2D(*this, SCREENWIDTH, SCREENHEIGHT);
|
||||
SetColor(0, 0, 0);
|
||||
Draw(DT_TriangleStrip, FFlatVertexBuffer::FULLSCREEN_INDEX, 4, true);
|
||||
}
|
||||
|
||||
void PolyRenderState::Draw(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
Apply();
|
||||
|
||||
PolyTriangleDrawer::Draw(GetPolyFrameBuffer()->GetDrawCommands(), index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
void PolyRenderState::DrawIndexed(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
Apply();
|
||||
|
||||
PolyTriangleDrawer::DrawIndexed(GetPolyFrameBuffer()->GetDrawCommands(), index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
bool PolyRenderState::SetDepthClamp(bool on)
|
||||
{
|
||||
bool lastValue = mDepthClamp;
|
||||
mDepthClamp = on;
|
||||
PolyTriangleDrawer::SetDepthClamp(GetPolyFrameBuffer()->GetDrawCommands(), on);
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthMask(bool on)
|
||||
{
|
||||
PolyTriangleDrawer::SetDepthMask(GetPolyFrameBuffer()->GetDrawCommands(), on);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthFunc(int func)
|
||||
{
|
||||
PolyTriangleDrawer::SetDepthFunc(GetPolyFrameBuffer()->GetDrawCommands(), func);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthRange(float min, float max)
|
||||
{
|
||||
PolyTriangleDrawer::SetDepthRange(GetPolyFrameBuffer()->GetDrawCommands(), min, max);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
PolyTriangleDrawer::SetColorMask(GetPolyFrameBuffer()->GetDrawCommands(), r, g, b, a);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetStencil(int offs, int op, int flags)
|
||||
{
|
||||
PolyTriangleDrawer::SetStencil(GetPolyFrameBuffer()->GetDrawCommands(), screen->stencilValue + offs, op);
|
||||
|
||||
if (flags != -1)
|
||||
{
|
||||
bool cmon = !(flags & SF_ColorMaskOff);
|
||||
SetColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer
|
||||
SetDepthMask(!(flags & SF_DepthMaskOff));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderState::SetCulling(int mode)
|
||||
{
|
||||
PolyTriangleDrawer::SetCulling(GetPolyFrameBuffer()->GetDrawCommands(), mode);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableClipDistance(int num, bool state)
|
||||
{
|
||||
PolyTriangleDrawer::EnableClipDistance(GetPolyFrameBuffer()->GetDrawCommands(), num, state);
|
||||
}
|
||||
|
||||
void PolyRenderState::Clear(int targets)
|
||||
{
|
||||
//if (targets & CT_Color)
|
||||
// PolyTriangleDrawer::ClearColor(GetPolyFrameBuffer()->GetDrawCommands());
|
||||
if (targets & CT_Depth)
|
||||
PolyTriangleDrawer::ClearDepth(GetPolyFrameBuffer()->GetDrawCommands(), 65535.0f);
|
||||
if (targets & CT_Stencil)
|
||||
PolyTriangleDrawer::ClearStencil(GetPolyFrameBuffer()->GetDrawCommands(), 0);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableStencil(bool on)
|
||||
{
|
||||
PolyTriangleDrawer::EnableStencil(GetPolyFrameBuffer()->GetDrawCommands(), on);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
if (w < 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = mRenderTarget.Canvas->GetWidth();
|
||||
h = mRenderTarget.Canvas->GetHeight();
|
||||
}
|
||||
PolyTriangleDrawer::SetScissor(fb->GetDrawCommands(), x, mRenderTarget.Canvas->GetHeight() - y - h, w, h);
|
||||
}
|
||||
|
||||
void PolyRenderState::SetViewport(int x, int y, int w, int h)
|
||||
{
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
if (w < 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = mRenderTarget.Canvas->GetWidth();
|
||||
h = mRenderTarget.Canvas->GetHeight();
|
||||
}
|
||||
PolyTriangleDrawer::SetViewport(fb->GetDrawCommands(), x, mRenderTarget.Canvas->GetHeight() - y - h, w, h, mRenderTarget.Canvas, mRenderTarget.DepthStencil);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDepthTest(bool on)
|
||||
{
|
||||
PolyTriangleDrawer::EnableDepthTest(GetPolyFrameBuffer()->GetDrawCommands(), on);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableMultisampling(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableLineSmooth(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDrawBuffers(int count)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::Apply()
|
||||
{
|
||||
drawcalls.Clock();
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
|
||||
int fogset = 0;
|
||||
if (mFogEnabled)
|
||||
{
|
||||
if (mFogEnabled == 2)
|
||||
{
|
||||
fogset = -3; // 2D rendering with 'foggy' overlay.
|
||||
}
|
||||
else if ((GetFogColor() & 0xffffff) == 0)
|
||||
{
|
||||
fogset = gl_fogmode;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogset = -gl_fogmode;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyMaterial();
|
||||
|
||||
if (mVertexBuffer) PolyTriangleDrawer::SetVertexBuffer(fb->GetDrawCommands(), mVertexBuffer->Memory());
|
||||
if (mIndexBuffer) PolyTriangleDrawer::SetIndexBuffer(fb->GetDrawCommands(), mIndexBuffer->Memory());
|
||||
PolyTriangleDrawer::SetInputAssembly(fb->GetDrawCommands(), static_cast<PolyVertexBuffer*>(mVertexBuffer)->VertexFormat);
|
||||
PolyTriangleDrawer::SetRenderStyle(fb->GetDrawCommands(), mRenderStyle);
|
||||
|
||||
if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
PolyTriangleDrawer::SetShader(fb->GetDrawCommands(), mSpecialEffect, 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0);
|
||||
PolyTriangleDrawer::SetShader(fb->GetDrawCommands(), EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f);
|
||||
}
|
||||
|
||||
PolyPushConstants constants;
|
||||
constants.uFogEnabled = fogset;
|
||||
constants.uTextureMode = mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode;
|
||||
constants.uLightDist = mLightParms[0];
|
||||
constants.uLightFactor = mLightParms[1];
|
||||
constants.uFogDensity = mLightParms[2];
|
||||
constants.uLightLevel = mLightParms[3];
|
||||
constants.uAlphaThreshold = mAlphaThreshold;
|
||||
constants.uClipSplit = { mClipSplit[0], mClipSplit[1] };
|
||||
constants.uLightIndex = mLightIndex;
|
||||
|
||||
PolyTriangleDrawer::PushStreamData(fb->GetDrawCommands(), mStreamData, constants);
|
||||
ApplyMatrices();
|
||||
|
||||
if (mBias.mChanged)
|
||||
{
|
||||
PolyTriangleDrawer::SetDepthBias(fb->GetDrawCommands(), mBias.mUnits, mBias.mFactor);
|
||||
mBias.mChanged = false;
|
||||
}
|
||||
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void PolyRenderState::ApplyMaterial()
|
||||
{
|
||||
if (mMaterial.mChanged && mMaterial.mMaterial)
|
||||
{
|
||||
mTempTM = mMaterial.mMaterial->tex->isHardwareCanvas() ? TM_OPAQUE : TM_NORMAL;
|
||||
|
||||
auto base = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation));
|
||||
if (base)
|
||||
{
|
||||
DCanvas *texcanvas = base->GetImage(mMaterial);
|
||||
PolyTriangleDrawer::SetTexture(GetPolyFrameBuffer()->GetDrawCommands(), 0, texcanvas->GetPixels(), texcanvas->GetHeight(), texcanvas->GetWidth(), texcanvas->IsBgra());
|
||||
|
||||
int numLayers = mMaterial.mMaterial->GetLayers();
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
FTexture* layer;
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(i, 0, &layer));
|
||||
|
||||
texcanvas = systex->GetImage(layer, 0, mMaterial.mMaterial->isExpanded() ? CTF_Expand : 0);
|
||||
PolyTriangleDrawer::SetTexture(GetPolyFrameBuffer()->GetDrawCommands(), i, texcanvas->GetPixels(), texcanvas->GetHeight(), texcanvas->GetWidth(), texcanvas->IsBgra());
|
||||
}
|
||||
}
|
||||
|
||||
mMaterial.mChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void BufferedSet(bool &modified, T &dst, const T &src)
|
||||
{
|
||||
if (dst == src)
|
||||
return;
|
||||
dst = src;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
static void BufferedSet(bool &modified, VSMatrix &dst, const VSMatrix &src)
|
||||
{
|
||||
if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0)
|
||||
return;
|
||||
dst = src;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::ApplyMatrices()
|
||||
{
|
||||
bool modified = mFirstMatrixApply;
|
||||
if (mTextureMatrixEnabled)
|
||||
{
|
||||
BufferedSet(modified, mMatrices.TextureMatrix, mTextureMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix);
|
||||
}
|
||||
|
||||
if (mModelMatrixEnabled)
|
||||
{
|
||||
BufferedSet(modified, mMatrices.ModelMatrix, mModelMatrix);
|
||||
if (modified)
|
||||
mMatrices.NormalModelMatrix.computeNormalMatrix(mModelMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix);
|
||||
BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix);
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
mFirstMatrixApply = false;
|
||||
PolyTriangleDrawer::PushMatrices(GetPolyFrameBuffer()->GetDrawCommands(), mMatrices.ModelMatrix, mMatrices.NormalModelMatrix, mMatrices.TextureMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderState::SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil)
|
||||
{
|
||||
mRenderTarget.Canvas = canvas;
|
||||
mRenderTarget.DepthStencil = depthStencil;
|
||||
PolyTriangleDrawer::SetViewport(GetPolyFrameBuffer()->GetDrawCommands(), 0, 0, canvas->GetWidth(), canvas->GetHeight(), canvas, depthStencil);
|
||||
}
|
||||
|
||||
void PolyRenderState::Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length)
|
||||
{
|
||||
if (buffer->bindingpoint == VIEWPOINT_BINDINGPOINT)
|
||||
{
|
||||
mViewpointUniforms = reinterpret_cast<HWViewpointUniforms*>(static_cast<uint8_t*>(buffer->Memory()) + offset);
|
||||
PolyTriangleDrawer::SetViewpointUniforms(GetPolyFrameBuffer()->GetDrawCommands(), mViewpointUniforms);
|
||||
}
|
||||
}
|
||||
|
||||
PolyVertexInputAssembly *PolyRenderState::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
||||
{
|
||||
for (size_t i = 0; i < mVertexFormats.size(); i++)
|
||||
{
|
||||
auto f = mVertexFormats[i].get();
|
||||
if (f->Attrs.size() == (size_t)numAttributes && f->NumBindingPoints == numBindingPoints && f->Stride == stride)
|
||||
{
|
||||
bool matches = true;
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
if (memcmp(&f->Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0)
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
auto fmt = std::make_unique<PolyVertexInputAssembly>();
|
||||
fmt->NumBindingPoints = numBindingPoints;
|
||||
fmt->Stride = stride;
|
||||
fmt->UseVertexData = 0;
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
if (attrs[j].location == VATTR_COLOR)
|
||||
fmt->UseVertexData |= 1;
|
||||
else if (attrs[j].location == VATTR_NORMAL)
|
||||
fmt->UseVertexData |= 2;
|
||||
fmt->Attrs.push_back(attrs[j]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
fmt->mOffsets[attrs[j].location] = attrs[j].offset;
|
||||
}
|
||||
fmt->mStride = stride;
|
||||
|
||||
mVertexFormats.push_back(std::move(fmt));
|
||||
return mVertexFormats.back().get();
|
||||
}
|
72
src/rendering/polyrenderer/backend/poly_renderstate.h
Normal file
72
src/rendering/polyrenderer/backend/poly_renderstate.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/backend/poly_buffers.h"
|
||||
#include "rendering/polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
#include "name.h"
|
||||
|
||||
#include "hwrenderer/scene/hw_drawstructs.h"
|
||||
#include "hwrenderer/scene/hw_renderstate.h"
|
||||
#include "hwrenderer/textures/hw_material.h"
|
||||
|
||||
struct HWViewpointUniforms;
|
||||
|
||||
class PolyRenderState : public FRenderState
|
||||
{
|
||||
public:
|
||||
PolyRenderState();
|
||||
|
||||
// Draw commands
|
||||
void ClearScreen() override;
|
||||
void Draw(int dt, int index, int count, bool apply = true) override;
|
||||
void DrawIndexed(int dt, int index, int count, bool apply = true) override;
|
||||
|
||||
// Immediate render state change commands. These only change infrequently and should not clutter the render state.
|
||||
bool SetDepthClamp(bool on) override;
|
||||
void SetDepthMask(bool on) override;
|
||||
void SetDepthFunc(int func) override;
|
||||
void SetDepthRange(float min, float max) override;
|
||||
void SetColorMask(bool r, bool g, bool b, bool a) override;
|
||||
void SetStencil(int offs, int op, int flags = -1) override;
|
||||
void SetCulling(int mode) override;
|
||||
void EnableClipDistance(int num, bool state) override;
|
||||
void Clear(int targets) override;
|
||||
void EnableStencil(bool on) override;
|
||||
void SetScissor(int x, int y, int w, int h) override;
|
||||
void SetViewport(int x, int y, int w, int h) override;
|
||||
void EnableDepthTest(bool on) override;
|
||||
void EnableMultisampling(bool on) override;
|
||||
void EnableLineSmooth(bool on) override;
|
||||
void EnableDrawBuffers(int count) override;
|
||||
|
||||
void SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil);
|
||||
void Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length);
|
||||
PolyVertexInputAssembly *GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs);
|
||||
|
||||
private:
|
||||
void Apply();
|
||||
void ApplyMaterial();
|
||||
void ApplyMatrices();
|
||||
|
||||
struct Matrices
|
||||
{
|
||||
VSMatrix ModelMatrix;
|
||||
VSMatrix NormalModelMatrix;
|
||||
VSMatrix TextureMatrix;
|
||||
} mMatrices;
|
||||
VSMatrix mIdentityMatrix;
|
||||
bool mFirstMatrixApply = true;
|
||||
|
||||
HWViewpointUniforms *mViewpointUniforms = nullptr;
|
||||
std::vector<std::unique_ptr<PolyVertexInputAssembly>> mVertexFormats;
|
||||
|
||||
bool mDepthClamp = true;
|
||||
int mTempTM = TM_NORMAL;
|
||||
|
||||
struct RenderTarget
|
||||
{
|
||||
DCanvas *Canvas = nullptr;
|
||||
PolyDepthStencil *DepthStencil = nullptr;
|
||||
} mRenderTarget;
|
||||
};
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
|
||||
#include "w_wad.h"
|
||||
#include "v_video.h"
|
||||
#include "doomstat.h"
|
||||
#include "st_stuff.h"
|
||||
#include "g_game.h"
|
||||
#include "g_level.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "poly_buffer.h"
|
||||
#include "screen_triangle.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyZBuffer *PolyZBuffer::Instance()
|
||||
{
|
||||
static PolyZBuffer buffer;
|
||||
return &buffer;
|
||||
}
|
||||
|
||||
void PolyZBuffer::Resize(int newwidth, int newheight)
|
||||
{
|
||||
width = newwidth;
|
||||
height = newheight;
|
||||
values.resize(width * height);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyStencilBuffer *PolyStencilBuffer::Instance()
|
||||
{
|
||||
static PolyStencilBuffer buffer;
|
||||
return &buffer;
|
||||
}
|
||||
|
||||
void PolyStencilBuffer::Resize(int newwidth, int newheight)
|
||||
{
|
||||
width = newwidth;
|
||||
height = newheight;
|
||||
values.resize(width * height);
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct TriVertex;
|
||||
|
||||
class PolyZBuffer
|
||||
{
|
||||
public:
|
||||
static PolyZBuffer *Instance();
|
||||
void Resize(int newwidth, int newheight);
|
||||
int Width() const { return width; }
|
||||
int Height() const { return height; }
|
||||
float *Values() { return values.data(); }
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
std::vector<float> values;
|
||||
};
|
||||
|
||||
class PolyStencilBuffer
|
||||
{
|
||||
public:
|
||||
static PolyStencilBuffer *Instance();
|
||||
void Resize(int newwidth, int newheight);
|
||||
int Width() const { return width; }
|
||||
int Height() const { return height; }
|
||||
uint8_t *Values() { return values.data(); }
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
std::vector<uint8_t> values;
|
||||
};
|
|
@ -1,353 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
|
||||
#include "w_wad.h"
|
||||
#include "v_video.h"
|
||||
#include "doomstat.h"
|
||||
#include "st_stuff.h"
|
||||
#include "g_game.h"
|
||||
#include "g_level.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
#include "poly_draw_args.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
void PolyDrawArgs::SetTexture(const uint8_t *texels, int width, int height)
|
||||
{
|
||||
mTexture = nullptr;
|
||||
mTexturePixels = texels;
|
||||
mTextureWidth = width;
|
||||
mTextureHeight = height;
|
||||
mTranslation = nullptr;
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetTexture(FSoftwareTexture *texture, FRenderStyle style)
|
||||
{
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetPhysicalWidth();
|
||||
mTextureHeight = texture->GetPhysicalHeight();
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
mTexturePixels = (const uint8_t *)texture->GetPixelsBgra();
|
||||
else
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
mTranslation = nullptr;
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style)
|
||||
{
|
||||
// Alphatexture overrides translations.
|
||||
if (translationID != 0xffffffff && translationID != 0 && !(style.Flags & STYLEF_RedIsAlpha))
|
||||
{
|
||||
FRemapTable *table = TranslationToTable(translationID);
|
||||
if (table != nullptr && !table->Inactive)
|
||||
{
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
mTranslation = (uint8_t*)table->Palette;
|
||||
else
|
||||
mTranslation = table->Remap;
|
||||
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetPhysicalWidth();
|
||||
mTextureHeight = texture->GetPhysicalHeight();
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (style.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetPhysicalWidth();
|
||||
mTextureHeight = texture->GetPhysicalHeight();
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTexture(texture, style);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel, double globVis, bool fixed)
|
||||
{
|
||||
mGlobVis = (float)globVis;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
lightlevel = cameraLight->FixedLightLevel() >= 0 ? cameraLight->FixedLightLevel() : 255;
|
||||
fixed = true;
|
||||
}
|
||||
|
||||
mLight = clamp<uint32_t>(lightlevel, 0, 255);
|
||||
mFixedLight = fixed;
|
||||
mLightRed = base_colormap->Color.r;
|
||||
mLightRed += mLightRed >> 7;
|
||||
mLightGreen = base_colormap->Color.g;
|
||||
mLightGreen += mLightGreen >> 7;
|
||||
mLightBlue = base_colormap->Color.b;
|
||||
mLightBlue += mLightBlue >> 7;
|
||||
mLightAlpha = base_colormap->Color.a;
|
||||
mLightAlpha += mLightAlpha >> 7;
|
||||
mFadeRed = base_colormap->Fade.r;
|
||||
mFadeRed += mFadeRed >> 7;
|
||||
mFadeGreen = base_colormap->Fade.g;
|
||||
mFadeGreen += mFadeGreen >> 7;
|
||||
mFadeBlue = base_colormap->Fade.b;
|
||||
mFadeBlue += mFadeBlue >> 7;
|
||||
mFadeAlpha = base_colormap->Fade.a;
|
||||
mFadeAlpha += mFadeAlpha >> 7;
|
||||
mDesaturate = MIN(abs(base_colormap->Desaturate), 255);
|
||||
mDesaturate += mDesaturate >> 7;
|
||||
mSimpleShade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0);
|
||||
mColormaps = base_colormap->Maps;
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
|
||||
{
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
{
|
||||
mColor = bgra;
|
||||
}
|
||||
else
|
||||
{
|
||||
mColor = palindex;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *tex, bool fullbright)
|
||||
{
|
||||
SetTexture(tex, translationID, renderstyle);
|
||||
SetColor(0xff000000 | fillcolor, fillcolor >> 24);
|
||||
|
||||
if (renderstyle == LegacyRenderStyles[STYLE_Normal] || (r_drawfuzz == 0 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::NormalTranslated : TriBlendMode::Normal, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Add] && fullbright && alpha == 1.0 && !Translation())
|
||||
{
|
||||
SetStyle(TriBlendMode::SrcColor, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_SoulTrans])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddTranslated : TriBlendMode::Add, transsouls);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Fuzzy] || (r_drawfuzz == 1 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetColor(0xff000000, 0);
|
||||
SetStyle(TriBlendMode::Fuzzy);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Shadow] || (r_drawfuzz == 2 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetColor(0xff000000, 0);
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentStencilTranslated : TriBlendMode::TranslucentStencil, 1.0 - 160 / 255.0);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Stencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::StencilTranslated : TriBlendMode::Stencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Translucent])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentTranslated : TriBlendMode::Translucent, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Add])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddTranslated : TriBlendMode::Add, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Shaded])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::ShadedTranslated : TriBlendMode::Shaded, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_TranslucentStencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentStencilTranslated : TriBlendMode::TranslucentStencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Subtract])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::SubtractTranslated : TriBlendMode::Subtract, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_AddStencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddStencilTranslated : TriBlendMode::AddStencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_AddShaded])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddShadedTranslated : TriBlendMode::AddShaded, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RectDrawArgs::SetTexture(FSoftwareTexture *texture, FRenderStyle style)
|
||||
{
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetWidth();
|
||||
mTextureHeight = texture->GetHeight();
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
mTexturePixels = (const uint8_t *)texture->GetPixelsBgra();
|
||||
else
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
mTranslation = nullptr;
|
||||
}
|
||||
|
||||
void RectDrawArgs::SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style)
|
||||
{
|
||||
// Alphatexture overrides translations.
|
||||
if (translationID != 0xffffffff && translationID != 0 && !(style.Flags & STYLEF_RedIsAlpha))
|
||||
{
|
||||
FRemapTable *table = TranslationToTable(translationID);
|
||||
if (table != nullptr && !table->Inactive)
|
||||
{
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
mTranslation = (uint8_t*)table->Palette;
|
||||
else
|
||||
mTranslation = table->Remap;
|
||||
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetWidth();
|
||||
mTextureHeight = texture->GetHeight();
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (style.Flags & STYLEF_RedIsAlpha)
|
||||
{
|
||||
mTexture = texture;
|
||||
mTextureWidth = texture->GetWidth();
|
||||
mTextureHeight = texture->GetHeight();
|
||||
mTexturePixels = texture->GetPixels(style);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTexture(texture, style);
|
||||
}
|
||||
}
|
||||
|
||||
void RectDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel)
|
||||
{
|
||||
mLight = clamp<uint32_t>(lightlevel, 0, 255);
|
||||
mLightRed = base_colormap->Color.r * 256 / 255;
|
||||
mLightGreen = base_colormap->Color.g * 256 / 255;
|
||||
mLightBlue = base_colormap->Color.b * 256 / 255;
|
||||
mLightAlpha = base_colormap->Color.a * 256 / 255;
|
||||
mFadeRed = base_colormap->Fade.r;
|
||||
mFadeGreen = base_colormap->Fade.g;
|
||||
mFadeBlue = base_colormap->Fade.b;
|
||||
mFadeAlpha = base_colormap->Fade.a;
|
||||
mDesaturate = MIN(abs(base_colormap->Desaturate), 255) * 255 / 256;
|
||||
mSimpleShade = (base_colormap->Color.d == 0x00ffffff && base_colormap->Fade.d == 0x00000000 && base_colormap->Desaturate == 0);
|
||||
mColormaps = base_colormap->Maps;
|
||||
}
|
||||
|
||||
void RectDrawArgs::SetColor(uint32_t bgra, uint8_t palindex)
|
||||
{
|
||||
if (PolyTriangleDrawer::IsBgra())
|
||||
{
|
||||
mColor = bgra;
|
||||
}
|
||||
else
|
||||
{
|
||||
mColor = palindex;
|
||||
}
|
||||
}
|
||||
|
||||
void RectDrawArgs::Draw(PolyRenderThread *thread, double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1)
|
||||
{
|
||||
mX0 = (float)x0;
|
||||
mX1 = (float)x1;
|
||||
mY0 = (float)y0;
|
||||
mY1 = (float)y1;
|
||||
mU0 = (float)u0;
|
||||
mU1 = (float)u1;
|
||||
mV0 = (float)v0;
|
||||
mV1 = (float)v1;
|
||||
|
||||
thread->DrawQueue->Push<DrawRectCommand>(*this);
|
||||
}
|
||||
|
||||
void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *tex, bool fullbright)
|
||||
{
|
||||
SetTexture(tex, translationID, renderstyle);
|
||||
SetColor(0xff000000 | fillcolor, fillcolor >> 24);
|
||||
|
||||
if (renderstyle == LegacyRenderStyles[STYLE_Normal] || (r_drawfuzz == 0 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::NormalTranslated : TriBlendMode::Normal, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Add] && fullbright && alpha == 1.0 && !Translation())
|
||||
{
|
||||
SetStyle(TriBlendMode::SrcColor, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_SoulTrans])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddTranslated : TriBlendMode::Add, transsouls);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Fuzzy] || (r_drawfuzz == 1 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetColor(0xff000000, 0);
|
||||
SetStyle(TriBlendMode::Fuzzy);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Shadow] || (r_drawfuzz == 2 && renderstyle == LegacyRenderStyles[STYLE_OptFuzzy]))
|
||||
{
|
||||
SetColor(0xff000000, 0);
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentStencilTranslated : TriBlendMode::TranslucentStencil, 1.0 - 160 / 255.0);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Stencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::StencilTranslated : TriBlendMode::Stencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Translucent])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentTranslated : TriBlendMode::Translucent, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Add])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddTranslated : TriBlendMode::Add, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Shaded])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::ShadedTranslated : TriBlendMode::Shaded, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_TranslucentStencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::TranslucentStencilTranslated : TriBlendMode::TranslucentStencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_Subtract])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::SubtractTranslated : TriBlendMode::Subtract, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_AddStencil])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddStencilTranslated : TriBlendMode::AddStencil, alpha);
|
||||
}
|
||||
else if (renderstyle == LegacyRenderStyles[STYLE_AddShaded])
|
||||
{
|
||||
SetStyle(Translation() ? TriBlendMode::AddShadedTranslated : TriBlendMode::AddShaded, alpha);
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "r_data/r_translate.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "screen_triangle.h"
|
||||
|
||||
class PolyRenderThread;
|
||||
class FSoftwareTexture;
|
||||
class Mat4f;
|
||||
|
||||
enum class PolyDrawMode
|
||||
{
|
||||
Triangles,
|
||||
TriangleFan,
|
||||
TriangleStrip
|
||||
};
|
||||
|
||||
class PolyClipPlane
|
||||
{
|
||||
public:
|
||||
PolyClipPlane() : A(0.0f), B(0.0f), C(0.0f), D(1.0f) { }
|
||||
PolyClipPlane(float a, float b, float c, float d) : A(a), B(b), C(c), D(d) { }
|
||||
|
||||
float A, B, C, D;
|
||||
};
|
||||
|
||||
struct TriVertex
|
||||
{
|
||||
TriVertex() { }
|
||||
TriVertex(float x, float y, float z, float w, float u, float v) : x(x), y(y), z(z), w(w), u(u), v(v) { }
|
||||
|
||||
float x, y, z, w;
|
||||
float u, v;
|
||||
};
|
||||
|
||||
struct PolyLight
|
||||
{
|
||||
uint32_t color;
|
||||
float x, y, z;
|
||||
float radius;
|
||||
};
|
||||
|
||||
class PolyDrawArgs
|
||||
{
|
||||
public:
|
||||
void SetClipPlane(int index, const PolyClipPlane &plane) { mClipPlane[index] = plane; }
|
||||
void SetTexture(const uint8_t *texels, int width, int height);
|
||||
void SetTexture(FSoftwareTexture *texture, FRenderStyle style);
|
||||
void SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style);
|
||||
void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed);
|
||||
void SetDepthTest(bool enable) { mDepthTest = enable; }
|
||||
void SetStencilTestValue(uint8_t stencilTestValue) { mStencilTestValue = stencilTestValue; }
|
||||
void SetWriteColor(bool enable) { mWriteColor = enable; }
|
||||
void SetWriteStencil(bool enable, uint8_t stencilWriteValue = 0) { mWriteStencil = enable; mStencilWriteValue = stencilWriteValue; }
|
||||
void SetWriteDepth(bool enable) { mWriteDepth = enable; }
|
||||
void SetStyle(TriBlendMode blendmode, double alpha = 1.0) { mBlendMode = blendmode; mAlpha = (uint32_t)(alpha * 256.0 + 0.5); }
|
||||
void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *texture, bool fullbright);
|
||||
void SetColor(uint32_t bgra, uint8_t palindex);
|
||||
void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; }
|
||||
void SetDynLightColor(uint32_t color) { mDynLightColor = color; }
|
||||
|
||||
const PolyClipPlane &ClipPlane(int index) const { return mClipPlane[index]; }
|
||||
|
||||
bool WriteColor() const { return mWriteColor; }
|
||||
|
||||
FSoftwareTexture *Texture() const { return mTexture; }
|
||||
const uint8_t *TexturePixels() const { return mTexturePixels; }
|
||||
int TextureWidth() const { return mTextureWidth; }
|
||||
int TextureHeight() const { return mTextureHeight; }
|
||||
const uint8_t *Translation() const { return mTranslation; }
|
||||
|
||||
bool WriteStencil() const { return mWriteStencil; }
|
||||
uint8_t StencilTestValue() const { return mStencilTestValue; }
|
||||
uint8_t StencilWriteValue() const { return mStencilWriteValue; }
|
||||
|
||||
bool DepthTest() const { return mDepthTest; }
|
||||
bool WriteDepth() const { return mWriteDepth; }
|
||||
|
||||
TriBlendMode BlendMode() const { return mBlendMode; }
|
||||
uint32_t Color() const { return mColor; }
|
||||
uint32_t Alpha() const { return mAlpha; }
|
||||
|
||||
float GlobVis() const { return mGlobVis; }
|
||||
uint32_t Light() const { return mLight; }
|
||||
const uint8_t *BaseColormap() const { return mColormaps; }
|
||||
uint16_t ShadeLightAlpha() const { return mLightAlpha; }
|
||||
uint16_t ShadeLightRed() const { return mLightRed; }
|
||||
uint16_t ShadeLightGreen() const { return mLightGreen; }
|
||||
uint16_t ShadeLightBlue() const { return mLightBlue; }
|
||||
uint16_t ShadeFadeAlpha() const { return mFadeAlpha; }
|
||||
uint16_t ShadeFadeRed() const { return mFadeRed; }
|
||||
uint16_t ShadeFadeGreen() const { return mFadeGreen; }
|
||||
uint16_t ShadeFadeBlue() const { return mFadeBlue; }
|
||||
uint16_t ShadeDesaturate() const { return mDesaturate; }
|
||||
|
||||
bool SimpleShade() const { return mSimpleShade; }
|
||||
bool NearestFilter() const { return mNearestFilter; }
|
||||
bool FixedLight() const { return mFixedLight; }
|
||||
|
||||
PolyLight *Lights() const { return mLights; }
|
||||
int NumLights() const { return mNumLights; }
|
||||
uint32_t DynLightColor() const { return mDynLightColor; }
|
||||
|
||||
const FVector3 &Normal() const { return mNormal; }
|
||||
void SetNormal(const FVector3 &normal) { mNormal = normal; }
|
||||
|
||||
private:
|
||||
bool mDepthTest = false;
|
||||
bool mWriteStencil = true;
|
||||
bool mWriteColor = true;
|
||||
bool mWriteDepth = true;
|
||||
FSoftwareTexture *mTexture = nullptr;
|
||||
const uint8_t *mTexturePixels = nullptr;
|
||||
int mTextureWidth = 0;
|
||||
int mTextureHeight = 0;
|
||||
const uint8_t *mTranslation = nullptr;
|
||||
uint8_t mStencilTestValue = 0;
|
||||
uint8_t mStencilWriteValue = 0;
|
||||
const uint8_t *mColormaps = nullptr;
|
||||
PolyClipPlane mClipPlane[3];
|
||||
TriBlendMode mBlendMode = TriBlendMode::Fill;
|
||||
uint32_t mLight = 0;
|
||||
uint32_t mColor = 0;
|
||||
uint32_t mAlpha = 0;
|
||||
uint16_t mLightAlpha = 0;
|
||||
uint16_t mLightRed = 0;
|
||||
uint16_t mLightGreen = 0;
|
||||
uint16_t mLightBlue = 0;
|
||||
uint16_t mFadeAlpha = 0;
|
||||
uint16_t mFadeRed = 0;
|
||||
uint16_t mFadeGreen = 0;
|
||||
uint16_t mFadeBlue = 0;
|
||||
uint16_t mDesaturate = 0;
|
||||
float mGlobVis = 0.0f;
|
||||
bool mSimpleShade = true;
|
||||
bool mNearestFilter = true;
|
||||
bool mFixedLight = false;
|
||||
PolyLight *mLights = nullptr;
|
||||
int mNumLights = 0;
|
||||
FVector3 mNormal;
|
||||
uint32_t mDynLightColor = 0;
|
||||
};
|
||||
|
||||
class RectDrawArgs
|
||||
{
|
||||
public:
|
||||
void SetTexture(FSoftwareTexture *texture, FRenderStyle style);
|
||||
void SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style);
|
||||
void SetLight(FSWColormap *basecolormap, uint32_t lightlevel);
|
||||
void SetStyle(TriBlendMode blendmode, double alpha = 1.0) { mBlendMode = blendmode; mAlpha = (uint32_t)(alpha * 256.0 + 0.5); }
|
||||
void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *texture, bool fullbright);
|
||||
void SetColor(uint32_t bgra, uint8_t palindex);
|
||||
void Draw(PolyRenderThread *thread, double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1);
|
||||
|
||||
FSoftwareTexture *Texture() const { return mTexture; }
|
||||
const uint8_t *TexturePixels() const { return mTexturePixels; }
|
||||
int TextureWidth() const { return mTextureWidth; }
|
||||
int TextureHeight() const { return mTextureHeight; }
|
||||
const uint8_t *Translation() const { return mTranslation; }
|
||||
|
||||
TriBlendMode BlendMode() const { return mBlendMode; }
|
||||
uint32_t Color() const { return mColor; }
|
||||
uint32_t Alpha() const { return mAlpha; }
|
||||
|
||||
uint32_t Light() const { return mLight; }
|
||||
const uint8_t *BaseColormap() const { return mColormaps; }
|
||||
uint16_t ShadeLightAlpha() const { return mLightAlpha; }
|
||||
uint16_t ShadeLightRed() const { return mLightRed; }
|
||||
uint16_t ShadeLightGreen() const { return mLightGreen; }
|
||||
uint16_t ShadeLightBlue() const { return mLightBlue; }
|
||||
uint16_t ShadeFadeAlpha() const { return mFadeAlpha; }
|
||||
uint16_t ShadeFadeRed() const { return mFadeRed; }
|
||||
uint16_t ShadeFadeGreen() const { return mFadeGreen; }
|
||||
uint16_t ShadeFadeBlue() const { return mFadeBlue; }
|
||||
uint16_t ShadeDesaturate() const { return mDesaturate; }
|
||||
bool SimpleShade() const { return mSimpleShade; }
|
||||
|
||||
float X0() const { return mX0; }
|
||||
float X1() const { return mX1; }
|
||||
float Y0() const { return mY0; }
|
||||
float Y1() const { return mY1; }
|
||||
float U0() const { return mU0; }
|
||||
float U1() const { return mU1; }
|
||||
float V0() const { return mV0; }
|
||||
float V1() const { return mV1; }
|
||||
|
||||
private:
|
||||
FSoftwareTexture *mTexture = nullptr;
|
||||
const uint8_t *mTexturePixels = nullptr;
|
||||
int mTextureWidth = 0;
|
||||
int mTextureHeight = 0;
|
||||
const uint8_t *mTranslation = nullptr;
|
||||
const uint8_t *mColormaps = nullptr;
|
||||
TriBlendMode mBlendMode = TriBlendMode::Fill;
|
||||
uint32_t mLight = 0;
|
||||
uint32_t mColor = 0;
|
||||
uint32_t mAlpha = 0;
|
||||
uint16_t mLightAlpha = 0;
|
||||
uint16_t mLightRed = 0;
|
||||
uint16_t mLightGreen = 0;
|
||||
uint16_t mLightBlue = 0;
|
||||
uint16_t mFadeAlpha = 0;
|
||||
uint16_t mFadeRed = 0;
|
||||
uint16_t mFadeGreen = 0;
|
||||
uint16_t mFadeBlue = 0;
|
||||
uint16_t mDesaturate = 0;
|
||||
bool mSimpleShade = true;
|
||||
float mX0, mX1, mY0, mY1, mU0, mU1, mV0, mV1;
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -26,42 +26,138 @@
|
|||
#include "swrenderer/drawers/r_thread.h"
|
||||
#include "polyrenderer/drawers/screen_triangle.h"
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
#include "polyrenderer/drawers/poly_buffer.h"
|
||||
#include "polyrenderer/drawers/poly_draw_args.h"
|
||||
#include "polyrenderer/drawers/poly_vertex_shader.h"
|
||||
|
||||
class DCanvas;
|
||||
class PolyDrawerCommand;
|
||||
class PolyInputAssembly;
|
||||
class PolyDepthStencil;
|
||||
struct PolyPushConstants;
|
||||
|
||||
enum class PolyDrawMode
|
||||
{
|
||||
Points,
|
||||
Lines,
|
||||
Triangles,
|
||||
TriangleFan,
|
||||
TriangleStrip
|
||||
};
|
||||
|
||||
class PolyTriangleDrawer
|
||||
{
|
||||
public:
|
||||
static void ResizeBuffers(DCanvas *canvas);
|
||||
static void SetViewport(const DrawerCommandQueuePtr &queue, int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthStencil);
|
||||
static void SetInputAssembly(const DrawerCommandQueuePtr &queue, PolyInputAssembly *input);
|
||||
static void SetVertexBuffer(const DrawerCommandQueuePtr &queue, const void *vertices);
|
||||
static void SetIndexBuffer(const DrawerCommandQueuePtr &queue, const void *elements);
|
||||
static void SetLightBuffer(const DrawerCommandQueuePtr& queue, const void *lights);
|
||||
static void SetViewpointUniforms(const DrawerCommandQueuePtr &queue, const HWViewpointUniforms *uniforms);
|
||||
static void SetDepthClamp(const DrawerCommandQueuePtr &queue, bool on);
|
||||
static void SetDepthMask(const DrawerCommandQueuePtr &queue, bool on);
|
||||
static void SetDepthFunc(const DrawerCommandQueuePtr &queue, int func);
|
||||
static void SetDepthRange(const DrawerCommandQueuePtr &queue, float min, float max);
|
||||
static void SetDepthBias(const DrawerCommandQueuePtr &queue, float depthBiasConstantFactor, float depthBiasSlopeFactor);
|
||||
static void SetColorMask(const DrawerCommandQueuePtr &queue, bool r, bool g, bool b, bool a);
|
||||
static void SetStencil(const DrawerCommandQueuePtr &queue, int stencilRef, int op);
|
||||
static void SetCulling(const DrawerCommandQueuePtr &queue, int mode);
|
||||
static void EnableClipDistance(const DrawerCommandQueuePtr &queue, int num, bool state);
|
||||
static void EnableStencil(const DrawerCommandQueuePtr &queue, bool on);
|
||||
static void SetScissor(const DrawerCommandQueuePtr &queue, int x, int y, int w, int h);
|
||||
static void EnableDepthTest(const DrawerCommandQueuePtr &queue, bool on);
|
||||
static void SetRenderStyle(const DrawerCommandQueuePtr &queue, FRenderStyle style);
|
||||
static void SetTexture(const DrawerCommandQueuePtr &queue, int unit, void *pixels, int width, int height, bool bgra);
|
||||
static void SetShader(const DrawerCommandQueuePtr &queue, int specialEffect, int effectState, bool alphaTest);
|
||||
static void PushStreamData(const DrawerCommandQueuePtr &queue, const StreamData &data, const PolyPushConstants &constants);
|
||||
static void PushMatrices(const DrawerCommandQueuePtr &queue, const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix);
|
||||
static void ClearDepth(const DrawerCommandQueuePtr &queue, float value);
|
||||
static void ClearStencil(const DrawerCommandQueuePtr &queue, uint8_t value);
|
||||
static void SetViewport(const DrawerCommandQueuePtr &queue, int x, int y, int width, int height, DCanvas *canvas);
|
||||
static void SetCullCCW(const DrawerCommandQueuePtr &queue, bool ccw);
|
||||
static void SetTwoSided(const DrawerCommandQueuePtr &queue, bool twosided);
|
||||
static void SetWeaponScene(const DrawerCommandQueuePtr &queue, bool enable);
|
||||
static void SetModelVertexShader(const DrawerCommandQueuePtr &queue, int frame1, int frame2, float interpolationFactor);
|
||||
static void SetTransform(const DrawerCommandQueuePtr &queue, const Mat4f *objectToClip, const Mat4f *objectToWorld);
|
||||
static void DrawArray(const DrawerCommandQueuePtr &queue, const PolyDrawArgs &args, const void *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
static void DrawElements(const DrawerCommandQueuePtr &queue, const PolyDrawArgs &args, const void *vertices, const unsigned int *elements, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
static bool IsBgra();
|
||||
static void Draw(const DrawerCommandQueuePtr &queue, int index, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
static void DrawIndexed(const DrawerCommandQueuePtr &queue, int index, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
};
|
||||
|
||||
class PolyDepthStencil
|
||||
{
|
||||
public:
|
||||
PolyDepthStencil(int width, int height) : width(width), height(height), depthbuffer(width * height), stencilbuffer(width * height) { }
|
||||
|
||||
int Width() const { return width; }
|
||||
int Height() const { return height; }
|
||||
float *DepthValues() { return depthbuffer.data(); }
|
||||
uint8_t *StencilValues() { return stencilbuffer.data(); }
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
std::vector<float> depthbuffer;
|
||||
std::vector<uint8_t> stencilbuffer;
|
||||
};
|
||||
|
||||
struct PolyPushConstants
|
||||
{
|
||||
int uTextureMode;
|
||||
float uAlphaThreshold;
|
||||
Vec2f uClipSplit;
|
||||
|
||||
// Lighting + Fog
|
||||
float uLightLevel;
|
||||
float uFogDensity;
|
||||
float uLightFactor;
|
||||
float uLightDist;
|
||||
int uFogEnabled;
|
||||
|
||||
// dynamic lights
|
||||
int uLightIndex;
|
||||
};
|
||||
|
||||
class PolyInputAssembly
|
||||
{
|
||||
public:
|
||||
virtual void Load(PolyTriangleThreadData *thread, const void *vertices, int index) = 0;
|
||||
};
|
||||
|
||||
class PolyTriangleThreadData
|
||||
{
|
||||
public:
|
||||
PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y) : core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y) { }
|
||||
PolyTriangleThreadData(int32_t core, int32_t num_cores, int32_t numa_node, int32_t num_numa_nodes, int numa_start_y, int numa_end_y)
|
||||
: core(core), num_cores(num_cores), numa_node(numa_node), num_numa_nodes(num_numa_nodes), numa_start_y(numa_start_y), numa_end_y(numa_end_y)
|
||||
{
|
||||
}
|
||||
|
||||
void ClearDepth(float value);
|
||||
void ClearStencil(uint8_t value);
|
||||
void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra);
|
||||
void SetTransform(const Mat4f *objectToClip, const Mat4f *objectToWorld);
|
||||
void SetViewport(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil *depthstencil);
|
||||
|
||||
void SetCullCCW(bool value) { ccw = value; }
|
||||
void SetTwoSided(bool value) { twosided = value; }
|
||||
void SetWeaponScene(bool value) { weaponScene = value; }
|
||||
void SetModelVertexShader(int frame1, int frame2, float interpolationFactor) { modelFrame1 = frame1; modelFrame2 = frame2; modelInterpolationFactor = interpolationFactor; }
|
||||
|
||||
void DrawElements(const PolyDrawArgs &args, const void *vertices, const unsigned int *elements, int count, PolyDrawMode mode);
|
||||
void DrawArray(const PolyDrawArgs &args, const void *vertices, int vcount, PolyDrawMode mode);
|
||||
void SetInputAssembly(PolyInputAssembly *input) { inputAssembly = input; }
|
||||
void SetVertexBuffer(const void *data) { vertices = data; }
|
||||
void SetIndexBuffer(const void *data) { elements = (const unsigned int *)data; }
|
||||
void SetLightBuffer(const void *data) { lights = (const FVector4 *)data; }
|
||||
void SetViewpointUniforms(const HWViewpointUniforms *uniforms);
|
||||
void SetDepthClamp(bool on);
|
||||
void SetDepthMask(bool on);
|
||||
void SetDepthFunc(int func);
|
||||
void SetDepthRange(float min, float max);
|
||||
void SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor);
|
||||
void SetColorMask(bool r, bool g, bool b, bool a);
|
||||
void SetStencil(int stencilRef, int op);
|
||||
void SetCulling(int mode);
|
||||
void EnableClipDistance(int num, bool state);
|
||||
void EnableStencil(bool on);
|
||||
void SetScissor(int x, int y, int w, int h);
|
||||
void EnableDepthTest(bool on);
|
||||
void SetRenderStyle(FRenderStyle style);
|
||||
void SetTexture(int unit, const void *pixels, int width, int height, bool bgra);
|
||||
void SetShader(int specialEffect, int effectState, bool alphaTest);
|
||||
|
||||
void UpdateClip();
|
||||
|
||||
void PushStreamData(const StreamData &data, const PolyPushConstants &constants);
|
||||
void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix);
|
||||
|
||||
void DrawIndexed(int index, int count, PolyDrawMode mode);
|
||||
void Draw(int index, int vcount, PolyDrawMode mode);
|
||||
|
||||
int32_t core;
|
||||
int32_t num_cores;
|
||||
|
@ -90,14 +186,18 @@ public:
|
|||
return MAX(c, 0);
|
||||
}
|
||||
|
||||
// Varyings
|
||||
float worldposX[MAXWIDTH];
|
||||
float worldposY[MAXWIDTH];
|
||||
float worldposZ[MAXWIDTH];
|
||||
uint32_t texel[MAXWIDTH];
|
||||
int32_t texelV[MAXWIDTH];
|
||||
uint16_t lightarray[MAXWIDTH];
|
||||
uint32_t dynlights[MAXWIDTH];
|
||||
struct Scanline
|
||||
{
|
||||
float W[MAXWIDTH];
|
||||
float U[MAXWIDTH];
|
||||
float V[MAXWIDTH];
|
||||
float WorldX[MAXWIDTH];
|
||||
float WorldY[MAXWIDTH];
|
||||
float WorldZ[MAXWIDTH];
|
||||
uint32_t FragColor[MAXWIDTH];
|
||||
uint16_t lightarray[MAXWIDTH];
|
||||
//uint32_t dynlights[MAXWIDTH];
|
||||
} scanline;
|
||||
|
||||
static PolyTriangleThreadData *Get(DrawerThread *thread);
|
||||
|
||||
|
@ -106,29 +206,78 @@ public:
|
|||
int dest_height = 0;
|
||||
bool dest_bgra = false;
|
||||
uint8_t *dest = nullptr;
|
||||
bool weaponScene = false;
|
||||
PolyDepthStencil *depthstencil = nullptr;
|
||||
|
||||
float depthbias = 0.0f;
|
||||
|
||||
int viewport_y = 0;
|
||||
|
||||
struct ClipRect
|
||||
{
|
||||
int left = 0;
|
||||
int top = 0;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
} clip, scissor;
|
||||
|
||||
FRenderStyle RenderStyle;
|
||||
int SpecialEffect = EFF_NONE;
|
||||
int EffectState = 0;
|
||||
bool AlphaTest = false;
|
||||
const PolyPushConstants* PushConstants = nullptr;
|
||||
|
||||
const void *vertices = nullptr;
|
||||
const unsigned int *elements = nullptr;
|
||||
const FVector4 *lights = nullptr;
|
||||
|
||||
/*struct PolyLight
|
||||
{
|
||||
uint32_t color;
|
||||
float x, y, z;
|
||||
float radius;
|
||||
};
|
||||
|
||||
enum { maxPolyLights = 16 };
|
||||
PolyLight polyLights[maxPolyLights];*/
|
||||
|
||||
PolyMainVertexShader mainVertexShader;
|
||||
|
||||
struct TextureUnit
|
||||
{
|
||||
const void* pixels = nullptr;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
bool bgra = true;
|
||||
} textures[16];
|
||||
|
||||
bool DepthTest = false;
|
||||
bool StencilTest = true;
|
||||
bool WriteStencil = true;
|
||||
bool WriteColor = true;
|
||||
bool WriteDepth = true;
|
||||
uint8_t StencilTestValue = 0;
|
||||
uint8_t StencilWriteValue = 0;
|
||||
|
||||
private:
|
||||
ShadedTriVertex ShadeVertex(const PolyDrawArgs &drawargs, const void *vertices, int index);
|
||||
void DrawShadedTriangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args);
|
||||
static bool IsDegenerate(const ShadedTriVertex *vertices);
|
||||
ShadedTriVertex ShadeVertex(int index);
|
||||
void DrawShadedPoint(const ShadedTriVertex *const* vertex);
|
||||
void DrawShadedLine(const ShadedTriVertex *const* vertices);
|
||||
void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw, TriDrawTriangleArgs *args);
|
||||
static bool IsDegenerate(const ShadedTriVertex *const* vertices);
|
||||
static bool IsFrontfacing(TriDrawTriangleArgs *args);
|
||||
static int ClipEdge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert);
|
||||
|
||||
int ClipEdge(const ShadedTriVertex *const* verts);
|
||||
|
||||
int viewport_x = 0;
|
||||
int viewport_width = 0;
|
||||
int viewport_height = 0;
|
||||
bool ccw = true;
|
||||
bool twosided = false;
|
||||
const Mat4f *objectToClip = nullptr;
|
||||
const Mat4f *objectToWorld = nullptr;
|
||||
int modelFrame1 = -1;
|
||||
int modelFrame2 = -1;
|
||||
float modelInterpolationFactor = 0.0f;
|
||||
bool twosided = true;
|
||||
PolyInputAssembly *inputAssembly = nullptr;
|
||||
|
||||
enum { max_additional_vertices = 16 };
|
||||
float weightsbuffer[max_additional_vertices * 3 * 2];
|
||||
float *weights = nullptr;
|
||||
};
|
||||
|
||||
class PolyDrawerCommand : public DrawerCommand
|
||||
|
@ -136,70 +285,227 @@ class PolyDrawerCommand : public DrawerCommand
|
|||
public:
|
||||
};
|
||||
|
||||
class PolySetTransformCommand : public PolyDrawerCommand
|
||||
class PolySetDepthClampCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetTransformCommand(const Mat4f *objectToClip, const Mat4f *objectToWorld);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetDepthClampCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthClamp(on); }
|
||||
|
||||
private:
|
||||
const Mat4f *objectToClip;
|
||||
const Mat4f *objectToWorld;
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetCullCCWCommand : public PolyDrawerCommand
|
||||
class PolySetDepthMaskCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetCullCCWCommand(bool ccw);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetDepthMaskCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthMask(on); }
|
||||
|
||||
private:
|
||||
bool ccw;
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetTwoSidedCommand : public PolyDrawerCommand
|
||||
class PolySetDepthFuncCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetTwoSidedCommand(bool twosided);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetDepthFuncCommand(int func) : func(func) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthFunc(func); }
|
||||
|
||||
private:
|
||||
bool twosided;
|
||||
int func;
|
||||
};
|
||||
|
||||
class PolySetWeaponSceneCommand : public PolyDrawerCommand
|
||||
class PolySetDepthRangeCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetWeaponSceneCommand(bool value);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetDepthRangeCommand(float min, float max) : min(min), max(max) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthRange(min, max); }
|
||||
|
||||
private:
|
||||
bool value;
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
|
||||
class PolySetModelVertexShaderCommand : public PolyDrawerCommand
|
||||
class PolySetDepthBiasCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetModelVertexShaderCommand(int frame1, int frame2, float interpolationFactor);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetDepthBiasCommand(float depthBiasConstantFactor, float depthBiasSlopeFactor) : depthBiasConstantFactor(depthBiasConstantFactor), depthBiasSlopeFactor(depthBiasSlopeFactor) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetDepthBias(depthBiasConstantFactor, depthBiasSlopeFactor); }
|
||||
|
||||
private:
|
||||
int frame1;
|
||||
int frame2;
|
||||
float interpolationFactor;
|
||||
float depthBiasConstantFactor;
|
||||
float depthBiasSlopeFactor;
|
||||
};
|
||||
|
||||
class PolySetColorMaskCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetColorMaskCommand(bool r, bool g, bool b, bool a) : r(r), g(g), b(b), a(a) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetColorMask(r, g, b, a); }
|
||||
|
||||
private:
|
||||
bool r;
|
||||
bool g;
|
||||
bool b;
|
||||
bool a;
|
||||
};
|
||||
|
||||
class PolySetStencilCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetStencilCommand(int stencilRef, int op) : stencilRef(stencilRef), op(op) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetStencil(stencilRef, op); }
|
||||
|
||||
private:
|
||||
int stencilRef;
|
||||
int op;
|
||||
};
|
||||
|
||||
class PolySetCullingCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetCullingCommand(int mode) : mode(mode) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetCulling(mode); }
|
||||
|
||||
private:
|
||||
int mode;
|
||||
};
|
||||
|
||||
class PolyEnableClipDistanceCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyEnableClipDistanceCommand(int num, bool state) : num(num), state(state) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->EnableClipDistance(num, state); }
|
||||
|
||||
private:
|
||||
int num;
|
||||
bool state;
|
||||
};
|
||||
|
||||
class PolyEnableStencilCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyEnableStencilCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->EnableStencil(on); }
|
||||
|
||||
private:
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetScissorCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetScissorCommand(int x, int y, int w, int h) : x(x), y(y), w(w), h(h) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetScissor(x, y, w, h); }
|
||||
|
||||
private:
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
};
|
||||
|
||||
class PolyEnableDepthTestCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyEnableDepthTestCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->EnableDepthTest(on); }
|
||||
|
||||
private:
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetRenderStyleCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetRenderStyleCommand(FRenderStyle style) : style(style) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetRenderStyle(style); }
|
||||
|
||||
private:
|
||||
FRenderStyle style;
|
||||
};
|
||||
|
||||
class PolySetTextureCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetTextureCommand(int unit, void *pixels, int width, int height, bool bgra) : unit(unit), pixels(pixels), width(width), height(height), bgra(bgra) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetTexture(unit, pixels, width, height, bgra); }
|
||||
|
||||
private:
|
||||
int unit;
|
||||
void *pixels;
|
||||
int width;
|
||||
int height;
|
||||
bool bgra;
|
||||
};
|
||||
|
||||
class PolySetShaderCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetShaderCommand(int specialEffect, int effectState, bool alphaTest) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest); }
|
||||
|
||||
private:
|
||||
int specialEffect;
|
||||
int effectState;
|
||||
bool alphaTest;
|
||||
};
|
||||
|
||||
class PolySetVertexBufferCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetVertexBufferCommand(const void *vertices) : vertices(vertices) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetVertexBuffer(vertices); }
|
||||
|
||||
private:
|
||||
const void *vertices;
|
||||
};
|
||||
|
||||
class PolySetIndexBufferCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetIndexBufferCommand(const void *indices) : indices(indices) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetIndexBuffer(indices); }
|
||||
|
||||
private:
|
||||
const void *indices;
|
||||
};
|
||||
|
||||
class PolySetLightBufferCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetLightBufferCommand(const void *lights) : lights(lights) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetLightBuffer(lights); }
|
||||
|
||||
private:
|
||||
const void *lights;
|
||||
};
|
||||
|
||||
class PolySetInputAssemblyCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetInputAssemblyCommand(PolyInputAssembly *input) : input(input) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetInputAssembly(input); }
|
||||
|
||||
private:
|
||||
PolyInputAssembly *input;
|
||||
};
|
||||
|
||||
class PolyClearDepthCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyClearDepthCommand(float value) : value(value) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->ClearDepth(value); }
|
||||
|
||||
private:
|
||||
float value;
|
||||
};
|
||||
|
||||
class PolyClearStencilCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyClearStencilCommand(uint8_t value);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolyClearStencilCommand(uint8_t value) : value(value) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->ClearStencil(value); }
|
||||
|
||||
private:
|
||||
uint8_t value;
|
||||
|
@ -208,9 +514,9 @@ private:
|
|||
class PolySetViewportCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetViewportCommand(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetViewportCommand(int x, int y, int width, int height, uint8_t *dest, int dest_width, int dest_height, int dest_pitch, bool dest_bgra, PolyDepthStencil *depthstencil)
|
||||
: x(x), y(y), width(width), height(height), dest(dest), dest_width(dest_width), dest_height(dest_height), dest_pitch(dest_pitch), dest_bgra(dest_bgra), depthstencil(depthstencil) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetViewport(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil); }
|
||||
|
||||
private:
|
||||
int x;
|
||||
|
@ -222,30 +528,63 @@ private:
|
|||
int dest_height;
|
||||
int dest_pitch;
|
||||
bool dest_bgra;
|
||||
PolyDepthStencil *depthstencil;
|
||||
};
|
||||
|
||||
class DrawPolyTrianglesCommand : public PolyDrawerCommand
|
||||
class PolySetViewpointUniformsCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
DrawPolyTrianglesCommand(const PolyDrawArgs &args, const void *vertices, const unsigned int *elements, int count, PolyDrawMode mode);
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolySetViewpointUniformsCommand(const HWViewpointUniforms *uniforms) : uniforms(uniforms) {}
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->SetViewpointUniforms(uniforms); }
|
||||
|
||||
private:
|
||||
PolyDrawArgs args;
|
||||
const void *vertices;
|
||||
const unsigned int *elements;
|
||||
const HWViewpointUniforms *uniforms;
|
||||
};
|
||||
|
||||
class PolyPushMatricesCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyPushMatricesCommand(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix)
|
||||
: modelMatrix(modelMatrix), normalModelMatrix(normalModelMatrix), textureMatrix(textureMatrix) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->PushMatrices(modelMatrix, normalModelMatrix, textureMatrix); }
|
||||
|
||||
private:
|
||||
VSMatrix modelMatrix;
|
||||
VSMatrix normalModelMatrix;
|
||||
VSMatrix textureMatrix;
|
||||
};
|
||||
|
||||
class PolyPushStreamDataCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyPushStreamDataCommand(const StreamData &data, const PolyPushConstants &constants) : data(data), constants(constants) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->PushStreamData(data, constants); }
|
||||
|
||||
private:
|
||||
StreamData data;
|
||||
PolyPushConstants constants;
|
||||
};
|
||||
|
||||
class PolyDrawCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolyDrawCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->Draw(index, count, mode); }
|
||||
|
||||
private:
|
||||
int index;
|
||||
int count;
|
||||
PolyDrawMode mode;
|
||||
};
|
||||
|
||||
class DrawRectCommand : public PolyDrawerCommand
|
||||
class PolyDrawIndexedCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
DrawRectCommand(const RectDrawArgs &args) : args(args) { }
|
||||
|
||||
void Execute(DrawerThread *thread) override;
|
||||
PolyDrawIndexedCommand(int index, int count, PolyDrawMode mode) : index(index), count(count), mode(mode) { }
|
||||
void Execute(DrawerThread *thread) override { PolyTriangleThreadData::Get(thread)->DrawIndexed(index, count, mode); }
|
||||
|
||||
private:
|
||||
RectDrawArgs args;
|
||||
int index;
|
||||
int count;
|
||||
PolyDrawMode mode;
|
||||
};
|
||||
|
|
199
src/rendering/polyrenderer/drawers/poly_vertex_shader.h
Normal file
199
src/rendering/polyrenderer/drawers/poly_vertex_shader.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
#include "hwrenderer/scene/hw_viewpointuniforms.h"
|
||||
#include "hwrenderer/scene/hw_renderstate.h"
|
||||
|
||||
#ifndef NO_SSE
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
class ShadedTriVertex
|
||||
{
|
||||
public:
|
||||
Vec4f gl_Position;
|
||||
float gl_ClipDistance[5];
|
||||
Vec4f vTexCoord;
|
||||
uint32_t vColor;
|
||||
Vec4f pixelpos;
|
||||
Vec4f vWorldNormal;
|
||||
};
|
||||
|
||||
class PolyMainVertexShader : public ShadedTriVertex
|
||||
{
|
||||
public:
|
||||
// Input
|
||||
Vec4f aPosition;
|
||||
Vec2f aTexCoord;
|
||||
uint32_t aColor;
|
||||
Vec4f aVertex2;
|
||||
Vec4f aNormal;
|
||||
Vec4f aNormal2;
|
||||
|
||||
// Output
|
||||
Vec3f glowdist;
|
||||
Vec3f gradientdist;
|
||||
Vec4f vEyeNormal;
|
||||
|
||||
// Defines
|
||||
bool SIMPLE = false;
|
||||
bool SPHEREMAP = false;
|
||||
|
||||
// Uniforms
|
||||
VSMatrix ModelMatrix;
|
||||
VSMatrix NormalModelMatrix;
|
||||
VSMatrix TextureMatrix;
|
||||
StreamData Data;
|
||||
Vec2f uClipSplit;
|
||||
const HWViewpointUniforms *Viewpoint = nullptr;
|
||||
|
||||
void main()
|
||||
{
|
||||
Vec2f parmTexCoord = aTexCoord;
|
||||
Vec4f parmPosition = aPosition;
|
||||
|
||||
Vec4f worldcoord;
|
||||
if (SIMPLE)
|
||||
worldcoord = mul(ModelMatrix, mix(parmPosition, aVertex2, Data.uInterpolationFactor));
|
||||
else
|
||||
worldcoord = mul(ModelMatrix, parmPosition);
|
||||
|
||||
Vec4f eyeCoordPos = mul(Viewpoint->mViewMatrix, worldcoord);
|
||||
|
||||
vColor = aColor;
|
||||
|
||||
if (!SIMPLE)
|
||||
{
|
||||
pixelpos.X = worldcoord.X;
|
||||
pixelpos.Y = worldcoord.Y;
|
||||
pixelpos.Z = worldcoord.Z;
|
||||
pixelpos.W = -eyeCoordPos.Z / eyeCoordPos.W;
|
||||
|
||||
if (Data.uGlowTopColor.W > 0 || Data.uGlowBottomColor.W > 0)
|
||||
{
|
||||
float topatpoint = (Data.uGlowTopPlane.W + Data.uGlowTopPlane.X * worldcoord.X + Data.uGlowTopPlane.Y * worldcoord.Z) * Data.uGlowTopPlane.Z;
|
||||
float bottomatpoint = (Data.uGlowBottomPlane.W + Data.uGlowBottomPlane.X * worldcoord.X + Data.uGlowBottomPlane.Y * worldcoord.Z) * Data.uGlowBottomPlane.Z;
|
||||
glowdist.X = topatpoint - worldcoord.Y;
|
||||
glowdist.Y = worldcoord.Y - bottomatpoint;
|
||||
glowdist.Z = clamp(glowdist.X / (topatpoint - bottomatpoint), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (Data.uObjectColor2.a != 0)
|
||||
{
|
||||
float topatpoint = (Data.uGradientTopPlane.W + Data.uGradientTopPlane.X * worldcoord.X + Data.uGradientTopPlane.Y * worldcoord.Z) * Data.uGradientTopPlane.Z;
|
||||
float bottomatpoint = (Data.uGradientBottomPlane.W + Data.uGradientBottomPlane.X * worldcoord.X + Data.uGradientBottomPlane.Y * worldcoord.Z) * Data.uGradientBottomPlane.Z;
|
||||
gradientdist.X = topatpoint - worldcoord.Y;
|
||||
gradientdist.Y = worldcoord.Y - bottomatpoint;
|
||||
gradientdist.Z = clamp(gradientdist.X / (topatpoint - bottomatpoint), 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (Data.uSplitBottomPlane.Z != 0.0f)
|
||||
{
|
||||
gl_ClipDistance[3] = ((Data.uSplitTopPlane.W + Data.uSplitTopPlane.X * worldcoord.X + Data.uSplitTopPlane.Y * worldcoord.Z) * Data.uSplitTopPlane.Z) - worldcoord.Y;
|
||||
gl_ClipDistance[4] = worldcoord.Y - ((Data.uSplitBottomPlane.W + Data.uSplitBottomPlane.X * worldcoord.X + Data.uSplitBottomPlane.Y * worldcoord.Z) * Data.uSplitBottomPlane.Z);
|
||||
}
|
||||
|
||||
vWorldNormal = mul(NormalModelMatrix, Vec4f(normalize(mix3(aNormal, aNormal2, Data.uInterpolationFactor)), 1.0f));
|
||||
vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal);
|
||||
}
|
||||
|
||||
if (!SPHEREMAP)
|
||||
{
|
||||
vTexCoord = mul(TextureMatrix, Vec4f(parmTexCoord, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
Vec3f u = normalize3(eyeCoordPos);
|
||||
Vec3f n = normalize3(mul(Viewpoint->mNormalViewMatrix, Vec4f(parmTexCoord.X, 0.0f, parmTexCoord.Y, 0.0f)));
|
||||
Vec3f r = reflect(u, n);
|
||||
float m = 2.0f * sqrt(r.X*r.X + r.Y*r.Y + (r.Z + 1.0f)*(r.Z + 1.0f));
|
||||
vTexCoord.X = r.X / m + 0.5f;
|
||||
vTexCoord.Y = r.Y / m + 0.5f;
|
||||
}
|
||||
|
||||
gl_Position = mul(Viewpoint->mProjectionMatrix, eyeCoordPos);
|
||||
|
||||
if (Viewpoint->mClipHeightDirection != 0.0f) // clip planes used for reflective flats
|
||||
{
|
||||
gl_ClipDistance[0] = (worldcoord.Y - Viewpoint->mClipHeight) * Viewpoint->mClipHeightDirection;
|
||||
}
|
||||
else if (Viewpoint->mClipLine.X > -1000000.0f) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane.
|
||||
{
|
||||
gl_ClipDistance[0] = -((worldcoord.Z - Viewpoint->mClipLine.Y) * Viewpoint->mClipLine.Z + (Viewpoint->mClipLine.X - worldcoord.X) * Viewpoint->mClipLine.W) + 1.0f / 32768.0f; // allow a tiny bit of imprecisions for colinear linedefs.
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_ClipDistance[0] = 1.0f;
|
||||
}
|
||||
|
||||
// clip planes used for translucency splitting
|
||||
gl_ClipDistance[1] = worldcoord.Y - uClipSplit.X;
|
||||
gl_ClipDistance[2] = uClipSplit.Y - worldcoord.Y;
|
||||
|
||||
if (Data.uSplitTopPlane == FVector4(0.0f, 0.0f, 0.0f, 0.0f))
|
||||
{
|
||||
gl_ClipDistance[3] = 1.0f;
|
||||
gl_ClipDistance[4] = 1.0f;
|
||||
}
|
||||
|
||||
std::swap(vTexCoord.X, vTexCoord.Y); // textures are transposed because the software renderer did them this way
|
||||
}
|
||||
|
||||
private:
|
||||
static Vec3f normalize(const Vec3f &a)
|
||||
{
|
||||
float rcplen = 1.0f / sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z);
|
||||
return Vec3f(a.X * rcplen, a.Y * rcplen, a.Z * rcplen);
|
||||
}
|
||||
|
||||
static Vec3f normalize3(const Vec4f &a)
|
||||
{
|
||||
float rcplen = 1.0f / sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z);
|
||||
return Vec3f(a.X * rcplen, a.Y * rcplen, a.Z * rcplen);
|
||||
}
|
||||
|
||||
static Vec4f mix(const Vec4f &a, const Vec4f &b, float t)
|
||||
{
|
||||
float invt = 1.0f - t;
|
||||
return Vec4f(a.X * invt + b.X * t, a.Y * invt + b.Y * t, a.Z * invt + b.Z * t, a.W * invt + b.W * t);
|
||||
}
|
||||
|
||||
static Vec3f mix3(const Vec4f &a, const Vec4f &b, float t)
|
||||
{
|
||||
float invt = 1.0f - t;
|
||||
return Vec3f(a.X * invt + b.X * t, a.Y * invt + b.Y * t, a.Z * invt + b.Z * t);
|
||||
}
|
||||
|
||||
static Vec3f reflect(const Vec3f &u, const Vec3f &n)
|
||||
{
|
||||
float d = 2.0f * (n.X * u.X + n.Y * u.Y + n.Z * u.Z);
|
||||
return Vec3f(u.X - d * n.X, u.Y - d * n.Y, u.Z - d * n.Z);
|
||||
}
|
||||
|
||||
static Vec4f mul(const VSMatrix &mat, const Vec4f &v)
|
||||
{
|
||||
const float *m = mat.get();
|
||||
|
||||
Vec4f result;
|
||||
#ifdef NO_SSE
|
||||
result.X = m[0 * 4 + 0] * v.X + m[1 * 4 + 0] * v.Y + m[2 * 4 + 0] * v.Z + m[3 * 4 + 0] * v.W;
|
||||
result.Y = m[0 * 4 + 1] * v.X + m[1 * 4 + 1] * v.Y + m[2 * 4 + 1] * v.Z + m[3 * 4 + 1] * v.W;
|
||||
result.Z = m[0 * 4 + 2] * v.X + m[1 * 4 + 2] * v.Y + m[2 * 4 + 2] * v.Z + m[3 * 4 + 2] * v.W;
|
||||
result.W = m[0 * 4 + 3] * v.X + m[1 * 4 + 3] * v.Y + m[2 * 4 + 3] * v.Z + m[3 * 4 + 3] * v.W;
|
||||
#else
|
||||
__m128 m0 = _mm_loadu_ps(m);
|
||||
__m128 m1 = _mm_loadu_ps(m + 4);
|
||||
__m128 m2 = _mm_loadu_ps(m + 8);
|
||||
__m128 m3 = _mm_loadu_ps(m + 12);
|
||||
__m128 mv = _mm_loadu_ps(&v.X);
|
||||
m0 = _mm_mul_ps(m0, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(0, 0, 0, 0)));
|
||||
m1 = _mm_mul_ps(m1, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(1, 1, 1, 1)));
|
||||
m2 = _mm_mul_ps(m2, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
m3 = _mm_mul_ps(m3, _mm_shuffle_ps(mv, mv, _MM_SHUFFLE(3, 3, 3, 3)));
|
||||
mv = _mm_add_ps(_mm_add_ps(_mm_add_ps(m0, m1), m2), m3);
|
||||
_mm_storeu_ps(&result.X, mv);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -24,16 +24,16 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "r_data/renderstyle.h"
|
||||
#include "rendering/swrenderer/drawers/r_draw.h"
|
||||
|
||||
class FString;
|
||||
class PolyDrawArgs;
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
struct ShadedTriVertex
|
||||
struct ScreenTriVertex
|
||||
{
|
||||
float x, y, z, w;
|
||||
float u, v;
|
||||
float clipDistance[3];
|
||||
float worldX, worldY, worldZ;
|
||||
};
|
||||
|
||||
|
@ -45,10 +45,9 @@ struct ScreenTriangleStepVariables
|
|||
|
||||
struct TriDrawTriangleArgs
|
||||
{
|
||||
ShadedTriVertex *v1;
|
||||
ShadedTriVertex *v2;
|
||||
ShadedTriVertex *v3;
|
||||
const PolyDrawArgs *uniforms;
|
||||
ScreenTriVertex *v1;
|
||||
ScreenTriVertex *v2;
|
||||
ScreenTriVertex *v3;
|
||||
ScreenTriangleStepVariables gradientX;
|
||||
ScreenTriangleStepVariables gradientY;
|
||||
|
||||
|
@ -94,157 +93,25 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class RectDrawArgs;
|
||||
|
||||
enum class TriBlendMode
|
||||
{
|
||||
Opaque,
|
||||
Skycap,
|
||||
FogBoundary,
|
||||
SrcColor,
|
||||
Fill,
|
||||
Normal,
|
||||
Fuzzy,
|
||||
Stencil,
|
||||
Translucent,
|
||||
Add,
|
||||
Shaded,
|
||||
TranslucentStencil,
|
||||
Shadow,
|
||||
Subtract,
|
||||
AddStencil,
|
||||
AddShaded,
|
||||
OpaqueTranslated,
|
||||
SrcColorTranslated,
|
||||
NormalTranslated,
|
||||
StencilTranslated,
|
||||
TranslucentTranslated,
|
||||
AddTranslated,
|
||||
ShadedTranslated,
|
||||
TranslucentStencilTranslated,
|
||||
ShadowTranslated,
|
||||
SubtractTranslated,
|
||||
AddStencilTranslated,
|
||||
AddShadedTranslated
|
||||
};
|
||||
|
||||
class ScreenTriangle
|
||||
{
|
||||
public:
|
||||
static void Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
|
||||
static void Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
||||
|
||||
static void(*TriangleDrawers[])(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread, int16_t *edges, int topY, int bottomY);
|
||||
|
||||
static void(*SpanDrawers8[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
|
||||
static void(*SpanDrawers32[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
|
||||
static void(*RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *);
|
||||
static void(*RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *);
|
||||
|
||||
static int FuzzStart;
|
||||
private:
|
||||
static void(*TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
||||
};
|
||||
|
||||
namespace TriScreenDrawerModes
|
||||
{
|
||||
enum SWStyleFlags
|
||||
{
|
||||
SWSTYLEF_Translated = 1,
|
||||
SWSTYLEF_Skycap = 2,
|
||||
SWSTYLEF_FogBoundary = 4,
|
||||
SWSTYLEF_Fill = 8,
|
||||
SWSTYLEF_SrcColorOneMinusSrcColor = 16
|
||||
};
|
||||
|
||||
struct StyleOpaque { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_One, BlendDest = STYLEALPHA_Zero, Flags = STYLEF_Alpha1, SWFlags = 0; };
|
||||
struct StyleSkycap { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_One, BlendDest = STYLEALPHA_Zero, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_Skycap; };
|
||||
struct StyleFogBoundary { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_One, BlendDest = STYLEALPHA_Zero, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_FogBoundary; };
|
||||
struct StyleSrcColor { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_SrcColorOneMinusSrcColor; };
|
||||
struct StyleFill { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_One, BlendDest = STYLEALPHA_Zero, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_Fill; };
|
||||
|
||||
struct StyleNormal { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1, SWFlags = 0; };
|
||||
struct StyleFuzzy { static const int BlendOp = STYLEOP_Fuzz, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = 0, SWFlags = 0; };
|
||||
struct StyleStencil { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1 | STYLEF_ColorIsFixed, SWFlags = 0; };
|
||||
struct StyleTranslucent { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = 0, SWFlags = 0; };
|
||||
struct StyleAdd { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = 0, SWFlags = 0; };
|
||||
struct StyleShaded { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, SWFlags = 0; };
|
||||
struct StyleTranslucentStencil { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_ColorIsFixed, SWFlags = 0; };
|
||||
struct StyleShadow { static const int BlendOp = STYLEOP_Shadow, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = 0, SWFlags = 0; };
|
||||
struct StyleSubtract { static const int BlendOp = STYLEOP_RevSub, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = 0, SWFlags = 0; };
|
||||
struct StyleAddStencil { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = STYLEF_ColorIsFixed, SWFlags = 0; };
|
||||
struct StyleAddShaded { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, SWFlags = 0; };
|
||||
|
||||
struct StyleOpaqueTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_One, BlendDest = STYLEALPHA_Zero, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleSrcColorTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_Translated|SWSTYLEF_SrcColorOneMinusSrcColor; };
|
||||
struct StyleNormalTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleStencilTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_Alpha1 | STYLEF_ColorIsFixed, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleTranslucentTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = 0, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleAddTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = 0, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleShadedTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleTranslucentStencilTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = STYLEF_ColorIsFixed, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleShadowTranslated { static const int BlendOp = STYLEOP_Shadow, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_InvSrc, Flags = 0, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleSubtractTranslated { static const int BlendOp = STYLEOP_RevSub, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = 0, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleAddStencilTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = STYLEF_ColorIsFixed, SWFlags = SWSTYLEF_Translated; };
|
||||
struct StyleAddShadedTranslated { static const int BlendOp = STYLEOP_Add, BlendSrc = STYLEALPHA_Src, BlendDest = STYLEALPHA_One, Flags = STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, SWFlags = SWSTYLEF_Translated; };
|
||||
|
||||
enum SWOptFlags
|
||||
{
|
||||
SWOPT_DynLights = 1,
|
||||
SWOPT_ColoredFog = 2,
|
||||
SWOPT_FixedLight = 4
|
||||
};
|
||||
|
||||
struct DrawerOpt { static const int Flags = 0; };
|
||||
struct DrawerOptF { static const int Flags = SWOPT_FixedLight; };
|
||||
struct DrawerOptC { static const int Flags = SWOPT_ColoredFog; };
|
||||
struct DrawerOptCF { static const int Flags = SWOPT_ColoredFog | SWOPT_FixedLight; };
|
||||
struct DrawerOptL { static const int Flags = SWOPT_DynLights; };
|
||||
struct DrawerOptLC { static const int Flags = SWOPT_DynLights | SWOPT_ColoredFog; };
|
||||
struct DrawerOptLF { static const int Flags = SWOPT_DynLights | SWOPT_FixedLight; };
|
||||
struct DrawerOptLCF { static const int Flags = SWOPT_DynLights | SWOPT_ColoredFog | SWOPT_FixedLight; };
|
||||
|
||||
static const int fuzzcolormap[FUZZTABLE] =
|
||||
{
|
||||
6, 11, 6, 11, 6, 6, 11, 6, 6, 11,
|
||||
6, 6, 6, 11, 6, 6, 6, 11, 15, 18,
|
||||
21, 6, 11, 15, 6, 6, 6, 6, 11, 6,
|
||||
11, 6, 6, 11, 15, 6, 6, 11, 15, 18,
|
||||
21, 6, 6, 6, 6, 11, 6, 6, 11, 6,
|
||||
};
|
||||
|
||||
enum SWTriangleFlags
|
||||
enum SWTestSpan
|
||||
{
|
||||
SWTRI_DepthTest = 1,
|
||||
SWTRI_StencilTest = 2,
|
||||
SWTRI_WriteColor = 4,
|
||||
SWTRI_WriteDepth = 8,
|
||||
SWTRI_WriteStencil = 16
|
||||
SWTRI_StencilTest = 2
|
||||
};
|
||||
|
||||
struct TriangleOpt4 { static const int Flags = 4; };
|
||||
struct TriangleOpt5 { static const int Flags = 5; };
|
||||
struct TriangleOpt6 { static const int Flags = 6; };
|
||||
struct TriangleOpt7 { static const int Flags = 7; };
|
||||
struct TriangleOpt8 { static const int Flags = 8; };
|
||||
struct TriangleOpt9 { static const int Flags = 9; };
|
||||
struct TriangleOpt10 { static const int Flags = 10; };
|
||||
struct TriangleOpt11 { static const int Flags = 11; };
|
||||
struct TriangleOpt12 { static const int Flags = 12; };
|
||||
struct TriangleOpt13 { static const int Flags = 13; };
|
||||
struct TriangleOpt14 { static const int Flags = 14; };
|
||||
struct TriangleOpt15 { static const int Flags = 15; };
|
||||
struct TriangleOpt16 { static const int Flags = 16; };
|
||||
struct TriangleOpt17 { static const int Flags = 17; };
|
||||
struct TriangleOpt18 { static const int Flags = 18; };
|
||||
struct TriangleOpt19 { static const int Flags = 19; };
|
||||
struct TriangleOpt20 { static const int Flags = 20; };
|
||||
struct TriangleOpt21 { static const int Flags = 21; };
|
||||
struct TriangleOpt22 { static const int Flags = 22; };
|
||||
struct TriangleOpt23 { static const int Flags = 23; };
|
||||
struct TriangleOpt24 { static const int Flags = 24; };
|
||||
struct TriangleOpt25 { static const int Flags = 25; };
|
||||
struct TriangleOpt26 { static const int Flags = 26; };
|
||||
struct TriangleOpt27 { static const int Flags = 27; };
|
||||
struct TriangleOpt28 { static const int Flags = 28; };
|
||||
struct TriangleOpt29 { static const int Flags = 29; };
|
||||
struct TriangleOpt30 { static const int Flags = 30; };
|
||||
struct TriangleOpt31 { static const int Flags = 31; };
|
||||
struct TestSpanOpt0 { static const int Flags = 0; };
|
||||
struct TestSpanOpt1 { static const int Flags = 1; };
|
||||
struct TestSpanOpt2 { static const int Flags = 2; };
|
||||
struct TestSpanOpt3 { static const int Flags = 3; };
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ Mat4f Mat4f::Identity()
|
|||
return m;
|
||||
}
|
||||
|
||||
Mat4f Mat4f::FromValues(float *matrix)
|
||||
Mat4f Mat4f::FromValues(const float *matrix)
|
||||
{
|
||||
Mat4f m;
|
||||
memcpy(m.Matrix, matrix, sizeof(m.Matrix));
|
||||
|
|
|
@ -115,7 +115,7 @@ class Mat4f
|
|||
public:
|
||||
static Mat4f Null();
|
||||
static Mat4f Identity();
|
||||
static Mat4f FromValues(float *matrix);
|
||||
static Mat4f FromValues(const float *matrix);
|
||||
static Mat4f Transpose(const Mat4f &matrix);
|
||||
static Mat4f Translate(float x, float y, float z);
|
||||
static Mat4f Scale(float x, float y, float z);
|
||||
|
|
|
@ -1,21 +1,4 @@
|
|||
#include "../swrenderer/textures/r_swtexture.h"
|
||||
#include "poly_renderer.cpp"
|
||||
#include "poly_renderthread.cpp"
|
||||
#include "drawers/poly_buffer.cpp"
|
||||
#include "drawers/poly_draw_args.cpp"
|
||||
#include "drawers/poly_triangle.cpp"
|
||||
#include "drawers/screen_triangle.cpp"
|
||||
#include "math/gpu_types.cpp"
|
||||
#include "scene/poly_cull.cpp"
|
||||
#include "scene/poly_decal.cpp"
|
||||
#include "scene/poly_particle.cpp"
|
||||
#include "scene/poly_plane.cpp"
|
||||
#include "scene/poly_playersprite.cpp"
|
||||
#include "scene/poly_portal.cpp"
|
||||
#include "scene/poly_scene.cpp"
|
||||
#include "scene/poly_sky.cpp"
|
||||
#include "scene/poly_sprite.cpp"
|
||||
#include "scene/poly_model.cpp"
|
||||
#include "scene/poly_wall.cpp"
|
||||
#include "scene/poly_wallsprite.cpp"
|
||||
#include "scene/poly_light.cpp"
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "st_stuff.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "r_data/r_interpolate.h"
|
||||
#include "r_data/models/models.h"
|
||||
#include "poly_renderer.h"
|
||||
#include "d_net.h"
|
||||
#include "po_man.h"
|
||||
#include "st_stuff.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "p_effect.h"
|
||||
#include "actorinlines.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
EXTERN_CVAR(Float, r_visibility)
|
||||
EXTERN_CVAR(Bool, r_models)
|
||||
|
||||
extern bool r_modelscene;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyRenderer *PolyRenderer::Instance()
|
||||
{
|
||||
static PolyRenderer scene;
|
||||
return &scene;
|
||||
}
|
||||
|
||||
PolyRenderer::PolyRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch)
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
R_ExecuteSetViewSize(Viewpoint, Viewwindow);
|
||||
|
||||
RenderTarget = target;
|
||||
RenderToCanvas = false;
|
||||
|
||||
RenderActorView(player->mo, true, false);
|
||||
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(Threads.MainThread()->FrameMemory.get());
|
||||
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
|
||||
PolyDrawerWaitCycles.Clock();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
PolyDrawerWaitCycles.Unclock();
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
|
||||
{
|
||||
// Save a bunch of silly globals:
|
||||
auto savedViewpoint = Viewpoint;
|
||||
auto savedViewwindow = Viewwindow;
|
||||
auto savedviewwindowx = viewwindowx;
|
||||
auto savedviewwindowy = viewwindowy;
|
||||
auto savedviewwidth = viewwidth;
|
||||
auto savedviewheight = viewheight;
|
||||
auto savedviewactive = viewactive;
|
||||
auto savedRenderTarget = RenderTarget;
|
||||
|
||||
// Setup the view:
|
||||
RenderTarget = canvas;
|
||||
RenderToCanvas = true;
|
||||
R_SetWindow(Viewpoint, Viewwindow, 12, width, height, height, true);
|
||||
viewwindowx = x;
|
||||
viewwindowy = y;
|
||||
viewactive = true;
|
||||
|
||||
// Render:
|
||||
RenderActorView(actor, false, dontmaplines);
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
RenderToCanvas = false;
|
||||
|
||||
// Restore silly globals:
|
||||
Viewpoint = savedViewpoint;
|
||||
Viewwindow = savedViewwindow;
|
||||
viewwindowx = savedviewwindowx;
|
||||
viewwindowy = savedviewwindowy;
|
||||
viewwidth = savedviewwidth;
|
||||
viewheight = savedviewheight;
|
||||
viewactive = savedviewactive;
|
||||
RenderTarget = savedRenderTarget;
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderActorView(AActor *actor, bool drawpsprites, bool dontmaplines)
|
||||
{
|
||||
PolyTotalBatches = 0;
|
||||
PolyTotalTriangles = 0;
|
||||
PolyTotalDrawCalls = 0;
|
||||
PolyCullCycles.Reset();
|
||||
PolyOpaqueCycles.Reset();
|
||||
PolyMaskedCycles.Reset();
|
||||
PolyDrawerWaitCycles.Reset();
|
||||
|
||||
DontMapLines = dontmaplines;
|
||||
|
||||
R_SetupFrame(Viewpoint, Viewwindow, actor);
|
||||
Level = Viewpoint.ViewLevel;
|
||||
|
||||
static bool firstcall = true;
|
||||
if (firstcall)
|
||||
{
|
||||
swrenderer::R_InitFuzzTable(RenderTarget->GetPitch());
|
||||
firstcall = false;
|
||||
}
|
||||
|
||||
swrenderer::R_UpdateFuzzPosFrameStart();
|
||||
|
||||
if (APART(R_OldBlend)) NormalLight.Maps = realcolormaps.Maps;
|
||||
else NormalLight.Maps = realcolormaps.Maps + NUMCOLORMAPS * 256 * R_OldBlend;
|
||||
|
||||
Light.SetVisibility(Viewwindow, r_visibility);
|
||||
|
||||
PolyCameraLight::Instance()->SetCamera(Viewpoint, RenderTarget, actor);
|
||||
//Viewport->SetupFreelook();
|
||||
|
||||
ActorRenderFlags savedflags = 0;
|
||||
if (Viewpoint.camera)
|
||||
{
|
||||
savedflags = Viewpoint.camera->renderflags;
|
||||
|
||||
// Never draw the player unless in chasecam mode
|
||||
if (!Viewpoint.showviewer)
|
||||
Viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
|
||||
ScreenTriangle::FuzzStart = (ScreenTriangle::FuzzStart + 14) % FUZZTABLE;
|
||||
|
||||
r_modelscene = r_models && Models.Size() > 0;
|
||||
|
||||
NextStencilValue = 0;
|
||||
Threads.Clear();
|
||||
Threads.MainThread()->SectorPortals.clear();
|
||||
Threads.MainThread()->LinePortals.clear();
|
||||
Threads.MainThread()->TranslucentObjects.clear();
|
||||
|
||||
PolyTriangleDrawer::ResizeBuffers(RenderTarget);
|
||||
PolyTriangleDrawer::ClearStencil(Threads.MainThread()->DrawQueue, 0);
|
||||
SetSceneViewport();
|
||||
|
||||
PolyPortalViewpoint mainViewpoint = SetupPerspectiveMatrix();
|
||||
mainViewpoint.StencilValue = GetNextStencilValue();
|
||||
Scene.CurrentViewpoint = &mainViewpoint;
|
||||
Scene.Render(&mainViewpoint);
|
||||
if (drawpsprites)
|
||||
PlayerSprites.Render(Threads.MainThread());
|
||||
|
||||
Scene.CurrentViewpoint = nullptr;
|
||||
|
||||
if (Viewpoint.camera)
|
||||
Viewpoint.camera->renderflags = savedflags;
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderRemainingPlayerSprites()
|
||||
{
|
||||
PlayerSprites.RenderRemainingSprites();
|
||||
}
|
||||
|
||||
void PolyRenderer::SetSceneViewport()
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
if (!RenderToCanvas) // Rendering to screen
|
||||
{
|
||||
int height;
|
||||
if (screenblocks >= 10)
|
||||
height = SCREENHEIGHT;
|
||||
else
|
||||
height = (screenblocks*SCREENHEIGHT / 10) & ~7;
|
||||
|
||||
int bottom = SCREENHEIGHT - (height + viewwindowy - ((height - viewheight) / 2));
|
||||
PolyTriangleDrawer::SetViewport(Threads.MainThread()->DrawQueue, viewwindowx, SCREENHEIGHT - bottom - height, viewwidth, height, RenderTarget);
|
||||
}
|
||||
else // Rendering to camera texture
|
||||
{
|
||||
PolyTriangleDrawer::SetViewport(Threads.MainThread()->DrawQueue, 0, 0, RenderTarget->GetWidth(), RenderTarget->GetHeight(), RenderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
PolyPortalViewpoint PolyRenderer::SetupPerspectiveMatrix(bool mirror)
|
||||
{
|
||||
// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
|
||||
double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * PolyRenderer::Instance()->Level->info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
float adjustedPitch = (float)asin(angy / alen);
|
||||
float adjustedViewAngle = (float)(Viewpoint.Angles.Yaw - 90).Radians();
|
||||
|
||||
float ratio = Viewwindow.WidescreenRatio;
|
||||
float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
|
||||
|
||||
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees);
|
||||
|
||||
PolyPortalViewpoint portalViewpoint;
|
||||
|
||||
portalViewpoint.WorldToView =
|
||||
Mat4f::Rotate((float)Viewpoint.Angles.Roll.Radians(), 0.0f, 0.0f, 1.0f) *
|
||||
Mat4f::Rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
|
||||
Mat4f::Rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
|
||||
Mat4f::Scale(1.0f, PolyRenderer::Instance()->Level->info->pixelstretch, 1.0f) *
|
||||
Mat4f::SwapYZ() *
|
||||
Mat4f::Translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z);
|
||||
|
||||
portalViewpoint.Mirror = mirror;
|
||||
|
||||
if (mirror)
|
||||
portalViewpoint.WorldToView = Mat4f::Scale(-1.0f, 1.0f, 1.0f) * portalViewpoint.WorldToView;
|
||||
|
||||
portalViewpoint.WorldToClip = Mat4f::Perspective(fovy, ratio, 5.0f, 65535.0f, Handedness::Right, ClipZRange::NegativePositiveW) * portalViewpoint.WorldToView;
|
||||
|
||||
return portalViewpoint;
|
||||
}
|
||||
|
||||
cycle_t PolyCullCycles, PolyOpaqueCycles, PolyMaskedCycles, PolyDrawerWaitCycles;
|
||||
int PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls;
|
||||
|
||||
ADD_STAT(polyfps)
|
||||
{
|
||||
FString out;
|
||||
out.Format("frame=%04.1f ms cull=%04.1f ms opaque=%04.1f ms masked=%04.1f ms drawers=%04.1f ms",
|
||||
FrameCycles.TimeMS(), PolyCullCycles.TimeMS(), PolyOpaqueCycles.TimeMS(), PolyMaskedCycles.TimeMS(), PolyDrawerWaitCycles.TimeMS());
|
||||
out.AppendFormat("\nbatches drawn: %d triangles drawn: %d drawcalls: %d", PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls);
|
||||
return out;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "doomdata.h"
|
||||
#include "r_utility.h"
|
||||
#include "scene/poly_portal.h"
|
||||
#include "scene/poly_playersprite.h"
|
||||
#include "scene/poly_light.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "poly_renderthread.h"
|
||||
#include "stats.h"
|
||||
|
||||
class AActor;
|
||||
class DCanvas;
|
||||
class PolyPortalViewpoint;
|
||||
class DrawerCommandQueue;
|
||||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
|
||||
extern cycle_t PolyCullCycles, PolyOpaqueCycles, PolyMaskedCycles, PolyDrawerWaitCycles;
|
||||
extern int PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls;
|
||||
|
||||
class PolyRenderer
|
||||
{
|
||||
public:
|
||||
PolyRenderer();
|
||||
|
||||
void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch);
|
||||
void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines);
|
||||
void RenderRemainingPlayerSprites();
|
||||
|
||||
static PolyRenderer *Instance();
|
||||
|
||||
PolyPortalViewpoint SetupPerspectiveMatrix(bool mirror = false);
|
||||
|
||||
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
|
||||
|
||||
bool DontMapLines = false;
|
||||
|
||||
PolyRenderThreads Threads;
|
||||
DCanvas *RenderTarget = nullptr;
|
||||
bool RenderToCanvas = false;
|
||||
FViewWindow Viewwindow;
|
||||
FRenderViewpoint Viewpoint;
|
||||
PolyLightVisibility Light;
|
||||
RenderPolyScene Scene;
|
||||
FLevelLocals *Level;
|
||||
|
||||
private:
|
||||
void RenderActorView(AActor *actor, bool drawpsprites, bool dontmaplines);
|
||||
void SetSceneViewport();
|
||||
|
||||
RenderPolyPlayerSprites PlayerSprites;
|
||||
uint32_t NextStencilValue = 0;
|
||||
};
|
|
@ -1,268 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_bbox.h"
|
||||
|
||||
#include "p_lnspec.h"
|
||||
#include "p_setup.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "p_effect.h"
|
||||
#include "doomstat.h"
|
||||
#include "r_state.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_sky.h"
|
||||
#include "po_man.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "poly_renderthread.h"
|
||||
#include "poly_renderer.h"
|
||||
#include <mutex>
|
||||
|
||||
#ifdef WIN32
|
||||
void PeekThreadedErrorPane();
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR(Int, r_scene_multithreaded);
|
||||
|
||||
PolyRenderThread::PolyRenderThread(int threadIndex) : MainThread(threadIndex == 0), ThreadIndex(threadIndex)
|
||||
{
|
||||
FrameMemory.reset(new RenderMemory());
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
|
||||
PolyRenderThread::~PolyRenderThread()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderThread::FlushDrawQueue()
|
||||
{
|
||||
DrawerThreads::Execute(DrawQueue);
|
||||
|
||||
UsedDrawQueues.push_back(DrawQueue);
|
||||
DrawQueue.reset();
|
||||
|
||||
if (!FreeDrawQueues.empty())
|
||||
{
|
||||
DrawQueue = FreeDrawQueues.back();
|
||||
FreeDrawQueues.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex loadmutex;
|
||||
void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
return;
|
||||
|
||||
// Textures may not have loaded/refreshed yet. The shared code doing
|
||||
// this is not thread safe. By calling GetPixels in a mutex lock we
|
||||
// make sure that only one thread is loading a texture at any given
|
||||
// time.
|
||||
//
|
||||
// It is critical that this function is called before any direct
|
||||
// calls to GetPixels for this to work.
|
||||
|
||||
std::unique_lock<std::mutex> lock(loadmutex);
|
||||
|
||||
const FSoftwareTextureSpan *spans;
|
||||
if (PolyRenderer::Instance()->RenderTarget->IsBgra())
|
||||
{
|
||||
texture->GetPixelsBgra();
|
||||
texture->GetColumnBgra(0, &spans);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool alpha = !!(style.Flags & STYLEF_RedIsAlpha);
|
||||
texture->GetPixels(alpha);
|
||||
texture->GetColumn(alpha, 0, &spans);
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex polyobjmutex;
|
||||
void PolyRenderThread::PreparePolyObject(subsector_t *sub)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(polyobjmutex);
|
||||
|
||||
if (sub->BSP == nullptr || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyRenderThreads::PolyRenderThreads()
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread(0));
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
|
||||
PolyRenderThreads::~PolyRenderThreads()
|
||||
{
|
||||
StopThreads();
|
||||
}
|
||||
|
||||
void PolyRenderThreads::Clear()
|
||||
{
|
||||
for (auto &thread : Threads)
|
||||
{
|
||||
thread->FrameMemory->Clear();
|
||||
thread->DrawQueue->Clear();
|
||||
|
||||
while (!thread->UsedDrawQueues.empty())
|
||||
{
|
||||
auto queue = thread->UsedDrawQueues.back();
|
||||
thread->UsedDrawQueues.pop_back();
|
||||
queue->Clear();
|
||||
thread->FreeDrawQueues.push_back(queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback)
|
||||
{
|
||||
WorkerCallback = workerCallback;
|
||||
|
||||
int numThreads = std::thread::hardware_concurrency();
|
||||
if (numThreads == 0)
|
||||
numThreads = 1;
|
||||
|
||||
if (r_scene_multithreaded == 0 || r_multithreaded == 0)
|
||||
numThreads = 1;
|
||||
else if (r_scene_multithreaded != 1)
|
||||
numThreads = r_scene_multithreaded;
|
||||
|
||||
if (numThreads != (int)Threads.size())
|
||||
{
|
||||
StopThreads();
|
||||
StartThreads(numThreads);
|
||||
}
|
||||
|
||||
// Setup threads:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->Start = totalcount * i / numThreads;
|
||||
Threads[i]->End = totalcount * (i + 1) / numThreads;
|
||||
}
|
||||
run_id++;
|
||||
start_lock.unlock();
|
||||
|
||||
// Notify threads to run
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
start_condition.notify_all();
|
||||
}
|
||||
|
||||
// Do the main thread ourselves:
|
||||
RenderThreadSlice(MainThread());
|
||||
|
||||
// Wait for everyone to finish:
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); }))
|
||||
{
|
||||
#ifdef WIN32
|
||||
PeekThreadedErrorPane();
|
||||
#endif
|
||||
// Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing
|
||||
int *threadCrashed = nullptr;
|
||||
*threadCrashed = 0xdeadbeef;
|
||||
}
|
||||
finished_threads = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->FlushDrawQueue();
|
||||
}
|
||||
|
||||
WorkerCallback = {};
|
||||
|
||||
for (int i = 1; i < numThreads; i++)
|
||||
{
|
||||
collectCallback(Threads[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlice(PolyRenderThread *thread)
|
||||
{
|
||||
WorkerCallback(thread);
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StartThreads(size_t numThreads)
|
||||
{
|
||||
while (Threads.size() < (size_t)numThreads)
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread((int)Threads.size()));
|
||||
auto renderthread = thread.get();
|
||||
int start_run_id = run_id;
|
||||
thread->thread = std::thread([=]()
|
||||
{
|
||||
int last_run_id = start_run_id;
|
||||
while (true)
|
||||
{
|
||||
// Wait until we are signalled to run:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
start_condition.wait(start_lock, [&]() { return run_id != last_run_id || shutdown_flag; });
|
||||
if (shutdown_flag)
|
||||
break;
|
||||
last_run_id = run_id;
|
||||
start_lock.unlock();
|
||||
|
||||
RenderThreadSlice(renderthread);
|
||||
|
||||
// Notify main thread that we finished:
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
end_lock.unlock();
|
||||
end_condition.notify_all();
|
||||
}
|
||||
});
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StopThreads()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex);
|
||||
shutdown_flag = true;
|
||||
lock.unlock();
|
||||
start_condition.notify_all();
|
||||
while (Threads.size() > 1)
|
||||
{
|
||||
Threads.back()->thread.join();
|
||||
Threads.pop_back();
|
||||
}
|
||||
lock.lock();
|
||||
shutdown_flag = false;
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include "swrenderer/r_memory.h"
|
||||
|
||||
class DrawerCommandQueue;
|
||||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
class RenderMemory;
|
||||
class PolyTranslucentObject;
|
||||
class PolyDrawSectorPortal;
|
||||
class PolyDrawLinePortal;
|
||||
struct FDynamicLight;
|
||||
|
||||
class PolyRenderThread
|
||||
{
|
||||
public:
|
||||
PolyRenderThread(int threadIndex);
|
||||
~PolyRenderThread();
|
||||
|
||||
void FlushDrawQueue();
|
||||
|
||||
int Start = 0;
|
||||
int End = 0;
|
||||
bool MainThread = false;
|
||||
int ThreadIndex = 0;
|
||||
|
||||
std::unique_ptr<RenderMemory> FrameMemory;
|
||||
DrawerCommandQueuePtr DrawQueue;
|
||||
|
||||
std::vector<PolyTranslucentObject *> TranslucentObjects;
|
||||
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
|
||||
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
|
||||
|
||||
TArray<FDynamicLight*> AddedLightsArray;
|
||||
|
||||
// Make sure texture can accessed safely
|
||||
void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style);
|
||||
|
||||
// Setup poly object in a threadsafe manner
|
||||
void PreparePolyObject(subsector_t *sub);
|
||||
|
||||
private:
|
||||
std::thread thread;
|
||||
std::vector<DrawerCommandQueuePtr> UsedDrawQueues;
|
||||
std::vector<DrawerCommandQueuePtr> FreeDrawQueues;
|
||||
|
||||
friend class PolyRenderThreads;
|
||||
};
|
||||
|
||||
class PolyRenderThreads
|
||||
{
|
||||
public:
|
||||
PolyRenderThreads();
|
||||
~PolyRenderThreads();
|
||||
|
||||
void Clear();
|
||||
void RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback);
|
||||
|
||||
PolyRenderThread *MainThread() { return Threads.front().get(); }
|
||||
int NumThreads() const { return (int)Threads.size(); }
|
||||
|
||||
std::vector<std::unique_ptr<PolyRenderThread>> Threads;
|
||||
|
||||
private:
|
||||
void RenderThreadSlice(PolyRenderThread *thread);
|
||||
|
||||
void StartThreads(size_t numThreads);
|
||||
void StopThreads();
|
||||
|
||||
std::function<void(PolyRenderThread *)> WorkerCallback;
|
||||
|
||||
std::mutex start_mutex;
|
||||
std::condition_variable start_condition;
|
||||
bool shutdown_flag = false;
|
||||
int run_id = 0;
|
||||
std::mutex end_mutex;
|
||||
std::condition_variable end_condition;
|
||||
size_t finished_threads = 0;
|
||||
};
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_cull.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
|
||||
void PolyCull::CullScene(sector_t *portalSector, line_t *portalLine)
|
||||
{
|
||||
for (uint32_t sub : PvsSubsectors)
|
||||
SubsectorDepths[sub] = 0xffffffff;
|
||||
SubsectorDepths.resize(PolyRenderer::Instance()->Level->subsectors.Size(), 0xffffffff);
|
||||
|
||||
for (uint32_t sector : SeenSectors)
|
||||
SectorSeen[sector] = false;
|
||||
SectorSeen.resize(PolyRenderer::Instance()->Level->sectors.Size());
|
||||
|
||||
PvsSubsectors.clear();
|
||||
SeenSectors.clear();
|
||||
|
||||
NextPvsLineStart = 0;
|
||||
PvsLineStart.clear();
|
||||
PvsLineVisible.resize(PolyRenderer::Instance()->Level->segs.Size());
|
||||
|
||||
PortalSector = portalSector;
|
||||
PortalLine = portalLine;
|
||||
|
||||
SolidSegments.clear();
|
||||
|
||||
if (portalLine)
|
||||
{
|
||||
DVector3 viewpos = PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
DVector2 pt1 = portalLine->v1->fPos() - viewpos;
|
||||
DVector2 pt2 = portalLine->v2->fPos() - viewpos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
{
|
||||
angle_t angle1 = PointToPseudoAngle(portalLine->v1->fX(), portalLine->v1->fY());
|
||||
angle_t angle2 = PointToPseudoAngle(portalLine->v2->fX(), portalLine->v2->fY());
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t angle2 = PointToPseudoAngle(portalLine->v1->fX(), portalLine->v1->fY());
|
||||
angle_t angle1 = PointToPseudoAngle(portalLine->v2->fX(), portalLine->v2->fY());
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
InvertSegments();
|
||||
}
|
||||
else
|
||||
{
|
||||
MarkViewFrustum();
|
||||
}
|
||||
|
||||
// Cull front to back
|
||||
FirstSkyHeight = true;
|
||||
MaxCeilingHeight = 0.0;
|
||||
MinFloorHeight = 0.0;
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
CullSubsector(&PolyRenderer::Instance()->Level->subsectors[0]);
|
||||
else
|
||||
CullNode(PolyRenderer::Instance()->Level->HeadNode());
|
||||
}
|
||||
|
||||
void PolyCull::CullNode(void *node)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
// Decide which side the view point is on.
|
||||
int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
CullNode(bsp->children[side]);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
if (!CheckBBox(bsp->bbox[side]))
|
||||
return;
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
CullSubsector(sub);
|
||||
}
|
||||
|
||||
void PolyCull::CullSubsector(subsector_t *sub)
|
||||
{
|
||||
// Ignore everything in front of the portal
|
||||
if (PortalSector)
|
||||
{
|
||||
if (sub->sector != PortalSector)
|
||||
return;
|
||||
PortalSector = nullptr;
|
||||
}
|
||||
|
||||
// Update sky heights for the scene
|
||||
if (!FirstSkyHeight)
|
||||
{
|
||||
MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0());
|
||||
MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0());
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxCeilingHeight = sub->sector->ceilingplane.Zat0();
|
||||
MinFloorHeight = sub->sector->floorplane.Zat0();
|
||||
FirstSkyHeight = false;
|
||||
}
|
||||
|
||||
uint32_t subsectorDepth = (uint32_t)PvsSubsectors.size();
|
||||
|
||||
// Mark that we need to render this
|
||||
PvsSubsectors.push_back(sub->Index());
|
||||
PvsLineStart.push_back(NextPvsLineStart);
|
||||
|
||||
DVector3 viewpos = PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
|
||||
// Update culling info for further bsp clipping
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
// Skip lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
{
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not draw the portal line
|
||||
if (line->linedef == PortalLine)
|
||||
{
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
angle_t angle2 = PointToPseudoAngle(line->v1->fX(), line->v1->fY());
|
||||
angle_t angle1 = PointToPseudoAngle(line->v2->fX(), line->v2->fY());
|
||||
bool lineVisible = !IsSegmentCulled(angle1, angle2);
|
||||
if (lineVisible && IsSolidLine(line))
|
||||
{
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
|
||||
// Mark if this line was visible
|
||||
PvsLineVisible[NextPvsLineStart++] = lineVisible;
|
||||
}
|
||||
|
||||
if (!SectorSeen[sub->sector->Index()])
|
||||
{
|
||||
SectorSeen[sub->sector->Index()] = true;
|
||||
SeenSectors.push_back(sub->sector->Index());
|
||||
}
|
||||
|
||||
SubsectorDepths[sub->Index()] = subsectorDepth;
|
||||
}
|
||||
|
||||
bool PolyCull::IsSolidLine(seg_t *line)
|
||||
{
|
||||
// One-sided
|
||||
if (!line->backsector) return true;
|
||||
|
||||
// Portal
|
||||
if (line->linedef && line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0]) return true;
|
||||
|
||||
double frontCeilingZ1 = line->frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontFloorZ1 = line->frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontCeilingZ2 = line->frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontFloorZ2 = line->frontsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double backCeilingZ1 = line->backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backFloorZ1 = line->backsector->floorplane.ZatPoint(line->v1);
|
||||
double backCeilingZ2 = line->backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backFloorZ2 = line->backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
// Closed door.
|
||||
if (backCeilingZ1 <= frontFloorZ1 && backCeilingZ2 <= frontFloorZ2) return true;
|
||||
if (backFloorZ1 >= frontCeilingZ1 && backFloorZ2 >= frontCeilingZ2) return true;
|
||||
|
||||
// properly render skies (consider door "open" if both ceilings are sky)
|
||||
if (line->backsector->GetTexture(sector_t::ceiling) == skyflatnum && line->frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false;
|
||||
|
||||
// if door is closed because back is shut:
|
||||
if (!(backCeilingZ1 <= backFloorZ1 && backCeilingZ2 <= backFloorZ2)) return false;
|
||||
|
||||
// preserve a kind of transparent door/lift special effect:
|
||||
if (((backCeilingZ1 >= frontCeilingZ1 && backCeilingZ2 >= frontCeilingZ2) || line->sidedef->GetTexture(side_t::top).isValid())
|
||||
&& ((backFloorZ1 <= frontFloorZ1 && backFloorZ2 <= frontFloorZ2) || line->sidedef->GetTexture(side_t::bottom).isValid()))
|
||||
{
|
||||
// killough 1/18/98 -- This function is used to fix the automap bug which
|
||||
// showed lines behind closed doors simply because the door had a dropoff.
|
||||
//
|
||||
// It assumes that Doom has already ruled out a door being closed because
|
||||
// of front-back closure (e.g. front floor is taller than back ceiling).
|
||||
|
||||
// This fixes the automap floor height bug -- killough 1/18/98:
|
||||
// killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PolyCull::IsSegmentCulled(angle_t startAngle, angle_t endAngle) const
|
||||
{
|
||||
if (startAngle > endAngle)
|
||||
{
|
||||
return IsSegmentCulled(startAngle, ANGLE_MAX) && IsSegmentCulled(0, endAngle);
|
||||
}
|
||||
|
||||
for (const auto &segment : SolidSegments)
|
||||
{
|
||||
if (startAngle >= segment.Start && endAngle <= segment.End)
|
||||
return true;
|
||||
else if (endAngle < segment.Start)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PolyCull::MarkSegmentCulled(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
if (startAngle > endAngle)
|
||||
{
|
||||
MarkSegmentCulled(startAngle, ANGLE_MAX);
|
||||
MarkSegmentCulled(0, endAngle);
|
||||
return;
|
||||
}
|
||||
|
||||
int count = (int)SolidSegments.size();
|
||||
int cur = 0;
|
||||
while (cur < count)
|
||||
{
|
||||
if (SolidSegments[cur].Start <= startAngle && SolidSegments[cur].End >= endAngle) // Already fully marked
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (SolidSegments[cur].End >= startAngle && SolidSegments[cur].Start <= endAngle) // Merge segments
|
||||
{
|
||||
// Find last segment
|
||||
int merge = cur;
|
||||
while (merge + 1 != count && SolidSegments[merge + 1].Start <= endAngle)
|
||||
merge++;
|
||||
|
||||
// Apply new merged range
|
||||
SolidSegments[cur].Start = MIN(SolidSegments[cur].Start, startAngle);
|
||||
SolidSegments[cur].End = MAX(SolidSegments[merge].End, endAngle);
|
||||
|
||||
// Remove additional segments we merged with
|
||||
if (merge > cur)
|
||||
SolidSegments.erase(SolidSegments.begin() + (cur + 1), SolidSegments.begin() + (merge + 1));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (SolidSegments[cur].Start > startAngle) // Insert new segment
|
||||
{
|
||||
SolidSegments.insert(SolidSegments.begin() + cur, { startAngle, endAngle });
|
||||
return;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
SolidSegments.push_back({ startAngle, endAngle });
|
||||
|
||||
#if 0
|
||||
count = (int)SolidSegments.size();
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
if (SolidSegments[i - 1].Start >= SolidSegments[i].Start ||
|
||||
SolidSegments[i - 1].End >= SolidSegments[i].Start ||
|
||||
SolidSegments[i - 1].End + 1 == SolidSegments[i].Start ||
|
||||
SolidSegments[i].Start > SolidSegments[i].End)
|
||||
{
|
||||
I_FatalError("MarkSegmentCulled is broken!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int PolyCull::PointOnSide(const DVector2 &pos, const node_t *node)
|
||||
{
|
||||
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
|
||||
}
|
||||
|
||||
bool PolyCull::CheckBBox(float *bspcoord)
|
||||
{
|
||||
// Occlusion test using solid segments:
|
||||
static const uint8_t checkcoord[12][4] =
|
||||
{
|
||||
{ 3,0,2,1 },
|
||||
{ 3,0,2,0 },
|
||||
{ 3,1,2,0 },
|
||||
{ 0 },
|
||||
{ 2,0,2,1 },
|
||||
{ 0,0,0,0 },
|
||||
{ 3,1,3,0 },
|
||||
{ 0 },
|
||||
{ 2,0,3,1 },
|
||||
{ 2,1,3,1 },
|
||||
{ 2,1,3,0 }
|
||||
};
|
||||
|
||||
// Find the corners of the box that define the edges from current viewpoint.
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
int boxpos = (viewpoint.Pos.X <= bspcoord[BOXLEFT] ? 0 : viewpoint.Pos.X < bspcoord[BOXRIGHT] ? 1 : 2) +
|
||||
(viewpoint.Pos.Y >= bspcoord[BOXTOP] ? 0 : viewpoint.Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
if (boxpos == 5) return true;
|
||||
|
||||
const uint8_t *check = checkcoord[boxpos];
|
||||
angle_t angle1 = PointToPseudoAngle(bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle_t angle2 = PointToPseudoAngle(bspcoord[check[2]], bspcoord[check[3]]);
|
||||
|
||||
return !IsSegmentCulled(angle2, angle1);
|
||||
}
|
||||
|
||||
void PolyCull::InvertSegments()
|
||||
{
|
||||
TempInvertSolidSegments.swap(SolidSegments);
|
||||
SolidSegments.clear();
|
||||
angle_t cur = 0;
|
||||
for (const auto &segment : TempInvertSolidSegments)
|
||||
{
|
||||
if (cur < segment.Start)
|
||||
MarkSegmentCulled(cur, segment.Start - 1);
|
||||
if (segment.End == ANGLE_MAX)
|
||||
return;
|
||||
cur = segment.End + 1;
|
||||
}
|
||||
MarkSegmentCulled(cur, ANGLE_MAX);
|
||||
}
|
||||
|
||||
void PolyCull::MarkViewFrustum()
|
||||
{
|
||||
// Clips things outside the viewing frustum.
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
double tilt = fabs(viewpoint.Angles.Pitch.Degrees);
|
||||
if (tilt > 46.0) // If the pitch is larger than this you can look all around
|
||||
return;
|
||||
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(viewwindow.WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 < ANGLE_180)
|
||||
{
|
||||
MarkSegmentCulled(AngleToPseudo(viewpoint.Angles.Yaw.BAMs() + a1), AngleToPseudo(viewpoint.Angles.Yaw.BAMs() - a1));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
// line from p1 to p2. The pseudoangle has the property that the ordering of
|
||||
// points by true angle around p1 and ordering of points by pseudoangle are the
|
||||
// same.
|
||||
//
|
||||
// For clipping exact angles are not needed. Only the ordering matters.
|
||||
// This is about as fast as the fixed point R_PointToAngle2 but without
|
||||
// the precision issues associated with that function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t PolyCull::PointToPseudoAngle(double x, double y)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
double vecx = x - viewpoint.Pos.X;
|
||||
double vecy = y - viewpoint.Pos.Y;
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2. - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
}
|
||||
|
||||
angle_t PolyCull::AngleToPseudo(angle_t ang)
|
||||
{
|
||||
double vecx = cos(ang * M_PI / ANGLE_180);
|
||||
double vecy = sin(ang * M_PI / ANGLE_180);
|
||||
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
class PolyCull
|
||||
{
|
||||
public:
|
||||
void CullScene(sector_t *portalSector, line_t *portalLine);
|
||||
|
||||
bool IsLineSegVisible(uint32_t subsectorDepth, uint32_t lineIndex)
|
||||
{
|
||||
return PvsLineVisible[PvsLineStart[subsectorDepth] + lineIndex];
|
||||
}
|
||||
|
||||
std::vector<uint32_t> PvsSubsectors;
|
||||
double MaxCeilingHeight = 0.0;
|
||||
double MinFloorHeight = 0.0;
|
||||
|
||||
std::vector<uint32_t> SeenSectors;
|
||||
std::vector<bool> SectorSeen;
|
||||
std::vector<uint32_t> SubsectorDepths;
|
||||
|
||||
static angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
private:
|
||||
struct SolidSegment
|
||||
{
|
||||
SolidSegment(angle_t start, angle_t end) : Start(start), End(end) { }
|
||||
angle_t Start, End;
|
||||
};
|
||||
|
||||
void MarkViewFrustum();
|
||||
void InvertSegments();
|
||||
|
||||
static bool IsSolidLine(seg_t *line);
|
||||
|
||||
bool IsSegmentCulled(angle_t angle1, angle_t angle2) const;
|
||||
|
||||
void CullNode(void *node);
|
||||
void CullSubsector(subsector_t *sub);
|
||||
int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
||||
// Checks BSP node/subtree bounding box.
|
||||
// Returns true if some part of the bbox might be visible.
|
||||
bool CheckBBox(float *bspcoord);
|
||||
|
||||
void MarkSegmentCulled(angle_t angle1, angle_t angle2);
|
||||
|
||||
std::vector<SolidSegment> SolidSegments;
|
||||
std::vector<SolidSegment> TempInvertSolidSegments;
|
||||
std::vector<SolidSegment> PortalVisibility;
|
||||
bool FirstSkyHeight = true;
|
||||
|
||||
sector_t *PortalSector = nullptr;
|
||||
line_t *PortalLine = nullptr;
|
||||
|
||||
std::vector<uint32_t> PvsLineStart;
|
||||
std::vector<bool> PvsLineVisible;
|
||||
uint32_t NextPvsLineStart = 0;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
};
|
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_decal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
|
||||
void RenderPolyDecal::RenderWallDecals(PolyRenderThread *thread, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (line->linedef == nullptr && line->sidedef == nullptr)
|
||||
return;
|
||||
|
||||
for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext)
|
||||
{
|
||||
RenderPolyDecal render;
|
||||
render.Render(thread, decal, line, stencilValue);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::Render(PolyRenderThread *thread, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
|
||||
return;
|
||||
|
||||
FTexture *ttex = TexMan.GetPalettedTexture(decal->PicNum, true);
|
||||
if (ttex == nullptr || !ttex->isValid())
|
||||
return;
|
||||
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
|
||||
sector_t *front, *back;
|
||||
GetDecalSectors(decal, line, &front, &back);
|
||||
|
||||
// Calculate unclipped position and UV coordinates
|
||||
|
||||
// decals should not use renderer specific offsets.
|
||||
double edge_left = tex->GetLeftOffset(0) * decal->ScaleX;
|
||||
double edge_right = (tex->GetWidth() - tex->GetLeftOffset(0)) * decal->ScaleX;
|
||||
|
||||
DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit();
|
||||
DVector2 normal = { angvec.Y, -angvec.X };
|
||||
|
||||
double dcx, dcy;
|
||||
decal->GetXY(line->sidedef, dcx, dcy);
|
||||
DVector2 decal_pos = DVector2(dcx, dcy) + normal;
|
||||
DVector2 decal_left = decal_pos - edge_left * angvec;
|
||||
DVector2 decal_right = decal_pos + edge_right * angvec;
|
||||
|
||||
bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP;
|
||||
double u_left = flipTextureX ? 1.0 : 0.0;
|
||||
double u_right = flipTextureX ? 1.0 - tex->GetScale().X : tex->GetScale().X;
|
||||
double u_unit = (u_right - u_left) / (edge_left + edge_right);
|
||||
|
||||
double zpos = GetDecalZ(decal, line, front, back);
|
||||
double spriteHeight = decal->ScaleY / tex->GetScale().Y * tex->GetHeight();
|
||||
double ztop = zpos + spriteHeight - spriteHeight * 0.5;
|
||||
double zbottom = zpos - spriteHeight * 0.5;
|
||||
|
||||
double v_top = 0.0;
|
||||
double v_bottom = tex->GetScale().Y;
|
||||
double v_unit = (v_bottom - v_top) / (zbottom - ztop);
|
||||
|
||||
// Clip decal to wall part
|
||||
|
||||
double walltopz, wallbottomz;
|
||||
GetWallZ(decal, line, front, back, walltopz, wallbottomz);
|
||||
|
||||
double clip_left_v1 = (decal_left - line->v1->fPos()) | angvec;
|
||||
double clip_right_v1 = (decal_right - line->v1->fPos()) | angvec;
|
||||
double clip_left_v2 = (decal_left - line->v2->fPos()) | angvec;
|
||||
double clip_right_v2 = (decal_right - line->v2->fPos()) | angvec;
|
||||
|
||||
if ((clip_left_v1 <= 0.0 && clip_right_v1 <= 0.0) || (clip_left_v2 >= 0.0 && clip_right_v2 >= 0.0))
|
||||
return;
|
||||
|
||||
if (clip_left_v1 < 0.0)
|
||||
{
|
||||
decal_left -= angvec * clip_left_v1;
|
||||
u_left -= u_unit * clip_left_v1;
|
||||
}
|
||||
if (clip_right_v1 < 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v1;
|
||||
u_right -= u_unit * clip_right_v1;
|
||||
}
|
||||
if (clip_left_v2 > 0.0)
|
||||
{
|
||||
decal_left -= angvec * clip_left_v2;
|
||||
u_left -= u_unit * clip_left_v2;
|
||||
}
|
||||
if (clip_right_v2 > 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v2;
|
||||
u_right -= u_unit * clip_right_v2;
|
||||
}
|
||||
|
||||
double clip_top_floor = ztop - wallbottomz;
|
||||
double clip_bottom_floor = zbottom - wallbottomz;
|
||||
double clip_top_ceiling = ztop - walltopz;
|
||||
double clip_bottom_ceiling = zbottom - walltopz;
|
||||
|
||||
if ((clip_top_floor <= 0.0 && clip_bottom_floor <= 0.0) || (clip_top_ceiling >= 0.0 && clip_bottom_ceiling >= 0.0))
|
||||
return;
|
||||
|
||||
if (clip_top_floor < 0.0)
|
||||
{
|
||||
ztop -= clip_top_floor;
|
||||
v_top -= v_unit * clip_top_floor;
|
||||
}
|
||||
if (clip_bottom_floor < 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_floor;
|
||||
v_bottom -= v_unit * clip_bottom_floor;
|
||||
}
|
||||
if (clip_top_ceiling > 0.0)
|
||||
{
|
||||
ztop -= clip_top_ceiling;
|
||||
v_top -= v_unit * clip_top_ceiling;
|
||||
}
|
||||
if (clip_bottom_ceiling > 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_ceiling;
|
||||
v_bottom -= v_unit * clip_bottom_ceiling;
|
||||
}
|
||||
|
||||
// Generate vertices for the decal
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
vertices[0].x = (float)decal_left.X;
|
||||
vertices[0].y = (float)decal_left.Y;
|
||||
vertices[0].z = (float)ztop;
|
||||
vertices[0].w = 1.0f;
|
||||
vertices[0].u = (float)u_left;
|
||||
vertices[0].v = 1.0f - (float)v_top;
|
||||
vertices[1].x = (float)decal_right.X;
|
||||
vertices[1].y = (float)decal_right.Y;
|
||||
vertices[1].z = (float)ztop;
|
||||
vertices[1].w = 1.0f;
|
||||
vertices[1].u = (float)u_right;
|
||||
vertices[1].v = 1.0f - (float)v_top;
|
||||
vertices[2].x = (float)decal_right.X;
|
||||
vertices[2].y = (float)decal_right.Y;
|
||||
vertices[2].z = (float)zbottom;
|
||||
vertices[2].w = 1.0f;
|
||||
vertices[2].u = (float)u_right;
|
||||
vertices[2].v = 1.0f - (float)v_bottom;
|
||||
vertices[3].x = (float)decal_left.X;
|
||||
vertices[3].y = (float)decal_left.Y;
|
||||
vertices[3].z = (float)zbottom;
|
||||
vertices[3].w = 1.0f;
|
||||
vertices[3].u = (float)u_left;
|
||||
vertices[3].v = 1.0f - (float)v_bottom;
|
||||
|
||||
// Light calculations
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT;
|
||||
int lightlevel = fullbrightSprite ? 255 : front->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(front->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite);
|
||||
args.SetColor(0xff000000 | decal->AlphaColor, decal->AlphaColor >> 24);
|
||||
args.SetStyle(decal->RenderStyle, decal->Alpha, decal->AlphaColor, decal->Translation, tex, false);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back)
|
||||
{
|
||||
// for 3d-floor segments use the model sector as reference
|
||||
if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID)
|
||||
*front = decal->Sector;
|
||||
else
|
||||
*front = line->frontsector;
|
||||
|
||||
*back = (line->backsector != nullptr) ? line->backsector : line->frontsector;
|
||||
}
|
||||
|
||||
double RenderPolyDecal::GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back)
|
||||
{
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
return decal->Z;
|
||||
case RF_RELUPPER:
|
||||
if (line->linedef->flags & ML_DONTPEGTOP)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
|
||||
case RF_RELLOWER:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::floor);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::floor);
|
||||
else
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz)
|
||||
{
|
||||
double frontceilz1 = front->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = front->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = front->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = front->floorplane.ZatPoint(line->v2);
|
||||
if (back == nullptr)
|
||||
{
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
}
|
||||
else
|
||||
{
|
||||
double backceilz1 = back->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = back->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = back->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = back->floorplane.ZatPoint(line->v2);
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MAX(MIN(backceilz1, frontceilz1), frontfloorz1);
|
||||
double topfloorz2 = MAX(MIN(backceilz2, frontceilz2), frontfloorz2);
|
||||
double bottomceilz1 = MIN(MAX(frontfloorz1, backfloorz1), frontceilz1);
|
||||
double bottomceilz2 = MIN(MAX(frontfloorz2, backfloorz2), frontceilz2);
|
||||
double bottomfloorz1 = frontfloorz1;
|
||||
double bottomfloorz2 = frontfloorz2;
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
break;
|
||||
case RF_RELUPPER:
|
||||
walltopz = MAX(topceilz1, topceilz2);
|
||||
wallbottomz = MIN(topfloorz1, topfloorz2);
|
||||
break;
|
||||
case RF_RELLOWER:
|
||||
walltopz = MAX(bottomceilz1, bottomceilz2);
|
||||
wallbottomz = MIN(bottomfloorz1, bottomfloorz2);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
walltopz = MAX(middleceilz1, middleceilz2);
|
||||
wallbottomz = MIN(middlefloorz1, middlefloorz2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolyDecal
|
||||
{
|
||||
public:
|
||||
static void RenderWallDecals(PolyRenderThread *thread, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
void Render(PolyRenderThread *thread, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
void GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back);
|
||||
double GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back);
|
||||
void GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz);
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "poly_light.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
|
||||
void PolyLightVisibility::SetVisibility(FViewWindow &viewwindow, float vis)
|
||||
{
|
||||
GlobVis = R_GetGlobVis(viewwindow, vis);
|
||||
}
|
||||
|
||||
fixed_t PolyLightVisibility::LightLevelToShade(int lightlevel, bool foggy)
|
||||
{
|
||||
bool nolightfade = !foggy && ((PolyRenderer::Instance()->Level->flags3 & LEVEL3_NOLIGHTFADE));
|
||||
if (nolightfade)
|
||||
{
|
||||
return (MAX(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a light level into an unbounded colormap index (shade). Result is
|
||||
// fixed point. Why the +12? I wish I knew, but experimentation indicates it
|
||||
// is necessary in order to best reproduce Doom's original lighting.
|
||||
return (NUMCOLORMAPS * 2 * FRACUNIT) - ((lightlevel + 12) * (FRACUNIT*NUMCOLORMAPS / 128));
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
|
||||
struct FViewWindow;
|
||||
|
||||
// Keep using the software renderer's camera light class, for now.
|
||||
// The DFrameBuffer abstraction relies on this being globally shared
|
||||
typedef swrenderer::CameraLight PolyCameraLight;
|
||||
|
||||
class PolyLightVisibility
|
||||
{
|
||||
public:
|
||||
void SetVisibility(FViewWindow &viewwindow, float vis);
|
||||
|
||||
double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis; }
|
||||
double ParticleGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis * 0.5; }
|
||||
|
||||
// The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros
|
||||
double WallVis(double screenZ, bool foggy) const { return WallGlobVis(foggy) / screenZ; }
|
||||
double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / screenZ; }
|
||||
double ParticleVis(double screenZ, bool foggy) const { return ParticleGlobVis(foggy) / screenZ; }
|
||||
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy);
|
||||
|
||||
private:
|
||||
double GlobVis = 0.0f;
|
||||
bool NoLightFade = false;
|
||||
};
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_model.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, stencilValue);
|
||||
|
||||
renderer.sector = actor->Sector;
|
||||
renderer.RenderStyle = actor->RenderStyle;
|
||||
renderer.RenderAlpha = (float)actor->Alpha;
|
||||
if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha))
|
||||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = ((actor->renderflags & RF_FULLBRIGHT) || (actor->flags5 & MF5_BRIGHT));
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : actor->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
|
||||
renderer.fillcolor = actor->fillcolor;
|
||||
renderer.Translation = actor->Translation;
|
||||
|
||||
renderer.AddLights(actor);
|
||||
renderer.RenderModel(x, y, z, smf, actor, PolyRenderer::Instance()->Viewpoint.TicFrac);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(worldToClip), nullptr);
|
||||
}
|
||||
|
||||
static bool isBright(DPSprite *psp)
|
||||
{
|
||||
if (psp != nullptr && psp->GetState() != nullptr)
|
||||
{
|
||||
bool disablefullbright = false;
|
||||
FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr);
|
||||
if (lump.isValid())
|
||||
{
|
||||
FTexture * tex = TexMan.GetPalettedTexture(lump, true);
|
||||
if (tex) disablefullbright = tex->isFullbrightDisabled();
|
||||
}
|
||||
return psp->GetState()->GetFullbright() && !disablefullbright;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PolyRenderHUDModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy)
|
||||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, stencilValue);
|
||||
|
||||
AActor *playermo = players[consoleplayer].camera;
|
||||
auto rs = psp->GetRenderStyle(playermo->RenderStyle, playermo->Alpha);
|
||||
renderer.sector = playermo->Sector;
|
||||
renderer.RenderStyle = rs.first;
|
||||
renderer.RenderAlpha = rs.second;
|
||||
if (psp->Flags & PSPF_FORCEALPHA) renderer.RenderAlpha = 0.0f;
|
||||
if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha))
|
||||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = isBright(psp);
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
|
||||
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
|
||||
renderer.fillcolor = fullbrightSprite ? ThingColor : ThingColor.Modulate(playermo->Sector->SpecialColors[sector_t::sprites]);
|
||||
renderer.Translation = 0xffffffff;// playermo->Translation;
|
||||
|
||||
renderer.RenderHUDModel(psp, ofsx, ofsy);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyModelRenderer::PolyModelRenderer(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), StencilValue(stencilValue)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyModelRenderer::AddLights(AActor *actor)
|
||||
{
|
||||
if (r_dynlights && actor)
|
||||
{
|
||||
auto &addedLights = Thread->AddedLightsArray;
|
||||
|
||||
addedLights.Clear();
|
||||
|
||||
float x = (float)actor->X();
|
||||
float y = (float)actor->Y();
|
||||
float z = (float)actor->Center();
|
||||
float actorradius = (float)actor->RenderRadius();
|
||||
float radiusSquared = actorradius * actorradius;
|
||||
|
||||
BSPWalkCircle(actor->Level, x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor
|
||||
{
|
||||
FLightNode * node = subsector->section->lighthead;
|
||||
while (node) // check all lights touching a subsector
|
||||
{
|
||||
FDynamicLight *light = node->lightsource;
|
||||
if (light->ShouldLightActor(actor))
|
||||
{
|
||||
int group = subsector->sector->PortalGroup;
|
||||
DVector3 pos = light->PosRelative(group);
|
||||
float radius = (float)(light->GetRadius() + actorradius);
|
||||
double dx = pos.X - x;
|
||||
double dy = pos.Y - y;
|
||||
double dz = pos.Z - z;
|
||||
double distSquared = dx * dx + dy * dy + dz * dz;
|
||||
if (distSquared < radius * radius) // Light and actor touches
|
||||
{
|
||||
if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector
|
||||
{
|
||||
addedLights.Push(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
});
|
||||
|
||||
NumLights = addedLights.Size();
|
||||
Lights = Thread->FrameMemory->AllocMemory<PolyLight>(NumLights);
|
||||
for (int i = 0; i < NumLights; i++)
|
||||
{
|
||||
FDynamicLight *lightsource = addedLights[i];
|
||||
|
||||
bool is_point_light = lightsource->IsAttenuated();
|
||||
|
||||
uint32_t red = lightsource->GetRed();
|
||||
uint32_t green = lightsource->GetGreen();
|
||||
uint32_t blue = lightsource->GetBlue();
|
||||
|
||||
PolyLight &light = Lights[i];
|
||||
light.x = (float)lightsource->X();
|
||||
light.y = (float)lightsource->Y();
|
||||
light.z = (float)lightsource->Z();
|
||||
light.radius = 256.0f / lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
SetTransform();
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !mirrored);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf)
|
||||
{
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
IModelVertexBuffer *PolyModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
return new PolyModelVertexBuffer(needindex, singleframe);
|
||||
}
|
||||
|
||||
VSMatrix PolyModelRenderer::GetViewToWorldMatrix()
|
||||
{
|
||||
Mat4f swapYZ = Mat4f::Null();
|
||||
swapYZ.Matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.Matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.Matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.Matrix[3 + 3 * 4] = 1.0f;
|
||||
|
||||
VSMatrix worldToView;
|
||||
worldToView.loadMatrix((PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToView * swapYZ).Matrix);
|
||||
|
||||
VSMatrix objectToWorld;
|
||||
worldToView.inverseMatrix(objectToWorld);
|
||||
return objectToWorld;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
SetTransform();
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, true);
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, mirrored);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::EndDrawHUDModel(AActor *actor)
|
||||
{
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, false);
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetInterpolation(double interpolation)
|
||||
{
|
||||
InterpolationFactor = (float)interpolation;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation)
|
||||
{
|
||||
SkinTexture = skin? skin->GetSoftwareTexture() : nullptr;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetTransform()
|
||||
{
|
||||
Mat4f swapYZ = Mat4f::Null();
|
||||
swapYZ.Matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.Matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.Matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.Matrix[3 + 3 * 4] = 1.0f;
|
||||
ObjectToWorld = swapYZ * ObjectToWorld;
|
||||
|
||||
PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject<Mat4f>(WorldToClip * ObjectToWorld), Thread->FrameMemory->NewObject<Mat4f>(ObjectToWorld));
|
||||
}
|
||||
|
||||
void PolyModelRenderer::DrawArrays(int start, int count)
|
||||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(Thread->DrawQueue, args, VertexBuffer + start, count);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::DrawElements(int numIndices, size_t offset)
|
||||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawElements(Thread->DrawQueue, args, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyModelVertexBuffer::PolyModelVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
}
|
||||
|
||||
PolyModelVertexBuffer::~PolyModelVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
FModelVertex *PolyModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||
{
|
||||
mVertexBuffer.Resize(size);
|
||||
return &mVertexBuffer[0];
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::UnlockVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int *PolyModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||
{
|
||||
mIndexBuffer.Resize(size);
|
||||
return &mIndexBuffer[0];
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::UnlockIndexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||
{
|
||||
PolyModelRenderer *polyrenderer = (PolyModelRenderer *)renderer;
|
||||
polyrenderer->VertexBuffer = mVertexBuffer.Size() ? &mVertexBuffer[0] : nullptr;
|
||||
polyrenderer->IndexBuffer = mIndexBuffer.Size() ? &mIndexBuffer[0] : nullptr;
|
||||
PolyTriangleDrawer::SetModelVertexShader(polyrenderer->Thread->DrawQueue, frame1, frame2, polyrenderer->InterpolationFactor);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "matrix.h"
|
||||
#include "r_data/models/models.h"
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
|
||||
void PolyRenderHUDModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy);
|
||||
|
||||
class PolyModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
PolyModelRenderer(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue);
|
||||
|
||||
void AddLights(AActor *actor);
|
||||
|
||||
ModelRendererType GetType() const override { return PolyModelRendererType; }
|
||||
|
||||
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
|
||||
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
|
||||
VSMatrix GetViewToWorldMatrix() override;
|
||||
void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawHUDModel(AActor *actor) override;
|
||||
void SetInterpolation(double interpolation) override;
|
||||
void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override;
|
||||
void DrawArrays(int start, int count) override;
|
||||
void DrawElements(int numIndices, size_t offset) override;
|
||||
|
||||
void SetTransform();
|
||||
|
||||
PolyRenderThread *Thread = nullptr;
|
||||
const Mat4f &WorldToClip;
|
||||
uint32_t StencilValue = 0;
|
||||
|
||||
FRenderStyle RenderStyle;
|
||||
float RenderAlpha;
|
||||
sector_t *sector;
|
||||
bool fullbrightSprite;
|
||||
int lightlevel;
|
||||
double visibility;
|
||||
uint32_t fillcolor;
|
||||
uint32_t Translation;
|
||||
|
||||
Mat4f ObjectToWorld;
|
||||
FSoftwareTexture *SkinTexture = nullptr;
|
||||
unsigned int *IndexBuffer = nullptr;
|
||||
FModelVertex *VertexBuffer = nullptr;
|
||||
float InterpolationFactor = 0.0;
|
||||
PolyLight *Lights = nullptr;
|
||||
int NumLights = 0;
|
||||
};
|
||||
|
||||
class PolyModelVertexBuffer : public IModelVertexBuffer
|
||||
{
|
||||
public:
|
||||
PolyModelVertexBuffer(bool needindex, bool singleframe);
|
||||
~PolyModelVertexBuffer();
|
||||
|
||||
FModelVertex *LockVertexBuffer(unsigned int size) override;
|
||||
void UnlockVertexBuffer() override;
|
||||
|
||||
unsigned int *LockIndexBuffer(unsigned int size) override;
|
||||
void UnlockIndexBuffer() override;
|
||||
|
||||
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
|
||||
|
||||
private:
|
||||
TArray<FModelVertex> mVertexBuffer;
|
||||
TArray<unsigned int> mIndexBuffer;
|
||||
};
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_particle.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
EXTERN_CVAR(Int, gl_particles_style)
|
||||
|
||||
void RenderPolyParticle::Render(PolyRenderThread *thread, particle_t *particle, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
double timefrac = PolyRenderer::Instance()->Viewpoint.TicFrac;
|
||||
if (paused || PolyRenderer::Instance()->Viewpoint.ViewLevel->isFrozen())
|
||||
timefrac = 0.;
|
||||
DVector3 pos = particle->Pos + (particle->Vel * timefrac);
|
||||
double psize = particle->size / 8.0;
|
||||
double zpos = pos.Z;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
DVector2 points[2] =
|
||||
{
|
||||
{ pos.X - viewpoint.Sin * psize, pos.Y + viewpoint.Cos * psize },
|
||||
{ pos.X + viewpoint.Sin * psize, pos.Y - viewpoint.Cos * psize }
|
||||
};
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(zpos + psize * (2.0 * offsets[i].second - 1.0));
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)(offsets[i].first);
|
||||
vertices[i].v = (float)(1.0f - offsets[i].second);
|
||||
}
|
||||
|
||||
bool fullbrightSprite = particle->bright != 0;
|
||||
int lightlevel = fullbrightSprite ? 255 : sub->sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.ParticleGlobVis(foggy), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetColor(particle->color | 0xff000000, particle->color >> 24);
|
||||
args.SetStyle(TriBlendMode::Shaded, particle->alpha);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetTexture(GetParticleTexture(), ParticleTextureSize, ParticleTextureSize);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
uint8_t *RenderPolyParticle::GetParticleTexture()
|
||||
{
|
||||
static uint8_t particle_texture[NumParticleTextures][ParticleTextureSize * ParticleTextureSize];
|
||||
static bool first_call = true;
|
||||
if (first_call)
|
||||
{
|
||||
double center = ParticleTextureSize * 0.5f;
|
||||
for (int y = 0; y < ParticleTextureSize; y++)
|
||||
{
|
||||
for (int x = 0; x < ParticleTextureSize; x++)
|
||||
{
|
||||
double dx = (center - x - 0.5f) / center;
|
||||
double dy = (center - y - 0.5f) / center;
|
||||
double dist2 = dx * dx + dy * dy;
|
||||
double round_alpha = clamp<double>(1.7f - dist2 * 1.7f, 0.0f, 1.0f);
|
||||
double smooth_alpha = clamp<double>(1.1f - dist2 * 1.1f, 0.0f, 1.0f);
|
||||
|
||||
particle_texture[0][x + y * ParticleTextureSize] = 255;
|
||||
particle_texture[1][x + y * ParticleTextureSize] = (int)(round_alpha * 255.0f + 0.5f);
|
||||
particle_texture[2][x + y * ParticleTextureSize] = (int)(smooth_alpha * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
first_call = false;
|
||||
}
|
||||
return particle_texture[MIN<int>(gl_particles_style, NumParticleTextures)];
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "p_effect.h"
|
||||
|
||||
class RenderPolyParticle
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, particle_t *particle, subsector_t *sub, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
static uint8_t *GetParticleTexture();
|
||||
|
||||
enum
|
||||
{
|
||||
NumParticleTextures = 3,
|
||||
ParticleTextureSize = 64
|
||||
};
|
||||
};
|
||||
|
||||
class PolyTranslucentParticle : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentParticle(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, 0.0), particle(particle), sub(sub), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
RenderPolyParticle spr;
|
||||
spr.Render(thread, particle, sub, StencilValue + 1);
|
||||
}
|
||||
|
||||
particle_t *particle = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
|
@ -1,565 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_plane.h"
|
||||
#include "poly_portal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_dynlight.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_3dfloors)
|
||||
|
||||
void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
if (fakeflat.FrontSector->CenterFloor() == fakeflat.FrontSector->CenterCeiling())
|
||||
return;
|
||||
|
||||
RenderPolyPlane plane;
|
||||
plane.Render(thread, fakeflat, stencilValue, true, skyCeilingHeight, sectorPortals, sectorPortalsStart);
|
||||
plane.Render(thread, fakeflat, stencilValue, false, skyFloorHeight, sectorPortals, sectorPortalsStart);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::Render(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
FSectorPortal *portal = fakeflat.FrontSector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
|
||||
if (!portal || (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
|
||||
{
|
||||
RenderNormal(thread, fakeflat, stencilValue, ceiling, skyHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPortal(thread, fakeflat, stencilValue, ceiling, skyHeight, portal, sectorPortals, sectorPortalsStart);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
FTextureID picnum = fakeflat.FrontSector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor);
|
||||
if (picnum != skyflatnum)
|
||||
{
|
||||
FTexture *tex = TexMan.GetPalettedTexture(picnum, true);
|
||||
if (!tex || !tex->isValid())
|
||||
return;
|
||||
|
||||
PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex->GetSoftwareTexture());
|
||||
TriVertex *vertices = CreatePlaneVertices(thread, fakeflat.Subsector, transform, ceiling ? fakeflat.FrontSector->ceilingplane : fakeflat.FrontSector->floorplane);
|
||||
|
||||
PolyDrawArgs args;
|
||||
SetLightLevel(thread, args, fakeflat, ceiling);
|
||||
SetDynLights(thread, args, fakeflat.Subsector, ceiling);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle());
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, 255);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
|
||||
RenderSkyWalls(thread, args, fakeflat.Subsector, nullptr, ceiling, skyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
PolyDrawSectorPortal *polyportal = nullptr;
|
||||
std::vector<PolyPortalSegment> portalSegments;
|
||||
|
||||
// Skip portals not facing the camera
|
||||
if ((ceiling && fakeflat.FrontSector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) ||
|
||||
(!ceiling && fakeflat.FrontSector->floorplane.PointOnSide(viewpoint.Pos) < 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = sectorPortalsStart; i < sectorPortals.size(); i++)
|
||||
{
|
||||
if (sectorPortals[i]->Portal == portal) // To do: what other criteria do we need to check for?
|
||||
{
|
||||
polyportal = sectorPortals[i].get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polyportal)
|
||||
{
|
||||
sectorPortals.push_back(std::unique_ptr<PolyDrawSectorPortal>(new PolyDrawSectorPortal(portal, ceiling)));
|
||||
polyportal = sectorPortals.back().get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate portal clipping
|
||||
portalSegments.reserve(sub->numlines);
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
|
||||
bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0;
|
||||
if (!backside)
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||
portalSegments.push_back({ angle1, angle2 });
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2))
|
||||
portalSegments.push_back({ angle1, angle2 });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, polyportal->StencilValue);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
|
||||
RenderSkyWalls(thread, args, fakeflat.Subsector, polyportal, ceiling, skyHeight);
|
||||
|
||||
polyportal->Shape.push_back({ vertices, (int)fakeflat.Subsector->numlines });
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight)
|
||||
{
|
||||
sector_t *frontsector = sub->sector;
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
if (line->backsector)
|
||||
{
|
||||
sector_t *backsector = line->backsector;
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
|
||||
bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2;
|
||||
if (ceiling && bothSkyCeiling && closedSector)
|
||||
{
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MIN(backceilz1, frontceilz1);
|
||||
double topfloorz2 = MIN(backceilz2, frontceilz2);
|
||||
double bottomceilz1 = MAX(frontfloorz1, backfloorz1);
|
||||
double bottomceilz2 = MAX(frontfloorz2, backfloorz2);
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
skyBottomz1 = middlefloorz1;
|
||||
skyBottomz2 = middlefloorz2;
|
||||
}
|
||||
else if (bothSkyCeiling)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (polyportal && line->linedef && line->linedef->special == Line_Horizon)
|
||||
{
|
||||
// Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity
|
||||
skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
skyBottomz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
}
|
||||
|
||||
TriVertex *wallvert = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
if (ceiling)
|
||||
{
|
||||
wallvert[0] = GetSkyVertex(line->v1, skyHeight);
|
||||
wallvert[1] = GetSkyVertex(line->v2, skyHeight);
|
||||
wallvert[2] = GetSkyVertex(line->v2, skyBottomz2);
|
||||
wallvert[3] = GetSkyVertex(line->v1, skyBottomz1);
|
||||
}
|
||||
else
|
||||
{
|
||||
wallvert[0] = GetSkyVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
|
||||
wallvert[1] = GetSkyVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2));
|
||||
wallvert[2] = GetSkyVertex(line->v2, skyHeight);
|
||||
wallvert[3] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, wallvert, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
if (polyportal)
|
||||
{
|
||||
polyportal->Shape.push_back({ wallvert, 4 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling)
|
||||
{
|
||||
bool foggy = PolyRenderer::Instance()->Level->fadeto || fakeflat.FrontSector->Colormap.FadeColor || (PolyRenderer::Instance()->Level->flags & LEVEL_HASFADETABLE);
|
||||
|
||||
int lightlevel = ceiling ? fakeflat.CeilingLightLevel : fakeflat.FloorLightLevel;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
FDynamicColormap *basecolormap = GetColorTable(fakeflat.FrontSector->Colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (cameraLight->FixedLightLevel() < 0 && fakeflat.FrontSector->e && fakeflat.FrontSector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(fakeflat.FrontSector, ceiling ? &fakeflat.FrontSector->ceilingplane : &fakeflat.FrontSector->floorplane, false);
|
||||
basecolormap = GetColorTable(light->extra_colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (light->p_lightlevel != &fakeflat.FrontSector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for.
|
||||
{
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
}
|
||||
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling)
|
||||
{
|
||||
if (!r_dynlights)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FLightNode *light_list = sub->section->lighthead;
|
||||
|
||||
auto cameraLight = PolyCameraLight::Instance();
|
||||
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
|
||||
{
|
||||
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate max lights that can touch the wall so we can allocate memory for the list
|
||||
int max_lights = 0;
|
||||
FLightNode *cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
max_lights++;
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
if (max_lights == 0)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int dc_num_lights = 0;
|
||||
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
|
||||
|
||||
// Setup lights
|
||||
cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
{
|
||||
bool is_point_light = cur_node->lightsource->IsAttenuated();
|
||||
|
||||
// To do: cull lights not touching subsector
|
||||
|
||||
uint32_t red = cur_node->lightsource->GetRed();
|
||||
uint32_t green = cur_node->lightsource->GetGreen();
|
||||
uint32_t blue = cur_node->lightsource->GetBlue();
|
||||
|
||||
auto &light = dc_lights[dc_num_lights++];
|
||||
light.x = (float)cur_node->lightsource->X();
|
||||
light.y = (float)cur_node->lightsource->Y();
|
||||
light.z = (float)cur_node->lightsource->Z();
|
||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
args.SetLights(dc_lights, dc_num_lights);
|
||||
|
||||
DVector3 normal = ceiling ? sub->sector->ceilingplane.Normal() : sub->sector->floorplane.Normal();
|
||||
args.SetNormal({ (float)normal.X, (float)normal.Y, (float)normal.Z });
|
||||
}
|
||||
|
||||
TriVertex *RenderPolyPlane::CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane)
|
||||
{
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
double planeZ = plane.ZatPoint(viewpoint.Pos.XY());
|
||||
if (viewpoint.Pos.Z < planeZ)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
|
||||
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
TriVertex *RenderPolyPlane::CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight)
|
||||
{
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
if (viewpoint.Pos.Z < skyHeight)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
|
||||
vertices[i] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex)
|
||||
{
|
||||
if (tex)
|
||||
{
|
||||
xscale = (float)(transform.xScale * tex->GetScale().X / tex->GetWidth());
|
||||
yscale = (float)(transform.yScale * tex->GetScale().Y / tex->GetHeight());
|
||||
|
||||
double planeang = (transform.Angle + transform.baseAngle).Radians();
|
||||
cosine = (float)cos(planeang);
|
||||
sine = (float)sin(planeang);
|
||||
|
||||
xOffs = (float)transform.xOffs;
|
||||
yOffs = (float)transform.yOffs;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscale = 1.0f / 64.0f;
|
||||
yscale = 1.0f / 64.0f;
|
||||
cosine = 1.0f;
|
||||
sine = 0.0f;
|
||||
xOffs = 0.0f;
|
||||
yOffs = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Render3DFloorPlane::RenderPlanes(PolyRenderThread *thread, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects)
|
||||
{
|
||||
if (!r_3dfloors || sub->sector->CenterFloor() == sub->sector->CenterCeiling())
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
auto frontsector = sub->sector;
|
||||
auto &ffloors = frontsector->e->XFloor.ffloors;
|
||||
|
||||
// 3D floor floors
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
F3DFloor *prevFloor = i > 0 ? ffloors[i - 1] : nullptr;
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (prevFloor && (prevFloor->flags & fakeFloor->flags & FF_SWIMMABLE)) continue;
|
||||
|
||||
double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->top.plane->isSlope() || (fakeHeight < viewpoint.Pos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = false;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
|
||||
// 3D floor ceilings
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
F3DFloor *prevFloor = i > 0 ? ffloors[i - 1] : nullptr;
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (prevFloor && (prevFloor->flags & fakeFloor->flags & FF_SWIMMABLE)) continue;
|
||||
|
||||
double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->bottom.plane->isSlope() || (fakeHeight > viewpoint.Pos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = true;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Render3DFloorPlane::Render(PolyRenderThread *thread)
|
||||
{
|
||||
FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
|
||||
auto tex = TexMan.GetPalettedTexture(picnum, true);
|
||||
if (!tex->isValid())
|
||||
return;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
|
||||
int lightlevel = 255;
|
||||
bool foggy = false;
|
||||
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(sub->sector, ceiling ? fakeFloor->bottom.plane : fakeFloor->top.plane, ceiling);
|
||||
//basecolormap = light->extra_colormap;
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyPlaneUVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex->GetSoftwareTexture());
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
if (ceiling)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = xform.GetVertex(line->v1, fakeFloor->bottom.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = xform.GetVertex(line->v1, fakeFloor->top.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
if (!Masked)
|
||||
{
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.SetStyle(Additive ? TriBlendMode::Add : TriBlendMode::Normal, MIN(Alpha, 1.0));
|
||||
args.SetStencilTestValue(stencilValue + 1);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
}
|
||||
args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle());
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
|
||||
class PolyPlaneUVTransform
|
||||
{
|
||||
public:
|
||||
PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex);
|
||||
|
||||
TriVertex GetVertex(vertex_t *v1, double height) const
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = (float)v1->fX();
|
||||
v.y = (float)v1->fY();
|
||||
v.z = (float)height;
|
||||
v.w = 1.0f;
|
||||
v.u = GetU(v.x, v.y);
|
||||
v.v = GetV(v.x, v.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
private:
|
||||
float GetU(float x, float y) const { return (xOffs + x * cosine - y * sine) * xscale; }
|
||||
float GetV(float x, float y) const { return (yOffs - x * sine - y * cosine) * yscale; }
|
||||
|
||||
float xscale;
|
||||
float yscale;
|
||||
float cosine;
|
||||
float sine;
|
||||
float xOffs, yOffs;
|
||||
};
|
||||
|
||||
class RenderPolyPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
|
||||
private:
|
||||
void Render(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
|
||||
void RenderPortal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
void RenderNormal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight);
|
||||
|
||||
void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight);
|
||||
|
||||
void SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling);
|
||||
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling);
|
||||
|
||||
TriVertex *CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane);
|
||||
TriVertex *CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight);
|
||||
|
||||
static TriVertex GetSkyVertex(vertex_t *v, double height) { return { (float)v->fX(), (float)v->fY(), (float)height, 1.0f, 0.0f, 0.0f }; }
|
||||
};
|
||||
|
||||
class Render3DFloorPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(PolyRenderThread *thread, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects);
|
||||
|
||||
void Render(PolyRenderThread *thread);
|
||||
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t stencilValue = 0;
|
||||
bool ceiling = false;
|
||||
F3DFloor *fakeFloor = nullptr;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
};
|
||||
|
||||
class PolyTranslucent3DFloorPlane : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucent3DFloorPlane(Render3DFloorPlane plane, uint32_t subsectorDepth) : PolyTranslucentObject(subsectorDepth, 1e7), plane(plane) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
plane.Render(thread);
|
||||
}
|
||||
|
||||
Render3DFloorPlane plane;
|
||||
};
|
|
@ -1,548 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_playersprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "d_player.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_model.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawplayersprites)
|
||||
EXTERN_CVAR(Bool, r_deathcamera)
|
||||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||
extern bool r_modelscene;
|
||||
|
||||
void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
|
||||
{
|
||||
// This code cannot be moved directly to RenderRemainingSprites because the engine
|
||||
// draws the canvas textures between this call and the final call to RenderRemainingSprites..
|
||||
//
|
||||
// We also can't move it because the model render code relies on it
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
int i;
|
||||
int lightnum;
|
||||
DPSprite* psp;
|
||||
DPSprite* weapon;
|
||||
sector_t* sec = nullptr;
|
||||
int floorlight, ceilinglight;
|
||||
F3DFloor *rover;
|
||||
|
||||
if (!r_drawplayersprites ||
|
||||
!viewpoint.camera ||
|
||||
!viewpoint.camera->player ||
|
||||
(players[consoleplayer].cheats & CF_CHASECAM) ||
|
||||
(r_deathcamera && viewpoint.camera->health <= 0))
|
||||
return;
|
||||
|
||||
renderHUDModel = r_modelscene && IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
|
||||
PolyTransferHeights fakeflat(viewpoint.camera->subsector);
|
||||
|
||||
FDynamicColormap *basecolormap;
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
bool nc = !!(viewpoint.camera->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
|
||||
if (cameraLight->FixedLightLevel() < 0 && viewpoint.sector->e && viewpoint.sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
for (i = viewpoint.sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (viewpoint.Pos.Z <= viewpoint.sector->e->XFloor.lightlist[i].plane.Zat0())
|
||||
{
|
||||
rover = viewpoint.sector->e->XFloor.lightlist[i].caster;
|
||||
if (rover)
|
||||
{
|
||||
if (rover->flags & FF_DOUBLESHADOW && viewpoint.Pos.Z <= rover->bottom.plane->Zat0())
|
||||
break;
|
||||
sec = rover->model;
|
||||
if (rover->flags & FF_FADEWALLS)
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
else
|
||||
basecolormap = GetSpriteColorTable(viewpoint.sector->e->XFloor.lightlist[i].extra_colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sec)
|
||||
{
|
||||
sec = viewpoint.sector;
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
floorlight = ceilinglight = sec->lightlevel;
|
||||
}
|
||||
else
|
||||
{ // This used to use camera->Sector but due to interpolation that can be incorrect
|
||||
// when the interpolated viewpoint is in a different sector than the camera.
|
||||
|
||||
sec = fakeflat.FrontSector;
|
||||
floorlight = fakeflat.FloorLightLevel;
|
||||
ceilinglight = fakeflat.CeilingLightLevel;
|
||||
|
||||
// [RH] set basecolormap
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
|
||||
// [RH] set foggy flag
|
||||
bool foggy = (PolyRenderer::Instance()->Level->fadeto || basecolormap->Fade || (PolyRenderer::Instance()->Level->flags & LEVEL_HASFADETABLE));
|
||||
|
||||
// get light level
|
||||
lightnum = ((floorlight + ceilinglight) >> 1) + (foggy ? 0 : viewpoint.extralight << 4);
|
||||
int spriteshade = LightLevelToShade(lightnum, foggy) - 24 * FRACUNIT;
|
||||
|
||||
if (viewpoint.camera->player != nullptr)
|
||||
{
|
||||
double wx, wy;
|
||||
float bobx, boby;
|
||||
|
||||
P_BobWeapon(viewpoint.camera->player, &bobx, &boby, viewpoint.TicFrac);
|
||||
|
||||
// Interpolate the main weapon layer once so as to be able to add it to other layers.
|
||||
if ((weapon = viewpoint.camera->player->FindPSprite(PSP_WEAPON)) != nullptr)
|
||||
{
|
||||
if (weapon->firstTic)
|
||||
{
|
||||
wx = weapon->x;
|
||||
wy = weapon->y;
|
||||
}
|
||||
else
|
||||
{
|
||||
wx = weapon->oldx + (weapon->x - weapon->oldx) * viewpoint.TicFrac;
|
||||
wy = weapon->oldy + (weapon->y - weapon->oldy) * viewpoint.TicFrac;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wx = 0;
|
||||
wy = 0;
|
||||
}
|
||||
|
||||
// add all active psprites
|
||||
psp = viewpoint.camera->player->psprites;
|
||||
while (psp)
|
||||
{
|
||||
// [RH] Don't draw the targeter's crosshair if the player already has a crosshair set.
|
||||
// It's possible this psprite's caller is now null but the layer itself hasn't been destroyed
|
||||
// because it didn't tick yet (if we typed 'take all' while in the console for example).
|
||||
// In this case let's simply not draw it to avoid crashing.
|
||||
|
||||
if ((psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && psp->GetCaller() != nullptr)
|
||||
{
|
||||
RenderSprite(thread, psp, viewpoint.camera, bobx, boby, wx, wy, viewpoint.TicFrac, spriteshade, basecolormap, foggy);
|
||||
}
|
||||
|
||||
psp = psp->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlayerSprites::RenderRemainingSprites()
|
||||
{
|
||||
for (const PolyHWAccelPlayerSprite &sprite : AcceleratedSprites)
|
||||
{
|
||||
screen->DrawTexture(sprite.pic->GetTexture(),
|
||||
viewwindowx + sprite.x1,
|
||||
viewwindowy + viewheight / 2 - sprite.texturemid * sprite.yscale - 0.5,
|
||||
DTA_DestWidthF, FIXED2DBL(sprite.pic->GetWidth() * sprite.xscale),
|
||||
DTA_DestHeightF, sprite.pic->GetHeight() * sprite.yscale,
|
||||
DTA_TranslationIndex, sprite.Translation,
|
||||
DTA_FlipX, sprite.flip,
|
||||
DTA_TopOffset, 0,
|
||||
DTA_LeftOffset, 0,
|
||||
DTA_ClipLeft, viewwindowx,
|
||||
DTA_ClipTop, viewwindowy,
|
||||
DTA_ClipRight, viewwindowx + viewwidth,
|
||||
DTA_ClipBottom, viewwindowy + viewheight,
|
||||
DTA_Alpha, sprite.Alpha,
|
||||
DTA_RenderStyle, sprite.RenderStyle,
|
||||
DTA_FillColor, sprite.FillColor,
|
||||
DTA_SpecialColormap, sprite.special,
|
||||
DTA_ColorOverlay, sprite.overlay.d,
|
||||
DTA_Color, sprite.LightColor | 0xff000000, // the color here does not have a valid alpha component.
|
||||
DTA_Desaturate, sprite.Desaturate,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
AcceleratedSprites.Clear();
|
||||
}
|
||||
|
||||
void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy)
|
||||
{
|
||||
double tx;
|
||||
int x1;
|
||||
int x2;
|
||||
double sx, sy;
|
||||
spritedef_t* sprdef;
|
||||
spriteframe_t* sprframe;
|
||||
FTextureID picnum;
|
||||
uint16_t flip;
|
||||
FTexture* ttex;
|
||||
FSoftwareTexture* tex;
|
||||
bool noaccel;
|
||||
double alpha = owner->Alpha;
|
||||
|
||||
// decide which patch to use
|
||||
if ((unsigned)pspr->GetSprite() >= (unsigned)sprites.Size())
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite number %i\n", pspr->GetSprite());
|
||||
return;
|
||||
}
|
||||
sprdef = &sprites[pspr->GetSprite()];
|
||||
if (pspr->GetFrame() >= sprdef->numframes)
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite frame %i : %i\n", pspr->GetSprite(), pspr->GetFrame());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
DCanvas *renderTarget = PolyRenderer::Instance()->RenderTarget;
|
||||
|
||||
// Force it to use software rendering when drawing to a canvas texture.
|
||||
bool renderToCanvas = PolyRenderer::Instance()->RenderToCanvas;
|
||||
|
||||
sprframe = &SpriteFrames[sprdef->spriteframes + pspr->GetFrame()];
|
||||
|
||||
picnum = sprframe->Texture[0];
|
||||
flip = sprframe->Flip & 1;
|
||||
ttex = TexMan.GetTexture(picnum);
|
||||
|
||||
if (!ttex->isValid())
|
||||
return;
|
||||
|
||||
tex = ttex->GetSoftwareTexture();
|
||||
|
||||
if (pspr->firstTic)
|
||||
{ // Can't interpolate the first tic.
|
||||
pspr->firstTic = false;
|
||||
pspr->oldx = pspr->x;
|
||||
pspr->oldy = pspr->y;
|
||||
}
|
||||
|
||||
sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac;
|
||||
sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y;
|
||||
|
||||
if (pspr->Flags & PSPF_ADDBOB)
|
||||
{
|
||||
sx += (pspr->Flags & PSPF_MIRROR) ? -bobx : bobx;
|
||||
sy += boby;
|
||||
}
|
||||
|
||||
if (pspr->Flags & PSPF_ADDWEAPON && pspr->GetID() != PSP_WEAPON)
|
||||
{
|
||||
sx += wx;
|
||||
sy += wy;
|
||||
}
|
||||
|
||||
if (renderHUDModel)
|
||||
{
|
||||
PolyRenderHUDModel(thread, PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToClip, 1, pspr, (float)sx, (float)sy);
|
||||
return;
|
||||
}
|
||||
|
||||
double yaspectMul = 1.2 * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio;
|
||||
|
||||
double pspritexscale = viewwindow.centerxwide / 160.0;
|
||||
double pspriteyscale = pspritexscale * yaspectMul;
|
||||
double pspritexiscale = 1 / pspritexscale;
|
||||
|
||||
int tleft = tex->GetScaledLeftOffsetPo();
|
||||
int twidth = tex->GetScaledWidth();
|
||||
|
||||
// calculate edges of the shape
|
||||
//tx = sx - BASEXCENTER;
|
||||
tx = (pspr->Flags & PSPF_MIRROR) ? ((BASEXCENTER - twidth) - (sx - tleft)) : ((sx - BASEXCENTER) - tleft);
|
||||
|
||||
x1 = xs_RoundToInt(viewwindow.centerx + tx * pspritexscale);
|
||||
|
||||
// off the right side
|
||||
if (x1 > viewwidth)
|
||||
return;
|
||||
|
||||
tx += twidth;
|
||||
x2 = xs_RoundToInt(viewwindow.centerx + tx * pspritexscale);
|
||||
|
||||
// off the left side
|
||||
if (x2 <= 0)
|
||||
return;
|
||||
|
||||
// store information in a vissprite
|
||||
PolyNoAccelPlayerSprite vis;
|
||||
|
||||
vis.renderflags = owner->renderflags;
|
||||
|
||||
vis.texturemid = (BASEYCENTER - sy) * tex->GetScale().Y + tex->GetTopOffsetPo();
|
||||
|
||||
if (viewpoint.camera->player && (renderToCanvas ||
|
||||
viewheight == renderTarget->GetHeight() ||
|
||||
(renderTarget->GetWidth() > (BASEXCENTER * 2))))
|
||||
{ // Adjust PSprite for fullscreen views
|
||||
vis.texturemid -= pspr->GetYAdjust(renderToCanvas || viewheight == renderTarget->GetHeight());
|
||||
}
|
||||
if (pspr->GetID() < PSP_TARGETCENTER)
|
||||
{ // Move the weapon down for 1280x1024.
|
||||
vis.texturemid -= AspectPspriteOffset(viewwindow.WidescreenRatio);
|
||||
}
|
||||
vis.x1 = x1 < 0 ? 0 : x1;
|
||||
vis.x2 = x2 >= viewwidth ? viewwidth : x2;
|
||||
vis.xscale = FLOAT2FIXED(pspritexscale / tex->GetScale().X);
|
||||
vis.yscale = float(pspriteyscale / tex->GetScale().Y);
|
||||
vis.pic = tex;
|
||||
|
||||
// If flip is used, provided that it's not already flipped (that would just invert itself)
|
||||
// (It's an XOR...)
|
||||
if (!(flip) != !(pspr->Flags & PSPF_FLIP))
|
||||
{
|
||||
vis.xiscale = -FLOAT2FIXED(pspritexiscale * tex->GetScale().X);
|
||||
vis.startfrac = (tex->GetWidth() << FRACBITS) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
vis.xiscale = FLOAT2FIXED(pspritexiscale * tex->GetScale().X);
|
||||
vis.startfrac = 0;
|
||||
}
|
||||
|
||||
if (vis.x1 > x1)
|
||||
vis.startfrac += vis.xiscale*(vis.x1 - x1);
|
||||
|
||||
noaccel = false;
|
||||
FDynamicColormap *colormap_to_use = nullptr;
|
||||
if (pspr->GetID() < PSP_TARGETCENTER)
|
||||
{
|
||||
auto rs = pspr->GetRenderStyle(owner->RenderStyle, owner->Alpha);
|
||||
vis.RenderStyle = rs.first;
|
||||
vis.Alpha = rs.second;
|
||||
|
||||
if (!vis.RenderStyle.IsVisible(vis.Alpha))
|
||||
return;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// The software renderer cannot invert the source without inverting the overlay
|
||||
// too. That means if the source is inverted, we need to do the reverse of what
|
||||
// the invert overlay flag says to do.
|
||||
bool invertcolormap = (vis.RenderStyle.Flags & STYLEF_InvertOverlay) != 0;
|
||||
|
||||
if (vis.RenderStyle.Flags & STYLEF_InvertSource)
|
||||
{
|
||||
invertcolormap = !invertcolormap;
|
||||
}
|
||||
|
||||
const FState* const psprState = pspr->GetState();
|
||||
bool fullbright = !foggy && (psprState == nullptr ? false : psprState->GetFullbright());
|
||||
bool fadeToBlack = (vis.RenderStyle.Flags & STYLEF_FadeToBlack) != 0;
|
||||
|
||||
vis.Light.SetColormap(0, spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack);
|
||||
|
||||
colormap_to_use = (FDynamicColormap*)vis.Light.BaseColormap;
|
||||
|
||||
if (viewpoint.camera->Inventory != nullptr)
|
||||
{
|
||||
visstyle_t visstyle;
|
||||
visstyle.Alpha = vis.Alpha;
|
||||
visstyle.RenderStyle = STYLE_Count;
|
||||
visstyle.Invert = false;
|
||||
|
||||
viewpoint.camera->Inventory->AlterWeaponSprite(&visstyle);
|
||||
|
||||
if (!(pspr->Flags & PSPF_FORCEALPHA)) vis.Alpha = visstyle.Alpha;
|
||||
|
||||
if (visstyle.RenderStyle != STYLE_Count && !(pspr->Flags & PSPF_FORCESTYLE))
|
||||
{
|
||||
vis.RenderStyle = visstyle.RenderStyle;
|
||||
}
|
||||
|
||||
if (visstyle.Invert)
|
||||
{
|
||||
vis.Light.BaseColormap = &SpecialSWColormaps[INVERSECOLORMAP];
|
||||
vis.Light.ColormapNum = 0;
|
||||
noaccel = true;
|
||||
}
|
||||
}
|
||||
// If drawing with a BOOM colormap, disable acceleration.
|
||||
if (vis.Light.BaseColormap == &NormalLight && NormalLight.Maps != realcolormaps.Maps)
|
||||
{
|
||||
noaccel = true;
|
||||
}
|
||||
#if 0
|
||||
// The HW 2D drawer should be able to handle this without problems
|
||||
// If the main colormap has fixed lights, and this sprite is being drawn with that
|
||||
// colormap, disable acceleration so that the lights can remain fixed.
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (!noaccel && cameraLight->ShaderColormap() == nullptr &&
|
||||
NormalLightHasFixedLights && vis.Light.BaseColormap == &NormalLight &&
|
||||
vis.pic->UseBasePalette())
|
||||
{
|
||||
noaccel = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
colormap_to_use = basecolormap;
|
||||
|
||||
vis.Light.BaseColormap = basecolormap;
|
||||
vis.Light.ColormapNum = 0;
|
||||
}
|
||||
|
||||
// Check for hardware-assisted 2D. If it's available, and this sprite is not
|
||||
// fuzzy, don't draw it until after the switch to 2D mode.
|
||||
if (!noaccel && !renderToCanvas)
|
||||
{
|
||||
FRenderStyle style = vis.RenderStyle;
|
||||
style.CheckFuzz();
|
||||
if (style.BlendOp != STYLEOP_Fuzz)
|
||||
{
|
||||
PolyHWAccelPlayerSprite accelSprite;
|
||||
|
||||
accelSprite.pic = vis.pic;
|
||||
accelSprite.texturemid = vis.texturemid;
|
||||
accelSprite.yscale = vis.yscale;
|
||||
accelSprite.xscale = vis.xscale;
|
||||
|
||||
accelSprite.Alpha = vis.Alpha;
|
||||
accelSprite.RenderStyle = vis.RenderStyle;
|
||||
accelSprite.Translation = vis.Translation;
|
||||
accelSprite.FillColor = vis.FillColor;
|
||||
|
||||
accelSprite.basecolormap = colormap_to_use;
|
||||
accelSprite.x1 = x1;
|
||||
accelSprite.flip = vis.xiscale < 0;
|
||||
|
||||
if (vis.Light.BaseColormap >= &SpecialSWColormaps[0] &&
|
||||
vis.Light.BaseColormap < &SpecialSWColormaps[SpecialColormaps.Size()])
|
||||
{
|
||||
accelSprite.special = &SpecialColormaps[vis.Light.BaseColormap - &SpecialSWColormaps[0]];
|
||||
}
|
||||
else if (PolyCameraLight::Instance()->ShaderColormap())
|
||||
{
|
||||
accelSprite.special = PolyCameraLight::Instance()->ShaderColormap();
|
||||
}
|
||||
else
|
||||
{
|
||||
accelSprite.overlay = colormap_to_use->Fade;
|
||||
accelSprite.overlay.a = uint8_t(vis.Light.ColormapNum * 255 / NUMCOLORMAPS);
|
||||
accelSprite.LightColor = colormap_to_use->Color;
|
||||
accelSprite.Desaturate = (uint8_t)clamp(colormap_to_use->Desaturate, 0, 255);
|
||||
}
|
||||
|
||||
AcceleratedSprites.Push(accelSprite);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vis.Render(thread);
|
||||
}
|
||||
|
||||
fixed_t RenderPolyPlayerSprites::LightLevelToShade(int lightlevel, bool foggy)
|
||||
{
|
||||
bool nolightfade = !foggy && ((PolyRenderer::Instance()->Level->flags3 & LEVEL3_NOLIGHTFADE));
|
||||
if (nolightfade)
|
||||
{
|
||||
return (MAX(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a light level into an unbounded colormap index (shade). Result is
|
||||
// fixed point. Why the +12? I wish I knew, but experimentation indicates it
|
||||
// is necessary in order to best reproduce Doom's original lighting.
|
||||
return (NUMCOLORMAPS * 2 * FRACUNIT) - ((lightlevel + 12) * (FRACUNIT*NUMCOLORMAPS / 128));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyNoAccelPlayerSprite::Render(PolyRenderThread *thread)
|
||||
{
|
||||
if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f))
|
||||
{ // scaled to 0; can't see
|
||||
return;
|
||||
}
|
||||
|
||||
RectDrawArgs args;
|
||||
args.SetStyle(RenderStyle, Alpha, FillColor, Translation, pic, false);
|
||||
args.SetLight(Light.BaseColormap, 255 - (Light.ColormapNum << 3));
|
||||
|
||||
double centerY = viewheight / 2;
|
||||
double y1, y2;
|
||||
if (renderflags & RF_YFLIP)
|
||||
{
|
||||
y1 = centerY + (texturemid - pic->GetHeight()) * (-yscale);
|
||||
y2 = y1 + pic->GetHeight() * (-yscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
y1 = centerY - texturemid * yscale;
|
||||
y2 = y1 + pic->GetHeight() * yscale;
|
||||
}
|
||||
args.Draw(thread, viewwindowx + x1, viewwindowx + x2, viewwindowy + y1, viewwindowy + y2, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyColormapLight::SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack)
|
||||
{
|
||||
if (fadeToBlack)
|
||||
{
|
||||
if (invertColormap) // Fade to white
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, MAKERGB(255, 255, 255), basecolormap->Desaturate);
|
||||
invertColormap = false;
|
||||
}
|
||||
else // Fade to black
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, MAKERGB(0, 0, 0), basecolormap->Desaturate);
|
||||
}
|
||||
}
|
||||
|
||||
if (invertColormap)
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, basecolormap->Fade.InverseColor(), basecolormap->Desaturate);
|
||||
}
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedColormap())
|
||||
{
|
||||
BaseColormap = cameraLight->FixedColormap();
|
||||
ColormapNum = 0;
|
||||
}
|
||||
else if (cameraLight->FixedLightLevel() >= 0)
|
||||
{
|
||||
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap;
|
||||
ColormapNum = cameraLight->FixedLightLevel() >> COLORMAPSHIFT;
|
||||
}
|
||||
else if (fullbright)
|
||||
{
|
||||
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap;
|
||||
ColormapNum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseColormap = basecolormap;
|
||||
ColormapNum = GETPALOOKUP(visibility, shade);
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "r_defs.h"
|
||||
|
||||
class DPSprite;
|
||||
struct FDynamicColormap;
|
||||
|
||||
class PolyColormapLight
|
||||
{
|
||||
public:
|
||||
int ColormapNum = 0;
|
||||
FSWColormap *BaseColormap = nullptr;
|
||||
|
||||
void SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack);
|
||||
};
|
||||
|
||||
class PolyNoAccelPlayerSprite
|
||||
{
|
||||
public:
|
||||
short x1 = 0;
|
||||
short x2 = 0;
|
||||
|
||||
double texturemid = 0.0;
|
||||
|
||||
fixed_t xscale = 0;
|
||||
float yscale = 0.0f;
|
||||
|
||||
FSoftwareTexture *pic = nullptr;
|
||||
|
||||
fixed_t xiscale = 0;
|
||||
fixed_t startfrac = 0;
|
||||
|
||||
float Alpha = 0.0f;
|
||||
FRenderStyle RenderStyle;
|
||||
uint32_t Translation = 0;
|
||||
uint32_t FillColor = 0;
|
||||
|
||||
PolyColormapLight Light;
|
||||
|
||||
short renderflags = 0;
|
||||
|
||||
void Render(PolyRenderThread *thread);
|
||||
};
|
||||
|
||||
class PolyHWAccelPlayerSprite
|
||||
{
|
||||
public:
|
||||
FSoftwareTexture *pic = nullptr;
|
||||
double texturemid = 0.0;
|
||||
float yscale = 0.0f;
|
||||
fixed_t xscale = 0;
|
||||
|
||||
float Alpha = 0.0f;
|
||||
FRenderStyle RenderStyle;
|
||||
uint32_t Translation = 0;
|
||||
uint32_t FillColor = 0;
|
||||
|
||||
FDynamicColormap *basecolormap = nullptr;
|
||||
int x1 = 0;
|
||||
|
||||
bool flip = false;
|
||||
FSpecialColormap *special = nullptr;
|
||||
PalEntry overlay = 0;
|
||||
PalEntry LightColor = 0xffffffff;
|
||||
uint8_t Desaturate = 0;
|
||||
};
|
||||
|
||||
class RenderPolyPlayerSprites
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread);
|
||||
void RenderRemainingSprites();
|
||||
|
||||
private:
|
||||
void RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy);
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy);
|
||||
|
||||
enum { BASEXCENTER = 160 };
|
||||
enum { BASEYCENTER = 100 };
|
||||
|
||||
TArray<PolyHWAccelPlayerSprite> AcceleratedSprites;
|
||||
sector_t tempsec;
|
||||
bool renderHUDModel = false;
|
||||
};
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_maputl.h"
|
||||
#include "sbar.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_portal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyDrawSectorPortal::PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling) : Portal(portal), Ceiling(ceiling)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::Render(int portalDepth)
|
||||
{
|
||||
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
|
||||
return;
|
||||
|
||||
/*angle_t angle1 = PolyCull::PointToPseudoAngle(v1->fX(), v1->fY());
|
||||
angle_t angle2 = PolyCull::PointToPseudoAngle(v2->fX(), v2->fY());
|
||||
Segments.clear();
|
||||
Segments.push_back({ angle1, angle2 });*/
|
||||
|
||||
SaveGlobals();
|
||||
|
||||
PortalViewpoint = PolyRenderer::Instance()->SetupPerspectiveMatrix();
|
||||
PortalViewpoint.StencilValue = StencilValue;
|
||||
PortalViewpoint.PortalDepth = portalDepth;
|
||||
PortalViewpoint.PortalEnterSector = Portal->mDestination;
|
||||
|
||||
PolyRenderer::Instance()->Scene.Render(&PortalViewpoint);
|
||||
|
||||
RestoreGlobals();
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::SaveGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
SavedViewpoint = viewpoint;
|
||||
SavedInvisibility = viewpoint.camera ? (viewpoint.camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false;
|
||||
|
||||
if (Portal->mType == PORTS_SKYVIEWPOINT)
|
||||
{
|
||||
// Don't let gun flashes brighten the sky box
|
||||
AActor *sky = Portal->mSkybox;
|
||||
viewpoint.extralight = 0;
|
||||
//PolyRenderer::Instance()->Light.SetVisibility(sky->args[0] * 0.25f);
|
||||
viewpoint.Pos = sky->InterpolatedPosition(viewpoint.TicFrac);
|
||||
viewpoint.Angles.Yaw = SavedViewpoint.Angles.Yaw + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * viewpoint.TicFrac);
|
||||
}
|
||||
else //if (Portal->mType == PORTS_STACKEDSECTORTHING || Portal->mType == PORTS_PORTAL || Portal->mType == PORTS_LINKEDPORTAL)
|
||||
{
|
||||
//extralight = pl->extralight;
|
||||
//SetVisibility(pl->visibility);
|
||||
viewpoint.Pos.X += Portal->mDisplacement.X;
|
||||
viewpoint.Pos.Y += Portal->mDisplacement.Y;
|
||||
}
|
||||
|
||||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = Portal->mDestination;
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
|
||||
Portal->mFlags |= PORTSF_INSKYBOX;
|
||||
if (Portal->mPartner > 0) PolyRenderer::Instance()->Level->sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX;
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::RestoreGlobals()
|
||||
{
|
||||
Portal->mFlags &= ~PORTSF_INSKYBOX;
|
||||
if (Portal->mPartner > 0) PolyRenderer::Instance()->Level->sectorPortals[Portal->mPartner].mFlags &= ~PORTSF_INSKYBOX;
|
||||
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
viewpoint = SavedViewpoint;
|
||||
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
if (SavedInvisibility)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
else
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
|
||||
//PolyRenderer::Instance()->Light.SetVisibility(savedvisibility);
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyDrawLinePortal::PolyDrawLinePortal(FLinePortal *portal) : Portal(portal)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
PolyDrawLinePortal::PolyDrawLinePortal(line_t *mirror) : Mirror(mirror)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::Render(int portalDepth)
|
||||
{
|
||||
SaveGlobals();
|
||||
|
||||
// Find portal destination line and make sure it faces the right way
|
||||
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
|
||||
DVector2 pt1 = clipLine->v1->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
DVector2 pt2 = clipLine->v2->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
bool backfacing = (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0);
|
||||
|
||||
PortalViewpoint = PolyRenderer::Instance()->SetupPerspectiveMatrix(Mirror != nullptr);
|
||||
PortalViewpoint.StencilValue = StencilValue;
|
||||
PortalViewpoint.PortalDepth = portalDepth;
|
||||
PortalViewpoint.PortalEnterLine = clipLine;
|
||||
PortalViewpoint.PortalEnterSector = backfacing ? clipLine->frontsector : clipLine->backsector;
|
||||
|
||||
PolyRenderer::Instance()->Scene.Render(&PortalViewpoint);
|
||||
|
||||
RestoreGlobals();
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::SaveGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
SavedViewpoint = viewpoint;
|
||||
SavedInvisibility = viewpoint.camera ? (viewpoint.camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false;
|
||||
|
||||
if (Mirror)
|
||||
{
|
||||
DAngle startang = viewpoint.Angles.Yaw;
|
||||
DVector3 startpos = viewpoint.Pos;
|
||||
|
||||
vertex_t *v1 = Mirror->v1;
|
||||
|
||||
// Reflect the current view behind the mirror.
|
||||
if (Mirror->Delta().X == 0)
|
||||
{ // vertical mirror
|
||||
viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX();
|
||||
}
|
||||
else if (Mirror->Delta().Y == 0)
|
||||
{ // horizontal mirror
|
||||
viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY();
|
||||
}
|
||||
else
|
||||
{ // any mirror
|
||||
vertex_t *v2 = Mirror->v2;
|
||||
|
||||
double dx = v2->fX() - v1->fX();
|
||||
double dy = v2->fY() - v1->fY();
|
||||
double x1 = v1->fX();
|
||||
double y1 = v1->fY();
|
||||
double x = startpos.X;
|
||||
double y = startpos.Y;
|
||||
|
||||
// the above two cases catch len == 0
|
||||
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
|
||||
|
||||
viewpoint.Pos.X = (x1 + r * dx) * 2 - x;
|
||||
viewpoint.Pos.Y = (y1 + r * dy) * 2 - y;
|
||||
}
|
||||
viewpoint.Angles.Yaw = Mirror->Delta().Angle() * 2 - startang;
|
||||
|
||||
if (viewpoint.camera)
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto src = Portal->mOrigin;
|
||||
auto dst = Portal->mDestination;
|
||||
|
||||
P_TranslatePortalXY(src, viewpoint.Pos.X, viewpoint.Pos.Y);
|
||||
P_TranslatePortalZ(src, viewpoint.Pos.Z);
|
||||
P_TranslatePortalAngle(src, viewpoint.Angles.Yaw);
|
||||
P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
|
||||
P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y);
|
||||
|
||||
if (viewpoint.camera && !viewpoint.showviewer)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
|
||||
/* What is this code trying to do?
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
|
||||
if (!viewpoint.showviewer && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst))
|
||||
{
|
||||
double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
|
||||
if (distp > EQUAL_EPSILON)
|
||||
{
|
||||
double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length();
|
||||
double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length();
|
||||
|
||||
if (dist1 + dist2 < distp + 1)
|
||||
{
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(viewpoint.Pos)->sector;
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::RestoreGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
viewpoint = SavedViewpoint;
|
||||
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
if (SavedInvisibility)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
else
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "poly_scene.h"
|
||||
|
||||
struct PolyPortalVertexRange
|
||||
{
|
||||
PolyPortalVertexRange(const TriVertex *vertices, int count) : Vertices(vertices), Count(count) { }
|
||||
const TriVertex *Vertices;
|
||||
int Count;
|
||||
};
|
||||
|
||||
class PolyPortalSegment
|
||||
{
|
||||
public:
|
||||
PolyPortalSegment(angle_t start, angle_t end) : Start(start), End(end) { }
|
||||
angle_t Start, End;
|
||||
};
|
||||
|
||||
class PolyDrawSectorPortal
|
||||
{
|
||||
public:
|
||||
PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling);
|
||||
|
||||
void Render(int portalDepth);
|
||||
|
||||
FSectorPortal *Portal = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
void RestoreGlobals();
|
||||
|
||||
bool Ceiling;
|
||||
PolyPortalViewpoint PortalViewpoint;
|
||||
|
||||
FRenderViewpoint SavedViewpoint;
|
||||
bool SavedInvisibility;
|
||||
};
|
||||
|
||||
class PolyDrawLinePortal
|
||||
{
|
||||
public:
|
||||
PolyDrawLinePortal(FLinePortal *portal);
|
||||
PolyDrawLinePortal(line_t *mirror);
|
||||
|
||||
void Render(int portalDepth);
|
||||
|
||||
FLinePortal *Portal = nullptr;
|
||||
line_t *Mirror = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
void RestoreGlobals();
|
||||
|
||||
PolyPortalViewpoint PortalViewpoint;
|
||||
|
||||
FRenderViewpoint SavedViewpoint;
|
||||
bool SavedInvisibility;
|
||||
};
|
|
@ -1,594 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_maputl.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_wall.h"
|
||||
#include "polyrenderer/scene/poly_wallsprite.h"
|
||||
#include "polyrenderer/scene/poly_plane.h"
|
||||
#include "polyrenderer/scene/poly_particle.h"
|
||||
#include "polyrenderer/scene/poly_sprite.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_portal_recursions)
|
||||
|
||||
extern double model_distance_cull;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RenderPolyScene::RenderPolyScene()
|
||||
{
|
||||
}
|
||||
|
||||
RenderPolyScene::~RenderPolyScene()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderPolyScene::Render(PolyPortalViewpoint *viewpoint)
|
||||
{
|
||||
PolyPortalViewpoint *oldviewpoint = CurrentViewpoint;
|
||||
CurrentViewpoint = viewpoint;
|
||||
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
CurrentViewpoint->ObjectsStart = thread->TranslucentObjects.size();
|
||||
CurrentViewpoint->SectorPortalsStart = thread->SectorPortals.size();
|
||||
CurrentViewpoint->LinePortalsStart = thread->LinePortals.size();
|
||||
|
||||
PolyCullCycles.Clock();
|
||||
Cull.CullScene(CurrentViewpoint->PortalEnterSector, CurrentViewpoint->PortalEnterLine);
|
||||
PolyCullCycles.Unclock();
|
||||
|
||||
RenderSectors();
|
||||
|
||||
PolyMaskedCycles.Clock();
|
||||
const auto &rviewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
for (uint32_t sectorIndex : Cull.SeenSectors)
|
||||
{
|
||||
sector_t *sector = &PolyRenderer::Instance()->Level->sectors[sectorIndex];
|
||||
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
|
||||
{
|
||||
if (!RenderPolySprite::IsThingCulled(thing))
|
||||
{
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
double distanceSquared = (thing->Pos() - rviewpoint.Pos).LengthSquared();
|
||||
if (r_modelscene && modelframe && distanceSquared < model_distance_cull)
|
||||
{
|
||||
AddModel(thread, thing, distanceSquared, thing->Pos());
|
||||
}
|
||||
else
|
||||
{
|
||||
DVector2 left, right;
|
||||
if (!RenderPolySprite::GetLine(thing, left, right))
|
||||
continue;
|
||||
AddSprite(thread, thing, distanceSquared, left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PolyMaskedCycles.Unclock();
|
||||
|
||||
CurrentViewpoint->ObjectsEnd = thread->TranslucentObjects.size();
|
||||
CurrentViewpoint->SectorPortalsEnd = thread->SectorPortals.size();
|
||||
CurrentViewpoint->LinePortalsEnd = thread->LinePortals.size();
|
||||
|
||||
Skydome.Render(thread, CurrentViewpoint->WorldToView, CurrentViewpoint->WorldToClip);
|
||||
|
||||
RenderPortals();
|
||||
RenderTranslucent();
|
||||
|
||||
CurrentViewpoint = oldviewpoint;
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSectors()
|
||||
{
|
||||
PolyRenderThread *mainthread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
int totalcount = (int)Cull.PvsSubsectors.size();
|
||||
uint32_t *subsectors = Cull.PvsSubsectors.data();
|
||||
|
||||
PolyOpaqueCycles.Clock();
|
||||
|
||||
PolyRenderer::Instance()->Threads.RenderThreadSlices(totalcount, [&](PolyRenderThread *thread)
|
||||
{
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip), nullptr);
|
||||
|
||||
if (thread != mainthread)
|
||||
{
|
||||
thread->TranslucentObjects.clear();
|
||||
thread->SectorPortals.clear();
|
||||
thread->LinePortals.clear();
|
||||
}
|
||||
|
||||
int start = thread->Start;
|
||||
int end = thread->End;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
RenderSubsector(thread, &PolyRenderer::Instance()->Level->subsectors[subsectors[i]], i);
|
||||
}
|
||||
}, [&](PolyRenderThread *thread)
|
||||
{
|
||||
const auto &objects = thread->TranslucentObjects;
|
||||
mainthread->TranslucentObjects.insert(mainthread->TranslucentObjects.end(), objects.begin(), objects.end());
|
||||
});
|
||||
|
||||
PolyOpaqueCycles.Unclock();
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth)
|
||||
{
|
||||
sector_t *frontsector = sub->sector;
|
||||
auto Level = frontsector->Level;
|
||||
frontsector->MoreFlags |= SECMF_DRAWN;
|
||||
|
||||
if (sub->polys)
|
||||
{
|
||||
if (sub->BSP == nullptr || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
|
||||
// This is done by the GL renderer, but not the sw renderer. No idea what the purpose is..
|
||||
for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++)
|
||||
{
|
||||
sub->BSP->Segs[i].Subsector = sub;
|
||||
sub->BSP->Segs[i].PartnerSeg = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (sub->BSP->Nodes.Size() == 0)
|
||||
{
|
||||
RenderPolySubsector(thread, &sub->BSP->Subsectors[0], subsectorDepth, frontsector);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolyNode(thread, &sub->BSP->Nodes.Last(), subsectorDepth, frontsector);
|
||||
}
|
||||
}
|
||||
|
||||
PolyTransferHeights fakeflat(sub);
|
||||
|
||||
Render3DFloorPlane::RenderPlanes(thread, sub, CurrentViewpoint->StencilValue, subsectorDepth, thread->TranslucentObjects);
|
||||
RenderPolyPlane::RenderPlanes(thread, fakeflat, CurrentViewpoint->StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, thread->SectorPortals, CurrentViewpoint->SectorPortalsStart);
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
if (Cull.IsLineSegVisible(subsectorDepth, i))
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
RenderLine(thread, sub, line, fakeflat.FrontSector, subsectorDepth);
|
||||
}
|
||||
}
|
||||
|
||||
int subsectorIndex = sub->Index();
|
||||
for (int i = Level->ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Level->Particles[i].snext)
|
||||
{
|
||||
particle_t *particle = &Level->Particles[i];
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentParticle>(particle, sub, subsectorDepth, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
// Decide which side the view point is on.
|
||||
int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
RenderPolyNode(thread, bsp->children[side], subsectorDepth, frontsector);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
// Don't bother culling on poly objects
|
||||
//if (!CheckBBox(bsp->bbox[side]))
|
||||
// return;
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
RenderPolySubsector(thread, sub, subsectorDepth, frontsector);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
if (line->linedef)
|
||||
{
|
||||
// Reject lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
continue;
|
||||
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
line->linedef->flags |= ML_MAPPED;
|
||||
sub->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
|
||||
RenderPolyWall::RenderLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, thread->TranslucentObjects, thread->LinePortals, CurrentViewpoint->LinePortalsStart, CurrentViewpoint->PortalEnterLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RenderPolyScene::PointOnSide(const DVector2 &pos, const node_t *node)
|
||||
{
|
||||
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
|
||||
{
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
{
|
||||
subsector_t *sub = &PolyRenderer::Instance()->Level->subsectors[0];
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSprite(thread, thing, sortDistance, left, right, 0.0, 1.0, PolyRenderer::Instance()->Level->HeadNode());
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
|
||||
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
|
||||
double planeD = planeNormal | planePos;
|
||||
|
||||
int sideLeft = (left | planeNormal) > planeD;
|
||||
int sideRight = (right | planeNormal) > planeD;
|
||||
|
||||
if (sideLeft != sideRight)
|
||||
{
|
||||
double dotLeft = planeNormal | left;
|
||||
double dotRight = planeNormal | right;
|
||||
double t = (planeD - dotLeft) / (dotRight - dotLeft);
|
||||
|
||||
DVector2 mid = left * (1.0 - t) + right * t;
|
||||
double tmid = t1 * (1.0 - t) + t2 * t;
|
||||
|
||||
AddSprite(thread, thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
|
||||
right = mid;
|
||||
t2 = tmid;
|
||||
}
|
||||
node = bsp->children[sideLeft];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, (float)t1, (float)t2, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddModel(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 pos)
|
||||
{
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
{
|
||||
subsector_t *sub = &PolyRenderer::Instance()->Level->subsectors[0];
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
void *node = PolyRenderer::Instance()->Level->HeadNode();
|
||||
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
|
||||
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
|
||||
double planeD = planeNormal | planePos;
|
||||
|
||||
int side = (pos | planeNormal) > planeD;
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
||||
{
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
line->linedef->flags |= ML_MAPPED;
|
||||
sub->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
|
||||
// Render 3D floor sides
|
||||
if (line->sidedef && line->backsector && line->backsector->e && line->backsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = line->backsector->e->XFloor.ffloors[i];
|
||||
RenderPolyWall::Render3DFloorLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, fakeFloor, thread->TranslucentObjects);
|
||||
}
|
||||
}
|
||||
|
||||
// Render wall, and update culling info if its an occlusion blocker
|
||||
RenderPolyWall::RenderLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, thread->TranslucentObjects, thread->LinePortals, CurrentViewpoint->LinePortalsStart, CurrentViewpoint->PortalEnterLine);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPortals()
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
bool enterPortals = CurrentViewpoint->PortalDepth < r_portal_recursions;
|
||||
|
||||
if (enterPortals)
|
||||
{
|
||||
for (size_t i = CurrentViewpoint->SectorPortalsStart; i < CurrentViewpoint->SectorPortalsEnd; i++)
|
||||
thread->SectorPortals[i]->Render(CurrentViewpoint->PortalDepth + 1);
|
||||
|
||||
for (size_t i = CurrentViewpoint->LinePortalsStart; i < CurrentViewpoint->LinePortalsEnd; i++)
|
||||
thread->LinePortals[i]->Render(CurrentViewpoint->PortalDepth + 1);
|
||||
}
|
||||
|
||||
Mat4f *transform = thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip);
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, transform, nullptr);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetWriteColor(!enterPortals);
|
||||
args.SetDepthTest(false);
|
||||
|
||||
if (!enterPortals) // Fill with black
|
||||
{
|
||||
bool foggy = false;
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true);
|
||||
args.SetStyle(TriBlendMode::Fill);
|
||||
args.SetColor(0, 0);
|
||||
}
|
||||
|
||||
for (size_t i = CurrentViewpoint->SectorPortalsStart; i < CurrentViewpoint->SectorPortalsEnd; i++)
|
||||
{
|
||||
const auto &portal = thread->SectorPortals[i];
|
||||
args.SetStencilTestValue(enterPortals ? portal->StencilValue + 1 : portal->StencilValue);
|
||||
args.SetWriteStencil(true, CurrentViewpoint->StencilValue + 1);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = CurrentViewpoint->LinePortalsStart; i < CurrentViewpoint->LinePortalsEnd; i++)
|
||||
{
|
||||
const auto &portal = thread->LinePortals[i];
|
||||
args.SetStencilTestValue(enterPortals ? portal->StencilValue + 1 : portal->StencilValue);
|
||||
args.SetWriteStencil(true, CurrentViewpoint->StencilValue + 1);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderTranslucent()
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
Mat4f *transform = thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip);
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, transform, nullptr);
|
||||
|
||||
PolyMaskedCycles.Clock();
|
||||
|
||||
// Draw all translucent objects back to front
|
||||
std::stable_sort(
|
||||
thread->TranslucentObjects.begin() + CurrentViewpoint->ObjectsStart,
|
||||
thread->TranslucentObjects.begin() + CurrentViewpoint->ObjectsEnd,
|
||||
[](auto a, auto b) { return *a < *b; });
|
||||
|
||||
auto objects = thread->TranslucentObjects.data();
|
||||
for (size_t i = CurrentViewpoint->ObjectsEnd; i > CurrentViewpoint->ObjectsStart; i--)
|
||||
{
|
||||
PolyTranslucentObject *obj = objects[i - 1];
|
||||
obj->Render(thread);
|
||||
obj->~PolyTranslucentObject();
|
||||
}
|
||||
|
||||
PolyMaskedCycles.Unclock();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyTransferHeights::PolyTransferHeights(subsector_t *sub) : Subsector(sub)
|
||||
{
|
||||
sector_t *sec = sub->sector;
|
||||
|
||||
// If player's view height is underneath fake floor, lower the
|
||||
// drawn ceiling to be just under the floor height, and replace
|
||||
// the drawn floor and ceiling textures, and light PolyRenderer::Instance()->Level->, with
|
||||
// the control sector's.
|
||||
//
|
||||
// Similar for ceiling, only reflected.
|
||||
|
||||
// [RH] allow per-plane lighting
|
||||
FloorLightLevel = sec->GetFloorLight();
|
||||
CeilingLightLevel = sec->GetCeilingLight();
|
||||
|
||||
FakeSide = PolyWaterFakeSide::Center;
|
||||
|
||||
const sector_t *s = sec->GetHeightSec();
|
||||
if (s != nullptr)
|
||||
{
|
||||
sector_t *heightsec = PolyRenderer::Instance()->Viewpoint.sector->heightsec;
|
||||
bool underwater = (heightsec && heightsec->floorplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0);
|
||||
bool doorunderwater = false;
|
||||
int diffTex = (s->MoreFlags & SECMF_CLIPFAKEPLANES);
|
||||
|
||||
// Replace sector being drawn with a copy to be hacked
|
||||
tempsec = *sec;
|
||||
|
||||
// Replace floor and ceiling height with control sector's heights.
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->floorplane.CopyPlaneIfValid(&tempsec.floorplane, &sec->ceilingplane))
|
||||
{
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
}
|
||||
else if (s->MoreFlags & SECMF_FAKEFLOORONLY)
|
||||
{
|
||||
if (underwater)
|
||||
{
|
||||
tempsec.Colormap = s->Colormap;
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::BelowFloor;
|
||||
FrontSector = &tempsec;
|
||||
return;
|
||||
}
|
||||
FrontSector = sec;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.floorplane = s->floorplane;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
||||
{
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->ceilingplane.CopyPlaneIfValid(&tempsec.ceilingplane, &sec->floorplane))
|
||||
{
|
||||
tempsec.SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.ceilingplane = s->ceilingplane;
|
||||
}
|
||||
}
|
||||
|
||||
double refceilz = s->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
|
||||
double orgceilz = sec->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
|
||||
|
||||
if (underwater || doorunderwater)
|
||||
{
|
||||
tempsec.floorplane = sec->floorplane;
|
||||
tempsec.ceilingplane = s->floorplane;
|
||||
tempsec.ceilingplane.FlipVert();
|
||||
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
|
||||
tempsec.Colormap = s->Colormap;
|
||||
}
|
||||
|
||||
// killough 11/98: prevent sudden light changes from non-water sectors:
|
||||
if (underwater || doorunderwater)
|
||||
{
|
||||
// head-below-floor hack
|
||||
tempsec.SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
|
||||
tempsec.ceilingplane = s->floorplane;
|
||||
tempsec.ceilingplane.FlipVert();
|
||||
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
|
||||
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
|
||||
{
|
||||
tempsec.floorplane = tempsec.ceilingplane;
|
||||
tempsec.floorplane.FlipVert();
|
||||
tempsec.floorplane.ChangeHeight(+1 / 65536.);
|
||||
tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::BelowFloor;
|
||||
}
|
||||
else if (heightsec && heightsec->ceilingplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0 && orgceilz > refceilz && !(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
||||
{
|
||||
// Above-ceiling hack
|
||||
tempsec.ceilingplane = s->ceilingplane;
|
||||
tempsec.floorplane = s->ceilingplane;
|
||||
tempsec.floorplane.FlipVert();
|
||||
tempsec.floorplane.ChangeHeight(+1 / 65536.);
|
||||
tempsec.Colormap = s->Colormap;
|
||||
|
||||
tempsec.SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
|
||||
|
||||
if (s->GetTexture(sector_t::floor) != skyflatnum)
|
||||
{
|
||||
tempsec.ceilingplane = sec->ceilingplane;
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::AboveCeiling;
|
||||
}
|
||||
sec = &tempsec;
|
||||
}
|
||||
FrontSector = sec;
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "doomdata.h"
|
||||
#include "r_utility.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
#include "poly_playersprite.h"
|
||||
#include "poly_cull.h"
|
||||
#include "poly_sky.h"
|
||||
|
||||
class PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentObject(uint32_t subsectorDepth = 0, double distanceSquared = 0.0) : subsectorDepth(subsectorDepth), DistanceSquared(distanceSquared) { }
|
||||
virtual ~PolyTranslucentObject() { }
|
||||
|
||||
virtual void Render(PolyRenderThread *thread) = 0;
|
||||
|
||||
bool operator<(const PolyTranslucentObject &other) const
|
||||
{
|
||||
return subsectorDepth != other.subsectorDepth ? subsectorDepth < other.subsectorDepth : DistanceSquared < other.DistanceSquared;
|
||||
}
|
||||
|
||||
uint32_t subsectorDepth;
|
||||
double DistanceSquared;
|
||||
};
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
class PolyDrawLinePortal;
|
||||
class PolyPortalSegment;
|
||||
|
||||
class PolyPortalViewpoint
|
||||
{
|
||||
public:
|
||||
Mat4f WorldToView;
|
||||
Mat4f WorldToClip;
|
||||
uint32_t StencilValue = 0;
|
||||
int PortalDepth = 0;
|
||||
bool Mirror = false;
|
||||
|
||||
line_t *PortalEnterLine = nullptr;
|
||||
sector_t *PortalEnterSector = nullptr;
|
||||
|
||||
size_t ObjectsStart = 0;
|
||||
size_t ObjectsEnd = 0;
|
||||
size_t SectorPortalsStart = 0;
|
||||
size_t SectorPortalsEnd = 0;
|
||||
size_t LinePortalsStart = 0;
|
||||
size_t LinePortalsEnd = 0;
|
||||
};
|
||||
|
||||
// Renders everything from a specific viewpoint
|
||||
class RenderPolyScene
|
||||
{
|
||||
public:
|
||||
RenderPolyScene();
|
||||
~RenderPolyScene();
|
||||
|
||||
void Render(PolyPortalViewpoint *viewpoint);
|
||||
|
||||
static const uint32_t SkySubsectorDepth = 0x7fffffff;
|
||||
|
||||
PolyPortalViewpoint *CurrentViewpoint = nullptr;
|
||||
|
||||
private:
|
||||
void RenderPortals();
|
||||
void RenderTranslucent();
|
||||
void RenderSectors();
|
||||
void RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth);
|
||||
void RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
||||
void AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
|
||||
void AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
|
||||
void AddModel(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 pos);
|
||||
|
||||
void RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
void RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
static int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
||||
PolyCull Cull;
|
||||
PolySkyDome Skydome;
|
||||
};
|
||||
|
||||
enum class PolyWaterFakeSide
|
||||
{
|
||||
Center,
|
||||
BelowFloor,
|
||||
AboveCeiling
|
||||
};
|
||||
|
||||
class PolyTransferHeights
|
||||
{
|
||||
public:
|
||||
PolyTransferHeights(subsector_t *sub);
|
||||
|
||||
subsector_t *Subsector = nullptr;
|
||||
sector_t *FrontSector = nullptr;
|
||||
PolyWaterFakeSide FakeSide = PolyWaterFakeSide::Center;
|
||||
int FloorLightLevel = 0;
|
||||
int CeilingLightLevel = 0;
|
||||
|
||||
private:
|
||||
sector_t tempsec;
|
||||
};
|
|
@ -1,429 +0,0 @@
|
|||
/*
|
||||
** Sky dome rendering
|
||||
** Copyright(C) 2003-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with this program. If not, see http:**www.gnu.org/licenses/
|
||||
**
|
||||
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_sky.h"
|
||||
#include "poly_portal.h"
|
||||
#include "r_sky.h" // for skyflatnum
|
||||
#include "g_levellocals.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
|
||||
EXTERN_CVAR(Float, skyoffset)
|
||||
EXTERN_CVAR(Int, r_skymode)
|
||||
|
||||
PolySkyDome::PolySkyDome()
|
||||
{
|
||||
CreateDome();
|
||||
}
|
||||
|
||||
void PolySkyDome::Render(PolyRenderThread *thread, const Mat4f &worldToView, const Mat4f &worldToClip)
|
||||
{
|
||||
#ifdef USE_GL_DOME_MATH
|
||||
Mat4f modelMatrix = GLSkyMath();
|
||||
#else
|
||||
Mat4f modelMatrix = Mat4f::Identity();
|
||||
|
||||
PolySkySetup frameSetup;
|
||||
frameSetup.Update();
|
||||
|
||||
if (frameSetup != mCurrentSetup)
|
||||
{
|
||||
// frontcyl = pixels for full 360 degrees, front texture
|
||||
// backcyl = pixels for full 360 degrees, back texture
|
||||
// skymid = Y scaled pixel offset
|
||||
// sky1pos = unscaled X offset, front
|
||||
// sky2pos = unscaled X offset, back
|
||||
// frontpos = scaled X pixel offset (fixed point)
|
||||
// backpos = scaled X pixel offset (fixed point)
|
||||
// skyflip = flip X direction
|
||||
|
||||
float scaleBaseV = 1.42f;
|
||||
float offsetBaseV = 0.25f;
|
||||
|
||||
float scaleFrontU = frameSetup.frontcyl / (float)frameSetup.frontskytex->GetWidth();
|
||||
float scaleFrontV = (float)frameSetup.frontskytex->GetScale().Y * scaleBaseV;
|
||||
float offsetFrontU = (float)((frameSetup.frontpos / 65536.0 + frameSetup.frontcyl / 2) / frameSetup.frontskytex->GetWidth());
|
||||
float offsetFrontV = (float)((frameSetup.skymid / frameSetup.frontskytex->GetHeight() + offsetBaseV) * scaleBaseV);
|
||||
|
||||
unsigned int count = mVertices.Size();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
mVertices[i].u = offsetFrontU + mInitialUV[i].X * scaleFrontU;
|
||||
mVertices[i].v = offsetFrontV + mInitialUV[i].Y * scaleFrontV;
|
||||
}
|
||||
|
||||
mCurrentSetup = frameSetup;
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
Mat4f objectToWorld = Mat4f::Translate((float)viewpoint.Pos.X, (float)viewpoint.Pos.Y, (float)viewpoint.Pos.Z) * modelMatrix;
|
||||
|
||||
int rc = mRows + 1;
|
||||
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(worldToClip * objectToWorld), nullptr);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(false), true);
|
||||
args.SetStencilTestValue(255);
|
||||
args.SetWriteStencil(true, 1);
|
||||
args.SetClipPlane(0, PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, 0, false);
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, rc, true);
|
||||
|
||||
args.SetTexture(mCurrentSetup.frontskytex, DefaultRenderStyle());
|
||||
|
||||
uint32_t topcapcolor = mCurrentSetup.frontskytex->GetSkyCapColor(false);
|
||||
uint32_t bottomcapcolor = mCurrentSetup.frontskytex->GetSkyCapColor(true);
|
||||
uint8_t topcapindex = RGB256k.All[((RPART(topcapcolor) >> 2) << 12) | ((GPART(topcapcolor) >> 2) << 6) | (BPART(topcapcolor) >> 2)];
|
||||
uint8_t bottomcapindex = RGB256k.All[((RPART(bottomcapcolor) >> 2) << 12) | ((GPART(bottomcapcolor) >> 2) << 6) | (BPART(bottomcapcolor) >> 2)];
|
||||
|
||||
for (int i = 1; i <= mRows; i++)
|
||||
{
|
||||
RenderRow(thread, args, i, topcapcolor, topcapindex);
|
||||
RenderRow(thread, args, rc + i, bottomcapcolor, bottomcapindex);
|
||||
}
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex)
|
||||
{
|
||||
args.SetColor(capcolor, capcolorindex);
|
||||
args.SetStyle(TriBlendMode::Skycap);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip);
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap)
|
||||
{
|
||||
uint32_t solid = skytex->GetSkyCapColor(bottomCap);
|
||||
uint8_t palsolid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
|
||||
|
||||
args.SetColor(solid, palsolid);
|
||||
args.SetStyle(TriBlendMode::Fill);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void PolySkyDome::CreateDome()
|
||||
{
|
||||
mColumns = 16;// 128;
|
||||
mRows = 4;
|
||||
CreateSkyHemisphere(false);
|
||||
CreateSkyHemisphere(true);
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
}
|
||||
|
||||
void PolySkyDome::CreateSkyHemisphere(bool zflip)
|
||||
{
|
||||
int r, c;
|
||||
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
|
||||
for (c = 0; c < mColumns; c++)
|
||||
{
|
||||
SkyVertex(1, zflip ? c : (mColumns - 1 - c), zflip);
|
||||
}
|
||||
|
||||
// The total number of triangles per hemisphere can be calculated
|
||||
// as follows: rows * columns * 2 + 2 (for the top cap).
|
||||
for (r = 0; r < mRows; r++)
|
||||
{
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
for (c = 0; c <= mColumns; c++)
|
||||
{
|
||||
SkyVertex(r + 1 - zflip, c, zflip);
|
||||
SkyVertex(r + zflip, c, zflip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TriVertex PolySkyDome::SetVertexXYZ(float xx, float yy, float zz, float uu, float vv)
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = xx;
|
||||
v.y = zz;
|
||||
v.z = yy;
|
||||
v.w = 1.0f;
|
||||
v.u = uu;
|
||||
v.v = vv;
|
||||
return v;
|
||||
}
|
||||
|
||||
void PolySkyDome::SkyVertex(int r, int c, bool zflip)
|
||||
{
|
||||
static const FAngle maxSideAngle = 60.f;
|
||||
static const float scale = 10000.;
|
||||
|
||||
FAngle topAngle = (c / (float)mColumns * 360.f);
|
||||
FAngle sideAngle = maxSideAngle * (float)(mRows - r) / (float)mRows;
|
||||
float height = sideAngle.Sin();
|
||||
float realRadius = scale * sideAngle.Cos();
|
||||
FVector2 pos = topAngle.ToVector(realRadius);
|
||||
float z = (!zflip) ? scale * height : -scale * height;
|
||||
|
||||
float u, v;
|
||||
|
||||
// And the texture coordinates.
|
||||
if (!zflip) // Flipped Y is for the lower hemisphere.
|
||||
{
|
||||
u = (-c / (float)mColumns);
|
||||
v = (r / (float)mRows);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (-c / (float)mColumns);
|
||||
v = 1.0f + ((mRows - r) / (float)mRows);
|
||||
}
|
||||
|
||||
if (r != 4) z += 300;
|
||||
|
||||
// And finally the vertex.
|
||||
TriVertex vert;
|
||||
vert = SetVertexXYZ(-pos.X, z - 1.f, pos.Y, u, v - 0.5f);
|
||||
mVertices.Push(vert);
|
||||
mInitialUV.Push({ vert.u, vert.v });
|
||||
}
|
||||
|
||||
Mat4f PolySkyDome::GLSkyMath()
|
||||
{
|
||||
PolySkySetup frameSetup;
|
||||
frameSetup.Update();
|
||||
mCurrentSetup = frameSetup;
|
||||
|
||||
float x_offset = 0.0f;
|
||||
float y_offset = 0.0f;
|
||||
bool mirror = false;
|
||||
FSoftwareTexture *tex = mCurrentSetup.frontskytex;
|
||||
|
||||
int texh = 0;
|
||||
int texw = 0;
|
||||
|
||||
Mat4f modelMatrix = Mat4f::Identity();
|
||||
if (tex)
|
||||
{
|
||||
texw = tex->GetWidth();
|
||||
texh = tex->GetHeight();
|
||||
|
||||
modelMatrix = Mat4f::Rotate(-180.0f + x_offset, 0.f, 0.f, 1.f);
|
||||
|
||||
float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f;
|
||||
float yscale = 1.f;
|
||||
if (texh <= 128 && (PolyRenderer::Instance()->Level->flags & LEVEL_FORCETILEDSKY))
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
else if (texh < 128)
|
||||
{
|
||||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, -1250.f);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 128 / 230.f);
|
||||
yscale = (float)(128 / texh); // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, -1250.f);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, texh / 230.f);
|
||||
}
|
||||
else if (texh <= 240)
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (200 - texh + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f);
|
||||
}
|
||||
else
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
|
||||
float offsetU = 1.0f;
|
||||
float offsetV = y_offset / texh;
|
||||
float scaleU = mirror ? -xscale : xscale;
|
||||
float scaleV = yscale;
|
||||
|
||||
unsigned int count = mVertices.Size();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
mVertices[i].u = offsetU + mInitialUV[i].X * scaleU;
|
||||
mVertices[i].v = offsetV + mInitialUV[i].Y * scaleV;
|
||||
}
|
||||
}
|
||||
|
||||
return modelMatrix;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true)
|
||||
{
|
||||
auto tex = TexMan.GetPalettedTexture(texid, true);
|
||||
if (tex == nullptr) return nullptr;
|
||||
if (!allownull && !tex->isValid()) return nullptr;
|
||||
return tex->GetSoftwareTexture();
|
||||
}
|
||||
|
||||
void PolySkySetup::Update()
|
||||
{
|
||||
double skytexturemid = 0.0;
|
||||
double skyscale = 0.0;
|
||||
float skyiscale = 0.0f;
|
||||
fixed_t sky1cyl = 0, sky2cyl = 0;
|
||||
auto Level = PolyRenderer::Instance()->Level;
|
||||
|
||||
auto skytex1 = TexMan.GetPalettedTexture(Level->skytexture1, true);
|
||||
auto skytex2 = TexMan.GetPalettedTexture(Level->skytexture2, true);
|
||||
|
||||
if (skytex1)
|
||||
{
|
||||
FSoftwareTexture *sskytex1 = skytex1->GetSoftwareTexture();
|
||||
FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture();
|
||||
skytexturemid = 0;
|
||||
int skyheight = skytex1->GetDisplayHeight();
|
||||
if (skyheight >= 128 && skyheight < 200)
|
||||
{
|
||||
skytexturemid = -28;
|
||||
}
|
||||
else if (skyheight > 200)
|
||||
{
|
||||
skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0);
|
||||
}
|
||||
|
||||
if (viewwidth != 0 && viewheight != 0)
|
||||
{
|
||||
skyiscale = float(r_Yaspect / freelookviewheight);
|
||||
skyscale = freelookviewheight / r_Yaspect;
|
||||
|
||||
skyiscale *= float(PolyRenderer::Instance()->Viewpoint.FieldOfView.Degrees / 90.);
|
||||
skyscale *= float(90. / PolyRenderer::Instance()->Viewpoint.FieldOfView.Degrees);
|
||||
}
|
||||
|
||||
if (Level->skystretch)
|
||||
{
|
||||
skyscale *= (double)SKYSTRETCH_HEIGHT / skyheight;
|
||||
skyiscale *= skyheight / (float)SKYSTRETCH_HEIGHT;
|
||||
skytexturemid *= skyheight / (double)SKYSTRETCH_HEIGHT;
|
||||
}
|
||||
|
||||
// The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees,
|
||||
// giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024,
|
||||
// we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of
|
||||
// the texture as the cylinder's circumfrence.
|
||||
sky1cyl = MAX(sskytex1->GetWidth(), fixed_t(sskytex1->GetScale().X * 1024));
|
||||
sky2cyl = MAX(sskytex2->GetWidth(), fixed_t(sskytex2->GetScale().Y * 1024));
|
||||
}
|
||||
|
||||
FTextureID sky1tex, sky2tex;
|
||||
double frontdpos = 0, backdpos = 0;
|
||||
|
||||
if ((PolyRenderer::Instance()->Level->flags & LEVEL_SWAPSKIES) && !(PolyRenderer::Instance()->Level->flags & LEVEL_DOUBLESKY))
|
||||
{
|
||||
sky1tex = Level->skytexture2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sky1tex = Level->skytexture1;
|
||||
}
|
||||
sky2tex = Level->skytexture2;
|
||||
skymid = skytexturemid;
|
||||
skyangle = 0;
|
||||
|
||||
int sectorSky = 0;// sector->sky;
|
||||
|
||||
if (!(sectorSky & PL_SKYFLAT))
|
||||
{ // use sky1
|
||||
sky1:
|
||||
frontskytex = GetSWTex(sky1tex);
|
||||
if (PolyRenderer::Instance()->Level->flags & LEVEL_DOUBLESKY)
|
||||
backskytex = GetSWTex(sky2tex);
|
||||
else
|
||||
backskytex = nullptr;
|
||||
skyflip = false;
|
||||
frontdpos = Level->sky1pos;
|
||||
backdpos = Level->sky2pos;
|
||||
frontcyl = sky1cyl;
|
||||
backcyl = sky2cyl;
|
||||
}
|
||||
else if (sectorSky == PL_SKYFLAT)
|
||||
{ // use sky2
|
||||
frontskytex = GetSWTex(sky2tex);
|
||||
backskytex = nullptr;
|
||||
frontcyl = sky2cyl;
|
||||
skyflip = false;
|
||||
frontdpos = Level->sky2pos;
|
||||
}
|
||||
else
|
||||
{ // MBF's linedef-controlled skies
|
||||
// Sky Linedef
|
||||
const line_t *l = &PolyRenderer::Instance()->Level->lines[(sectorSky & ~PL_SKYFLAT) - 1];
|
||||
|
||||
// Sky transferred from first sidedef
|
||||
const side_t *s = l->sidedef[0];
|
||||
int pos;
|
||||
|
||||
// Texture comes from upper texture of reference sidedef
|
||||
// [RH] If swapping skies, then use the lower sidedef
|
||||
if (PolyRenderer::Instance()->Level->flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid())
|
||||
{
|
||||
pos = side_t::bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = side_t::top;
|
||||
}
|
||||
|
||||
frontskytex = GetSWTex(s->GetTexture(pos), false);
|
||||
if (frontskytex == nullptr)
|
||||
{ // [RH] The blank texture: Use normal sky instead.
|
||||
goto sky1;
|
||||
}
|
||||
backskytex = nullptr;
|
||||
|
||||
// Horizontal offset is turned into an angle offset,
|
||||
// to allow sky rotation as well as careful positioning.
|
||||
// However, the offset is scaled very small, so that it
|
||||
// allows a long-period of sky rotation.
|
||||
skyangle += FLOAT2FIXED(s->GetTextureXOffset(pos));
|
||||
|
||||
// Vertical offset allows careful sky positioning.
|
||||
skymid = s->GetTextureYOffset(pos);
|
||||
|
||||
// We sometimes flip the picture horizontally.
|
||||
//
|
||||
// Doom always flipped the picture, so we make it optional,
|
||||
// to make it easier to use the new feature, while to still
|
||||
// allow old sky textures to be used.
|
||||
skyflip = l->args[2] ? false : true;
|
||||
|
||||
int frontxscale = int(frontskytex->GetScale().X * 1024);
|
||||
frontcyl = MAX(frontskytex->GetWidth(), frontxscale);
|
||||
}
|
||||
|
||||
frontpos = int(fmod(frontdpos, sky1cyl * 65536.0));
|
||||
if (backskytex != nullptr)
|
||||
{
|
||||
backpos = int(fmod(backdpos, sky2cyl * 65536.0));
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
** Sky dome rendering
|
||||
** Copyright(C) 2003-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with this program. If not, see http:**www.gnu.org/licenses/
|
||||
**
|
||||
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolySkySetup
|
||||
{
|
||||
public:
|
||||
void Update();
|
||||
|
||||
bool operator==(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) == 0; }
|
||||
bool operator!=(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) != 0; }
|
||||
|
||||
FSoftwareTexture *frontskytex = nullptr;
|
||||
FSoftwareTexture *backskytex = nullptr;
|
||||
bool skyflip = 0;
|
||||
int frontpos = 0;
|
||||
int backpos = 0;
|
||||
fixed_t frontcyl = 0;
|
||||
fixed_t backcyl = 0;
|
||||
double skymid = 0.0;
|
||||
angle_t skyangle = 0;
|
||||
};
|
||||
|
||||
class PolySkyDome
|
||||
{
|
||||
public:
|
||||
PolySkyDome();
|
||||
void Render(PolyRenderThread *thread, const Mat4f &worldToView, const Mat4f &worldToClip);
|
||||
|
||||
private:
|
||||
TArray<FVector2> mInitialUV;
|
||||
TArray<TriVertex> mVertices;
|
||||
TArray<unsigned int> mPrimStart;
|
||||
int mRows, mColumns;
|
||||
|
||||
void SkyVertex(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphere(bool zflip);
|
||||
void CreateDome();
|
||||
void RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex);
|
||||
void RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap);
|
||||
|
||||
TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0);
|
||||
|
||||
Mat4f GLSkyMath();
|
||||
|
||||
PolySkySetup mCurrentSetup;
|
||||
};
|
|
@ -1,432 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_sprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "polyrenderer/scene/poly_model.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
EXTERN_CVAR(Int, r_drawfuzz)
|
||||
EXTERN_CVAR (Bool, r_debug_disable_vis_filter)
|
||||
EXTERN_CVAR(Int, gl_spriteclip)
|
||||
EXTERN_CVAR(Float, gl_sclipthreshold)
|
||||
EXTERN_CVAR(Float, gl_sclipfactor)
|
||||
|
||||
extern uint32_t r_renderercaps;
|
||||
extern double model_distance_cull;
|
||||
|
||||
bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return false;
|
||||
|
||||
DVector2 spriteScale = thing->Scale;
|
||||
double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
double thingyscalemul = spriteScale.Y / tex->GetScale().Y;
|
||||
|
||||
double spriteWidth = thingxscalemul * tex->GetWidth();
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
double offsetX;
|
||||
if (flipTextureX)
|
||||
offsetX = (tex->GetWidth() - tex->GetLeftOffsetPo()) * thingxscalemul;
|
||||
else
|
||||
offsetX = tex->GetLeftOffsetPo() * thingxscalemul;
|
||||
|
||||
left = DVector2(pos.X - viewpoint.Sin * offsetX, pos.Y + viewpoint.Cos * offsetX);
|
||||
right = DVector2(left.X + viewpoint.Sin * spriteWidth, left.Y - viewpoint.Cos * spriteWidth);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderPolySprite::Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2)
|
||||
{
|
||||
if (r_modelscene)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe && (thing->Pos() - viewpoint.Pos).LengthSquared() < model_distance_cull)
|
||||
{
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
PolyRenderModel(thread, PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToClip, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DVector2 line[2];
|
||||
if (!GetLine(thing, line[0], line[1]))
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 thingpos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
|
||||
double posZ = thingpos.Z;
|
||||
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
|
||||
if (spritetype == RF_FACESPRITE)
|
||||
posZ -= thing->Floorclip;
|
||||
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
posZ += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return;
|
||||
|
||||
double thingyscalemul = thing->Scale.Y / tex->GetScale().Y;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
posZ -= (tex->GetHeight() - tex->GetTopOffsetPo()) * thingyscalemul;
|
||||
posZ = PerformSpriteClipAdjustment(thing, thingpos, spriteHeight, posZ);
|
||||
|
||||
//double depth = 1.0;
|
||||
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
|
||||
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
|
||||
//R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS);
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ t1, 1.0f },
|
||||
{ t2, 1.0f },
|
||||
{ t2, 0.0f },
|
||||
{ t1, 0.0f },
|
||||
};
|
||||
|
||||
DVector2 points[2] =
|
||||
{
|
||||
line[0] * (1.0 - t1) + line[1] * t1,
|
||||
line[0] * (1.0 - t2) + line[1] * t2
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(posZ + spriteHeight * offsets[i].second);
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)offsets[i].first;
|
||||
vertices[i].v = (float)(1.0f - offsets[i].second);
|
||||
if (flipTextureX)
|
||||
vertices[i].u = 1.0f - vertices[i].u;
|
||||
}
|
||||
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
SetDynlight(thing, args);
|
||||
auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], nc), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite); args.SetStencilTestValue(stencilValue);
|
||||
if ((thing->renderflags & RF_ZDOOMTRANS) && r_UseVanillaTransparency)
|
||||
args.SetStyle(LegacyRenderStyles[STYLE_Normal], 1.0f, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
else
|
||||
args.SetStyle(thing->RenderStyle, thing->Alpha, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double floorh = ff->top.plane->ZatPoint(thingpos);
|
||||
if (floorh == thing->floorz)
|
||||
return floorh;
|
||||
}
|
||||
|
||||
if (thing->Sector->GetHeightSec())
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->floorz == thing->Sector->heightsec->floorplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->floorz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->floorplane.ZatPoint(thing) - thing->Floorclip;
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double ceilingh = ff->bottom.plane->ZatPoint(thingpos);
|
||||
if (ceilingh == thing->ceilingz)
|
||||
return ceilingh;
|
||||
}
|
||||
|
||||
if (thing->Sector->GetHeightSec())
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->ceilingz == thing->Sector->heightsec->ceilingplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->ceilingz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->ceilingplane.ZatPoint(thingpos);
|
||||
}
|
||||
|
||||
double RenderPolySprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z2)
|
||||
{
|
||||
int spriteclip = 2; // gl_spriteclip, but use 'always' mode for now
|
||||
|
||||
double z1 = z2 + spriteheight;
|
||||
|
||||
// Tests show that this doesn't look good for many decorations and corpses
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
if (!(spriteheight > 0 && spriteclip > 0 && spritetype == RF_FACESPRITE))
|
||||
return z2;
|
||||
|
||||
bool clipthing = (thing->player || thing->flags3&MF3_ISMONSTER || thing->IsKindOf(NAME_Inventory)) && (thing->flags&MF_ICECORPSE || !(thing->flags&MF_CORPSE));
|
||||
bool smarterclip = !clipthing && spriteclip == 3;
|
||||
if (clipthing || spriteclip > 1)
|
||||
{
|
||||
double diffb = MIN(z2 - GetSpriteFloorZ(thing, thingpos), 0.0);
|
||||
|
||||
// Adjust sprites clipping into ceiling and adjust clipping adjustment for tall graphics
|
||||
if (smarterclip)
|
||||
{
|
||||
// Reduce slightly clipping adjustment of corpses
|
||||
if (thing->flags & MF_CORPSE || spriteheight > fabs(diffb))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(diffb) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
diffb *= ratio;
|
||||
}
|
||||
if (!diffb)
|
||||
{
|
||||
double difft = MAX(z1 - GetSpriteCeilingZ(thing, thingpos), 0.0);
|
||||
if (difft >= (double)gl_sclipthreshold)
|
||||
{
|
||||
// dumb copy of the above.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || difft > (double)gl_sclipthreshold)
|
||||
{
|
||||
difft = 0;
|
||||
}
|
||||
}
|
||||
if (spriteheight > fabs(difft))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(difft) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
difft *= ratio;
|
||||
}
|
||||
z2 -= difft;
|
||||
}
|
||||
}
|
||||
if (diffb <= (0 - (double)gl_sclipthreshold)) // such a large displacement can't be correct!
|
||||
{
|
||||
// for living monsters standing on the floor allow a little more.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || diffb < (-1.8*(double)gl_sclipthreshold))
|
||||
{
|
||||
diffb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
z2 -= diffb;
|
||||
}
|
||||
return z2;
|
||||
}
|
||||
|
||||
bool RenderPolySprite::IsThingCulled(AActor *thing)
|
||||
{
|
||||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
double dist = (thing->Pos() - PolyRenderer::Instance()->Viewpoint.Pos).LengthSquared();
|
||||
double check = (double)**cvar;
|
||||
if (dist >= check * check)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't waste time projecting sprites that are definitely not visible.
|
||||
if (thing == nullptr ||
|
||||
(thing->renderflags & RF_INVISIBLE) ||
|
||||
!thing->RenderStyle.IsVisible(thing->Alpha) ||
|
||||
!thing->IsVisibleToPlayer())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature,
|
||||
// check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it.
|
||||
if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
(!!(thing->RenderHidden & r_renderercaps)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
FSoftwareTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
flipX = false;
|
||||
|
||||
if (thing->renderflags & RF_FLATSPRITE)
|
||||
return nullptr; // do not draw flat sprites.
|
||||
|
||||
if (thing->picnum.isValid())
|
||||
{
|
||||
FTexture *ttex = TexMan.GetPalettedTexture(thing->picnum, true);
|
||||
if (!ttex || !ttex->isValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
|
||||
if (ttex->GetRotations() != 0xFFFF)
|
||||
{
|
||||
// choose a different rotation based on player view
|
||||
spriteframe_t *sprframe = &SpriteFrames[ttex->GetRotations()];
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
DAngle ang = (pos - viewpoint.Pos).Angle();
|
||||
angle_t rot;
|
||||
if (sprframe->Texture[0] == sprframe->Texture[1])
|
||||
{
|
||||
rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28;
|
||||
}
|
||||
else
|
||||
{
|
||||
rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||
}
|
||||
flipX = (sprframe->Flip & (1 << rot)) != 0;
|
||||
ttex = TexMan.GetPalettedTexture(sprframe->Texture[rot], false); // Do not animate the rotation
|
||||
tex = ttex->GetSoftwareTexture();
|
||||
if (!ttex || !ttex->isValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// decide which texture to use for the sprite
|
||||
int spritenum = thing->sprite;
|
||||
if (spritenum >= (signed)sprites.Size() || spritenum < 0)
|
||||
return nullptr;
|
||||
|
||||
spritedef_t *sprdef = &sprites[spritenum];
|
||||
if (thing->frame >= sprdef->numframes)
|
||||
{
|
||||
// If there are no frames at all for this sprite, don't draw it.
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
|
||||
// choose a different rotation based on player view
|
||||
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
DAngle ang = (pos - viewpoint.Pos).Angle();
|
||||
|
||||
DAngle sprangle = thing->GetSpriteAngle((pos - viewpoint.Pos).Angle(), viewpoint.TicFrac);
|
||||
FTextureID tex = sprdef->GetSpriteFrame(thing->frame, -1, sprangle, &flipX);
|
||||
if (!tex.isValid()) return nullptr;
|
||||
return TexMan.GetPalettedTexture(tex, false)->GetSoftwareTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolySprite::SetDynlight(AActor *thing, PolyDrawArgs &args)
|
||||
{
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
if (fullbrightSprite || !r_dynlights)
|
||||
{
|
||||
args.SetDynLightColor(0);
|
||||
return;
|
||||
}
|
||||
|
||||
float lit_red = 0;
|
||||
float lit_green = 0;
|
||||
float lit_blue = 0;
|
||||
auto node = thing->section->lighthead;
|
||||
while (node != nullptr)
|
||||
{
|
||||
FDynamicLight *light = node->lightsource;
|
||||
if (light->ShouldLightActor(thing))
|
||||
{
|
||||
float lx = (float)(light->X() - thing->X());
|
||||
float ly = (float)(light->Y() - thing->Y());
|
||||
float lz = (float)(light->Z() - thing->Center());
|
||||
float LdotL = lx * lx + ly * ly + lz * lz;
|
||||
float radius = node->lightsource->GetRadius();
|
||||
if (radius * radius >= LdotL)
|
||||
{
|
||||
float distance = sqrt(LdotL);
|
||||
float attenuation = 1.0f - distance / radius;
|
||||
if (attenuation > 0.0f)
|
||||
{
|
||||
float red = light->GetRed() * (1.0f / 255.0f);
|
||||
float green = light->GetGreen() * (1.0f / 255.0f);
|
||||
float blue = light->GetBlue() * (1.0f / 255.0f);
|
||||
/*if (light->IsSubtractive())
|
||||
{
|
||||
float bright = FVector3(lr, lg, lb).Length();
|
||||
FVector3 lightColor(lr, lg, lb);
|
||||
red = (bright - lr) * -1;
|
||||
green = (bright - lg) * -1;
|
||||
blue = (bright - lb) * -1;
|
||||
}*/
|
||||
|
||||
lit_red += red * attenuation;
|
||||
lit_green += green * attenuation;
|
||||
lit_blue += blue * attenuation;
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
lit_red = clamp(lit_red * 255.0f, 0.0f, 255.0f);
|
||||
lit_green = clamp(lit_green * 255.0f, 0.0f, 255.0f);
|
||||
lit_blue = clamp(lit_blue * 255.0f, 0.0f, 255.0f);
|
||||
args.SetDynLightColor((((uint32_t)lit_red) << 16) | (((uint32_t)lit_green) << 8) | ((uint32_t)lit_blue));
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolySprite
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2);
|
||||
|
||||
static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right);
|
||||
static bool IsThingCulled(AActor *thing);
|
||||
static FSoftwareTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
|
||||
|
||||
private:
|
||||
static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z);
|
||||
static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos);
|
||||
static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos);
|
||||
static void SetDynlight(AActor *thing, PolyDrawArgs &args);
|
||||
};
|
||||
|
||||
class PolyTranslucentThing : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentThing(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, dist), thing(thing), sub(sub), SpriteLeft(t1), SpriteRight(t2), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
if ((thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
|
||||
{
|
||||
RenderPolyWallSprite wallspr;
|
||||
wallspr.Render(thread, thing, sub, StencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolySprite spr;
|
||||
spr.Render(thread, thing, sub, StencilValue + 1, SpriteLeft, SpriteRight);
|
||||
}
|
||||
}
|
||||
|
||||
AActor *thing = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
float SpriteLeft = 0.0f;
|
||||
float SpriteRight = 1.0f;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
|
@ -1,721 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomdata.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_wall.h"
|
||||
#include "poly_decal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "a_dynlight.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawmirrors)
|
||||
EXTERN_CVAR(Bool, r_fogboundary)
|
||||
|
||||
bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, size_t linePortalsStart, line_t *portalEnterLine)
|
||||
{
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
PolyDrawLinePortal *polyportal = nullptr;
|
||||
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
|
||||
{
|
||||
if (portalEnterLine == line->linedef)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
|
||||
polyportal = linePortals.back().get();
|
||||
}
|
||||
else if (line->linedef && line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0])
|
||||
{
|
||||
if (portalEnterLine == line->linedef)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FLinePortal *portal = line->linedef->getPortal();
|
||||
for (size_t i = linePortalsStart; i < linePortals.size(); i++)
|
||||
{
|
||||
if (linePortals[i]->Portal == portal) // To do: what other criteria do we need to check for?
|
||||
{
|
||||
polyportal = linePortals[i].get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polyportal)
|
||||
{
|
||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
|
||||
polyportal = linePortals.back().get();
|
||||
}
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
wall.LineSeg = line;
|
||||
wall.Line = line->linedef;
|
||||
wall.Side = line->sidedef;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Masked = false;
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
wall.StencilValue = stencilValue;
|
||||
wall.SectorLightLevel = frontsector->lightlevel;
|
||||
|
||||
if (line->backsector == nullptr)
|
||||
{
|
||||
if (line->sidedef)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(thread);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (line->PartnerSeg && line->PartnerSeg->Subsector)
|
||||
{
|
||||
PolyTransferHeights fakeback(line->PartnerSeg->Subsector);
|
||||
sector_t *backsector = fakeback.FrontSector;
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MAX(MIN(backceilz1, frontceilz1), frontfloorz1);
|
||||
double topfloorz2 = MAX(MIN(backceilz2, frontceilz2), frontfloorz2);
|
||||
double bottomceilz1 = MIN(MAX(frontfloorz1, backfloorz1), frontceilz1);
|
||||
double bottomceilz2 = MIN(MAX(frontfloorz2, backfloorz2), frontceilz2);
|
||||
double bottomfloorz1 = frontfloorz1;
|
||||
double bottomfloorz2 = frontfloorz2;
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
bool bothSkyFloor = frontsector->GetTexture(sector_t::floor) == skyflatnum && backsector->GetTexture(sector_t::floor) == skyflatnum;
|
||||
|
||||
if ((topceilz1 > topfloorz1 || topceilz2 > topfloorz2) && line->sidedef && !bothSkyCeiling)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), topceilz1, topfloorz1, topceilz2, topfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2));
|
||||
wall.Wallpart = side_t::top;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::top);
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef && !bothSkyFloor)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), bottomceilz1, bottomfloorz1, bottomceilz2, bottomfloorz2);
|
||||
wall.TopTexZ = MAX(MAX(frontfloorz1, backfloorz1), MAX(frontfloorz2, backfloorz2));
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.UnpeggedCeil1 = topceilz1;
|
||||
wall.UnpeggedCeil2 = topceilz2;
|
||||
wall.Wallpart = side_t::bottom;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::bottom);
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
if (line->sidedef)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), middleceilz1, middlefloorz1, middleceilz2, middlefloorz2);
|
||||
wall.TopTexZ = MAX(middleceilz1, middleceilz2);
|
||||
wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2);
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Masked = true;
|
||||
wall.Additive = !!(wall.Line->flags & ML_ADDTRANS);
|
||||
wall.Alpha = wall.Line->alpha;
|
||||
wall.FogBoundary = IsFogBoundary(frontsector, backsector);
|
||||
|
||||
FTexture *midtex = TexMan.GetPalettedTexture(line->sidedef->GetTexture(side_t::mid), true);
|
||||
if ((midtex && midtex->isValid()) || wall.FogBoundary)
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
|
||||
if (polyportal)
|
||||
{
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
return polyportal != nullptr;
|
||||
}
|
||||
|
||||
bool RenderPolyWall::IsFogBoundary(sector_t *front, sector_t *back)
|
||||
{
|
||||
return r_fogboundary && PolyCameraLight::Instance()->FixedColormap() == nullptr && front->Colormap.FadeColor &&
|
||||
front->Colormap.FadeColor != back->Colormap.FadeColor &&
|
||||
(front->GetTexture(sector_t::ceiling) != skyflatnum || back->GetTexture(sector_t::ceiling) != skyflatnum);
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
|
||||
{
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) return;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) return;
|
||||
if (!fakeFloor->model) return;
|
||||
if (fakeFloor->alpha == 0) return;
|
||||
|
||||
double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
|
||||
double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);
|
||||
double frontceilz2 = fakeFloor->top.plane->ZatPoint(line->v2);
|
||||
double frontfloorz2 = fakeFloor->bottom.plane->ZatPoint(line->v2);
|
||||
double topTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
if (frontceilz1 <= frontfloorz1 || frontceilz2 <= frontfloorz2)
|
||||
return;
|
||||
|
||||
if (fakeFloor->flags & FF_SWIMMABLE) // Only draw swimmable boundary if not swimmable on both sides
|
||||
{
|
||||
DVector2 c = (line->v1->fPos() + line->v2->fPos()) * 0.5;
|
||||
double cz = (frontceilz1 + frontceilz2 + frontfloorz1 + frontfloorz2) * 0.25;
|
||||
for (unsigned i = 0; i < frontsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *frontFloor = frontsector->e->XFloor.ffloors[i];
|
||||
if (!(frontFloor->flags & FF_EXISTS)) continue;
|
||||
if (!(frontFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (!frontFloor->model) continue;
|
||||
if (frontFloor->alpha == 0) continue;
|
||||
if (frontFloor->top.plane->ZatPoint(c) >= cz && frontFloor->bottom.plane->ZatPoint(c) <= cz && (frontFloor->flags & FF_SWIMMABLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
wall.LineSeg = line;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Line = fakeFloor->master;
|
||||
wall.Side = fakeFloor->master->sidedef[0];
|
||||
wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!wall.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
wall.Masked = false;
|
||||
wall.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wall.Masked = true;
|
||||
wall.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
wall.StencilValue = stencilValue;
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
if (fakeFloor->flags & FF_UPPERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top);
|
||||
else if (fakeFloor->flags & FF_LOWERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::bottom);
|
||||
else
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
|
||||
if (frontsector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(frontsector, fakeFloor->top.plane, true);
|
||||
wall.Colormap = GetColorTable(light->extra_colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.SectorLightLevel = *light->p_lightlevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
wall.SectorLightLevel = frontsector->lightlevel;
|
||||
}
|
||||
|
||||
if (!wall.Masked)
|
||||
wall.Render(thread);
|
||||
else
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
}
|
||||
|
||||
void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2)
|
||||
{
|
||||
this->v1 = v1;
|
||||
this->v2 = v2;
|
||||
this->ceil1 = ceil1;
|
||||
this->floor1 = floor1;
|
||||
this->ceil2 = ceil2;
|
||||
this->floor2 = floor2;
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render(PolyRenderThread *thread)
|
||||
{
|
||||
bool foggy = false;
|
||||
if (!Texture && !Polyportal && !FogBoundary)
|
||||
return;
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
vertices[0].x = (float)v1.X;
|
||||
vertices[0].y = (float)v1.Y;
|
||||
vertices[0].z = (float)ceil1;
|
||||
vertices[0].w = 1.0f;
|
||||
|
||||
vertices[1].x = (float)v2.X;
|
||||
vertices[1].y = (float)v2.Y;
|
||||
vertices[1].z = (float)ceil2;
|
||||
vertices[1].w = 1.0f;
|
||||
|
||||
vertices[2].x = (float)v2.X;
|
||||
vertices[2].y = (float)v2.Y;
|
||||
vertices[2].z = (float)floor2;
|
||||
vertices[2].w = 1.0f;
|
||||
|
||||
vertices[3].x = (float)v1.X;
|
||||
vertices[3].y = (float)v1.Y;
|
||||
vertices[3].z = (float)floor1;
|
||||
vertices[3].w = 1.0f;
|
||||
|
||||
if (Texture)
|
||||
{
|
||||
PolyWallTextureCoordsU texcoordsU(Texture, LineSeg, LineSegLine, Side, Wallpart);
|
||||
PolyWallTextureCoordsV texcoordsVLeft(Texture, Line, Side, Wallpart, ceil1, floor1, UnpeggedCeil1, TopTexZ, BottomTexZ);
|
||||
PolyWallTextureCoordsV texcoordsVRght(Texture, Line, Side, Wallpart, ceil2, floor2, UnpeggedCeil2, TopTexZ, BottomTexZ);
|
||||
vertices[0].u = (float)texcoordsU.u1;
|
||||
vertices[0].v = (float)texcoordsVLeft.v1;
|
||||
vertices[1].u = (float)texcoordsU.u2;
|
||||
vertices[1].v = (float)texcoordsVRght.v1;
|
||||
vertices[2].u = (float)texcoordsU.u2;
|
||||
vertices[2].v = (float)texcoordsVRght.v2;
|
||||
vertices[3].u = (float)texcoordsU.u1;
|
||||
vertices[3].v = (float)texcoordsVLeft.v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].u = 0.0f;
|
||||
vertices[i].v = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Masked walls clamp to the 0-1 range (no texture repeat)
|
||||
if (Masked)
|
||||
{
|
||||
bool wrap = (Line->flags & ML_WRAP_MIDTEX) || (Side->Flags & WALLF_WRAP_MIDTEX);
|
||||
if (!wrap)
|
||||
{
|
||||
ClampHeight(vertices[0], vertices[3]);
|
||||
ClampHeight(vertices[1], vertices[2]);
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(Colormap, GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
if (Texture && !Polyportal)
|
||||
args.SetTexture(Texture, DefaultRenderStyle());
|
||||
|
||||
SetDynLights(thread, args);
|
||||
|
||||
if (FogBoundary)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue + 1);
|
||||
args.SetStyle(TriBlendMode::FogBoundary);
|
||||
args.SetColor(0xffffffff, 254);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
if (!Texture)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Polyportal)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetWriteStencil(true, Polyportal->StencilValue);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
Polyportal->Shape.push_back({ vertices, 4 });
|
||||
}
|
||||
else if (!Masked)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetWriteStencil(true, StencilValue + 1);
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
else
|
||||
{
|
||||
double a = MIN(Alpha, 1.0);
|
||||
if (Additive)
|
||||
args.SetStyle(TriBlendMode::Add, a);
|
||||
else if (a < 1.0)
|
||||
args.SetStyle(TriBlendMode::Translucent, a);
|
||||
else
|
||||
args.SetStyle(TriBlendMode::Normal);
|
||||
|
||||
args.SetStencilTestValue(StencilValue + 1);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
|
||||
RenderPolyDecal::RenderWallDecals(thread, LineSeg, StencilValue + 1);
|
||||
}
|
||||
|
||||
void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args)
|
||||
{
|
||||
if (!r_dynlights)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FLightNode *light_list = (LineSeg && LineSeg->sidedef) ? LineSeg->sidedef->lighthead : nullptr;
|
||||
|
||||
auto cameraLight = PolyCameraLight::Instance();
|
||||
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
|
||||
{
|
||||
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate max lights that can touch the wall so we can allocate memory for the list
|
||||
int max_lights = 0;
|
||||
FLightNode *cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
max_lights++;
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
if (max_lights == 0)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int dc_num_lights = 0;
|
||||
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
|
||||
|
||||
// Setup lights
|
||||
cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
{
|
||||
bool is_point_light = cur_node->lightsource->IsAttenuated();
|
||||
|
||||
// To do: cull lights not touching wall
|
||||
|
||||
uint32_t red = cur_node->lightsource->GetRed();
|
||||
uint32_t green = cur_node->lightsource->GetGreen();
|
||||
uint32_t blue = cur_node->lightsource->GetBlue();
|
||||
|
||||
auto &light = dc_lights[dc_num_lights++];
|
||||
light.x = (float)cur_node->lightsource->X();
|
||||
light.y = (float)cur_node->lightsource->Y();
|
||||
light.z = (float)cur_node->lightsource->Z();
|
||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
args.SetLights(dc_lights, dc_num_lights);
|
||||
|
||||
// Face normal:
|
||||
float dx = (float)(v2.X - v1.X);
|
||||
float dy = (float)(v2.Y - v1.Y);
|
||||
float nx = dy;
|
||||
float ny = -dx;
|
||||
float lensqr = nx * nx + ny * ny;
|
||||
float rcplen = 1.0f / sqrt(lensqr);
|
||||
nx *= rcplen;
|
||||
ny *= rcplen;
|
||||
args.SetNormal({ nx, ny, 0.0f });
|
||||
}
|
||||
|
||||
void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices)
|
||||
{
|
||||
const auto &lightlist = Line->frontsector->e->XFloor.lightlist;
|
||||
if (lightlist.Size() > 0)
|
||||
{
|
||||
PolyClipPlane topPlane;
|
||||
|
||||
for (unsigned int i = 0; i < lightlist.Size(); i++)
|
||||
{
|
||||
lightlist_t *lit = &lightlist[i];
|
||||
|
||||
DVector3 normal = lit->plane.Normal();
|
||||
double d = lit->plane.fD();
|
||||
if (normal.Z < 0.0)
|
||||
{
|
||||
normal = -normal;
|
||||
d = -d;
|
||||
}
|
||||
|
||||
PolyClipPlane bottomPlane = { (float)normal.X, (float)normal.Y, (float)normal.Z, (float)d };
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, bottomPlane);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
FDynamicColormap *basecolormap = GetColorTable(lit->extra_colormap, Line->frontsector->SpecialColors[sector_t::walltop]);
|
||||
|
||||
bool foggy = false;
|
||||
int lightlevel;
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
lightlevel = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(Side->GetLightLevel(foggy, *lit->p_lightlevel) + actualextralight, 0, 255);
|
||||
}
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
|
||||
topPlane = { (float)-normal.X, (float)-normal.Y, (float)-normal.Z, (float)-d };
|
||||
}
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, PolyClipPlane());
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2)
|
||||
{
|
||||
float top = v1.z;
|
||||
float bottom = v2.z;
|
||||
float texv1 = v1.v;
|
||||
float texv2 = v2.v;
|
||||
float delta = (texv2 - texv1);
|
||||
|
||||
float t1 = texv1 < 0.0f ? -texv1 / delta : 0.0f;
|
||||
float t2 = texv2 > 1.0f ? (1.0f - texv1) / delta : 1.0f;
|
||||
float inv_t1 = 1.0f - t1;
|
||||
float inv_t2 = 1.0f - t2;
|
||||
|
||||
v1.z = top * inv_t1 + bottom * t1;
|
||||
v1.v = texv1 * inv_t1 + texv2 * t1;
|
||||
|
||||
v2.z = top * inv_t2 + bottom * t2;
|
||||
v2.v = texv1 * inv_t2 + texv2 * t2;
|
||||
}
|
||||
|
||||
FSoftwareTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
||||
{
|
||||
FTexture *tex = TexMan.GetPalettedTexture(side->GetTexture(texpart), true);
|
||||
if (tex == nullptr || !tex->isValid())
|
||||
{
|
||||
// Mapping error. Doom floodfills this with a plane.
|
||||
// This code doesn't do that, but at least it uses the "right" texture..
|
||||
|
||||
if (line && line->backsector && line->sidedef[0] == side)
|
||||
{
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
if (line && line->backsector && line->sidedef[1] == side)
|
||||
{
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
|
||||
if (tex == nullptr || !tex->isValid())
|
||||
return nullptr;
|
||||
}
|
||||
return tex? tex->GetSoftwareTexture() : nullptr;
|
||||
}
|
||||
|
||||
int RenderPolyWall::GetLightLevel()
|
||||
{
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
return clamp(Side->GetLightLevel(foggy, SectorLightLevel) + actualextralight, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart wallpart)
|
||||
{
|
||||
// Calculate the U texture coordinate for the line
|
||||
double lineu1 = side->GetTextureXOffset(wallpart);
|
||||
double lineu2 = side->GetTextureXOffset(wallpart) + line->sidedef[0]->TexelLength * side->GetTextureXScale(wallpart);
|
||||
lineu1 *= tex->GetScale().X / tex->GetWidth();
|
||||
lineu2 *= tex->GetScale().X / tex->GetWidth();
|
||||
|
||||
// Calculate where we are on the lineseg
|
||||
double t1, t2;
|
||||
if (fabs(line->delta.X) > fabs(line->delta.Y))
|
||||
{
|
||||
t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X;
|
||||
t2 = (lineseg->v2->fX() - line->v1->fX()) / line->delta.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = (lineseg->v1->fY() - line->v1->fY()) / line->delta.Y;
|
||||
t2 = (lineseg->v2->fY() - line->v1->fY()) / line->delta.Y;
|
||||
}
|
||||
|
||||
// Check if lineseg is the backside of the line
|
||||
if (t2 < t1)
|
||||
{
|
||||
std::swap(lineu1, lineu2);
|
||||
}
|
||||
|
||||
// Calculate texture coordinates for the lineseg
|
||||
u1 = (1.0 - t1) * lineu1 + t1 * lineu2;
|
||||
u2 = (1.0 - t2) * lineu1 + t2 * lineu2;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsV::PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ)
|
||||
{
|
||||
double yoffset = side->GetTextureYOffset(wallpart);
|
||||
if (tex->useWorldPanning(line->GetLevel()))
|
||||
yoffset *= side->GetTextureYScale(wallpart) * tex->GetScale().Y;
|
||||
|
||||
switch (wallpart)
|
||||
{
|
||||
default:
|
||||
case side_t::mid:
|
||||
CalcVMidPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::top:
|
||||
CalcVTopPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::bottom:
|
||||
CalcVBottomPart(tex, line, side, topTexZ, bottomTexZ, unpeggedceil, yoffset);
|
||||
break;
|
||||
}
|
||||
|
||||
v1 *= tex->GetScale().Y / tex->GetHeight();
|
||||
v2 *= tex->GetScale().Y / tex->GetHeight();
|
||||
|
||||
double texZHeight = (bottomTexZ - topTexZ);
|
||||
if (texZHeight > 0.0f || texZHeight < -0.0f)
|
||||
{
|
||||
double t1 = (topz - topTexZ) / texZHeight;
|
||||
double t2 = (bottomz - topTexZ) / texZHeight;
|
||||
double vorig1 = v1;
|
||||
double vorig2 = v2;
|
||||
v1 = vorig1 * (1.0f - t1) + vorig2 * t1;
|
||||
v2 = vorig1 * (1.0f - t2) + vorig2 * t2;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGTOP) == 0;
|
||||
if (pegged) // bottom to top
|
||||
{
|
||||
double texHeight = tex->GetHeight() / tex->GetScale().Y;
|
||||
v1 = (topz - bottomz) * side->GetTextureYScale(side_t::top) - yoffset;
|
||||
v2 = -yoffset;
|
||||
v1 = texHeight - v1;
|
||||
v2 = texHeight - v2;
|
||||
}
|
||||
else // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::top) + yoffset;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::mid) + yoffset;
|
||||
}
|
||||
else // bottom to top
|
||||
{
|
||||
double texHeight = tex->GetHeight() / tex->GetScale().Y;
|
||||
v1 = yoffset - (topz - bottomz) * side->GetTextureYScale(side_t::mid);
|
||||
v2 = yoffset;
|
||||
v1 = texHeight + v1;
|
||||
v2 = texHeight + v2;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = yoffset + (topz - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = yoffset + (unpeggedceil - topz) * side->GetTextureYScale(side_t::bottom);
|
||||
v2 = yoffset + (unpeggedceil - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolyTranslucentObject;
|
||||
class PolyDrawLinePortal;
|
||||
class PolyCull;
|
||||
|
||||
class RenderPolyWall
|
||||
{
|
||||
public:
|
||||
static bool RenderLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, size_t linePortalsStart, line_t *portalEnterLine);
|
||||
static void Render3DFloorLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
||||
|
||||
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
||||
void Render(PolyRenderThread *thread);
|
||||
|
||||
DVector2 v1;
|
||||
DVector2 v2;
|
||||
double ceil1 = 0.0;
|
||||
double floor1 = 0.0;
|
||||
double ceil2 = 0.0;
|
||||
double floor2 = 0.0;
|
||||
|
||||
const seg_t *LineSeg = nullptr;
|
||||
const line_t *LineSegLine = nullptr;
|
||||
const line_t *Line = nullptr;
|
||||
const side_t *Side = nullptr;
|
||||
FSoftwareTexture *Texture = nullptr;
|
||||
side_t::ETexpart Wallpart = side_t::mid;
|
||||
double TopTexZ = 0.0;
|
||||
double BottomTexZ = 0.0;
|
||||
double UnpeggedCeil1 = 0.0;
|
||||
double UnpeggedCeil2 = 0.0;
|
||||
FSWColormap *Colormap = nullptr;
|
||||
int SectorLightLevel = 0;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
bool FogBoundary = false;
|
||||
uint32_t SubsectorDepth = 0;
|
||||
uint32_t StencilValue = 0;
|
||||
PolyDrawLinePortal *Polyportal = nullptr;
|
||||
|
||||
private:
|
||||
void ClampHeight(TriVertex &v1, TriVertex &v2);
|
||||
int GetLightLevel();
|
||||
void DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices);
|
||||
|
||||
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args);
|
||||
|
||||
static bool IsFogBoundary(sector_t *front, sector_t *back);
|
||||
static FSoftwareTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart);
|
||||
};
|
||||
|
||||
class PolyWallTextureCoordsU
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *linesegline, const side_t *side, side_t::ETexpart wallpart);
|
||||
|
||||
double u1, u2;
|
||||
};
|
||||
|
||||
class PolyWallTextureCoordsV
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ);
|
||||
|
||||
double v1, v2;
|
||||
|
||||
private:
|
||||
void CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset);
|
||||
};
|
||||
|
||||
class PolyTranslucentWall : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentWall(RenderPolyWall wall) : PolyTranslucentObject(wall.SubsectorDepth, 1e6), wall(wall) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
};
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_wallsprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
void RenderPolyWallSprite::Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
if (RenderPolySprite::IsThingCulled(thing))
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return;
|
||||
|
||||
DVector2 spriteScale = thing->Scale;
|
||||
double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
double thingyscalemul = spriteScale.Y / tex->GetScale().Y;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
DAngle ang = thing->Angles.Yaw + 90;
|
||||
double angcos = ang.Cos();
|
||||
double angsin = ang.Sin();
|
||||
|
||||
// Determine left and right edges of sprite. The sprite's angle is its normal,
|
||||
// so the edges are 90 degrees each side of it.
|
||||
double x2 = tex->GetScaledWidth() * spriteScale.X;
|
||||
double x1 = tex->GetScaledLeftOffsetPo() * spriteScale.X;
|
||||
DVector2 left, right;
|
||||
left.X = pos.X - x1 * angcos;
|
||||
left.Y = pos.Y - x1 * angsin;
|
||||
right.X = left.X + x2 * angcos;
|
||||
right.Y = left.Y + x2 * angsin;
|
||||
|
||||
//int scaled_to = tex->GetScaledTopOffset();
|
||||
//int scaled_bo = scaled_to - tex->GetScaledHeight();
|
||||
//gzt = pos.Z + scale.Y * scaled_to;
|
||||
//gzb = pos.Z + scale.Y * scaled_bo;
|
||||
|
||||
DVector2 points[2] = { left, right };
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second);
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)(offsets[i].first * tex->GetScale().X);
|
||||
vertices[i].v = (float)((1.0f - offsets[i].second) * tex->GetScale().Y);
|
||||
if (flipTextureX)
|
||||
vertices[i].u = 1.0f - vertices[i].u;
|
||||
}
|
||||
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], nc), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite); args.SetStencilTestValue(stencilValue);
|
||||
args.SetTexture(tex, thing->RenderStyle);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetStyle(TriBlendMode::Normal);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolyWallSprite
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue);
|
||||
};
|
|
@ -52,6 +52,7 @@
|
|||
#include "r_thread.h"
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
#include "playsim/a_dynlight.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, r_fuzzscale, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
@ -471,9 +472,9 @@ namespace swrenderer
|
|||
}
|
||||
count = args.Count();
|
||||
|
||||
auto zbuffer = PolyZBuffer::Instance();
|
||||
int pitch = PolyStencilBuffer::Instance()->Width();
|
||||
float* values = zbuffer->Values() + y * pitch + x;
|
||||
auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float* values = zbuffer->DepthValues() + y * pitch + x;
|
||||
int cnt = count;
|
||||
|
||||
values = thread->dest_for_thread(y, pitch, values);
|
||||
|
@ -583,9 +584,9 @@ namespace swrenderer
|
|||
|
||||
void Execute(DrawerThread *thread) override
|
||||
{
|
||||
auto zbuffer = PolyZBuffer::Instance();
|
||||
int pitch = PolyStencilBuffer::Instance()->Width();
|
||||
float *values = zbuffer->Values() + y * pitch + x;
|
||||
auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float *values = zbuffer->DepthValues() + y * pitch + x;
|
||||
int cnt = count;
|
||||
|
||||
values = thread->dest_for_thread(y, pitch, values);
|
||||
|
@ -625,9 +626,9 @@ namespace swrenderer
|
|||
if (thread->skipped_by_thread(y))
|
||||
return;
|
||||
|
||||
auto zbuffer = PolyZBuffer::Instance();
|
||||
int pitch = PolyStencilBuffer::Instance()->Width();
|
||||
float *values = zbuffer->Values() + y * pitch;
|
||||
auto zbuffer = PolyTriangleThreadData::Get(thread)->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float *values = zbuffer->DepthValues() + y * pitch;
|
||||
int end = x2;
|
||||
|
||||
if (idepth1 == idepth2)
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "r_thread.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "swrenderer/r_renderthread.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <chrono>
|
||||
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "textures/textures.h"
|
||||
#include "r_data/voxels.h"
|
||||
#include "drawers/r_draw_rgba.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "p_setup.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "image.h"
|
||||
|
@ -185,22 +184,11 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &
|
|||
|
||||
void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch)
|
||||
{
|
||||
if (V_IsPolyRenderer())
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
r_viewpoint.ViewLevel->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov)
|
||||
{
|
||||
|
@ -215,43 +203,22 @@ void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int wi
|
|||
DCanvas pic(width, height, false);
|
||||
|
||||
// Take a snapshot of the player's view
|
||||
if (V_IsPolyRenderer())
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderViewToCanvas(player->mo, &pic, 0, 0, width, height, true);
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderViewToCanvas(player->mo, &pic, 0, 0, width, height);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderViewToCanvas(player->mo, &pic, 0, 0, width, height);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
DoWriteSavePic(file, SS_PAL, pic.GetPixels(), width, height, r_viewpoint.sector, false);
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::DrawRemainingPlayerSprites()
|
||||
{
|
||||
if (!V_IsPolyRenderer())
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.MainThread()->PlayerSprites->RenderRemaining();
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderRemainingPlayerSprites();
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.MainThread()->PlayerSprites->RenderRemaining();
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::SetClearColor(int color)
|
||||
|
@ -261,9 +228,9 @@ void FSoftwareRenderer::SetClearColor(int color)
|
|||
|
||||
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewpoint, double fov)
|
||||
{
|
||||
auto renderTarget = V_IsPolyRenderer() ? PolyRenderer::Instance()->RenderTarget : mScene.MainThread()->Viewport->RenderTarget;
|
||||
auto &cameraViewpoint = V_IsPolyRenderer() ? PolyRenderer::Instance()->Viewpoint : mScene.MainThread()->Viewport->viewpoint;
|
||||
auto &cameraViewwindow = V_IsPolyRenderer() ? PolyRenderer::Instance()->Viewwindow : mScene.MainThread()->Viewport->viewwindow;
|
||||
auto renderTarget = mScene.MainThread()->Viewport->RenderTarget;
|
||||
auto &cameraViewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
auto &cameraViewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
// Grab global state shared with rest of zdoom
|
||||
cameraViewpoint = r_viewpoint;
|
||||
|
@ -280,10 +247,7 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewp
|
|||
DAngle savedfov = cameraViewpoint.FieldOfView;
|
||||
R_SetFOV (cameraViewpoint, fov);
|
||||
|
||||
if (V_IsPolyRenderer())
|
||||
PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
else
|
||||
mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
|
||||
R_SetFOV (cameraViewpoint, savedfov);
|
||||
|
||||
|
|
|
@ -86,41 +86,53 @@ SWSceneDrawer::~SWSceneDrawer()
|
|||
|
||||
sector_t *SWSceneDrawer::RenderView(player_t *player)
|
||||
{
|
||||
// Avoid using the pixel buffer from the last frame
|
||||
FBTextureIndex = (FBTextureIndex + 1) % 2;
|
||||
auto &fbtex = FBTexture[FBTextureIndex];
|
||||
|
||||
if (fbtex == nullptr || fbtex->GetSystemTexture() == nullptr ||
|
||||
fbtex->GetDisplayWidth() != screen->GetWidth() ||
|
||||
fbtex->GetDisplayHeight() != screen->GetHeight() ||
|
||||
(V_IsTrueColor() ? 1:0) != fbtex->GetColorFormat())
|
||||
if (!V_IsTrueColor() || !screen->IsPoly())
|
||||
{
|
||||
// This manually constructs its own material here.
|
||||
fbtex.reset();
|
||||
fbtex.reset(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()));
|
||||
fbtex->GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1);
|
||||
auto mat = FMaterial::ValidateTexture(fbtex.get(), false);
|
||||
mat->AddTextureLayer(PaletteTexture);
|
||||
// Avoid using the pixel buffer from the last frame
|
||||
FBTextureIndex = (FBTextureIndex + 1) % 2;
|
||||
auto &fbtex = FBTexture[FBTextureIndex];
|
||||
|
||||
Canvas.reset();
|
||||
Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()));
|
||||
if (fbtex == nullptr || fbtex->GetSystemTexture() == nullptr ||
|
||||
fbtex->GetDisplayWidth() != screen->GetWidth() ||
|
||||
fbtex->GetDisplayHeight() != screen->GetHeight() ||
|
||||
(V_IsTrueColor() ? 1:0) != fbtex->GetColorFormat())
|
||||
{
|
||||
// This manually constructs its own material here.
|
||||
fbtex.reset();
|
||||
fbtex.reset(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()));
|
||||
fbtex->GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1);
|
||||
auto mat = FMaterial::ValidateTexture(fbtex.get(), false);
|
||||
mat->AddTextureLayer(PaletteTexture);
|
||||
|
||||
Canvas.reset();
|
||||
Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor()));
|
||||
}
|
||||
|
||||
IHardwareTexture *systemTexture = fbtex->GetSystemTexture();
|
||||
auto buf = systemTexture->MapBuffer();
|
||||
if (!buf) I_FatalError("Unable to map buffer for software rendering");
|
||||
SWRenderer->RenderView(player, Canvas.get(), buf, systemTexture->GetBufferPitch());
|
||||
systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer");
|
||||
|
||||
auto map = swrenderer::CameraLight::Instance()->ShaderColormap();
|
||||
screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE);
|
||||
screen->Draw2D();
|
||||
screen->Clear2D();
|
||||
screen->PostProcessScene(CM_DEFAULT, [&]() {
|
||||
SWRenderer->DrawRemainingPlayerSprites();
|
||||
screen->Draw2D();
|
||||
screen->Clear2D();
|
||||
});
|
||||
}
|
||||
|
||||
IHardwareTexture *systemTexture = fbtex->GetSystemTexture();
|
||||
auto buf = systemTexture->MapBuffer();
|
||||
if (!buf) I_FatalError("Unable to map buffer for software rendering");
|
||||
SWRenderer->RenderView(player, Canvas.get(), buf, systemTexture->GetBufferPitch());
|
||||
systemTexture->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer");
|
||||
|
||||
auto map = swrenderer::CameraLight::Instance()->ShaderColormap();
|
||||
screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE);
|
||||
screen->Draw2D();
|
||||
screen->Clear2D();
|
||||
screen->PostProcessScene(CM_DEFAULT, [&]() {
|
||||
else
|
||||
{
|
||||
DCanvas *canvas = screen->GetCanvas();
|
||||
SWRenderer->RenderView(player, canvas, canvas->GetPixels(), canvas->GetPitch());
|
||||
// To do: apply swrenderer::CameraLight::Instance()->ShaderColormap();
|
||||
SWRenderer->DrawRemainingPlayerSprites();
|
||||
screen->Draw2D();
|
||||
screen->Clear2D();
|
||||
});
|
||||
}
|
||||
|
||||
return r_viewpoint.sector;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ namespace swrenderer
|
|||
double FlatPlaneVis(int screenY, double planeheight, bool foggy, RenderViewport *viewport) const { return FlatPlaneGlobVis(foggy) / planeheight * fabs(viewport->CenterY - screenY); }
|
||||
|
||||
double SlopePlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : TiltVisibility; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy, RenderViewport *viewport) { return LightLevelToShadeImpl(viewport, lightlevel + ActualExtraLight(foggy, viewport), foggy); }
|
||||
|
||||
|
@ -93,7 +94,6 @@ namespace swrenderer
|
|||
|
||||
private:
|
||||
double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
double FlatPlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : FloorVisibility; }
|
||||
|
||||
static fixed_t LightLevelToShadeImpl(RenderViewport *viewport, int lightlevel, bool foggy);
|
||||
|
|
|
@ -107,7 +107,12 @@ namespace swrenderer
|
|||
r_modelscene = r_models && Models.Size() > 0;
|
||||
if (r_modelscene)
|
||||
{
|
||||
PolyTriangleDrawer::ResizeBuffers(viewport->RenderTarget);
|
||||
if (!DepthStencil || DepthStencil->Width() != viewport->RenderTarget->GetWidth() || DepthStencil->Height() != viewport->RenderTarget->GetHeight())
|
||||
{
|
||||
DepthStencil.reset();
|
||||
DepthStencil.reset(new PolyDepthStencil(viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight()));
|
||||
}
|
||||
PolyTriangleDrawer::SetViewport(MainThread()->DrawQueue, 0, 0, viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight(), viewport->RenderTarget, DepthStencil.get());
|
||||
PolyTriangleDrawer::ClearStencil(MainThread()->DrawQueue, 0);
|
||||
}
|
||||
|
||||
|
@ -131,9 +136,12 @@ namespace swrenderer
|
|||
|
||||
RenderActorView(player->mo, true, false);
|
||||
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(MainThread()->FrameMemory.get());
|
||||
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
if (videobuffer != target->GetPixels())
|
||||
{
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(MainThread()->FrameMemory.get());
|
||||
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
}
|
||||
|
||||
DrawerWaitCycles.Clock();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
@ -275,7 +283,8 @@ namespace swrenderer
|
|||
if (r_modelscene && thread->MainThread)
|
||||
PolyTriangleDrawer::ClearStencil(MainThread()->DrawQueue, 0);
|
||||
|
||||
PolyTriangleDrawer::SetViewport(thread->DrawQueue, viewwindowx, viewwindowy, viewwidth, viewheight, thread->Viewport->RenderTarget);
|
||||
PolyTriangleDrawer::SetViewport(thread->DrawQueue, viewwindowx, viewwindowy, viewwidth, viewheight, thread->Viewport->RenderTarget, DepthStencil.get());
|
||||
PolyTriangleDrawer::SetScissor(thread->DrawQueue, viewwindowx, viewwindowy, viewwidth, viewheight);
|
||||
|
||||
// Cull things outside the range seen by this thread
|
||||
VisibleSegmentRenderer visitor;
|
||||
|
@ -371,7 +380,13 @@ namespace swrenderer
|
|||
viewactive = true;
|
||||
viewport->SetViewport(actor->Level, MainThread(), width, height, MainThread()->Viewport->viewwindow.WidescreenRatio);
|
||||
if (r_modelscene)
|
||||
PolyTriangleDrawer::ResizeBuffers(viewport->RenderTarget);
|
||||
{
|
||||
if (!DepthStencil || DepthStencil->Width() != viewport->RenderTarget->GetWidth() || DepthStencil->Height() != viewport->RenderTarget->GetHeight())
|
||||
{
|
||||
DepthStencil.reset();
|
||||
DepthStencil.reset(new PolyDepthStencil(viewport->RenderTarget->GetWidth(), viewport->RenderTarget->GetHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
// Render:
|
||||
RenderActorView(actor, false, dontmaplines);
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
extern cycle_t FrameCycles;
|
||||
|
||||
class PolyDepthStencil;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
extern cycle_t WallCycles, PlaneCycles, MaskedCycles, DrawerWaitCycles;
|
||||
|
@ -67,6 +69,7 @@ namespace swrenderer
|
|||
bool dontmaplines = false;
|
||||
int clearcolor = 0;
|
||||
|
||||
std::unique_ptr<PolyDepthStencil> DepthStencil;
|
||||
std::vector<std::unique_ptr<RenderThread>> Threads;
|
||||
std::mutex start_mutex;
|
||||
std::condition_variable start_condition;
|
||||
|
|
|
@ -74,6 +74,7 @@ namespace swrenderer
|
|||
|
||||
void RenderModel::Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor)
|
||||
{
|
||||
#if 0
|
||||
SWModelRenderer renderer(thread, clip3DFloor, &WorldToClip, MirrorWorldToClip);
|
||||
|
||||
renderer.sector = actor->Sector;
|
||||
|
@ -83,10 +84,10 @@ namespace swrenderer
|
|||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = ((actor->renderflags & RF_FULLBRIGHT) || (actor->flags5 & MF5_BRIGHT));
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : actor->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
renderer.visibility = thread->Light->SpriteGlobVis(foggy);
|
||||
|
||||
renderer.fillcolor = actor->fillcolor;
|
||||
renderer.Translation = actor->Translation;
|
||||
|
@ -94,6 +95,7 @@ namespace swrenderer
|
|||
renderer.AddLights(actor);
|
||||
renderer.RenderModel(x, y, z, smf, actor, r_viewpoint.TicFrac);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -116,6 +118,7 @@ namespace swrenderer
|
|||
|
||||
void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy)
|
||||
{
|
||||
#if 0
|
||||
SWModelRenderer renderer(thread, Fake3DTranslucent(), &thread->Viewport->WorldToClip, false);
|
||||
|
||||
AActor *playermo = players[consoleplayer].camera;
|
||||
|
@ -128,10 +131,10 @@ namespace swrenderer
|
|||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = isBright(psp);
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
renderer.visibility = thread->Light->SpriteGlobVis(foggy);
|
||||
|
||||
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
|
@ -141,13 +144,17 @@ namespace swrenderer
|
|||
|
||||
renderer.RenderHUDModel(psp, ofsx, ofsy);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
SWModelRenderer::SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip)
|
||||
: Thread(thread), Clip3DFloor(clip3DFloor), WorldToClip(worldToClip), MirrorWorldToClip(mirrorWorldToClip)
|
||||
{
|
||||
static PolySWInputAssembly input;
|
||||
PolyTriangleDrawer::SetInputAssembly(thread->DrawQueue, &input);
|
||||
}
|
||||
|
||||
void SWModelRenderer::AddLights(AActor *actor)
|
||||
|
@ -354,7 +361,8 @@ namespace swrenderer
|
|||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite);
|
||||
args.SetLights(Lights, NumLights);
|
||||
args.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
|
@ -364,14 +372,16 @@ namespace swrenderer
|
|||
args.SetClipPlane(1, ClipTop);
|
||||
args.SetClipPlane(2, ClipBottom);
|
||||
|
||||
PolyTriangleDrawer::DrawArray(Thread->DrawQueue, args, VertexBuffer + start, count);
|
||||
PolyTriangleDrawer::PushDrawArgs(Thread->DrawQueue, args);
|
||||
PolyTriangleDrawer::Draw(Thread->DrawQueue, start, count);
|
||||
}
|
||||
|
||||
void SWModelRenderer::DrawElements(int numIndices, size_t offset)
|
||||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite);
|
||||
args.SetLights(Lights, NumLights);
|
||||
args.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
|
@ -381,7 +391,8 @@ namespace swrenderer
|
|||
args.SetClipPlane(1, ClipTop);
|
||||
args.SetClipPlane(2, ClipBottom);
|
||||
|
||||
PolyTriangleDrawer::DrawElements(Thread->DrawQueue, args, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices);
|
||||
PolyTriangleDrawer::PushDrawArgs(Thread->DrawQueue, args);
|
||||
PolyTriangleDrawer::DrawIndexed(Thread->DrawQueue, static_cast<int>(offset / sizeof(unsigned int)), numIndices);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -417,8 +428,13 @@ namespace swrenderer
|
|||
void SWModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||
{
|
||||
SWModelRenderer *swrenderer = (SWModelRenderer *)renderer;
|
||||
swrenderer->VertexBuffer = mVertexBuffer.Size() ? &mVertexBuffer[0] : nullptr;
|
||||
swrenderer->IndexBuffer = mIndexBuffer.Size() ? &mIndexBuffer[0] : nullptr;
|
||||
|
||||
if (mVertexBuffer.Size() > 0)
|
||||
PolyTriangleDrawer::SetVertexBuffer(swrenderer->Thread->DrawQueue, &mVertexBuffer[0]);
|
||||
if (mIndexBuffer.Size() > 0)
|
||||
PolyTriangleDrawer::SetIndexBuffer(swrenderer->Thread->DrawQueue, &mIndexBuffer[0]);
|
||||
|
||||
PolyTriangleDrawer::SetModelVertexShader(swrenderer->Thread->DrawQueue, frame1, frame2, swrenderer->InterpolationFactor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace swrenderer
|
|||
bool MirrorWorldToClip;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class SWModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
|
@ -90,8 +91,6 @@ namespace swrenderer
|
|||
Mat4f ObjectToWorld;
|
||||
PolyClipPlane ClipTop, ClipBottom;
|
||||
FTexture *SkinTexture = nullptr;
|
||||
unsigned int *IndexBuffer = nullptr;
|
||||
FModelVertex *VertexBuffer = nullptr;
|
||||
float InterpolationFactor = 0.0;
|
||||
Mat4f *WorldToClip = nullptr;
|
||||
bool MirrorWorldToClip = false;
|
||||
|
@ -117,4 +116,5 @@ namespace swrenderer
|
|||
TArray<FModelVertex> mVertexBuffer;
|
||||
TArray<unsigned int> mIndexBuffer;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
#include <memory>
|
||||
#include "v_video.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_utility.h"
|
||||
#include "actorinlines.h"
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
|
||||
#define MINZ double((2048*4) / double(1 << 20))
|
||||
|
||||
class PolyDepthStencil;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
class RenderThread;
|
||||
|
|
|
@ -108,12 +108,26 @@ CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN
|
|||
// No further checks needed. All this changes now is which scene drawer the render backend calls.
|
||||
}
|
||||
|
||||
CUSTOM_CVAR(Int, vid_enablevulkan, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
{
|
||||
// [SP] This may seem pointless - but I don't want to implement live switching just
|
||||
// yet - I'm pretty sure it's going to require a lot of reinits and destructions to
|
||||
// do it right without memory leaks
|
||||
|
||||
switch(self)
|
||||
{
|
||||
case 2:
|
||||
Printf("Selecting SoftPoly backend...\n");
|
||||
break;
|
||||
#ifdef HAVE_VULKAN
|
||||
case 1:
|
||||
Printf("Selecting Vulkan backend...\n");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
Printf("Selecting OpenGL backend...\n");
|
||||
}
|
||||
|
||||
Printf("Changing the video backend requires a restart for " GAMENAME ".\n");
|
||||
}
|
||||
|
||||
|
@ -202,7 +216,7 @@ DCanvas::~DCanvas ()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::Resize(int width, int height)
|
||||
void DCanvas::Resize(int width, int height, bool optimizepitch)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
@ -213,7 +227,7 @@ void DCanvas::Resize(int width, int height)
|
|||
// longer than the width. The values used here are all based on
|
||||
// empirical evidence.
|
||||
|
||||
if (width <= 640)
|
||||
if (width <= 640 || !optimizepitch)
|
||||
{
|
||||
// For low resolutions, just keep the pitch the same as the width.
|
||||
// Some speedup can be seen using the technique below, but the speedup
|
||||
|
|
|
@ -326,7 +326,7 @@ class DCanvas
|
|||
public:
|
||||
DCanvas (int width, int height, bool bgra);
|
||||
~DCanvas ();
|
||||
void Resize(int width, int height);
|
||||
void Resize(int width, int height, bool optimizepitch = true);
|
||||
|
||||
// Member variable access
|
||||
inline uint8_t *GetPixels () const { return Pixels.Data(); }
|
||||
|
@ -394,6 +394,9 @@ public:
|
|||
virtual ~DFrameBuffer();
|
||||
virtual void InitializeState() = 0; // For stuff that needs 'screen' set.
|
||||
virtual bool IsVulkan() { return false; }
|
||||
virtual bool IsPoly() { return false; }
|
||||
|
||||
virtual DCanvas* GetCanvas() { return nullptr; }
|
||||
|
||||
void SetSize(int width, int height);
|
||||
void SetVirtualSize(int width, int height)
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "m_argv.h"
|
||||
#include "version.h"
|
||||
#include "win32glvideo.h"
|
||||
#include "win32polyvideo.h"
|
||||
#ifdef HAVE_VULKAN
|
||||
#include "win32vulkanvideo.h"
|
||||
#endif
|
||||
|
@ -50,7 +51,7 @@
|
|||
#include "i_system.h"
|
||||
#include "swrenderer/r_swrenderer.h"
|
||||
|
||||
EXTERN_CVAR(Int, vid_enablevulkan)
|
||||
EXTERN_CVAR(Int, vid_preferbackend)
|
||||
|
||||
extern HWND Window;
|
||||
|
||||
|
@ -128,8 +129,12 @@ void I_InitGraphics ()
|
|||
// are the active app. Huh?
|
||||
}
|
||||
|
||||
if (vid_preferbackend == 2)
|
||||
{
|
||||
Video = new Win32PolyVideo();
|
||||
}
|
||||
#ifdef HAVE_VULKAN
|
||||
if (vid_enablevulkan == 1)
|
||||
else if (vid_preferbackend == 1)
|
||||
{
|
||||
// first try Vulkan, if that fails OpenGL
|
||||
try
|
||||
|
@ -142,12 +147,16 @@ void I_InitGraphics ()
|
|||
Video = new Win32GLVideo();
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
else
|
||||
{
|
||||
Video = new Win32GLVideo();
|
||||
}
|
||||
|
||||
if (Video == NULL)
|
||||
Video = new Win32PolyVideo();
|
||||
|
||||
// we somehow STILL don't have a display!!
|
||||
if (Video == NULL)
|
||||
I_FatalError ("Failed to initialize display");
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ EXTERN_CVAR (Bool, queryiwad);
|
|||
EXTERN_CVAR (Bool, disableautoload)
|
||||
EXTERN_CVAR (Bool, autoloadlights)
|
||||
EXTERN_CVAR (Bool, autoloadbrightmaps)
|
||||
EXTERN_CVAR (Int, vid_enablevulkan)
|
||||
EXTERN_CVAR (Int, vid_preferbackend)
|
||||
|
||||
extern HWND Window, ConWindow, GameTitleWindow;
|
||||
extern HANDLE StdOut;
|
||||
|
@ -589,7 +589,7 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
|
|||
// Check the current video settings.
|
||||
//SendDlgItemMessage( hDlg, vid_renderer ? IDC_WELCOME_OPENGL : IDC_WELCOME_SOFTWARE, BM_SETCHECK, BST_CHECKED, 0 );
|
||||
SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_SETCHECK, fullscreen ? BST_CHECKED : BST_UNCHECKED, 0 );
|
||||
SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN, BM_SETCHECK, vid_enablevulkan ? BST_CHECKED : BST_UNCHECKED, 0 );
|
||||
SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN, BM_SETCHECK, (vid_preferbackend == 1) ? BST_CHECKED : BST_UNCHECKED, 0 );
|
||||
|
||||
// [SP] This is our's
|
||||
SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_SETCHECK, disableautoload ? BST_CHECKED : BST_UNCHECKED, 0 );
|
||||
|
@ -635,7 +635,8 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
|
|||
SetQueryIWad(hDlg);
|
||||
// [SP] Upstreamed from Zandronum
|
||||
fullscreen = SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_GETCHECK, 0, 0 ) == BST_CHECKED;
|
||||
vid_enablevulkan = SendDlgItemMessage( hDlg, IDC_WELCOME_VULKAN, BM_GETCHECK, 0, 0 ) == BST_CHECKED;
|
||||
if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN, BM_GETCHECK, 0, 0) == BST_CHECKED) vid_preferbackend = 1;
|
||||
else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN, BM_GETCHECK, 0, 0) != BST_CHECKED && vid_preferbackend == 1) vid_preferbackend = 0;
|
||||
|
||||
// [SP] This is our's.
|
||||
disableautoload = SendDlgItemMessage( hDlg, IDC_WELCOME_NOAUTOLOAD, BM_GETCHECK, 0, 0 ) == BST_CHECKED;
|
||||
|
|
186
src/win32/win32polyvideo.cpp
Normal file
186
src/win32/win32polyvideo.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include "hardware.h"
|
||||
#include "doomerrors.h"
|
||||
#include <Windows.h>
|
||||
|
||||
EXTERN_CVAR(Bool, vid_vsync)
|
||||
|
||||
extern HWND Window;
|
||||
|
||||
#include <d3d9.h>
|
||||
#pragma comment(lib, "d3d9.lib")
|
||||
|
||||
namespace
|
||||
{
|
||||
int SrcWidth = 0;
|
||||
int SrcHeight = 0;
|
||||
int ClientWidth = 0;
|
||||
int ClientHeight = 0;
|
||||
bool CurrentVSync = false;
|
||||
|
||||
IDirect3D9Ex *d3d9 = nullptr;
|
||||
IDirect3DDevice9Ex *device = nullptr;
|
||||
IDirect3DSurface9* surface = nullptr;
|
||||
}
|
||||
|
||||
void I_PolyPresentInit()
|
||||
{
|
||||
Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9);
|
||||
if (!d3d9)
|
||||
{
|
||||
I_FatalError("Direct3DCreate9 failed");
|
||||
}
|
||||
|
||||
RECT rect = {};
|
||||
GetClientRect(Window, &rect);
|
||||
|
||||
ClientWidth = rect.right;
|
||||
ClientHeight = rect.bottom;
|
||||
|
||||
D3DPRESENT_PARAMETERS pp = {};
|
||||
pp.Windowed = true;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_FLIPEX;
|
||||
pp.BackBufferWidth = ClientWidth;
|
||||
pp.BackBufferHeight = ClientHeight;
|
||||
pp.BackBufferCount = 1;
|
||||
pp.hDeviceWindow = Window;
|
||||
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
|
||||
HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, nullptr, &device);
|
||||
if (FAILED(result))
|
||||
{
|
||||
I_FatalError("IDirect3D9.CreateDevice failed");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
RECT rect = {};
|
||||
GetClientRect(Window, &rect);
|
||||
if (rect.right != ClientWidth || rect.bottom != ClientHeight || CurrentVSync != vsync)
|
||||
{
|
||||
if (surface)
|
||||
{
|
||||
surface->Release();
|
||||
surface = nullptr;
|
||||
}
|
||||
|
||||
CurrentVSync = vsync;
|
||||
ClientWidth = rect.right;
|
||||
ClientHeight = rect.bottom;
|
||||
|
||||
D3DPRESENT_PARAMETERS pp = {};
|
||||
pp.Windowed = true;
|
||||
pp.SwapEffect = D3DSWAPEFFECT_FLIPEX;
|
||||
pp.BackBufferWidth = ClientWidth;
|
||||
pp.BackBufferHeight = ClientHeight;
|
||||
pp.BackBufferCount = 1;
|
||||
pp.hDeviceWindow = Window;
|
||||
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
device->Reset(&pp);
|
||||
}
|
||||
|
||||
if (SrcWidth != w || SrcHeight != h || !surface)
|
||||
{
|
||||
if (surface)
|
||||
{
|
||||
surface->Release();
|
||||
surface = nullptr;
|
||||
}
|
||||
|
||||
SrcWidth = w;
|
||||
SrcHeight = h;
|
||||
result = device->CreateOffscreenPlainSurface(SrcWidth, SrcHeight, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &surface, 0);
|
||||
if (FAILED(result))
|
||||
{
|
||||
I_FatalError("IDirect3DDevice9.CreateOffscreenPlainSurface failed");
|
||||
}
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT lockrect = {};
|
||||
result = surface->LockRect(&lockrect, nullptr, D3DLOCK_DISCARD);
|
||||
if (FAILED(result))
|
||||
{
|
||||
pitch = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pitch = lockrect.Pitch;
|
||||
return (uint8_t*)lockrect.pBits;
|
||||
}
|
||||
|
||||
void I_PolyPresentUnlock(int x, int y, int width, int height)
|
||||
{
|
||||
surface->UnlockRect();
|
||||
|
||||
IDirect3DSurface9 *backbuffer = nullptr;
|
||||
HRESULT result = device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
result = device->BeginScene();
|
||||
if (SUCCEEDED(result))
|
||||
{
|
||||
int count = 0;
|
||||
D3DRECT clearrects[4];
|
||||
if (y > 0)
|
||||
{
|
||||
clearrects[count].x1 = 0;
|
||||
clearrects[count].y1 = 0;
|
||||
clearrects[count].x2 = ClientWidth;
|
||||
clearrects[count].y2 = y;
|
||||
count++;
|
||||
}
|
||||
if (y + height < ClientHeight)
|
||||
{
|
||||
clearrects[count].x1 = 0;
|
||||
clearrects[count].y1 = y + height;
|
||||
clearrects[count].x2 = ClientWidth;
|
||||
clearrects[count].y2 = ClientHeight;
|
||||
count++;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
clearrects[count].x1 = 0;
|
||||
clearrects[count].y1 = y;
|
||||
clearrects[count].x2 = x;
|
||||
clearrects[count].y2 = y + height;
|
||||
count++;
|
||||
}
|
||||
if (x + width < ClientWidth)
|
||||
{
|
||||
clearrects[count].x1 = x + width;
|
||||
clearrects[count].y1 = y;
|
||||
clearrects[count].x2 = ClientWidth;
|
||||
clearrects[count].y2 = y + height;
|
||||
count++;
|
||||
}
|
||||
if (count > 0)
|
||||
device->Clear(count, clearrects, D3DCLEAR_TARGET, 0, 0.0f, 0);
|
||||
|
||||
RECT srcrect = {}, dstrect = {};
|
||||
srcrect.right = SrcWidth;
|
||||
srcrect.bottom = SrcHeight;
|
||||
dstrect.left = x;
|
||||
dstrect.top = y;
|
||||
dstrect.right = x + width;
|
||||
dstrect.bottom = y + height;
|
||||
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR);
|
||||
|
||||
result = device->EndScene();
|
||||
if (SUCCEEDED(result))
|
||||
device->PresentEx(nullptr, nullptr, 0, nullptr, CurrentVSync ? 0 : D3DPRESENT_FORCEIMMEDIATE);
|
||||
}
|
||||
|
||||
backbuffer->Release();
|
||||
}
|
||||
|
||||
void I_PolyPresentDeinit()
|
||||
{
|
||||
if (surface) surface->Release();
|
||||
if (device) device->Release();
|
||||
if (d3d9) d3d9->Release();
|
||||
}
|
21
src/win32/win32polyvideo.h
Normal file
21
src/win32/win32polyvideo.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "win32basevideo.h"
|
||||
#include "c_cvars.h"
|
||||
#include "rendering/polyrenderer/backend/poly_framebuffer.h"
|
||||
|
||||
EXTERN_CVAR(Bool, fullscreen)
|
||||
|
||||
class Win32PolyVideo : public Win32BaseVideo
|
||||
{
|
||||
public:
|
||||
void Shutdown() override
|
||||
{
|
||||
}
|
||||
|
||||
DFrameBuffer *CreateFrameBuffer() override
|
||||
{
|
||||
auto fb = new PolyFrameBuffer(m_hMonitor, fullscreen);
|
||||
return fb;
|
||||
}
|
||||
};
|
|
@ -885,6 +885,12 @@ OptionValue GPUSwitch
|
|||
2.0, "$OPTVAL_INTEGRATED"
|
||||
}
|
||||
|
||||
OptionValue PreferBackend
|
||||
{
|
||||
0, "$OPTVAL_OPENGL"
|
||||
1, "$OPTVAL_VULKAN"
|
||||
2, "$OPTVAL_SOFTPOLY"
|
||||
}
|
||||
|
||||
OptionMenu "TrueColorOptions" protected
|
||||
{
|
||||
|
@ -918,6 +924,8 @@ OptionMenu "VideoOptions" protected
|
|||
Submenu "$GLMNU_TEXOPT", "GLTextureGLOptions"
|
||||
Submenu "$GLMNU_DYNLIGHT", "GLLightOptions"
|
||||
StaticText " "
|
||||
Option "$DSPLYMNU_PREFERBACKEND", "vid_preferbackend", "PreferBackend"
|
||||
StaticText " "
|
||||
Slider "$DSPLYMNU_SCREENSIZE", "screenblocks", 3.0, 12.0, 1.0, 0
|
||||
|
||||
Slider "$DSPLYMNU_GAMMA", "Gamma", 0.75, 3.0, 0.05, 2
|
||||
|
@ -2759,7 +2767,6 @@ OptionMenu "vkoptions"
|
|||
StaticText "$VK_WARNING"
|
||||
StaticText "$VK_RESTART"
|
||||
StaticText ""
|
||||
Option "$VKMNU_ENABLE", "vid_enablevulkan", "OnOff"
|
||||
TextField "$VKMNU_DEVICE", vk_device
|
||||
Option "$VKMNU_HDR", "vk_hdr", "OnOff"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue