mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 06:42:12 +00:00
- removed the Softpoly backend.
Its only relevant use case has been to use the software renderer on hardware not capable of OpenGL 3.3, but a large chunk of that can now be serviced with GLES. In addition it has ceased further development and has not received any of the recent 2D render features which further reduces its viability.
This commit is contained in:
parent
9eb8d65cb1
commit
93e934c8d0
58 changed files with 25 additions and 7282 deletions
|
@ -218,7 +218,7 @@ if( MSVC )
|
|||
# String pooling
|
||||
# Function-level linking
|
||||
# Disable run-time type information
|
||||
set( ALL_C_FLAGS "/GF /Gy /permissive- /DHAVE_SOFTPOLY" )
|
||||
set( ALL_C_FLAGS "/GF /Gy /permissive-" )
|
||||
|
||||
if ( HAVE_VULKAN )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} /DHAVE_VULKAN" )
|
||||
|
@ -260,7 +260,7 @@ if( MSVC )
|
|||
string(REPLACE "/MDd " " " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} )
|
||||
else()
|
||||
set( REL_LINKER_FLAGS "" )
|
||||
set( ALL_C_FLAGS "-ffp-contract=off -DHAVE_SOFTPOLY" )
|
||||
set( ALL_C_FLAGS "-ffp-contract=off" )
|
||||
|
||||
if ( HAVE_VULKAN )
|
||||
set( ALL_C_FLAGS "${ALL_C_FLAGS} -DHAVE_VULKAN" )
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
cmake_minimum_required( VERSION 3.1.0 )
|
||||
cmake_minimum_required( VERSION 3.1.0 )
|
||||
|
||||
include(precompiled_headers)
|
||||
|
||||
|
@ -454,7 +455,7 @@ set( PLAT_WIN32_SOURCES
|
|||
common/platform/win32/base_sysfb.cpp
|
||||
common/platform/win32/win32basevideo.cpp
|
||||
common/platform/win32/win32glvideo.cpp
|
||||
common/platform/win32/win32polyvideo.cpp)
|
||||
)
|
||||
|
||||
if (HAVE_VULKAN)
|
||||
set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} common/platform/win32/win32vulkanvideo.cpp )
|
||||
|
@ -633,10 +634,6 @@ file( GLOB HEADER_FILES
|
|||
common/rendering/gl_load/*.h
|
||||
common/rendering/gles/*.h
|
||||
common/rendering/hwrenderer/data/*.h
|
||||
common/rendering/polyrenderer/*.h
|
||||
common/rendering/polyrenderer/math/*.h
|
||||
common/rendering/polyrenderer/drawers/*.h
|
||||
common/rendering/polyrenderer/backend/*.h
|
||||
common/rendering/vulkan/*.h
|
||||
common/rendering/vulkan/system/*.h
|
||||
common/rendering/vulkan/renderer/*.h
|
||||
|
@ -707,7 +704,6 @@ set ( SWRENDER_SOURCES
|
|||
rendering/swrenderer/things/r_sprite.cpp
|
||||
rendering/swrenderer/things/r_wallsprite.cpp
|
||||
rendering/swrenderer/things/r_decal.cpp
|
||||
rendering/swrenderer/things/r_model.cpp
|
||||
rendering/swrenderer/plane/r_visibleplane.cpp
|
||||
rendering/swrenderer/plane/r_visibleplanelist.cpp
|
||||
rendering/swrenderer/plane/r_skyplane.cpp
|
||||
|
@ -716,21 +712,11 @@ set ( SWRENDER_SOURCES
|
|||
rendering/swrenderer/plane/r_slopeplane.cpp
|
||||
)
|
||||
|
||||
set( POLYRENDER_SOURCES
|
||||
common/rendering/polyrenderer/drawers/poly_triangle.cpp
|
||||
common/rendering/polyrenderer/drawers/poly_thread.cpp
|
||||
common/rendering/polyrenderer/drawers/screen_triangle.cpp
|
||||
common/rendering/polyrenderer/drawers/screen_scanline_setup.cpp
|
||||
common/rendering/polyrenderer/drawers/screen_shader.cpp
|
||||
common/rendering/polyrenderer/drawers/screen_blend.cpp
|
||||
)
|
||||
|
||||
# These files will be flagged as "headers" so that they appear in project files
|
||||
# without being compiled.
|
||||
set( NOT_COMPILED_SOURCE_FILES
|
||||
${OTHER_SYSTEM_SOURCES}
|
||||
${SWRENDER_SOURCES}
|
||||
${POLYRENDER_SOURCES}
|
||||
sc_man_scanner.h
|
||||
common/engine/sc_man_scanner.re
|
||||
g_statusbar/sbarinfo_commands.cpp
|
||||
|
@ -763,7 +749,6 @@ set( VM_JIT_SOURCES
|
|||
set( FASTMATH_SOURCES
|
||||
rendering/swrenderer/r_all.cpp
|
||||
rendering/swrenderer/r_swscene.cpp
|
||||
common/rendering/polyrenderer/poly_all.cpp
|
||||
common/textures/hires/hqnx/init.cpp
|
||||
common/textures/hires/hqnx/hq2x.cpp
|
||||
common/textures/hires/hqnx/hq3x.cpp
|
||||
|
@ -843,12 +828,6 @@ if (HAVE_VULKAN)
|
|||
set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES})
|
||||
endif()
|
||||
|
||||
set (POLYBACKEND_SOURCES
|
||||
common/rendering/polyrenderer/backend/poly_framebuffer.cpp
|
||||
common/rendering/polyrenderer/backend/poly_buffers.cpp
|
||||
common/rendering/polyrenderer/backend/poly_hwtexture.cpp
|
||||
common/rendering/polyrenderer/backend/poly_renderstate.cpp
|
||||
)
|
||||
set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${POLYBACKEND_SOURCES})
|
||||
|
||||
set (PCH_SOURCES
|
||||
|
@ -1337,8 +1316,6 @@ include_directories( .
|
|||
common/rendering/gles/glad/include
|
||||
common/rendering/gles/Mali_OpenGL_ES_Emulator/include
|
||||
common/rendering/vulkan/thirdparty
|
||||
common/rendering/polyrenderer/backend
|
||||
common/rendering/polyrenderer/drawers
|
||||
common/scripting/vm
|
||||
common/scripting/jit
|
||||
common/scripting/core
|
||||
|
@ -1449,7 +1426,6 @@ endif()
|
|||
if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
|
||||
# Need to enable intrinsics for these files.
|
||||
set_property( SOURCE
|
||||
common/rendering/polyrenderer/poly_all.cpp
|
||||
common/utility/palette.cpp
|
||||
common/utility/x86.cpp
|
||||
rendering/swrenderer/r_all.cpp
|
||||
|
@ -1554,9 +1530,6 @@ source_group("Common\\Rendering\\Vulkan Renderer\\Textures" REGULAR_EXPRESSION "
|
|||
source_group("Common\\Rendering\\Vulkan Renderer\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/thirdparty/.+")
|
||||
source_group("Common\\Rendering\\Vulkan Renderer\\Third Party\\Volk" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/thirdparty/volk/.+")
|
||||
source_group("Common\\Rendering\\Vulkan Renderer\\Third Party\\Vk_Mem_Alloc" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/vulkan/thirdparty/vk_mem_alloc.+")
|
||||
source_group("Common\\Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/polyrenderer/.+")
|
||||
source_group("Common\\Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/polyrenderer/drawers/.+")
|
||||
source_group("Common\\Rendering\\Poly Renderer\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/rendering/polyrenderer/backend/.+")
|
||||
source_group("Common\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/models/.+")
|
||||
source_group("Common\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/.+")
|
||||
source_group("Common\\Textures\\Hires" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/textures/hires/.+")
|
||||
|
|
|
@ -60,9 +60,6 @@
|
|||
#ifdef HAVE_VULKAN
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#endif
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
#include "poly_framebuffer.h"
|
||||
#endif
|
||||
|
||||
extern bool ToggleFullscreen;
|
||||
|
||||
|
@ -101,7 +98,6 @@ extern bool ToggleFullscreen;
|
|||
EXTERN_CVAR(Bool, vid_hidpi)
|
||||
EXTERN_CVAR(Int, vid_defwidth)
|
||||
EXTERN_CVAR(Int, vid_defheight)
|
||||
EXTERN_CVAR(Int, vid_preferbackend)
|
||||
EXTERN_CVAR(Bool, vk_debug)
|
||||
|
||||
CVAR(Bool, mvk_debug, false, 0)
|
||||
|
@ -376,7 +372,7 @@ class CocoaVideo : public IVideo
|
|||
public:
|
||||
CocoaVideo()
|
||||
{
|
||||
ms_isVulkanEnabled = vid_preferbackend == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11
|
||||
ms_isVulkanEnabled = V_GetBackend() == 1 && NSAppKitVersionNumber >= 1404; // NSAppKitVersionNumber10_11
|
||||
}
|
||||
|
||||
~CocoaVideo()
|
||||
|
@ -450,23 +446,12 @@ public:
|
|||
else
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (vid_preferbackend == 2)
|
||||
{
|
||||
SetupOpenGLView(ms_window, OpenGLProfile::Legacy);
|
||||
|
||||
fb = new PolyFrameBuffer(nullptr, vid_fullscreen);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
SetupOpenGLView(ms_window, OpenGLProfile::Core);
|
||||
}
|
||||
SetupOpenGLView(ms_window, OpenGLProfile::Core);
|
||||
|
||||
if (fb == nullptr)
|
||||
{
|
||||
#ifdef HAVE_GLES2
|
||||
if( (Args->CheckParm ("-gles2_renderer")) || (vid_preferbackend == 3) )
|
||||
if(V_GetBackend() == 2)
|
||||
fb = new OpenGLESRenderer::OpenGLFrameBuffer(0, vid_fullscreen);
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -58,10 +58,6 @@
|
|||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
#include "poly_framebuffer.h"
|
||||
#endif
|
||||
|
||||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#if defined HAVE_VULKAN
|
||||
|
@ -81,7 +77,6 @@ EXTERN_CVAR (Int, vid_adapter)
|
|||
EXTERN_CVAR (Int, vid_displaybits)
|
||||
EXTERN_CVAR (Int, vid_defwidth)
|
||||
EXTERN_CVAR (Int, vid_defheight)
|
||||
EXTERN_CVAR (Int, vid_preferbackend)
|
||||
EXTERN_CVAR (Bool, cl_capfps)
|
||||
|
||||
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
||||
|
@ -233,157 +228,6 @@ bool I_CreateVulkanSurface(VkInstance instance, VkSurfaceKHR *surface)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
namespace
|
||||
{
|
||||
SDL_Renderer* polyrendertarget = nullptr;
|
||||
SDL_Texture* polytexture = nullptr;
|
||||
int polytexturew = 0;
|
||||
int polytextureh = 0;
|
||||
bool polyvsync = false;
|
||||
bool polyfirstinit = true;
|
||||
}
|
||||
|
||||
void I_PolyPresentInit()
|
||||
{
|
||||
assert(Priv::softpolyEnabled);
|
||||
assert(Priv::window != nullptr);
|
||||
|
||||
if (strcmp(vid_sdl_render_driver, "") != 0)
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, vid_sdl_render_driver);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *I_PolyPresentLock(int w, int h, bool vsync, int &pitch)
|
||||
{
|
||||
// When vsync changes we need to reinitialize
|
||||
if (polyrendertarget && polyvsync != vsync)
|
||||
{
|
||||
I_PolyPresentDeinit();
|
||||
}
|
||||
|
||||
if (!polyrendertarget)
|
||||
{
|
||||
polyvsync = vsync;
|
||||
|
||||
polyrendertarget = SDL_CreateRenderer(Priv::window, -1, vsync ? SDL_RENDERER_PRESENTVSYNC : 0);
|
||||
if (!polyrendertarget)
|
||||
{
|
||||
I_FatalError("Could not create render target for softpoly: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
// Tell the user which render driver is being used, but don't repeat
|
||||
// outselves if we're just changing vsync.
|
||||
if (polyfirstinit)
|
||||
{
|
||||
polyfirstinit = false;
|
||||
|
||||
SDL_RendererInfo rendererInfo;
|
||||
if (SDL_GetRendererInfo(polyrendertarget, &rendererInfo) == 0)
|
||||
{
|
||||
Printf("Using render driver %s\n", rendererInfo.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("Failed to query render driver\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Mask color
|
||||
SDL_SetRenderDrawColor(polyrendertarget, 0, 0, 0, 255);
|
||||
}
|
||||
|
||||
if (!polytexture || polytexturew != w || polytextureh != h)
|
||||
{
|
||||
if (polytexture)
|
||||
{
|
||||
SDL_DestroyTexture(polytexture);
|
||||
polytexture = nullptr;
|
||||
polytexturew = polytextureh = 0;
|
||||
}
|
||||
if ((polytexture = SDL_CreateTexture(polyrendertarget, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, w, h)) == nullptr)
|
||||
I_Error("Failed to create %dx%d render target texture.", w, h);
|
||||
polytexturew = w;
|
||||
polytextureh = h;
|
||||
}
|
||||
|
||||
uint8_t* pixels;
|
||||
SDL_LockTexture(polytexture, nullptr, (void**)&pixels, &pitch);
|
||||
return pixels;
|
||||
}
|
||||
|
||||
void I_PolyPresentUnlock(int x, int y, int width, int height)
|
||||
{
|
||||
SDL_UnlockTexture(polytexture);
|
||||
|
||||
int ClientWidth, ClientHeight;
|
||||
SDL_GetRendererOutputSize(polyrendertarget, &ClientWidth, &ClientHeight);
|
||||
|
||||
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_RenderFillRects(polyrendertarget, clearrects, count);
|
||||
|
||||
SDL_Rect dstrect;
|
||||
dstrect.x = x;
|
||||
dstrect.y = y;
|
||||
dstrect.w = width;
|
||||
dstrect.h = height;
|
||||
SDL_RenderCopy(polyrendertarget, polytexture, nullptr, &dstrect);
|
||||
|
||||
SDL_RenderPresent(polyrendertarget);
|
||||
}
|
||||
|
||||
void I_PolyPresentDeinit()
|
||||
{
|
||||
if (polytexture)
|
||||
{
|
||||
SDL_DestroyTexture(polytexture);
|
||||
polytexture = nullptr;
|
||||
}
|
||||
|
||||
if (polyrendertarget)
|
||||
{
|
||||
SDL_DestroyRenderer(polyrendertarget);
|
||||
polyrendertarget = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
SDLVideo::SDLVideo ()
|
||||
{
|
||||
|
@ -399,11 +243,8 @@ SDLVideo::SDLVideo ()
|
|||
I_FatalError("Only SDL 2.0.6 or later is supported.");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
Priv::softpolyEnabled = vid_preferbackend == 2;
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
Priv::vulkanEnabled = vid_preferbackend == 1;
|
||||
Priv::vulkanEnabled = V_GetBackend() == 1;
|
||||
|
||||
if (Priv::vulkanEnabled)
|
||||
{
|
||||
|
@ -415,16 +256,6 @@ SDLVideo::SDLVideo ()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
Priv::CreateWindow(SDL_WINDOW_HIDDEN);
|
||||
if (Priv::window == nullptr)
|
||||
{
|
||||
I_FatalError("Could not create SoftPoly window:\n%s\n",SDL_GetError());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SDLVideo::~SDLVideo ()
|
||||
|
@ -461,16 +292,10 @@ DFrameBuffer *SDLVideo::CreateFrameBuffer ()
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
fb = new PolyFrameBuffer(nullptr, vid_fullscreen);
|
||||
}
|
||||
#endif
|
||||
if (fb == nullptr)
|
||||
{
|
||||
#ifdef HAVE_GLES2
|
||||
if( (Args->CheckParm ("-gles2_renderer")) || (vid_preferbackend == 3) )
|
||||
if (V_GetBackend() == 2)
|
||||
fb = new OpenGLESRenderer::OpenGLFrameBuffer(0, vid_fullscreen);
|
||||
else
|
||||
#endif
|
||||
|
@ -503,16 +328,6 @@ int SystemBaseFrameBuffer::GetClientWidth()
|
|||
{
|
||||
int width = 0;
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
if (polyrendertarget)
|
||||
SDL_GetRendererOutputSize(polyrendertarget, &width, nullptr);
|
||||
else
|
||||
SDL_GetWindowSize(Priv::window, &width, nullptr);
|
||||
return width;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
|
@ -526,17 +341,6 @@ int SystemBaseFrameBuffer::GetClientHeight()
|
|||
{
|
||||
int height = 0;
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (Priv::softpolyEnabled)
|
||||
{
|
||||
if (polyrendertarget)
|
||||
SDL_GetRendererOutputSize(polyrendertarget, nullptr, &height);
|
||||
else
|
||||
SDL_GetWindowSize(Priv::window, nullptr, &height);
|
||||
return height;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VULKAN
|
||||
assert(Priv::vulkanEnabled);
|
||||
SDL_Vulkan_GetDrawableSize(Priv::window, nullptr, &height);
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
#include "version.h"
|
||||
#include "printf.h"
|
||||
#include "win32glvideo.h"
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
#include "win32polyvideo.h"
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
#include "win32vulkanvideo.h"
|
||||
#endif
|
||||
|
@ -54,8 +51,6 @@
|
|||
#include "i_system.h"
|
||||
#include "i_mainwindow.h"
|
||||
|
||||
EXTERN_CVAR(Int, vid_preferbackend)
|
||||
|
||||
IVideo *Video;
|
||||
|
||||
// do not include GL headers here, only declare the necessary functions.
|
||||
|
@ -130,15 +125,8 @@ void I_InitGraphics ()
|
|||
// are the active app. Huh?
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (vid_preferbackend == 2)
|
||||
{
|
||||
Video = new Win32PolyVideo();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_VULKAN
|
||||
if (vid_preferbackend == 1)
|
||||
if (V_GetBackend() == 1)
|
||||
{
|
||||
// first try Vulkan, if that fails OpenGL
|
||||
try
|
||||
|
@ -157,10 +145,6 @@ void I_InitGraphics ()
|
|||
Video = new Win32GLVideo();
|
||||
}
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
if (Video == NULL)
|
||||
Video = new Win32PolyVideo();
|
||||
#endif
|
||||
// we somehow STILL don't have a display!!
|
||||
if (Video == NULL)
|
||||
I_FatalError ("Failed to initialize display");
|
||||
|
|
|
@ -447,12 +447,10 @@ BOOL CALLBACK IWADBoxCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lPa
|
|||
vid_fullscreen = SendDlgItemMessage( hDlg, IDC_WELCOME_FULLSCREEN, BM_GETCHECK, 0, 0 ) == BST_CHECKED;
|
||||
#ifdef HAVE_GLES2
|
||||
if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN4, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
vid_preferbackend = 3;
|
||||
vid_preferbackend = 2;
|
||||
else
|
||||
#endif
|
||||
if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN3, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
vid_preferbackend = 2;
|
||||
else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN2, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN2, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
vid_preferbackend = 1;
|
||||
else if (SendDlgItemMessage(hDlg, IDC_WELCOME_VULKAN1, BM_GETCHECK, 0, 0) == BST_CHECKED)
|
||||
vid_preferbackend = 0;
|
||||
|
|
|
@ -65,7 +65,6 @@ PROC zd_wglGetProcAddress(LPCSTR name);
|
|||
}
|
||||
|
||||
EXTERN_CVAR(Int, vid_adapter)
|
||||
EXTERN_CVAR(Int, vid_preferbackend)
|
||||
EXTERN_CVAR(Bool, vid_hdr)
|
||||
|
||||
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
|
@ -110,7 +109,7 @@ DFrameBuffer *Win32GLVideo::CreateFrameBuffer()
|
|||
SystemGLFrameBuffer *fb;
|
||||
|
||||
#ifdef HAVE_GLES2
|
||||
if ((Args->CheckParm("-gles2_renderer")) || (vid_preferbackend == 3) )
|
||||
if (V_GetBackend() == 2)
|
||||
fb = new OpenGLESRenderer::OpenGLFrameBuffer(m_hMonitor, vid_fullscreen);
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include "hardware.h"
|
||||
#include "engineerrors.h"
|
||||
#include <Windows.h>
|
||||
#include "i_mainwindow.h"
|
||||
|
||||
#ifdef HAVE_SOFTPOLY
|
||||
|
||||
EXTERN_CVAR(Bool, vid_vsync)
|
||||
|
||||
bool ViewportLinearScale();
|
||||
|
||||
#include <d3d9.h>
|
||||
#pragma comment(lib, "d3d9.lib")
|
||||
|
||||
#ifndef D3DPRESENT_FORCEIMMEDIATE
|
||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L // MinGW
|
||||
#endif
|
||||
|
||||
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(mainwindow.GetHandle(), &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 = mainwindow.GetHandle();
|
||||
pp.PresentationInterval = CurrentVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
|
||||
HRESULT result = d3d9->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mainwindow.GetHandle(), 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(mainwindow.GetHandle(), &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 = mainwindow.GetHandle();
|
||||
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;
|
||||
if (ViewportLinearScale())
|
||||
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_LINEAR);
|
||||
else
|
||||
device->StretchRect(surface, &srcrect, backbuffer, &dstrect, D3DTEXF_POINT);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "win32basevideo.h"
|
||||
#include "c_cvars.h"
|
||||
#include "poly_framebuffer.h"
|
||||
|
||||
EXTERN_CVAR(Bool, vid_fullscreen)
|
||||
|
||||
class Win32PolyVideo : public Win32BaseVideo
|
||||
{
|
||||
public:
|
||||
void Shutdown() override
|
||||
{
|
||||
}
|
||||
|
||||
DFrameBuffer *CreateFrameBuffer() override
|
||||
{
|
||||
auto fb = new PolyFrameBuffer(m_hMonitor, vid_fullscreen);
|
||||
return fb;
|
||||
}
|
||||
};
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 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 "poly_buffers.h"
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "poly_thread.h"
|
||||
#include "engineerrors.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, BufferUsageType usage)
|
||||
{
|
||||
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 frame0, int frame1, int index)
|
||||
{
|
||||
uint8_t* buff = (uint8_t*)vertices;
|
||||
|
||||
// [GEC] finds the right frame.
|
||||
uint32_t offsets[2] = { static_cast<uint32_t>(frame0 * Stride), static_cast<uint32_t>(frame1 * Stride) };
|
||||
uint8_t* vertexBuffers[2] = { buff + offsets[0], buff + offsets[1] };
|
||||
|
||||
const uint8_t* vertex = static_cast<const uint8_t*>(vertexBuffers[0]) + mStride * index;
|
||||
const float* attrVertex = reinterpret_cast<const float*>(vertex + mOffsets[VATTR_VERTEX]);
|
||||
|
||||
const uint8_t* vertex2 = static_cast<const uint8_t*>(vertexBuffers[1]) + mStride * index;
|
||||
const float* attrVertex2 = reinterpret_cast<const float*>(vertex2 + 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]);
|
||||
|
||||
// [GEC] Apply the formula for model interpolation
|
||||
|
||||
float newVertex[3];
|
||||
|
||||
float t = thread->mainVertexShader.Data.uInterpolationFactor;
|
||||
float invt = 1.0f - t;
|
||||
|
||||
newVertex[0] = (invt * attrVertex[0]) + (t * attrVertex2[0]);
|
||||
newVertex[1] = (invt * attrVertex[1]) + (t * attrVertex2[1]);
|
||||
newVertex[2] = (invt * attrVertex[2]) + (t * attrVertex2[2]);
|
||||
|
||||
thread->mainVertexShader.aPosition = { newVertex[0], newVertex[1], newVertex[2], 1.0f };
|
||||
thread->mainVertexShader.aTexCoord = { attrTexcoord[0], attrTexcoord[1] };
|
||||
|
||||
if ((UseVertexData & 1) == 0)
|
||||
{
|
||||
const auto &c = thread->mainVertexShader.Data.uVertexColor;
|
||||
thread->mainVertexShader.aColor.X = c.X;
|
||||
thread->mainVertexShader.aColor.Y = c.Y;
|
||||
thread->mainVertexShader.aColor.Z = c.Z;
|
||||
thread->mainVertexShader.aColor.W = c.W;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->mainVertexShader.aColor.X = attrColor[0] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.Y = attrColor[1] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.Z = attrColor[2] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.W = attrColor[3] * (1.0f / 255.0f);
|
||||
}
|
||||
|
||||
if ((UseVertexData & 2) == 0)
|
||||
{
|
||||
const auto &n = thread->mainVertexShader.Data.uVertexNormal;
|
||||
thread->mainVertexShader.aNormal = FVector4(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 = FVector4(x, y, z, 0.0f);
|
||||
thread->mainVertexShader.aNormal2 = FVector4(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);
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "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, BufferUsageType usage) 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 final : 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 frame0, int frame1, 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;
|
||||
};
|
|
@ -1,503 +0,0 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 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 "v_video.h"
|
||||
#include "m_png.h"
|
||||
|
||||
#include "r_videoscale.h"
|
||||
#include "i_time.h"
|
||||
#include "v_text.h"
|
||||
#include "i_video.h"
|
||||
#include "v_draw.h"
|
||||
|
||||
#include "hw_clock.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_skydome.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_buffers.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "poly_hwtexture.h"
|
||||
#include "engineerrors.h"
|
||||
|
||||
void Draw2D(F2DDrawer *drawer, FRenderState &state);
|
||||
|
||||
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 mScreenQuad.VertexBuffer;
|
||||
delete mScreenQuad.IndexBuffer;
|
||||
|
||||
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();
|
||||
|
||||
static const FVertexBufferAttribute format[] =
|
||||
{
|
||||
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(ScreenQuadVertex, x) },
|
||||
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(ScreenQuadVertex, u) },
|
||||
{ 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(ScreenQuadVertex, color0) }
|
||||
};
|
||||
|
||||
uint32_t indices[6] = { 0, 1, 2, 1, 3, 2 };
|
||||
|
||||
mScreenQuad.VertexBuffer = screen->CreateVertexBuffer();
|
||||
mScreenQuad.VertexBuffer->SetFormat(1, 3, sizeof(ScreenQuadVertex), format);
|
||||
|
||||
mScreenQuad.IndexBuffer = screen->CreateIndexBuffer();
|
||||
mScreenQuad.IndexBuffer->SetData(6 * sizeof(uint32_t), indices, BufferUsageType::Stream);
|
||||
|
||||
CheckCanvas();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::CheckCanvas()
|
||||
{
|
||||
if (!mCanvas || mCanvas->GetWidth() != GetWidth() || mCanvas->GetHeight() != GetHeight())
|
||||
{
|
||||
FlushDrawCommands();
|
||||
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(), true);
|
||||
}
|
||||
}
|
||||
|
||||
PolyCommandBuffer *PolyFrameBuffer::GetDrawCommands()
|
||||
{
|
||||
if (!mDrawCommands)
|
||||
{
|
||||
mDrawCommands.reset(new PolyCommandBuffer(&mFrameMemory));
|
||||
mDrawCommands->SetLightBuffer(mLightBuffer->Memory());
|
||||
}
|
||||
return mDrawCommands.get();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::FlushDrawCommands()
|
||||
{
|
||||
mRenderState->EndRenderPass();
|
||||
if (mDrawCommands)
|
||||
{
|
||||
mDrawCommands->Submit();
|
||||
mDrawCommands.reset();
|
||||
}
|
||||
}
|
||||
|
||||
EXTERN_CVAR(Float, vid_brightness)
|
||||
EXTERN_CVAR(Float, vid_contrast)
|
||||
EXTERN_CVAR(Float, vid_saturation)
|
||||
|
||||
void PolyFrameBuffer::Update()
|
||||
{
|
||||
twoD.Reset();
|
||||
Flush3D.Reset();
|
||||
|
||||
Flush3D.Clock();
|
||||
|
||||
Draw2D();
|
||||
twod->Clear();
|
||||
|
||||
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
|
||||
// [GEC] with the help of dpJudas a new system of copying and applying gamma in the video buffer
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(&mFrameMemory);
|
||||
copyqueue->Push<CopyAndApplyGammaCommand>(dst, pitch / pixelsize, src, w, h, w, vid_gamma, vid_contrast, vid_brightness, vid_saturation);
|
||||
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);
|
||||
}
|
||||
FPSLimit();
|
||||
}
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mFrameMemory.Clear();
|
||||
FrameDeleteList.Buffers.clear();
|
||||
FrameDeleteList.Images.clear();
|
||||
|
||||
CheckCanvas();
|
||||
|
||||
Super::Update();
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc)
|
||||
{
|
||||
auto BaseLayer = static_cast<PolyHardwareTexture*>(tex->GetHardwareTexture(0, 0));
|
||||
|
||||
DCanvas *image = BaseLayer->GetImage(tex, 0, 0);
|
||||
PolyDepthStencil *depthStencil = BaseLayer->GetDepthStencil(tex);
|
||||
mRenderState->SetRenderTarget(image, depthStencil, false);
|
||||
|
||||
IntRect bounds;
|
||||
bounds.left = bounds.top = 0;
|
||||
bounds.width = min(tex->GetWidth(), image->GetWidth());
|
||||
bounds.height = min(tex->GetHeight(), image->GetHeight());
|
||||
|
||||
renderFunc(bounds);
|
||||
|
||||
FlushDrawCommands();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil(), true);
|
||||
|
||||
tex->SetUpdated(true);
|
||||
}
|
||||
|
||||
static uint8_t ToIntColorComponent(float v)
|
||||
{
|
||||
return clamp((int)(v * 255.0f + 0.5f), 0, 255);
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D)
|
||||
{
|
||||
afterBloomDrawEndScene2D();
|
||||
|
||||
if (fixedcm >= CM_FIRSTSPECIALCOLORMAP && fixedcm < CM_MAXCOLORMAP)
|
||||
{
|
||||
FSpecialColormap* scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP];
|
||||
|
||||
mRenderState->SetViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
||||
screen->mViewpoints->Set2D(*mRenderState, screen->GetWidth(), screen->GetHeight());
|
||||
|
||||
ScreenQuadVertex vertices[4] =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
{ (float)mScreenViewport.width, 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, (float)mScreenViewport.height, 0.0f, 1.0f },
|
||||
{ (float)mScreenViewport.width, (float)mScreenViewport.height, 1.0f, 1.0f }
|
||||
};
|
||||
mScreenQuad.VertexBuffer->SetData(4 * sizeof(ScreenQuadVertex), vertices, BufferUsageType::Stream);
|
||||
|
||||
mRenderState->SetVertexBuffer(mScreenQuad.VertexBuffer, 0, 0);
|
||||
mRenderState->SetIndexBuffer(mScreenQuad.IndexBuffer);
|
||||
|
||||
mRenderState->SetObjectColor(PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f)));
|
||||
mRenderState->SetAddColor(PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f)));
|
||||
|
||||
mRenderState->EnableDepthTest(false);
|
||||
mRenderState->EnableMultisampling(false);
|
||||
mRenderState->SetCulling(Cull_None);
|
||||
|
||||
mRenderState->SetScissor(-1, -1, -1, -1);
|
||||
mRenderState->SetColor(1, 1, 1, 1);
|
||||
mRenderState->AlphaFunc(Alpha_GEqual, 0.f);
|
||||
mRenderState->EnableTexture(false);
|
||||
mRenderState->SetColormapShader(true);
|
||||
mRenderState->DrawIndexed(DT_Triangles, 0, 6);
|
||||
mRenderState->SetColormapShader(false);
|
||||
mRenderState->SetObjectColor(0xffffffff);
|
||||
mRenderState->SetAddColor(0);
|
||||
mRenderState->SetVertexBuffer(screen->mVertexData);
|
||||
mRenderState->EnableTexture(true);
|
||||
mRenderState->ResetColor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::SetVSync(bool vsync)
|
||||
{
|
||||
cur_vsync = vsync;
|
||||
}
|
||||
|
||||
FRenderState* PolyFrameBuffer::RenderState()
|
||||
{
|
||||
return mRenderState.get();
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
|
||||
{
|
||||
if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return;
|
||||
|
||||
MaterialLayerInfo* layer;
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mat->GetLayer(0, translation, &layer));
|
||||
systex->GetImage(layer->layerTexture, translation, layer->scaleFlags);
|
||||
|
||||
int numLayers = mat->NumLayers();
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mat->GetLayer(i, 0, &layer));
|
||||
systex->GetImage(layer->layerTexture, 0, layer->scaleFlags); // fixme: Upscale flags must be disabled for certain layers.
|
||||
}
|
||||
}
|
||||
|
||||
IHardwareTexture *PolyFrameBuffer::CreateHardwareTexture(int numchannels)
|
||||
{
|
||||
return new PolyHardwareTexture();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
twod->Clear();
|
||||
|
||||
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)
|
||||
{
|
||||
// [GEC] Really necessary to apply gamma, brightness, contrast and saturation for screenshot
|
||||
|
||||
std::vector<uint8_t> gammatablebuf(256);
|
||||
uint8_t* gammatable = gammatablebuf.data();
|
||||
|
||||
float InvGamma = 1.0f / clamp<float>(vid_gamma, 0.1f, 4.f);
|
||||
float Brightness = clamp<float>(vid_brightness, -0.8f, 0.8f);
|
||||
float Contrast = clamp<float>(vid_contrast, 0.1f, 3.f);
|
||||
float Saturation = clamp<float>(vid_saturation, -15.0f, 15.f);
|
||||
|
||||
for (int x = 0; x < 256; x++)
|
||||
{
|
||||
float ramp = (float)(x / 255.f);
|
||||
// Apply Contrast
|
||||
// vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0);
|
||||
if(vid_contrast != 1.0f)
|
||||
ramp = (((ramp - 0.5f) * Contrast) + 0.5f);
|
||||
|
||||
// Apply Brightness
|
||||
// vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0);
|
||||
if (vid_brightness != 0.0f)
|
||||
ramp += (Brightness / 2.0f);
|
||||
|
||||
// Apply Gamma
|
||||
// FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma));
|
||||
if (vid_gamma != 1.0f)
|
||||
ramp = pow(ramp, InvGamma);
|
||||
|
||||
// Clamp ramp
|
||||
ramp = clamp<float>(ramp, 0.0f, 1.f);
|
||||
|
||||
gammatable[x] = (uint8_t)(ramp * 255);
|
||||
}
|
||||
|
||||
int w = SCREENWIDTH;
|
||||
int h = SCREENHEIGHT;
|
||||
|
||||
TArray<uint8_t> ScreenshotBuffer(w * h * 3, true);
|
||||
const uint8_t* pixels = GetCanvas()->GetPixels();
|
||||
int dindex = 0;
|
||||
|
||||
// Convert to RGB
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
int sindex = y * w * 4;
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
uint32_t red = pixels[sindex + 2];
|
||||
uint32_t green = pixels[sindex + 1];
|
||||
uint32_t blue = pixels[sindex];
|
||||
|
||||
if (vid_saturation != 1.0f)
|
||||
{
|
||||
float NewR = (float)(red / 255.f);
|
||||
float NewG = (float)(green / 255.f);
|
||||
float NewB = (float)(blue / 255.f);
|
||||
|
||||
// Apply Saturation
|
||||
// float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750));
|
||||
// Out = luma.xxx + Saturation.xxx * (In - luma.xxx);
|
||||
//float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709
|
||||
float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601
|
||||
NewR = luma + (Saturation * (NewR - luma));
|
||||
NewG = luma + (Saturation * (NewG - luma));
|
||||
NewB = luma + (Saturation * (NewB - luma));
|
||||
|
||||
// Clamp All
|
||||
NewR = clamp<float>(NewR, 0.0f, 1.f);
|
||||
NewG = clamp<float>(NewG, 0.0f, 1.f);
|
||||
NewB = clamp<float>(NewB, 0.0f, 1.f);
|
||||
|
||||
red = (uint32_t)(NewR * 255.f);
|
||||
green = (uint32_t)(NewG * 255.f);
|
||||
blue = (uint32_t)(NewB * 255.f);
|
||||
}
|
||||
|
||||
// Apply Contrast / Brightness / Gamma
|
||||
red = gammatable[red];
|
||||
green = gammatable[green];
|
||||
blue = gammatable[blue];
|
||||
|
||||
ScreenshotBuffer[dindex ] = red;
|
||||
ScreenshotBuffer[dindex + 1] = green;
|
||||
ScreenshotBuffer[dindex + 2] = blue;
|
||||
|
||||
dindex += 3;
|
||||
sindex += 4;
|
||||
}
|
||||
}
|
||||
|
||||
pitch = w * 3;
|
||||
color_type = SS_RGB;
|
||||
gamma = 1.0f;
|
||||
return ScreenshotBuffer;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::BeginFrame()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
CheckCanvas();
|
||||
|
||||
#if 0
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::Draw2D()
|
||||
{
|
||||
::Draw2D(twod, *mRenderState);
|
||||
}
|
||||
|
||||
unsigned int PolyFrameBuffer::GetLightBufferBlockSize() const
|
||||
{
|
||||
return mLights->GetBlockSize();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::UpdateShadowMap()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::AmbientOccludeScene(float m5)
|
||||
{
|
||||
//mPostprocess->AmbientOccludeScene(m5);
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "gl_sysfb.h"
|
||||
#include "r_memory.h"
|
||||
#include "r_thread.h"
|
||||
#include "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(); }
|
||||
PolyCommandBuffer *GetDrawCommands();
|
||||
void FlushDrawCommands();
|
||||
|
||||
unsigned int GetLightBufferBlockSize() const;
|
||||
|
||||
PolyFrameBuffer(void *hMonitor, bool fullscreen);
|
||||
~PolyFrameBuffer();
|
||||
int GetShaderCount() override { return 0; }
|
||||
|
||||
void Update() override;
|
||||
|
||||
bool IsPoly() override { return true; }
|
||||
|
||||
void InitializeState() override;
|
||||
|
||||
FRenderState* RenderState() override;
|
||||
void PrecacheMaterial(FMaterial *mat, int translation) override;
|
||||
void UpdatePalette() override;
|
||||
void SetTextureFilterMode() override;
|
||||
void BeginFrame() override;
|
||||
void BlurScene(float amount) override;
|
||||
void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D) override;
|
||||
void AmbientOccludeScene(float m5) override;
|
||||
//void SetSceneRenderTarget(bool useSSAO) override;
|
||||
|
||||
IHardwareTexture *CreateHardwareTexture(int numchannels) 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:
|
||||
void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc) override;
|
||||
void UpdateShadowMap() override;
|
||||
|
||||
void CheckCanvas();
|
||||
|
||||
IDataBuffer *mLightBuffer = nullptr;
|
||||
|
||||
std::unique_ptr<PolyRenderState> mRenderState;
|
||||
std::unique_ptr<DCanvas> mCanvas;
|
||||
std::unique_ptr<PolyDepthStencil> mDepthStencil;
|
||||
std::unique_ptr<PolyCommandBuffer> mDrawCommands;
|
||||
RenderMemory mFrameMemory;
|
||||
|
||||
struct ScreenQuadVertex
|
||||
{
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
PalEntry color0;
|
||||
|
||||
ScreenQuadVertex() = default;
|
||||
ScreenQuadVertex(float x, float y, float u, float v) : x(x), y(y), z(1.0f), u(u), v(v), color0(0xffffffff) { }
|
||||
};
|
||||
|
||||
struct ScreenQuad
|
||||
{
|
||||
IVertexBuffer* VertexBuffer = nullptr;
|
||||
IIndexBuffer* IndexBuffer = nullptr;
|
||||
} mScreenQuad;
|
||||
|
||||
bool cur_vsync = false;
|
||||
};
|
||||
|
||||
inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast<PolyFrameBuffer*>(screen); }
|
||||
|
||||
// [GEC] Original code of dpJudas, I add the formulas of gamma, brightness, contrast and saturation.
|
||||
class CopyAndApplyGammaCommand : public DrawerCommand
|
||||
{
|
||||
public:
|
||||
CopyAndApplyGammaCommand(void* dest, int destpitch, const void* src, int width, int height, int srcpitch,
|
||||
float gamma, float contrast, float brightness, float saturation) : dest(dest), src(src), destpitch(destpitch), width(width), height(height), srcpitch(srcpitch),
|
||||
gamma(gamma), contrast(contrast), brightness(brightness), saturation(saturation)
|
||||
{
|
||||
}
|
||||
|
||||
void Execute(DrawerThread* thread)
|
||||
{
|
||||
float Saturation = clamp<float>(saturation, -15.0f, 15.f);
|
||||
|
||||
std::vector<uint8_t> gammatablebuf(256);
|
||||
uint8_t* gammatable = gammatablebuf.data();
|
||||
InitGammaTable(gammatable);
|
||||
|
||||
int w = width;
|
||||
int start = thread->skipped_by_thread(0);
|
||||
int count = thread->count_for_thread(0, height);
|
||||
int sstep = thread->num_cores * srcpitch;
|
||||
int dstep = thread->num_cores * destpitch;
|
||||
uint32_t* d = (uint32_t*)dest + start * destpitch;
|
||||
const uint32_t* s = (const uint32_t*)src + start * srcpitch;
|
||||
for (int y = 0; y < count; y++)
|
||||
{
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
uint32_t red = RPART(s[x]);
|
||||
uint32_t green = GPART(s[x]);
|
||||
uint32_t blue = BPART(s[x]);
|
||||
uint32_t alpha = APART(s[x]);
|
||||
|
||||
if (saturation != 1.0f)
|
||||
{
|
||||
float NewR = (float)(red / 255.f);
|
||||
float NewG = (float)(green / 255.f);
|
||||
float NewB = (float)(blue / 255.f);
|
||||
|
||||
// Apply Saturation
|
||||
// float luma = dot(In, float3(0.2126729, 0.7151522, 0.0721750));
|
||||
// Out = luma.xxx + Saturation.xxx * (In - luma.xxx);
|
||||
//float luma = (NewR * 0.2126729f) + (NewG * 0.7151522f) + (NewB * 0.0721750f); // Rec. 709
|
||||
float luma = (NewR * 0.299f) + (NewG * 0.587f) + (NewB * 0.114f); //Rec. 601
|
||||
NewR = luma + (Saturation * (NewR - luma));
|
||||
NewG = luma + (Saturation * (NewG - luma));
|
||||
NewB = luma + (Saturation * (NewB - luma));
|
||||
|
||||
// Clamp All
|
||||
NewR = clamp<float>(NewR, 0.0f, 1.f);
|
||||
NewG = clamp<float>(NewG, 0.0f, 1.f);
|
||||
NewB = clamp<float>(NewB, 0.0f, 1.f);
|
||||
|
||||
red = (uint32_t)(NewR * 255.f);
|
||||
green = (uint32_t)(NewG * 255.f);
|
||||
blue = (uint32_t)(NewB * 255.f);
|
||||
}
|
||||
|
||||
// Apply Contrast / Brightness / Gamma
|
||||
red = gammatable[red];
|
||||
green = gammatable[green];
|
||||
blue = gammatable[blue];
|
||||
|
||||
d[x] = MAKEARGB(alpha, (uint8_t)red, (uint8_t)green, (uint8_t)blue);
|
||||
}
|
||||
d += dstep;
|
||||
s += sstep;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void InitGammaTable(uint8_t *gammatable)
|
||||
{
|
||||
float InvGamma = 1.0f / clamp<float>(gamma, 0.1f, 4.f);
|
||||
float Brightness = clamp<float>(brightness, -0.8f, 0.8f);
|
||||
float Contrast = clamp<float>(contrast, 0.1f, 3.f);
|
||||
|
||||
for (int x = 0; x < 256; x++)
|
||||
{
|
||||
float ramp = (float)(x / 255.f);
|
||||
|
||||
// Apply Contrast
|
||||
// vec4 finalColor = vec4((((originalColor.rgb - vec3(0.5)) * Contrast) + vec3(0.5)), 1.0);
|
||||
if (contrast != 1.0f)
|
||||
ramp = (((ramp - 0.5f) * Contrast) + 0.5f);
|
||||
|
||||
// Apply Brightness
|
||||
// vec4 finalColor = vec4(originalColor.rgb + Brightness, 1.0);
|
||||
if (brightness != 0.0f)
|
||||
ramp += (Brightness / 2.0f);
|
||||
|
||||
// Apply Gamma
|
||||
// FragColor.rgb = pow(fragColor.rgb, vec3(1.0/gamma));
|
||||
if (gamma != 1.0f)
|
||||
ramp = pow(ramp, InvGamma);
|
||||
|
||||
// Clamp ramp
|
||||
ramp = clamp<float>(ramp, 0.0f, 1.f);
|
||||
|
||||
gammatable[x] = (uint8_t)(ramp * 255);
|
||||
}
|
||||
}
|
||||
|
||||
void* dest;
|
||||
const void* src;
|
||||
int destpitch;
|
||||
int width;
|
||||
int height;
|
||||
int srcpitch;
|
||||
float gamma;
|
||||
float contrast;
|
||||
float brightness;
|
||||
float saturation;
|
||||
};
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 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 "c_cvars.h"
|
||||
#include "hw_material.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "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));
|
||||
}
|
||||
}
|
||||
|
||||
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, 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())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef LoadImage
|
||||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
#define SHADED_TEXTURE -1
|
||||
#define DIRECT_PALETTE -2
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hw_ihwtexture.h"
|
||||
#include "volk/volk.h"
|
||||
|
||||
struct FMaterialState;
|
||||
class PolyBuffer;
|
||||
|
||||
class PolyHardwareTexture : public IHardwareTexture
|
||||
{
|
||||
public:
|
||||
PolyHardwareTexture();
|
||||
~PolyHardwareTexture();
|
||||
|
||||
static void ResetAll();
|
||||
void Reset();
|
||||
|
||||
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, 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;
|
||||
};
|
|
@ -1,451 +0,0 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 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 "polyrenderer/backend/poly_renderstate.h"
|
||||
#include "polyrenderer/backend/poly_framebuffer.h"
|
||||
#include "polyrenderer/backend/poly_hwtexture.h"
|
||||
|
||||
#include "hw_skydome.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_clock.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "hwrenderer/data/shaderuniforms.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 || mNeedApply)
|
||||
Apply();
|
||||
|
||||
mDrawCommands->Draw(index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
void PolyRenderState::DrawIndexed(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply || mNeedApply)
|
||||
Apply();
|
||||
|
||||
mDrawCommands->DrawIndexed(index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
bool PolyRenderState::SetDepthClamp(bool on)
|
||||
{
|
||||
bool lastValue = mDepthClamp;
|
||||
mDepthClamp = on;
|
||||
mNeedApply = true;
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthMask(bool on)
|
||||
{
|
||||
mDepthMask = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthFunc(int func)
|
||||
{
|
||||
mDepthFunc = func;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthRange(float min, float max)
|
||||
{
|
||||
mDepthRangeMin = min;
|
||||
mDepthRangeMax = max;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
mColorMask[0] = r;
|
||||
mColorMask[1] = g;
|
||||
mColorMask[2] = b;
|
||||
mColorMask[3] = a;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetStencil(int offs, int op, int flags)
|
||||
{
|
||||
mStencilValue = screen->stencilValue + offs;
|
||||
mStencilOp = op;
|
||||
mNeedApply = true;
|
||||
|
||||
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)
|
||||
{
|
||||
mCulling = mode;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableClipDistance(int num, bool state)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::Clear(int targets)
|
||||
{
|
||||
if (mNeedApply)
|
||||
Apply();
|
||||
|
||||
//if (targets & CT_Color)
|
||||
// mDrawCommands->ClearColor();
|
||||
if (targets & CT_Depth)
|
||||
mDrawCommands->ClearDepth(65535.0f);
|
||||
if (targets & CT_Stencil)
|
||||
mDrawCommands->ClearStencil(0);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableStencil(bool on)
|
||||
{
|
||||
mStencilEnabled = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
if (w < 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = mRenderTarget.Canvas->GetWidth();
|
||||
h = mRenderTarget.Canvas->GetHeight();
|
||||
}
|
||||
mScissor.x = x;
|
||||
mScissor.y = mRenderTarget.Canvas->GetHeight() - y - h;
|
||||
mScissor.width = w;
|
||||
mScissor.height = h;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
mViewport.x = x;
|
||||
mViewport.y = mRenderTarget.Canvas->GetHeight() - y - h;
|
||||
mViewport.width = w;
|
||||
mViewport.height = h;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDepthTest(bool on)
|
||||
{
|
||||
mDepthTest = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableMultisampling(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableLineSmooth(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDrawBuffers(int count, bool apply)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::SetColormapShader(bool enable)
|
||||
{
|
||||
mNeedApply = true;
|
||||
mColormapShader = enable;
|
||||
}
|
||||
|
||||
void PolyRenderState::EndRenderPass()
|
||||
{
|
||||
mDrawCommands = nullptr;
|
||||
mNeedApply = true;
|
||||
mFirstMatrixApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::Apply()
|
||||
{
|
||||
drawcalls.Clock();
|
||||
|
||||
if (!mDrawCommands)
|
||||
{
|
||||
mDrawCommands = GetPolyFrameBuffer()->GetDrawCommands();
|
||||
}
|
||||
|
||||
if (mNeedApply)
|
||||
{
|
||||
mDrawCommands->SetViewport(mViewport.x, mViewport.y, mViewport.width, mViewport.height, mRenderTarget.Canvas, mRenderTarget.DepthStencil, mRenderTarget.TopDown);
|
||||
mDrawCommands->SetScissor(mScissor.x, mScissor.y, mScissor.width, mScissor.height);
|
||||
mDrawCommands->SetViewpointUniforms(mViewpointUniforms);
|
||||
mDrawCommands->SetDepthClamp(mDepthClamp);
|
||||
mDrawCommands->SetDepthMask(mDepthTest && mDepthMask);
|
||||
mDrawCommands->SetDepthFunc(mDepthTest ? mDepthFunc : DF_Always);
|
||||
mDrawCommands->SetDepthRange(mDepthRangeMin, mDepthRangeMax);
|
||||
mDrawCommands->SetStencil(mStencilValue, mStencilOp);
|
||||
mDrawCommands->EnableStencil(mStencilEnabled);
|
||||
mDrawCommands->SetCulling(mCulling);
|
||||
mDrawCommands->SetColorMask(mColorMask[0], mColorMask[1], mColorMask[2], mColorMask[3]);
|
||||
mNeedApply = false;
|
||||
}
|
||||
|
||||
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)
|
||||
SetVertexBuffer(screen->mVertexData);
|
||||
|
||||
if (mVertexBuffer)
|
||||
{
|
||||
mDrawCommands->SetVertexBuffer(mVertexBuffer->Memory(), mVertexOffsets[0], mVertexOffsets[1]); // [GEC] Add offset params
|
||||
}
|
||||
if (mIndexBuffer) mDrawCommands->SetIndexBuffer(mIndexBuffer->Memory());
|
||||
mDrawCommands->SetInputAssembly(static_cast<PolyVertexBuffer*>(mVertexBuffer)->VertexFormat);
|
||||
mDrawCommands->SetRenderStyle(mRenderStyle);
|
||||
|
||||
if (mColormapShader)
|
||||
{
|
||||
mDrawCommands->SetShader(EFF_NONE, 0, false, true);
|
||||
}
|
||||
else if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
mDrawCommands->SetShader(mSpecialEffect, 0, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0);
|
||||
mDrawCommands->SetShader(EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, false);
|
||||
}
|
||||
|
||||
if (mMaterial.mMaterial && mMaterial.mMaterial->Source())
|
||||
mStreamData.timer = static_cast<float>((double)(screen->FrameTime - firstFrame) * (double)mMaterial.mMaterial->Source()->GetShaderSpeed() / 1000.);
|
||||
else
|
||||
mStreamData.timer = 0.0f;
|
||||
|
||||
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;
|
||||
constants.uDynLightColor = mStreamData.uDynLightColor; // [GEC]
|
||||
|
||||
mDrawCommands->PushStreamData(mStreamData, constants);
|
||||
ApplyMatrices();
|
||||
|
||||
if (mBias.mChanged)
|
||||
{
|
||||
mDrawCommands->SetDepthBias(mBias.mUnits, mBias.mFactor);
|
||||
mBias.mChanged = false;
|
||||
}
|
||||
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void PolyRenderState::ApplyMaterial()
|
||||
{
|
||||
if (mMaterial.mChanged && mMaterial.mMaterial)
|
||||
{
|
||||
mTempTM = mMaterial.mMaterial->Source()->isHardwareCanvas() ? TM_OPAQUE : TM_NORMAL;
|
||||
|
||||
if (mMaterial.mMaterial->Source()->isHardwareCanvas()) static_cast<FCanvasTexture*>(mMaterial.mMaterial->Source()->GetTexture())->NeedUpdate();
|
||||
|
||||
MaterialLayerInfo* layer;
|
||||
auto base = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation, &layer));
|
||||
if (base)
|
||||
{
|
||||
DCanvas *texcanvas = base->GetImage(layer->layerTexture, mMaterial.mTranslation, layer->scaleFlags);
|
||||
mDrawCommands->SetTexture(0, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), texcanvas->IsBgra());
|
||||
|
||||
int numLayers = mMaterial.mMaterial->NumLayers();
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(i, 0, &layer));
|
||||
|
||||
texcanvas = systex->GetImage(layer->layerTexture, 0, layer->scaleFlags);
|
||||
mDrawCommands->SetTexture(i, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), 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;
|
||||
mDrawCommands->PushMatrices(mMatrices.ModelMatrix, mMatrices.NormalModelMatrix, mMatrices.TextureMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderState::SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown)
|
||||
{
|
||||
mRenderTarget.Canvas = canvas;
|
||||
mRenderTarget.DepthStencil = depthStencil;
|
||||
mRenderTarget.TopDown = topdown;
|
||||
}
|
||||
|
||||
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);
|
||||
mNeedApply = true;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/backend/poly_buffers.h"
|
||||
#include "poly_triangle.h"
|
||||
|
||||
#include "name.h"
|
||||
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_material.h"
|
||||
|
||||
struct HWViewpointUniforms;
|
||||
|
||||
class PolyRenderState final : 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, bool apply) override;
|
||||
|
||||
void SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown);
|
||||
void Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length);
|
||||
PolyVertexInputAssembly *GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs);
|
||||
void EndRenderPass();
|
||||
|
||||
void SetColormapShader(bool enable);
|
||||
|
||||
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;
|
||||
bool TopDown = true;
|
||||
} mRenderTarget;
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
} mScissor, mViewport;
|
||||
|
||||
bool mNeedApply = true;
|
||||
|
||||
bool mDepthTest = false;
|
||||
bool mDepthMask = false;
|
||||
int mDepthFunc = DF_Always;
|
||||
float mDepthRangeMin = 0.0f;
|
||||
float mDepthRangeMax = 1.0f;
|
||||
bool mStencilEnabled = false;
|
||||
int mStencilValue = 0;
|
||||
int mStencilOp = SOP_Keep;
|
||||
int mCulling = Cull_None;
|
||||
bool mColorMask[4] = { true, true, true, true };
|
||||
bool mColormapShader = false;
|
||||
|
||||
PolyCommandBuffer* mDrawCommands = nullptr;
|
||||
};
|
|
@ -1,827 +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 "filesystem.h"
|
||||
#include "v_video.h"
|
||||
#include "model.h"
|
||||
#include "poly_thread.h"
|
||||
#include "screen_triangle.h"
|
||||
|
||||
#ifndef NO_SSE
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
PolyTriangleThreadData::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 PolyTriangleThreadData::ClearDepth(float value)
|
||||
{
|
||||
int width = depthstencil->Width();
|
||||
int height = depthstencil->Height();
|
||||
float *data = depthstencil->DepthValues();
|
||||
|
||||
int skip = skipped_by_thread(0);
|
||||
int count = count_for_thread(0, height);
|
||||
|
||||
data += skip * width;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
data[x] = value;
|
||||
data += num_cores * width;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::ClearStencil(uint8_t value)
|
||||
{
|
||||
int width = depthstencil->Width();
|
||||
int height = depthstencil->Height();
|
||||
uint8_t *data = depthstencil->StencilValues();
|
||||
|
||||
int skip = skipped_by_thread(0);
|
||||
int count = count_for_thread(0, height);
|
||||
|
||||
data += skip * width;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
memset(data, value, width);
|
||||
data += num_cores * width;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, uint8_t *new_dest, int new_dest_width, int new_dest_height, int new_dest_pitch, bool new_dest_bgra, PolyDepthStencil *new_depthstencil, bool new_topdown)
|
||||
{
|
||||
viewport_x = x;
|
||||
viewport_y = y;
|
||||
viewport_width = width;
|
||||
viewport_height = height;
|
||||
dest = new_dest;
|
||||
dest_width = new_dest_width;
|
||||
dest_height = new_dest_height;
|
||||
dest_pitch = new_dest_pitch;
|
||||
dest_bgra = new_dest_bgra;
|
||||
depthstencil = new_depthstencil;
|
||||
topdown = new_topdown;
|
||||
UpdateClip();
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
scissor.left = x;
|
||||
scissor.right = x + w;
|
||||
scissor.top = y;
|
||||
scissor.bottom = y + h;
|
||||
UpdateClip();
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::UpdateClip()
|
||||
{
|
||||
clip.left = max(max(viewport_x, scissor.left), 0);
|
||||
clip.top = max(max(viewport_y, scissor.top), 0);
|
||||
clip.right = min(min(viewport_x + viewport_width, scissor.right), dest_width);
|
||||
clip.bottom = min(min(viewport_y + viewport_height, scissor.bottom), dest_height);
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::PushStreamData(const StreamData &data, const PolyPushConstants &constants)
|
||||
{
|
||||
mainVertexShader.Data = data;
|
||||
mainVertexShader.uClipSplit = constants.uClipSplit;
|
||||
|
||||
PushConstants = &constants;
|
||||
|
||||
AlphaThreshold = clamp((int)(PushConstants->uAlphaThreshold * 255.0f + 0.5f), 0, 255) << 24;
|
||||
|
||||
numPolyLights = 0;
|
||||
if (constants.uLightIndex >= 0)
|
||||
{
|
||||
const FVector4 &lightRange = lights[constants.uLightIndex];
|
||||
static_assert(sizeof(FVector4) == 16, "sizeof(FVector4) is not 16 bytes");
|
||||
if (lightRange.Y > lightRange.X)
|
||||
{
|
||||
int start = constants.uLightIndex + 1;
|
||||
int modulatedStart = static_cast<int>(lightRange.X) + start;
|
||||
int modulatedEnd = static_cast<int>(lightRange.Y) + start;
|
||||
for (int i = modulatedStart; i < modulatedEnd; i += 4)
|
||||
{
|
||||
if (numPolyLights == maxPolyLights)
|
||||
break;
|
||||
|
||||
auto &lightpos = lights[i];
|
||||
auto &lightcolor = lights[i + 1];
|
||||
//auto &lightspot1 = lights[i + 2];
|
||||
//auto &lightspot2 = lights[i + 3];
|
||||
uint32_t r = (int)clamp(lightcolor.X * 255.0f, 0.0f, 255.0f);
|
||||
uint32_t g = (int)clamp(lightcolor.Y * 255.0f, 0.0f, 255.0f);
|
||||
uint32_t b = (int)clamp(lightcolor.Z * 255.0f, 0.0f, 255.0f);
|
||||
|
||||
auto& polylight = polyLights[numPolyLights++];
|
||||
polylight.x = lightpos.X;
|
||||
polylight.y = lightpos.Y;
|
||||
polylight.z = lightpos.Z;
|
||||
polylight.radius = 256.0f / lightpos.W;
|
||||
polylight.color = (r << 16) | (g << 8) | b;
|
||||
if (lightcolor.W < 0.0f)
|
||||
polylight.radius = -polylight.radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix)
|
||||
{
|
||||
mainVertexShader.ModelMatrix = modelMatrix;
|
||||
mainVertexShader.NormalModelMatrix = normalModelMatrix;
|
||||
mainVertexShader.TextureMatrix = textureMatrix;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetViewpointUniforms(const HWViewpointUniforms *uniforms)
|
||||
{
|
||||
mainVertexShader.Viewpoint = uniforms;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetDepthClamp(bool on)
|
||||
{
|
||||
DepthClamp = on;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetDepthMask(bool on)
|
||||
{
|
||||
WriteDepth = on;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetDepthFunc(int func)
|
||||
{
|
||||
if (func == DF_LEqual || func == DF_Less)
|
||||
{
|
||||
DepthTest = true;
|
||||
}
|
||||
else // if (func == DF_Always)
|
||||
{
|
||||
DepthTest = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetDepthRange(float min, float max)
|
||||
{
|
||||
DepthRangeStart = min;
|
||||
DepthRangeScale = max - min;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor)
|
||||
{
|
||||
depthbias = (float)(depthBiasConstantFactor / 2500.0);
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
WriteColor = r;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetStencil(int stencilRef, int op)
|
||||
{
|
||||
StencilTestValue = stencilRef;
|
||||
if (op == SOP_Increment)
|
||||
{
|
||||
StencilWriteValue = min(stencilRef + 1, (int)255);
|
||||
}
|
||||
else if (op == SOP_Decrement)
|
||||
{
|
||||
StencilWriteValue = max(stencilRef - 1, (int)0);
|
||||
}
|
||||
else // SOP_Keep
|
||||
{
|
||||
StencilWriteValue = stencilRef;
|
||||
}
|
||||
|
||||
WriteStencil = StencilTest && (StencilTestValue != StencilWriteValue);
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetCulling(int mode)
|
||||
{
|
||||
SetTwoSided(mode == Cull_None);
|
||||
SetCullCCW(mode == Cull_CCW);
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::EnableStencil(bool on)
|
||||
{
|
||||
StencilTest = on;
|
||||
WriteStencil = on && (StencilTestValue != StencilWriteValue);
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetRenderStyle(FRenderStyle style)
|
||||
{
|
||||
RenderStyle = style;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader)
|
||||
{
|
||||
SpecialEffect = specialEffect;
|
||||
EffectState = effectState;
|
||||
AlphaTest = alphaTest;
|
||||
ColormapShader = colormapShader;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::SetTexture(int unit, const void *pixels, int width, int height, bool bgra)
|
||||
{
|
||||
textures[unit].pixels = pixels;
|
||||
textures[unit].width = width;
|
||||
textures[unit].height = height;
|
||||
textures[unit].bgra = bgra;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::DrawIndexed(int index, int vcount, PolyDrawMode drawmode)
|
||||
{
|
||||
if (vcount < 3)
|
||||
return;
|
||||
|
||||
elements += index;
|
||||
|
||||
ShadedTriVertex vertbuffer[3];
|
||||
ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] };
|
||||
if (drawmode == PolyDrawMode::Triangles)
|
||||
{
|
||||
for (int i = 0; i < vcount / 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
*vert[j] = ShadeVertex(*(elements++));
|
||||
DrawShadedTriangle(vert, ccw);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::TriangleFan)
|
||||
{
|
||||
*vert[0] = ShadeVertex(*(elements++));
|
||||
*vert[1] = ShadeVertex(*(elements++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
*vert[2] = ShadeVertex(*(elements++));
|
||||
DrawShadedTriangle(vert, ccw);
|
||||
std::swap(vert[1], vert[2]);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::TriangleStrip)
|
||||
{
|
||||
bool toggleccw = ccw;
|
||||
*vert[0] = ShadeVertex(*(elements++));
|
||||
*vert[1] = ShadeVertex(*(elements++));
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
*vert[2] = ShadeVertex(*(elements++));
|
||||
DrawShadedTriangle(vert, toggleccw);
|
||||
ShadedTriVertex *vtmp = vert[0];
|
||||
vert[0] = vert[1];
|
||||
vert[1] = vert[2];
|
||||
vert[2] = vtmp;
|
||||
toggleccw = !toggleccw;
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::Lines)
|
||||
{
|
||||
for (int i = 0; i < vcount / 2; i++)
|
||||
{
|
||||
*vert[0] = ShadeVertex(*(elements++));
|
||||
*vert[1] = ShadeVertex(*(elements++));
|
||||
DrawShadedLine(vert);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::Points)
|
||||
{
|
||||
for (int i = 0; i < vcount; i++)
|
||||
{
|
||||
*vert[0] = ShadeVertex(*(elements++));
|
||||
DrawShadedPoint(vert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::Draw(int index, int vcount, PolyDrawMode drawmode)
|
||||
{
|
||||
if (vcount < 3)
|
||||
return;
|
||||
|
||||
int vinput = index;
|
||||
|
||||
ShadedTriVertex vertbuffer[3];
|
||||
ShadedTriVertex *vert[3] = { &vertbuffer[0], &vertbuffer[1], &vertbuffer[2] };
|
||||
if (drawmode == PolyDrawMode::Triangles)
|
||||
{
|
||||
for (int i = 0; i < vcount / 3; i++)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
*vert[j] = ShadeVertex(vinput++);
|
||||
DrawShadedTriangle(vert, ccw);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::TriangleFan)
|
||||
{
|
||||
*vert[0] = ShadeVertex(vinput++);
|
||||
*vert[1] = ShadeVertex(vinput++);
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
*vert[2] = ShadeVertex(vinput++);
|
||||
DrawShadedTriangle(vert, ccw);
|
||||
std::swap(vert[1], vert[2]);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::TriangleStrip)
|
||||
{
|
||||
bool toggleccw = ccw;
|
||||
*vert[0] = ShadeVertex(vinput++);
|
||||
*vert[1] = ShadeVertex(vinput++);
|
||||
for (int i = 2; i < vcount; i++)
|
||||
{
|
||||
*vert[2] = ShadeVertex(vinput++);
|
||||
DrawShadedTriangle(vert, toggleccw);
|
||||
ShadedTriVertex *vtmp = vert[0];
|
||||
vert[0] = vert[1];
|
||||
vert[1] = vert[2];
|
||||
vert[2] = vtmp;
|
||||
toggleccw = !toggleccw;
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::Lines)
|
||||
{
|
||||
for (int i = 0; i < vcount / 2; i++)
|
||||
{
|
||||
*vert[0] = ShadeVertex(vinput++);
|
||||
*vert[1] = ShadeVertex(vinput++);
|
||||
DrawShadedLine(vert);
|
||||
}
|
||||
}
|
||||
else if (drawmode == PolyDrawMode::Points)
|
||||
{
|
||||
for (int i = 0; i < vcount; i++)
|
||||
{
|
||||
*vert[0] = ShadeVertex(vinput++);
|
||||
DrawShadedPoint(vert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShadedTriVertex PolyTriangleThreadData::ShadeVertex(int index)
|
||||
{
|
||||
inputAssembly->Load(this, vertices, frame0, frame1, index);
|
||||
mainVertexShader.SIMPLE = (SpecialEffect == EFF_BURN) || (SpecialEffect == EFF_STENCIL);
|
||||
mainVertexShader.SPHEREMAP = (SpecialEffect == EFF_SPHEREMAP);
|
||||
mainVertexShader.main();
|
||||
return mainVertexShader;
|
||||
}
|
||||
|
||||
bool PolyTriangleThreadData::IsDegenerate(const ShadedTriVertex *const* vert)
|
||||
{
|
||||
// A degenerate triangle has a zero cross product for two of its sides.
|
||||
float ax = vert[1]->gl_Position.X - vert[0]->gl_Position.X;
|
||||
float ay = vert[1]->gl_Position.Y - vert[0]->gl_Position.Y;
|
||||
float az = vert[1]->gl_Position.W - vert[0]->gl_Position.W;
|
||||
float bx = vert[2]->gl_Position.X - vert[0]->gl_Position.X;
|
||||
float by = vert[2]->gl_Position.Y - vert[0]->gl_Position.Y;
|
||||
float bz = vert[2]->gl_Position.W - vert[0]->gl_Position.W;
|
||||
float crossx = ay * bz - az * by;
|
||||
float crossy = az * bx - ax * bz;
|
||||
float crossz = ax * by - ay * bx;
|
||||
float crosslengthsqr = crossx * crossx + crossy * crossy + crossz * crossz;
|
||||
return crosslengthsqr <= 1.e-8f;
|
||||
}
|
||||
|
||||
bool PolyTriangleThreadData::IsFrontfacing(TriDrawTriangleArgs *args)
|
||||
{
|
||||
float a =
|
||||
args->v1->x * args->v2->y - args->v2->x * args->v1->y +
|
||||
args->v2->x * args->v3->y - args->v3->x * args->v2->y +
|
||||
args->v3->x * args->v1->y - args->v1->x * args->v3->y;
|
||||
return a <= 0.0f;
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::DrawShadedPoint(const ShadedTriVertex *const* vertex)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::DrawShadedLine(const ShadedTriVertex *const* vert)
|
||||
{
|
||||
static const int numclipdistances = 9;
|
||||
float clipdistance[numclipdistances * 2];
|
||||
float *clipd = clipdistance;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const auto &v = *vert[i];
|
||||
clipd[0] = v.gl_Position.X + v.gl_Position.W;
|
||||
clipd[1] = v.gl_Position.W - v.gl_Position.X;
|
||||
clipd[2] = v.gl_Position.Y + v.gl_Position.W;
|
||||
clipd[3] = v.gl_Position.W - v.gl_Position.Y;
|
||||
if (DepthClamp)
|
||||
{
|
||||
clipd[4] = 1.0f;
|
||||
clipd[5] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipd[4] = v.gl_Position.Z + v.gl_Position.W;
|
||||
clipd[5] = v.gl_Position.W - v.gl_Position.Z;
|
||||
}
|
||||
clipd[6] = v.gl_ClipDistance[0];
|
||||
clipd[7] = v.gl_ClipDistance[1];
|
||||
clipd[8] = v.gl_ClipDistance[2];
|
||||
clipd += numclipdistances;
|
||||
}
|
||||
|
||||
float t1 = 0.0f;
|
||||
float t2 = 1.0f;
|
||||
for (int p = 0; p < numclipdistances; p++)
|
||||
{
|
||||
float clipdistance1 = clipdistance[0 * numclipdistances + p];
|
||||
float clipdistance2 = clipdistance[1 * numclipdistances + p];
|
||||
if (clipdistance1 < 0.0f) t1 = max(-clipdistance1 / (clipdistance2 - clipdistance1), t1);
|
||||
if (clipdistance2 < 0.0f) t2 = min(1.0f + clipdistance2 / (clipdistance1 - clipdistance2), t2);
|
||||
if (t1 >= t2)
|
||||
return;
|
||||
}
|
||||
|
||||
float weights[] = { 1.0f - t1, t1, 1.0f - t2, t2 };
|
||||
|
||||
ScreenTriVertex clippedvert[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
auto &v = clippedvert[i];
|
||||
memset(&v, 0, sizeof(ScreenTriVertex));
|
||||
for (int w = 0; w < 2; w++)
|
||||
{
|
||||
float weight = weights[i * 2 + w];
|
||||
v.x += vert[w]->gl_Position.X * weight;
|
||||
v.y += vert[w]->gl_Position.Y * weight;
|
||||
v.z += vert[w]->gl_Position.Z * weight;
|
||||
v.w += vert[w]->gl_Position.W * weight;
|
||||
}
|
||||
|
||||
// Calculate normalized device coordinates:
|
||||
v.w = 1.0f / v.w;
|
||||
v.x *= v.w;
|
||||
v.y *= v.w;
|
||||
v.z *= v.w;
|
||||
|
||||
// Apply viewport scale to get screen coordinates:
|
||||
v.x = viewport_x + viewport_width * (1.0f + v.x) * 0.5f;
|
||||
if (topdown)
|
||||
v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f;
|
||||
else
|
||||
v.y = viewport_y + viewport_height * (1.0f + v.y) * 0.5f;
|
||||
}
|
||||
|
||||
uint32_t vColorA = (int)(vert[0]->vColor.W * 255.0f + 0.5f);
|
||||
uint32_t vColorR = (int)(vert[0]->vColor.X * 255.0f + 0.5f);
|
||||
uint32_t vColorG = (int)(vert[0]->vColor.Y * 255.0f + 0.5f);
|
||||
uint32_t vColorB = (int)(vert[0]->vColor.Z * 255.0f + 0.5f);
|
||||
uint32_t color = MAKEARGB(vColorA, vColorR, vColorG, vColorB);
|
||||
|
||||
// Slow and naive implementation. Hopefully fast enough..
|
||||
|
||||
float x1 = clippedvert[0].x;
|
||||
float y1 = clippedvert[0].y;
|
||||
float x2 = clippedvert[1].x;
|
||||
float y2 = clippedvert[1].y;
|
||||
float dx = x2 - x1;
|
||||
float dy = y2 - y1;
|
||||
float step = (abs(dx) >= abs(dy)) ? abs(dx) : abs(dy);
|
||||
dx /= step;
|
||||
dy /= step;
|
||||
float x = x1;
|
||||
float y = y1;
|
||||
int istep = (int)step;
|
||||
int pixelsize = dest_bgra ? 4 : 1;
|
||||
for (int i = 0; i <= istep; i++)
|
||||
{
|
||||
int scrx = (int)x;
|
||||
int scry = (int)y;
|
||||
if (scrx >= clip.left && scrx < clip.right && scry >= clip.top && scry < clip.bottom && !line_skipped_by_thread(scry))
|
||||
{
|
||||
uint8_t *destpixel = dest + (scrx + scry * dest_width) * pixelsize;
|
||||
if (pixelsize == 4)
|
||||
{
|
||||
*reinterpret_cast<uint32_t*>(destpixel) = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
*destpixel = color;
|
||||
}
|
||||
}
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyTriangleThreadData::DrawShadedTriangle(const ShadedTriVertex *const* vert, bool ccw)
|
||||
{
|
||||
// Reject triangle if degenerate
|
||||
if (IsDegenerate(vert))
|
||||
return;
|
||||
|
||||
// Cull, clip and generate additional vertices as needed
|
||||
ScreenTriVertex clippedvert[max_additional_vertices];
|
||||
int numclipvert = ClipEdge(vert);
|
||||
|
||||
// Convert barycentric weights to actual vertices
|
||||
for (int i = 0; i < numclipvert; i++)
|
||||
{
|
||||
auto &v = clippedvert[i];
|
||||
memset(&v, 0, sizeof(ScreenTriVertex));
|
||||
for (int w = 0; w < 3; w++)
|
||||
{
|
||||
float weight = weights[i * 3 + w];
|
||||
v.x += vert[w]->gl_Position.X * weight;
|
||||
v.y += vert[w]->gl_Position.Y * weight;
|
||||
v.z += vert[w]->gl_Position.Z * weight;
|
||||
v.w += vert[w]->gl_Position.W * weight;
|
||||
v.u += vert[w]->vTexCoord.X * weight;
|
||||
v.v += vert[w]->vTexCoord.Y * weight;
|
||||
v.worldX += vert[w]->pixelpos.X * weight;
|
||||
v.worldY += vert[w]->pixelpos.Y * weight;
|
||||
v.worldZ += vert[w]->pixelpos.Z * weight;
|
||||
v.a += vert[w]->vColor.W * weight;
|
||||
v.r += vert[w]->vColor.X * weight;
|
||||
v.g += vert[w]->vColor.Y * weight;
|
||||
v.b += vert[w]->vColor.Z * weight;
|
||||
v.gradientdistZ += vert[w]->gradientdist.Z * weight;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_SSE
|
||||
// Map to 2D viewport:
|
||||
for (int j = 0; j < numclipvert; j++)
|
||||
{
|
||||
auto &v = clippedvert[j];
|
||||
|
||||
// Calculate normalized device coordinates:
|
||||
v.w = 1.0f / v.w;
|
||||
v.x *= v.w;
|
||||
v.y *= v.w;
|
||||
v.z *= v.w;
|
||||
|
||||
// Apply viewport scale to get screen coordinates:
|
||||
v.x = viewport_x + viewport_width * (1.0f + v.x) * 0.5f;
|
||||
if (topdown)
|
||||
v.y = viewport_y + viewport_height * (1.0f - v.y) * 0.5f;
|
||||
else
|
||||
v.y = viewport_y + viewport_height * (1.0f + v.y) * 0.5f;
|
||||
}
|
||||
#else
|
||||
// Map to 2D viewport:
|
||||
__m128 mviewport_x = _mm_set1_ps((float)viewport_x);
|
||||
__m128 mviewport_y = _mm_set1_ps((float)viewport_y);
|
||||
__m128 mviewport_halfwidth = _mm_set1_ps(viewport_width * 0.5f);
|
||||
__m128 mviewport_halfheight = _mm_set1_ps(viewport_height * 0.5f);
|
||||
__m128 mone = _mm_set1_ps(1.0f);
|
||||
int sse_length = (numclipvert + 3) / 4 * 4;
|
||||
for (int j = 0; j < sse_length; j += 4)
|
||||
{
|
||||
__m128 vx = _mm_loadu_ps(&clippedvert[j].x);
|
||||
__m128 vy = _mm_loadu_ps(&clippedvert[j + 1].x);
|
||||
__m128 vz = _mm_loadu_ps(&clippedvert[j + 2].x);
|
||||
__m128 vw = _mm_loadu_ps(&clippedvert[j + 3].x);
|
||||
_MM_TRANSPOSE4_PS(vx, vy, vz, vw);
|
||||
|
||||
// Calculate normalized device coordinates:
|
||||
vw = _mm_div_ps(mone, vw);
|
||||
vx = _mm_mul_ps(vx, vw);
|
||||
vy = _mm_mul_ps(vy, vw);
|
||||
vz = _mm_mul_ps(vz, vw);
|
||||
|
||||
// Apply viewport scale to get screen coordinates:
|
||||
vx = _mm_add_ps(mviewport_x, _mm_mul_ps(mviewport_halfwidth, _mm_add_ps(mone, vx)));
|
||||
if (topdown)
|
||||
vy = _mm_add_ps(mviewport_y, _mm_mul_ps(mviewport_halfheight, _mm_sub_ps(mone, vy)));
|
||||
else
|
||||
vy = _mm_add_ps(mviewport_y, _mm_mul_ps(mviewport_halfheight, _mm_add_ps(mone, vy)));
|
||||
|
||||
_MM_TRANSPOSE4_PS(vx, vy, vz, vw);
|
||||
_mm_storeu_ps(&clippedvert[j].x, vx);
|
||||
_mm_storeu_ps(&clippedvert[j + 1].x, vy);
|
||||
_mm_storeu_ps(&clippedvert[j + 2].x, vz);
|
||||
_mm_storeu_ps(&clippedvert[j + 3].x, vw);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!topdown) ccw = !ccw;
|
||||
|
||||
TriDrawTriangleArgs args;
|
||||
|
||||
if (twosided && numclipvert > 2)
|
||||
{
|
||||
args.v1 = &clippedvert[0];
|
||||
args.v2 = &clippedvert[1];
|
||||
args.v3 = &clippedvert[2];
|
||||
ccw = !IsFrontfacing(&args);
|
||||
}
|
||||
|
||||
// Draw screen triangles
|
||||
if (ccw)
|
||||
{
|
||||
for (int i = numclipvert - 1; i > 1; i--)
|
||||
{
|
||||
args.v1 = &clippedvert[numclipvert - 1];
|
||||
args.v2 = &clippedvert[i - 1];
|
||||
args.v3 = &clippedvert[i - 2];
|
||||
if (IsFrontfacing(&args) == ccw && args.CalculateGradients())
|
||||
{
|
||||
ScreenTriangle::Draw(&args, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 2; i < numclipvert; i++)
|
||||
{
|
||||
args.v1 = &clippedvert[0];
|
||||
args.v2 = &clippedvert[i - 1];
|
||||
args.v3 = &clippedvert[i];
|
||||
if (IsFrontfacing(&args) != ccw && args.CalculateGradients())
|
||||
{
|
||||
ScreenTriangle::Draw(&args, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PolyTriangleThreadData::ClipEdge(const ShadedTriVertex *const* verts)
|
||||
{
|
||||
// use barycentric weights for clipped vertices
|
||||
weights = weightsbuffer;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
weights[i * 3 + 0] = 0.0f;
|
||||
weights[i * 3 + 1] = 0.0f;
|
||||
weights[i * 3 + 2] = 0.0f;
|
||||
weights[i * 3 + i] = 1.0f;
|
||||
}
|
||||
|
||||
// Clip and cull so that the following is true for all vertices:
|
||||
// -v.w <= v.x <= v.w
|
||||
// -v.w <= v.y <= v.w
|
||||
// -v.w <= v.z <= v.w
|
||||
|
||||
// halfspace clip distances
|
||||
static const int numclipdistances = 9;
|
||||
#ifdef NO_SSE
|
||||
float clipdistance[numclipdistances * 3];
|
||||
bool needsclipping = false;
|
||||
float *clipd = clipdistance;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const auto &v = *verts[i];
|
||||
clipd[0] = v.gl_Position.X + v.gl_Position.W;
|
||||
clipd[1] = v.gl_Position.W - v.gl_Position.X;
|
||||
clipd[2] = v.gl_Position.Y + v.gl_Position.W;
|
||||
clipd[3] = v.gl_Position.W - v.gl_Position.Y;
|
||||
if (DepthClamp)
|
||||
{
|
||||
clipd[4] = 1.0f;
|
||||
clipd[5] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipd[4] = v.gl_Position.Z + v.gl_Position.W;
|
||||
clipd[5] = v.gl_Position.W - v.gl_Position.Z;
|
||||
}
|
||||
clipd[6] = v.gl_ClipDistance[0];
|
||||
clipd[7] = v.gl_ClipDistance[1];
|
||||
clipd[8] = v.gl_ClipDistance[2];
|
||||
for (int j = 0; j < 9; j++)
|
||||
needsclipping = needsclipping || clipd[i];
|
||||
clipd += numclipdistances;
|
||||
}
|
||||
|
||||
// If all halfspace clip distances are positive then the entire triangle is visible. Skip the expensive clipping step.
|
||||
if (!needsclipping)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
#else
|
||||
__m128 mx = _mm_loadu_ps(&verts[0]->gl_Position.X);
|
||||
__m128 my = _mm_loadu_ps(&verts[1]->gl_Position.X);
|
||||
__m128 mz = _mm_loadu_ps(&verts[2]->gl_Position.X);
|
||||
__m128 mw = _mm_setzero_ps();
|
||||
_MM_TRANSPOSE4_PS(mx, my, mz, mw);
|
||||
__m128 clipd0 = _mm_add_ps(mx, mw);
|
||||
__m128 clipd1 = _mm_sub_ps(mw, mx);
|
||||
__m128 clipd2 = _mm_add_ps(my, mw);
|
||||
__m128 clipd3 = _mm_sub_ps(mw, my);
|
||||
__m128 clipd4 = DepthClamp ? _mm_set1_ps(1.0f) : _mm_add_ps(mz, mw);
|
||||
__m128 clipd5 = DepthClamp ? _mm_set1_ps(1.0f) : _mm_sub_ps(mw, mz);
|
||||
__m128 clipd6 = _mm_setr_ps(verts[0]->gl_ClipDistance[0], verts[1]->gl_ClipDistance[0], verts[2]->gl_ClipDistance[0], 0.0f);
|
||||
__m128 clipd7 = _mm_setr_ps(verts[0]->gl_ClipDistance[1], verts[1]->gl_ClipDistance[1], verts[2]->gl_ClipDistance[1], 0.0f);
|
||||
__m128 clipd8 = _mm_setr_ps(verts[0]->gl_ClipDistance[2], verts[1]->gl_ClipDistance[2], verts[2]->gl_ClipDistance[2], 0.0f);
|
||||
__m128 mneedsclipping = _mm_cmplt_ps(clipd0, _mm_setzero_ps());
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd1, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd2, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd3, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd4, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd5, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd6, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd7, _mm_setzero_ps()));
|
||||
mneedsclipping = _mm_or_ps(mneedsclipping, _mm_cmplt_ps(clipd8, _mm_setzero_ps()));
|
||||
if (_mm_movemask_ps(mneedsclipping) == 0)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
float clipdistance[numclipdistances * 4];
|
||||
_mm_storeu_ps(clipdistance, clipd0);
|
||||
_mm_storeu_ps(clipdistance + 4, clipd1);
|
||||
_mm_storeu_ps(clipdistance + 8, clipd2);
|
||||
_mm_storeu_ps(clipdistance + 12, clipd3);
|
||||
_mm_storeu_ps(clipdistance + 16, clipd4);
|
||||
_mm_storeu_ps(clipdistance + 20, clipd5);
|
||||
_mm_storeu_ps(clipdistance + 24, clipd6);
|
||||
_mm_storeu_ps(clipdistance + 28, clipd7);
|
||||
_mm_storeu_ps(clipdistance + 32, clipd8);
|
||||
#endif
|
||||
|
||||
// Clip against each halfspace
|
||||
float *input = weights;
|
||||
float *output = weights + max_additional_vertices * 3;
|
||||
int inputverts = 3;
|
||||
for (int p = 0; p < numclipdistances; p++)
|
||||
{
|
||||
// Clip each edge
|
||||
int outputverts = 0;
|
||||
for (int i = 0; i < inputverts; i++)
|
||||
{
|
||||
int j = (i + 1) % inputverts;
|
||||
#ifdef NO_SSE
|
||||
float clipdistance1 =
|
||||
clipdistance[0 * numclipdistances + p] * input[i * 3 + 0] +
|
||||
clipdistance[1 * numclipdistances + p] * input[i * 3 + 1] +
|
||||
clipdistance[2 * numclipdistances + p] * input[i * 3 + 2];
|
||||
|
||||
float clipdistance2 =
|
||||
clipdistance[0 * numclipdistances + p] * input[j * 3 + 0] +
|
||||
clipdistance[1 * numclipdistances + p] * input[j * 3 + 1] +
|
||||
clipdistance[2 * numclipdistances + p] * input[j * 3 + 2];
|
||||
#else
|
||||
float clipdistance1 =
|
||||
clipdistance[0 + p * 4] * input[i * 3 + 0] +
|
||||
clipdistance[1 + p * 4] * input[i * 3 + 1] +
|
||||
clipdistance[2 + p * 4] * input[i * 3 + 2];
|
||||
|
||||
float clipdistance2 =
|
||||
clipdistance[0 + p * 4] * input[j * 3 + 0] +
|
||||
clipdistance[1 + p * 4] * input[j * 3 + 1] +
|
||||
clipdistance[2 + p * 4] * input[j * 3 + 2];
|
||||
#endif
|
||||
|
||||
// Clip halfspace
|
||||
if ((clipdistance1 >= 0.0f || clipdistance2 >= 0.0f) && outputverts + 1 < max_additional_vertices)
|
||||
{
|
||||
float t1 = (clipdistance1 < 0.0f) ? max(-clipdistance1 / (clipdistance2 - clipdistance1), 0.0f) : 0.0f;
|
||||
float t2 = (clipdistance2 < 0.0f) ? min(1.0f + clipdistance2 / (clipdistance1 - clipdistance2), 1.0f) : 1.0f;
|
||||
|
||||
// add t1 vertex
|
||||
for (int k = 0; k < 3; k++)
|
||||
output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t1) + input[j * 3 + k] * t1;
|
||||
outputverts++;
|
||||
|
||||
if (t2 != 1.0f && t2 > t1)
|
||||
{
|
||||
// add t2 vertex
|
||||
for (int k = 0; k < 3; k++)
|
||||
output[outputverts * 3 + k] = input[i * 3 + k] * (1.0f - t2) + input[j * 3 + k] * t2;
|
||||
outputverts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::swap(input, output);
|
||||
inputverts = outputverts;
|
||||
if (inputverts == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
weights = input;
|
||||
return inputverts;
|
||||
}
|
||||
|
||||
PolyTriangleThreadData *PolyTriangleThreadData::Get(DrawerThread *thread)
|
||||
{
|
||||
if (!thread->poly)
|
||||
thread->poly = std::make_unique<PolyTriangleThreadData>(thread->core, thread->num_cores, thread->numa_node, thread->num_numa_nodes, thread->numa_start_y, thread->numa_end_y);
|
||||
return thread->poly.get();
|
||||
}
|
|
@ -1,204 +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_triangle.h"
|
||||
|
||||
struct PolyLight
|
||||
{
|
||||
uint32_t color;
|
||||
float x, y, z;
|
||||
float radius;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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, PolyDepthStencil *depthstencil, bool topdown);
|
||||
|
||||
void SetCullCCW(bool value) { ccw = value; }
|
||||
void SetTwoSided(bool value) { twosided = value; }
|
||||
|
||||
void SetInputAssembly(PolyInputAssembly *input) { inputAssembly = input; }
|
||||
void SetVertexBuffer(const void *data, int offset0, int offset1) { vertices = data; frame0 = offset0; frame1 = offset1;} //[GEC] Save frame params
|
||||
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 EnableStencil(bool on);
|
||||
void SetScissor(int x, int y, int w, int h);
|
||||
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, bool colormapShader);
|
||||
|
||||
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;
|
||||
int32_t numa_node;
|
||||
int32_t num_numa_nodes;
|
||||
|
||||
int numa_start_y;
|
||||
int numa_end_y;
|
||||
|
||||
bool line_skipped_by_thread(int line)
|
||||
{
|
||||
return line < numa_start_y || line >= numa_end_y || line % num_cores != core;
|
||||
}
|
||||
|
||||
int skipped_by_thread(int first_line)
|
||||
{
|
||||
int clip_first_line = max(first_line, numa_start_y);
|
||||
int core_skip = (num_cores - (clip_first_line - core) % num_cores) % num_cores;
|
||||
return clip_first_line + core_skip - first_line;
|
||||
}
|
||||
|
||||
int count_for_thread(int first_line, int count)
|
||||
{
|
||||
count = min(count, numa_end_y - first_line);
|
||||
int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores;
|
||||
return max(c, 0);
|
||||
}
|
||||
|
||||
struct Scanline
|
||||
{
|
||||
float W[MAXWIDTH];
|
||||
uint16_t U[MAXWIDTH];
|
||||
uint16_t V[MAXWIDTH];
|
||||
float WorldX[MAXWIDTH];
|
||||
float WorldY[MAXWIDTH];
|
||||
float WorldZ[MAXWIDTH];
|
||||
uint8_t vColorA[MAXWIDTH];
|
||||
uint8_t vColorR[MAXWIDTH];
|
||||
uint8_t vColorG[MAXWIDTH];
|
||||
uint8_t vColorB[MAXWIDTH];
|
||||
float GradientdistZ[MAXWIDTH];
|
||||
uint32_t FragColor[MAXWIDTH];
|
||||
uint32_t lightarray[MAXWIDTH];
|
||||
uint8_t discard[MAXWIDTH];
|
||||
} scanline;
|
||||
|
||||
static PolyTriangleThreadData *Get(DrawerThread *thread);
|
||||
|
||||
int dest_pitch = 0;
|
||||
int dest_width = 0;
|
||||
int dest_height = 0;
|
||||
bool dest_bgra = false;
|
||||
uint8_t *dest = nullptr;
|
||||
PolyDepthStencil *depthstencil = nullptr;
|
||||
bool topdown = true;
|
||||
|
||||
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;
|
||||
bool ColormapShader = false;
|
||||
uint32_t AlphaThreshold = 0x7f000000;
|
||||
const PolyPushConstants* PushConstants = nullptr;
|
||||
|
||||
// [GEC] Add frame params, necessary to project frames and model interpolation correctly
|
||||
int frame0 = 0;
|
||||
int frame1 = 0;
|
||||
|
||||
const void *vertices = nullptr;
|
||||
const unsigned int *elements = nullptr;
|
||||
const FVector4 *lights = nullptr;
|
||||
|
||||
enum { maxPolyLights = 16 };
|
||||
PolyLight polyLights[maxPolyLights];
|
||||
int numPolyLights = 0;
|
||||
|
||||
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;
|
||||
float DepthRangeStart = 0.0f;
|
||||
float DepthRangeScale = 1.0f;
|
||||
bool DepthClamp = true;
|
||||
|
||||
void (*FragmentShader)(int x0, int x1, PolyTriangleThreadData* thread) = nullptr;
|
||||
void (*WriteColorFunc)(int y, int x0, int x1, PolyTriangleThreadData* thread) = nullptr;
|
||||
|
||||
private:
|
||||
ShadedTriVertex ShadeVertex(int index);
|
||||
void DrawShadedPoint(const ShadedTriVertex *const* vertex);
|
||||
void DrawShadedLine(const ShadedTriVertex *const* vertices);
|
||||
void DrawShadedTriangle(const ShadedTriVertex *const* vertices, bool ccw);
|
||||
static bool IsDegenerate(const ShadedTriVertex *const* vertices);
|
||||
static bool IsFrontfacing(TriDrawTriangleArgs *args);
|
||||
|
||||
int ClipEdge(const ShadedTriVertex *const* verts);
|
||||
|
||||
int viewport_x = 0;
|
||||
int viewport_width = 0;
|
||||
int viewport_height = 0;
|
||||
bool ccw = true;
|
||||
bool twosided = true;
|
||||
PolyInputAssembly *inputAssembly = nullptr;
|
||||
|
||||
enum { max_additional_vertices = 16 };
|
||||
float weightsbuffer[max_additional_vertices * 3 * 2];
|
||||
float *weights = nullptr;
|
||||
};
|
|
@ -1,469 +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 "filesystem.h"
|
||||
#include "v_video.h"
|
||||
#include "model.h"
|
||||
#include "poly_triangle.h"
|
||||
#include "poly_thread.h"
|
||||
#include "screen_triangle.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PolyDrawerCommand : public DrawerCommand
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class PolySetDepthClampCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetDepthClampCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthClamp(on); }
|
||||
|
||||
private:
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetDepthMaskCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetDepthMaskCommand(bool on) : on(on) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthMask(on); }
|
||||
|
||||
private:
|
||||
bool on;
|
||||
};
|
||||
|
||||
class PolySetDepthFuncCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetDepthFuncCommand(int func) : func(func) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthFunc(func); }
|
||||
|
||||
private:
|
||||
int func;
|
||||
};
|
||||
|
||||
class PolySetDepthRangeCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetDepthRangeCommand(float min, float max) : min(min), max(max) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthRange(min, max); }
|
||||
|
||||
private:
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
|
||||
class PolySetDepthBiasCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetDepthBiasCommand(float depthBiasConstantFactor, float depthBiasSlopeFactor) : depthBiasConstantFactor(depthBiasConstantFactor), depthBiasSlopeFactor(depthBiasSlopeFactor) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetDepthBias(depthBiasConstantFactor, depthBiasSlopeFactor); }
|
||||
|
||||
private:
|
||||
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 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 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, bool colormapShader) : specialEffect(specialEffect), effectState(effectState), alphaTest(alphaTest), colormapShader(colormapShader) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetShader(specialEffect, effectState, alphaTest, colormapShader); }
|
||||
|
||||
private:
|
||||
int specialEffect;
|
||||
int effectState;
|
||||
bool alphaTest;
|
||||
bool colormapShader;
|
||||
};
|
||||
|
||||
class PolySetVertexBufferCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetVertexBufferCommand(const void* vertices, int offset0, int offset1) : vertices(vertices), offset0(offset0), offset1(offset1){ }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetVertexBuffer(vertices, offset0, offset1); }
|
||||
|
||||
private:
|
||||
const void* vertices;
|
||||
// [GEC] Add offset params, necessary to project frames and model interpolation correctly
|
||||
int offset0;
|
||||
int offset1;
|
||||
};
|
||||
|
||||
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) : value(value) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->ClearStencil(value); }
|
||||
|
||||
private:
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
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, PolyDepthStencil* depthstencil, bool topdown)
|
||||
: 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), topdown(topdown) { }
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetViewport(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil, topdown); }
|
||||
|
||||
private:
|
||||
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;
|
||||
bool topdown;
|
||||
};
|
||||
|
||||
class PolySetViewpointUniformsCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
PolySetViewpointUniformsCommand(const HWViewpointUniforms* uniforms) : uniforms(uniforms) {}
|
||||
void Execute(DrawerThread* thread) override { PolyTriangleThreadData::Get(thread)->SetViewpointUniforms(uniforms); }
|
||||
|
||||
private:
|
||||
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 PolyDrawIndexedCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
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:
|
||||
int index;
|
||||
int count;
|
||||
PolyDrawMode mode;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyCommandBuffer::PolyCommandBuffer(RenderMemory* frameMemory)
|
||||
{
|
||||
mQueue = std::make_shared<DrawerCommandQueue>(frameMemory);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetViewport(int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthstencil, bool topdown)
|
||||
{
|
||||
uint8_t *dest = (uint8_t*)canvas->GetPixels();
|
||||
int dest_width = canvas->GetWidth();
|
||||
int dest_height = canvas->GetHeight();
|
||||
int dest_pitch = canvas->GetPitch();
|
||||
bool dest_bgra = canvas->IsBgra();
|
||||
|
||||
mQueue->Push<PolySetViewportCommand>(x, y, width, height, dest, dest_width, dest_height, dest_pitch, dest_bgra, depthstencil, topdown);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetInputAssembly(PolyInputAssembly *input)
|
||||
{
|
||||
mQueue->Push<PolySetInputAssemblyCommand>(input);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetVertexBuffer(const void *vertices, int offset0, int offset1)
|
||||
{
|
||||
mQueue->Push<PolySetVertexBufferCommand>(vertices, offset0, offset1);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetIndexBuffer(const void *elements)
|
||||
{
|
||||
mQueue->Push<PolySetIndexBufferCommand>(elements);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetLightBuffer(const void *lights)
|
||||
{
|
||||
mQueue->Push<PolySetLightBufferCommand>(lights);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetDepthClamp(bool on)
|
||||
{
|
||||
mQueue->Push<PolySetDepthClampCommand>(on);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetDepthMask(bool on)
|
||||
{
|
||||
mQueue->Push<PolySetDepthMaskCommand>(on);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetDepthFunc(int func)
|
||||
{
|
||||
mQueue->Push<PolySetDepthFuncCommand>(func);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetDepthRange(float min, float max)
|
||||
{
|
||||
mQueue->Push<PolySetDepthRangeCommand>(min, max);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor)
|
||||
{
|
||||
mQueue->Push<PolySetDepthBiasCommand>(depthBiasConstantFactor, depthBiasSlopeFactor);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
mQueue->Push<PolySetColorMaskCommand>(r, g, b, a);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetStencil(int stencilRef, int op)
|
||||
{
|
||||
mQueue->Push<PolySetStencilCommand>(stencilRef, op);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetCulling(int mode)
|
||||
{
|
||||
mQueue->Push<PolySetCullingCommand>(mode);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::EnableStencil(bool on)
|
||||
{
|
||||
mQueue->Push<PolyEnableStencilCommand>(on);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
mQueue->Push<PolySetScissorCommand>(x, y, w, h);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetRenderStyle(FRenderStyle style)
|
||||
{
|
||||
mQueue->Push<PolySetRenderStyleCommand>(style);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetTexture(int unit, void *pixels, int width, int height, bool bgra)
|
||||
{
|
||||
mQueue->Push<PolySetTextureCommand>(unit, pixels, width, height, bgra);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader)
|
||||
{
|
||||
mQueue->Push<PolySetShaderCommand>(specialEffect, effectState, alphaTest, colormapShader);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::PushStreamData(const StreamData &data, const PolyPushConstants &constants)
|
||||
{
|
||||
mQueue->Push<PolyPushStreamDataCommand>(data, constants);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix)
|
||||
{
|
||||
mQueue->Push<PolyPushMatricesCommand>(modelMatrix, normalModelMatrix, textureMatrix);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::SetViewpointUniforms(const HWViewpointUniforms *uniforms)
|
||||
{
|
||||
mQueue->Push<PolySetViewpointUniformsCommand>(uniforms);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::ClearDepth(float value)
|
||||
{
|
||||
mQueue->Push<PolyClearDepthCommand>(value);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::ClearStencil(uint8_t value)
|
||||
{
|
||||
mQueue->Push<PolyClearStencilCommand>(value);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::Draw(int index, int vcount, PolyDrawMode mode)
|
||||
{
|
||||
mQueue->Push<PolyDrawCommand>(index, vcount, mode);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::DrawIndexed(int index, int count, PolyDrawMode mode)
|
||||
{
|
||||
mQueue->Push<PolyDrawIndexedCommand>(index, count, mode);
|
||||
}
|
||||
|
||||
void PolyCommandBuffer::Submit()
|
||||
{
|
||||
DrawerThreads::Execute(mQueue);
|
||||
}
|
|
@ -1,121 +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/drawers/r_draw.h"
|
||||
#include "r_thread.h"
|
||||
#include "polyrenderer/drawers/screen_triangle.h"
|
||||
#include "polyrenderer/drawers/poly_vertex_shader.h"
|
||||
|
||||
class DCanvas;
|
||||
class RenderMemory;
|
||||
class PolyDrawerCommand;
|
||||
class PolyInputAssembly;
|
||||
class PolyDepthStencil;
|
||||
struct PolyPushConstants;
|
||||
|
||||
enum class PolyDrawMode
|
||||
{
|
||||
Points,
|
||||
Lines,
|
||||
Triangles,
|
||||
TriangleFan,
|
||||
TriangleStrip
|
||||
};
|
||||
|
||||
class PolyCommandBuffer
|
||||
{
|
||||
public:
|
||||
PolyCommandBuffer(RenderMemory* frameMemory);
|
||||
|
||||
void SetViewport(int x, int y, int width, int height, DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown);
|
||||
void SetInputAssembly(PolyInputAssembly *input);
|
||||
void SetVertexBuffer(const void *vertices, int offset0, int offset1); // [GEC] Add offset params
|
||||
void SetIndexBuffer(const void *elements);
|
||||
void SetLightBuffer(const void *lights);
|
||||
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 EnableStencil(bool on);
|
||||
void SetScissor(int x, int y, int w, int h);
|
||||
void SetRenderStyle(FRenderStyle style);
|
||||
void SetTexture(int unit, void *pixels, int width, int height, bool bgra);
|
||||
void SetShader(int specialEffect, int effectState, bool alphaTest, bool colormapShader);
|
||||
void PushStreamData(const StreamData &data, const PolyPushConstants &constants);
|
||||
void PushMatrices(const VSMatrix &modelMatrix, const VSMatrix &normalModelMatrix, const VSMatrix &textureMatrix);
|
||||
void ClearDepth(float value);
|
||||
void ClearStencil(uint8_t value);
|
||||
void Draw(int index, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void DrawIndexed(int index, int count, PolyDrawMode mode = PolyDrawMode::Triangles);
|
||||
void Submit();
|
||||
|
||||
private:
|
||||
std::shared_ptr<DrawerCommandQueue> mQueue;
|
||||
};
|
||||
|
||||
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;
|
||||
FVector2 uClipSplit;
|
||||
|
||||
// Lighting + Fog
|
||||
float uLightLevel;
|
||||
float uFogDensity;
|
||||
float uLightFactor;
|
||||
float uLightDist;
|
||||
int uFogEnabled;
|
||||
|
||||
// dynamic lights
|
||||
int uLightIndex;
|
||||
FVector4 uDynLightColor; // [GEC]
|
||||
};
|
||||
|
||||
class PolyInputAssembly
|
||||
{
|
||||
public:
|
||||
virtual void Load(PolyTriangleThreadData *thread, const void *vertices, int frame0, int frame1, int index) = 0; // [GEC] Add frame params
|
||||
};
|
|
@ -1,194 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "hw_renderstate.h"
|
||||
|
||||
#ifndef NO_SSE
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
class ShadedTriVertex
|
||||
{
|
||||
public:
|
||||
FVector4 gl_Position;
|
||||
float gl_ClipDistance[5];
|
||||
FVector4 vTexCoord;
|
||||
FVector4 vColor;
|
||||
FVector4 pixelpos;
|
||||
//FVector3 glowdist;
|
||||
FVector3 gradientdist;
|
||||
//FVector4 vEyeNormal;
|
||||
FVector4 vWorldNormal;
|
||||
};
|
||||
|
||||
class PolyMainVertexShader : public ShadedTriVertex
|
||||
{
|
||||
public:
|
||||
// Input
|
||||
FVector4 aPosition;
|
||||
FVector2 aTexCoord;
|
||||
FVector4 aColor;
|
||||
FVector4 aVertex2;
|
||||
FVector4 aNormal;
|
||||
FVector4 aNormal2;
|
||||
|
||||
// Defines
|
||||
bool SIMPLE = false;
|
||||
bool SPHEREMAP = false;
|
||||
|
||||
// Uniforms
|
||||
VSMatrix ModelMatrix;
|
||||
VSMatrix NormalModelMatrix;
|
||||
VSMatrix TextureMatrix;
|
||||
StreamData Data;
|
||||
FVector2 uClipSplit;
|
||||
const HWViewpointUniforms *Viewpoint = nullptr;
|
||||
|
||||
void main()
|
||||
{
|
||||
FVector2 parmTexCoord = aTexCoord;
|
||||
FVector4 parmPosition = aPosition;
|
||||
|
||||
FVector4 worldcoord;
|
||||
if (SIMPLE)
|
||||
worldcoord = mul(ModelMatrix, mix(parmPosition, aVertex2, Data.uInterpolationFactor));
|
||||
else
|
||||
worldcoord = mul(ModelMatrix, parmPosition);
|
||||
|
||||
FVector4 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, FVector4(normalize(mix3(aNormal, aNormal2, Data.uInterpolationFactor)), 1.0f));
|
||||
//vEyeNormal = mul(Viewpoint->mNormalViewMatrix, vWorldNormal);
|
||||
}
|
||||
|
||||
if (!SPHEREMAP)
|
||||
{
|
||||
vTexCoord = mul(TextureMatrix, FVector4(parmTexCoord.X, parmTexCoord.Y, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
FVector3 u = normalize3(eyeCoordPos);
|
||||
FVector3 n = normalize3(mul(Viewpoint->mNormalViewMatrix, FVector4(parmTexCoord.X, 0.0f, parmTexCoord.Y, 0.0f)));
|
||||
FVector3 r = reflect(u, n);
|
||||
float m = 2.0f * sqrtf(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;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static FVector3 normalize(const FVector3 &a)
|
||||
{
|
||||
float rcplen = 1.0f / sqrtf(a.X * a.X + a.Y * a.Y + a.Z * a.Z);
|
||||
return FVector3(a.X * rcplen, a.Y * rcplen, a.Z * rcplen);
|
||||
}
|
||||
|
||||
static FVector3 normalize3(const FVector4 &a)
|
||||
{
|
||||
float rcplen = 1.0f / sqrtf(a.X * a.X + a.Y * a.Y + a.Z * a.Z);
|
||||
return FVector3(a.X * rcplen, a.Y * rcplen, a.Z * rcplen);
|
||||
}
|
||||
|
||||
static FVector4 mix(const FVector4 &a, const FVector4 &b, float t)
|
||||
{
|
||||
float invt = 1.0f - t;
|
||||
return FVector4(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 FVector3 mix3(const FVector4 &a, const FVector4 &b, float t)
|
||||
{
|
||||
float invt = 1.0f - t;
|
||||
return FVector3(a.X * invt + b.X * t, a.Y * invt + b.Y * t, a.Z * invt + b.Z * t);
|
||||
}
|
||||
|
||||
static FVector3 reflect(const FVector3 &u, const FVector3 &n)
|
||||
{
|
||||
float d = 2.0f * (n.X * u.X + n.Y * u.Y + n.Z * u.Z);
|
||||
return FVector3(u.X - d * n.X, u.Y - d * n.Y, u.Z - d * n.Z);
|
||||
}
|
||||
|
||||
static FVector4 mul(const VSMatrix &mat, const FVector4 &v)
|
||||
{
|
||||
const float *m = mat.get();
|
||||
|
||||
FVector4 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;
|
||||
}
|
||||
};
|
|
@ -1,627 +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 "screen_blend.h"
|
||||
|
||||
#ifndef NO_SSE
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
static const int shiftTable[] = {
|
||||
0, 0, 0, 0, // STYLEALPHA_Zero
|
||||
0, 0, 0, 0, // STYLEALPHA_One
|
||||
24, 24, 24, 24, // STYLEALPHA_Src
|
||||
24, 24, 24, 24, // STYLEALPHA_InvSrc
|
||||
24, 16, 8, 0, // STYLEALPHA_SrcCol
|
||||
24, 16, 8, 0, // STYLEALPHA_InvSrcCol
|
||||
24, 16, 8, 0, // STYLEALPHA_DstCol
|
||||
24, 16, 8, 0 // STYLEALPHA_InvDstCol
|
||||
};
|
||||
|
||||
#if 1 //#ifndef USE_AVX2
|
||||
template<typename OptT>
|
||||
void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
FRenderStyle style = thread->RenderStyle;
|
||||
|
||||
bool invsrc = style.SrcAlpha & 1;
|
||||
bool invdst = style.DestAlpha & 1;
|
||||
|
||||
const int* shiftsrc = shiftTable + (style.SrcAlpha << 2);
|
||||
const int* shiftdst = shiftTable + (style.DestAlpha << 2);
|
||||
|
||||
uint32_t* dest = (uint32_t*)thread->dest;
|
||||
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int srcSelect = style.SrcAlpha <= STYLEALPHA_One ? 0 : (style.SrcAlpha >= STYLEALPHA_DstCol ? 1 : 2);
|
||||
int dstSelect = style.DestAlpha <= STYLEALPHA_One ? 0 : (style.DestAlpha >= STYLEALPHA_DstCol ? 1 : 2);
|
||||
|
||||
uint32_t inputs[3];
|
||||
inputs[0] = 0;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
inputs[1] = line[x];
|
||||
inputs[2] = fragcolor[x];
|
||||
|
||||
uint32_t srcinput = inputs[srcSelect];
|
||||
uint32_t dstinput = inputs[dstSelect];
|
||||
|
||||
uint32_t out[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// Grab component for scale factors
|
||||
int32_t src = (srcinput >> shiftsrc[i]) & 0xff;
|
||||
int32_t dst = (dstinput >> shiftdst[i]) & 0xff;
|
||||
|
||||
// Inverse if needed
|
||||
if (invsrc) src = 0xff - src;
|
||||
if (invdst) dst = 0xff - dst;
|
||||
|
||||
// Rescale 0-255 to 0-256
|
||||
src = src + (src >> 7);
|
||||
dst = dst + (dst >> 7);
|
||||
|
||||
// Multiply with input
|
||||
src = src * ((inputs[2] >> (24 - (i << 3))) & 0xff);
|
||||
dst = dst * ((inputs[1] >> (24 - (i << 3))) & 0xff);
|
||||
|
||||
// Apply blend operator
|
||||
int32_t val;
|
||||
if (OptT::Flags & SWBLEND_Sub)
|
||||
{
|
||||
val = src - dst;
|
||||
}
|
||||
else if (OptT::Flags & SWBLEND_RevSub)
|
||||
{
|
||||
val = dst - src;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = src + dst;
|
||||
}
|
||||
out[i] = clamp((val + 127) >> 8, 0, 255);
|
||||
}
|
||||
|
||||
line[x] = MAKEARGB(out[0], out[1], out[2], out[3]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename OptT>
|
||||
void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
FRenderStyle style = thread->RenderStyle;
|
||||
|
||||
bool invsrc = style.SrcAlpha & 1;
|
||||
bool invdst = style.DestAlpha & 1;
|
||||
|
||||
__m128i shiftsrc = _mm_loadu_si128((const __m128i*)(shiftTable + (style.SrcAlpha << 2)));
|
||||
__m128i shiftdst = _mm_loadu_si128((const __m128i*)(shiftTable + (style.DestAlpha << 2)));
|
||||
|
||||
uint32_t* dest = (uint32_t*)thread->dest;
|
||||
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int srcSelect = style.SrcAlpha <= STYLEALPHA_One ? 0 : (style.SrcAlpha >= STYLEALPHA_DstCol ? 1 : 2);
|
||||
int dstSelect = style.DestAlpha <= STYLEALPHA_One ? 0 : (style.DestAlpha >= STYLEALPHA_DstCol ? 1 : 2);
|
||||
|
||||
uint32_t inputs[3];
|
||||
inputs[0] = 0;
|
||||
|
||||
__m128i shiftmul = _mm_set_epi32(24, 16, 8, 0);
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
inputs[1] = line[x];
|
||||
inputs[2] = fragcolor[x];
|
||||
|
||||
__m128i srcinput = _mm_set1_epi32(inputs[srcSelect]);
|
||||
__m128i dstinput = _mm_set1_epi32(inputs[dstSelect]);
|
||||
|
||||
// Grab component for scale factors
|
||||
__m128i src = _mm_and_si128(_mm_srlv_epi32(srcinput, shiftsrc), _mm_set1_epi32(0xff));
|
||||
__m128i dst = _mm_and_si128(_mm_srlv_epi32(dstinput, shiftdst), _mm_set1_epi32(0xff));
|
||||
|
||||
// Inverse if needed
|
||||
if (invsrc) src = _mm_sub_epi32(_mm_set1_epi32(0xff), src);
|
||||
if (invdst) dst = _mm_sub_epi32(_mm_set1_epi32(0xff), dst);
|
||||
|
||||
// Rescale 0-255 to 0-256
|
||||
src = _mm_add_epi32(src, _mm_srli_epi32(src, 7));
|
||||
dst = _mm_add_epi32(dst, _mm_srli_epi32(dst, 7));
|
||||
|
||||
// Multiply with input
|
||||
__m128i mulsrc = _mm_and_si128(_mm_srlv_epi32(_mm_set1_epi32(inputs[2]), shiftmul), _mm_set1_epi32(0xff));
|
||||
__m128i muldst = _mm_and_si128(_mm_srlv_epi32(_mm_set1_epi32(inputs[1]), shiftmul), _mm_set1_epi32(0xff));
|
||||
__m128i mulresult = _mm_mullo_epi16(_mm_packs_epi32(src, dst), _mm_packs_epi32(mulsrc, muldst));
|
||||
src = _mm_unpacklo_epi16(mulresult, _mm_setzero_si128());
|
||||
dst = _mm_unpackhi_epi16(mulresult, _mm_setzero_si128());
|
||||
|
||||
// Apply blend operator
|
||||
__m128i val;
|
||||
if (OptT::Flags & SWBLEND_Sub)
|
||||
{
|
||||
val = _mm_sub_epi32(src, dst);
|
||||
}
|
||||
else if (OptT::Flags & SWBLEND_RevSub)
|
||||
{
|
||||
val = _mm_sub_epi32(dst, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = _mm_add_epi32(src, dst);
|
||||
}
|
||||
|
||||
__m128i out = _mm_srli_epi32(_mm_add_epi32(val, _mm_set1_epi32(127)), 8);
|
||||
out = _mm_packs_epi32(out, out);
|
||||
out = _mm_packus_epi16(out, out);
|
||||
line[x] = _mm_cvtsi128_si32(out);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NO_SSE
|
||||
void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* dest = (uint32_t*)thread->dest;
|
||||
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
memcpy(line + x0, fragcolor + x0, (x1 - x0) * sizeof(uint32_t));
|
||||
}
|
||||
#else
|
||||
void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* dest = (uint32_t*)thread->dest;
|
||||
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
int sseend = x0 + ssecount;
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
__m128i v = _mm_loadu_si128((__m128i*) & fragcolor[x]);
|
||||
_mm_storeu_si128((__m128i*) & line[x], v);
|
||||
}
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
line[x] = fragcolor[x];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlendColorAdd_Src_InvSrc(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)&line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)&fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3));
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
__m128i dstscale = _mm_sub_epi16(_mm_set1_epi16(256), srcscale);
|
||||
|
||||
__m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_mullo_epi16(dst, dstscale)), _mm_set1_epi16(127)), 8);
|
||||
_mm_storel_epi64((__m128i*)&line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale = APART(src);
|
||||
srcscale += srcscale >> 7;
|
||||
uint32_t dstscale = 256 - srcscale;
|
||||
|
||||
uint32_t a = ((APART(src) * srcscale + APART(dst) * dstscale) + 127) >> 8;
|
||||
uint32_t r = ((RPART(src) * srcscale + RPART(dst) * dstscale) + 127) >> 8;
|
||||
uint32_t g = ((GPART(src) * srcscale + GPART(dst) * dstscale) + 127) >> 8;
|
||||
uint32_t b = ((BPART(src) * srcscale + BPART(dst) * dstscale) + 127) >> 8;
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorAdd_SrcCol_InvSrcCol(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = src;
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
__m128i dstscale = _mm_sub_epi16(_mm_set1_epi16(256), srcscale);
|
||||
|
||||
__m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_mullo_epi16(dst, dstscale)), _mm_set1_epi16(127)), 8);
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale_a = APART(src);
|
||||
uint32_t srcscale_r = RPART(src);
|
||||
uint32_t srcscale_g = GPART(src);
|
||||
uint32_t srcscale_b = BPART(src);
|
||||
srcscale_a += srcscale_a >> 7;
|
||||
srcscale_r += srcscale_r >> 7;
|
||||
srcscale_g += srcscale_g >> 7;
|
||||
srcscale_b += srcscale_b >> 7;
|
||||
uint32_t dstscale_a = 256 - srcscale_a;
|
||||
uint32_t dstscale_r = 256 - srcscale_r;
|
||||
uint32_t dstscale_g = 256 - srcscale_g;
|
||||
uint32_t dstscale_b = 256 - srcscale_b;
|
||||
|
||||
uint32_t a = ((APART(src) * srcscale_a + APART(dst) * dstscale_a) + 127) >> 8;
|
||||
uint32_t r = ((RPART(src) * srcscale_r + RPART(dst) * dstscale_r) + 127) >> 8;
|
||||
uint32_t g = ((GPART(src) * srcscale_g + GPART(dst) * dstscale_g) + 127) >> 8;
|
||||
uint32_t b = ((BPART(src) * srcscale_b + BPART(dst) * dstscale_b) + 127) >> 8;
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorAdd_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3));
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
|
||||
__m128i out = _mm_add_epi16(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8), dst);
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale = APART(src);
|
||||
srcscale += srcscale >> 7;
|
||||
|
||||
uint32_t a = min<int32_t>((((APART(src) * srcscale) + 127) >> 8) + APART(dst), 255);
|
||||
uint32_t r = min<int32_t>((((RPART(src) * srcscale) + 127) >> 8) + RPART(dst), 255);
|
||||
uint32_t g = min<int32_t>((((GPART(src) * srcscale) + 127) >> 8) + GPART(dst), 255);
|
||||
uint32_t b = min<int32_t>((((BPART(src) * srcscale) + 127) >> 8) + BPART(dst), 255);
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorAdd_SrcCol_One(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = src;
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
|
||||
__m128i out = _mm_add_epi16(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8), dst);
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale_a = APART(src);
|
||||
uint32_t srcscale_r = RPART(src);
|
||||
uint32_t srcscale_g = GPART(src);
|
||||
uint32_t srcscale_b = BPART(src);
|
||||
srcscale_a += srcscale_a >> 7;
|
||||
srcscale_r += srcscale_r >> 7;
|
||||
srcscale_g += srcscale_g >> 7;
|
||||
srcscale_b += srcscale_b >> 7;
|
||||
|
||||
uint32_t a = min<int32_t>((((APART(src) * srcscale_a) + 127) >> 8) + APART(dst), 255);
|
||||
uint32_t r = min<int32_t>((((RPART(src) * srcscale_r) + 127) >> 8) + RPART(dst), 255);
|
||||
uint32_t g = min<int32_t>((((GPART(src) * srcscale_g) + 127) >> 8) + GPART(dst), 255);
|
||||
uint32_t b = min<int32_t>((((BPART(src) * srcscale_b) + 127) >> 8) + BPART(dst), 255);
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorAdd_DstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = dst;
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
|
||||
__m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8);
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale_a = APART(dst);
|
||||
uint32_t srcscale_r = RPART(dst);
|
||||
uint32_t srcscale_g = GPART(dst);
|
||||
uint32_t srcscale_b = BPART(dst);
|
||||
srcscale_a += srcscale_a >> 7;
|
||||
srcscale_r += srcscale_r >> 7;
|
||||
srcscale_g += srcscale_g >> 7;
|
||||
srcscale_b += srcscale_b >> 7;
|
||||
|
||||
uint32_t a = (((APART(src) * srcscale_a) + 127) >> 8);
|
||||
uint32_t r = (((RPART(src) * srcscale_r) + 127) >> 8);
|
||||
uint32_t g = (((GPART(src) * srcscale_g) + 127) >> 8);
|
||||
uint32_t b = (((BPART(src) * srcscale_b) + 127) >> 8);
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorAdd_InvDstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = _mm_sub_epi16(_mm_set1_epi16(255), dst);
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
|
||||
__m128i out = _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8);
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale_a = 255 - APART(dst);
|
||||
uint32_t srcscale_r = 255 - RPART(dst);
|
||||
uint32_t srcscale_g = 255 - GPART(dst);
|
||||
uint32_t srcscale_b = 255 - BPART(dst);
|
||||
srcscale_a += srcscale_a >> 7;
|
||||
srcscale_r += srcscale_r >> 7;
|
||||
srcscale_g += srcscale_g >> 7;
|
||||
srcscale_b += srcscale_b >> 7;
|
||||
|
||||
uint32_t a = (((APART(src) * srcscale_a) + 127) >> 8);
|
||||
uint32_t r = (((RPART(src) * srcscale_r) + 127) >> 8);
|
||||
uint32_t g = (((GPART(src) * srcscale_g) + 127) >> 8);
|
||||
uint32_t b = (((BPART(src) * srcscale_b) + 127) >> 8);
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorRevSub_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~1);
|
||||
sseend = x0 + ssecount;
|
||||
for (int x = x0; x < sseend; x += 2)
|
||||
{
|
||||
__m128i dst = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & line[x]), _mm_setzero_si128());
|
||||
__m128i src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*) & fragcolor[x]), _mm_setzero_si128());
|
||||
|
||||
__m128i srcscale = _mm_shufflehi_epi16(_mm_shufflelo_epi16(src, _MM_SHUFFLE(3, 3, 3, 3)), _MM_SHUFFLE(3, 3, 3, 3));
|
||||
srcscale = _mm_add_epi16(srcscale, _mm_srli_epi16(srcscale, 7));
|
||||
|
||||
__m128i out = _mm_sub_epi16(dst, _mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(src, srcscale), _mm_set1_epi16(127)), 8));
|
||||
_mm_storel_epi64((__m128i*) & line[x], _mm_packus_epi16(out, out));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
uint32_t src = fragcolor[x];
|
||||
|
||||
uint32_t srcscale = APART(src);
|
||||
srcscale += srcscale >> 7;
|
||||
|
||||
uint32_t a = max<int32_t>(APART(dst) - (((APART(src) * srcscale) + 127) >> 8), 0);
|
||||
uint32_t r = max<int32_t>(RPART(dst) - (((RPART(src) * srcscale) + 127) >> 8), 0);
|
||||
uint32_t g = max<int32_t>(GPART(dst) - (((GPART(src) * srcscale) + 127) >> 8), 0);
|
||||
uint32_t b = max<int32_t>(BPART(dst) - (((BPART(src) * srcscale) + 127) >> 8), 0);
|
||||
|
||||
line[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
void BlendColorColormap(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* line = (uint32_t*)thread->dest + y * (ptrdiff_t)thread->dest_pitch;
|
||||
|
||||
// [GEC] I leave the default floating values.
|
||||
float startR = thread->mainVertexShader.Data.uObjectColor.r;
|
||||
float startG = thread->mainVertexShader.Data.uObjectColor.g;
|
||||
float startB = thread->mainVertexShader.Data.uObjectColor.b;
|
||||
float rangeR = thread->mainVertexShader.Data.uAddColor.r - startR;
|
||||
float rangeG = thread->mainVertexShader.Data.uAddColor.g - startG;
|
||||
float rangeB = thread->mainVertexShader.Data.uAddColor.b - startB;
|
||||
|
||||
int sseend = x0;
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t dst = line[x];
|
||||
|
||||
uint32_t a = APART(dst);
|
||||
uint32_t r = RPART(dst);
|
||||
uint32_t g = GPART(dst);
|
||||
uint32_t b = BPART(dst);
|
||||
|
||||
uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8;
|
||||
gray += (gray >> 7); // gray*=256/255
|
||||
|
||||
// [GEC] I use the same method as in shaders using floating values.
|
||||
// This avoids errors in the invulneravility colormap in Doom and Heretic.
|
||||
float fgray = (float)(gray / 255.f);
|
||||
float fr = (startR + (fgray * rangeR)) * 2;
|
||||
float fg = (startG + (fgray * rangeG)) * 2;
|
||||
float fb = (startB + (fgray * rangeB)) * 2;
|
||||
|
||||
fr = clamp<float>(fr, 0.0f, 1.0f);
|
||||
fg = clamp<float>(fg, 0.0f, 1.0f);
|
||||
fb = clamp<float>(fb, 0.0f, 1.0f);
|
||||
|
||||
r = (uint32_t)(fr * 255.f);
|
||||
g = (uint32_t)(fg * 255.f);
|
||||
b = (uint32_t)(fb * 255.f);
|
||||
|
||||
line[x] = MAKEARGB(a, (uint8_t)r, (uint8_t)g, (uint8_t)b);
|
||||
}
|
||||
}
|
||||
|
||||
void SelectWriteColorFunc(PolyTriangleThreadData* thread)
|
||||
{
|
||||
FRenderStyle style = thread->RenderStyle;
|
||||
if (thread->ColormapShader)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorColormap;
|
||||
}
|
||||
else if (style.BlendOp == STYLEOP_Add)
|
||||
{
|
||||
if (style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorOpaque;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_InvSrc)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_Src_InvSrc;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_SrcCol && style.DestAlpha == STYLEALPHA_InvSrcCol)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_SrcCol_InvSrcCol;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_One)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_Src_One;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_SrcCol && style.DestAlpha == STYLEALPHA_One)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_SrcCol_One;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_DstCol && style.DestAlpha == STYLEALPHA_Zero)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_DstCol_Zero;
|
||||
}
|
||||
else if (style.SrcAlpha == STYLEALPHA_InvDstCol && style.DestAlpha == STYLEALPHA_Zero)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorAdd_InvDstCol_Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColor<BlendColorOpt_Add>;
|
||||
}
|
||||
}
|
||||
else if (style.BlendOp == STYLEOP_Sub)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColor<BlendColorOpt_Sub>;
|
||||
}
|
||||
else // if (style.BlendOp == STYLEOP_RevSub)
|
||||
{
|
||||
if (style.SrcAlpha == STYLEALPHA_Src && style.DestAlpha == STYLEALPHA_One)
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColorRevSub_Src_One;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->WriteColorFunc = &BlendColor<BlendColorOpt_RevSub>;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
enum SWBlendColor
|
||||
{
|
||||
SWBLEND_Sub = 1,
|
||||
SWBLEND_RevSub = 2
|
||||
};
|
||||
|
||||
struct BlendColorOpt_Add { static const int Flags = 0; };
|
||||
struct BlendColorOpt_Sub { static const int Flags = 1; };
|
||||
struct BlendColorOpt_RevSub { static const int Flags = 2; };
|
||||
|
||||
template<typename OptT>
|
||||
void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_Src_InvSrc(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_SrcCol_InvSrcCol(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_SrcCol_One(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_DstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorAdd_InvDstCol_Zero(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
void BlendColorRevSub_Src_One(int y, int x0, int x1, PolyTriangleThreadData* thread);
|
||||
|
||||
void SelectWriteColorFunc(PolyTriangleThreadData* thread);
|
|
@ -1,590 +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 "poly_thread.h"
|
||||
#include "screen_scanline_setup.h"
|
||||
#include <cmath>
|
||||
|
||||
#ifndef NO_SSE
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef NO_SSE
|
||||
void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float startX = x0 + (0.5f - args->v1->x);
|
||||
float startY = y + (0.5f - args->v1->y);
|
||||
|
||||
float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY;
|
||||
float stepW = args->gradientX.W;
|
||||
float* w = thread->scanline.W;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
w[x] = 1.0f / posW;
|
||||
posW += stepW;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float startX = x0 + (0.5f - args->v1->x);
|
||||
float startY = y + (0.5f - args->v1->y);
|
||||
|
||||
float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY;
|
||||
float stepW = args->gradientX.W;
|
||||
float* w = thread->scanline.W;
|
||||
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
int sseend = x0 + ssecount;
|
||||
|
||||
__m128 mstepW = _mm_set1_ps(stepW * 4.0f);
|
||||
__m128 mposW = _mm_setr_ps(posW, posW + stepW, posW + stepW + stepW, posW + stepW + stepW + stepW);
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
// One Newton-Raphson iteration for 1/posW
|
||||
__m128 res = _mm_rcp_ps(mposW);
|
||||
__m128 muls = _mm_mul_ps(mposW, _mm_mul_ps(res, res));
|
||||
_mm_storeu_ps(w + x, _mm_sub_ps(_mm_add_ps(res, res), muls));
|
||||
mposW = _mm_add_ps(mposW, mstepW);
|
||||
}
|
||||
|
||||
mstepW = _mm_set_ss(stepW);
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
__m128 res = _mm_rcp_ss(mposW);
|
||||
__m128 muls = _mm_mul_ss(mposW, _mm_mul_ss(res, res));
|
||||
_mm_store_ss(w + x, _mm_sub_ss(_mm_add_ss(res, res), muls));
|
||||
mposW = _mm_add_ss(mposW, mstepW);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void WriteDynLightArray(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int num_lights = thread->numPolyLights;
|
||||
PolyLight* lights = thread->polyLights;
|
||||
|
||||
float worldnormalX = thread->mainVertexShader.vWorldNormal.X;
|
||||
float worldnormalY = thread->mainVertexShader.vWorldNormal.Y;
|
||||
float worldnormalZ = thread->mainVertexShader.vWorldNormal.Z;
|
||||
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
float* worldposX = thread->scanline.WorldX;
|
||||
float* worldposY = thread->scanline.WorldY;
|
||||
float* worldposZ = thread->scanline.WorldZ;
|
||||
|
||||
int sseend = x0;
|
||||
|
||||
#ifndef NO_SSE
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
sseend = x0 + ssecount;
|
||||
|
||||
__m128 mworldnormalX = _mm_set1_ps(worldnormalX);
|
||||
__m128 mworldnormalY = _mm_set1_ps(worldnormalY);
|
||||
__m128 mworldnormalZ = _mm_set1_ps(worldnormalZ);
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
__m128i lit = _mm_loadu_si128((__m128i*)&lightarray[x]);
|
||||
__m128i litlo = _mm_unpacklo_epi8(lit, _mm_setzero_si128());
|
||||
__m128i lithi = _mm_unpackhi_epi8(lit, _mm_setzero_si128());
|
||||
|
||||
for (int i = 0; i < num_lights; i++)
|
||||
{
|
||||
__m128 lightposX = _mm_set1_ps(lights[i].x);
|
||||
__m128 lightposY = _mm_set1_ps(lights[i].y);
|
||||
__m128 lightposZ = _mm_set1_ps(lights[i].z);
|
||||
__m128 light_radius = _mm_set1_ps(lights[i].radius);
|
||||
__m128i light_color = _mm_shuffle_epi32(_mm_unpacklo_epi8(_mm_cvtsi32_si128(lights[i].color), _mm_setzero_si128()), _MM_SHUFFLE(1, 0, 1, 0));
|
||||
|
||||
__m128 is_attenuated = _mm_cmplt_ps(light_radius, _mm_setzero_ps());
|
||||
light_radius = _mm_andnot_ps(_mm_set1_ps(-0.0f), light_radius); // clear sign bit
|
||||
|
||||
// L = light-pos
|
||||
// dist = sqrt(dot(L, L))
|
||||
// distance_attenuation = 1 - min(dist * (1/radius), 1)
|
||||
__m128 Lx = _mm_sub_ps(lightposX, _mm_loadu_ps(&worldposX[x]));
|
||||
__m128 Ly = _mm_sub_ps(lightposY, _mm_loadu_ps(&worldposY[x]));
|
||||
__m128 Lz = _mm_sub_ps(lightposZ, _mm_loadu_ps(&worldposZ[x]));
|
||||
__m128 dist2 = _mm_add_ps(_mm_mul_ps(Lx, Lx), _mm_add_ps(_mm_mul_ps(Ly, Ly), _mm_mul_ps(Lz, Lz)));
|
||||
__m128 rcp_dist = _mm_rsqrt_ps(dist2);
|
||||
__m128 dist = _mm_mul_ps(dist2, rcp_dist);
|
||||
__m128 distance_attenuation = _mm_sub_ps(_mm_set1_ps(256.0f), _mm_min_ps(_mm_mul_ps(dist, light_radius), _mm_set1_ps(256.0f)));
|
||||
|
||||
// The simple light type
|
||||
__m128 simple_attenuation = distance_attenuation;
|
||||
|
||||
// The point light type
|
||||
// diffuse = max(dot(N,normalize(L)),0) * attenuation
|
||||
Lx = _mm_mul_ps(Lx, rcp_dist);
|
||||
Ly = _mm_mul_ps(Ly, rcp_dist);
|
||||
Lz = _mm_mul_ps(Lz, rcp_dist);
|
||||
__m128 dotNL = _mm_add_ps(_mm_add_ps(_mm_mul_ps(mworldnormalX, Lx), _mm_mul_ps(mworldnormalY, Ly)), _mm_mul_ps(mworldnormalZ, Lz));
|
||||
__m128 point_attenuation = _mm_mul_ps(_mm_max_ps(dotNL, _mm_setzero_ps()), distance_attenuation);
|
||||
|
||||
__m128i attenuation = _mm_cvtps_epi32(_mm_or_ps(_mm_and_ps(is_attenuated, point_attenuation), _mm_andnot_ps(is_attenuated, simple_attenuation)));
|
||||
|
||||
attenuation = _mm_shufflehi_epi16(_mm_shufflelo_epi16(attenuation, _MM_SHUFFLE(2, 2, 0, 0)), _MM_SHUFFLE(2, 2, 0, 0));
|
||||
__m128i attenlo = _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(1, 1, 0, 0));
|
||||
__m128i attenhi = _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(3, 3, 2, 2));
|
||||
|
||||
litlo = _mm_add_epi16(litlo, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenlo), 8));
|
||||
lithi = _mm_add_epi16(lithi, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenhi), 8));
|
||||
}
|
||||
|
||||
_mm_storeu_si128((__m128i*)&lightarray[x], _mm_packus_epi16(litlo, lithi));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
uint32_t lit_a = APART(lightarray[x]);
|
||||
uint32_t lit_r = RPART(lightarray[x]);
|
||||
uint32_t lit_g = GPART(lightarray[x]);
|
||||
uint32_t lit_b = BPART(lightarray[x]);
|
||||
|
||||
for (int i = 0; i < num_lights; i++)
|
||||
{
|
||||
float lightposX = lights[i].x;
|
||||
float lightposY = lights[i].y;
|
||||
float lightposZ = lights[i].z;
|
||||
float light_radius = lights[i].radius;
|
||||
uint32_t light_color = lights[i].color;
|
||||
|
||||
bool is_attenuated = light_radius < 0.0f;
|
||||
if (is_attenuated)
|
||||
light_radius = -light_radius;
|
||||
|
||||
// L = light-pos
|
||||
// dist = sqrt(dot(L, L))
|
||||
// distance_attenuation = 1 - min(dist * (1/radius), 1)
|
||||
float Lx = lightposX - worldposX[x];
|
||||
float Ly = lightposY - worldposY[x];
|
||||
float Lz = lightposZ - worldposZ[x];
|
||||
float dist2 = Lx * Lx + Ly * Ly + Lz * Lz;
|
||||
#ifdef NO_SSE
|
||||
//float rcp_dist = 1.0f / sqrt(dist2);
|
||||
float rcp_dist = 1.0f / (dist2 * 0.01f);
|
||||
#else
|
||||
float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(dist2)));
|
||||
#endif
|
||||
float dist = dist2 * rcp_dist;
|
||||
float distance_attenuation = 256.0f - min(dist * light_radius, 256.0f);
|
||||
|
||||
// The simple light type
|
||||
float simple_attenuation = distance_attenuation;
|
||||
|
||||
// The point light type
|
||||
// diffuse = max(dot(N,normalize(L)),0) * attenuation
|
||||
Lx *= rcp_dist;
|
||||
Ly *= rcp_dist;
|
||||
Lz *= rcp_dist;
|
||||
float dotNL = worldnormalX * Lx + worldnormalY * Ly + worldnormalZ * Lz;
|
||||
float point_attenuation = max(dotNL, 0.0f) * distance_attenuation;
|
||||
|
||||
uint32_t attenuation = (uint32_t)(is_attenuated ? (int32_t)point_attenuation : (int32_t)simple_attenuation);
|
||||
|
||||
lit_r += (RPART(light_color) * attenuation) >> 8;
|
||||
lit_g += (GPART(light_color) * attenuation) >> 8;
|
||||
lit_b += (BPART(light_color) * attenuation) >> 8;
|
||||
}
|
||||
|
||||
lit_r = min<uint32_t>(lit_r, 255);
|
||||
lit_g = min<uint32_t>(lit_g, 255);
|
||||
lit_b = min<uint32_t>(lit_b, 255);
|
||||
lightarray[x] = MAKEARGB(lit_a, lit_r, lit_g, lit_b);
|
||||
|
||||
// Palette version:
|
||||
// dynlights[x] = RGB256k.All[((lit_r >> 2) << 12) | ((lit_g >> 2) << 6) | (lit_b >> 2)];
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteLightArray(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto constants = thread->PushConstants;
|
||||
|
||||
auto vColorR = thread->scanline.vColorR;
|
||||
auto vColorG = thread->scanline.vColorG;
|
||||
auto vColorB = thread->scanline.vColorB;
|
||||
auto vColorA = thread->scanline.vColorA;
|
||||
|
||||
if (thread->PushConstants->uLightLevel >= 0.0f)
|
||||
{
|
||||
float startX = x0 + (0.5f - args->v1->x);
|
||||
float startY = y + (0.5f - args->v1->y);
|
||||
float posW = args->v1->w + args->gradientX.W * startX + args->gradientY.W * startY;
|
||||
float stepW = args->gradientX.W;
|
||||
|
||||
float globVis = thread->mainVertexShader.Viewpoint->mGlobVis;
|
||||
|
||||
uint32_t light = (int)(constants->uLightLevel * 255.0f);
|
||||
fixed_t shade = (fixed_t)((2.0f - (light + 12.0f) / 128.0f) * (float)FRACUNIT);
|
||||
fixed_t lightpos = (fixed_t)(globVis * posW * (float)FRACUNIT);
|
||||
fixed_t lightstep = (fixed_t)(globVis * stepW * (float)FRACUNIT);
|
||||
|
||||
fixed_t maxvis = 24 * FRACUNIT / 32;
|
||||
fixed_t maxlight = 31 * FRACUNIT / 32;
|
||||
|
||||
fixed_t lightend = lightpos + lightstep * (x1 - x0);
|
||||
if (lightpos < maxvis && shade >= lightpos && shade - lightpos <= maxlight &&
|
||||
lightend < maxvis && shade >= lightend && shade - lightend <= maxlight)
|
||||
{
|
||||
lightpos += FRACUNIT - shade;
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t l = min(lightpos >> 8, 256);
|
||||
|
||||
uint32_t r = vColorR[x];
|
||||
uint32_t g = vColorG[x];
|
||||
uint32_t b = vColorB[x];
|
||||
uint32_t a = vColorA[x];
|
||||
|
||||
// [GEC] DynLightColor On Sprite
|
||||
r = (r * l) >> 8;
|
||||
g = (g * l) >> 8;
|
||||
b = (b * l) >> 8;
|
||||
|
||||
if (constants->uLightIndex == -1)
|
||||
{
|
||||
r += (uint32_t)(constants->uDynLightColor.X * 255.0f);
|
||||
g += (uint32_t)(constants->uDynLightColor.Y * 255.0f);
|
||||
b += (uint32_t)(constants->uDynLightColor.Z * 255.0f);
|
||||
|
||||
r = min<uint32_t>(r, 255);
|
||||
g = min<uint32_t>(g, 255);
|
||||
b = min<uint32_t>(b, 255);
|
||||
}
|
||||
|
||||
lightarray[x] = MAKEARGB(a, r, g, b);
|
||||
lightpos += lightstep;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t l = min((FRACUNIT - clamp<fixed_t>(shade - min(maxvis, lightpos), 0, maxlight)) >> 8, 256);
|
||||
uint32_t r = vColorR[x];
|
||||
uint32_t g = vColorG[x];
|
||||
uint32_t b = vColorB[x];
|
||||
uint32_t a = vColorA[x];
|
||||
|
||||
// [GEC] DynLightColor On Sprite
|
||||
r = (r * l) >> 8;
|
||||
g = (g * l) >> 8;
|
||||
b = (b * l) >> 8;
|
||||
|
||||
if (constants->uLightIndex == -1)
|
||||
{
|
||||
r += (uint32_t)(constants->uDynLightColor.X * 255.0f);
|
||||
g += (uint32_t)(constants->uDynLightColor.Y * 255.0f);
|
||||
b += (uint32_t)(constants->uDynLightColor.Z * 255.0f);
|
||||
|
||||
r = min<uint32_t>(r, 255);
|
||||
g = min<uint32_t>(g, 255);
|
||||
b = min<uint32_t>(b, 255);
|
||||
}
|
||||
|
||||
lightarray[x] = MAKEARGB(a, r, g, b);
|
||||
lightpos += lightstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (constants->uFogEnabled > 0)
|
||||
{
|
||||
float uLightDist = constants->uLightDist;
|
||||
float uLightFactor = constants->uLightFactor;
|
||||
float* w = thread->scanline.W;
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t a = thread->scanline.vColorA[x];
|
||||
uint32_t r = thread->scanline.vColorR[x];
|
||||
uint32_t g = thread->scanline.vColorG[x];
|
||||
uint32_t b = thread->scanline.vColorB[x];
|
||||
|
||||
float fogdist = max(16.0f, w[x]);
|
||||
float fogfactor = std::exp2(constants->uFogDensity * fogdist);
|
||||
|
||||
// brightening around the player for light mode 2:
|
||||
if (fogdist < uLightDist)
|
||||
{
|
||||
uint32_t l = (int)((uLightFactor - (fogdist / uLightDist) * (uLightFactor - 1.0)) * 256.0f);
|
||||
r = (r * l) >> 8;
|
||||
g = (g * l) >> 8;
|
||||
b = (b * l) >> 8;
|
||||
}
|
||||
|
||||
// apply light diminishing through fog equation: mix(vec3(0.0, 0.0, 0.0), lightshade.rgb, fogfactor)
|
||||
uint32_t t = (int)(fogfactor * 256.0f);
|
||||
r = (r * t) >> 8;
|
||||
g = (g * t) >> 8;
|
||||
b = (b * t) >> 8;
|
||||
|
||||
lightarray[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t a = thread->scanline.vColorA[x];
|
||||
uint32_t r = thread->scanline.vColorR[x];
|
||||
uint32_t g = thread->scanline.vColorG[x];
|
||||
uint32_t b = thread->scanline.vColorB[x];
|
||||
|
||||
// [GEC] DynLightColor On Weapon
|
||||
if (constants->uLightIndex == -1)
|
||||
{
|
||||
r += (uint32_t)(constants->uDynLightColor.X * 255.0f);
|
||||
g += (uint32_t)(constants->uDynLightColor.Y * 255.0f);
|
||||
b += (uint32_t)(constants->uDynLightColor.Z * 255.0f);
|
||||
|
||||
r = min<uint32_t>(r, 255);
|
||||
g = min<uint32_t>(g, 255);
|
||||
b = min<uint32_t>(b, 255);
|
||||
}
|
||||
|
||||
lightarray[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_SSE
|
||||
static void WriteVarying(float pos, float step, int x0, int x1, const float* w, float* varying)
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
varying[x] = pos * w[x];
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void WriteVarying(float pos, float step, int x0, int x1, const float* w, float* varying)
|
||||
{
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
int sseend = x0 + ssecount;
|
||||
|
||||
__m128 mstep = _mm_set1_ps(step * 4.0f);
|
||||
__m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step);
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
_mm_storeu_ps(varying + x, _mm_mul_ps(mpos, _mm_loadu_ps(w + x)));
|
||||
mpos = _mm_add_ps(mpos, mstep);
|
||||
}
|
||||
|
||||
pos += ssecount * step;
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
varying[x] = pos * w[x];
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NO_SSE
|
||||
static void WriteVaryingWrap(float pos, float step, int x0, int x1, const float* w, uint16_t* varying)
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
float value = pos * w[x];
|
||||
value = value - std::floor(value);
|
||||
varying[x] = static_cast<uint32_t>(static_cast<int32_t>(value * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void WriteVaryingWrap(float pos, float step, int x0, int x1, const float* w, uint16_t* varying)
|
||||
{
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
int sseend = x0 + ssecount;
|
||||
|
||||
__m128 mstep = _mm_set1_ps(step * 4.0f);
|
||||
__m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step);
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
__m128 value = _mm_mul_ps(mpos, _mm_loadu_ps(w + x));
|
||||
__m128 f = value;
|
||||
__m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));
|
||||
__m128 r = _mm_sub_ps(t, _mm_and_ps(_mm_cmplt_ps(f, t), _mm_set1_ps(1.0f)));
|
||||
value = _mm_sub_ps(f, r);
|
||||
|
||||
__m128i ivalue = _mm_srli_epi32(_mm_slli_epi32(_mm_cvttps_epi32(_mm_mul_ps(value, _mm_set1_ps(static_cast<float>(0x1000'0000)))), 4), 17);
|
||||
_mm_storel_epi64((__m128i*)(varying + x), _mm_slli_epi16(_mm_packs_epi32(ivalue, ivalue), 1));
|
||||
mpos = _mm_add_ps(mpos, mstep);
|
||||
}
|
||||
|
||||
pos += ssecount * step;
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
float value = pos * w[x];
|
||||
__m128 f = _mm_set_ss(value);
|
||||
__m128 t = _mm_cvtepi32_ps(_mm_cvttps_epi32(f));
|
||||
__m128 r = _mm_sub_ss(t, _mm_and_ps(_mm_cmplt_ps(f, t), _mm_set_ss(1.0f)));
|
||||
value = _mm_cvtss_f32(_mm_sub_ss(f, r));
|
||||
|
||||
varying[x] = static_cast<uint32_t>(static_cast<int32_t>(value * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void WriteVaryingWarp1(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float pi2 = 3.14159265358979323846f * 2.0f;
|
||||
float timer = thread->mainVertexShader.Data.timer * 0.125f;
|
||||
|
||||
const float* w = thread->scanline.W;
|
||||
uint16_t* scanlineU = thread->scanline.U;
|
||||
uint16_t* scanlineV = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
float u = posU * w[x];
|
||||
float v = posV * w[x];
|
||||
|
||||
v += (float)g_sin(pi2 * (u + timer)) * 0.1f;
|
||||
u += (float)g_sin(pi2 * (v + timer)) * 0.1f;
|
||||
|
||||
u = u - std::floor(u);
|
||||
v = v - std::floor(v);
|
||||
scanlineU[x] = static_cast<uint32_t>(static_cast<int32_t>(u * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
scanlineV[x] = static_cast<uint32_t>(static_cast<int32_t>(v * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteVaryingWarp2(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float pi2 = 3.14159265358979323846f * 2.0f;
|
||||
float timer = thread->mainVertexShader.Data.timer;
|
||||
|
||||
const float* w = thread->scanline.W;
|
||||
uint16_t* scanlineU = thread->scanline.U;
|
||||
uint16_t* scanlineV = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
float u = posU * w[x];
|
||||
float v = posV * w[x];
|
||||
|
||||
v += (0.5f + (float)g_sin(pi2 * (v + timer * 0.61f + 900.f/8192.f)) + (float)g_sin(pi2 * (u * 2.0f + timer * 0.36f + 300.0f/8192.0f))) * 0.025f;
|
||||
u += (0.5f + (float)g_sin(pi2 * (v + timer * 0.49f + 700.f/8192.f)) + (float)g_sin(pi2 * (u * 2.0f + timer * 0.49f + 1200.0f/8192.0f))) * 0.025f;
|
||||
|
||||
u = u - std::floor(u);
|
||||
v = v - std::floor(v);
|
||||
scanlineU[x] = static_cast<uint32_t>(static_cast<int32_t>(u * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
scanlineV[x] = static_cast<uint32_t>(static_cast<int32_t>(v * static_cast<float>(0x1000'0000)) << 4) >> 16;
|
||||
|
||||
posU += stepU;
|
||||
posV += stepV;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NO_SSE
|
||||
static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying)
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
varying[x] = clamp(static_cast<int>(pos * w[x] * 255.0f), 0, 255);
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void WriteVaryingColor(float pos, float step, int x0, int x1, const float* w, uint8_t* varying)
|
||||
{
|
||||
int ssecount = ((x1 - x0) & ~3);
|
||||
int sseend = x0 + ssecount;
|
||||
|
||||
__m128 mstep = _mm_set1_ps(step * 4.0f);
|
||||
__m128 mpos = _mm_setr_ps(pos, pos + step, pos + step + step, pos + step + step + step);
|
||||
|
||||
for (int x = x0; x < sseend; x += 4)
|
||||
{
|
||||
__m128i value = _mm_cvttps_epi32(_mm_mul_ps(_mm_mul_ps(mpos, _mm_loadu_ps(w + x)), _mm_set1_ps(255.0f)));
|
||||
value = _mm_packs_epi32(value, value);
|
||||
value = _mm_packus_epi16(value, value);
|
||||
*(uint32_t*)(varying + x) = _mm_cvtsi128_si32(value);
|
||||
mpos = _mm_add_ps(mpos, mstep);
|
||||
}
|
||||
|
||||
pos += ssecount * step;
|
||||
for (int x = sseend; x < x1; x++)
|
||||
{
|
||||
varying[x] = clamp(static_cast<int>(pos * w[x] * 255.0f), 0, 255);
|
||||
pos += step;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float startX = x0 + (0.5f - args->v1->x);
|
||||
float startY = y + (0.5f - args->v1->y);
|
||||
|
||||
void (*useShader)(float posU, float posV, float stepU, float stepV, int x0, int x1, PolyTriangleThreadData* thread) = nullptr;
|
||||
|
||||
if (thread->EffectState == SHADER_Warp1)
|
||||
useShader = &WriteVaryingWarp1;
|
||||
else if (thread->EffectState == SHADER_Warp2)
|
||||
useShader = &WriteVaryingWarp2;
|
||||
|
||||
if (useShader)
|
||||
{
|
||||
useShader(
|
||||
args->v1->u * args->v1->w + args->gradientX.U * startX + args->gradientY.U * startY,
|
||||
args->v1->v * args->v1->w + args->gradientX.V * startX + args->gradientY.V * startY,
|
||||
args->gradientX.U,
|
||||
args->gradientX.V,
|
||||
x0, x1,
|
||||
thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteVaryingWrap(args->v1->u * args->v1->w + args->gradientX.U * startX + args->gradientY.U * startY, args->gradientX.U, x0, x1, thread->scanline.W, thread->scanline.U);
|
||||
WriteVaryingWrap(args->v1->v * args->v1->w + args->gradientX.V * startX + args->gradientY.V * startY, args->gradientX.V, x0, x1, thread->scanline.W, thread->scanline.V);
|
||||
}
|
||||
WriteVarying(args->v1->worldX * args->v1->w + args->gradientX.WorldX * startX + args->gradientY.WorldX * startY, args->gradientX.WorldX, x0, x1, thread->scanline.W, thread->scanline.WorldX);
|
||||
WriteVarying(args->v1->worldY * args->v1->w + args->gradientX.WorldY * startX + args->gradientY.WorldY * startY, args->gradientX.WorldY, x0, x1, thread->scanline.W, thread->scanline.WorldY);
|
||||
WriteVarying(args->v1->worldZ * args->v1->w + args->gradientX.WorldZ * startX + args->gradientY.WorldZ * startY, args->gradientX.WorldZ, x0, x1, thread->scanline.W, thread->scanline.WorldZ);
|
||||
WriteVarying(args->v1->gradientdistZ * args->v1->w + args->gradientX.GradientdistZ * startX + args->gradientY.GradientdistZ * startY, args->gradientX.GradientdistZ, x0, x1, thread->scanline.W, thread->scanline.GradientdistZ);
|
||||
WriteVaryingColor(args->v1->a * args->v1->w + args->gradientX.A * startX + args->gradientY.A * startY, args->gradientX.A, x0, x1, thread->scanline.W, thread->scanline.vColorA);
|
||||
WriteVaryingColor(args->v1->r * args->v1->w + args->gradientX.R * startX + args->gradientY.R * startY, args->gradientX.R, x0, x1, thread->scanline.W, thread->scanline.vColorR);
|
||||
WriteVaryingColor(args->v1->g * args->v1->w + args->gradientX.G * startX + args->gradientY.G * startY, args->gradientX.G, x0, x1, thread->scanline.W, thread->scanline.vColorG);
|
||||
WriteVaryingColor(args->v1->b * args->v1->w + args->gradientX.B * startX + args->gradientY.B * startY, args->gradientX.B, x0, x1, thread->scanline.W, thread->scanline.vColorB);
|
||||
|
||||
if (thread->PushConstants->uFogEnabled != -3 && thread->PushConstants->uTextureMode != TM_FOGLAYER)
|
||||
WriteLightArray(y, x0, x1, args, thread);
|
||||
|
||||
if (thread->numPolyLights > 0)
|
||||
WriteDynLightArray(x0, x1, thread);
|
||||
}
|
|
@ -1,29 +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
|
||||
|
||||
struct TriDrawTriangleArgs;
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
||||
void WriteVaryings(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
|
@ -1,637 +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 "poly_thread.h"
|
||||
#include "screen_scanline_setup.h"
|
||||
#include <cmath>
|
||||
|
||||
static uint32_t SampleTexture(uint32_t u, uint32_t v, const void* texPixels, int texWidth, int texHeight, bool texBgra)
|
||||
{
|
||||
int texelX = (u * texWidth) >> 16;
|
||||
int texelY = (v * texHeight) >> 16;
|
||||
int texelOffset = texelX + texelY * texWidth;
|
||||
if (texBgra)
|
||||
{
|
||||
return static_cast<const uint32_t*>(texPixels)[texelOffset];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t c = static_cast<const uint8_t*>(texPixels)[texelOffset];
|
||||
return (c << 16) | 0xff000000;
|
||||
}
|
||||
}
|
||||
|
||||
static void EffectFogBoundary(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float uFogDensity = thread->PushConstants->uFogDensity;
|
||||
uint32_t fogcolor = MAKEARGB(
|
||||
0,
|
||||
static_cast<int>(clamp(thread->mainVertexShader.Data.uFogColor.r, 0.0f, 1.0f) * 255.0f),
|
||||
static_cast<int>(clamp(thread->mainVertexShader.Data.uFogColor.g, 0.0f, 1.0f) * 255.0f),
|
||||
static_cast<int>(clamp(thread->mainVertexShader.Data.uFogColor.b, 0.0f, 1.0f) * 255.0f));
|
||||
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
float fogdist = thread->scanline.W[x];
|
||||
float fogfactor = std::exp2(uFogDensity * fogdist);
|
||||
|
||||
// FragColor = vec4(uFogColor.rgb, 1.0 - fogfactor):
|
||||
uint32_t alpha = static_cast<int>(clamp(1.0f - (1.0f / 255.0f), 0.0f, 1.0f) * 255.0f);
|
||||
fragcolor[x] = fogcolor | alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void EffectBurn(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
|
||||
int tex2Width = thread->textures[1].width;
|
||||
int tex2Height = thread->textures[1].height;
|
||||
const void* tex2Pixels = thread->textures[1].pixels;
|
||||
bool tex2Bgra = thread->textures[1].bgra;
|
||||
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t frag_r = thread->scanline.vColorR[x];
|
||||
uint32_t frag_g = thread->scanline.vColorG[x];
|
||||
uint32_t frag_b = thread->scanline.vColorB[x];
|
||||
uint32_t frag_a = thread->scanline.vColorA[x];
|
||||
frag_r += frag_r >> 7; // 255 -> 256
|
||||
frag_g += frag_g >> 7; // 255 -> 256
|
||||
frag_b += frag_b >> 7; // 255 -> 256
|
||||
frag_a += frag_a >> 7; // 255 -> 256
|
||||
|
||||
uint32_t t1 = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
uint32_t t2 = SampleTexture(u[x], 0xffff - v[x], tex2Pixels, tex2Width, tex2Height, tex2Bgra);
|
||||
|
||||
uint32_t r = (frag_r * RPART(t1)) >> 8;
|
||||
uint32_t g = (frag_g * GPART(t1)) >> 8;
|
||||
uint32_t b = (frag_b * BPART(t1)) >> 8;
|
||||
uint32_t a = (frag_a * APART(t2)) >> 8;
|
||||
|
||||
fragcolor[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
static void EffectStencil(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
/*for (int x = x0; x < x1; x++)
|
||||
{
|
||||
fragcolor[x] = 0x00ffffff;
|
||||
}*/
|
||||
}
|
||||
|
||||
static void FuncPaletted(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
const uint32_t* lut = (const uint32_t*)thread->textures[1].pixels;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
fragcolor[x] = lut[RPART(SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra))] | 0xff000000;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNoTexture(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
uint32_t a = (int)(streamdata.uObjectColor.a * 255.0f);
|
||||
uint32_t r = (int)(streamdata.uObjectColor.r * 255.0f);
|
||||
uint32_t g = (int)(streamdata.uObjectColor.g * 255.0f);
|
||||
uint32_t b = (int)(streamdata.uObjectColor.b * 255.0f);
|
||||
uint32_t texel = MAKEARGB(a, r, g, b);
|
||||
|
||||
if (streamdata.uDesaturationFactor > 0.0f)
|
||||
{
|
||||
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
|
||||
uint32_t inv_t = 256 - t;
|
||||
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
|
||||
texel = MAKEARGB(
|
||||
APART(texel),
|
||||
(RPART(texel) * inv_t + gray * t + 127) >> 8,
|
||||
(GPART(texel) * inv_t + gray * t + 127) >> 8,
|
||||
(BPART(texel) * inv_t + gray * t + 127) >> 8);
|
||||
}
|
||||
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
fragcolor[x] = texel;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
fragcolor[x] = texel;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_Stencil(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
fragcolor[x] = texel | 0x00ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_Opaque(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
fragcolor[x] = texel | 0xff000000;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_Inverse(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
fragcolor[x] = MAKEARGB(APART(texel), 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_AlphaTexture(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
|
||||
uint32_t alpha = APART(texel);
|
||||
alpha += alpha >> 7;
|
||||
alpha = (alpha * gray + 127) >> 8;
|
||||
texel = (alpha << 24) | 0x00ffffff;
|
||||
fragcolor[x] = texel;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_ClampY(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
fragcolor[x] = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
if (v[x] < 0.0 || v[x] > 1.0)
|
||||
fragcolor[x] &= 0x00ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_InvertOpaque(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
int texWidth = thread->textures[0].width;
|
||||
int texHeight = thread->textures[0].height;
|
||||
const void* texPixels = thread->textures[0].pixels;
|
||||
bool texBgra = thread->textures[0].bgra;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint16_t* u = thread->scanline.U;
|
||||
uint16_t* v = thread->scanline.V;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = SampleTexture(u[x], v[x], texPixels, texWidth, texHeight, texBgra);
|
||||
fragcolor[x] = MAKEARGB(0xff, 0xff - RPART(texel), 0xff - BPART(texel), 0xff - GPART(texel));
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_AddColor(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
uint32_t r = (int)(streamdata.uAddColor.r * 255.0f);
|
||||
uint32_t g = (int)(streamdata.uAddColor.g * 255.0f);
|
||||
uint32_t b = (int)(streamdata.uAddColor.b * 255.0f);
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = fragcolor[x];
|
||||
fragcolor[x] = MAKEARGB(
|
||||
APART(texel),
|
||||
min(r + RPART(texel), (uint32_t)255),
|
||||
min(g + GPART(texel), (uint32_t)255),
|
||||
min(b + BPART(texel), (uint32_t)255));
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_AddObjectColor(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
uint32_t r = (int)(streamdata.uObjectColor.r * 256.0f);
|
||||
uint32_t g = (int)(streamdata.uObjectColor.g * 256.0f);
|
||||
uint32_t b = (int)(streamdata.uObjectColor.b * 256.0f);
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = fragcolor[x];
|
||||
fragcolor[x] = MAKEARGB(
|
||||
APART(texel),
|
||||
min((r * RPART(texel)) >> 8, (uint32_t)255),
|
||||
min((g * GPART(texel)) >> 8, (uint32_t)255),
|
||||
min((b * BPART(texel)) >> 8, (uint32_t)255));
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_AddObjectColor2(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
float* gradientdistZ = thread->scanline.GradientdistZ;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
float t = gradientdistZ[x];
|
||||
float inv_t = 1.0f - t;
|
||||
uint32_t r = (int)((streamdata.uObjectColor.r * inv_t + streamdata.uObjectColor2.r * t) * 256.0f);
|
||||
uint32_t g = (int)((streamdata.uObjectColor.g * inv_t + streamdata.uObjectColor2.g * t) * 256.0f);
|
||||
uint32_t b = (int)((streamdata.uObjectColor.b * inv_t + streamdata.uObjectColor2.b * t) * 256.0f);
|
||||
|
||||
uint32_t texel = fragcolor[x];
|
||||
fragcolor[x] = MAKEARGB(
|
||||
APART(texel),
|
||||
min((r * RPART(texel)) >> 8, (uint32_t)255),
|
||||
min((g * GPART(texel)) >> 8, (uint32_t)255),
|
||||
min((b * BPART(texel)) >> 8, (uint32_t)255));
|
||||
}
|
||||
}
|
||||
|
||||
static void FuncNormal_DesaturationFactor(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint32_t t = (int)(streamdata.uDesaturationFactor * 256.0f);
|
||||
uint32_t inv_t = 256 - t;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t texel = fragcolor[x];
|
||||
uint32_t gray = (RPART(texel) * 77 + GPART(texel) * 143 + BPART(texel) * 37) >> 8;
|
||||
fragcolor[x] = MAKEARGB(
|
||||
APART(texel),
|
||||
(RPART(texel) * inv_t + gray * t + 127) >> 8,
|
||||
(GPART(texel) * inv_t + gray * t + 127) >> 8,
|
||||
(BPART(texel) * inv_t + gray * t + 127) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void RunAlphaTest(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t alphaThreshold = thread->AlphaThreshold;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint8_t* discard = thread->scanline.discard;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
discard[x] = fragcolor[x] <= alphaThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessMaterial(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
if (thread->EffectState == SHADER_Paletted) // func_paletted
|
||||
{
|
||||
FuncPaletted(x0, x1, thread);
|
||||
}
|
||||
else if (thread->EffectState == SHADER_NoTexture) // func_notexture
|
||||
{
|
||||
FuncNoTexture(x0, x1, thread);
|
||||
}
|
||||
else // func_normal
|
||||
{
|
||||
auto constants = thread->PushConstants;
|
||||
|
||||
switch (constants->uTextureMode)
|
||||
{
|
||||
default:
|
||||
case TM_NORMAL:
|
||||
case TM_FOGLAYER: FuncNormal(x0, x1, thread); break;
|
||||
case TM_STENCIL: FuncNormal_Stencil(x0, x1, thread); break;
|
||||
case TM_OPAQUE: FuncNormal_Opaque(x0, x1, thread); break;
|
||||
case TM_INVERSE: FuncNormal_Inverse(x0, x1, thread); break;
|
||||
case TM_ALPHATEXTURE: FuncNormal_AlphaTexture(x0, x1, thread); break;
|
||||
case TM_CLAMPY: FuncNormal_ClampY(x0, x1, thread); break;
|
||||
case TM_INVERTOPAQUE: FuncNormal_InvertOpaque(x0, x1, thread); break;
|
||||
}
|
||||
|
||||
if (constants->uTextureMode != TM_FOGLAYER)
|
||||
{
|
||||
auto& streamdata = thread->mainVertexShader.Data;
|
||||
|
||||
if (streamdata.uAddColor.r != 0.0f || streamdata.uAddColor.g != 0.0f || streamdata.uAddColor.b != 0.0f)
|
||||
{
|
||||
FuncNormal_AddColor(x0, x1, thread);
|
||||
}
|
||||
|
||||
if (streamdata.uObjectColor2.a == 0.0f)
|
||||
{
|
||||
if (streamdata.uObjectColor.r != 1.0f || streamdata.uObjectColor.g != 1.0f || streamdata.uObjectColor.b != 1.0f)
|
||||
{
|
||||
FuncNormal_AddObjectColor(x0, x1, thread);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FuncNormal_AddObjectColor2(x0, x1, thread);
|
||||
}
|
||||
|
||||
if (streamdata.uDesaturationFactor > 0.0f)
|
||||
{
|
||||
FuncNormal_DesaturationFactor(x0, x1, thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GetLightColor(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
uint32_t* lightarray = thread->scanline.lightarray;
|
||||
|
||||
if (thread->PushConstants->uFogEnabled >= 0)
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t fg = fragcolor[x];
|
||||
uint32_t lightshade = lightarray[x];
|
||||
|
||||
uint32_t mulA = APART(lightshade);
|
||||
uint32_t mulR = RPART(lightshade);
|
||||
uint32_t mulG = GPART(lightshade);
|
||||
uint32_t mulB = BPART(lightshade);
|
||||
mulA += mulA >> 7;
|
||||
mulR += mulR >> 7;
|
||||
mulG += mulG >> 7;
|
||||
mulB += mulB >> 7;
|
||||
|
||||
uint32_t a = (APART(fg) * mulA + 127) >> 8;
|
||||
uint32_t r = (RPART(fg) * mulR + 127) >> 8;
|
||||
uint32_t g = (GPART(fg) * mulG + 127) >> 8;
|
||||
uint32_t b = (BPART(fg) * mulB + 127) >> 8;
|
||||
|
||||
fragcolor[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t fogR = (int)((thread->mainVertexShader.Data.uFogColor.r) * 255.0f);
|
||||
uint32_t fogG = (int)((thread->mainVertexShader.Data.uFogColor.g) * 255.0f);
|
||||
uint32_t fogB = (int)((thread->mainVertexShader.Data.uFogColor.b) * 255.0f);
|
||||
float uFogDensity = thread->PushConstants->uFogDensity;
|
||||
|
||||
float* w = thread->scanline.W;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t fg = fragcolor[x];
|
||||
uint32_t lightshade = lightarray[x];
|
||||
|
||||
uint32_t mulA = APART(lightshade);
|
||||
uint32_t mulR = RPART(lightshade);
|
||||
uint32_t mulG = GPART(lightshade);
|
||||
uint32_t mulB = BPART(lightshade);
|
||||
mulA += mulA >> 7;
|
||||
mulR += mulR >> 7;
|
||||
mulG += mulG >> 7;
|
||||
mulB += mulB >> 7;
|
||||
|
||||
float fogdist = max(16.0f, w[x]);
|
||||
float fogfactor = std::exp2(uFogDensity * fogdist);
|
||||
|
||||
uint32_t a = (APART(fg) * mulA + 127) >> 8;
|
||||
uint32_t r = (RPART(fg) * mulR + 127) >> 8;
|
||||
uint32_t g = (GPART(fg) * mulG + 127) >> 8;
|
||||
uint32_t b = (BPART(fg) * mulB + 127) >> 8;
|
||||
|
||||
uint32_t t = (int)(fogfactor * 256.0f);
|
||||
uint32_t inv_t = 256 - t;
|
||||
r = (fogR * inv_t + r * t + 127) >> 8;
|
||||
g = (fogG * inv_t + g * t + 127) >> 8;
|
||||
b = (fogB * inv_t + b * t + 127) >> 8;
|
||||
|
||||
fragcolor[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void MainFP(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
ProcessMaterial(x0, x1, thread);
|
||||
|
||||
if (thread->AlphaTest)
|
||||
RunAlphaTest(x0, x1, thread);
|
||||
|
||||
auto constants = thread->PushConstants;
|
||||
if (constants->uFogEnabled != -3)
|
||||
{
|
||||
if (constants->uTextureMode != TM_FOGLAYER)
|
||||
{
|
||||
GetLightColor(x0, x1, thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*float fogdist = 0.0f;
|
||||
float fogfactor = 0.0f;
|
||||
if (constants->uFogEnabled != 0)
|
||||
{
|
||||
fogdist = max(16.0f, w[x]);
|
||||
fogfactor = std::exp2(constants->uFogDensity * fogdist);
|
||||
}
|
||||
frag = vec4(uFogColor.rgb, (1.0 - fogfactor) * frag.a * 0.75 * vColor.a);*/
|
||||
}
|
||||
}
|
||||
else // simple 2D (uses the fog color to add a color overlay)
|
||||
{
|
||||
uint32_t fogR = (int)((thread->mainVertexShader.Data.uFogColor.r) * 255.0f);
|
||||
uint32_t fogG = (int)((thread->mainVertexShader.Data.uFogColor.g) * 255.0f);
|
||||
uint32_t fogB = (int)((thread->mainVertexShader.Data.uFogColor.b) * 255.0f);
|
||||
|
||||
auto vColorR = thread->scanline.vColorR;
|
||||
auto vColorG = thread->scanline.vColorG;
|
||||
auto vColorB = thread->scanline.vColorB;
|
||||
auto vColorA = thread->scanline.vColorA;
|
||||
uint32_t* fragcolor = thread->scanline.FragColor;
|
||||
|
||||
if (constants->uTextureMode == TM_FIXEDCOLORMAP)
|
||||
{
|
||||
// float gray = grayscale(frag);
|
||||
// vec4 cm = (uObjectColor + gray * (uAddColor - uObjectColor)) * 2;
|
||||
// frag = vec4(clamp(cm.rgb, 0.0, 1.0), frag.a);
|
||||
// frag = frag * vColor;
|
||||
// frag.rgb = frag.rgb + uFogColor.rgb;
|
||||
|
||||
// [GEC] I leave the default floating values.
|
||||
float startR = thread->mainVertexShader.Data.uObjectColor.r;
|
||||
float startG = thread->mainVertexShader.Data.uObjectColor.g;
|
||||
float startB = thread->mainVertexShader.Data.uObjectColor.b;
|
||||
float rangeR = thread->mainVertexShader.Data.uAddColor.r - startR;
|
||||
float rangeG = thread->mainVertexShader.Data.uAddColor.g - startG;
|
||||
float rangeB = thread->mainVertexShader.Data.uAddColor.b - startB;
|
||||
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t a = APART(fragcolor[x]);
|
||||
uint32_t r = RPART(fragcolor[x]);
|
||||
uint32_t g = GPART(fragcolor[x]);
|
||||
uint32_t b = BPART(fragcolor[x]);
|
||||
|
||||
uint32_t gray = (r * 77 + g * 143 + b * 37) >> 8;
|
||||
gray += (gray >> 7); // gray*=256/255
|
||||
|
||||
// [GEC] I use the same method as in shaders using floating values.
|
||||
// This avoids errors in the invulneravility colormap in Doom and Heretic.
|
||||
float fgray = (float)(gray / 255.f);
|
||||
float fr = (startR + (fgray * rangeR)) * 2;
|
||||
float fg = (startG + (fgray * rangeG)) * 2;
|
||||
float fb = (startB + (fgray * rangeB)) * 2;
|
||||
|
||||
fr = clamp<float>(fr, 0.0f, 1.0f);
|
||||
fg = clamp<float>(fg, 0.0f, 1.0f);
|
||||
fb = clamp<float>(fb, 0.0f, 1.0f);
|
||||
|
||||
r = (uint32_t)(fr * 255.f);
|
||||
g = (uint32_t)(fg * 255.f);
|
||||
b = (uint32_t)(fb * 255.f);
|
||||
|
||||
fragcolor[x] = MAKEARGB(a, (uint8_t)r, (uint8_t)g, (uint8_t)b);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
uint32_t a = vColorA[x];
|
||||
uint32_t r = vColorR[x];
|
||||
uint32_t g = vColorG[x];
|
||||
uint32_t b = vColorB[x];
|
||||
a += a >> 7;
|
||||
r += r >> 7;
|
||||
g += g >> 7;
|
||||
b += b >> 7;
|
||||
|
||||
// frag = frag * vColor;
|
||||
a = (APART(fragcolor[x]) * a + 127) >> 8;
|
||||
r = (RPART(fragcolor[x]) * r + 127) >> 8;
|
||||
g = (GPART(fragcolor[x]) * g + 127) >> 8;
|
||||
b = (BPART(fragcolor[x]) * b + 127) >> 8;
|
||||
|
||||
// frag.rgb = frag.rgb + uFogColor.rgb;
|
||||
r = min(r + fogR, (uint32_t)255);
|
||||
g = min(g + fogG, (uint32_t)255);
|
||||
b = min(b + fogB, (uint32_t)255);
|
||||
|
||||
fragcolor[x] = MAKEARGB(a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ColormapFP(int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
// This is implemented in BlendColorColormap.
|
||||
}
|
||||
|
||||
void SelectFragmentShader(PolyTriangleThreadData* thread)
|
||||
{
|
||||
void (*fragshader)(int x0, int x1, PolyTriangleThreadData * thread);
|
||||
|
||||
if (thread->ColormapShader)
|
||||
{
|
||||
fragshader = &ColormapFP;
|
||||
}
|
||||
else if (thread->SpecialEffect == EFF_FOGBOUNDARY) // fogboundary.fp
|
||||
{
|
||||
fragshader = &EffectFogBoundary;
|
||||
}
|
||||
else if (thread->SpecialEffect == EFF_BURN) // burn.fp
|
||||
{
|
||||
fragshader = &EffectBurn;
|
||||
}
|
||||
else if (thread->SpecialEffect == EFF_STENCIL) // stencil.fp
|
||||
{
|
||||
fragshader = &EffectStencil;
|
||||
}
|
||||
else
|
||||
{
|
||||
fragshader = &MainFP;
|
||||
}
|
||||
|
||||
thread->FragmentShader = fragshader;
|
||||
}
|
|
@ -1,27 +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
|
||||
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
void SelectFragmentShader(PolyTriangleThreadData* thread);
|
|
@ -1,302 +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 "filesystem.h"
|
||||
#include "v_video.h"
|
||||
#include "poly_triangle.h"
|
||||
#include "screen_triangle.h"
|
||||
#include "screen_blend.h"
|
||||
#include "screen_scanline_setup.h"
|
||||
#include "screen_shader.h"
|
||||
#include <cmath>
|
||||
|
||||
static void WriteDepth(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
float* line = thread->depthstencil->DepthValues() + (size_t)thread->depthstencil->Width() * y;
|
||||
|
||||
if (thread->DepthRangeScale != 0.0f)
|
||||
{
|
||||
float* w = thread->scanline.W;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
line[x] = w[x];
|
||||
}
|
||||
}
|
||||
else // portal fills always uses DepthRangeStart = 1 and DepthRangeScale = 0
|
||||
{
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
line[x] = 65536.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteStencil(int y, int x0, int x1, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint8_t* line = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y;
|
||||
uint8_t value = thread->StencilWriteValue;
|
||||
for (int x = x0; x < x1; x++)
|
||||
{
|
||||
line[x] = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void RunFragmentShader(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
WriteVaryings(y, x0, x1, args, thread);
|
||||
thread->FragmentShader(x0, x1, thread);
|
||||
}
|
||||
|
||||
static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
if (thread->WriteColor || thread->AlphaTest)
|
||||
RunFragmentShader(y, x0, x1, args, thread);
|
||||
|
||||
if (!thread->AlphaTest)
|
||||
{
|
||||
if (thread->WriteColor)
|
||||
thread->WriteColorFunc(y, x0, x1, thread);
|
||||
if (thread->WriteDepth)
|
||||
WriteDepth(y, x0, x1, thread);
|
||||
if (thread->WriteStencil)
|
||||
WriteStencil(y, x0, x1, thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* discard = thread->scanline.discard;
|
||||
while (x0 < x1)
|
||||
{
|
||||
int xstart = x0;
|
||||
while (!discard[x0] && x0 < x1) x0++;
|
||||
|
||||
if (xstart < x0)
|
||||
{
|
||||
if (thread->WriteColor)
|
||||
thread->WriteColorFunc(y, xstart, x0, thread);
|
||||
if (thread->WriteDepth)
|
||||
WriteDepth(y, xstart, x0, thread);
|
||||
if (thread->WriteStencil)
|
||||
WriteStencil(y, xstart, x0, thread);
|
||||
}
|
||||
|
||||
while (discard[x0] && x0 < x1) x0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void NoTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
WriteW(y, x0, x1, args, thread);
|
||||
DrawSpan(y, x0, x1, args, thread);
|
||||
}
|
||||
|
||||
static void DepthTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
WriteW(y, x0, x1, args, thread);
|
||||
|
||||
float* zbufferLine = thread->depthstencil->DepthValues() + (size_t)thread->depthstencil->Width() * y;
|
||||
float* w = thread->scanline.W;
|
||||
float depthbias = thread->depthbias;
|
||||
|
||||
int x = x0;
|
||||
int xend = x1;
|
||||
while (x < xend)
|
||||
{
|
||||
int xstart = x;
|
||||
|
||||
while (zbufferLine[x] >= w[x] + depthbias && x < xend)
|
||||
x++;
|
||||
|
||||
if (x > xstart)
|
||||
{
|
||||
DrawSpan(y, xstart, x, args, thread);
|
||||
}
|
||||
|
||||
while (zbufferLine[x] < w[x] + depthbias && x < xend)
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
static void DepthStencilTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint8_t* stencilLine = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y;
|
||||
uint8_t stencilTestValue = thread->StencilTestValue;
|
||||
|
||||
int x = x0;
|
||||
int xend = x1;
|
||||
while (x < xend)
|
||||
{
|
||||
int xstart = x;
|
||||
while (stencilLine[x] == stencilTestValue && x < xend)
|
||||
x++;
|
||||
|
||||
if (x > xstart)
|
||||
{
|
||||
DepthTestSpan(y, xstart, x, args, thread);
|
||||
}
|
||||
|
||||
while (stencilLine[x] != stencilTestValue && x < xend)
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
static void StencilTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
uint8_t* stencilLine = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y;
|
||||
uint8_t stencilTestValue = thread->StencilTestValue;
|
||||
|
||||
int x = x0;
|
||||
int xend = x1;
|
||||
while (x < xend)
|
||||
{
|
||||
int xstart = x;
|
||||
while (stencilLine[x] == stencilTestValue && x < xend)
|
||||
x++;
|
||||
|
||||
if (x > xstart)
|
||||
{
|
||||
WriteW(y, x0, x1, args, thread);
|
||||
DrawSpan(y, xstart, x, args, thread);
|
||||
}
|
||||
|
||||
while (stencilLine[x] != stencilTestValue && x < xend)
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
static void SortVertices(const TriDrawTriangleArgs* args, ScreenTriVertex** sortedVertices)
|
||||
{
|
||||
sortedVertices[0] = args->v1;
|
||||
sortedVertices[1] = args->v2;
|
||||
sortedVertices[2] = args->v3;
|
||||
|
||||
if (sortedVertices[1]->y < sortedVertices[0]->y)
|
||||
std::swap(sortedVertices[0], sortedVertices[1]);
|
||||
if (sortedVertices[2]->y < sortedVertices[0]->y)
|
||||
std::swap(sortedVertices[0], sortedVertices[2]);
|
||||
if (sortedVertices[2]->y < sortedVertices[1]->y)
|
||||
std::swap(sortedVertices[1], sortedVertices[2]);
|
||||
}
|
||||
|
||||
void ScreenTriangle::Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread)
|
||||
{
|
||||
// Sort vertices by Y position
|
||||
ScreenTriVertex* sortedVertices[3];
|
||||
SortVertices(args, sortedVertices);
|
||||
|
||||
int clipleft = thread->clip.left;
|
||||
int cliptop = max(thread->clip.top, thread->numa_start_y);
|
||||
int clipright = thread->clip.right;
|
||||
int clipbottom = min(thread->clip.bottom, thread->numa_end_y);
|
||||
|
||||
int topY = (int)(sortedVertices[0]->y + 0.5f);
|
||||
int midY = (int)(sortedVertices[1]->y + 0.5f);
|
||||
int bottomY = (int)(sortedVertices[2]->y + 0.5f);
|
||||
|
||||
topY = max(topY, cliptop);
|
||||
midY = min(midY, clipbottom);
|
||||
bottomY = min(bottomY, clipbottom);
|
||||
|
||||
if (topY >= bottomY)
|
||||
return;
|
||||
|
||||
SelectFragmentShader(thread);
|
||||
SelectWriteColorFunc(thread);
|
||||
|
||||
void(*testfunc)(int y, int x0, int x1, const TriDrawTriangleArgs * args, PolyTriangleThreadData * thread);
|
||||
|
||||
int opt = 0;
|
||||
if (thread->DepthTest) opt |= SWTRI_DepthTest;
|
||||
if (thread->StencilTest) opt |= SWTRI_StencilTest;
|
||||
testfunc = ScreenTriangle::TestSpanOpts[opt];
|
||||
|
||||
topY += thread->skipped_by_thread(topY);
|
||||
int num_cores = thread->num_cores;
|
||||
|
||||
// Find start/end X positions for each line covered by the triangle:
|
||||
|
||||
int y = topY;
|
||||
|
||||
float longDX = sortedVertices[2]->x - sortedVertices[0]->x;
|
||||
float longDY = sortedVertices[2]->y - sortedVertices[0]->y;
|
||||
float longStep = longDX / longDY;
|
||||
float longPos = sortedVertices[0]->x + longStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f;
|
||||
longStep *= num_cores;
|
||||
|
||||
if (y < midY)
|
||||
{
|
||||
float shortDX = sortedVertices[1]->x - sortedVertices[0]->x;
|
||||
float shortDY = sortedVertices[1]->y - sortedVertices[0]->y;
|
||||
float shortStep = shortDX / shortDY;
|
||||
float shortPos = sortedVertices[0]->x + shortStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f;
|
||||
shortStep *= num_cores;
|
||||
|
||||
while (y < midY)
|
||||
{
|
||||
int x0 = (int)shortPos;
|
||||
int x1 = (int)longPos;
|
||||
if (x1 < x0) std::swap(x0, x1);
|
||||
x0 = clamp(x0, clipleft, clipright);
|
||||
x1 = clamp(x1, clipleft, clipright);
|
||||
|
||||
testfunc(y, x0, x1, args, thread);
|
||||
|
||||
shortPos += shortStep;
|
||||
longPos += longStep;
|
||||
y += num_cores;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < bottomY)
|
||||
{
|
||||
float shortDX = sortedVertices[2]->x - sortedVertices[1]->x;
|
||||
float shortDY = sortedVertices[2]->y - sortedVertices[1]->y;
|
||||
float shortStep = shortDX / shortDY;
|
||||
float shortPos = sortedVertices[1]->x + shortStep * (y + 0.5f - sortedVertices[1]->y) + 0.5f;
|
||||
shortStep *= num_cores;
|
||||
|
||||
while (y < bottomY)
|
||||
{
|
||||
int x0 = (int)shortPos;
|
||||
int x1 = (int)longPos;
|
||||
if (x1 < x0) std::swap(x0, x1);
|
||||
x0 = clamp(x0, clipleft, clipright);
|
||||
x1 = clamp(x1, clipleft, clipright);
|
||||
|
||||
testfunc(y, x0, x1, args, thread);
|
||||
|
||||
shortPos += shortStep;
|
||||
longPos += longStep;
|
||||
y += num_cores;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void(*ScreenTriangle::TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) =
|
||||
{
|
||||
&NoTestSpan,
|
||||
&DepthTestSpan,
|
||||
&StencilTestSpan,
|
||||
&DepthStencilTestSpan
|
||||
};
|
|
@ -1,124 +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 <cstdint>
|
||||
#include <vector>
|
||||
#include <float.h>
|
||||
#include "renderstyle.h"
|
||||
//#include "rendering/swrenderer/drawers/r_draw.h"
|
||||
|
||||
class FString;
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
struct ScreenTriVertex
|
||||
{
|
||||
float x, y, z, w;
|
||||
float u, v;
|
||||
float worldX, worldY, worldZ;
|
||||
float a, r, g, b;
|
||||
float gradientdistZ;
|
||||
};
|
||||
|
||||
struct ScreenTriangleStepVariables
|
||||
{
|
||||
float W, U, V;
|
||||
float WorldX, WorldY, WorldZ;
|
||||
float A, R, G, B;
|
||||
float GradientdistZ;
|
||||
};
|
||||
|
||||
struct TriDrawTriangleArgs
|
||||
{
|
||||
ScreenTriVertex *v1;
|
||||
ScreenTriVertex *v2;
|
||||
ScreenTriVertex *v3;
|
||||
ScreenTriangleStepVariables gradientX;
|
||||
ScreenTriangleStepVariables gradientY;
|
||||
|
||||
bool CalculateGradients()
|
||||
{
|
||||
float bottomX = (v2->x - v3->x) * (v1->y - v3->y) - (v1->x - v3->x) * (v2->y - v3->y);
|
||||
float bottomY = (v1->x - v3->x) * (v2->y - v3->y) - (v2->x - v3->x) * (v1->y - v3->y);
|
||||
if ((bottomX >= -FLT_EPSILON && bottomX <= FLT_EPSILON) || (bottomY >= -FLT_EPSILON && bottomY <= FLT_EPSILON))
|
||||
return false;
|
||||
|
||||
gradientX.W = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f);
|
||||
gradientX.U = FindGradientX(bottomX, v1->u, v2->u, v3->u);
|
||||
gradientX.V = FindGradientX(bottomX, v1->v, v2->v, v3->v);
|
||||
gradientX.WorldX = FindGradientX(bottomX, v1->worldX, v2->worldX, v3->worldX);
|
||||
gradientX.WorldY = FindGradientX(bottomX, v1->worldY, v2->worldY, v3->worldY);
|
||||
gradientX.WorldZ = FindGradientX(bottomX, v1->worldZ, v2->worldZ, v3->worldZ);
|
||||
gradientX.A = FindGradientX(bottomX, v1->a, v2->a, v3->a);
|
||||
gradientX.R = FindGradientX(bottomX, v1->r, v2->r, v3->r);
|
||||
gradientX.G = FindGradientX(bottomX, v1->g, v2->g, v3->g);
|
||||
gradientX.B = FindGradientX(bottomX, v1->b, v2->b, v3->b);
|
||||
gradientX.GradientdistZ = FindGradientX(bottomX, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ);
|
||||
|
||||
gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f);
|
||||
gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u);
|
||||
gradientY.V = FindGradientY(bottomY, v1->v, v2->v, v3->v);
|
||||
gradientY.WorldX = FindGradientY(bottomY, v1->worldX, v2->worldX, v3->worldX);
|
||||
gradientY.WorldY = FindGradientY(bottomY, v1->worldY, v2->worldY, v3->worldY);
|
||||
gradientY.WorldZ = FindGradientY(bottomY, v1->worldZ, v2->worldZ, v3->worldZ);
|
||||
gradientY.A = FindGradientY(bottomY, v1->a, v2->a, v3->a);
|
||||
gradientY.R = FindGradientY(bottomY, v1->r, v2->r, v3->r);
|
||||
gradientY.G = FindGradientY(bottomY, v1->g, v2->g, v3->g);
|
||||
gradientY.B = FindGradientY(bottomY, v1->b, v2->b, v3->b);
|
||||
gradientY.GradientdistZ = FindGradientY(bottomY, v1->gradientdistZ, v2->gradientdistZ, v3->gradientdistZ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
float FindGradientX(float bottomX, float c0, float c1, float c2)
|
||||
{
|
||||
c0 *= v1->w;
|
||||
c1 *= v2->w;
|
||||
c2 *= v3->w;
|
||||
return ((c1 - c2) * (v1->y - v3->y) - (c0 - c2) * (v2->y - v3->y)) / bottomX;
|
||||
}
|
||||
|
||||
float FindGradientY(float bottomY, float c0, float c1, float c2)
|
||||
{
|
||||
c0 *= v1->w;
|
||||
c1 *= v2->w;
|
||||
c2 *= v3->w;
|
||||
return ((c1 - c2) * (v1->x - v3->x) - (c0 - c2) * (v2->x - v3->x)) / bottomY;
|
||||
}
|
||||
};
|
||||
|
||||
class ScreenTriangle
|
||||
{
|
||||
public:
|
||||
static void Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
||||
|
||||
private:
|
||||
static void(*TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread);
|
||||
};
|
||||
|
||||
enum SWTestSpan
|
||||
{
|
||||
SWTRI_DepthTest = 1,
|
||||
SWTRI_StencilTest = 2
|
||||
};
|
|
@ -1,6 +0,0 @@
|
|||
#include "drawers/poly_triangle.cpp"
|
||||
#include "drawers/poly_thread.cpp"
|
||||
#include "drawers/screen_triangle.cpp"
|
||||
#include "drawers/screen_scanline_setup.cpp"
|
||||
#include "drawers/screen_shader.cpp"
|
||||
#include "drawers/screen_blend.cpp"
|
|
@ -27,9 +27,7 @@
|
|||
#include "v_video.h"
|
||||
#include "r_thread.h"
|
||||
#include "r_memory.h"
|
||||
#include "poly_thread.h"
|
||||
#include "printf.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <chrono>
|
||||
|
||||
CVAR(Int, r_multithreaded, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
@ -130,11 +128,6 @@ void DrawerThreads::WorkerMain(DrawerThread *thread)
|
|||
thread->current_queue++;
|
||||
thread->numa_start_y = thread->numa_node * screen->GetHeight() / thread->num_numa_nodes;
|
||||
thread->numa_end_y = (thread->numa_node + 1) * screen->GetHeight() / thread->num_numa_nodes;
|
||||
if (thread->poly)
|
||||
{
|
||||
thread->poly->numa_start_y = thread->numa_start_y;
|
||||
thread->poly->numa_end_y = thread->numa_end_y;
|
||||
}
|
||||
start_lock.unlock();
|
||||
|
||||
// Do the work:
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
// Use multiple threads when drawing
|
||||
EXTERN_CVAR(Int, r_multithreaded)
|
||||
|
||||
class PolyTriangleThreadData;
|
||||
|
||||
namespace swrenderer { class WallColumnDrawerArgs; }
|
||||
|
||||
// Worker data for each thread executing drawer commands
|
||||
|
@ -64,8 +62,6 @@ public:
|
|||
// Working buffer used by the tilted (sloped) span drawer
|
||||
const uint8_t *tiltlighting[MAXWIDTH];
|
||||
|
||||
std::unique_ptr<PolyTriangleThreadData> poly;
|
||||
|
||||
size_t debug_draw_pos = 0;
|
||||
|
||||
// Checks if a line is rendered by this thread
|
||||
|
|
|
@ -103,12 +103,10 @@ CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N
|
|||
{
|
||||
#ifdef HAVE_GLES2
|
||||
case 3:
|
||||
case 2:
|
||||
Printf("Selecting OpenGLES 2.0 backend...\n");
|
||||
break;
|
||||
#endif
|
||||
case 2:
|
||||
Printf("Selecting SoftPoly backend...\n");
|
||||
break;
|
||||
#ifdef HAVE_VULKAN
|
||||
case 1:
|
||||
Printf("Selecting Vulkan backend...\n");
|
||||
|
@ -121,6 +119,14 @@ CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N
|
|||
Printf("Changing the video backend requires a restart for " GAMENAME ".\n");
|
||||
}
|
||||
|
||||
int V_GetBackend()
|
||||
{
|
||||
int v = vid_preferbackend;
|
||||
if (v == 3) v = 2;
|
||||
else if (v < 0 || v > 3) v = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL)
|
||||
{
|
||||
|
|
|
@ -306,6 +306,7 @@ void V_InitScreen();
|
|||
void V_Init2 ();
|
||||
|
||||
void V_Shutdown ();
|
||||
int V_GetBackend();
|
||||
|
||||
inline bool IsRatioWidescreen(int ratio) { return (ratio & 3) != 0; }
|
||||
extern bool setsizeneeded, setmodeneeded;
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#include "r_thread.h"
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
#include "playsim/a_dynlight.h"
|
||||
#include "polyrenderer/drawers/poly_thread.h"
|
||||
|
||||
CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, r_fuzzscale, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
@ -221,44 +220,6 @@ namespace swrenderer
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthColumn(const WallColumnDrawerArgs& args, float idepth)
|
||||
{
|
||||
int x, y, count;
|
||||
|
||||
auto rendertarget = args.Viewport()->RenderTarget;
|
||||
if (rendertarget->IsBgra())
|
||||
{
|
||||
uint32_t* destorg = (uint32_t*)rendertarget->GetPixels();
|
||||
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
|
||||
uint32_t* dest = (uint32_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* destorg = rendertarget->GetPixels();
|
||||
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
|
||||
uint8_t* dest = (uint8_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
count = args.Count();
|
||||
|
||||
auto zbuffer = thread->Poly->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float* values = zbuffer->DepthValues() + y * pitch + x;
|
||||
int cnt = count;
|
||||
|
||||
float depth = idepth;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
*values = depth;
|
||||
values += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void SWPixelFormatDrawers::SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1, const WallDrawerArgs& wallargs)
|
||||
{
|
||||
bool mirror = !!(wallargs.PortalMirrorFlags & RF_XFLIP);
|
||||
|
@ -323,76 +284,4 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth)
|
||||
{
|
||||
int x, y, count;
|
||||
auto rendertarget = args.Viewport()->RenderTarget;
|
||||
if (rendertarget->IsBgra())
|
||||
{
|
||||
uint32_t* destorg = (uint32_t*)rendertarget->GetPixels();
|
||||
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
|
||||
uint32_t* dest = (uint32_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* destorg = rendertarget->GetPixels();
|
||||
destorg += viewwindowx + viewwindowy * rendertarget->GetPitch();
|
||||
uint8_t* dest = (uint8_t*)args.Dest();
|
||||
int offset = (int)(ptrdiff_t)(dest - destorg);
|
||||
x = offset % rendertarget->GetPitch();
|
||||
y = offset / rendertarget->GetPitch();
|
||||
}
|
||||
count = args.Count();
|
||||
|
||||
auto zbuffer = thread->Poly->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float* values = zbuffer->DepthValues() + y * pitch + x;
|
||||
int cnt = count;
|
||||
|
||||
float depth = idepth;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
*values = depth;
|
||||
values += pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void SWPixelFormatDrawers::DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2)
|
||||
{
|
||||
int y = args.DestY();
|
||||
int x1 = args.DestX1();
|
||||
int x2 = args.DestX2();
|
||||
|
||||
auto zbuffer = thread->Poly->depthstencil;
|
||||
int pitch = zbuffer->Width();
|
||||
float *values = zbuffer->DepthValues() + x1 + y * pitch;
|
||||
|
||||
int count = x2 - x1 + 1;
|
||||
|
||||
if (idepth1 == idepth2)
|
||||
{
|
||||
float depth = idepth1;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
*values = depth;
|
||||
values++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float depth = idepth1;
|
||||
float step = (idepth2 - idepth1) / (x2 - x1 + 1);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
*values = depth;
|
||||
values++;
|
||||
depth += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,10 +94,6 @@ namespace swrenderer
|
|||
virtual void DrawFogBoundaryLine(const SpanDrawerArgs &args) = 0;
|
||||
virtual void DrawParticleColumn(int x, int yl, int ycount, uint32_t fg, uint32_t alpha, uint32_t fracposx) = 0;
|
||||
|
||||
void DrawDepthColumn(const WallColumnDrawerArgs& args, float idepth);
|
||||
void DrawDepthSkyColumn(const SkyDrawerArgs &args, float idepth);
|
||||
void DrawDepthSpan(const SpanDrawerArgs &args, float idepth1, float idepth2);
|
||||
|
||||
void SetLights(WallColumnDrawerArgs& drawerargs, int x, int y1, const WallDrawerArgs& wallargs);
|
||||
|
||||
RenderThread* thread = nullptr;
|
||||
|
|
|
@ -3060,30 +3060,6 @@ namespace swrenderer
|
|||
wpos += wstepX;
|
||||
curlight += lightstep;
|
||||
}
|
||||
|
||||
if (r_modelscene)
|
||||
{
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
int y1 = uwal[x];
|
||||
int y2 = dwal[x];
|
||||
if (y2 > y1)
|
||||
{
|
||||
int count = y2 - y1;
|
||||
|
||||
float w1 = 1.0f / wallargs.WallC.sz1;
|
||||
float w2 = 1.0f / wallargs.WallC.sz2;
|
||||
float t = (x - wallargs.WallC.sx1 + 0.5f) / (wallargs.WallC.sx2 - wallargs.WallC.sx1);
|
||||
float wcol = w1 * (1.0f - t) + w2 * t;
|
||||
float zcol = 1.0f / wcol;
|
||||
float zbufferdepth = 1.0f / (zcol / wallargs.FocalTangent);
|
||||
|
||||
wallcolargs.SetDest(x, y1);
|
||||
wallcolargs.SetCount(count);
|
||||
DrawDepthColumn(wallcolargs, zbufferdepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DrawerT>
|
||||
|
|
|
@ -956,30 +956,6 @@ namespace swrenderer
|
|||
wpos += wstepX;
|
||||
curlight += lightstep;
|
||||
}
|
||||
|
||||
if (r_modelscene)
|
||||
{
|
||||
for (int x = x1; x < x2; x++)
|
||||
{
|
||||
int y1 = uwal[x];
|
||||
int y2 = dwal[x];
|
||||
if (y2 > y1)
|
||||
{
|
||||
int count = y2 - y1;
|
||||
|
||||
float w1 = 1.0f / wallargs.WallC.sz1;
|
||||
float w2 = 1.0f / wallargs.WallC.sz2;
|
||||
float t = (x - wallargs.WallC.sx1 + 0.5f) / (wallargs.WallC.sx2 - wallargs.WallC.sx1);
|
||||
float wcol = w1 * (1.0f - t) + w2 * t;
|
||||
float zcol = 1.0f / wcol;
|
||||
float zbufferdepth = 1.0f / (zcol / wallargs.FocalTangent);
|
||||
|
||||
wallcolargs.SetDest(x, y1);
|
||||
wallcolargs.SetCount(count);
|
||||
DrawDepthColumn(wallcolargs, zbufferdepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename DrawerT>
|
||||
|
|
|
@ -270,8 +270,6 @@ namespace swrenderer
|
|||
drawerargs.SetDestX2(x2);
|
||||
|
||||
drawerargs.DrawSpan(Thread);
|
||||
if (r_modelscene)
|
||||
drawerargs.DrawDepthSpan(Thread, zbufferdepth, zbufferdepth);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -267,8 +267,6 @@ namespace swrenderer
|
|||
else
|
||||
drawerargs.DrawDoubleSkyColumn(Thread);
|
||||
|
||||
if (r_modelscene)
|
||||
drawerargs.DrawDepthSkyColumn(Thread, 1.0f / 65536.0f);
|
||||
}
|
||||
|
||||
void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2)
|
||||
|
|
|
@ -205,22 +205,5 @@ namespace swrenderer
|
|||
void RenderSlopePlane::RenderLine(int y, int x1, int x2)
|
||||
{
|
||||
drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, lightlevel, foggy, planelightfloat, pviewx, pviewy, basecolormap);
|
||||
|
||||
if (r_modelscene)
|
||||
{
|
||||
double viewZ = 1.0;
|
||||
double viewX1 = Thread->Viewport->ScreenToViewX(x1, viewZ);
|
||||
double viewX2 = Thread->Viewport->ScreenToViewX(x2 + 1, viewZ);
|
||||
double viewY = Thread->Viewport->ScreenToViewY(y, viewZ);
|
||||
|
||||
// Find depth values for the span
|
||||
float zbufferdepth1 = (float)(-planeD / (planeNormal | DVector3(viewX1, viewZ, viewY)));
|
||||
float zbufferdepth2 = (float)(-planeD / (planeNormal | DVector3(viewX2, viewZ, viewY)));
|
||||
|
||||
drawerargs.SetDestX1(x1);
|
||||
drawerargs.SetDestX2(x2);
|
||||
drawerargs.SetDestY(Thread->Viewport.get(), y);
|
||||
drawerargs.DrawDepthSpan(Thread, 1.0f / zbufferdepth1, 1.0f / zbufferdepth2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "things/r_visiblespritelist.cpp"
|
||||
#include "things/r_voxel.cpp"
|
||||
#include "things/r_wallsprite.cpp"
|
||||
#include "things/r_model.cpp"
|
||||
#include "viewport/r_drawerargs.cpp"
|
||||
#include "viewport/r_skydrawer.cpp"
|
||||
#include "viewport/r_spandrawer.cpp"
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#include "swrenderer/drawers/r_draw_pal.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "r_memory.h"
|
||||
#include "common/rendering/polyrenderer/drawers/poly_thread.h"
|
||||
|
||||
std::pair<PalEntry, PalEntry>& R_GetSkyCapColor(FGameTexture* tex);
|
||||
|
||||
|
@ -75,7 +74,6 @@ namespace swrenderer
|
|||
PlaneList.reset(new VisiblePlaneList(this));
|
||||
DrawSegments.reset(new DrawSegmentList(this));
|
||||
ClipSegments.reset(new RenderClipSegment());
|
||||
Poly.reset(new PolyTriangleThreadData(0, 1, 0, 1, 0, screen->GetHeight()));
|
||||
tc_drawers.reset(new SWTruecolorDrawers(this));
|
||||
pal_drawers.reset(new SWPalDrawers(this));
|
||||
}
|
||||
|
|
|
@ -26,11 +26,9 @@
|
|||
#include <thread>
|
||||
|
||||
class RenderMemory;
|
||||
class PolyTriangleThreadData;
|
||||
struct FDynamicLight;
|
||||
|
||||
EXTERN_CVAR(Bool, r_models);
|
||||
extern bool r_modelscene;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
|
@ -75,7 +73,6 @@ namespace swrenderer
|
|||
std::unique_ptr<RenderClipSegment> ClipSegments;
|
||||
std::unique_ptr<RenderViewport> Viewport;
|
||||
std::unique_ptr<LightVisibility> Light;
|
||||
std::unique_ptr<PolyTriangleThreadData> Poly;
|
||||
|
||||
TArray<FDynamicLight*> AddedLightsArray;
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "swrenderer/things/r_wallsprite.h"
|
||||
#include "swrenderer/things/r_voxel.h"
|
||||
#include "swrenderer/things/r_particle.h"
|
||||
#include "swrenderer/things/r_model.h"
|
||||
#include "swrenderer/segments/r_clipsegment.h"
|
||||
#include "swrenderer/line/r_wallsetup.h"
|
||||
#include "swrenderer/line/r_farclip_line.h"
|
||||
|
@ -932,13 +931,7 @@ namespace swrenderer
|
|||
ThingSprite sprite;
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (r_modelscene && modelframe && (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared() < model_distance_cull)
|
||||
{
|
||||
DVector3 pos = thing->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac);
|
||||
RenderModel::Project(Thread, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
||||
}
|
||||
else if (GetThingSprite(thing, sprite))
|
||||
if (GetThingSprite(thing, sprite))
|
||||
{
|
||||
int thinglightlevel;
|
||||
if (sec->sectornum != thing->Sector->sectornum) // compare sectornums to account for R_FakeFlat copies.
|
||||
|
|
|
@ -65,8 +65,6 @@ EXTERN_CVAR(Int, r_debug_draw)
|
|||
CVAR(Int, r_scene_multithreaded, 1, 0);
|
||||
CVAR(Bool, r_models, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
||||
bool r_modelscene = false;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
cycle_t WallCycles, PlaneCycles, MaskedCycles;
|
||||
|
@ -100,18 +98,6 @@ namespace swrenderer
|
|||
ActiveRatio(width, height, &trueratio);
|
||||
viewport->SetViewport(player->camera->Level, MainThread(), width, height, trueratio);
|
||||
|
||||
/*r_modelscene = r_models && Models.Size() > 0;
|
||||
if (r_modelscene)
|
||||
{
|
||||
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);
|
||||
}*/
|
||||
|
||||
if (r_clearbuffer != 0 || r_debug_draw != 0)
|
||||
{
|
||||
if (!viewport->RenderTarget->IsBgra())
|
||||
|
@ -158,9 +144,6 @@ namespace swrenderer
|
|||
|
||||
R_UpdateFuzzPosFrameStart();
|
||||
|
||||
if (r_modelscene)
|
||||
MainThread()->Viewport->SetupPolyViewport(MainThread());
|
||||
|
||||
FRenderViewpoint origviewpoint = MainThread()->Viewport->viewpoint;
|
||||
|
||||
ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags;
|
||||
|
@ -174,8 +157,6 @@ namespace swrenderer
|
|||
|
||||
// Mirrors fail to restore the original viewpoint -- we need it for the HUD weapon to draw correctly.
|
||||
MainThread()->Viewport->viewpoint = origviewpoint;
|
||||
if (r_modelscene)
|
||||
MainThread()->Viewport->SetupPolyViewport(MainThread());
|
||||
|
||||
if (renderPlayerSprites)
|
||||
RenderPSprites();
|
||||
|
@ -259,12 +240,6 @@ namespace swrenderer
|
|||
thread->OpaquePass->ResetFakingUnderwater(); // [RH] Hack to make windows into underwater areas possible
|
||||
thread->Portal->SetMainPortal();
|
||||
|
||||
/*if (r_modelscene && thread->MainThread)
|
||||
PolyTriangleDrawer::ClearStencil(MainThread()->DrawQueue, 0);
|
||||
|
||||
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;
|
||||
if (thread->X1 > 0)
|
||||
|
@ -388,14 +363,6 @@ namespace swrenderer
|
|||
viewwindowy = y;
|
||||
viewactive = true;
|
||||
viewport->SetViewport(actor->Level, MainThread(), width, height, MainThread()->Viewport->viewwindow.WidescreenRatio);
|
||||
if (r_modelscene)
|
||||
{
|
||||
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,8 +32,6 @@
|
|||
|
||||
extern cycle_t FrameCycles;
|
||||
|
||||
class PolyDepthStencil;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
extern cycle_t WallCycles, PlaneCycles, MaskedCycles, DrawerWaitCycles;
|
||||
|
@ -69,7 +67,6 @@ 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;
|
||||
|
|
|
@ -1,443 +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 "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "r_model.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
#include "texturemanager.h"
|
||||
#include "r_memory.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
void RenderModel::Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
{
|
||||
// transform the origin point
|
||||
double tr_x = x - thread->Viewport->viewpoint.Pos.X;
|
||||
double tr_y = y - thread->Viewport->viewpoint.Pos.Y;
|
||||
double tz = tr_x * thread->Viewport->viewpoint.TanCos + tr_y * thread->Viewport->viewpoint.TanSin;
|
||||
|
||||
// thing is behind view plane?
|
||||
if (tz < MINZ)
|
||||
return;
|
||||
|
||||
double tx = tr_x * thread->Viewport->viewpoint.Sin - tr_y * thread->Viewport->viewpoint.Cos;
|
||||
|
||||
// Flip for mirrors
|
||||
if (thread->Portal->MirrorFlags & RF_XFLIP)
|
||||
{
|
||||
tx = viewwidth - tx - 1;
|
||||
}
|
||||
|
||||
// too far off the side?
|
||||
if (fabs(tx / 64) > fabs(tz))
|
||||
return;
|
||||
|
||||
RenderModel *vis = thread->FrameMemory->NewObject<RenderModel>(x, y, z, smf, actor, float(1 / tz));
|
||||
vis->CurrentPortalUniq = thread->Portal->CurrentPortalUniq;
|
||||
vis->WorldToClip = thread->Viewport->WorldToClip;
|
||||
vis->MirrorWorldToClip = !!(thread->Portal->MirrorFlags & RF_XFLIP);
|
||||
thread->SpriteList->Push(vis);
|
||||
}
|
||||
|
||||
RenderModel::RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth) : x(x), y(y), z(z), smf(smf), actor(actor)
|
||||
{
|
||||
gpos = { x, y, z };
|
||||
this->idepth = idepth;
|
||||
}
|
||||
|
||||
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;
|
||||
renderer.RenderStyle = actor->RenderStyle;
|
||||
renderer.RenderAlpha = (float)actor->Alpha;
|
||||
if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha))
|
||||
return;
|
||||
|
||||
bool foggy = false;
|
||||
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 = thread->Light->SpriteGlobVis(foggy);
|
||||
|
||||
renderer.fillcolor = actor->fillcolor;
|
||||
renderer.Translation = actor->Translation;
|
||||
|
||||
renderer.AddLights(actor);
|
||||
RenderModel(&renderer, x, y, z, smf, actor, r_viewpoint.TicFrac);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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())
|
||||
{
|
||||
auto tex = TexMan.GetGameTexture(lump, true);
|
||||
if (tex) disablefullbright = tex->isFullbrightDisabled();
|
||||
}
|
||||
return psp->GetState()->GetFullbright() && !disablefullbright;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
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 : thread->Viewport->viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = isBright(psp);
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = thread->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]);
|
||||
uint32_t trans = psp->GetTranslation() != 0 ? psp->GetTranslation() : 0;
|
||||
if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = playermo->Translation;
|
||||
renderer.Translation = trans;
|
||||
|
||||
RenderHUDModel(&renderer, 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)
|
||||
{
|
||||
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 SWModelRenderer::BeginDrawModel(FRenderStyale style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
|
||||
ClipTop = {};
|
||||
ClipBottom = {};
|
||||
if (Clip3DFloor.clipTop || Clip3DFloor.clipBottom)
|
||||
{
|
||||
// Convert 3d floor clipping planes from world to object space
|
||||
|
||||
VSMatrix inverseMat;
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).inverseMatrix(inverseMat);
|
||||
Mat4f worldToObject;
|
||||
inverseMat.copy(worldToObject.Matrix);
|
||||
|
||||
// Note: Y and Z is swapped here
|
||||
|
||||
Vec4f one = worldToObject * Vec4f(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
Vec4f zero = worldToObject * Vec4f(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
Vec4f up = { one.X - zero.X, one.Y - zero.Y, one.Z - zero.Z };
|
||||
|
||||
if (Clip3DFloor.clipTop)
|
||||
{
|
||||
Vec4f p = worldToObject * Vec4f(0.0f, Clip3DFloor.sclipTop, 0.0f, 1.0f);
|
||||
float d = up.X * p.X + up.Y * p.Y + up.Z * p.Z;
|
||||
ClipTop = { -up.X, -up.Y, -up.Z, d };
|
||||
}
|
||||
|
||||
if (Clip3DFloor.clipBottom)
|
||||
{
|
||||
Vec4f p = worldToObject * Vec4f(0.0f, Clip3DFloor.sclipBottom, 0.0f, 1.0f);
|
||||
float d = up.X * p.X + up.Y * p.Y + up.Z * p.Z;
|
||||
ClipBottom = { up.X, up.Y, up.Z, -d };
|
||||
}
|
||||
}
|
||||
|
||||
SetTransform();
|
||||
|
||||
if (style == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip));
|
||||
}
|
||||
|
||||
void SWModelRenderer::EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf)
|
||||
{
|
||||
if (style == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
IModelVertexBuffer *SWModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
return new SWModelVertexBuffer(needindex, singleframe);
|
||||
}
|
||||
|
||||
VSMatrix SWModelRenderer::GetViewToWorldMatrix()
|
||||
{
|
||||
// Calculate the WorldToView matrix as it would have looked like without yshearing:
|
||||
const auto &Viewpoint = Thread->Viewport->viewpoint;
|
||||
auto Level = Thread->Viewport->Level();
|
||||
const auto &Viewwindow = Thread->Viewport->viewwindow;
|
||||
double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * 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);
|
||||
Mat4f altWorldToView =
|
||||
Mat4f::Rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
|
||||
Mat4f::Rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
|
||||
Mat4f::Scale(1.0f, Level->info->pixelstretch, 1.0f) *
|
||||
Mat4f::SwapYZ() *
|
||||
Mat4f::Translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z);
|
||||
|
||||
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((altWorldToView * swapYZ).Matrix);
|
||||
|
||||
VSMatrix objectToWorld;
|
||||
worldToView.inverseMatrix(objectToWorld);
|
||||
return objectToWorld;
|
||||
}
|
||||
|
||||
void SWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
ClipTop = {};
|
||||
ClipBottom = {};
|
||||
SetTransform();
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, true);
|
||||
|
||||
if (style == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !(mirrored ^ MirrorWorldToClip));
|
||||
}
|
||||
|
||||
void SWModelRenderer::EndDrawHUDModel(FRenderStyle style)
|
||||
{
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, false);
|
||||
|
||||
if (style == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
void SWModelRenderer::SetInterpolation(double interpolation)
|
||||
{
|
||||
InterpolationFactor = (float)interpolation;
|
||||
}
|
||||
|
||||
void SWModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation)
|
||||
{
|
||||
SkinTexture = skin;
|
||||
}
|
||||
|
||||
void SWModelRenderer::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 SWModelRenderer::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.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetClipPlane(1, ClipTop);
|
||||
args.SetClipPlane(2, ClipBottom);
|
||||
|
||||
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.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetClipPlane(1, ClipTop);
|
||||
args.SetClipPlane(2, ClipBottom);
|
||||
|
||||
PolyTriangleDrawer::PushDrawArgs(Thread->DrawQueue, args);
|
||||
PolyTriangleDrawer::DrawIndexed(Thread->DrawQueue, static_cast<int>(offset / sizeof(unsigned int)), numIndices);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SWModelVertexBuffer::SWModelVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
}
|
||||
|
||||
SWModelVertexBuffer::~SWModelVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
FModelVertex *SWModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||
{
|
||||
mVertexBuffer.Resize(size);
|
||||
return &mVertexBuffer[0];
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::UnlockVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int *SWModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||
{
|
||||
mIndexBuffer.Resize(size);
|
||||
return &mIndexBuffer[0];
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::UnlockIndexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void SWModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||
{
|
||||
SWModelRenderer *swrenderer = (SWModelRenderer *)renderer;
|
||||
|
||||
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
|
||||
}
|
|
@ -1,120 +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 "models.h"
|
||||
#include "swrenderer/r_renderthread.h"
|
||||
#include "swrenderer/things/r_visiblesprite.h"
|
||||
|
||||
struct PolyLight;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
void RenderHUDModel(RenderThread *thread, DPSprite *psp, float ofsx, float ofsy);
|
||||
|
||||
class RenderModel : public VisibleSprite
|
||||
{
|
||||
public:
|
||||
RenderModel(float x, float y, float z, FSpriteModelFrame *smf, AActor *actor, float idepth);
|
||||
|
||||
static void Project(RenderThread *thread, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
|
||||
|
||||
protected:
|
||||
void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override;
|
||||
bool IsModel() const override { return true; }
|
||||
|
||||
private:
|
||||
float x, y, z;
|
||||
FSpriteModelFrame *smf;
|
||||
AActor *actor;
|
||||
VSMatrix WorldToClip;
|
||||
bool MirrorWorldToClip;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class SWModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
SWModelRenderer(RenderThread *thread, Fake3DTranslucent clip3DFloor, Mat4f *worldToClip, bool mirrorWorldToClip);
|
||||
|
||||
void AddLights(AActor *actor);
|
||||
|
||||
ModelRendererType GetType() const override { return SWModelRendererType; }
|
||||
|
||||
void BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) override;
|
||||
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
|
||||
VSMatrix GetViewToWorldMatrix() override;
|
||||
void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawHUDModel(FRenderStyle style) 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();
|
||||
|
||||
RenderThread *Thread = nullptr;
|
||||
Fake3DTranslucent Clip3DFloor;
|
||||
|
||||
FRenderStyle RenderStyle;
|
||||
float RenderAlpha;
|
||||
sector_t *sector;
|
||||
bool fullbrightSprite;
|
||||
int lightlevel;
|
||||
double visibility;
|
||||
uint32_t fillcolor;
|
||||
uint32_t Translation;
|
||||
|
||||
Mat4f ObjectToWorld;
|
||||
PolyClipPlane ClipTop, ClipBottom;
|
||||
FTexture *SkinTexture = nullptr;
|
||||
float InterpolationFactor = 0.0;
|
||||
Mat4f *WorldToClip = nullptr;
|
||||
bool MirrorWorldToClip = false;
|
||||
PolyLight *Lights = nullptr;
|
||||
int NumLights = 0;
|
||||
};
|
||||
|
||||
class SWModelVertexBuffer : public IModelVertexBuffer
|
||||
{
|
||||
public:
|
||||
SWModelVertexBuffer(bool needindex, bool singleframe);
|
||||
~SWModelVertexBuffer();
|
||||
|
||||
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;
|
||||
};
|
||||
#endif
|
||||
}
|
|
@ -97,8 +97,6 @@ namespace swrenderer
|
|||
(r_deathcamera && Thread->Viewport->viewpoint.camera->health <= 0))
|
||||
return;
|
||||
|
||||
renderHUDModel = r_modelscene && IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
|
||||
FDynamicColormap *basecolormap;
|
||||
CameraLight *cameraLight = CameraLight::Instance();
|
||||
auto nc = !!(Thread->Viewport->Level()->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
|
@ -256,12 +254,6 @@ namespace swrenderer
|
|||
sy += wy;
|
||||
}
|
||||
|
||||
if (renderHUDModel)
|
||||
{
|
||||
RenderHUDModel(Thread, pspr, (float)sx, (float)sy);
|
||||
return;
|
||||
}
|
||||
|
||||
auto viewport = Thread->Viewport.get();
|
||||
|
||||
double pspritexscale = viewport->viewwindow.centerxwide / 160.0;
|
||||
|
|
|
@ -97,6 +97,5 @@ namespace swrenderer
|
|||
|
||||
TArray<HWAccelPlayerSprite> AcceleratedSprites;
|
||||
sector_t tempsec;
|
||||
bool renderHUDModel = false;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -316,24 +316,6 @@ namespace swrenderer
|
|||
DrawSegmentList *segmentlist = thread->DrawSegments.get();
|
||||
RenderPortal *renderportal = thread->Portal.get();
|
||||
|
||||
// Render draw segments behind sprite
|
||||
if (r_modelscene)
|
||||
{
|
||||
int subsectordepth = spr->SubsectorDepth;
|
||||
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
|
||||
{
|
||||
DrawSegment *ds = segmentlist->TranslucentSegment(index);
|
||||
if (ds->drawsegclip.SubsectorDepth >= subsectordepth && ds->drawsegclip.CurrentPortalUniq == renderportal->CurrentPortalUniq)
|
||||
{
|
||||
int r1 = max<int>(ds->x1, 0);
|
||||
int r2 = min<int>(ds->x2, viewwidth - 1);
|
||||
|
||||
RenderDrawSegment renderer(thread);
|
||||
renderer.Render(ds, r1, r2, clip3DFloor);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int index = 0; index != segmentlist->TranslucentSegmentsCount(); index++)
|
||||
{
|
||||
|
|
|
@ -83,23 +83,6 @@ namespace swrenderer
|
|||
SortedSprites[i] = Sprites[first + count - i - 1];
|
||||
}
|
||||
|
||||
if (r_modelscene)
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
FVector2 worldPos = SortedSprites[i]->WorldPos().XY();
|
||||
SortedSprites[i]->SubsectorDepth = FindSubsectorDepth(thread, { worldPos.X, worldPos.Y });
|
||||
}
|
||||
|
||||
std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool
|
||||
{
|
||||
if (a->SubsectorDepth != b->SubsectorDepth)
|
||||
return a->SubsectorDepth < b->SubsectorDepth;
|
||||
else
|
||||
return a->SortDist() > b->SortDist();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stable_sort(&SortedSprites[0], &SortedSprites[count], [](VisibleSprite *a, VisibleSprite *b) -> bool
|
||||
{
|
||||
|
|
|
@ -25,11 +25,6 @@
|
|||
|
||||
namespace swrenderer
|
||||
{
|
||||
void SkyDrawerArgs::DrawDepthSkyColumn(RenderThread *thread, float idepth)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->DrawDepthSkyColumn(*this, idepth);
|
||||
}
|
||||
|
||||
void SkyDrawerArgs::DrawSingleSkyColumn(RenderThread *thread)
|
||||
{
|
||||
thread->Drawers(dc_viewport)->DrawSingleSkyColumn(*this);
|
||||
|
|
|
@ -121,11 +121,6 @@ namespace swrenderer
|
|||
}
|
||||
}
|
||||
|
||||
void SpanDrawerArgs::DrawDepthSpan(RenderThread *thread, float idepth1, float idepth2)
|
||||
{
|
||||
thread->Drawers(ds_viewport)->DrawDepthSpan(*this, idepth1, idepth2);
|
||||
}
|
||||
|
||||
void SpanDrawerArgs::DrawSpan(RenderThread *thread)
|
||||
{
|
||||
(thread->Drawers(ds_viewport)->*spanfunc)(*this);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#define MINZ double((2048*4) / double(1 << 20))
|
||||
|
||||
class PolyDepthStencil;
|
||||
|
||||
namespace swrenderer
|
||||
{
|
||||
class RenderThread;
|
||||
|
|
|
@ -228,9 +228,8 @@ BEGIN
|
|||
#ifdef HAVE_VULKAN
|
||||
CONTROL "&Vulkan",IDC_WELCOME_VULKAN2,"Button",BS_AUTORADIOBUTTON,13,176,37,10
|
||||
#endif
|
||||
CONTROL "&SoftPoly",IDC_WELCOME_VULKAN3,"Button",BS_AUTORADIOBUTTON,13,185,43,10
|
||||
#ifdef HAVE_GLES2
|
||||
CONTROL "OpenGL &ES",IDC_WELCOME_VULKAN4,"Button",BS_AUTORADIOBUTTON,13,194,53,10
|
||||
CONTROL "OpenGL &ES",IDC_WELCOME_VULKAN4,"Button",BS_AUTORADIOBUTTON,13,185,53,10
|
||||
#endif
|
||||
END
|
||||
|
||||
|
|
Loading…
Reference in a new issue