mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-24 21:01:18 +00:00
- remove softpoly scene drawer
This commit is contained in:
parent
0eda298db2
commit
48d2d423f6
44 changed files with 48 additions and 6693 deletions
|
@ -713,7 +713,6 @@ file( GLOB HEADER_FILES
|
|||
rendering/polyrenderer/*.h
|
||||
rendering/polyrenderer/math/*.h
|
||||
rendering/polyrenderer/drawers/*.h
|
||||
rendering/polyrenderer/scene/*.h
|
||||
rendering/polyrenderer/backend/*.h
|
||||
rendering/hwrenderer/data/*.h
|
||||
rendering/hwrenderer/dynlights/*.h
|
||||
|
@ -786,21 +785,6 @@ set ( SWRENDER_SOURCES
|
|||
)
|
||||
|
||||
set( POLYRENDER_SOURCES
|
||||
rendering/polyrenderer/poly_renderer.cpp
|
||||
rendering/polyrenderer/poly_renderthread.cpp
|
||||
rendering/polyrenderer/scene/poly_scene.cpp
|
||||
rendering/polyrenderer/scene/poly_portal.cpp
|
||||
rendering/polyrenderer/scene/poly_cull.cpp
|
||||
rendering/polyrenderer/scene/poly_decal.cpp
|
||||
rendering/polyrenderer/scene/poly_particle.cpp
|
||||
rendering/polyrenderer/scene/poly_plane.cpp
|
||||
rendering/polyrenderer/scene/poly_playersprite.cpp
|
||||
rendering/polyrenderer/scene/poly_wall.cpp
|
||||
rendering/polyrenderer/scene/poly_wallsprite.cpp
|
||||
rendering/polyrenderer/scene/poly_sprite.cpp
|
||||
rendering/polyrenderer/scene/poly_model.cpp
|
||||
rendering/polyrenderer/scene/poly_sky.cpp
|
||||
rendering/polyrenderer/scene/poly_light.cpp
|
||||
rendering/polyrenderer/drawers/poly_buffer.cpp
|
||||
rendering/polyrenderer/drawers/poly_triangle.cpp
|
||||
rendering/polyrenderer/drawers/poly_draw_args.cpp
|
||||
|
@ -1564,7 +1548,6 @@ source_group("Rendering\\Software Renderer\\Viewport" REGULAR_EXPRESSION "^${CMA
|
|||
source_group("Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/math/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/drawers/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/scene/.+")
|
||||
source_group("Rendering\\Poly Renderer\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/backend/.+")
|
||||
source_group("Render Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+")
|
||||
source_group("Render Data\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/models/.+")
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "swrenderer/r_swcolormaps.h"
|
||||
#include "poly_draw_args.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
void PolyDrawArgs::SetTexture(const uint8_t *texels, int width, int height)
|
||||
{
|
||||
|
@ -97,13 +97,6 @@ void PolyDrawArgs::SetLight(FSWColormap *base_colormap, uint32_t lightlevel, dou
|
|||
{
|
||||
mGlobVis = (float)globVis;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
lightlevel = cameraLight->FixedLightLevel() >= 0 ? cameraLight->FixedLightLevel() : 255;
|
||||
fixed = true;
|
||||
}
|
||||
|
||||
mLight = clamp<uint32_t>(lightlevel, 0, 255);
|
||||
mFixedLight = fixed;
|
||||
mLightRed = base_colormap->Color.r;
|
||||
|
@ -203,6 +196,7 @@ void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint3
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
void RectDrawArgs::SetTexture(FSoftwareTexture *texture, FRenderStyle style)
|
||||
{
|
||||
mTexture = texture;
|
||||
|
@ -351,3 +345,4 @@ void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint3
|
|||
SetStyle(Translation() ? TriBlendMode::AddShadedTranslated : TriBlendMode::AddShaded, alpha);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -167,6 +167,7 @@ private:
|
|||
uint32_t mDynLightColor = 0;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class RectDrawArgs
|
||||
{
|
||||
public:
|
||||
|
@ -233,3 +234,4 @@ private:
|
|||
bool mSimpleShade = true;
|
||||
float mX0, mX1, mY0, mY1, mU0, mU1, mV0, mV1;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "v_palette.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "poly_triangle.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||
#include "screen_triangle.h"
|
||||
#include "x86.h"
|
||||
|
@ -724,6 +723,7 @@ void DrawPolyTrianglesCommand::Execute(DrawerThread *thread)
|
|||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
void DrawRectCommand::Execute(DrawerThread *thread)
|
||||
{
|
||||
auto renderTarget = PolyRenderer::Instance()->RenderTarget;
|
||||
|
@ -737,3 +737,4 @@ void DrawRectCommand::Execute(DrawerThread *thread)
|
|||
else
|
||||
ScreenTriangle::RectDrawers8[blendmode](destOrg, destWidth, destHeight, destPitch, &args, PolyTriangleThreadData::Get(thread));
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -240,6 +240,7 @@ private:
|
|||
PolyDrawMode mode;
|
||||
};
|
||||
|
||||
#if 0
|
||||
class DrawRectCommand : public PolyDrawerCommand
|
||||
{
|
||||
public:
|
||||
|
@ -250,3 +251,4 @@ public:
|
|||
private:
|
||||
RectDrawArgs args;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -1588,6 +1588,7 @@ void DrawSpan8(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTrian
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<typename ModeT>
|
||||
void DrawRect8(const void *destOrg, int destWidth, int destHeight, int destPitch, const RectDrawArgs *args, PolyTriangleThreadData *thread)
|
||||
{
|
||||
|
@ -2115,6 +2116,7 @@ void DrawRect32(const void *destOrg, int destWidth, int destHeight, int destPitc
|
|||
else
|
||||
DrawRectOpt32<ModeT, DrawerOptCF>(destOrg, destWidth, destHeight, destPitch, args, thread);
|
||||
}
|
||||
#endif
|
||||
|
||||
void(*ScreenTriangle::SpanDrawers8[])(int, int, int, const TriDrawTriangleArgs *, PolyTriangleThreadData *) =
|
||||
{
|
||||
|
@ -2180,6 +2182,7 @@ void(*ScreenTriangle::SpanDrawers32[])(int, int, int, const TriDrawTriangleArgs
|
|||
&DrawSpan32<TriScreenDrawerModes::StyleAddShadedTranslated>
|
||||
};
|
||||
|
||||
#if 0
|
||||
void(*ScreenTriangle::RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *) =
|
||||
{
|
||||
&DrawRect8<TriScreenDrawerModes::StyleOpaque>,
|
||||
|
@ -2243,6 +2246,7 @@ void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDr
|
|||
&DrawRect32<TriScreenDrawerModes::StyleAddStencilTranslated>,
|
||||
&DrawRect32<TriScreenDrawerModes::StyleAddShadedTranslated>
|
||||
};
|
||||
#endif
|
||||
|
||||
void(*ScreenTriangle::TriangleDrawers[])(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread, int16_t *edges, int topY, int bottomY) =
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "r_data/renderstyle.h"
|
||||
#include "rendering/swrenderer/drawers/r_draw.h"
|
||||
|
||||
class FString;
|
||||
class PolyDrawArgs;
|
||||
|
@ -138,8 +139,10 @@ public:
|
|||
|
||||
static void(*SpanDrawers8[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
|
||||
static void(*SpanDrawers32[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
|
||||
#if 0
|
||||
static void(*RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *);
|
||||
static void(*RectDrawers32[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *);
|
||||
#endif
|
||||
|
||||
static int FuzzStart;
|
||||
};
|
||||
|
|
|
@ -1,21 +1,6 @@
|
|||
#include "../swrenderer/textures/r_swtexture.h"
|
||||
#include "poly_renderer.cpp"
|
||||
#include "poly_renderthread.cpp"
|
||||
#include "drawers/poly_buffer.cpp"
|
||||
#include "drawers/poly_draw_args.cpp"
|
||||
#include "drawers/poly_triangle.cpp"
|
||||
#include "drawers/screen_triangle.cpp"
|
||||
#include "math/gpu_types.cpp"
|
||||
#include "scene/poly_cull.cpp"
|
||||
#include "scene/poly_decal.cpp"
|
||||
#include "scene/poly_particle.cpp"
|
||||
#include "scene/poly_plane.cpp"
|
||||
#include "scene/poly_playersprite.cpp"
|
||||
#include "scene/poly_portal.cpp"
|
||||
#include "scene/poly_scene.cpp"
|
||||
#include "scene/poly_sky.cpp"
|
||||
#include "scene/poly_sprite.cpp"
|
||||
#include "scene/poly_model.cpp"
|
||||
#include "scene/poly_wall.cpp"
|
||||
#include "scene/poly_wallsprite.cpp"
|
||||
#include "scene/poly_light.cpp"
|
||||
|
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "st_stuff.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "r_data/r_interpolate.h"
|
||||
#include "r_data/models/models.h"
|
||||
#include "poly_renderer.h"
|
||||
#include "d_net.h"
|
||||
#include "po_man.h"
|
||||
#include "st_stuff.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "p_effect.h"
|
||||
#include "actorinlines.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||
#include "swrenderer/viewport/r_viewport.h"
|
||||
#include "swrenderer/r_swcolormaps.h"
|
||||
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
EXTERN_CVAR(Float, r_visibility)
|
||||
EXTERN_CVAR(Bool, r_models)
|
||||
|
||||
extern bool r_modelscene;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyRenderer *PolyRenderer::Instance()
|
||||
{
|
||||
static PolyRenderer scene;
|
||||
return &scene;
|
||||
}
|
||||
|
||||
PolyRenderer::PolyRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch)
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
R_ExecuteSetViewSize(Viewpoint, Viewwindow);
|
||||
|
||||
RenderTarget = target;
|
||||
RenderToCanvas = false;
|
||||
|
||||
RenderActorView(player->mo, true, false);
|
||||
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(Threads.MainThread()->FrameMemory.get());
|
||||
copyqueue->Push<MemcpyCommand>(videobuffer, bufferpitch, target->GetPixels(), target->GetWidth(), target->GetHeight(), target->GetPitch(), target->IsBgra() ? 4 : 1);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
|
||||
PolyDrawerWaitCycles.Clock();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
PolyDrawerWaitCycles.Unclock();
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines)
|
||||
{
|
||||
// Save a bunch of silly globals:
|
||||
auto savedViewpoint = Viewpoint;
|
||||
auto savedViewwindow = Viewwindow;
|
||||
auto savedviewwindowx = viewwindowx;
|
||||
auto savedviewwindowy = viewwindowy;
|
||||
auto savedviewwidth = viewwidth;
|
||||
auto savedviewheight = viewheight;
|
||||
auto savedviewactive = viewactive;
|
||||
auto savedRenderTarget = RenderTarget;
|
||||
|
||||
// Setup the view:
|
||||
RenderTarget = canvas;
|
||||
RenderToCanvas = true;
|
||||
R_SetWindow(Viewpoint, Viewwindow, 12, width, height, height, true);
|
||||
viewwindowx = x;
|
||||
viewwindowy = y;
|
||||
viewactive = true;
|
||||
|
||||
// Render:
|
||||
RenderActorView(actor, false, dontmaplines);
|
||||
Threads.MainThread()->FlushDrawQueue();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
RenderToCanvas = false;
|
||||
|
||||
// Restore silly globals:
|
||||
Viewpoint = savedViewpoint;
|
||||
Viewwindow = savedViewwindow;
|
||||
viewwindowx = savedviewwindowx;
|
||||
viewwindowy = savedviewwindowy;
|
||||
viewwidth = savedviewwidth;
|
||||
viewheight = savedviewheight;
|
||||
viewactive = savedviewactive;
|
||||
RenderTarget = savedRenderTarget;
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderActorView(AActor *actor, bool drawpsprites, bool dontmaplines)
|
||||
{
|
||||
PolyTotalBatches = 0;
|
||||
PolyTotalTriangles = 0;
|
||||
PolyTotalDrawCalls = 0;
|
||||
PolyCullCycles.Reset();
|
||||
PolyOpaqueCycles.Reset();
|
||||
PolyMaskedCycles.Reset();
|
||||
PolyDrawerWaitCycles.Reset();
|
||||
|
||||
DontMapLines = dontmaplines;
|
||||
|
||||
R_SetupFrame(Viewpoint, Viewwindow, actor);
|
||||
Level = Viewpoint.ViewLevel;
|
||||
|
||||
static bool firstcall = true;
|
||||
if (firstcall)
|
||||
{
|
||||
swrenderer::R_InitFuzzTable(RenderTarget->GetPitch());
|
||||
firstcall = false;
|
||||
}
|
||||
|
||||
swrenderer::R_UpdateFuzzPosFrameStart();
|
||||
|
||||
if (APART(R_OldBlend)) NormalLight.Maps = realcolormaps.Maps;
|
||||
else NormalLight.Maps = realcolormaps.Maps + NUMCOLORMAPS * 256 * R_OldBlend;
|
||||
|
||||
Light.SetVisibility(Viewwindow, r_visibility);
|
||||
|
||||
PolyCameraLight::Instance()->SetCamera(Viewpoint, RenderTarget, actor);
|
||||
//Viewport->SetupFreelook();
|
||||
|
||||
ActorRenderFlags savedflags = 0;
|
||||
if (Viewpoint.camera)
|
||||
{
|
||||
savedflags = Viewpoint.camera->renderflags;
|
||||
|
||||
// Never draw the player unless in chasecam mode
|
||||
if (!Viewpoint.showviewer)
|
||||
Viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
|
||||
ScreenTriangle::FuzzStart = (ScreenTriangle::FuzzStart + 14) % FUZZTABLE;
|
||||
|
||||
r_modelscene = r_models && Models.Size() > 0;
|
||||
|
||||
NextStencilValue = 0;
|
||||
Threads.Clear();
|
||||
Threads.MainThread()->SectorPortals.clear();
|
||||
Threads.MainThread()->LinePortals.clear();
|
||||
Threads.MainThread()->TranslucentObjects.clear();
|
||||
|
||||
PolyTriangleDrawer::ResizeBuffers(RenderTarget);
|
||||
PolyTriangleDrawer::ClearStencil(Threads.MainThread()->DrawQueue, 0);
|
||||
SetSceneViewport();
|
||||
|
||||
PolyPortalViewpoint mainViewpoint = SetupPerspectiveMatrix();
|
||||
mainViewpoint.StencilValue = GetNextStencilValue();
|
||||
Scene.CurrentViewpoint = &mainViewpoint;
|
||||
Scene.Render(&mainViewpoint);
|
||||
if (drawpsprites)
|
||||
PlayerSprites.Render(Threads.MainThread());
|
||||
|
||||
Scene.CurrentViewpoint = nullptr;
|
||||
|
||||
if (Viewpoint.camera)
|
||||
Viewpoint.camera->renderflags = savedflags;
|
||||
}
|
||||
|
||||
void PolyRenderer::RenderRemainingPlayerSprites()
|
||||
{
|
||||
PlayerSprites.RenderRemainingSprites();
|
||||
}
|
||||
|
||||
void PolyRenderer::SetSceneViewport()
|
||||
{
|
||||
using namespace swrenderer;
|
||||
|
||||
if (!RenderToCanvas) // Rendering to screen
|
||||
{
|
||||
int height;
|
||||
if (screenblocks >= 10)
|
||||
height = SCREENHEIGHT;
|
||||
else
|
||||
height = (screenblocks*SCREENHEIGHT / 10) & ~7;
|
||||
|
||||
int bottom = SCREENHEIGHT - (height + viewwindowy - ((height - viewheight) / 2));
|
||||
PolyTriangleDrawer::SetViewport(Threads.MainThread()->DrawQueue, viewwindowx, SCREENHEIGHT - bottom - height, viewwidth, height, RenderTarget);
|
||||
}
|
||||
else // Rendering to camera texture
|
||||
{
|
||||
PolyTriangleDrawer::SetViewport(Threads.MainThread()->DrawQueue, 0, 0, RenderTarget->GetWidth(), RenderTarget->GetHeight(), RenderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
PolyPortalViewpoint PolyRenderer::SetupPerspectiveMatrix(bool mirror)
|
||||
{
|
||||
// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
|
||||
double radPitch = Viewpoint.Angles.Pitch.Normalized180().Radians();
|
||||
double angx = cos(radPitch);
|
||||
double angy = sin(radPitch) * PolyRenderer::Instance()->Level->info->pixelstretch;
|
||||
double alen = sqrt(angx*angx + angy*angy);
|
||||
float adjustedPitch = (float)asin(angy / alen);
|
||||
float adjustedViewAngle = (float)(Viewpoint.Angles.Yaw - 90).Radians();
|
||||
|
||||
float ratio = Viewwindow.WidescreenRatio;
|
||||
float fovratio = (Viewwindow.WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
|
||||
|
||||
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(Viewpoint.FieldOfView.Radians() / 2) / fovratio)).Degrees);
|
||||
|
||||
PolyPortalViewpoint portalViewpoint;
|
||||
|
||||
portalViewpoint.WorldToView =
|
||||
Mat4f::Rotate((float)Viewpoint.Angles.Roll.Radians(), 0.0f, 0.0f, 1.0f) *
|
||||
Mat4f::Rotate(adjustedPitch, 1.0f, 0.0f, 0.0f) *
|
||||
Mat4f::Rotate(adjustedViewAngle, 0.0f, -1.0f, 0.0f) *
|
||||
Mat4f::Scale(1.0f, PolyRenderer::Instance()->Level->info->pixelstretch, 1.0f) *
|
||||
Mat4f::SwapYZ() *
|
||||
Mat4f::Translate((float)-Viewpoint.Pos.X, (float)-Viewpoint.Pos.Y, (float)-Viewpoint.Pos.Z);
|
||||
|
||||
portalViewpoint.Mirror = mirror;
|
||||
|
||||
if (mirror)
|
||||
portalViewpoint.WorldToView = Mat4f::Scale(-1.0f, 1.0f, 1.0f) * portalViewpoint.WorldToView;
|
||||
|
||||
portalViewpoint.WorldToClip = Mat4f::Perspective(fovy, ratio, 5.0f, 65535.0f, Handedness::Right, ClipZRange::NegativePositiveW) * portalViewpoint.WorldToView;
|
||||
|
||||
return portalViewpoint;
|
||||
}
|
||||
|
||||
cycle_t PolyCullCycles, PolyOpaqueCycles, PolyMaskedCycles, PolyDrawerWaitCycles;
|
||||
int PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls;
|
||||
|
||||
ADD_STAT(polyfps)
|
||||
{
|
||||
FString out;
|
||||
out.Format("frame=%04.1f ms cull=%04.1f ms opaque=%04.1f ms masked=%04.1f ms drawers=%04.1f ms",
|
||||
FrameCycles.TimeMS(), PolyCullCycles.TimeMS(), PolyOpaqueCycles.TimeMS(), PolyMaskedCycles.TimeMS(), PolyDrawerWaitCycles.TimeMS());
|
||||
out.AppendFormat("\nbatches drawn: %d triangles drawn: %d drawcalls: %d", PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls);
|
||||
return out;
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "doomdata.h"
|
||||
#include "r_utility.h"
|
||||
#include "scene/poly_portal.h"
|
||||
#include "scene/poly_playersprite.h"
|
||||
#include "scene/poly_light.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "poly_renderthread.h"
|
||||
#include "stats.h"
|
||||
|
||||
class AActor;
|
||||
class DCanvas;
|
||||
class PolyPortalViewpoint;
|
||||
class DrawerCommandQueue;
|
||||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
|
||||
extern cycle_t PolyCullCycles, PolyOpaqueCycles, PolyMaskedCycles, PolyDrawerWaitCycles;
|
||||
extern int PolyTotalBatches, PolyTotalTriangles, PolyTotalDrawCalls;
|
||||
|
||||
class PolyRenderer
|
||||
{
|
||||
public:
|
||||
PolyRenderer();
|
||||
|
||||
void RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch);
|
||||
void RenderViewToCanvas(AActor *actor, DCanvas *canvas, int x, int y, int width, int height, bool dontmaplines);
|
||||
void RenderRemainingPlayerSprites();
|
||||
|
||||
static PolyRenderer *Instance();
|
||||
|
||||
PolyPortalViewpoint SetupPerspectiveMatrix(bool mirror = false);
|
||||
|
||||
uint32_t GetNextStencilValue() { uint32_t value = NextStencilValue; NextStencilValue += 2; return value; }
|
||||
|
||||
bool DontMapLines = false;
|
||||
|
||||
PolyRenderThreads Threads;
|
||||
DCanvas *RenderTarget = nullptr;
|
||||
bool RenderToCanvas = false;
|
||||
FViewWindow Viewwindow;
|
||||
FRenderViewpoint Viewpoint;
|
||||
PolyLightVisibility Light;
|
||||
RenderPolyScene Scene;
|
||||
FLevelLocals *Level;
|
||||
|
||||
private:
|
||||
void RenderActorView(AActor *actor, bool drawpsprites, bool dontmaplines);
|
||||
void SetSceneViewport();
|
||||
|
||||
RenderPolyPlayerSprites PlayerSprites;
|
||||
uint32_t NextStencilValue = 0;
|
||||
};
|
|
@ -1,268 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "m_bbox.h"
|
||||
|
||||
#include "p_lnspec.h"
|
||||
#include "p_setup.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "g_level.h"
|
||||
#include "p_effect.h"
|
||||
#include "doomstat.h"
|
||||
#include "r_state.h"
|
||||
#include "v_palette.h"
|
||||
#include "r_sky.h"
|
||||
#include "po_man.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "poly_renderthread.h"
|
||||
#include "poly_renderer.h"
|
||||
#include <mutex>
|
||||
|
||||
#ifdef WIN32
|
||||
void PeekThreadedErrorPane();
|
||||
#endif
|
||||
|
||||
EXTERN_CVAR(Int, r_scene_multithreaded);
|
||||
|
||||
PolyRenderThread::PolyRenderThread(int threadIndex) : MainThread(threadIndex == 0), ThreadIndex(threadIndex)
|
||||
{
|
||||
FrameMemory.reset(new RenderMemory());
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
|
||||
PolyRenderThread::~PolyRenderThread()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderThread::FlushDrawQueue()
|
||||
{
|
||||
DrawerThreads::Execute(DrawQueue);
|
||||
|
||||
UsedDrawQueues.push_back(DrawQueue);
|
||||
DrawQueue.reset();
|
||||
|
||||
if (!FreeDrawQueues.empty())
|
||||
{
|
||||
DrawQueue = FreeDrawQueues.back();
|
||||
FreeDrawQueues.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawQueue = std::make_shared<DrawerCommandQueue>(FrameMemory.get());
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex loadmutex;
|
||||
void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style)
|
||||
{
|
||||
if (texture == nullptr)
|
||||
return;
|
||||
|
||||
// Textures may not have loaded/refreshed yet. The shared code doing
|
||||
// this is not thread safe. By calling GetPixels in a mutex lock we
|
||||
// make sure that only one thread is loading a texture at any given
|
||||
// time.
|
||||
//
|
||||
// It is critical that this function is called before any direct
|
||||
// calls to GetPixels for this to work.
|
||||
|
||||
std::unique_lock<std::mutex> lock(loadmutex);
|
||||
|
||||
const FSoftwareTextureSpan *spans;
|
||||
if (PolyRenderer::Instance()->RenderTarget->IsBgra())
|
||||
{
|
||||
texture->GetPixelsBgra();
|
||||
texture->GetColumnBgra(0, &spans);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool alpha = !!(style.Flags & STYLEF_RedIsAlpha);
|
||||
texture->GetPixels(alpha);
|
||||
texture->GetColumn(alpha, 0, &spans);
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex polyobjmutex;
|
||||
void PolyRenderThread::PreparePolyObject(subsector_t *sub)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(polyobjmutex);
|
||||
|
||||
if (sub->BSP == nullptr || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyRenderThreads::PolyRenderThreads()
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread(0));
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
|
||||
PolyRenderThreads::~PolyRenderThreads()
|
||||
{
|
||||
StopThreads();
|
||||
}
|
||||
|
||||
void PolyRenderThreads::Clear()
|
||||
{
|
||||
for (auto &thread : Threads)
|
||||
{
|
||||
thread->FrameMemory->Clear();
|
||||
thread->DrawQueue->Clear();
|
||||
|
||||
while (!thread->UsedDrawQueues.empty())
|
||||
{
|
||||
auto queue = thread->UsedDrawQueues.back();
|
||||
thread->UsedDrawQueues.pop_back();
|
||||
queue->Clear();
|
||||
thread->FreeDrawQueues.push_back(queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback)
|
||||
{
|
||||
WorkerCallback = workerCallback;
|
||||
|
||||
int numThreads = std::thread::hardware_concurrency();
|
||||
if (numThreads == 0)
|
||||
numThreads = 1;
|
||||
|
||||
if (r_scene_multithreaded == 0 || r_multithreaded == 0)
|
||||
numThreads = 1;
|
||||
else if (r_scene_multithreaded != 1)
|
||||
numThreads = r_scene_multithreaded;
|
||||
|
||||
if (numThreads != (int)Threads.size())
|
||||
{
|
||||
StopThreads();
|
||||
StartThreads(numThreads);
|
||||
}
|
||||
|
||||
// Setup threads:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->Start = totalcount * i / numThreads;
|
||||
Threads[i]->End = totalcount * (i + 1) / numThreads;
|
||||
}
|
||||
run_id++;
|
||||
start_lock.unlock();
|
||||
|
||||
// Notify threads to run
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
start_condition.notify_all();
|
||||
}
|
||||
|
||||
// Do the main thread ourselves:
|
||||
RenderThreadSlice(MainThread());
|
||||
|
||||
// Wait for everyone to finish:
|
||||
if (Threads.size() > 1)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
if (!end_condition.wait_for(end_lock, 5s, [&]() { return finished_threads == Threads.size(); }))
|
||||
{
|
||||
#ifdef WIN32
|
||||
PeekThreadedErrorPane();
|
||||
#endif
|
||||
// Invoke the crash reporter so that we can capture the call stack of whatever the hung worker thread is doing
|
||||
int *threadCrashed = nullptr;
|
||||
*threadCrashed = 0xdeadbeef;
|
||||
}
|
||||
finished_threads = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numThreads; i++)
|
||||
{
|
||||
Threads[i]->FlushDrawQueue();
|
||||
}
|
||||
|
||||
WorkerCallback = {};
|
||||
|
||||
for (int i = 1; i < numThreads; i++)
|
||||
{
|
||||
collectCallback(Threads[i].get());
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::RenderThreadSlice(PolyRenderThread *thread)
|
||||
{
|
||||
WorkerCallback(thread);
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StartThreads(size_t numThreads)
|
||||
{
|
||||
while (Threads.size() < (size_t)numThreads)
|
||||
{
|
||||
std::unique_ptr<PolyRenderThread> thread(new PolyRenderThread((int)Threads.size()));
|
||||
auto renderthread = thread.get();
|
||||
int start_run_id = run_id;
|
||||
thread->thread = std::thread([=]()
|
||||
{
|
||||
int last_run_id = start_run_id;
|
||||
while (true)
|
||||
{
|
||||
// Wait until we are signalled to run:
|
||||
std::unique_lock<std::mutex> start_lock(start_mutex);
|
||||
start_condition.wait(start_lock, [&]() { return run_id != last_run_id || shutdown_flag; });
|
||||
if (shutdown_flag)
|
||||
break;
|
||||
last_run_id = run_id;
|
||||
start_lock.unlock();
|
||||
|
||||
RenderThreadSlice(renderthread);
|
||||
|
||||
// Notify main thread that we finished:
|
||||
std::unique_lock<std::mutex> end_lock(end_mutex);
|
||||
finished_threads++;
|
||||
end_lock.unlock();
|
||||
end_condition.notify_all();
|
||||
}
|
||||
});
|
||||
Threads.push_back(std::move(thread));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderThreads::StopThreads()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(start_mutex);
|
||||
shutdown_flag = true;
|
||||
lock.unlock();
|
||||
start_condition.notify_all();
|
||||
while (Threads.size() > 1)
|
||||
{
|
||||
Threads.back()->thread.join();
|
||||
Threads.pop_back();
|
||||
}
|
||||
lock.lock();
|
||||
shutdown_flag = false;
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include "swrenderer/r_memory.h"
|
||||
|
||||
class DrawerCommandQueue;
|
||||
typedef std::shared_ptr<DrawerCommandQueue> DrawerCommandQueuePtr;
|
||||
class RenderMemory;
|
||||
class PolyTranslucentObject;
|
||||
class PolyDrawSectorPortal;
|
||||
class PolyDrawLinePortal;
|
||||
struct FDynamicLight;
|
||||
|
||||
class PolyRenderThread
|
||||
{
|
||||
public:
|
||||
PolyRenderThread(int threadIndex);
|
||||
~PolyRenderThread();
|
||||
|
||||
void FlushDrawQueue();
|
||||
|
||||
int Start = 0;
|
||||
int End = 0;
|
||||
bool MainThread = false;
|
||||
int ThreadIndex = 0;
|
||||
|
||||
std::unique_ptr<RenderMemory> FrameMemory;
|
||||
DrawerCommandQueuePtr DrawQueue;
|
||||
|
||||
std::vector<PolyTranslucentObject *> TranslucentObjects;
|
||||
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
|
||||
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;
|
||||
|
||||
TArray<FDynamicLight*> AddedLightsArray;
|
||||
|
||||
// Make sure texture can accessed safely
|
||||
void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style);
|
||||
|
||||
// Setup poly object in a threadsafe manner
|
||||
void PreparePolyObject(subsector_t *sub);
|
||||
|
||||
private:
|
||||
std::thread thread;
|
||||
std::vector<DrawerCommandQueuePtr> UsedDrawQueues;
|
||||
std::vector<DrawerCommandQueuePtr> FreeDrawQueues;
|
||||
|
||||
friend class PolyRenderThreads;
|
||||
};
|
||||
|
||||
class PolyRenderThreads
|
||||
{
|
||||
public:
|
||||
PolyRenderThreads();
|
||||
~PolyRenderThreads();
|
||||
|
||||
void Clear();
|
||||
void RenderThreadSlices(int totalcount, std::function<void(PolyRenderThread *)> workerCallback, std::function<void(PolyRenderThread *)> collectCallback);
|
||||
|
||||
PolyRenderThread *MainThread() { return Threads.front().get(); }
|
||||
int NumThreads() const { return (int)Threads.size(); }
|
||||
|
||||
std::vector<std::unique_ptr<PolyRenderThread>> Threads;
|
||||
|
||||
private:
|
||||
void RenderThreadSlice(PolyRenderThread *thread);
|
||||
|
||||
void StartThreads(size_t numThreads);
|
||||
void StopThreads();
|
||||
|
||||
std::function<void(PolyRenderThread *)> WorkerCallback;
|
||||
|
||||
std::mutex start_mutex;
|
||||
std::condition_variable start_condition;
|
||||
bool shutdown_flag = false;
|
||||
int run_id = 0;
|
||||
std::mutex end_mutex;
|
||||
std::condition_variable end_condition;
|
||||
size_t finished_threads = 0;
|
||||
};
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_cull.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
|
||||
void PolyCull::CullScene(sector_t *portalSector, line_t *portalLine)
|
||||
{
|
||||
for (uint32_t sub : PvsSubsectors)
|
||||
SubsectorDepths[sub] = 0xffffffff;
|
||||
SubsectorDepths.resize(PolyRenderer::Instance()->Level->subsectors.Size(), 0xffffffff);
|
||||
|
||||
for (uint32_t sector : SeenSectors)
|
||||
SectorSeen[sector] = false;
|
||||
SectorSeen.resize(PolyRenderer::Instance()->Level->sectors.Size());
|
||||
|
||||
PvsSubsectors.clear();
|
||||
SeenSectors.clear();
|
||||
|
||||
NextPvsLineStart = 0;
|
||||
PvsLineStart.clear();
|
||||
PvsLineVisible.resize(PolyRenderer::Instance()->Level->segs.Size());
|
||||
|
||||
PortalSector = portalSector;
|
||||
PortalLine = portalLine;
|
||||
|
||||
SolidSegments.clear();
|
||||
|
||||
if (portalLine)
|
||||
{
|
||||
DVector3 viewpos = PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
DVector2 pt1 = portalLine->v1->fPos() - viewpos;
|
||||
DVector2 pt2 = portalLine->v2->fPos() - viewpos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
{
|
||||
angle_t angle1 = PointToPseudoAngle(portalLine->v1->fX(), portalLine->v1->fY());
|
||||
angle_t angle2 = PointToPseudoAngle(portalLine->v2->fX(), portalLine->v2->fY());
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t angle2 = PointToPseudoAngle(portalLine->v1->fX(), portalLine->v1->fY());
|
||||
angle_t angle1 = PointToPseudoAngle(portalLine->v2->fX(), portalLine->v2->fY());
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
InvertSegments();
|
||||
}
|
||||
else
|
||||
{
|
||||
MarkViewFrustum();
|
||||
}
|
||||
|
||||
// Cull front to back
|
||||
FirstSkyHeight = true;
|
||||
MaxCeilingHeight = 0.0;
|
||||
MinFloorHeight = 0.0;
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
CullSubsector(&PolyRenderer::Instance()->Level->subsectors[0]);
|
||||
else
|
||||
CullNode(PolyRenderer::Instance()->Level->HeadNode());
|
||||
}
|
||||
|
||||
void PolyCull::CullNode(void *node)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
// Decide which side the view point is on.
|
||||
int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
CullNode(bsp->children[side]);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
if (!CheckBBox(bsp->bbox[side]))
|
||||
return;
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
CullSubsector(sub);
|
||||
}
|
||||
|
||||
void PolyCull::CullSubsector(subsector_t *sub)
|
||||
{
|
||||
// Ignore everything in front of the portal
|
||||
if (PortalSector)
|
||||
{
|
||||
if (sub->sector != PortalSector)
|
||||
return;
|
||||
PortalSector = nullptr;
|
||||
}
|
||||
|
||||
// Update sky heights for the scene
|
||||
if (!FirstSkyHeight)
|
||||
{
|
||||
MaxCeilingHeight = MAX(MaxCeilingHeight, sub->sector->ceilingplane.Zat0());
|
||||
MinFloorHeight = MIN(MinFloorHeight, sub->sector->floorplane.Zat0());
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxCeilingHeight = sub->sector->ceilingplane.Zat0();
|
||||
MinFloorHeight = sub->sector->floorplane.Zat0();
|
||||
FirstSkyHeight = false;
|
||||
}
|
||||
|
||||
uint32_t subsectorDepth = (uint32_t)PvsSubsectors.size();
|
||||
|
||||
// Mark that we need to render this
|
||||
PvsSubsectors.push_back(sub->Index());
|
||||
PvsLineStart.push_back(NextPvsLineStart);
|
||||
|
||||
DVector3 viewpos = PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
|
||||
// Update culling info for further bsp clipping
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
// Skip lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
{
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not draw the portal line
|
||||
if (line->linedef == PortalLine)
|
||||
{
|
||||
PvsLineVisible[NextPvsLineStart++] = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
angle_t angle2 = PointToPseudoAngle(line->v1->fX(), line->v1->fY());
|
||||
angle_t angle1 = PointToPseudoAngle(line->v2->fX(), line->v2->fY());
|
||||
bool lineVisible = !IsSegmentCulled(angle1, angle2);
|
||||
if (lineVisible && IsSolidLine(line))
|
||||
{
|
||||
MarkSegmentCulled(angle1, angle2);
|
||||
}
|
||||
|
||||
// Mark if this line was visible
|
||||
PvsLineVisible[NextPvsLineStart++] = lineVisible;
|
||||
}
|
||||
|
||||
if (!SectorSeen[sub->sector->Index()])
|
||||
{
|
||||
SectorSeen[sub->sector->Index()] = true;
|
||||
SeenSectors.push_back(sub->sector->Index());
|
||||
}
|
||||
|
||||
SubsectorDepths[sub->Index()] = subsectorDepth;
|
||||
}
|
||||
|
||||
bool PolyCull::IsSolidLine(seg_t *line)
|
||||
{
|
||||
// One-sided
|
||||
if (!line->backsector) return true;
|
||||
|
||||
// Portal
|
||||
if (line->linedef && line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0]) return true;
|
||||
|
||||
double frontCeilingZ1 = line->frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontFloorZ1 = line->frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontCeilingZ2 = line->frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontFloorZ2 = line->frontsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double backCeilingZ1 = line->backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backFloorZ1 = line->backsector->floorplane.ZatPoint(line->v1);
|
||||
double backCeilingZ2 = line->backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backFloorZ2 = line->backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
// Closed door.
|
||||
if (backCeilingZ1 <= frontFloorZ1 && backCeilingZ2 <= frontFloorZ2) return true;
|
||||
if (backFloorZ1 >= frontCeilingZ1 && backFloorZ2 >= frontCeilingZ2) return true;
|
||||
|
||||
// properly render skies (consider door "open" if both ceilings are sky)
|
||||
if (line->backsector->GetTexture(sector_t::ceiling) == skyflatnum && line->frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false;
|
||||
|
||||
// if door is closed because back is shut:
|
||||
if (!(backCeilingZ1 <= backFloorZ1 && backCeilingZ2 <= backFloorZ2)) return false;
|
||||
|
||||
// preserve a kind of transparent door/lift special effect:
|
||||
if (((backCeilingZ1 >= frontCeilingZ1 && backCeilingZ2 >= frontCeilingZ2) || line->sidedef->GetTexture(side_t::top).isValid())
|
||||
&& ((backFloorZ1 <= frontFloorZ1 && backFloorZ2 <= frontFloorZ2) || line->sidedef->GetTexture(side_t::bottom).isValid()))
|
||||
{
|
||||
// killough 1/18/98 -- This function is used to fix the automap bug which
|
||||
// showed lines behind closed doors simply because the door had a dropoff.
|
||||
//
|
||||
// It assumes that Doom has already ruled out a door being closed because
|
||||
// of front-back closure (e.g. front floor is taller than back ceiling).
|
||||
|
||||
// This fixes the automap floor height bug -- killough 1/18/98:
|
||||
// killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PolyCull::IsSegmentCulled(angle_t startAngle, angle_t endAngle) const
|
||||
{
|
||||
if (startAngle > endAngle)
|
||||
{
|
||||
return IsSegmentCulled(startAngle, ANGLE_MAX) && IsSegmentCulled(0, endAngle);
|
||||
}
|
||||
|
||||
for (const auto &segment : SolidSegments)
|
||||
{
|
||||
if (startAngle >= segment.Start && endAngle <= segment.End)
|
||||
return true;
|
||||
else if (endAngle < segment.Start)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PolyCull::MarkSegmentCulled(angle_t startAngle, angle_t endAngle)
|
||||
{
|
||||
if (startAngle > endAngle)
|
||||
{
|
||||
MarkSegmentCulled(startAngle, ANGLE_MAX);
|
||||
MarkSegmentCulled(0, endAngle);
|
||||
return;
|
||||
}
|
||||
|
||||
int count = (int)SolidSegments.size();
|
||||
int cur = 0;
|
||||
while (cur < count)
|
||||
{
|
||||
if (SolidSegments[cur].Start <= startAngle && SolidSegments[cur].End >= endAngle) // Already fully marked
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (SolidSegments[cur].End >= startAngle && SolidSegments[cur].Start <= endAngle) // Merge segments
|
||||
{
|
||||
// Find last segment
|
||||
int merge = cur;
|
||||
while (merge + 1 != count && SolidSegments[merge + 1].Start <= endAngle)
|
||||
merge++;
|
||||
|
||||
// Apply new merged range
|
||||
SolidSegments[cur].Start = MIN(SolidSegments[cur].Start, startAngle);
|
||||
SolidSegments[cur].End = MAX(SolidSegments[merge].End, endAngle);
|
||||
|
||||
// Remove additional segments we merged with
|
||||
if (merge > cur)
|
||||
SolidSegments.erase(SolidSegments.begin() + (cur + 1), SolidSegments.begin() + (merge + 1));
|
||||
|
||||
return;
|
||||
}
|
||||
else if (SolidSegments[cur].Start > startAngle) // Insert new segment
|
||||
{
|
||||
SolidSegments.insert(SolidSegments.begin() + cur, { startAngle, endAngle });
|
||||
return;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
SolidSegments.push_back({ startAngle, endAngle });
|
||||
|
||||
#if 0
|
||||
count = (int)SolidSegments.size();
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
if (SolidSegments[i - 1].Start >= SolidSegments[i].Start ||
|
||||
SolidSegments[i - 1].End >= SolidSegments[i].Start ||
|
||||
SolidSegments[i - 1].End + 1 == SolidSegments[i].Start ||
|
||||
SolidSegments[i].Start > SolidSegments[i].End)
|
||||
{
|
||||
I_FatalError("MarkSegmentCulled is broken!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int PolyCull::PointOnSide(const DVector2 &pos, const node_t *node)
|
||||
{
|
||||
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
|
||||
}
|
||||
|
||||
bool PolyCull::CheckBBox(float *bspcoord)
|
||||
{
|
||||
// Occlusion test using solid segments:
|
||||
static const uint8_t checkcoord[12][4] =
|
||||
{
|
||||
{ 3,0,2,1 },
|
||||
{ 3,0,2,0 },
|
||||
{ 3,1,2,0 },
|
||||
{ 0 },
|
||||
{ 2,0,2,1 },
|
||||
{ 0,0,0,0 },
|
||||
{ 3,1,3,0 },
|
||||
{ 0 },
|
||||
{ 2,0,3,1 },
|
||||
{ 2,1,3,1 },
|
||||
{ 2,1,3,0 }
|
||||
};
|
||||
|
||||
// Find the corners of the box that define the edges from current viewpoint.
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
int boxpos = (viewpoint.Pos.X <= bspcoord[BOXLEFT] ? 0 : viewpoint.Pos.X < bspcoord[BOXRIGHT] ? 1 : 2) +
|
||||
(viewpoint.Pos.Y >= bspcoord[BOXTOP] ? 0 : viewpoint.Pos.Y > bspcoord[BOXBOTTOM] ? 4 : 8);
|
||||
|
||||
if (boxpos == 5) return true;
|
||||
|
||||
const uint8_t *check = checkcoord[boxpos];
|
||||
angle_t angle1 = PointToPseudoAngle(bspcoord[check[0]], bspcoord[check[1]]);
|
||||
angle_t angle2 = PointToPseudoAngle(bspcoord[check[2]], bspcoord[check[3]]);
|
||||
|
||||
return !IsSegmentCulled(angle2, angle1);
|
||||
}
|
||||
|
||||
void PolyCull::InvertSegments()
|
||||
{
|
||||
TempInvertSolidSegments.swap(SolidSegments);
|
||||
SolidSegments.clear();
|
||||
angle_t cur = 0;
|
||||
for (const auto &segment : TempInvertSolidSegments)
|
||||
{
|
||||
if (cur < segment.Start)
|
||||
MarkSegmentCulled(cur, segment.Start - 1);
|
||||
if (segment.End == ANGLE_MAX)
|
||||
return;
|
||||
cur = segment.End + 1;
|
||||
}
|
||||
MarkSegmentCulled(cur, ANGLE_MAX);
|
||||
}
|
||||
|
||||
void PolyCull::MarkViewFrustum()
|
||||
{
|
||||
// Clips things outside the viewing frustum.
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
double tilt = fabs(viewpoint.Angles.Pitch.Degrees);
|
||||
if (tilt > 46.0) // If the pitch is larger than this you can look all around
|
||||
return;
|
||||
|
||||
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(viewwindow.WidescreenRatio) / 90.0;
|
||||
angle_t a1 = DAngle(floatangle).BAMs();
|
||||
if (a1 < ANGLE_180)
|
||||
{
|
||||
MarkSegmentCulled(AngleToPseudo(viewpoint.Angles.Yaw.BAMs() + a1), AngleToPseudo(viewpoint.Angles.Yaw.BAMs() - a1));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
|
||||
// line from p1 to p2. The pseudoangle has the property that the ordering of
|
||||
// points by true angle around p1 and ordering of points by pseudoangle are the
|
||||
// same.
|
||||
//
|
||||
// For clipping exact angles are not needed. Only the ordering matters.
|
||||
// This is about as fast as the fixed point R_PointToAngle2 but without
|
||||
// the precision issues associated with that function.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
angle_t PolyCull::PointToPseudoAngle(double x, double y)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
double vecx = x - viewpoint.Pos.X;
|
||||
double vecy = y - viewpoint.Pos.Y;
|
||||
|
||||
if (vecx == 0 && vecy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2. - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
||||
}
|
||||
|
||||
angle_t PolyCull::AngleToPseudo(angle_t ang)
|
||||
{
|
||||
double vecx = cos(ang * M_PI / ANGLE_180);
|
||||
double vecy = sin(ang * M_PI / ANGLE_180);
|
||||
|
||||
double result = vecy / (fabs(vecx) + fabs(vecy));
|
||||
if (vecx < 0)
|
||||
{
|
||||
result = 2.f - result;
|
||||
}
|
||||
return xs_Fix<30>::ToFix(result);
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
class PolyCull
|
||||
{
|
||||
public:
|
||||
void CullScene(sector_t *portalSector, line_t *portalLine);
|
||||
|
||||
bool IsLineSegVisible(uint32_t subsectorDepth, uint32_t lineIndex)
|
||||
{
|
||||
return PvsLineVisible[PvsLineStart[subsectorDepth] + lineIndex];
|
||||
}
|
||||
|
||||
std::vector<uint32_t> PvsSubsectors;
|
||||
double MaxCeilingHeight = 0.0;
|
||||
double MinFloorHeight = 0.0;
|
||||
|
||||
std::vector<uint32_t> SeenSectors;
|
||||
std::vector<bool> SectorSeen;
|
||||
std::vector<uint32_t> SubsectorDepths;
|
||||
|
||||
static angle_t PointToPseudoAngle(double x, double y);
|
||||
|
||||
private:
|
||||
struct SolidSegment
|
||||
{
|
||||
SolidSegment(angle_t start, angle_t end) : Start(start), End(end) { }
|
||||
angle_t Start, End;
|
||||
};
|
||||
|
||||
void MarkViewFrustum();
|
||||
void InvertSegments();
|
||||
|
||||
static bool IsSolidLine(seg_t *line);
|
||||
|
||||
bool IsSegmentCulled(angle_t angle1, angle_t angle2) const;
|
||||
|
||||
void CullNode(void *node);
|
||||
void CullSubsector(subsector_t *sub);
|
||||
int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
||||
// Checks BSP node/subtree bounding box.
|
||||
// Returns true if some part of the bbox might be visible.
|
||||
bool CheckBBox(float *bspcoord);
|
||||
|
||||
void MarkSegmentCulled(angle_t angle1, angle_t angle2);
|
||||
|
||||
std::vector<SolidSegment> SolidSegments;
|
||||
std::vector<SolidSegment> TempInvertSolidSegments;
|
||||
std::vector<SolidSegment> PortalVisibility;
|
||||
bool FirstSkyHeight = true;
|
||||
|
||||
sector_t *PortalSector = nullptr;
|
||||
line_t *PortalLine = nullptr;
|
||||
|
||||
std::vector<uint32_t> PvsLineStart;
|
||||
std::vector<bool> PvsLineVisible;
|
||||
uint32_t NextPvsLineStart = 0;
|
||||
|
||||
static angle_t AngleToPseudo(angle_t ang);
|
||||
};
|
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_decal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "a_sharedglobal.h"
|
||||
#include "swrenderer/scene/r_scene.h"
|
||||
|
||||
void RenderPolyDecal::RenderWallDecals(PolyRenderThread *thread, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (line->linedef == nullptr && line->sidedef == nullptr)
|
||||
return;
|
||||
|
||||
for (DBaseDecal *decal = line->sidedef->AttachedDecals; decal != nullptr; decal = decal->WallNext)
|
||||
{
|
||||
RenderPolyDecal render;
|
||||
render.Render(thread, decal, line, stencilValue);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::Render(PolyRenderThread *thread, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue)
|
||||
{
|
||||
if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid())
|
||||
return;
|
||||
|
||||
FTexture *ttex = TexMan.GetPalettedTexture(decal->PicNum, true);
|
||||
if (ttex == nullptr || !ttex->isValid())
|
||||
return;
|
||||
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
|
||||
sector_t *front, *back;
|
||||
GetDecalSectors(decal, line, &front, &back);
|
||||
|
||||
// Calculate unclipped position and UV coordinates
|
||||
|
||||
// decals should not use renderer specific offsets.
|
||||
double edge_left = tex->GetLeftOffset(0) * decal->ScaleX;
|
||||
double edge_right = (tex->GetWidth() - tex->GetLeftOffset(0)) * decal->ScaleX;
|
||||
|
||||
DVector2 angvec = (line->v2->fPos() - line->v1->fPos()).Unit();
|
||||
DVector2 normal = { angvec.Y, -angvec.X };
|
||||
|
||||
double dcx, dcy;
|
||||
decal->GetXY(line->sidedef, dcx, dcy);
|
||||
DVector2 decal_pos = DVector2(dcx, dcy) + normal;
|
||||
DVector2 decal_left = decal_pos - edge_left * angvec;
|
||||
DVector2 decal_right = decal_pos + edge_right * angvec;
|
||||
|
||||
bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP;
|
||||
double u_left = flipTextureX ? 1.0 : 0.0;
|
||||
double u_right = flipTextureX ? 1.0 - tex->GetScale().X : tex->GetScale().X;
|
||||
double u_unit = (u_right - u_left) / (edge_left + edge_right);
|
||||
|
||||
double zpos = GetDecalZ(decal, line, front, back);
|
||||
double spriteHeight = decal->ScaleY / tex->GetScale().Y * tex->GetHeight();
|
||||
double ztop = zpos + spriteHeight - spriteHeight * 0.5;
|
||||
double zbottom = zpos - spriteHeight * 0.5;
|
||||
|
||||
double v_top = 0.0;
|
||||
double v_bottom = tex->GetScale().Y;
|
||||
double v_unit = (v_bottom - v_top) / (zbottom - ztop);
|
||||
|
||||
// Clip decal to wall part
|
||||
|
||||
double walltopz, wallbottomz;
|
||||
GetWallZ(decal, line, front, back, walltopz, wallbottomz);
|
||||
|
||||
double clip_left_v1 = (decal_left - line->v1->fPos()) | angvec;
|
||||
double clip_right_v1 = (decal_right - line->v1->fPos()) | angvec;
|
||||
double clip_left_v2 = (decal_left - line->v2->fPos()) | angvec;
|
||||
double clip_right_v2 = (decal_right - line->v2->fPos()) | angvec;
|
||||
|
||||
if ((clip_left_v1 <= 0.0 && clip_right_v1 <= 0.0) || (clip_left_v2 >= 0.0 && clip_right_v2 >= 0.0))
|
||||
return;
|
||||
|
||||
if (clip_left_v1 < 0.0)
|
||||
{
|
||||
decal_left -= angvec * clip_left_v1;
|
||||
u_left -= u_unit * clip_left_v1;
|
||||
}
|
||||
if (clip_right_v1 < 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v1;
|
||||
u_right -= u_unit * clip_right_v1;
|
||||
}
|
||||
if (clip_left_v2 > 0.0)
|
||||
{
|
||||
decal_left -= angvec * clip_left_v2;
|
||||
u_left -= u_unit * clip_left_v2;
|
||||
}
|
||||
if (clip_right_v2 > 0.0)
|
||||
{
|
||||
decal_right -= angvec * clip_right_v2;
|
||||
u_right -= u_unit * clip_right_v2;
|
||||
}
|
||||
|
||||
double clip_top_floor = ztop - wallbottomz;
|
||||
double clip_bottom_floor = zbottom - wallbottomz;
|
||||
double clip_top_ceiling = ztop - walltopz;
|
||||
double clip_bottom_ceiling = zbottom - walltopz;
|
||||
|
||||
if ((clip_top_floor <= 0.0 && clip_bottom_floor <= 0.0) || (clip_top_ceiling >= 0.0 && clip_bottom_ceiling >= 0.0))
|
||||
return;
|
||||
|
||||
if (clip_top_floor < 0.0)
|
||||
{
|
||||
ztop -= clip_top_floor;
|
||||
v_top -= v_unit * clip_top_floor;
|
||||
}
|
||||
if (clip_bottom_floor < 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_floor;
|
||||
v_bottom -= v_unit * clip_bottom_floor;
|
||||
}
|
||||
if (clip_top_ceiling > 0.0)
|
||||
{
|
||||
ztop -= clip_top_ceiling;
|
||||
v_top -= v_unit * clip_top_ceiling;
|
||||
}
|
||||
if (clip_bottom_ceiling > 0.0)
|
||||
{
|
||||
zbottom -= clip_bottom_ceiling;
|
||||
v_bottom -= v_unit * clip_bottom_ceiling;
|
||||
}
|
||||
|
||||
// Generate vertices for the decal
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
vertices[0].x = (float)decal_left.X;
|
||||
vertices[0].y = (float)decal_left.Y;
|
||||
vertices[0].z = (float)ztop;
|
||||
vertices[0].w = 1.0f;
|
||||
vertices[0].u = (float)u_left;
|
||||
vertices[0].v = 1.0f - (float)v_top;
|
||||
vertices[1].x = (float)decal_right.X;
|
||||
vertices[1].y = (float)decal_right.Y;
|
||||
vertices[1].z = (float)ztop;
|
||||
vertices[1].w = 1.0f;
|
||||
vertices[1].u = (float)u_right;
|
||||
vertices[1].v = 1.0f - (float)v_top;
|
||||
vertices[2].x = (float)decal_right.X;
|
||||
vertices[2].y = (float)decal_right.Y;
|
||||
vertices[2].z = (float)zbottom;
|
||||
vertices[2].w = 1.0f;
|
||||
vertices[2].u = (float)u_right;
|
||||
vertices[2].v = 1.0f - (float)v_bottom;
|
||||
vertices[3].x = (float)decal_left.X;
|
||||
vertices[3].y = (float)decal_left.Y;
|
||||
vertices[3].z = (float)zbottom;
|
||||
vertices[3].w = 1.0f;
|
||||
vertices[3].u = (float)u_left;
|
||||
vertices[3].v = 1.0f - (float)v_bottom;
|
||||
|
||||
// Light calculations
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = (decal->RenderFlags & RF_FULLBRIGHT) == RF_FULLBRIGHT;
|
||||
int lightlevel = fullbrightSprite ? 255 : front->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(front->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite);
|
||||
args.SetColor(0xff000000 | decal->AlphaColor, decal->AlphaColor >> 24);
|
||||
args.SetStyle(decal->RenderStyle, decal->Alpha, decal->AlphaColor, decal->Translation, tex, false);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back)
|
||||
{
|
||||
// for 3d-floor segments use the model sector as reference
|
||||
if ((decal->RenderFlags&RF_CLIPMASK) == RF_CLIPMID)
|
||||
*front = decal->Sector;
|
||||
else
|
||||
*front = line->frontsector;
|
||||
|
||||
*back = (line->backsector != nullptr) ? line->backsector : line->frontsector;
|
||||
}
|
||||
|
||||
double RenderPolyDecal::GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back)
|
||||
{
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
return decal->Z;
|
||||
case RF_RELUPPER:
|
||||
if (line->linedef->flags & ML_DONTPEGTOP)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::ceiling);
|
||||
case RF_RELLOWER:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
else
|
||||
return decal->Z + back->GetPlaneTexZ(sector_t::floor);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
if (line->linedef->flags & ML_DONTPEGBOTTOM)
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::floor);
|
||||
else
|
||||
return decal->Z + front->GetPlaneTexZ(sector_t::ceiling);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyDecal::GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz)
|
||||
{
|
||||
double frontceilz1 = front->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = front->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = front->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = front->floorplane.ZatPoint(line->v2);
|
||||
if (back == nullptr)
|
||||
{
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
}
|
||||
else
|
||||
{
|
||||
double backceilz1 = back->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = back->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = back->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = back->floorplane.ZatPoint(line->v2);
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MAX(MIN(backceilz1, frontceilz1), frontfloorz1);
|
||||
double topfloorz2 = MAX(MIN(backceilz2, frontceilz2), frontfloorz2);
|
||||
double bottomceilz1 = MIN(MAX(frontfloorz1, backfloorz1), frontceilz1);
|
||||
double bottomceilz2 = MIN(MAX(frontfloorz2, backfloorz2), frontceilz2);
|
||||
double bottomfloorz1 = frontfloorz1;
|
||||
double bottomfloorz2 = frontfloorz2;
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
switch (decal->RenderFlags & RF_RELMASK)
|
||||
{
|
||||
default:
|
||||
walltopz = MAX(frontceilz1, frontceilz2);
|
||||
wallbottomz = MIN(frontfloorz1, frontfloorz2);
|
||||
break;
|
||||
case RF_RELUPPER:
|
||||
walltopz = MAX(topceilz1, topceilz2);
|
||||
wallbottomz = MIN(topfloorz1, topfloorz2);
|
||||
break;
|
||||
case RF_RELLOWER:
|
||||
walltopz = MAX(bottomceilz1, bottomceilz2);
|
||||
wallbottomz = MIN(bottomfloorz1, bottomfloorz2);
|
||||
break;
|
||||
case RF_RELMID:
|
||||
walltopz = MAX(middleceilz1, middleceilz2);
|
||||
wallbottomz = MIN(middlefloorz1, middlefloorz2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolyDecal
|
||||
{
|
||||
public:
|
||||
static void RenderWallDecals(PolyRenderThread *thread, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
void Render(PolyRenderThread *thread, DBaseDecal *decal, const seg_t *line, uint32_t stencilValue);
|
||||
|
||||
void GetDecalSectors(DBaseDecal *decal, const seg_t *line, sector_t **front, sector_t **back);
|
||||
double GetDecalZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back);
|
||||
void GetWallZ(DBaseDecal *decal, const seg_t *line, sector_t *front, sector_t *back, double &walltopz, double &wallbottomz);
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "poly_light.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
|
||||
void PolyLightVisibility::SetVisibility(FViewWindow &viewwindow, float vis)
|
||||
{
|
||||
GlobVis = R_GetGlobVis(viewwindow, vis);
|
||||
}
|
||||
|
||||
fixed_t PolyLightVisibility::LightLevelToShade(int lightlevel, bool foggy)
|
||||
{
|
||||
bool nolightfade = !foggy && ((PolyRenderer::Instance()->Level->flags3 & LEVEL3_NOLIGHTFADE));
|
||||
if (nolightfade)
|
||||
{
|
||||
return (MAX(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a light level into an unbounded colormap index (shade). Result is
|
||||
// fixed point. Why the +12? I wish I knew, but experimentation indicates it
|
||||
// is necessary in order to best reproduce Doom's original lighting.
|
||||
return (NUMCOLORMAPS * 2 * FRACUNIT) - ((lightlevel + 12) * (FRACUNIT*NUMCOLORMAPS / 128));
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
|
||||
struct FViewWindow;
|
||||
|
||||
// Keep using the software renderer's camera light class, for now.
|
||||
// The DFrameBuffer abstraction relies on this being globally shared
|
||||
typedef swrenderer::CameraLight PolyCameraLight;
|
||||
|
||||
class PolyLightVisibility
|
||||
{
|
||||
public:
|
||||
void SetVisibility(FViewWindow &viewwindow, float vis);
|
||||
|
||||
double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis; }
|
||||
double ParticleGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0 : GlobVis * 0.5; }
|
||||
|
||||
// The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros
|
||||
double WallVis(double screenZ, bool foggy) const { return WallGlobVis(foggy) / screenZ; }
|
||||
double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / screenZ; }
|
||||
double ParticleVis(double screenZ, bool foggy) const { return ParticleGlobVis(foggy) / screenZ; }
|
||||
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy);
|
||||
|
||||
private:
|
||||
double GlobVis = 0.0f;
|
||||
bool NoLightFade = false;
|
||||
};
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_model.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor)
|
||||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, stencilValue);
|
||||
|
||||
renderer.sector = actor->Sector;
|
||||
renderer.RenderStyle = actor->RenderStyle;
|
||||
renderer.RenderAlpha = (float)actor->Alpha;
|
||||
if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha))
|
||||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = ((actor->renderflags & RF_FULLBRIGHT) || (actor->flags5 & MF5_BRIGHT));
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : actor->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
|
||||
renderer.fillcolor = actor->fillcolor;
|
||||
renderer.Translation = actor->Translation;
|
||||
|
||||
renderer.AddLights(actor);
|
||||
renderer.RenderModel(x, y, z, smf, actor, PolyRenderer::Instance()->Viewpoint.TicFrac);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(worldToClip), nullptr);
|
||||
}
|
||||
|
||||
static bool isBright(DPSprite *psp)
|
||||
{
|
||||
if (psp != nullptr && psp->GetState() != nullptr)
|
||||
{
|
||||
bool disablefullbright = false;
|
||||
FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr);
|
||||
if (lump.isValid())
|
||||
{
|
||||
FTexture * tex = TexMan.GetPalettedTexture(lump, true);
|
||||
if (tex) disablefullbright = tex->isFullbrightDisabled();
|
||||
}
|
||||
return psp->GetState()->GetFullbright() && !disablefullbright;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PolyRenderHUDModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy)
|
||||
{
|
||||
PolyModelRenderer renderer(thread, worldToClip, stencilValue);
|
||||
|
||||
AActor *playermo = players[consoleplayer].camera;
|
||||
auto rs = psp->GetRenderStyle(playermo->RenderStyle, playermo->Alpha);
|
||||
renderer.sector = playermo->Sector;
|
||||
renderer.RenderStyle = rs.first;
|
||||
renderer.RenderAlpha = rs.second;
|
||||
if (psp->Flags & PSPF_FORCEALPHA) renderer.RenderAlpha = 0.0f;
|
||||
if (!renderer.RenderStyle.IsVisible(renderer.RenderAlpha))
|
||||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = isBright(psp);
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
|
||||
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
|
||||
renderer.fillcolor = fullbrightSprite ? ThingColor : ThingColor.Modulate(playermo->Sector->SpecialColors[sector_t::sprites]);
|
||||
renderer.Translation = 0xffffffff;// playermo->Translation;
|
||||
|
||||
renderer.RenderHUDModel(psp, ofsx, ofsy);
|
||||
PolyTriangleDrawer::SetModelVertexShader(thread->DrawQueue, -1, -1, 0.0f);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyModelRenderer::PolyModelRenderer(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue) : Thread(thread), WorldToClip(worldToClip), StencilValue(stencilValue)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyModelRenderer::AddLights(AActor *actor)
|
||||
{
|
||||
if (r_dynlights && actor)
|
||||
{
|
||||
auto &addedLights = Thread->AddedLightsArray;
|
||||
|
||||
addedLights.Clear();
|
||||
|
||||
float x = (float)actor->X();
|
||||
float y = (float)actor->Y();
|
||||
float z = (float)actor->Center();
|
||||
float actorradius = (float)actor->RenderRadius();
|
||||
float radiusSquared = actorradius * actorradius;
|
||||
|
||||
BSPWalkCircle(actor->Level, x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor
|
||||
{
|
||||
FLightNode * node = subsector->section->lighthead;
|
||||
while (node) // check all lights touching a subsector
|
||||
{
|
||||
FDynamicLight *light = node->lightsource;
|
||||
if (light->ShouldLightActor(actor))
|
||||
{
|
||||
int group = subsector->sector->PortalGroup;
|
||||
DVector3 pos = light->PosRelative(group);
|
||||
float radius = (float)(light->GetRadius() + actorradius);
|
||||
double dx = pos.X - x;
|
||||
double dy = pos.Y - y;
|
||||
double dz = pos.Z - z;
|
||||
double distSquared = dx * dx + dy * dy + dz * dz;
|
||||
if (distSquared < radius * radius) // Light and actor touches
|
||||
{
|
||||
if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector
|
||||
{
|
||||
addedLights.Push(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
});
|
||||
|
||||
NumLights = addedLights.Size();
|
||||
Lights = Thread->FrameMemory->AllocMemory<PolyLight>(NumLights);
|
||||
for (int i = 0; i < NumLights; i++)
|
||||
{
|
||||
FDynamicLight *lightsource = addedLights[i];
|
||||
|
||||
bool is_point_light = lightsource->IsAttenuated();
|
||||
|
||||
uint32_t red = lightsource->GetRed();
|
||||
uint32_t green = lightsource->GetGreen();
|
||||
uint32_t blue = lightsource->GetBlue();
|
||||
|
||||
PolyLight &light = Lights[i];
|
||||
light.x = (float)lightsource->X();
|
||||
light.y = (float)lightsource->Y();
|
||||
light.z = (float)lightsource->Z();
|
||||
light.radius = 256.0f / lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PolyModelRenderer::BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
SetTransform();
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, !mirrored);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::EndDrawModel(AActor *actor, FSpriteModelFrame *smf)
|
||||
{
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] || !!(smf->flags & MDL_DONTCULLBACKFACES))
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
IModelVertexBuffer *PolyModelRenderer::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
return new PolyModelVertexBuffer(needindex, singleframe);
|
||||
}
|
||||
|
||||
VSMatrix PolyModelRenderer::GetViewToWorldMatrix()
|
||||
{
|
||||
Mat4f swapYZ = Mat4f::Null();
|
||||
swapYZ.Matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.Matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.Matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.Matrix[3 + 3 * 4] = 1.0f;
|
||||
|
||||
VSMatrix worldToView;
|
||||
worldToView.loadMatrix((PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToView * swapYZ).Matrix);
|
||||
|
||||
VSMatrix objectToWorld;
|
||||
worldToView.inverseMatrix(objectToWorld);
|
||||
return objectToWorld;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored)
|
||||
{
|
||||
const_cast<VSMatrix &>(objectToWorldMatrix).copy(ObjectToWorld.Matrix);
|
||||
SetTransform();
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, true);
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, true);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, mirrored);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::EndDrawHUDModel(AActor *actor)
|
||||
{
|
||||
PolyTriangleDrawer::SetWeaponScene(Thread->DrawQueue, false);
|
||||
|
||||
if (actor->RenderStyle == LegacyRenderStyles[STYLE_Normal])
|
||||
PolyTriangleDrawer::SetTwoSided(Thread->DrawQueue, false);
|
||||
PolyTriangleDrawer::SetCullCCW(Thread->DrawQueue, true);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetInterpolation(double interpolation)
|
||||
{
|
||||
InterpolationFactor = (float)interpolation;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation)
|
||||
{
|
||||
SkinTexture = skin? skin->GetSoftwareTexture() : nullptr;
|
||||
}
|
||||
|
||||
void PolyModelRenderer::SetTransform()
|
||||
{
|
||||
Mat4f swapYZ = Mat4f::Null();
|
||||
swapYZ.Matrix[0 + 0 * 4] = 1.0f;
|
||||
swapYZ.Matrix[1 + 2 * 4] = 1.0f;
|
||||
swapYZ.Matrix[2 + 1 * 4] = 1.0f;
|
||||
swapYZ.Matrix[3 + 3 * 4] = 1.0f;
|
||||
ObjectToWorld = swapYZ * ObjectToWorld;
|
||||
|
||||
PolyTriangleDrawer::SetTransform(Thread->DrawQueue, Thread->FrameMemory->NewObject<Mat4f>(WorldToClip * ObjectToWorld), Thread->FrameMemory->NewObject<Mat4f>(ObjectToWorld));
|
||||
}
|
||||
|
||||
void PolyModelRenderer::DrawArrays(int start, int count)
|
||||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(Thread->DrawQueue, args, VertexBuffer + start, count);
|
||||
}
|
||||
|
||||
void PolyModelRenderer::DrawElements(int numIndices, size_t offset)
|
||||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetClipPlane(0, PolyClipPlane());
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawElements(Thread->DrawQueue, args, VertexBuffer, IndexBuffer + offset / sizeof(unsigned int), numIndices);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyModelVertexBuffer::PolyModelVertexBuffer(bool needindex, bool singleframe)
|
||||
{
|
||||
}
|
||||
|
||||
PolyModelVertexBuffer::~PolyModelVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
FModelVertex *PolyModelVertexBuffer::LockVertexBuffer(unsigned int size)
|
||||
{
|
||||
mVertexBuffer.Resize(size);
|
||||
return &mVertexBuffer[0];
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::UnlockVertexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int *PolyModelVertexBuffer::LockIndexBuffer(unsigned int size)
|
||||
{
|
||||
mIndexBuffer.Resize(size);
|
||||
return &mIndexBuffer[0];
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::UnlockIndexBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyModelVertexBuffer::SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size)
|
||||
{
|
||||
PolyModelRenderer *polyrenderer = (PolyModelRenderer *)renderer;
|
||||
polyrenderer->VertexBuffer = mVertexBuffer.Size() ? &mVertexBuffer[0] : nullptr;
|
||||
polyrenderer->IndexBuffer = mIndexBuffer.Size() ? &mIndexBuffer[0] : nullptr;
|
||||
PolyTriangleDrawer::SetModelVertexShader(polyrenderer->Thread->DrawQueue, frame1, frame2, polyrenderer->InterpolationFactor);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "r_data/matrix.h"
|
||||
#include "r_data/models/models.h"
|
||||
|
||||
void PolyRenderModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, float x, float y, float z, FSpriteModelFrame *smf, AActor *actor);
|
||||
void PolyRenderHUDModel(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue, DPSprite *psp, float ofsx, float ofsy);
|
||||
|
||||
class PolyModelRenderer : public FModelRenderer
|
||||
{
|
||||
public:
|
||||
PolyModelRenderer(PolyRenderThread *thread, const Mat4f &worldToClip, uint32_t stencilValue);
|
||||
|
||||
void AddLights(AActor *actor);
|
||||
|
||||
ModelRendererType GetType() const override { return PolyModelRendererType; }
|
||||
|
||||
void BeginDrawModel(AActor *actor, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawModel(AActor *actor, FSpriteModelFrame *smf) override;
|
||||
IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override;
|
||||
VSMatrix GetViewToWorldMatrix() override;
|
||||
void BeginDrawHUDModel(AActor *actor, const VSMatrix &objectToWorldMatrix, bool mirrored) override;
|
||||
void EndDrawHUDModel(AActor *actor) override;
|
||||
void SetInterpolation(double interpolation) override;
|
||||
void SetMaterial(FTexture *skin, bool clampNoFilter, int translation) override;
|
||||
void DrawArrays(int start, int count) override;
|
||||
void DrawElements(int numIndices, size_t offset) override;
|
||||
|
||||
void SetTransform();
|
||||
|
||||
PolyRenderThread *Thread = nullptr;
|
||||
const Mat4f &WorldToClip;
|
||||
uint32_t StencilValue = 0;
|
||||
|
||||
FRenderStyle RenderStyle;
|
||||
float RenderAlpha;
|
||||
sector_t *sector;
|
||||
bool fullbrightSprite;
|
||||
int lightlevel;
|
||||
double visibility;
|
||||
uint32_t fillcolor;
|
||||
uint32_t Translation;
|
||||
|
||||
Mat4f ObjectToWorld;
|
||||
FSoftwareTexture *SkinTexture = nullptr;
|
||||
unsigned int *IndexBuffer = nullptr;
|
||||
FModelVertex *VertexBuffer = nullptr;
|
||||
float InterpolationFactor = 0.0;
|
||||
PolyLight *Lights = nullptr;
|
||||
int NumLights = 0;
|
||||
};
|
||||
|
||||
class PolyModelVertexBuffer : public IModelVertexBuffer
|
||||
{
|
||||
public:
|
||||
PolyModelVertexBuffer(bool needindex, bool singleframe);
|
||||
~PolyModelVertexBuffer();
|
||||
|
||||
FModelVertex *LockVertexBuffer(unsigned int size) override;
|
||||
void UnlockVertexBuffer() override;
|
||||
|
||||
unsigned int *LockIndexBuffer(unsigned int size) override;
|
||||
void UnlockIndexBuffer() override;
|
||||
|
||||
void SetupFrame(FModelRenderer *renderer, unsigned int frame1, unsigned int frame2, unsigned int size) override;
|
||||
|
||||
private:
|
||||
TArray<FModelVertex> mVertexBuffer;
|
||||
TArray<unsigned int> mIndexBuffer;
|
||||
};
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_particle.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
EXTERN_CVAR(Int, gl_particles_style)
|
||||
|
||||
void RenderPolyParticle::Render(PolyRenderThread *thread, particle_t *particle, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
double timefrac = PolyRenderer::Instance()->Viewpoint.TicFrac;
|
||||
if (paused || PolyRenderer::Instance()->Viewpoint.ViewLevel->isFrozen())
|
||||
timefrac = 0.;
|
||||
DVector3 pos = particle->Pos + (particle->Vel * timefrac);
|
||||
double psize = particle->size / 8.0;
|
||||
double zpos = pos.Z;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
DVector2 points[2] =
|
||||
{
|
||||
{ pos.X - viewpoint.Sin * psize, pos.Y + viewpoint.Cos * psize },
|
||||
{ pos.X + viewpoint.Sin * psize, pos.Y - viewpoint.Cos * psize }
|
||||
};
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(zpos + psize * (2.0 * offsets[i].second - 1.0));
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)(offsets[i].first);
|
||||
vertices[i].v = (float)(1.0f - offsets[i].second);
|
||||
}
|
||||
|
||||
bool fullbrightSprite = particle->bright != 0;
|
||||
int lightlevel = fullbrightSprite ? 255 : sub->sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.ParticleGlobVis(foggy), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetColor(particle->color | 0xff000000, particle->color >> 24);
|
||||
args.SetStyle(TriBlendMode::Shaded, particle->alpha);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetTexture(GetParticleTexture(), ParticleTextureSize, ParticleTextureSize);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
uint8_t *RenderPolyParticle::GetParticleTexture()
|
||||
{
|
||||
static uint8_t particle_texture[NumParticleTextures][ParticleTextureSize * ParticleTextureSize];
|
||||
static bool first_call = true;
|
||||
if (first_call)
|
||||
{
|
||||
double center = ParticleTextureSize * 0.5f;
|
||||
for (int y = 0; y < ParticleTextureSize; y++)
|
||||
{
|
||||
for (int x = 0; x < ParticleTextureSize; x++)
|
||||
{
|
||||
double dx = (center - x - 0.5f) / center;
|
||||
double dy = (center - y - 0.5f) / center;
|
||||
double dist2 = dx * dx + dy * dy;
|
||||
double round_alpha = clamp<double>(1.7f - dist2 * 1.7f, 0.0f, 1.0f);
|
||||
double smooth_alpha = clamp<double>(1.1f - dist2 * 1.1f, 0.0f, 1.0f);
|
||||
|
||||
particle_texture[0][x + y * ParticleTextureSize] = 255;
|
||||
particle_texture[1][x + y * ParticleTextureSize] = (int)(round_alpha * 255.0f + 0.5f);
|
||||
particle_texture[2][x + y * ParticleTextureSize] = (int)(smooth_alpha * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
first_call = false;
|
||||
}
|
||||
return particle_texture[MIN<int>(gl_particles_style, NumParticleTextures)];
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "p_effect.h"
|
||||
|
||||
class RenderPolyParticle
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, particle_t *particle, subsector_t *sub, uint32_t stencilValue);
|
||||
|
||||
private:
|
||||
static uint8_t *GetParticleTexture();
|
||||
|
||||
enum
|
||||
{
|
||||
NumParticleTextures = 3,
|
||||
ParticleTextureSize = 64
|
||||
};
|
||||
};
|
||||
|
||||
class PolyTranslucentParticle : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentParticle(particle_t *particle, subsector_t *sub, uint32_t subsectorDepth, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, 0.0), particle(particle), sub(sub), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
RenderPolyParticle spr;
|
||||
spr.Render(thread, particle, sub, StencilValue + 1);
|
||||
}
|
||||
|
||||
particle_t *particle = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
|
@ -1,565 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_plane.h"
|
||||
#include "poly_portal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_dynlight.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_3dfloors)
|
||||
|
||||
void RenderPolyPlane::RenderPlanes(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
if (fakeflat.FrontSector->CenterFloor() == fakeflat.FrontSector->CenterCeiling())
|
||||
return;
|
||||
|
||||
RenderPolyPlane plane;
|
||||
plane.Render(thread, fakeflat, stencilValue, true, skyCeilingHeight, sectorPortals, sectorPortalsStart);
|
||||
plane.Render(thread, fakeflat, stencilValue, false, skyFloorHeight, sectorPortals, sectorPortalsStart);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::Render(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
FSectorPortal *portal = fakeflat.FrontSector->ValidatePortal(ceiling ? sector_t::ceiling : sector_t::floor);
|
||||
if (!portal || (portal->mFlags & PORTSF_INSKYBOX) == PORTSF_INSKYBOX) // Do not recurse into portals we already recursed into
|
||||
{
|
||||
RenderNormal(thread, fakeflat, stencilValue, ceiling, skyHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPortal(thread, fakeflat, stencilValue, ceiling, skyHeight, portal, sectorPortals, sectorPortalsStart);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
FTextureID picnum = fakeflat.FrontSector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor);
|
||||
if (picnum != skyflatnum)
|
||||
{
|
||||
FTexture *tex = TexMan.GetPalettedTexture(picnum, true);
|
||||
if (!tex || !tex->isValid())
|
||||
return;
|
||||
|
||||
PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex->GetSoftwareTexture());
|
||||
TriVertex *vertices = CreatePlaneVertices(thread, fakeflat.Subsector, transform, ceiling ? fakeflat.FrontSector->ceilingplane : fakeflat.FrontSector->floorplane);
|
||||
|
||||
PolyDrawArgs args;
|
||||
SetLightLevel(thread, args, fakeflat, ceiling);
|
||||
SetDynLights(thread, args, fakeflat.Subsector, ceiling);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle());
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, 255);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
|
||||
RenderSkyWalls(thread, args, fakeflat.Subsector, nullptr, ceiling, skyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderPortal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
PolyDrawSectorPortal *polyportal = nullptr;
|
||||
std::vector<PolyPortalSegment> portalSegments;
|
||||
|
||||
// Skip portals not facing the camera
|
||||
if ((ceiling && fakeflat.FrontSector->ceilingplane.PointOnSide(viewpoint.Pos) < 0) ||
|
||||
(!ceiling && fakeflat.FrontSector->floorplane.PointOnSide(viewpoint.Pos) < 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = sectorPortalsStart; i < sectorPortals.size(); i++)
|
||||
{
|
||||
if (sectorPortals[i]->Portal == portal) // To do: what other criteria do we need to check for?
|
||||
{
|
||||
polyportal = sectorPortals[i].get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polyportal)
|
||||
{
|
||||
sectorPortals.push_back(std::unique_ptr<PolyDrawSectorPortal>(new PolyDrawSectorPortal(portal, ceiling)));
|
||||
polyportal = sectorPortals.back().get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Calculate portal clipping
|
||||
portalSegments.reserve(sub->numlines);
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
|
||||
bool backside = pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0;
|
||||
if (!backside)
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
if (cull.GetAnglesForLine(line->v1->fX(), line->v1->fY(), line->v2->fX(), line->v2->fY(), angle1, angle2))
|
||||
portalSegments.push_back({ angle1, angle2 });
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t angle1, angle2;
|
||||
if (cull.GetAnglesForLine(line->v2->fX(), line->v2->fY(), line->v1->fX(), line->v1->fY(), angle1, angle2))
|
||||
portalSegments.push_back({ angle1, angle2 });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TriVertex *vertices = CreateSkyPlaneVertices(thread, fakeflat.Subsector, skyHeight);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, polyportal->StencilValue);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan);
|
||||
|
||||
RenderSkyWalls(thread, args, fakeflat.Subsector, polyportal, ceiling, skyHeight);
|
||||
|
||||
polyportal->Shape.push_back({ vertices, (int)fakeflat.Subsector->numlines });
|
||||
}
|
||||
|
||||
void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight)
|
||||
{
|
||||
sector_t *frontsector = sub->sector;
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
|
||||
double skyBottomz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double skyBottomz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
if (line->backsector)
|
||||
{
|
||||
sector_t *backsector = line->backsector;
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
|
||||
bool closedSector = backceilz1 == backfloorz1 && backceilz2 == backfloorz2;
|
||||
if (ceiling && bothSkyCeiling && closedSector)
|
||||
{
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MIN(backceilz1, frontceilz1);
|
||||
double topfloorz2 = MIN(backceilz2, frontceilz2);
|
||||
double bottomceilz1 = MAX(frontfloorz1, backfloorz1);
|
||||
double bottomceilz2 = MAX(frontfloorz2, backfloorz2);
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
skyBottomz1 = middlefloorz1;
|
||||
skyBottomz2 = middlefloorz2;
|
||||
}
|
||||
else if (bothSkyCeiling)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (polyportal && line->linedef && line->linedef->special == Line_Horizon)
|
||||
{
|
||||
// Not entirely correct as this closes the line horizon rather than allowing the floor to continue to infinity
|
||||
skyBottomz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
skyBottomz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
}
|
||||
|
||||
TriVertex *wallvert = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
if (ceiling)
|
||||
{
|
||||
wallvert[0] = GetSkyVertex(line->v1, skyHeight);
|
||||
wallvert[1] = GetSkyVertex(line->v2, skyHeight);
|
||||
wallvert[2] = GetSkyVertex(line->v2, skyBottomz2);
|
||||
wallvert[3] = GetSkyVertex(line->v1, skyBottomz1);
|
||||
}
|
||||
else
|
||||
{
|
||||
wallvert[0] = GetSkyVertex(line->v1, frontsector->floorplane.ZatPoint(line->v1));
|
||||
wallvert[1] = GetSkyVertex(line->v2, frontsector->floorplane.ZatPoint(line->v2));
|
||||
wallvert[2] = GetSkyVertex(line->v2, skyHeight);
|
||||
wallvert[3] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, wallvert, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
if (polyportal)
|
||||
{
|
||||
polyportal->Shape.push_back({ wallvert, 4 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlane::SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling)
|
||||
{
|
||||
bool foggy = PolyRenderer::Instance()->Level->fadeto || fakeflat.FrontSector->Colormap.FadeColor || (PolyRenderer::Instance()->Level->flags & LEVEL_HASFADETABLE);
|
||||
|
||||
int lightlevel = ceiling ? fakeflat.CeilingLightLevel : fakeflat.FloorLightLevel;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
FDynamicColormap *basecolormap = GetColorTable(fakeflat.FrontSector->Colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (cameraLight->FixedLightLevel() < 0 && fakeflat.FrontSector->e && fakeflat.FrontSector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(fakeflat.FrontSector, ceiling ? &fakeflat.FrontSector->ceilingplane : &fakeflat.FrontSector->floorplane, false);
|
||||
basecolormap = GetColorTable(light->extra_colormap, fakeflat.FrontSector->SpecialColors[ceiling ? sector_t::ceiling : sector_t::floor]);
|
||||
if (light->p_lightlevel != &fakeflat.FrontSector->lightlevel) // If this is the real ceiling, don't discard plane lighting R_FakeFlat() accounted for.
|
||||
{
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
}
|
||||
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
}
|
||||
|
||||
void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling)
|
||||
{
|
||||
if (!r_dynlights)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FLightNode *light_list = sub->section->lighthead;
|
||||
|
||||
auto cameraLight = PolyCameraLight::Instance();
|
||||
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
|
||||
{
|
||||
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate max lights that can touch the wall so we can allocate memory for the list
|
||||
int max_lights = 0;
|
||||
FLightNode *cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
max_lights++;
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
if (max_lights == 0)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int dc_num_lights = 0;
|
||||
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
|
||||
|
||||
// Setup lights
|
||||
cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
{
|
||||
bool is_point_light = cur_node->lightsource->IsAttenuated();
|
||||
|
||||
// To do: cull lights not touching subsector
|
||||
|
||||
uint32_t red = cur_node->lightsource->GetRed();
|
||||
uint32_t green = cur_node->lightsource->GetGreen();
|
||||
uint32_t blue = cur_node->lightsource->GetBlue();
|
||||
|
||||
auto &light = dc_lights[dc_num_lights++];
|
||||
light.x = (float)cur_node->lightsource->X();
|
||||
light.y = (float)cur_node->lightsource->Y();
|
||||
light.z = (float)cur_node->lightsource->Z();
|
||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
args.SetLights(dc_lights, dc_num_lights);
|
||||
|
||||
DVector3 normal = ceiling ? sub->sector->ceilingplane.Normal() : sub->sector->floorplane.Normal();
|
||||
args.SetNormal({ (float)normal.X, (float)normal.Y, (float)normal.Z });
|
||||
}
|
||||
|
||||
TriVertex *RenderPolyPlane::CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane)
|
||||
{
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
double planeZ = plane.ZatPoint(viewpoint.Pos.XY());
|
||||
if (viewpoint.Pos.Z < planeZ)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
|
||||
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = transform.GetVertex(line->v1, plane.ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
TriVertex *RenderPolyPlane::CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight)
|
||||
{
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
if (viewpoint.Pos.Z < skyHeight)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[sub->numlines - 1 - i];
|
||||
vertices[i] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = GetSkyVertex(line->v1, skyHeight);
|
||||
}
|
||||
}
|
||||
|
||||
return vertices;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex)
|
||||
{
|
||||
if (tex)
|
||||
{
|
||||
xscale = (float)(transform.xScale * tex->GetScale().X / tex->GetWidth());
|
||||
yscale = (float)(transform.yScale * tex->GetScale().Y / tex->GetHeight());
|
||||
|
||||
double planeang = (transform.Angle + transform.baseAngle).Radians();
|
||||
cosine = (float)cos(planeang);
|
||||
sine = (float)sin(planeang);
|
||||
|
||||
xOffs = (float)transform.xOffs;
|
||||
yOffs = (float)transform.yOffs;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscale = 1.0f / 64.0f;
|
||||
yscale = 1.0f / 64.0f;
|
||||
cosine = 1.0f;
|
||||
sine = 0.0f;
|
||||
xOffs = 0.0f;
|
||||
yOffs = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Render3DFloorPlane::RenderPlanes(PolyRenderThread *thread, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects)
|
||||
{
|
||||
if (!r_3dfloors || sub->sector->CenterFloor() == sub->sector->CenterCeiling())
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
auto frontsector = sub->sector;
|
||||
auto &ffloors = frontsector->e->XFloor.ffloors;
|
||||
|
||||
// 3D floor floors
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
F3DFloor *prevFloor = i > 0 ? ffloors[i - 1] : nullptr;
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (prevFloor && (prevFloor->flags & fakeFloor->flags & FF_SWIMMABLE)) continue;
|
||||
|
||||
double fakeHeight = fakeFloor->top.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->top.plane->isSlope() || (fakeHeight < viewpoint.Pos.Z && fakeHeight > frontsector->floorplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = false;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
|
||||
// 3D floor ceilings
|
||||
for (int i = 0; i < (int)ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = ffloors[i];
|
||||
F3DFloor *prevFloor = i > 0 ? ffloors[i - 1] : nullptr;
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) continue;
|
||||
if (!fakeFloor->model) continue;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (fakeFloor->alpha == 0) continue;
|
||||
if (prevFloor && (prevFloor->flags & fakeFloor->flags & FF_SWIMMABLE)) continue;
|
||||
|
||||
double fakeHeight = fakeFloor->bottom.plane->ZatPoint(frontsector->centerspot);
|
||||
if (fakeFloor->bottom.plane->isSlope() || (fakeHeight > viewpoint.Pos.Z && fakeHeight < frontsector->ceilingplane.ZatPoint(frontsector->centerspot)))
|
||||
{
|
||||
Render3DFloorPlane plane;
|
||||
plane.sub = sub;
|
||||
plane.stencilValue = stencilValue;
|
||||
plane.ceiling = true;
|
||||
plane.fakeFloor = fakeFloor;
|
||||
plane.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!plane.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
plane.Masked = false;
|
||||
plane.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
plane.Masked = true;
|
||||
plane.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
|
||||
if (!plane.Masked)
|
||||
plane.Render(thread);
|
||||
else
|
||||
translucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucent3DFloorPlane>(plane, subsectorDepth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Render3DFloorPlane::Render(PolyRenderThread *thread)
|
||||
{
|
||||
FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture;
|
||||
auto tex = TexMan.GetPalettedTexture(picnum, true);
|
||||
if (!tex->isValid())
|
||||
return;
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
|
||||
int lightlevel = 255;
|
||||
bool foggy = false;
|
||||
if (cameraLight->FixedLightLevel() < 0 && sub->sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(sub->sector, ceiling ? fakeFloor->bottom.plane : fakeFloor->top.plane, ceiling);
|
||||
//basecolormap = light->extra_colormap;
|
||||
lightlevel = *light->p_lightlevel;
|
||||
}
|
||||
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(lightlevel + actualextralight, 0, 255);
|
||||
|
||||
PolyPlaneUVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex->GetSoftwareTexture());
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(sub->numlines);
|
||||
if (ceiling)
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[sub->numlines - 1 - i] = xform.GetVertex(line->v1, fakeFloor->bottom.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
vertices[i] = xform.GetVertex(line->v1, fakeFloor->top.plane->ZatPoint(line->v1));
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(GetColorTable(sub->sector->Colormap), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
if (!Masked)
|
||||
{
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
args.SetStencilTestValue(stencilValue);
|
||||
args.SetWriteStencil(true, stencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
args.SetStyle(Additive ? TriBlendMode::Add : TriBlendMode::Normal, MIN(Alpha, 1.0));
|
||||
args.SetStencilTestValue(stencilValue + 1);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
}
|
||||
args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle());
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, sub->numlines, PolyDrawMode::TriangleFan);
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
|
||||
class PolyPlaneUVTransform
|
||||
{
|
||||
public:
|
||||
PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex);
|
||||
|
||||
TriVertex GetVertex(vertex_t *v1, double height) const
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = (float)v1->fX();
|
||||
v.y = (float)v1->fY();
|
||||
v.z = (float)height;
|
||||
v.w = 1.0f;
|
||||
v.u = GetU(v.x, v.y);
|
||||
v.v = GetV(v.x, v.y);
|
||||
return v;
|
||||
}
|
||||
|
||||
private:
|
||||
float GetU(float x, float y) const { return (xOffs + x * cosine - y * sine) * xscale; }
|
||||
float GetV(float x, float y) const { return (yOffs - x * sine - y * cosine) * yscale; }
|
||||
|
||||
float xscale;
|
||||
float yscale;
|
||||
float cosine;
|
||||
float sine;
|
||||
float xOffs, yOffs;
|
||||
};
|
||||
|
||||
class RenderPolyPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, double skyCeilingHeight, double skyFloorHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
|
||||
private:
|
||||
void Render(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
|
||||
void RenderPortal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight, FSectorPortal *portal, std::vector<std::unique_ptr<PolyDrawSectorPortal>> §orPortals, size_t sectorPortalsStart);
|
||||
void RenderNormal(PolyRenderThread *thread, const PolyTransferHeights &fakeflat, uint32_t stencilValue, bool ceiling, double skyHeight);
|
||||
|
||||
void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight);
|
||||
|
||||
void SetLightLevel(PolyRenderThread *thread, PolyDrawArgs &args, const PolyTransferHeights &fakeflat, bool ceiling);
|
||||
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling);
|
||||
|
||||
TriVertex *CreatePlaneVertices(PolyRenderThread *thread, subsector_t *sub, const PolyPlaneUVTransform &transform, const secplane_t &plane);
|
||||
TriVertex *CreateSkyPlaneVertices(PolyRenderThread *thread, subsector_t *sub, double skyHeight);
|
||||
|
||||
static TriVertex GetSkyVertex(vertex_t *v, double height) { return { (float)v->fX(), (float)v->fY(), (float)height, 1.0f, 0.0f, 0.0f }; }
|
||||
};
|
||||
|
||||
class Render3DFloorPlane
|
||||
{
|
||||
public:
|
||||
static void RenderPlanes(PolyRenderThread *thread, subsector_t *sub, uint32_t stencilValue, uint32_t subsectorDepth, std::vector<PolyTranslucentObject *> &translucentObjects);
|
||||
|
||||
void Render(PolyRenderThread *thread);
|
||||
|
||||
subsector_t *sub = nullptr;
|
||||
uint32_t stencilValue = 0;
|
||||
bool ceiling = false;
|
||||
F3DFloor *fakeFloor = nullptr;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
};
|
||||
|
||||
class PolyTranslucent3DFloorPlane : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucent3DFloorPlane(Render3DFloorPlane plane, uint32_t subsectorDepth) : PolyTranslucentObject(subsectorDepth, 1e7), plane(plane) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
plane.Render(thread);
|
||||
}
|
||||
|
||||
Render3DFloorPlane plane;
|
||||
};
|
|
@ -1,548 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_playersprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "d_player.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_model.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawplayersprites)
|
||||
EXTERN_CVAR(Bool, r_deathcamera)
|
||||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||
extern bool r_modelscene;
|
||||
|
||||
void RenderPolyPlayerSprites::Render(PolyRenderThread *thread)
|
||||
{
|
||||
// This code cannot be moved directly to RenderRemainingSprites because the engine
|
||||
// draws the canvas textures between this call and the final call to RenderRemainingSprites..
|
||||
//
|
||||
// We also can't move it because the model render code relies on it
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
int i;
|
||||
int lightnum;
|
||||
DPSprite* psp;
|
||||
DPSprite* weapon;
|
||||
sector_t* sec = nullptr;
|
||||
int floorlight, ceilinglight;
|
||||
F3DFloor *rover;
|
||||
|
||||
if (!r_drawplayersprites ||
|
||||
!viewpoint.camera ||
|
||||
!viewpoint.camera->player ||
|
||||
(players[consoleplayer].cheats & CF_CHASECAM) ||
|
||||
(r_deathcamera && viewpoint.camera->health <= 0))
|
||||
return;
|
||||
|
||||
renderHUDModel = r_modelscene && IsHUDModelForPlayerAvailable(players[consoleplayer].camera->player);
|
||||
|
||||
PolyTransferHeights fakeflat(viewpoint.camera->subsector);
|
||||
|
||||
FDynamicColormap *basecolormap;
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
bool nc = !!(viewpoint.camera->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
|
||||
if (cameraLight->FixedLightLevel() < 0 && viewpoint.sector->e && viewpoint.sector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
for (i = viewpoint.sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (viewpoint.Pos.Z <= viewpoint.sector->e->XFloor.lightlist[i].plane.Zat0())
|
||||
{
|
||||
rover = viewpoint.sector->e->XFloor.lightlist[i].caster;
|
||||
if (rover)
|
||||
{
|
||||
if (rover->flags & FF_DOUBLESHADOW && viewpoint.Pos.Z <= rover->bottom.plane->Zat0())
|
||||
break;
|
||||
sec = rover->model;
|
||||
if (rover->flags & FF_FADEWALLS)
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
else
|
||||
basecolormap = GetSpriteColorTable(viewpoint.sector->e->XFloor.lightlist[i].extra_colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sec)
|
||||
{
|
||||
sec = viewpoint.sector;
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
floorlight = ceilinglight = sec->lightlevel;
|
||||
}
|
||||
else
|
||||
{ // This used to use camera->Sector but due to interpolation that can be incorrect
|
||||
// when the interpolated viewpoint is in a different sector than the camera.
|
||||
|
||||
sec = fakeflat.FrontSector;
|
||||
floorlight = fakeflat.FloorLightLevel;
|
||||
ceilinglight = fakeflat.CeilingLightLevel;
|
||||
|
||||
// [RH] set basecolormap
|
||||
basecolormap = GetSpriteColorTable(sec->Colormap, sec->SpecialColors[sector_t::sprites], nc);
|
||||
}
|
||||
|
||||
// [RH] set foggy flag
|
||||
bool foggy = (PolyRenderer::Instance()->Level->fadeto || basecolormap->Fade || (PolyRenderer::Instance()->Level->flags & LEVEL_HASFADETABLE));
|
||||
|
||||
// get light level
|
||||
lightnum = ((floorlight + ceilinglight) >> 1) + (foggy ? 0 : viewpoint.extralight << 4);
|
||||
int spriteshade = LightLevelToShade(lightnum, foggy) - 24 * FRACUNIT;
|
||||
|
||||
if (viewpoint.camera->player != nullptr)
|
||||
{
|
||||
double wx, wy;
|
||||
float bobx, boby;
|
||||
|
||||
P_BobWeapon(viewpoint.camera->player, &bobx, &boby, viewpoint.TicFrac);
|
||||
|
||||
// Interpolate the main weapon layer once so as to be able to add it to other layers.
|
||||
if ((weapon = viewpoint.camera->player->FindPSprite(PSP_WEAPON)) != nullptr)
|
||||
{
|
||||
if (weapon->firstTic)
|
||||
{
|
||||
wx = weapon->x;
|
||||
wy = weapon->y;
|
||||
}
|
||||
else
|
||||
{
|
||||
wx = weapon->oldx + (weapon->x - weapon->oldx) * viewpoint.TicFrac;
|
||||
wy = weapon->oldy + (weapon->y - weapon->oldy) * viewpoint.TicFrac;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wx = 0;
|
||||
wy = 0;
|
||||
}
|
||||
|
||||
// add all active psprites
|
||||
psp = viewpoint.camera->player->psprites;
|
||||
while (psp)
|
||||
{
|
||||
// [RH] Don't draw the targeter's crosshair if the player already has a crosshair set.
|
||||
// It's possible this psprite's caller is now null but the layer itself hasn't been destroyed
|
||||
// because it didn't tick yet (if we typed 'take all' while in the console for example).
|
||||
// In this case let's simply not draw it to avoid crashing.
|
||||
|
||||
if ((psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && psp->GetCaller() != nullptr)
|
||||
{
|
||||
RenderSprite(thread, psp, viewpoint.camera, bobx, boby, wx, wy, viewpoint.TicFrac, spriteshade, basecolormap, foggy);
|
||||
}
|
||||
|
||||
psp = psp->GetNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyPlayerSprites::RenderRemainingSprites()
|
||||
{
|
||||
for (const PolyHWAccelPlayerSprite &sprite : AcceleratedSprites)
|
||||
{
|
||||
screen->DrawTexture(sprite.pic->GetTexture(),
|
||||
viewwindowx + sprite.x1,
|
||||
viewwindowy + viewheight / 2 - sprite.texturemid * sprite.yscale - 0.5,
|
||||
DTA_DestWidthF, FIXED2DBL(sprite.pic->GetWidth() * sprite.xscale),
|
||||
DTA_DestHeightF, sprite.pic->GetHeight() * sprite.yscale,
|
||||
DTA_TranslationIndex, sprite.Translation,
|
||||
DTA_FlipX, sprite.flip,
|
||||
DTA_TopOffset, 0,
|
||||
DTA_LeftOffset, 0,
|
||||
DTA_ClipLeft, viewwindowx,
|
||||
DTA_ClipTop, viewwindowy,
|
||||
DTA_ClipRight, viewwindowx + viewwidth,
|
||||
DTA_ClipBottom, viewwindowy + viewheight,
|
||||
DTA_Alpha, sprite.Alpha,
|
||||
DTA_RenderStyle, sprite.RenderStyle,
|
||||
DTA_FillColor, sprite.FillColor,
|
||||
DTA_SpecialColormap, sprite.special,
|
||||
DTA_ColorOverlay, sprite.overlay.d,
|
||||
DTA_Color, sprite.LightColor | 0xff000000, // the color here does not have a valid alpha component.
|
||||
DTA_Desaturate, sprite.Desaturate,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
AcceleratedSprites.Clear();
|
||||
}
|
||||
|
||||
void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy)
|
||||
{
|
||||
double tx;
|
||||
int x1;
|
||||
int x2;
|
||||
double sx, sy;
|
||||
spritedef_t* sprdef;
|
||||
spriteframe_t* sprframe;
|
||||
FTextureID picnum;
|
||||
uint16_t flip;
|
||||
FTexture* ttex;
|
||||
FSoftwareTexture* tex;
|
||||
bool noaccel;
|
||||
double alpha = owner->Alpha;
|
||||
|
||||
// decide which patch to use
|
||||
if ((unsigned)pspr->GetSprite() >= (unsigned)sprites.Size())
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite number %i\n", pspr->GetSprite());
|
||||
return;
|
||||
}
|
||||
sprdef = &sprites[pspr->GetSprite()];
|
||||
if (pspr->GetFrame() >= sprdef->numframes)
|
||||
{
|
||||
DPrintf(DMSG_ERROR, "R_DrawPSprite: invalid sprite frame %i : %i\n", pspr->GetSprite(), pspr->GetFrame());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
DCanvas *renderTarget = PolyRenderer::Instance()->RenderTarget;
|
||||
|
||||
// Force it to use software rendering when drawing to a canvas texture.
|
||||
bool renderToCanvas = PolyRenderer::Instance()->RenderToCanvas;
|
||||
|
||||
sprframe = &SpriteFrames[sprdef->spriteframes + pspr->GetFrame()];
|
||||
|
||||
picnum = sprframe->Texture[0];
|
||||
flip = sprframe->Flip & 1;
|
||||
ttex = TexMan.GetTexture(picnum);
|
||||
|
||||
if (!ttex->isValid())
|
||||
return;
|
||||
|
||||
tex = ttex->GetSoftwareTexture();
|
||||
|
||||
if (pspr->firstTic)
|
||||
{ // Can't interpolate the first tic.
|
||||
pspr->firstTic = false;
|
||||
pspr->oldx = pspr->x;
|
||||
pspr->oldy = pspr->y;
|
||||
}
|
||||
|
||||
sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac;
|
||||
sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y;
|
||||
|
||||
if (pspr->Flags & PSPF_ADDBOB)
|
||||
{
|
||||
sx += (pspr->Flags & PSPF_MIRROR) ? -bobx : bobx;
|
||||
sy += boby;
|
||||
}
|
||||
|
||||
if (pspr->Flags & PSPF_ADDWEAPON && pspr->GetID() != PSP_WEAPON)
|
||||
{
|
||||
sx += wx;
|
||||
sy += wy;
|
||||
}
|
||||
|
||||
if (renderHUDModel)
|
||||
{
|
||||
PolyRenderHUDModel(thread, PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToClip, 1, pspr, (float)sx, (float)sy);
|
||||
return;
|
||||
}
|
||||
|
||||
double yaspectMul = 1.2 * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio;
|
||||
|
||||
double pspritexscale = viewwindow.centerxwide / 160.0;
|
||||
double pspriteyscale = pspritexscale * yaspectMul;
|
||||
double pspritexiscale = 1 / pspritexscale;
|
||||
|
||||
int tleft = tex->GetScaledLeftOffsetPo();
|
||||
int twidth = tex->GetScaledWidth();
|
||||
|
||||
// calculate edges of the shape
|
||||
//tx = sx - BASEXCENTER;
|
||||
tx = (pspr->Flags & PSPF_MIRROR) ? ((BASEXCENTER - twidth) - (sx - tleft)) : ((sx - BASEXCENTER) - tleft);
|
||||
|
||||
x1 = xs_RoundToInt(viewwindow.centerx + tx * pspritexscale);
|
||||
|
||||
// off the right side
|
||||
if (x1 > viewwidth)
|
||||
return;
|
||||
|
||||
tx += twidth;
|
||||
x2 = xs_RoundToInt(viewwindow.centerx + tx * pspritexscale);
|
||||
|
||||
// off the left side
|
||||
if (x2 <= 0)
|
||||
return;
|
||||
|
||||
// store information in a vissprite
|
||||
PolyNoAccelPlayerSprite vis;
|
||||
|
||||
vis.renderflags = owner->renderflags;
|
||||
|
||||
vis.texturemid = (BASEYCENTER - sy) * tex->GetScale().Y + tex->GetTopOffsetPo();
|
||||
|
||||
if (viewpoint.camera->player && (renderToCanvas ||
|
||||
viewheight == renderTarget->GetHeight() ||
|
||||
(renderTarget->GetWidth() > (BASEXCENTER * 2))))
|
||||
{ // Adjust PSprite for fullscreen views
|
||||
vis.texturemid -= pspr->GetYAdjust(renderToCanvas || viewheight == renderTarget->GetHeight());
|
||||
}
|
||||
if (pspr->GetID() < PSP_TARGETCENTER)
|
||||
{ // Move the weapon down for 1280x1024.
|
||||
vis.texturemid -= AspectPspriteOffset(viewwindow.WidescreenRatio);
|
||||
}
|
||||
vis.x1 = x1 < 0 ? 0 : x1;
|
||||
vis.x2 = x2 >= viewwidth ? viewwidth : x2;
|
||||
vis.xscale = FLOAT2FIXED(pspritexscale / tex->GetScale().X);
|
||||
vis.yscale = float(pspriteyscale / tex->GetScale().Y);
|
||||
vis.pic = tex;
|
||||
|
||||
// If flip is used, provided that it's not already flipped (that would just invert itself)
|
||||
// (It's an XOR...)
|
||||
if (!(flip) != !(pspr->Flags & PSPF_FLIP))
|
||||
{
|
||||
vis.xiscale = -FLOAT2FIXED(pspritexiscale * tex->GetScale().X);
|
||||
vis.startfrac = (tex->GetWidth() << FRACBITS) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
vis.xiscale = FLOAT2FIXED(pspritexiscale * tex->GetScale().X);
|
||||
vis.startfrac = 0;
|
||||
}
|
||||
|
||||
if (vis.x1 > x1)
|
||||
vis.startfrac += vis.xiscale*(vis.x1 - x1);
|
||||
|
||||
noaccel = false;
|
||||
FDynamicColormap *colormap_to_use = nullptr;
|
||||
if (pspr->GetID() < PSP_TARGETCENTER)
|
||||
{
|
||||
auto rs = pspr->GetRenderStyle(owner->RenderStyle, owner->Alpha);
|
||||
vis.RenderStyle = rs.first;
|
||||
vis.Alpha = rs.second;
|
||||
|
||||
if (!vis.RenderStyle.IsVisible(vis.Alpha))
|
||||
return;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// The software renderer cannot invert the source without inverting the overlay
|
||||
// too. That means if the source is inverted, we need to do the reverse of what
|
||||
// the invert overlay flag says to do.
|
||||
bool invertcolormap = (vis.RenderStyle.Flags & STYLEF_InvertOverlay) != 0;
|
||||
|
||||
if (vis.RenderStyle.Flags & STYLEF_InvertSource)
|
||||
{
|
||||
invertcolormap = !invertcolormap;
|
||||
}
|
||||
|
||||
const FState* const psprState = pspr->GetState();
|
||||
bool fullbright = !foggy && (psprState == nullptr ? false : psprState->GetFullbright());
|
||||
bool fadeToBlack = (vis.RenderStyle.Flags & STYLEF_FadeToBlack) != 0;
|
||||
|
||||
vis.Light.SetColormap(0, spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack);
|
||||
|
||||
colormap_to_use = (FDynamicColormap*)vis.Light.BaseColormap;
|
||||
|
||||
if (viewpoint.camera->Inventory != nullptr)
|
||||
{
|
||||
visstyle_t visstyle;
|
||||
visstyle.Alpha = vis.Alpha;
|
||||
visstyle.RenderStyle = STYLE_Count;
|
||||
visstyle.Invert = false;
|
||||
|
||||
viewpoint.camera->Inventory->AlterWeaponSprite(&visstyle);
|
||||
|
||||
if (!(pspr->Flags & PSPF_FORCEALPHA)) vis.Alpha = visstyle.Alpha;
|
||||
|
||||
if (visstyle.RenderStyle != STYLE_Count && !(pspr->Flags & PSPF_FORCESTYLE))
|
||||
{
|
||||
vis.RenderStyle = visstyle.RenderStyle;
|
||||
}
|
||||
|
||||
if (visstyle.Invert)
|
||||
{
|
||||
vis.Light.BaseColormap = &SpecialSWColormaps[INVERSECOLORMAP];
|
||||
vis.Light.ColormapNum = 0;
|
||||
noaccel = true;
|
||||
}
|
||||
}
|
||||
// If drawing with a BOOM colormap, disable acceleration.
|
||||
if (vis.Light.BaseColormap == &NormalLight && NormalLight.Maps != realcolormaps.Maps)
|
||||
{
|
||||
noaccel = true;
|
||||
}
|
||||
#if 0
|
||||
// The HW 2D drawer should be able to handle this without problems
|
||||
// If the main colormap has fixed lights, and this sprite is being drawn with that
|
||||
// colormap, disable acceleration so that the lights can remain fixed.
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (!noaccel && cameraLight->ShaderColormap() == nullptr &&
|
||||
NormalLightHasFixedLights && vis.Light.BaseColormap == &NormalLight &&
|
||||
vis.pic->UseBasePalette())
|
||||
{
|
||||
noaccel = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
colormap_to_use = basecolormap;
|
||||
|
||||
vis.Light.BaseColormap = basecolormap;
|
||||
vis.Light.ColormapNum = 0;
|
||||
}
|
||||
|
||||
// Check for hardware-assisted 2D. If it's available, and this sprite is not
|
||||
// fuzzy, don't draw it until after the switch to 2D mode.
|
||||
if (!noaccel && !renderToCanvas)
|
||||
{
|
||||
FRenderStyle style = vis.RenderStyle;
|
||||
style.CheckFuzz();
|
||||
if (style.BlendOp != STYLEOP_Fuzz)
|
||||
{
|
||||
PolyHWAccelPlayerSprite accelSprite;
|
||||
|
||||
accelSprite.pic = vis.pic;
|
||||
accelSprite.texturemid = vis.texturemid;
|
||||
accelSprite.yscale = vis.yscale;
|
||||
accelSprite.xscale = vis.xscale;
|
||||
|
||||
accelSprite.Alpha = vis.Alpha;
|
||||
accelSprite.RenderStyle = vis.RenderStyle;
|
||||
accelSprite.Translation = vis.Translation;
|
||||
accelSprite.FillColor = vis.FillColor;
|
||||
|
||||
accelSprite.basecolormap = colormap_to_use;
|
||||
accelSprite.x1 = x1;
|
||||
accelSprite.flip = vis.xiscale < 0;
|
||||
|
||||
if (vis.Light.BaseColormap >= &SpecialSWColormaps[0] &&
|
||||
vis.Light.BaseColormap < &SpecialSWColormaps[SpecialColormaps.Size()])
|
||||
{
|
||||
accelSprite.special = &SpecialColormaps[vis.Light.BaseColormap - &SpecialSWColormaps[0]];
|
||||
}
|
||||
else if (PolyCameraLight::Instance()->ShaderColormap())
|
||||
{
|
||||
accelSprite.special = PolyCameraLight::Instance()->ShaderColormap();
|
||||
}
|
||||
else
|
||||
{
|
||||
accelSprite.overlay = colormap_to_use->Fade;
|
||||
accelSprite.overlay.a = uint8_t(vis.Light.ColormapNum * 255 / NUMCOLORMAPS);
|
||||
accelSprite.LightColor = colormap_to_use->Color;
|
||||
accelSprite.Desaturate = (uint8_t)clamp(colormap_to_use->Desaturate, 0, 255);
|
||||
}
|
||||
|
||||
AcceleratedSprites.Push(accelSprite);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vis.Render(thread);
|
||||
}
|
||||
|
||||
fixed_t RenderPolyPlayerSprites::LightLevelToShade(int lightlevel, bool foggy)
|
||||
{
|
||||
bool nolightfade = !foggy && ((PolyRenderer::Instance()->Level->flags3 & LEVEL3_NOLIGHTFADE));
|
||||
if (nolightfade)
|
||||
{
|
||||
return (MAX(255 - lightlevel, 0) * NUMCOLORMAPS) << (FRACBITS - 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert a light level into an unbounded colormap index (shade). Result is
|
||||
// fixed point. Why the +12? I wish I knew, but experimentation indicates it
|
||||
// is necessary in order to best reproduce Doom's original lighting.
|
||||
return (NUMCOLORMAPS * 2 * FRACUNIT) - ((lightlevel + 12) * (FRACUNIT*NUMCOLORMAPS / 128));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyNoAccelPlayerSprite::Render(PolyRenderThread *thread)
|
||||
{
|
||||
if (xscale == 0 || fabs(yscale) < (1.0f / 32000.0f))
|
||||
{ // scaled to 0; can't see
|
||||
return;
|
||||
}
|
||||
|
||||
RectDrawArgs args;
|
||||
args.SetStyle(RenderStyle, Alpha, FillColor, Translation, pic, false);
|
||||
args.SetLight(Light.BaseColormap, 255 - (Light.ColormapNum << 3));
|
||||
|
||||
double centerY = viewheight / 2;
|
||||
double y1, y2;
|
||||
if (renderflags & RF_YFLIP)
|
||||
{
|
||||
y1 = centerY + (texturemid - pic->GetHeight()) * (-yscale);
|
||||
y2 = y1 + pic->GetHeight() * (-yscale);
|
||||
}
|
||||
else
|
||||
{
|
||||
y1 = centerY - texturemid * yscale;
|
||||
y2 = y1 + pic->GetHeight() * yscale;
|
||||
}
|
||||
args.Draw(thread, viewwindowx + x1, viewwindowx + x2, viewwindowy + y1, viewwindowy + y2, 0.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyColormapLight::SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack)
|
||||
{
|
||||
if (fadeToBlack)
|
||||
{
|
||||
if (invertColormap) // Fade to white
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, MAKERGB(255, 255, 255), basecolormap->Desaturate);
|
||||
invertColormap = false;
|
||||
}
|
||||
else // Fade to black
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, MAKERGB(0, 0, 0), basecolormap->Desaturate);
|
||||
}
|
||||
}
|
||||
|
||||
if (invertColormap)
|
||||
{
|
||||
basecolormap = GetSpecialLights(basecolormap->Color, basecolormap->Fade.InverseColor(), basecolormap->Desaturate);
|
||||
}
|
||||
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedColormap())
|
||||
{
|
||||
BaseColormap = cameraLight->FixedColormap();
|
||||
ColormapNum = 0;
|
||||
}
|
||||
else if (cameraLight->FixedLightLevel() >= 0)
|
||||
{
|
||||
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap;
|
||||
ColormapNum = cameraLight->FixedLightLevel() >> COLORMAPSHIFT;
|
||||
}
|
||||
else if (fullbright)
|
||||
{
|
||||
BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap;
|
||||
ColormapNum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseColormap = basecolormap;
|
||||
ColormapNum = GETPALOOKUP(visibility, shade);
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "r_defs.h"
|
||||
|
||||
class DPSprite;
|
||||
struct FDynamicColormap;
|
||||
|
||||
class PolyColormapLight
|
||||
{
|
||||
public:
|
||||
int ColormapNum = 0;
|
||||
FSWColormap *BaseColormap = nullptr;
|
||||
|
||||
void SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack);
|
||||
};
|
||||
|
||||
class PolyNoAccelPlayerSprite
|
||||
{
|
||||
public:
|
||||
short x1 = 0;
|
||||
short x2 = 0;
|
||||
|
||||
double texturemid = 0.0;
|
||||
|
||||
fixed_t xscale = 0;
|
||||
float yscale = 0.0f;
|
||||
|
||||
FSoftwareTexture *pic = nullptr;
|
||||
|
||||
fixed_t xiscale = 0;
|
||||
fixed_t startfrac = 0;
|
||||
|
||||
float Alpha = 0.0f;
|
||||
FRenderStyle RenderStyle;
|
||||
uint32_t Translation = 0;
|
||||
uint32_t FillColor = 0;
|
||||
|
||||
PolyColormapLight Light;
|
||||
|
||||
short renderflags = 0;
|
||||
|
||||
void Render(PolyRenderThread *thread);
|
||||
};
|
||||
|
||||
class PolyHWAccelPlayerSprite
|
||||
{
|
||||
public:
|
||||
FSoftwareTexture *pic = nullptr;
|
||||
double texturemid = 0.0;
|
||||
float yscale = 0.0f;
|
||||
fixed_t xscale = 0;
|
||||
|
||||
float Alpha = 0.0f;
|
||||
FRenderStyle RenderStyle;
|
||||
uint32_t Translation = 0;
|
||||
uint32_t FillColor = 0;
|
||||
|
||||
FDynamicColormap *basecolormap = nullptr;
|
||||
int x1 = 0;
|
||||
|
||||
bool flip = false;
|
||||
FSpecialColormap *special = nullptr;
|
||||
PalEntry overlay = 0;
|
||||
PalEntry LightColor = 0xffffffff;
|
||||
uint8_t Desaturate = 0;
|
||||
};
|
||||
|
||||
class RenderPolyPlayerSprites
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread);
|
||||
void RenderRemainingSprites();
|
||||
|
||||
private:
|
||||
void RenderSprite(PolyRenderThread *thread, DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy);
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy);
|
||||
|
||||
enum { BASEXCENTER = 160 };
|
||||
enum { BASEYCENTER = 100 };
|
||||
|
||||
TArray<PolyHWAccelPlayerSprite> AcceleratedSprites;
|
||||
sector_t tempsec;
|
||||
bool renderHUDModel = false;
|
||||
};
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_maputl.h"
|
||||
#include "sbar.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_portal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyDrawSectorPortal::PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling) : Portal(portal), Ceiling(ceiling)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::Render(int portalDepth)
|
||||
{
|
||||
if (Portal->mType == PORTS_HORIZON || Portal->mType == PORTS_PLANE)
|
||||
return;
|
||||
|
||||
/*angle_t angle1 = PolyCull::PointToPseudoAngle(v1->fX(), v1->fY());
|
||||
angle_t angle2 = PolyCull::PointToPseudoAngle(v2->fX(), v2->fY());
|
||||
Segments.clear();
|
||||
Segments.push_back({ angle1, angle2 });*/
|
||||
|
||||
SaveGlobals();
|
||||
|
||||
PortalViewpoint = PolyRenderer::Instance()->SetupPerspectiveMatrix();
|
||||
PortalViewpoint.StencilValue = StencilValue;
|
||||
PortalViewpoint.PortalDepth = portalDepth;
|
||||
PortalViewpoint.PortalEnterSector = Portal->mDestination;
|
||||
|
||||
PolyRenderer::Instance()->Scene.Render(&PortalViewpoint);
|
||||
|
||||
RestoreGlobals();
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::SaveGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
SavedViewpoint = viewpoint;
|
||||
SavedInvisibility = viewpoint.camera ? (viewpoint.camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false;
|
||||
|
||||
if (Portal->mType == PORTS_SKYVIEWPOINT)
|
||||
{
|
||||
// Don't let gun flashes brighten the sky box
|
||||
AActor *sky = Portal->mSkybox;
|
||||
viewpoint.extralight = 0;
|
||||
//PolyRenderer::Instance()->Light.SetVisibility(sky->args[0] * 0.25f);
|
||||
viewpoint.Pos = sky->InterpolatedPosition(viewpoint.TicFrac);
|
||||
viewpoint.Angles.Yaw = SavedViewpoint.Angles.Yaw + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * viewpoint.TicFrac);
|
||||
}
|
||||
else //if (Portal->mType == PORTS_STACKEDSECTORTHING || Portal->mType == PORTS_PORTAL || Portal->mType == PORTS_LINKEDPORTAL)
|
||||
{
|
||||
//extralight = pl->extralight;
|
||||
//SetVisibility(pl->visibility);
|
||||
viewpoint.Pos.X += Portal->mDisplacement.X;
|
||||
viewpoint.Pos.Y += Portal->mDisplacement.Y;
|
||||
}
|
||||
|
||||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = Portal->mDestination;
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
|
||||
Portal->mFlags |= PORTSF_INSKYBOX;
|
||||
if (Portal->mPartner > 0) PolyRenderer::Instance()->Level->sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX;
|
||||
}
|
||||
|
||||
void PolyDrawSectorPortal::RestoreGlobals()
|
||||
{
|
||||
Portal->mFlags &= ~PORTSF_INSKYBOX;
|
||||
if (Portal->mPartner > 0) PolyRenderer::Instance()->Level->sectorPortals[Portal->mPartner].mFlags &= ~PORTSF_INSKYBOX;
|
||||
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
viewpoint = SavedViewpoint;
|
||||
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
if (SavedInvisibility)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
else
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
|
||||
//PolyRenderer::Instance()->Light.SetVisibility(savedvisibility);
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyDrawLinePortal::PolyDrawLinePortal(FLinePortal *portal) : Portal(portal)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
PolyDrawLinePortal::PolyDrawLinePortal(line_t *mirror) : Mirror(mirror)
|
||||
{
|
||||
StencilValue = PolyRenderer::Instance()->GetNextStencilValue();
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::Render(int portalDepth)
|
||||
{
|
||||
SaveGlobals();
|
||||
|
||||
// Find portal destination line and make sure it faces the right way
|
||||
line_t *clipLine = Portal ? Portal->mDestination : Mirror;
|
||||
DVector2 pt1 = clipLine->v1->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
DVector2 pt2 = clipLine->v2->fPos() - PolyRenderer::Instance()->Viewpoint.Pos;
|
||||
bool backfacing = (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0);
|
||||
|
||||
PortalViewpoint = PolyRenderer::Instance()->SetupPerspectiveMatrix(Mirror != nullptr);
|
||||
PortalViewpoint.StencilValue = StencilValue;
|
||||
PortalViewpoint.PortalDepth = portalDepth;
|
||||
PortalViewpoint.PortalEnterLine = clipLine;
|
||||
PortalViewpoint.PortalEnterSector = backfacing ? clipLine->frontsector : clipLine->backsector;
|
||||
|
||||
PolyRenderer::Instance()->Scene.Render(&PortalViewpoint);
|
||||
|
||||
RestoreGlobals();
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::SaveGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
SavedViewpoint = viewpoint;
|
||||
SavedInvisibility = viewpoint.camera ? (viewpoint.camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false;
|
||||
|
||||
if (Mirror)
|
||||
{
|
||||
DAngle startang = viewpoint.Angles.Yaw;
|
||||
DVector3 startpos = viewpoint.Pos;
|
||||
|
||||
vertex_t *v1 = Mirror->v1;
|
||||
|
||||
// Reflect the current view behind the mirror.
|
||||
if (Mirror->Delta().X == 0)
|
||||
{ // vertical mirror
|
||||
viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX();
|
||||
}
|
||||
else if (Mirror->Delta().Y == 0)
|
||||
{ // horizontal mirror
|
||||
viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY();
|
||||
}
|
||||
else
|
||||
{ // any mirror
|
||||
vertex_t *v2 = Mirror->v2;
|
||||
|
||||
double dx = v2->fX() - v1->fX();
|
||||
double dy = v2->fY() - v1->fY();
|
||||
double x1 = v1->fX();
|
||||
double y1 = v1->fY();
|
||||
double x = startpos.X;
|
||||
double y = startpos.Y;
|
||||
|
||||
// the above two cases catch len == 0
|
||||
double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy);
|
||||
|
||||
viewpoint.Pos.X = (x1 + r * dx) * 2 - x;
|
||||
viewpoint.Pos.Y = (y1 + r * dy) * 2 - y;
|
||||
}
|
||||
viewpoint.Angles.Yaw = Mirror->Delta().Angle() * 2 - startang;
|
||||
|
||||
if (viewpoint.camera)
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto src = Portal->mOrigin;
|
||||
auto dst = Portal->mDestination;
|
||||
|
||||
P_TranslatePortalXY(src, viewpoint.Pos.X, viewpoint.Pos.Y);
|
||||
P_TranslatePortalZ(src, viewpoint.Pos.Z);
|
||||
P_TranslatePortalAngle(src, viewpoint.Angles.Yaw);
|
||||
P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y);
|
||||
P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y);
|
||||
|
||||
if (viewpoint.camera && !viewpoint.showviewer)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
|
||||
/* What is this code trying to do?
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
|
||||
if (!viewpoint.showviewer && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst))
|
||||
{
|
||||
double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length();
|
||||
if (distp > EQUAL_EPSILON)
|
||||
{
|
||||
double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length();
|
||||
double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length();
|
||||
|
||||
if (dist1 + dist2 < distp + 1)
|
||||
{
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
viewpoint.camera = nullptr;
|
||||
viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(viewpoint.Pos)->sector;
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
||||
|
||||
void PolyDrawLinePortal::RestoreGlobals()
|
||||
{
|
||||
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
const auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
|
||||
viewpoint = SavedViewpoint;
|
||||
|
||||
if (viewpoint.camera)
|
||||
{
|
||||
if (SavedInvisibility)
|
||||
viewpoint.camera->renderflags |= RF_INVISIBLE;
|
||||
else
|
||||
viewpoint.camera->renderflags &= ~RF_INVISIBLE;
|
||||
}
|
||||
|
||||
viewpoint.SetViewAngle(viewwindow);
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "poly_scene.h"
|
||||
|
||||
struct PolyPortalVertexRange
|
||||
{
|
||||
PolyPortalVertexRange(const TriVertex *vertices, int count) : Vertices(vertices), Count(count) { }
|
||||
const TriVertex *Vertices;
|
||||
int Count;
|
||||
};
|
||||
|
||||
class PolyPortalSegment
|
||||
{
|
||||
public:
|
||||
PolyPortalSegment(angle_t start, angle_t end) : Start(start), End(end) { }
|
||||
angle_t Start, End;
|
||||
};
|
||||
|
||||
class PolyDrawSectorPortal
|
||||
{
|
||||
public:
|
||||
PolyDrawSectorPortal(FSectorPortal *portal, bool ceiling);
|
||||
|
||||
void Render(int portalDepth);
|
||||
|
||||
FSectorPortal *Portal = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
void RestoreGlobals();
|
||||
|
||||
bool Ceiling;
|
||||
PolyPortalViewpoint PortalViewpoint;
|
||||
|
||||
FRenderViewpoint SavedViewpoint;
|
||||
bool SavedInvisibility;
|
||||
};
|
||||
|
||||
class PolyDrawLinePortal
|
||||
{
|
||||
public:
|
||||
PolyDrawLinePortal(FLinePortal *portal);
|
||||
PolyDrawLinePortal(line_t *mirror);
|
||||
|
||||
void Render(int portalDepth);
|
||||
|
||||
FLinePortal *Portal = nullptr;
|
||||
line_t *Mirror = nullptr;
|
||||
uint32_t StencilValue = 0;
|
||||
std::vector<PolyPortalVertexRange> Shape;
|
||||
|
||||
private:
|
||||
void SaveGlobals();
|
||||
void RestoreGlobals();
|
||||
|
||||
PolyPortalViewpoint PortalViewpoint;
|
||||
|
||||
FRenderViewpoint SavedViewpoint;
|
||||
bool SavedInvisibility;
|
||||
};
|
|
@ -1,594 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "p_maputl.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_scene.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/scene/poly_wall.h"
|
||||
#include "polyrenderer/scene/poly_wallsprite.h"
|
||||
#include "polyrenderer/scene/poly_plane.h"
|
||||
#include "polyrenderer/scene/poly_particle.h"
|
||||
#include "polyrenderer/scene/poly_sprite.h"
|
||||
|
||||
EXTERN_CVAR(Int, r_portal_recursions)
|
||||
|
||||
extern double model_distance_cull;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RenderPolyScene::RenderPolyScene()
|
||||
{
|
||||
}
|
||||
|
||||
RenderPolyScene::~RenderPolyScene()
|
||||
{
|
||||
}
|
||||
|
||||
void RenderPolyScene::Render(PolyPortalViewpoint *viewpoint)
|
||||
{
|
||||
PolyPortalViewpoint *oldviewpoint = CurrentViewpoint;
|
||||
CurrentViewpoint = viewpoint;
|
||||
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
CurrentViewpoint->ObjectsStart = thread->TranslucentObjects.size();
|
||||
CurrentViewpoint->SectorPortalsStart = thread->SectorPortals.size();
|
||||
CurrentViewpoint->LinePortalsStart = thread->LinePortals.size();
|
||||
|
||||
PolyCullCycles.Clock();
|
||||
Cull.CullScene(CurrentViewpoint->PortalEnterSector, CurrentViewpoint->PortalEnterLine);
|
||||
PolyCullCycles.Unclock();
|
||||
|
||||
RenderSectors();
|
||||
|
||||
PolyMaskedCycles.Clock();
|
||||
const auto &rviewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
for (uint32_t sectorIndex : Cull.SeenSectors)
|
||||
{
|
||||
sector_t *sector = &PolyRenderer::Instance()->Level->sectors[sectorIndex];
|
||||
for (AActor *thing = sector->thinglist; thing != nullptr; thing = thing->snext)
|
||||
{
|
||||
if (!RenderPolySprite::IsThingCulled(thing))
|
||||
{
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
double distanceSquared = (thing->Pos() - rviewpoint.Pos).LengthSquared();
|
||||
if (r_modelscene && modelframe && distanceSquared < model_distance_cull)
|
||||
{
|
||||
AddModel(thread, thing, distanceSquared, thing->Pos());
|
||||
}
|
||||
else
|
||||
{
|
||||
DVector2 left, right;
|
||||
if (!RenderPolySprite::GetLine(thing, left, right))
|
||||
continue;
|
||||
AddSprite(thread, thing, distanceSquared, left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PolyMaskedCycles.Unclock();
|
||||
|
||||
CurrentViewpoint->ObjectsEnd = thread->TranslucentObjects.size();
|
||||
CurrentViewpoint->SectorPortalsEnd = thread->SectorPortals.size();
|
||||
CurrentViewpoint->LinePortalsEnd = thread->LinePortals.size();
|
||||
|
||||
Skydome.Render(thread, CurrentViewpoint->WorldToView, CurrentViewpoint->WorldToClip);
|
||||
|
||||
RenderPortals();
|
||||
RenderTranslucent();
|
||||
|
||||
CurrentViewpoint = oldviewpoint;
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSectors()
|
||||
{
|
||||
PolyRenderThread *mainthread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
int totalcount = (int)Cull.PvsSubsectors.size();
|
||||
uint32_t *subsectors = Cull.PvsSubsectors.data();
|
||||
|
||||
PolyOpaqueCycles.Clock();
|
||||
|
||||
PolyRenderer::Instance()->Threads.RenderThreadSlices(totalcount, [&](PolyRenderThread *thread)
|
||||
{
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip), nullptr);
|
||||
|
||||
if (thread != mainthread)
|
||||
{
|
||||
thread->TranslucentObjects.clear();
|
||||
thread->SectorPortals.clear();
|
||||
thread->LinePortals.clear();
|
||||
}
|
||||
|
||||
int start = thread->Start;
|
||||
int end = thread->End;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
RenderSubsector(thread, &PolyRenderer::Instance()->Level->subsectors[subsectors[i]], i);
|
||||
}
|
||||
}, [&](PolyRenderThread *thread)
|
||||
{
|
||||
const auto &objects = thread->TranslucentObjects;
|
||||
mainthread->TranslucentObjects.insert(mainthread->TranslucentObjects.end(), objects.begin(), objects.end());
|
||||
});
|
||||
|
||||
PolyOpaqueCycles.Unclock();
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth)
|
||||
{
|
||||
sector_t *frontsector = sub->sector;
|
||||
auto Level = frontsector->Level;
|
||||
frontsector->MoreFlags |= SECMF_DRAWN;
|
||||
|
||||
if (sub->polys)
|
||||
{
|
||||
if (sub->BSP == nullptr || sub->BSP->bDirty)
|
||||
{
|
||||
sub->BuildPolyBSP();
|
||||
|
||||
// This is done by the GL renderer, but not the sw renderer. No idea what the purpose is..
|
||||
for (unsigned i = 0; i < sub->BSP->Segs.Size(); i++)
|
||||
{
|
||||
sub->BSP->Segs[i].Subsector = sub;
|
||||
sub->BSP->Segs[i].PartnerSeg = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (sub->BSP->Nodes.Size() == 0)
|
||||
{
|
||||
RenderPolySubsector(thread, &sub->BSP->Subsectors[0], subsectorDepth, frontsector);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolyNode(thread, &sub->BSP->Nodes.Last(), subsectorDepth, frontsector);
|
||||
}
|
||||
}
|
||||
|
||||
PolyTransferHeights fakeflat(sub);
|
||||
|
||||
Render3DFloorPlane::RenderPlanes(thread, sub, CurrentViewpoint->StencilValue, subsectorDepth, thread->TranslucentObjects);
|
||||
RenderPolyPlane::RenderPlanes(thread, fakeflat, CurrentViewpoint->StencilValue, Cull.MaxCeilingHeight, Cull.MinFloorHeight, thread->SectorPortals, CurrentViewpoint->SectorPortalsStart);
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
if (Cull.IsLineSegVisible(subsectorDepth, i))
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
RenderLine(thread, sub, line, fakeflat.FrontSector, subsectorDepth);
|
||||
}
|
||||
}
|
||||
|
||||
int subsectorIndex = sub->Index();
|
||||
for (int i = Level->ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Level->Particles[i].snext)
|
||||
{
|
||||
particle_t *particle = &Level->Particles[i];
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentParticle>(particle, sub, subsectorDepth, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
// Decide which side the view point is on.
|
||||
int side = PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos, bsp);
|
||||
|
||||
// Recursively divide front space (toward the viewer).
|
||||
RenderPolyNode(thread, bsp->children[side], subsectorDepth, frontsector);
|
||||
|
||||
// Possibly divide back space (away from the viewer).
|
||||
side ^= 1;
|
||||
|
||||
// Don't bother culling on poly objects
|
||||
//if (!CheckBBox(bsp->bbox[side]))
|
||||
// return;
|
||||
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
RenderPolySubsector(thread, sub, subsectorDepth, frontsector);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
|
||||
for (uint32_t i = 0; i < sub->numlines; i++)
|
||||
{
|
||||
seg_t *line = &sub->firstline[i];
|
||||
if (line->linedef)
|
||||
{
|
||||
// Reject lines not facing viewer
|
||||
DVector2 pt1 = line->v1->fPos() - viewpoint.Pos;
|
||||
DVector2 pt2 = line->v2->fPos() - viewpoint.Pos;
|
||||
if (pt1.Y * (pt1.X - pt2.X) + pt1.X * (pt2.Y - pt1.Y) >= 0)
|
||||
continue;
|
||||
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
line->linedef->flags |= ML_MAPPED;
|
||||
sub->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
|
||||
RenderPolyWall::RenderLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, thread->TranslucentObjects, thread->LinePortals, CurrentViewpoint->LinePortalsStart, CurrentViewpoint->PortalEnterLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RenderPolyScene::PointOnSide(const DVector2 &pos, const node_t *node)
|
||||
{
|
||||
return DMulScale32(FLOAT2FIXED(pos.Y) - node->y, node->dx, node->x - FLOAT2FIXED(pos.X), node->dy) > 0;
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right)
|
||||
{
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
{
|
||||
subsector_t *sub = &PolyRenderer::Instance()->Level->subsectors[0];
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSprite(thread, thing, sortDistance, left, right, 0.0, 1.0, PolyRenderer::Instance()->Level->HeadNode());
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node)
|
||||
{
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
|
||||
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
|
||||
double planeD = planeNormal | planePos;
|
||||
|
||||
int sideLeft = (left | planeNormal) > planeD;
|
||||
int sideRight = (right | planeNormal) > planeD;
|
||||
|
||||
if (sideLeft != sideRight)
|
||||
{
|
||||
double dotLeft = planeNormal | left;
|
||||
double dotRight = planeNormal | right;
|
||||
double t = (planeD - dotLeft) / (dotRight - dotLeft);
|
||||
|
||||
DVector2 mid = left * (1.0 - t) + right * t;
|
||||
double tmid = t1 * (1.0 - t) + t2 * t;
|
||||
|
||||
AddSprite(thread, thing, sortDistance, mid, right, tmid, t2, bsp->children[sideRight]);
|
||||
right = mid;
|
||||
t2 = tmid;
|
||||
}
|
||||
node = bsp->children[sideLeft];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, (float)t1, (float)t2, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
|
||||
void RenderPolyScene::AddModel(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 pos)
|
||||
{
|
||||
if (PolyRenderer::Instance()->Level->nodes.Size() == 0)
|
||||
{
|
||||
subsector_t *sub = &PolyRenderer::Instance()->Level->subsectors[0];
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
void *node = PolyRenderer::Instance()->Level->HeadNode();
|
||||
|
||||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||||
{
|
||||
node_t *bsp = (node_t *)node;
|
||||
|
||||
DVector2 planePos(FIXED2DBL(bsp->x), FIXED2DBL(bsp->y));
|
||||
DVector2 planeNormal = DVector2(FIXED2DBL(-bsp->dy), FIXED2DBL(bsp->dx));
|
||||
double planeD = planeNormal | planePos;
|
||||
|
||||
int side = (pos | planeNormal) > planeD;
|
||||
node = bsp->children[side];
|
||||
}
|
||||
|
||||
subsector_t *sub = (subsector_t *)((uint8_t *)node - 1);
|
||||
|
||||
if (Cull.SubsectorDepths[sub->Index()] != 0xffffffff)
|
||||
thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject<PolyTranslucentThing>(thing, sub, Cull.SubsectorDepths[sub->Index()], sortDistance, 0.0f, 1.0f, CurrentViewpoint->StencilValue));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
|
||||
{
|
||||
// Tell automap we saw this
|
||||
if (!PolyRenderer::Instance()->DontMapLines && line->linedef)
|
||||
{
|
||||
line->linedef->flags |= ML_MAPPED;
|
||||
sub->flags |= SSECMF_DRAWN;
|
||||
}
|
||||
|
||||
// Render 3D floor sides
|
||||
if (line->sidedef && line->backsector && line->backsector->e && line->backsector->e->XFloor.ffloors.Size())
|
||||
{
|
||||
for (unsigned int i = 0; i < line->backsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *fakeFloor = line->backsector->e->XFloor.ffloors[i];
|
||||
RenderPolyWall::Render3DFloorLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, fakeFloor, thread->TranslucentObjects);
|
||||
}
|
||||
}
|
||||
|
||||
// Render wall, and update culling info if its an occlusion blocker
|
||||
RenderPolyWall::RenderLine(thread, line, frontsector, subsectorDepth, CurrentViewpoint->StencilValue, thread->TranslucentObjects, thread->LinePortals, CurrentViewpoint->LinePortalsStart, CurrentViewpoint->PortalEnterLine);
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderPortals()
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
bool enterPortals = CurrentViewpoint->PortalDepth < r_portal_recursions;
|
||||
|
||||
if (enterPortals)
|
||||
{
|
||||
for (size_t i = CurrentViewpoint->SectorPortalsStart; i < CurrentViewpoint->SectorPortalsEnd; i++)
|
||||
thread->SectorPortals[i]->Render(CurrentViewpoint->PortalDepth + 1);
|
||||
|
||||
for (size_t i = CurrentViewpoint->LinePortalsStart; i < CurrentViewpoint->LinePortalsEnd; i++)
|
||||
thread->LinePortals[i]->Render(CurrentViewpoint->PortalDepth + 1);
|
||||
}
|
||||
|
||||
Mat4f *transform = thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip);
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, transform, nullptr);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetWriteColor(!enterPortals);
|
||||
args.SetDepthTest(false);
|
||||
|
||||
if (!enterPortals) // Fill with black
|
||||
{
|
||||
bool foggy = false;
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(foggy), true);
|
||||
args.SetStyle(TriBlendMode::Fill);
|
||||
args.SetColor(0, 0);
|
||||
}
|
||||
|
||||
for (size_t i = CurrentViewpoint->SectorPortalsStart; i < CurrentViewpoint->SectorPortalsEnd; i++)
|
||||
{
|
||||
const auto &portal = thread->SectorPortals[i];
|
||||
args.SetStencilTestValue(enterPortals ? portal->StencilValue + 1 : portal->StencilValue);
|
||||
args.SetWriteStencil(true, CurrentViewpoint->StencilValue + 1);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = CurrentViewpoint->LinePortalsStart; i < CurrentViewpoint->LinePortalsEnd; i++)
|
||||
{
|
||||
const auto &portal = thread->LinePortals[i];
|
||||
args.SetStencilTestValue(enterPortals ? portal->StencilValue + 1 : portal->StencilValue);
|
||||
args.SetWriteStencil(true, CurrentViewpoint->StencilValue + 1);
|
||||
for (const auto &verts : portal->Shape)
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, verts.Vertices, verts.Count, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyScene::RenderTranslucent()
|
||||
{
|
||||
PolyRenderThread *thread = PolyRenderer::Instance()->Threads.MainThread();
|
||||
|
||||
Mat4f *transform = thread->FrameMemory->NewObject<Mat4f>(CurrentViewpoint->WorldToClip);
|
||||
PolyTriangleDrawer::SetCullCCW(thread->DrawQueue, !CurrentViewpoint->Mirror);
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, transform, nullptr);
|
||||
|
||||
PolyMaskedCycles.Clock();
|
||||
|
||||
// Draw all translucent objects back to front
|
||||
std::stable_sort(
|
||||
thread->TranslucentObjects.begin() + CurrentViewpoint->ObjectsStart,
|
||||
thread->TranslucentObjects.begin() + CurrentViewpoint->ObjectsEnd,
|
||||
[](auto a, auto b) { return *a < *b; });
|
||||
|
||||
auto objects = thread->TranslucentObjects.data();
|
||||
for (size_t i = CurrentViewpoint->ObjectsEnd; i > CurrentViewpoint->ObjectsStart; i--)
|
||||
{
|
||||
PolyTranslucentObject *obj = objects[i - 1];
|
||||
obj->Render(thread);
|
||||
obj->~PolyTranslucentObject();
|
||||
}
|
||||
|
||||
PolyMaskedCycles.Unclock();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyTransferHeights::PolyTransferHeights(subsector_t *sub) : Subsector(sub)
|
||||
{
|
||||
sector_t *sec = sub->sector;
|
||||
|
||||
// If player's view height is underneath fake floor, lower the
|
||||
// drawn ceiling to be just under the floor height, and replace
|
||||
// the drawn floor and ceiling textures, and light PolyRenderer::Instance()->Level->, with
|
||||
// the control sector's.
|
||||
//
|
||||
// Similar for ceiling, only reflected.
|
||||
|
||||
// [RH] allow per-plane lighting
|
||||
FloorLightLevel = sec->GetFloorLight();
|
||||
CeilingLightLevel = sec->GetCeilingLight();
|
||||
|
||||
FakeSide = PolyWaterFakeSide::Center;
|
||||
|
||||
const sector_t *s = sec->GetHeightSec();
|
||||
if (s != nullptr)
|
||||
{
|
||||
sector_t *heightsec = PolyRenderer::Instance()->Viewpoint.sector->heightsec;
|
||||
bool underwater = (heightsec && heightsec->floorplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0);
|
||||
bool doorunderwater = false;
|
||||
int diffTex = (s->MoreFlags & SECMF_CLIPFAKEPLANES);
|
||||
|
||||
// Replace sector being drawn with a copy to be hacked
|
||||
tempsec = *sec;
|
||||
|
||||
// Replace floor and ceiling height with control sector's heights.
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->floorplane.CopyPlaneIfValid(&tempsec.floorplane, &sec->ceilingplane))
|
||||
{
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
}
|
||||
else if (s->MoreFlags & SECMF_FAKEFLOORONLY)
|
||||
{
|
||||
if (underwater)
|
||||
{
|
||||
tempsec.Colormap = s->Colormap;
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::BelowFloor;
|
||||
FrontSector = &tempsec;
|
||||
return;
|
||||
}
|
||||
FrontSector = sec;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.floorplane = s->floorplane;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
||||
{
|
||||
if (diffTex)
|
||||
{
|
||||
if (s->ceilingplane.CopyPlaneIfValid(&tempsec.ceilingplane, &sec->floorplane))
|
||||
{
|
||||
tempsec.SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.ceilingplane = s->ceilingplane;
|
||||
}
|
||||
}
|
||||
|
||||
double refceilz = s->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
|
||||
double orgceilz = sec->ceilingplane.ZatPoint(PolyRenderer::Instance()->Viewpoint.Pos);
|
||||
|
||||
if (underwater || doorunderwater)
|
||||
{
|
||||
tempsec.floorplane = sec->floorplane;
|
||||
tempsec.ceilingplane = s->floorplane;
|
||||
tempsec.ceilingplane.FlipVert();
|
||||
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
|
||||
tempsec.Colormap = s->Colormap;
|
||||
}
|
||||
|
||||
// killough 11/98: prevent sudden light changes from non-water sectors:
|
||||
if (underwater || doorunderwater)
|
||||
{
|
||||
// head-below-floor hack
|
||||
tempsec.SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
|
||||
tempsec.ceilingplane = s->floorplane;
|
||||
tempsec.ceilingplane.FlipVert();
|
||||
tempsec.ceilingplane.ChangeHeight(-1 / 65536.);
|
||||
if (s->GetTexture(sector_t::ceiling) == skyflatnum)
|
||||
{
|
||||
tempsec.floorplane = tempsec.ceilingplane;
|
||||
tempsec.floorplane.FlipVert();
|
||||
tempsec.floorplane.ChangeHeight(+1 / 65536.);
|
||||
tempsec.SetTexture(sector_t::ceiling, tempsec.GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempsec.SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::BelowFloor;
|
||||
}
|
||||
else if (heightsec && heightsec->ceilingplane.PointOnSide(PolyRenderer::Instance()->Viewpoint.Pos) <= 0 && orgceilz > refceilz && !(s->MoreFlags & SECMF_FAKEFLOORONLY))
|
||||
{
|
||||
// Above-ceiling hack
|
||||
tempsec.ceilingplane = s->ceilingplane;
|
||||
tempsec.floorplane = s->ceilingplane;
|
||||
tempsec.floorplane.FlipVert();
|
||||
tempsec.floorplane.ChangeHeight(+1 / 65536.);
|
||||
tempsec.Colormap = s->Colormap;
|
||||
|
||||
tempsec.SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false);
|
||||
tempsec.planes[sector_t::ceiling].xform = tempsec.planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform;
|
||||
|
||||
if (s->GetTexture(sector_t::floor) != skyflatnum)
|
||||
{
|
||||
tempsec.ceilingplane = sec->ceilingplane;
|
||||
tempsec.SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false);
|
||||
tempsec.planes[sector_t::floor].xform = s->planes[sector_t::floor].xform;
|
||||
}
|
||||
|
||||
if (!(s->MoreFlags & SECMF_NOFAKELIGHT))
|
||||
{
|
||||
tempsec.lightlevel = s->lightlevel;
|
||||
|
||||
FloorLightLevel = s->GetFloorLight();
|
||||
CeilingLightLevel = s->GetCeilingLight();
|
||||
}
|
||||
FakeSide = PolyWaterFakeSide::AboveCeiling;
|
||||
}
|
||||
sec = &tempsec;
|
||||
}
|
||||
FrontSector = sec;
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include "doomdata.h"
|
||||
#include "r_utility.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
#include "poly_playersprite.h"
|
||||
#include "poly_cull.h"
|
||||
#include "poly_sky.h"
|
||||
|
||||
class PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentObject(uint32_t subsectorDepth = 0, double distanceSquared = 0.0) : subsectorDepth(subsectorDepth), DistanceSquared(distanceSquared) { }
|
||||
virtual ~PolyTranslucentObject() { }
|
||||
|
||||
virtual void Render(PolyRenderThread *thread) = 0;
|
||||
|
||||
bool operator<(const PolyTranslucentObject &other) const
|
||||
{
|
||||
return subsectorDepth != other.subsectorDepth ? subsectorDepth < other.subsectorDepth : DistanceSquared < other.DistanceSquared;
|
||||
}
|
||||
|
||||
uint32_t subsectorDepth;
|
||||
double DistanceSquared;
|
||||
};
|
||||
|
||||
class PolyDrawSectorPortal;
|
||||
class PolyDrawLinePortal;
|
||||
class PolyPortalSegment;
|
||||
|
||||
class PolyPortalViewpoint
|
||||
{
|
||||
public:
|
||||
Mat4f WorldToView;
|
||||
Mat4f WorldToClip;
|
||||
uint32_t StencilValue = 0;
|
||||
int PortalDepth = 0;
|
||||
bool Mirror = false;
|
||||
|
||||
line_t *PortalEnterLine = nullptr;
|
||||
sector_t *PortalEnterSector = nullptr;
|
||||
|
||||
size_t ObjectsStart = 0;
|
||||
size_t ObjectsEnd = 0;
|
||||
size_t SectorPortalsStart = 0;
|
||||
size_t SectorPortalsEnd = 0;
|
||||
size_t LinePortalsStart = 0;
|
||||
size_t LinePortalsEnd = 0;
|
||||
};
|
||||
|
||||
// Renders everything from a specific viewpoint
|
||||
class RenderPolyScene
|
||||
{
|
||||
public:
|
||||
RenderPolyScene();
|
||||
~RenderPolyScene();
|
||||
|
||||
void Render(PolyPortalViewpoint *viewpoint);
|
||||
|
||||
static const uint32_t SkySubsectorDepth = 0x7fffffff;
|
||||
|
||||
PolyPortalViewpoint *CurrentViewpoint = nullptr;
|
||||
|
||||
private:
|
||||
void RenderPortals();
|
||||
void RenderTranslucent();
|
||||
void RenderSectors();
|
||||
void RenderSubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth);
|
||||
void RenderLine(PolyRenderThread *thread, subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth);
|
||||
void AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, const DVector2 &left, const DVector2 &right);
|
||||
void AddSprite(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 left, DVector2 right, double t1, double t2, void *node);
|
||||
void AddModel(PolyRenderThread *thread, AActor *thing, double sortDistance, DVector2 pos);
|
||||
|
||||
void RenderPolySubsector(PolyRenderThread *thread, subsector_t *sub, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
void RenderPolyNode(PolyRenderThread *thread, void *node, uint32_t subsectorDepth, sector_t *frontsector);
|
||||
static int PointOnSide(const DVector2 &pos, const node_t *node);
|
||||
|
||||
PolyCull Cull;
|
||||
PolySkyDome Skydome;
|
||||
};
|
||||
|
||||
enum class PolyWaterFakeSide
|
||||
{
|
||||
Center,
|
||||
BelowFloor,
|
||||
AboveCeiling
|
||||
};
|
||||
|
||||
class PolyTransferHeights
|
||||
{
|
||||
public:
|
||||
PolyTransferHeights(subsector_t *sub);
|
||||
|
||||
subsector_t *Subsector = nullptr;
|
||||
sector_t *FrontSector = nullptr;
|
||||
PolyWaterFakeSide FakeSide = PolyWaterFakeSide::Center;
|
||||
int FloorLightLevel = 0;
|
||||
int CeilingLightLevel = 0;
|
||||
|
||||
private:
|
||||
sector_t tempsec;
|
||||
};
|
|
@ -1,429 +0,0 @@
|
|||
/*
|
||||
** Sky dome rendering
|
||||
** Copyright(C) 2003-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with this program. If not, see http:**www.gnu.org/licenses/
|
||||
**
|
||||
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_sky.h"
|
||||
#include "poly_portal.h"
|
||||
#include "r_sky.h" // for skyflatnum
|
||||
#include "g_levellocals.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
|
||||
EXTERN_CVAR(Float, skyoffset)
|
||||
EXTERN_CVAR(Int, r_skymode)
|
||||
|
||||
PolySkyDome::PolySkyDome()
|
||||
{
|
||||
CreateDome();
|
||||
}
|
||||
|
||||
void PolySkyDome::Render(PolyRenderThread *thread, const Mat4f &worldToView, const Mat4f &worldToClip)
|
||||
{
|
||||
#ifdef USE_GL_DOME_MATH
|
||||
Mat4f modelMatrix = GLSkyMath();
|
||||
#else
|
||||
Mat4f modelMatrix = Mat4f::Identity();
|
||||
|
||||
PolySkySetup frameSetup;
|
||||
frameSetup.Update();
|
||||
|
||||
if (frameSetup != mCurrentSetup)
|
||||
{
|
||||
// frontcyl = pixels for full 360 degrees, front texture
|
||||
// backcyl = pixels for full 360 degrees, back texture
|
||||
// skymid = Y scaled pixel offset
|
||||
// sky1pos = unscaled X offset, front
|
||||
// sky2pos = unscaled X offset, back
|
||||
// frontpos = scaled X pixel offset (fixed point)
|
||||
// backpos = scaled X pixel offset (fixed point)
|
||||
// skyflip = flip X direction
|
||||
|
||||
float scaleBaseV = 1.42f;
|
||||
float offsetBaseV = 0.25f;
|
||||
|
||||
float scaleFrontU = frameSetup.frontcyl / (float)frameSetup.frontskytex->GetWidth();
|
||||
float scaleFrontV = (float)frameSetup.frontskytex->GetScale().Y * scaleBaseV;
|
||||
float offsetFrontU = (float)((frameSetup.frontpos / 65536.0 + frameSetup.frontcyl / 2) / frameSetup.frontskytex->GetWidth());
|
||||
float offsetFrontV = (float)((frameSetup.skymid / frameSetup.frontskytex->GetHeight() + offsetBaseV) * scaleBaseV);
|
||||
|
||||
unsigned int count = mVertices.Size();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
mVertices[i].u = offsetFrontU + mInitialUV[i].X * scaleFrontU;
|
||||
mVertices[i].v = offsetFrontV + mInitialUV[i].Y * scaleFrontV;
|
||||
}
|
||||
|
||||
mCurrentSetup = frameSetup;
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
Mat4f objectToWorld = Mat4f::Translate((float)viewpoint.Pos.X, (float)viewpoint.Pos.Y, (float)viewpoint.Pos.Z) * modelMatrix;
|
||||
|
||||
int rc = mRows + 1;
|
||||
|
||||
PolyTriangleDrawer::SetTransform(thread->DrawQueue, thread->FrameMemory->NewObject<Mat4f>(worldToClip * objectToWorld), nullptr);
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(&NormalLight, 255, PolyRenderer::Instance()->Light.WallGlobVis(false), true);
|
||||
args.SetStencilTestValue(255);
|
||||
args.SetWriteStencil(true, 1);
|
||||
args.SetClipPlane(0, PolyClipPlane(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, 0, false);
|
||||
RenderCapColorRow(thread, args, mCurrentSetup.frontskytex, rc, true);
|
||||
|
||||
args.SetTexture(mCurrentSetup.frontskytex, DefaultRenderStyle());
|
||||
|
||||
uint32_t topcapcolor = mCurrentSetup.frontskytex->GetSkyCapColor(false);
|
||||
uint32_t bottomcapcolor = mCurrentSetup.frontskytex->GetSkyCapColor(true);
|
||||
uint8_t topcapindex = RGB256k.All[((RPART(topcapcolor) >> 2) << 12) | ((GPART(topcapcolor) >> 2) << 6) | (BPART(topcapcolor) >> 2)];
|
||||
uint8_t bottomcapindex = RGB256k.All[((RPART(bottomcapcolor) >> 2) << 12) | ((GPART(bottomcapcolor) >> 2) << 6) | (BPART(bottomcapcolor) >> 2)];
|
||||
|
||||
for (int i = 1; i <= mRows; i++)
|
||||
{
|
||||
RenderRow(thread, args, i, topcapcolor, topcapindex);
|
||||
RenderRow(thread, args, rc + i, bottomcapcolor, bottomcapindex);
|
||||
}
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex)
|
||||
{
|
||||
args.SetColor(capcolor, capcolorindex);
|
||||
args.SetStyle(TriBlendMode::Skycap);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip);
|
||||
}
|
||||
|
||||
void PolySkyDome::RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap)
|
||||
{
|
||||
uint32_t solid = skytex->GetSkyCapColor(bottomCap);
|
||||
uint8_t palsolid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)];
|
||||
|
||||
args.SetColor(solid, palsolid);
|
||||
args.SetStyle(TriBlendMode::Fill);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
void PolySkyDome::CreateDome()
|
||||
{
|
||||
mColumns = 16;// 128;
|
||||
mRows = 4;
|
||||
CreateSkyHemisphere(false);
|
||||
CreateSkyHemisphere(true);
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
}
|
||||
|
||||
void PolySkyDome::CreateSkyHemisphere(bool zflip)
|
||||
{
|
||||
int r, c;
|
||||
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
|
||||
for (c = 0; c < mColumns; c++)
|
||||
{
|
||||
SkyVertex(1, zflip ? c : (mColumns - 1 - c), zflip);
|
||||
}
|
||||
|
||||
// The total number of triangles per hemisphere can be calculated
|
||||
// as follows: rows * columns * 2 + 2 (for the top cap).
|
||||
for (r = 0; r < mRows; r++)
|
||||
{
|
||||
mPrimStart.Push(mVertices.Size());
|
||||
for (c = 0; c <= mColumns; c++)
|
||||
{
|
||||
SkyVertex(r + 1 - zflip, c, zflip);
|
||||
SkyVertex(r + zflip, c, zflip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TriVertex PolySkyDome::SetVertexXYZ(float xx, float yy, float zz, float uu, float vv)
|
||||
{
|
||||
TriVertex v;
|
||||
v.x = xx;
|
||||
v.y = zz;
|
||||
v.z = yy;
|
||||
v.w = 1.0f;
|
||||
v.u = uu;
|
||||
v.v = vv;
|
||||
return v;
|
||||
}
|
||||
|
||||
void PolySkyDome::SkyVertex(int r, int c, bool zflip)
|
||||
{
|
||||
static const FAngle maxSideAngle = 60.f;
|
||||
static const float scale = 10000.;
|
||||
|
||||
FAngle topAngle = (c / (float)mColumns * 360.f);
|
||||
FAngle sideAngle = maxSideAngle * (float)(mRows - r) / (float)mRows;
|
||||
float height = sideAngle.Sin();
|
||||
float realRadius = scale * sideAngle.Cos();
|
||||
FVector2 pos = topAngle.ToVector(realRadius);
|
||||
float z = (!zflip) ? scale * height : -scale * height;
|
||||
|
||||
float u, v;
|
||||
|
||||
// And the texture coordinates.
|
||||
if (!zflip) // Flipped Y is for the lower hemisphere.
|
||||
{
|
||||
u = (-c / (float)mColumns);
|
||||
v = (r / (float)mRows);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = (-c / (float)mColumns);
|
||||
v = 1.0f + ((mRows - r) / (float)mRows);
|
||||
}
|
||||
|
||||
if (r != 4) z += 300;
|
||||
|
||||
// And finally the vertex.
|
||||
TriVertex vert;
|
||||
vert = SetVertexXYZ(-pos.X, z - 1.f, pos.Y, u, v - 0.5f);
|
||||
mVertices.Push(vert);
|
||||
mInitialUV.Push({ vert.u, vert.v });
|
||||
}
|
||||
|
||||
Mat4f PolySkyDome::GLSkyMath()
|
||||
{
|
||||
PolySkySetup frameSetup;
|
||||
frameSetup.Update();
|
||||
mCurrentSetup = frameSetup;
|
||||
|
||||
float x_offset = 0.0f;
|
||||
float y_offset = 0.0f;
|
||||
bool mirror = false;
|
||||
FSoftwareTexture *tex = mCurrentSetup.frontskytex;
|
||||
|
||||
int texh = 0;
|
||||
int texw = 0;
|
||||
|
||||
Mat4f modelMatrix = Mat4f::Identity();
|
||||
if (tex)
|
||||
{
|
||||
texw = tex->GetWidth();
|
||||
texh = tex->GetHeight();
|
||||
|
||||
modelMatrix = Mat4f::Rotate(-180.0f + x_offset, 0.f, 0.f, 1.f);
|
||||
|
||||
float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f;
|
||||
float yscale = 1.f;
|
||||
if (texh <= 128 && (PolyRenderer::Instance()->Level->flags & LEVEL_FORCETILEDSKY))
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
else if (texh < 128)
|
||||
{
|
||||
// smaller sky textures must be tiled. We restrict it to 128 sky pixels, though
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, -1250.f);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 128 / 230.f);
|
||||
yscale = (float)(128 / texh); // intentionally left as integer.
|
||||
}
|
||||
else if (texh < 200)
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, -1250.f);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, texh / 230.f);
|
||||
}
|
||||
else if (texh <= 240)
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (200 - texh + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f);
|
||||
}
|
||||
else
|
||||
{
|
||||
modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor);
|
||||
modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f);
|
||||
yscale = 240.f / texh;
|
||||
}
|
||||
|
||||
float offsetU = 1.0f;
|
||||
float offsetV = y_offset / texh;
|
||||
float scaleU = mirror ? -xscale : xscale;
|
||||
float scaleV = yscale;
|
||||
|
||||
unsigned int count = mVertices.Size();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
mVertices[i].u = offsetU + mInitialUV[i].X * scaleU;
|
||||
mVertices[i].v = offsetV + mInitialUV[i].Y * scaleV;
|
||||
}
|
||||
}
|
||||
|
||||
return modelMatrix;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true)
|
||||
{
|
||||
auto tex = TexMan.GetPalettedTexture(texid, true);
|
||||
if (tex == nullptr) return nullptr;
|
||||
if (!allownull && !tex->isValid()) return nullptr;
|
||||
return tex->GetSoftwareTexture();
|
||||
}
|
||||
|
||||
void PolySkySetup::Update()
|
||||
{
|
||||
double skytexturemid = 0.0;
|
||||
double skyscale = 0.0;
|
||||
float skyiscale = 0.0f;
|
||||
fixed_t sky1cyl = 0, sky2cyl = 0;
|
||||
auto Level = PolyRenderer::Instance()->Level;
|
||||
|
||||
auto skytex1 = TexMan.GetPalettedTexture(Level->skytexture1, true);
|
||||
auto skytex2 = TexMan.GetPalettedTexture(Level->skytexture2, true);
|
||||
|
||||
if (skytex1)
|
||||
{
|
||||
FSoftwareTexture *sskytex1 = skytex1->GetSoftwareTexture();
|
||||
FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture();
|
||||
skytexturemid = 0;
|
||||
int skyheight = skytex1->GetDisplayHeight();
|
||||
if (skyheight >= 128 && skyheight < 200)
|
||||
{
|
||||
skytexturemid = -28;
|
||||
}
|
||||
else if (skyheight > 200)
|
||||
{
|
||||
skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(Level->flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0);
|
||||
}
|
||||
|
||||
if (viewwidth != 0 && viewheight != 0)
|
||||
{
|
||||
skyiscale = float(r_Yaspect / freelookviewheight);
|
||||
skyscale = freelookviewheight / r_Yaspect;
|
||||
|
||||
skyiscale *= float(PolyRenderer::Instance()->Viewpoint.FieldOfView.Degrees / 90.);
|
||||
skyscale *= float(90. / PolyRenderer::Instance()->Viewpoint.FieldOfView.Degrees);
|
||||
}
|
||||
|
||||
if (Level->skystretch)
|
||||
{
|
||||
skyscale *= (double)SKYSTRETCH_HEIGHT / skyheight;
|
||||
skyiscale *= skyheight / (float)SKYSTRETCH_HEIGHT;
|
||||
skytexturemid *= skyheight / (double)SKYSTRETCH_HEIGHT;
|
||||
}
|
||||
|
||||
// The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees,
|
||||
// giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024,
|
||||
// we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of
|
||||
// the texture as the cylinder's circumfrence.
|
||||
sky1cyl = MAX(sskytex1->GetWidth(), fixed_t(sskytex1->GetScale().X * 1024));
|
||||
sky2cyl = MAX(sskytex2->GetWidth(), fixed_t(sskytex2->GetScale().Y * 1024));
|
||||
}
|
||||
|
||||
FTextureID sky1tex, sky2tex;
|
||||
double frontdpos = 0, backdpos = 0;
|
||||
|
||||
if ((PolyRenderer::Instance()->Level->flags & LEVEL_SWAPSKIES) && !(PolyRenderer::Instance()->Level->flags & LEVEL_DOUBLESKY))
|
||||
{
|
||||
sky1tex = Level->skytexture2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sky1tex = Level->skytexture1;
|
||||
}
|
||||
sky2tex = Level->skytexture2;
|
||||
skymid = skytexturemid;
|
||||
skyangle = 0;
|
||||
|
||||
int sectorSky = 0;// sector->sky;
|
||||
|
||||
if (!(sectorSky & PL_SKYFLAT))
|
||||
{ // use sky1
|
||||
sky1:
|
||||
frontskytex = GetSWTex(sky1tex);
|
||||
if (PolyRenderer::Instance()->Level->flags & LEVEL_DOUBLESKY)
|
||||
backskytex = GetSWTex(sky2tex);
|
||||
else
|
||||
backskytex = nullptr;
|
||||
skyflip = false;
|
||||
frontdpos = Level->sky1pos;
|
||||
backdpos = Level->sky2pos;
|
||||
frontcyl = sky1cyl;
|
||||
backcyl = sky2cyl;
|
||||
}
|
||||
else if (sectorSky == PL_SKYFLAT)
|
||||
{ // use sky2
|
||||
frontskytex = GetSWTex(sky2tex);
|
||||
backskytex = nullptr;
|
||||
frontcyl = sky2cyl;
|
||||
skyflip = false;
|
||||
frontdpos = Level->sky2pos;
|
||||
}
|
||||
else
|
||||
{ // MBF's linedef-controlled skies
|
||||
// Sky Linedef
|
||||
const line_t *l = &PolyRenderer::Instance()->Level->lines[(sectorSky & ~PL_SKYFLAT) - 1];
|
||||
|
||||
// Sky transferred from first sidedef
|
||||
const side_t *s = l->sidedef[0];
|
||||
int pos;
|
||||
|
||||
// Texture comes from upper texture of reference sidedef
|
||||
// [RH] If swapping skies, then use the lower sidedef
|
||||
if (PolyRenderer::Instance()->Level->flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid())
|
||||
{
|
||||
pos = side_t::bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = side_t::top;
|
||||
}
|
||||
|
||||
frontskytex = GetSWTex(s->GetTexture(pos), false);
|
||||
if (frontskytex == nullptr)
|
||||
{ // [RH] The blank texture: Use normal sky instead.
|
||||
goto sky1;
|
||||
}
|
||||
backskytex = nullptr;
|
||||
|
||||
// Horizontal offset is turned into an angle offset,
|
||||
// to allow sky rotation as well as careful positioning.
|
||||
// However, the offset is scaled very small, so that it
|
||||
// allows a long-period of sky rotation.
|
||||
skyangle += FLOAT2FIXED(s->GetTextureXOffset(pos));
|
||||
|
||||
// Vertical offset allows careful sky positioning.
|
||||
skymid = s->GetTextureYOffset(pos);
|
||||
|
||||
// We sometimes flip the picture horizontally.
|
||||
//
|
||||
// Doom always flipped the picture, so we make it optional,
|
||||
// to make it easier to use the new feature, while to still
|
||||
// allow old sky textures to be used.
|
||||
skyflip = l->args[2] ? false : true;
|
||||
|
||||
int frontxscale = int(frontskytex->GetScale().X * 1024);
|
||||
frontcyl = MAX(frontskytex->GetWidth(), frontxscale);
|
||||
}
|
||||
|
||||
frontpos = int(fmod(frontdpos, sky1cyl * 65536.0));
|
||||
if (backskytex != nullptr)
|
||||
{
|
||||
backpos = int(fmod(backdpos, sky2cyl * 65536.0));
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
** Sky dome rendering
|
||||
** Copyright(C) 2003-2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU Lesser General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU Lesser General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU Lesser General Public License
|
||||
** along with this program. If not, see http:**www.gnu.org/licenses/
|
||||
**
|
||||
** Loosely based on the JDoom sky and the ZDoomGL 0.66.2 sky.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolySkySetup
|
||||
{
|
||||
public:
|
||||
void Update();
|
||||
|
||||
bool operator==(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) == 0; }
|
||||
bool operator!=(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) != 0; }
|
||||
|
||||
FSoftwareTexture *frontskytex = nullptr;
|
||||
FSoftwareTexture *backskytex = nullptr;
|
||||
bool skyflip = 0;
|
||||
int frontpos = 0;
|
||||
int backpos = 0;
|
||||
fixed_t frontcyl = 0;
|
||||
fixed_t backcyl = 0;
|
||||
double skymid = 0.0;
|
||||
angle_t skyangle = 0;
|
||||
};
|
||||
|
||||
class PolySkyDome
|
||||
{
|
||||
public:
|
||||
PolySkyDome();
|
||||
void Render(PolyRenderThread *thread, const Mat4f &worldToView, const Mat4f &worldToClip);
|
||||
|
||||
private:
|
||||
TArray<FVector2> mInitialUV;
|
||||
TArray<TriVertex> mVertices;
|
||||
TArray<unsigned int> mPrimStart;
|
||||
int mRows, mColumns;
|
||||
|
||||
void SkyVertex(int r, int c, bool yflip);
|
||||
void CreateSkyHemisphere(bool zflip);
|
||||
void CreateDome();
|
||||
void RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex);
|
||||
void RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap);
|
||||
|
||||
TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0);
|
||||
|
||||
Mat4f GLSkyMath();
|
||||
|
||||
PolySkySetup mCurrentSetup;
|
||||
};
|
|
@ -1,432 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_sprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "polyrenderer/scene/poly_model.h"
|
||||
#include "r_data/r_vanillatrans.h"
|
||||
#include "actorinlines.h"
|
||||
|
||||
EXTERN_CVAR(Float, transsouls)
|
||||
EXTERN_CVAR(Int, r_drawfuzz)
|
||||
EXTERN_CVAR (Bool, r_debug_disable_vis_filter)
|
||||
EXTERN_CVAR(Int, gl_spriteclip)
|
||||
EXTERN_CVAR(Float, gl_sclipthreshold)
|
||||
EXTERN_CVAR(Float, gl_sclipfactor)
|
||||
|
||||
extern uint32_t r_renderercaps;
|
||||
extern double model_distance_cull;
|
||||
|
||||
bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return false;
|
||||
|
||||
DVector2 spriteScale = thing->Scale;
|
||||
double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
double thingyscalemul = spriteScale.Y / tex->GetScale().Y;
|
||||
|
||||
double spriteWidth = thingxscalemul * tex->GetWidth();
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
double offsetX;
|
||||
if (flipTextureX)
|
||||
offsetX = (tex->GetWidth() - tex->GetLeftOffsetPo()) * thingxscalemul;
|
||||
else
|
||||
offsetX = tex->GetLeftOffsetPo() * thingxscalemul;
|
||||
|
||||
left = DVector2(pos.X - viewpoint.Sin * offsetX, pos.Y + viewpoint.Cos * offsetX);
|
||||
right = DVector2(left.X + viewpoint.Sin * spriteWidth, left.Y - viewpoint.Cos * spriteWidth);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderPolySprite::Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2)
|
||||
{
|
||||
if (r_modelscene)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
int spritenum = thing->sprite;
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
FSpriteModelFrame *modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe && (thing->Pos() - viewpoint.Pos).LengthSquared() < model_distance_cull)
|
||||
{
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
PolyRenderModel(thread, PolyRenderer::Instance()->Scene.CurrentViewpoint->WorldToClip, stencilValue, (float)pos.X, (float)pos.Y, (float)pos.Z, modelframe, thing);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DVector2 line[2];
|
||||
if (!GetLine(thing, line[0], line[1]))
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 thingpos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
|
||||
double posZ = thingpos.Z;
|
||||
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
|
||||
if (spritetype == RF_FACESPRITE)
|
||||
posZ -= thing->Floorclip;
|
||||
|
||||
if (thing->flags2 & MF2_FLOATBOB)
|
||||
posZ += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return;
|
||||
|
||||
double thingyscalemul = thing->Scale.Y / tex->GetScale().Y;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
posZ -= (tex->GetHeight() - tex->GetTopOffsetPo()) * thingyscalemul;
|
||||
posZ = PerformSpriteClipAdjustment(thing, thingpos, spriteHeight, posZ);
|
||||
|
||||
//double depth = 1.0;
|
||||
//visstyle_t visstyle = GetSpriteVisStyle(thing, depth);
|
||||
// Rumor has it that AlterWeaponSprite needs to be called with visstyle passed in somewhere around here..
|
||||
//R_SetColorMapLight(visstyle.BaseColormap, 0, visstyle.ColormapNum << FRACBITS);
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ t1, 1.0f },
|
||||
{ t2, 1.0f },
|
||||
{ t2, 0.0f },
|
||||
{ t1, 0.0f },
|
||||
};
|
||||
|
||||
DVector2 points[2] =
|
||||
{
|
||||
line[0] * (1.0 - t1) + line[1] * t1,
|
||||
line[0] * (1.0 - t2) + line[1] * t2
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(posZ + spriteHeight * offsets[i].second);
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)offsets[i].first;
|
||||
vertices[i].v = (float)(1.0f - offsets[i].second);
|
||||
if (flipTextureX)
|
||||
vertices[i].u = 1.0f - vertices[i].u;
|
||||
}
|
||||
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
SetDynlight(thing, args);
|
||||
auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], nc), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite); args.SetStencilTestValue(stencilValue);
|
||||
if ((thing->renderflags & RF_ZDOOMTRANS) && r_UseVanillaTransparency)
|
||||
args.SetStyle(LegacyRenderStyles[STYLE_Normal], 1.0f, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
else
|
||||
args.SetStyle(thing->RenderStyle, thing->Alpha, thing->fillcolor, thing->Translation, tex, fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double floorh = ff->top.plane->ZatPoint(thingpos);
|
||||
if (floorh == thing->floorz)
|
||||
return floorh;
|
||||
}
|
||||
|
||||
if (thing->Sector->GetHeightSec())
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->floorz == thing->Sector->heightsec->floorplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->floorz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->floorplane.ZatPoint(thing) - thing->Floorclip;
|
||||
}
|
||||
|
||||
double RenderPolySprite::GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos)
|
||||
{
|
||||
extsector_t::xfloor &x = thing->Sector->e->XFloor;
|
||||
for (unsigned int i = 0; i < x.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *ff = x.ffloors[i];
|
||||
double ceilingh = ff->bottom.plane->ZatPoint(thingpos);
|
||||
if (ceilingh == thing->ceilingz)
|
||||
return ceilingh;
|
||||
}
|
||||
|
||||
if (thing->Sector->GetHeightSec())
|
||||
{
|
||||
if (thing->flags2&MF2_ONMOBJ && thing->ceilingz == thing->Sector->heightsec->ceilingplane.ZatPoint(thingpos))
|
||||
{
|
||||
return thing->ceilingz;
|
||||
}
|
||||
}
|
||||
|
||||
return thing->Sector->ceilingplane.ZatPoint(thingpos);
|
||||
}
|
||||
|
||||
double RenderPolySprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z2)
|
||||
{
|
||||
int spriteclip = 2; // gl_spriteclip, but use 'always' mode for now
|
||||
|
||||
double z1 = z2 + spriteheight;
|
||||
|
||||
// Tests show that this doesn't look good for many decorations and corpses
|
||||
uint32_t spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
|
||||
if (!(spriteheight > 0 && spriteclip > 0 && spritetype == RF_FACESPRITE))
|
||||
return z2;
|
||||
|
||||
bool clipthing = (thing->player || thing->flags3&MF3_ISMONSTER || thing->IsKindOf(NAME_Inventory)) && (thing->flags&MF_ICECORPSE || !(thing->flags&MF_CORPSE));
|
||||
bool smarterclip = !clipthing && spriteclip == 3;
|
||||
if (clipthing || spriteclip > 1)
|
||||
{
|
||||
double diffb = MIN(z2 - GetSpriteFloorZ(thing, thingpos), 0.0);
|
||||
|
||||
// Adjust sprites clipping into ceiling and adjust clipping adjustment for tall graphics
|
||||
if (smarterclip)
|
||||
{
|
||||
// Reduce slightly clipping adjustment of corpses
|
||||
if (thing->flags & MF_CORPSE || spriteheight > fabs(diffb))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(diffb) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
diffb *= ratio;
|
||||
}
|
||||
if (!diffb)
|
||||
{
|
||||
double difft = MAX(z1 - GetSpriteCeilingZ(thing, thingpos), 0.0);
|
||||
if (difft >= (double)gl_sclipthreshold)
|
||||
{
|
||||
// dumb copy of the above.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || difft > (double)gl_sclipthreshold)
|
||||
{
|
||||
difft = 0;
|
||||
}
|
||||
}
|
||||
if (spriteheight > fabs(difft))
|
||||
{
|
||||
double ratio = clamp<double>((fabs(difft) * (double)gl_sclipfactor / (spriteheight + 1)), 0.5, 1.0);
|
||||
difft *= ratio;
|
||||
}
|
||||
z2 -= difft;
|
||||
}
|
||||
}
|
||||
if (diffb <= (0 - (double)gl_sclipthreshold)) // such a large displacement can't be correct!
|
||||
{
|
||||
// for living monsters standing on the floor allow a little more.
|
||||
if (!(thing->flags3&MF3_ISMONSTER) || (thing->flags&MF_NOGRAVITY) || (thing->flags&MF_CORPSE) || diffb < (-1.8*(double)gl_sclipthreshold))
|
||||
{
|
||||
diffb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
z2 -= diffb;
|
||||
}
|
||||
return z2;
|
||||
}
|
||||
|
||||
bool RenderPolySprite::IsThingCulled(AActor *thing)
|
||||
{
|
||||
FIntCVar *cvar = thing->GetInfo()->distancecheck;
|
||||
if (cvar != nullptr && *cvar >= 0)
|
||||
{
|
||||
double dist = (thing->Pos() - PolyRenderer::Instance()->Viewpoint.Pos).LengthSquared();
|
||||
double check = (double)**cvar;
|
||||
if (dist >= check * check)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't waste time projecting sprites that are definitely not visible.
|
||||
if (thing == nullptr ||
|
||||
(thing->renderflags & RF_INVISIBLE) ||
|
||||
!thing->RenderStyle.IsVisible(thing->Alpha) ||
|
||||
!thing->IsVisibleToPlayer())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check renderrequired vs ~r_rendercaps, if anything matches we don't support that feature,
|
||||
// check renderhidden vs r_rendercaps, if anything matches we do support that feature and should hide it.
|
||||
if ((!r_debug_disable_vis_filter && !!(thing->RenderRequired & ~r_renderercaps)) ||
|
||||
(!!(thing->RenderHidden & r_renderercaps)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
FSoftwareTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX)
|
||||
{
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
flipX = false;
|
||||
|
||||
if (thing->renderflags & RF_FLATSPRITE)
|
||||
return nullptr; // do not draw flat sprites.
|
||||
|
||||
if (thing->picnum.isValid())
|
||||
{
|
||||
FTexture *ttex = TexMan.GetPalettedTexture(thing->picnum, true);
|
||||
if (!ttex || !ttex->isValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
|
||||
if (ttex->GetRotations() != 0xFFFF)
|
||||
{
|
||||
// choose a different rotation based on player view
|
||||
spriteframe_t *sprframe = &SpriteFrames[ttex->GetRotations()];
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
DAngle ang = (pos - viewpoint.Pos).Angle();
|
||||
angle_t rot;
|
||||
if (sprframe->Texture[0] == sprframe->Texture[1])
|
||||
{
|
||||
rot = (ang - thing->Angles.Yaw + 45.0 / 2 * 9).BAMs() >> 28;
|
||||
}
|
||||
else
|
||||
{
|
||||
rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
|
||||
}
|
||||
flipX = (sprframe->Flip & (1 << rot)) != 0;
|
||||
ttex = TexMan.GetPalettedTexture(sprframe->Texture[rot], false); // Do not animate the rotation
|
||||
tex = ttex->GetSoftwareTexture();
|
||||
if (!ttex || !ttex->isValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FSoftwareTexture *tex = ttex->GetSoftwareTexture();
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// decide which texture to use for the sprite
|
||||
int spritenum = thing->sprite;
|
||||
if (spritenum >= (signed)sprites.Size() || spritenum < 0)
|
||||
return nullptr;
|
||||
|
||||
spritedef_t *sprdef = &sprites[spritenum];
|
||||
if (thing->frame >= sprdef->numframes)
|
||||
{
|
||||
// If there are no frames at all for this sprite, don't draw it.
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
|
||||
// choose a different rotation based on player view
|
||||
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
DAngle ang = (pos - viewpoint.Pos).Angle();
|
||||
|
||||
DAngle sprangle = thing->GetSpriteAngle((pos - viewpoint.Pos).Angle(), viewpoint.TicFrac);
|
||||
FTextureID tex = sprdef->GetSpriteFrame(thing->frame, -1, sprangle, &flipX);
|
||||
if (!tex.isValid()) return nullptr;
|
||||
return TexMan.GetPalettedTexture(tex, false)->GetSoftwareTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolySprite::SetDynlight(AActor *thing, PolyDrawArgs &args)
|
||||
{
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
if (fullbrightSprite || !r_dynlights)
|
||||
{
|
||||
args.SetDynLightColor(0);
|
||||
return;
|
||||
}
|
||||
|
||||
float lit_red = 0;
|
||||
float lit_green = 0;
|
||||
float lit_blue = 0;
|
||||
auto node = thing->section->lighthead;
|
||||
while (node != nullptr)
|
||||
{
|
||||
FDynamicLight *light = node->lightsource;
|
||||
if (light->ShouldLightActor(thing))
|
||||
{
|
||||
float lx = (float)(light->X() - thing->X());
|
||||
float ly = (float)(light->Y() - thing->Y());
|
||||
float lz = (float)(light->Z() - thing->Center());
|
||||
float LdotL = lx * lx + ly * ly + lz * lz;
|
||||
float radius = node->lightsource->GetRadius();
|
||||
if (radius * radius >= LdotL)
|
||||
{
|
||||
float distance = sqrt(LdotL);
|
||||
float attenuation = 1.0f - distance / radius;
|
||||
if (attenuation > 0.0f)
|
||||
{
|
||||
float red = light->GetRed() * (1.0f / 255.0f);
|
||||
float green = light->GetGreen() * (1.0f / 255.0f);
|
||||
float blue = light->GetBlue() * (1.0f / 255.0f);
|
||||
/*if (light->IsSubtractive())
|
||||
{
|
||||
float bright = FVector3(lr, lg, lb).Length();
|
||||
FVector3 lightColor(lr, lg, lb);
|
||||
red = (bright - lr) * -1;
|
||||
green = (bright - lg) * -1;
|
||||
blue = (bright - lb) * -1;
|
||||
}*/
|
||||
|
||||
lit_red += red * attenuation;
|
||||
lit_green += green * attenuation;
|
||||
lit_blue += blue * attenuation;
|
||||
}
|
||||
}
|
||||
}
|
||||
node = node->nextLight;
|
||||
}
|
||||
lit_red = clamp(lit_red * 255.0f, 0.0f, 255.0f);
|
||||
lit_green = clamp(lit_green * 255.0f, 0.0f, 255.0f);
|
||||
lit_blue = clamp(lit_blue * 255.0f, 0.0f, 255.0f);
|
||||
args.SetDynLightColor((((uint32_t)lit_red) << 16) | (((uint32_t)lit_green) << 8) | ((uint32_t)lit_blue));
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolySprite
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue, float t1, float t2);
|
||||
|
||||
static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right);
|
||||
static bool IsThingCulled(AActor *thing);
|
||||
static FSoftwareTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX);
|
||||
|
||||
private:
|
||||
static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z);
|
||||
static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos);
|
||||
static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos);
|
||||
static void SetDynlight(AActor *thing, PolyDrawArgs &args);
|
||||
};
|
||||
|
||||
class PolyTranslucentThing : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentThing(AActor *thing, subsector_t *sub, uint32_t subsectorDepth, double dist, float t1, float t2, uint32_t stencilValue) : PolyTranslucentObject(subsectorDepth, dist), thing(thing), sub(sub), SpriteLeft(t1), SpriteRight(t2), StencilValue(stencilValue) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
if ((thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
|
||||
{
|
||||
RenderPolyWallSprite wallspr;
|
||||
wallspr.Render(thread, thing, sub, StencilValue + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderPolySprite spr;
|
||||
spr.Render(thread, thing, sub, StencilValue + 1, SpriteLeft, SpriteRight);
|
||||
}
|
||||
}
|
||||
|
||||
AActor *thing = nullptr;
|
||||
subsector_t *sub = nullptr;
|
||||
float SpriteLeft = 0.0f;
|
||||
float SpriteRight = 1.0f;
|
||||
uint32_t StencilValue = 0;
|
||||
};
|
|
@ -1,721 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
#include "doomdata.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_wall.h"
|
||||
#include "poly_decal.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "a_dynlight.h"
|
||||
|
||||
EXTERN_CVAR(Bool, r_drawmirrors)
|
||||
EXTERN_CVAR(Bool, r_fogboundary)
|
||||
|
||||
bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, size_t linePortalsStart, line_t *portalEnterLine)
|
||||
{
|
||||
double frontceilz1 = frontsector->ceilingplane.ZatPoint(line->v1);
|
||||
double frontfloorz1 = frontsector->floorplane.ZatPoint(line->v1);
|
||||
double frontceilz2 = frontsector->ceilingplane.ZatPoint(line->v2);
|
||||
double frontfloorz2 = frontsector->floorplane.ZatPoint(line->v2);
|
||||
double topTexZ = frontsector->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = frontsector->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
PolyDrawLinePortal *polyportal = nullptr;
|
||||
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
|
||||
{
|
||||
if (portalEnterLine == line->linedef)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(line->linedef)));
|
||||
polyportal = linePortals.back().get();
|
||||
}
|
||||
else if (line->linedef && line->linedef->isVisualPortal() && line->sidedef == line->linedef->sidedef[0])
|
||||
{
|
||||
if (portalEnterLine == line->linedef)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FLinePortal *portal = line->linedef->getPortal();
|
||||
for (size_t i = linePortalsStart; i < linePortals.size(); i++)
|
||||
{
|
||||
if (linePortals[i]->Portal == portal) // To do: what other criteria do we need to check for?
|
||||
{
|
||||
polyportal = linePortals[i].get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!polyportal)
|
||||
{
|
||||
linePortals.push_back(std::unique_ptr<PolyDrawLinePortal>(new PolyDrawLinePortal(portal)));
|
||||
polyportal = linePortals.back().get();
|
||||
}
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
wall.LineSeg = line;
|
||||
wall.Line = line->linedef;
|
||||
wall.Side = line->sidedef;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Masked = false;
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
wall.StencilValue = stencilValue;
|
||||
wall.SectorLightLevel = frontsector->lightlevel;
|
||||
|
||||
if (line->backsector == nullptr)
|
||||
{
|
||||
if (line->sidedef)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(thread);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (line->PartnerSeg && line->PartnerSeg->Subsector)
|
||||
{
|
||||
PolyTransferHeights fakeback(line->PartnerSeg->Subsector);
|
||||
sector_t *backsector = fakeback.FrontSector;
|
||||
|
||||
double backceilz1 = backsector->ceilingplane.ZatPoint(line->v1);
|
||||
double backfloorz1 = backsector->floorplane.ZatPoint(line->v1);
|
||||
double backceilz2 = backsector->ceilingplane.ZatPoint(line->v2);
|
||||
double backfloorz2 = backsector->floorplane.ZatPoint(line->v2);
|
||||
|
||||
double topceilz1 = frontceilz1;
|
||||
double topceilz2 = frontceilz2;
|
||||
double topfloorz1 = MAX(MIN(backceilz1, frontceilz1), frontfloorz1);
|
||||
double topfloorz2 = MAX(MIN(backceilz2, frontceilz2), frontfloorz2);
|
||||
double bottomceilz1 = MIN(MAX(frontfloorz1, backfloorz1), frontceilz1);
|
||||
double bottomceilz2 = MIN(MAX(frontfloorz2, backfloorz2), frontceilz2);
|
||||
double bottomfloorz1 = frontfloorz1;
|
||||
double bottomfloorz2 = frontfloorz2;
|
||||
double middleceilz1 = topfloorz1;
|
||||
double middleceilz2 = topfloorz2;
|
||||
double middlefloorz1 = MIN(bottomceilz1, middleceilz1);
|
||||
double middlefloorz2 = MIN(bottomceilz2, middleceilz2);
|
||||
|
||||
bool bothSkyCeiling = frontsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum;
|
||||
bool bothSkyFloor = frontsector->GetTexture(sector_t::floor) == skyflatnum && backsector->GetTexture(sector_t::floor) == skyflatnum;
|
||||
|
||||
if ((topceilz1 > topfloorz1 || topceilz2 > topfloorz2) && line->sidedef && !bothSkyCeiling)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), topceilz1, topfloorz1, topceilz2, topfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = MIN(MIN(backceilz1, frontceilz1), MIN(backceilz2, frontceilz2));
|
||||
wall.Wallpart = side_t::top;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::top);
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
if ((bottomfloorz1 < bottomceilz1 || bottomfloorz2 < bottomceilz2) && line->sidedef && !bothSkyFloor)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), bottomceilz1, bottomfloorz1, bottomceilz2, bottomfloorz2);
|
||||
wall.TopTexZ = MAX(MAX(frontfloorz1, backfloorz1), MAX(frontfloorz2, backfloorz2));
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.UnpeggedCeil1 = topceilz1;
|
||||
wall.UnpeggedCeil2 = topceilz2;
|
||||
wall.Wallpart = side_t::bottom;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::bottom);
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
if (line->sidedef)
|
||||
{
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), middleceilz1, middlefloorz1, middleceilz2, middlefloorz2);
|
||||
wall.TopTexZ = MAX(middleceilz1, middleceilz2);
|
||||
wall.BottomTexZ = MIN(middlefloorz1, middlefloorz2);
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
wall.Masked = true;
|
||||
wall.Additive = !!(wall.Line->flags & ML_ADDTRANS);
|
||||
wall.Alpha = wall.Line->alpha;
|
||||
wall.FogBoundary = IsFogBoundary(frontsector, backsector);
|
||||
|
||||
FTexture *midtex = TexMan.GetPalettedTexture(line->sidedef->GetTexture(side_t::mid), true);
|
||||
if ((midtex && midtex->isValid()) || wall.FogBoundary)
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
|
||||
if (polyportal)
|
||||
{
|
||||
wall.Polyportal = polyportal;
|
||||
wall.Render(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
return polyportal != nullptr;
|
||||
}
|
||||
|
||||
bool RenderPolyWall::IsFogBoundary(sector_t *front, sector_t *back)
|
||||
{
|
||||
return r_fogboundary && PolyCameraLight::Instance()->FixedColormap() == nullptr && front->Colormap.FadeColor &&
|
||||
front->Colormap.FadeColor != back->Colormap.FadeColor &&
|
||||
(front->GetTexture(sector_t::ceiling) != skyflatnum || back->GetTexture(sector_t::ceiling) != skyflatnum);
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render3DFloorLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
|
||||
{
|
||||
if (!(fakeFloor->flags & FF_EXISTS)) return;
|
||||
if (!(fakeFloor->flags & FF_RENDERPLANES)) return;
|
||||
if (!fakeFloor->model) return;
|
||||
if (fakeFloor->alpha == 0) return;
|
||||
|
||||
double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
|
||||
double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);
|
||||
double frontceilz2 = fakeFloor->top.plane->ZatPoint(line->v2);
|
||||
double frontfloorz2 = fakeFloor->bottom.plane->ZatPoint(line->v2);
|
||||
double topTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::ceiling);
|
||||
double bottomTexZ = fakeFloor->model->GetPlaneTexZ(sector_t::floor);
|
||||
|
||||
if (frontceilz1 <= frontfloorz1 || frontceilz2 <= frontfloorz2)
|
||||
return;
|
||||
|
||||
if (fakeFloor->flags & FF_SWIMMABLE) // Only draw swimmable boundary if not swimmable on both sides
|
||||
{
|
||||
DVector2 c = (line->v1->fPos() + line->v2->fPos()) * 0.5;
|
||||
double cz = (frontceilz1 + frontceilz2 + frontfloorz1 + frontfloorz2) * 0.25;
|
||||
for (unsigned i = 0; i < frontsector->e->XFloor.ffloors.Size(); i++)
|
||||
{
|
||||
F3DFloor *frontFloor = frontsector->e->XFloor.ffloors[i];
|
||||
if (!(frontFloor->flags & FF_EXISTS)) continue;
|
||||
if (!(frontFloor->flags & FF_RENDERPLANES)) continue;
|
||||
if (!frontFloor->model) continue;
|
||||
if (frontFloor->alpha == 0) continue;
|
||||
if (frontFloor->top.plane->ZatPoint(c) >= cz && frontFloor->bottom.plane->ZatPoint(c) <= cz && (frontFloor->flags & FF_SWIMMABLE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
wall.LineSeg = line;
|
||||
wall.LineSegLine = line->linedef;
|
||||
wall.Line = fakeFloor->master;
|
||||
wall.Side = fakeFloor->master->sidedef[0];
|
||||
wall.Additive = !!(fakeFloor->flags & FF_ADDITIVETRANS);
|
||||
if (!wall.Additive && fakeFloor->alpha == 255)
|
||||
{
|
||||
wall.Masked = false;
|
||||
wall.Alpha = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wall.Masked = true;
|
||||
wall.Alpha = fakeFloor->alpha / 255.0;
|
||||
}
|
||||
wall.SubsectorDepth = subsectorDepth;
|
||||
wall.StencilValue = stencilValue;
|
||||
wall.SetCoords(line->v1->fPos(), line->v2->fPos(), frontceilz1, frontfloorz1, frontceilz2, frontfloorz2);
|
||||
wall.TopTexZ = topTexZ;
|
||||
wall.BottomTexZ = bottomTexZ;
|
||||
wall.Wallpart = side_t::mid;
|
||||
wall.Colormap = GetColorTable(frontsector->Colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
if (fakeFloor->flags & FF_UPPERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::top);
|
||||
else if (fakeFloor->flags & FF_LOWERTEXTURE)
|
||||
wall.Texture = GetTexture(line->linedef, line->sidedef, side_t::bottom);
|
||||
else
|
||||
wall.Texture = GetTexture(wall.Line, wall.Side, side_t::mid);
|
||||
|
||||
if (frontsector->e->XFloor.lightlist.Size())
|
||||
{
|
||||
lightlist_t *light = P_GetPlaneLight(frontsector, fakeFloor->top.plane, true);
|
||||
wall.Colormap = GetColorTable(light->extra_colormap, wall.Side->GetSpecialColor(wall.Wallpart, side_t::walltop, frontsector));
|
||||
wall.SectorLightLevel = *light->p_lightlevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
wall.SectorLightLevel = frontsector->lightlevel;
|
||||
}
|
||||
|
||||
if (!wall.Masked)
|
||||
wall.Render(thread);
|
||||
else
|
||||
translucentWallsOutput.push_back(thread->FrameMemory->NewObject<PolyTranslucentWall>(wall));
|
||||
}
|
||||
|
||||
void RenderPolyWall::SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2)
|
||||
{
|
||||
this->v1 = v1;
|
||||
this->v2 = v2;
|
||||
this->ceil1 = ceil1;
|
||||
this->floor1 = floor1;
|
||||
this->ceil2 = ceil2;
|
||||
this->floor2 = floor2;
|
||||
}
|
||||
|
||||
void RenderPolyWall::Render(PolyRenderThread *thread)
|
||||
{
|
||||
bool foggy = false;
|
||||
if (!Texture && !Polyportal && !FogBoundary)
|
||||
return;
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
vertices[0].x = (float)v1.X;
|
||||
vertices[0].y = (float)v1.Y;
|
||||
vertices[0].z = (float)ceil1;
|
||||
vertices[0].w = 1.0f;
|
||||
|
||||
vertices[1].x = (float)v2.X;
|
||||
vertices[1].y = (float)v2.Y;
|
||||
vertices[1].z = (float)ceil2;
|
||||
vertices[1].w = 1.0f;
|
||||
|
||||
vertices[2].x = (float)v2.X;
|
||||
vertices[2].y = (float)v2.Y;
|
||||
vertices[2].z = (float)floor2;
|
||||
vertices[2].w = 1.0f;
|
||||
|
||||
vertices[3].x = (float)v1.X;
|
||||
vertices[3].y = (float)v1.Y;
|
||||
vertices[3].z = (float)floor1;
|
||||
vertices[3].w = 1.0f;
|
||||
|
||||
if (Texture)
|
||||
{
|
||||
PolyWallTextureCoordsU texcoordsU(Texture, LineSeg, LineSegLine, Side, Wallpart);
|
||||
PolyWallTextureCoordsV texcoordsVLeft(Texture, Line, Side, Wallpart, ceil1, floor1, UnpeggedCeil1, TopTexZ, BottomTexZ);
|
||||
PolyWallTextureCoordsV texcoordsVRght(Texture, Line, Side, Wallpart, ceil2, floor2, UnpeggedCeil2, TopTexZ, BottomTexZ);
|
||||
vertices[0].u = (float)texcoordsU.u1;
|
||||
vertices[0].v = (float)texcoordsVLeft.v1;
|
||||
vertices[1].u = (float)texcoordsU.u2;
|
||||
vertices[1].v = (float)texcoordsVRght.v1;
|
||||
vertices[2].u = (float)texcoordsU.u2;
|
||||
vertices[2].v = (float)texcoordsVRght.v2;
|
||||
vertices[3].u = (float)texcoordsU.u1;
|
||||
vertices[3].v = (float)texcoordsVLeft.v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
vertices[i].u = 0.0f;
|
||||
vertices[i].v = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Masked walls clamp to the 0-1 range (no texture repeat)
|
||||
if (Masked)
|
||||
{
|
||||
bool wrap = (Line->flags & ML_WRAP_MIDTEX) || (Side->Flags & WALLF_WRAP_MIDTEX);
|
||||
if (!wrap)
|
||||
{
|
||||
ClampHeight(vertices[0], vertices[3]);
|
||||
ClampHeight(vertices[1], vertices[2]);
|
||||
}
|
||||
}
|
||||
|
||||
PolyDrawArgs args;
|
||||
args.SetLight(Colormap, GetLightLevel(), PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
if (Texture && !Polyportal)
|
||||
args.SetTexture(Texture, DefaultRenderStyle());
|
||||
|
||||
SetDynLights(thread, args);
|
||||
|
||||
if (FogBoundary)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue + 1);
|
||||
args.SetStyle(TriBlendMode::FogBoundary);
|
||||
args.SetColor(0xffffffff, 254);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
if (!Texture)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Polyportal)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetWriteStencil(true, Polyportal->StencilValue);
|
||||
args.SetWriteColor(false);
|
||||
args.SetWriteDepth(false);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
Polyportal->Shape.push_back({ vertices, 4 });
|
||||
}
|
||||
else if (!Masked)
|
||||
{
|
||||
args.SetStencilTestValue(StencilValue);
|
||||
args.SetWriteStencil(true, StencilValue + 1);
|
||||
args.SetStyle(TriBlendMode::Opaque);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
else
|
||||
{
|
||||
double a = MIN(Alpha, 1.0);
|
||||
if (Additive)
|
||||
args.SetStyle(TriBlendMode::Add, a);
|
||||
else if (a < 1.0)
|
||||
args.SetStyle(TriBlendMode::Translucent, a);
|
||||
else
|
||||
args.SetStyle(TriBlendMode::Normal);
|
||||
|
||||
args.SetStencilTestValue(StencilValue + 1);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(true);
|
||||
args.SetWriteStencil(false);
|
||||
DrawStripes(thread, args, vertices);
|
||||
}
|
||||
|
||||
RenderPolyDecal::RenderWallDecals(thread, LineSeg, StencilValue + 1);
|
||||
}
|
||||
|
||||
void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args)
|
||||
{
|
||||
if (!r_dynlights)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
FLightNode *light_list = (LineSeg && LineSeg->sidedef) ? LineSeg->sidedef->lighthead : nullptr;
|
||||
|
||||
auto cameraLight = PolyCameraLight::Instance();
|
||||
if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr))
|
||||
{
|
||||
args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate max lights that can touch the wall so we can allocate memory for the list
|
||||
int max_lights = 0;
|
||||
FLightNode *cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
max_lights++;
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
if (max_lights == 0)
|
||||
{
|
||||
args.SetLights(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int dc_num_lights = 0;
|
||||
PolyLight *dc_lights = thread->FrameMemory->AllocMemory<PolyLight>(max_lights);
|
||||
|
||||
// Setup lights
|
||||
cur_node = light_list;
|
||||
while (cur_node)
|
||||
{
|
||||
if (cur_node->lightsource->IsActive())
|
||||
{
|
||||
bool is_point_light = cur_node->lightsource->IsAttenuated();
|
||||
|
||||
// To do: cull lights not touching wall
|
||||
|
||||
uint32_t red = cur_node->lightsource->GetRed();
|
||||
uint32_t green = cur_node->lightsource->GetGreen();
|
||||
uint32_t blue = cur_node->lightsource->GetBlue();
|
||||
|
||||
auto &light = dc_lights[dc_num_lights++];
|
||||
light.x = (float)cur_node->lightsource->X();
|
||||
light.y = (float)cur_node->lightsource->Y();
|
||||
light.z = (float)cur_node->lightsource->Z();
|
||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||
light.color = (red << 16) | (green << 8) | blue;
|
||||
if (is_point_light)
|
||||
light.radius = -light.radius;
|
||||
}
|
||||
|
||||
cur_node = cur_node->nextLight;
|
||||
}
|
||||
|
||||
args.SetLights(dc_lights, dc_num_lights);
|
||||
|
||||
// Face normal:
|
||||
float dx = (float)(v2.X - v1.X);
|
||||
float dy = (float)(v2.Y - v1.Y);
|
||||
float nx = dy;
|
||||
float ny = -dx;
|
||||
float lensqr = nx * nx + ny * ny;
|
||||
float rcplen = 1.0f / sqrt(lensqr);
|
||||
nx *= rcplen;
|
||||
ny *= rcplen;
|
||||
args.SetNormal({ nx, ny, 0.0f });
|
||||
}
|
||||
|
||||
void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices)
|
||||
{
|
||||
const auto &lightlist = Line->frontsector->e->XFloor.lightlist;
|
||||
if (lightlist.Size() > 0)
|
||||
{
|
||||
PolyClipPlane topPlane;
|
||||
|
||||
for (unsigned int i = 0; i < lightlist.Size(); i++)
|
||||
{
|
||||
lightlist_t *lit = &lightlist[i];
|
||||
|
||||
DVector3 normal = lit->plane.Normal();
|
||||
double d = lit->plane.fD();
|
||||
if (normal.Z < 0.0)
|
||||
{
|
||||
normal = -normal;
|
||||
d = -d;
|
||||
}
|
||||
|
||||
PolyClipPlane bottomPlane = { (float)normal.X, (float)normal.Y, (float)normal.Z, (float)d };
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, bottomPlane);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
|
||||
FDynamicColormap *basecolormap = GetColorTable(lit->extra_colormap, Line->frontsector->SpecialColors[sector_t::walltop]);
|
||||
|
||||
bool foggy = false;
|
||||
int lightlevel;
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
lightlevel = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
lightlevel = clamp(Side->GetLightLevel(foggy, *lit->p_lightlevel) + actualextralight, 0, 255);
|
||||
}
|
||||
args.SetLight(basecolormap, lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), false);
|
||||
|
||||
topPlane = { (float)-normal.X, (float)-normal.Y, (float)-normal.Z, (float)-d };
|
||||
}
|
||||
|
||||
args.SetClipPlane(1, topPlane);
|
||||
args.SetClipPlane(2, PolyClipPlane());
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
else
|
||||
{
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2)
|
||||
{
|
||||
float top = v1.z;
|
||||
float bottom = v2.z;
|
||||
float texv1 = v1.v;
|
||||
float texv2 = v2.v;
|
||||
float delta = (texv2 - texv1);
|
||||
|
||||
float t1 = texv1 < 0.0f ? -texv1 / delta : 0.0f;
|
||||
float t2 = texv2 > 1.0f ? (1.0f - texv1) / delta : 1.0f;
|
||||
float inv_t1 = 1.0f - t1;
|
||||
float inv_t2 = 1.0f - t2;
|
||||
|
||||
v1.z = top * inv_t1 + bottom * t1;
|
||||
v1.v = texv1 * inv_t1 + texv2 * t1;
|
||||
|
||||
v2.z = top * inv_t2 + bottom * t2;
|
||||
v2.v = texv1 * inv_t2 + texv2 * t2;
|
||||
}
|
||||
|
||||
FSoftwareTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, side_t::ETexpart texpart)
|
||||
{
|
||||
FTexture *tex = TexMan.GetPalettedTexture(side->GetTexture(texpart), true);
|
||||
if (tex == nullptr || !tex->isValid())
|
||||
{
|
||||
// Mapping error. Doom floodfills this with a plane.
|
||||
// This code doesn't do that, but at least it uses the "right" texture..
|
||||
|
||||
if (line && line->backsector && line->sidedef[0] == side)
|
||||
{
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
if (line && line->backsector && line->sidedef[1] == side)
|
||||
{
|
||||
if (texpart == side_t::top)
|
||||
tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::ceiling), true);
|
||||
else if (texpart == side_t::bottom)
|
||||
tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::floor), true);
|
||||
}
|
||||
|
||||
if (tex == nullptr || !tex->isValid())
|
||||
return nullptr;
|
||||
}
|
||||
return tex? tex->GetSoftwareTexture() : nullptr;
|
||||
}
|
||||
|
||||
int RenderPolyWall::GetLightLevel()
|
||||
{
|
||||
PolyCameraLight *cameraLight = PolyCameraLight::Instance();
|
||||
if (cameraLight->FixedLightLevel() >= 0 || cameraLight->FixedColormap())
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
return clamp(Side->GetLightLevel(foggy, SectorLightLevel) + actualextralight, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsU::PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart wallpart)
|
||||
{
|
||||
// Calculate the U texture coordinate for the line
|
||||
double lineu1 = side->GetTextureXOffset(wallpart);
|
||||
double lineu2 = side->GetTextureXOffset(wallpart) + line->sidedef[0]->TexelLength * side->GetTextureXScale(wallpart);
|
||||
lineu1 *= tex->GetScale().X / tex->GetWidth();
|
||||
lineu2 *= tex->GetScale().X / tex->GetWidth();
|
||||
|
||||
// Calculate where we are on the lineseg
|
||||
double t1, t2;
|
||||
if (fabs(line->delta.X) > fabs(line->delta.Y))
|
||||
{
|
||||
t1 = (lineseg->v1->fX() - line->v1->fX()) / line->delta.X;
|
||||
t2 = (lineseg->v2->fX() - line->v1->fX()) / line->delta.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
t1 = (lineseg->v1->fY() - line->v1->fY()) / line->delta.Y;
|
||||
t2 = (lineseg->v2->fY() - line->v1->fY()) / line->delta.Y;
|
||||
}
|
||||
|
||||
// Check if lineseg is the backside of the line
|
||||
if (t2 < t1)
|
||||
{
|
||||
std::swap(lineu1, lineu2);
|
||||
}
|
||||
|
||||
// Calculate texture coordinates for the lineseg
|
||||
u1 = (1.0 - t1) * lineu1 + t1 * lineu2;
|
||||
u2 = (1.0 - t2) * lineu1 + t2 * lineu2;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PolyWallTextureCoordsV::PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ)
|
||||
{
|
||||
double yoffset = side->GetTextureYOffset(wallpart);
|
||||
if (tex->useWorldPanning(line->GetLevel()))
|
||||
yoffset *= side->GetTextureYScale(wallpart) * tex->GetScale().Y;
|
||||
|
||||
switch (wallpart)
|
||||
{
|
||||
default:
|
||||
case side_t::mid:
|
||||
CalcVMidPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::top:
|
||||
CalcVTopPart(tex, line, side, topTexZ, bottomTexZ, yoffset);
|
||||
break;
|
||||
case side_t::bottom:
|
||||
CalcVBottomPart(tex, line, side, topTexZ, bottomTexZ, unpeggedceil, yoffset);
|
||||
break;
|
||||
}
|
||||
|
||||
v1 *= tex->GetScale().Y / tex->GetHeight();
|
||||
v2 *= tex->GetScale().Y / tex->GetHeight();
|
||||
|
||||
double texZHeight = (bottomTexZ - topTexZ);
|
||||
if (texZHeight > 0.0f || texZHeight < -0.0f)
|
||||
{
|
||||
double t1 = (topz - topTexZ) / texZHeight;
|
||||
double t2 = (bottomz - topTexZ) / texZHeight;
|
||||
double vorig1 = v1;
|
||||
double vorig2 = v2;
|
||||
v1 = vorig1 * (1.0f - t1) + vorig2 * t1;
|
||||
v2 = vorig1 * (1.0f - t2) + vorig2 * t2;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGTOP) == 0;
|
||||
if (pegged) // bottom to top
|
||||
{
|
||||
double texHeight = tex->GetHeight() / tex->GetScale().Y;
|
||||
v1 = (topz - bottomz) * side->GetTextureYScale(side_t::top) - yoffset;
|
||||
v2 = -yoffset;
|
||||
v1 = texHeight - v1;
|
||||
v2 = texHeight - v2;
|
||||
}
|
||||
else // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::top) + yoffset;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = (topz - bottomz) * side->GetTextureYScale(side_t::mid) + yoffset;
|
||||
}
|
||||
else // bottom to top
|
||||
{
|
||||
double texHeight = tex->GetHeight() / tex->GetScale().Y;
|
||||
v1 = yoffset - (topz - bottomz) * side->GetTextureYScale(side_t::mid);
|
||||
v2 = yoffset;
|
||||
v1 = texHeight + v1;
|
||||
v2 = texHeight + v2;
|
||||
}
|
||||
}
|
||||
|
||||
void PolyWallTextureCoordsV::CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset)
|
||||
{
|
||||
bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0;
|
||||
if (pegged) // top to bottom
|
||||
{
|
||||
v1 = yoffset;
|
||||
v2 = yoffset + (topz - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
v1 = yoffset + (unpeggedceil - topz) * side->GetTextureYScale(side_t::bottom);
|
||||
v2 = yoffset + (unpeggedceil - bottomz) * side->GetTextureYScale(side_t::bottom);
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class PolyTranslucentObject;
|
||||
class PolyDrawLinePortal;
|
||||
class PolyCull;
|
||||
|
||||
class RenderPolyWall
|
||||
{
|
||||
public:
|
||||
static bool RenderLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals, size_t linePortalsStart, line_t *portalEnterLine);
|
||||
static void Render3DFloorLine(PolyRenderThread *thread, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
|
||||
|
||||
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
|
||||
void Render(PolyRenderThread *thread);
|
||||
|
||||
DVector2 v1;
|
||||
DVector2 v2;
|
||||
double ceil1 = 0.0;
|
||||
double floor1 = 0.0;
|
||||
double ceil2 = 0.0;
|
||||
double floor2 = 0.0;
|
||||
|
||||
const seg_t *LineSeg = nullptr;
|
||||
const line_t *LineSegLine = nullptr;
|
||||
const line_t *Line = nullptr;
|
||||
const side_t *Side = nullptr;
|
||||
FSoftwareTexture *Texture = nullptr;
|
||||
side_t::ETexpart Wallpart = side_t::mid;
|
||||
double TopTexZ = 0.0;
|
||||
double BottomTexZ = 0.0;
|
||||
double UnpeggedCeil1 = 0.0;
|
||||
double UnpeggedCeil2 = 0.0;
|
||||
FSWColormap *Colormap = nullptr;
|
||||
int SectorLightLevel = 0;
|
||||
bool Masked = false;
|
||||
bool Additive = false;
|
||||
double Alpha = 1.0;
|
||||
bool FogBoundary = false;
|
||||
uint32_t SubsectorDepth = 0;
|
||||
uint32_t StencilValue = 0;
|
||||
PolyDrawLinePortal *Polyportal = nullptr;
|
||||
|
||||
private:
|
||||
void ClampHeight(TriVertex &v1, TriVertex &v2);
|
||||
int GetLightLevel();
|
||||
void DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices);
|
||||
|
||||
void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args);
|
||||
|
||||
static bool IsFogBoundary(sector_t *front, sector_t *back);
|
||||
static FSoftwareTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart);
|
||||
};
|
||||
|
||||
class PolyWallTextureCoordsU
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *linesegline, const side_t *side, side_t::ETexpart wallpart);
|
||||
|
||||
double u1, u2;
|
||||
};
|
||||
|
||||
class PolyWallTextureCoordsV
|
||||
{
|
||||
public:
|
||||
PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ);
|
||||
|
||||
double v1, v2;
|
||||
|
||||
private:
|
||||
void CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset);
|
||||
void CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset);
|
||||
};
|
||||
|
||||
class PolyTranslucentWall : public PolyTranslucentObject
|
||||
{
|
||||
public:
|
||||
PolyTranslucentWall(RenderPolyWall wall) : PolyTranslucentObject(wall.SubsectorDepth, 1e6), wall(wall) { }
|
||||
|
||||
void Render(PolyRenderThread *thread) override
|
||||
{
|
||||
wall.Render(thread);
|
||||
}
|
||||
|
||||
RenderPolyWall wall;
|
||||
};
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "templates.h"
|
||||
#include "doomdef.h"
|
||||
#include "sbar.h"
|
||||
#include "r_data/r_translate.h"
|
||||
#include "poly_wallsprite.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "polyrenderer/scene/poly_light.h"
|
||||
#include "polyrenderer/poly_renderthread.h"
|
||||
|
||||
void RenderPolyWallSprite::Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
if (RenderPolySprite::IsThingCulled(thing))
|
||||
return;
|
||||
|
||||
const auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac);
|
||||
pos.Z += thing->GetBobOffset(viewpoint.TicFrac);
|
||||
|
||||
bool flipTextureX = false;
|
||||
FSoftwareTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX);
|
||||
if (tex == nullptr)
|
||||
return;
|
||||
|
||||
DVector2 spriteScale = thing->Scale;
|
||||
double thingxscalemul = spriteScale.X / tex->GetScale().X;
|
||||
double thingyscalemul = spriteScale.Y / tex->GetScale().Y;
|
||||
double spriteHeight = thingyscalemul * tex->GetHeight();
|
||||
|
||||
DAngle ang = thing->Angles.Yaw + 90;
|
||||
double angcos = ang.Cos();
|
||||
double angsin = ang.Sin();
|
||||
|
||||
// Determine left and right edges of sprite. The sprite's angle is its normal,
|
||||
// so the edges are 90 degrees each side of it.
|
||||
double x2 = tex->GetScaledWidth() * spriteScale.X;
|
||||
double x1 = tex->GetScaledLeftOffsetPo() * spriteScale.X;
|
||||
DVector2 left, right;
|
||||
left.X = pos.X - x1 * angcos;
|
||||
left.Y = pos.Y - x1 * angsin;
|
||||
right.X = left.X + x2 * angcos;
|
||||
right.Y = left.Y + x2 * angsin;
|
||||
|
||||
//int scaled_to = tex->GetScaledTopOffset();
|
||||
//int scaled_bo = scaled_to - tex->GetScaledHeight();
|
||||
//gzt = pos.Z + scale.Y * scaled_to;
|
||||
//gzb = pos.Z + scale.Y * scaled_bo;
|
||||
|
||||
DVector2 points[2] = { left, right };
|
||||
|
||||
TriVertex *vertices = thread->FrameMemory->AllocMemory<TriVertex>(4);
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : viewpoint.extralight << 4;
|
||||
|
||||
std::pair<float, float> offsets[4] =
|
||||
{
|
||||
{ 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f },
|
||||
{ 1.0f, 0.0f },
|
||||
{ 0.0f, 0.0f },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
auto &p = (i == 0 || i == 3) ? points[0] : points[1];
|
||||
|
||||
vertices[i].x = (float)p.X;
|
||||
vertices[i].y = (float)p.Y;
|
||||
vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second);
|
||||
vertices[i].w = 1.0f;
|
||||
vertices[i].u = (float)(offsets[i].first * tex->GetScale().X);
|
||||
vertices[i].v = (float)((1.0f - offsets[i].second) * tex->GetScale().Y);
|
||||
if (flipTextureX)
|
||||
vertices[i].u = 1.0f - vertices[i].u;
|
||||
}
|
||||
|
||||
bool fullbrightSprite = ((thing->renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT));
|
||||
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
|
||||
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(thing->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], nc), lightlevel, PolyRenderer::Instance()->Light.WallGlobVis(foggy), fullbrightSprite); args.SetStencilTestValue(stencilValue);
|
||||
args.SetTexture(tex, thing->RenderStyle);
|
||||
args.SetDepthTest(true);
|
||||
args.SetWriteDepth(false);
|
||||
args.SetWriteStencil(false);
|
||||
args.SetStyle(TriBlendMode::Normal);
|
||||
PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, 4, PolyDrawMode::TriangleFan);
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
** Polygon Doom software renderer
|
||||
** Copyright (c) 2016 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
|
||||
class RenderPolyWallSprite
|
||||
{
|
||||
public:
|
||||
void Render(PolyRenderThread *thread, AActor *thing, subsector_t *sub, uint32_t stencilValue);
|
||||
};
|
|
@ -51,6 +51,7 @@
|
|||
#include "r_draw_pal.h"
|
||||
#include "r_thread.h"
|
||||
#include "swrenderer/scene/r_light.h"
|
||||
#include "polyrenderer/drawers/poly_buffer.h"
|
||||
|
||||
CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, r_fuzzscale, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "r_thread.h"
|
||||
#include "swrenderer/r_memory.h"
|
||||
#include "swrenderer/r_renderthread.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include <chrono>
|
||||
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include "textures/textures.h"
|
||||
#include "r_data/voxels.h"
|
||||
#include "drawers/r_draw_rgba.h"
|
||||
#include "polyrenderer/poly_renderer.h"
|
||||
#include "p_setup.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "image.h"
|
||||
|
@ -185,22 +184,11 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &
|
|||
|
||||
void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer, int bufferpitch)
|
||||
{
|
||||
if (V_IsPolyRenderer())
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderView(player, target, videobuffer, bufferpitch);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
r_viewpoint.ViewLevel->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov)
|
||||
{
|
||||
|
@ -215,43 +203,22 @@ void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int wi
|
|||
DCanvas pic(width, height, false);
|
||||
|
||||
// Take a snapshot of the player's view
|
||||
if (V_IsPolyRenderer())
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderViewToCanvas(player->mo, &pic, 0, 0, width, height, true);
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderViewToCanvas(player->mo, &pic, 0, 0, width, height);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.RenderViewToCanvas(player->mo, &pic, 0, 0, width, height);
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
DoWriteSavePic(file, SS_PAL, pic.GetPixels(), width, height, r_viewpoint.sector, false);
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::DrawRemainingPlayerSprites()
|
||||
{
|
||||
if (!V_IsPolyRenderer())
|
||||
{
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.MainThread()->PlayerSprites->RenderRemaining();
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
|
||||
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
|
||||
PolyRenderer::Instance()->RenderRemainingPlayerSprites();
|
||||
r_viewpoint = PolyRenderer::Instance()->Viewpoint;
|
||||
r_viewwindow = PolyRenderer::Instance()->Viewwindow;
|
||||
}
|
||||
mScene.MainThread()->Viewport->viewpoint = r_viewpoint;
|
||||
mScene.MainThread()->Viewport->viewwindow = r_viewwindow;
|
||||
mScene.MainThread()->PlayerSprites->RenderRemaining();
|
||||
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
}
|
||||
|
||||
void FSoftwareRenderer::SetClearColor(int color)
|
||||
|
@ -261,9 +228,9 @@ void FSoftwareRenderer::SetClearColor(int color)
|
|||
|
||||
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewpoint, double fov)
|
||||
{
|
||||
auto renderTarget = V_IsPolyRenderer() ? PolyRenderer::Instance()->RenderTarget : mScene.MainThread()->Viewport->RenderTarget;
|
||||
auto &cameraViewpoint = V_IsPolyRenderer() ? PolyRenderer::Instance()->Viewpoint : mScene.MainThread()->Viewport->viewpoint;
|
||||
auto &cameraViewwindow = V_IsPolyRenderer() ? PolyRenderer::Instance()->Viewwindow : mScene.MainThread()->Viewport->viewwindow;
|
||||
auto renderTarget = mScene.MainThread()->Viewport->RenderTarget;
|
||||
auto &cameraViewpoint = mScene.MainThread()->Viewport->viewpoint;
|
||||
auto &cameraViewwindow = mScene.MainThread()->Viewport->viewwindow;
|
||||
|
||||
// Grab global state shared with rest of zdoom
|
||||
cameraViewpoint = r_viewpoint;
|
||||
|
@ -280,10 +247,7 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewp
|
|||
DAngle savedfov = cameraViewpoint.FieldOfView;
|
||||
R_SetFOV (cameraViewpoint, fov);
|
||||
|
||||
if (V_IsPolyRenderer())
|
||||
PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
else
|
||||
mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate);
|
||||
|
||||
R_SetFOV (cameraViewpoint, savedfov);
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ namespace swrenderer
|
|||
double FlatPlaneVis(int screenY, double planeheight, bool foggy, RenderViewport *viewport) const { return FlatPlaneGlobVis(foggy) / planeheight * fabs(viewport->CenterY - screenY); }
|
||||
|
||||
double SlopePlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : TiltVisibility; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
|
||||
static fixed_t LightLevelToShade(int lightlevel, bool foggy, RenderViewport *viewport) { return LightLevelToShadeImpl(viewport, lightlevel + ActualExtraLight(foggy, viewport), foggy); }
|
||||
|
||||
|
@ -93,7 +94,6 @@ namespace swrenderer
|
|||
|
||||
private:
|
||||
double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; }
|
||||
double FlatPlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : FloorVisibility; }
|
||||
|
||||
static fixed_t LightLevelToShadeImpl(RenderViewport *viewport, int lightlevel, bool foggy);
|
||||
|
|
|
@ -83,10 +83,10 @@ namespace swrenderer
|
|||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = ((actor->renderflags & RF_FULLBRIGHT) || (actor->flags5 & MF5_BRIGHT));
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : actor->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
renderer.visibility = thread->Light->SpriteGlobVis(foggy);
|
||||
|
||||
renderer.fillcolor = actor->fillcolor;
|
||||
renderer.Translation = actor->Translation;
|
||||
|
@ -128,10 +128,10 @@ namespace swrenderer
|
|||
return;
|
||||
|
||||
bool foggy = false;
|
||||
int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4;
|
||||
int actualextralight = foggy ? 0 : thread->Viewport->viewpoint.extralight << 4;
|
||||
bool fullbrightSprite = isBright(psp);
|
||||
renderer.lightlevel = fullbrightSprite ? 255 : playermo->Sector->lightlevel + actualextralight;
|
||||
renderer.visibility = PolyRenderer::Instance()->Light.SpriteGlobVis(foggy);
|
||||
renderer.visibility = thread->Light->SpriteGlobVis(foggy);
|
||||
|
||||
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
||||
ThingColor.a = 255;
|
||||
|
@ -354,7 +354,8 @@ namespace swrenderer
|
|||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite);
|
||||
args.SetLights(Lights, NumLights);
|
||||
args.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
|
@ -371,7 +372,8 @@ namespace swrenderer
|
|||
{
|
||||
PolyDrawArgs args;
|
||||
auto nc = !!(sector->Level->flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights);
|
||||
args.SetLight(GetSpriteColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], nc), lightlevel, visibility, fullbrightSprite);
|
||||
args.SetLights(Lights, NumLights);
|
||||
args.SetNormal(FVector3(0.0f, 0.0f, 0.0f));
|
||||
args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite);
|
||||
args.SetDepthTest(true);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <memory>
|
||||
#include "v_video.h"
|
||||
#include "r_defs.h"
|
||||
#include "r_utility.h"
|
||||
#include "actorinlines.h"
|
||||
#include "polyrenderer/math/gpu_types.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue