vkdoom_m/src/polyrenderer/poly_renderer.cpp
2018-04-23 23:09:11 +02:00

257 lines
7.8 KiB
C++

/*
** 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 "poly_renderer.h"
#include "d_net.h"
#include "po_man.h"
#include "st_stuff.h"
#include "g_levellocals.h"
#include "p_effect.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)
/////////////////////////////////////////////////////////////////////////////
PolyRenderer *PolyRenderer::Instance()
{
static PolyRenderer scene;
return &scene;
}
PolyRenderer::PolyRenderer()
{
}
void PolyRenderer::RenderView(player_t *player, DCanvas *target)
{
using namespace swrenderer;
R_ExecuteSetViewSize(Viewpoint, Viewwindow);
RenderTarget = target;
RenderToCanvas = false;
RenderActorView(player->mo, false);
Threads.MainThread()->FlushDrawQueue();
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, 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 dontmaplines)
{
PolyTotalBatches = 0;
PolyTotalTriangles = 0;
PolyTotalDrawCalls = 0;
PolyCullCycles.Reset();
PolyOpaqueCycles.Reset();
PolyMaskedCycles.Reset();
PolyDrawerWaitCycles.Reset();
NetUpdate();
DontMapLines = dontmaplines;
R_SetupFrame(Viewpoint, Viewwindow, actor);
P_FindParticleSubsectors();
PO_LinkToSubsectors();
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;
ClearBuffers();
SetSceneViewport();
PolyPortalViewpoint mainViewpoint = SetupPerspectiveMatrix();
mainViewpoint.StencilValue = GetNextStencilValue();
Scene.CurrentViewpoint = &mainViewpoint;
Scene.Render(&mainViewpoint);
PlayerSprites.Render(Threads.MainThread());
Scene.CurrentViewpoint = nullptr;
if (Viewpoint.camera)
Viewpoint.camera->renderflags = savedflags;
interpolator.RestoreInterpolations ();
NetUpdate();
}
void PolyRenderer::RenderRemainingPlayerSprites()
{
PlayerSprites.RenderRemainingSprites();
}
void PolyRenderer::ClearBuffers()
{
Threads.Clear();
PolyTriangleDrawer::ClearBuffers(RenderTarget);
NextStencilValue = 0;
Threads.MainThread()->SectorPortals.clear();
Threads.MainThread()->LinePortals.clear();
Threads.MainThread()->TranslucentObjects.clear();
}
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, false);
}
else // Rendering to camera texture
{
PolyTriangleDrawer::SetViewport(Threads.MainThread()->DrawQueue, 0, 0, RenderTarget->GetWidth(), RenderTarget->GetHeight(), RenderTarget, false);
}
}
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) * 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, 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;
}