gzdoom-gles/src/swrenderer/r_swrenderer.cpp
Christoph Oelckers df4f435952 - merged vid_renderer, swtruecolor and r_polyrender into one CVAR to reduce menu clutter.
- with renderers freely switchable, some shortcuts in the 3D floor code had to be removed, because now the hardware renderer can get FF_THISINSIDE-flagged 3D floors.
- changed handling of attenuated lights in the legacy renderer to be adjusted when being rendered instead of when being spawned. For the software renderer the light needs to retain its original values.
2018-04-07 23:30:28 +02:00

334 lines
10 KiB
C++

/*
** r_swrender.cpp
** Software renderer interface
**
**---------------------------------------------------------------------------
** Copyright 2011 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "swrenderer/scene/r_scene.h"
#include "swrenderer/viewport/r_viewport.h"
#include "swrenderer/things/r_playersprite.h"
#include "swrenderer/scene/r_scene.h"
#include "swrenderer/scene/r_light.h"
#include "swrenderer/r_swcolormaps.h"
#include "v_palette.h"
#include "v_video.h"
#include "m_png.h"
#include "r_swrenderer.h"
#include "scene/r_opaque_pass.h"
#include "scene/r_3dfloors.h"
#include "scene/r_portal.h"
#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"
// [BB] Use ZDoom's freelook limit for the sotfware renderer.
// Note: ZDoom's limit is chosen such that the sky is rendered properly.
CUSTOM_CVAR (Bool, cl_oldfreelooklimit, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (usergame) // [SP] Update pitch limits to the netgame/gamesim.
players[consoleplayer].SendPitchLimits();
}
EXTERN_CVAR(Float, maxviewpitch) // [SP] CVAR from OpenGL Renderer
EXTERN_CVAR(Bool, r_drawvoxels)
using namespace swrenderer;
FSoftwareRenderer::FSoftwareRenderer()
{
}
void FSoftwareRenderer::Init()
{
R_InitShadeMaps();
InitSWColorMaps();
}
FRenderer *CreateSWRenderer()
{
return new FSoftwareRenderer;
}
void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache)
{
bool isbgra = V_IsTrueColor();
if (tex != NULL)
{
if (cache & FTextureManager::HIT_Columnmode)
{
const FTexture::Span *spanp;
if (isbgra)
tex->GetColumnBgra(0, &spanp);
else
tex->GetColumn(DefaultRenderStyle(), 0, &spanp);
}
else if (cache != 0)
{
if (isbgra)
tex->GetPixelsBgra();
else
tex->GetPixels (DefaultRenderStyle());
}
else
{
tex->Unload ();
}
}
}
void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap<PClassActor*, bool> &actorhitlist)
{
uint8_t *spritelist = new uint8_t[sprites.Size()];
TMap<PClassActor*, bool>::Iterator it(actorhitlist);
TMap<PClassActor*, bool>::Pair *pair;
memset(spritelist, 0, sprites.Size());
while (it.NextPair(pair))
{
PClassActor *cls = pair->Key;
for (unsigned i = 0; i < cls->GetStateCount(); i++)
{
spritelist[cls->GetStates()[i].sprite] = true;
}
}
// Precache textures (and sprites).
for (int i = (int)(sprites.Size() - 1); i >= 0; i--)
{
if (spritelist[i])
{
int j, k;
for (j = 0; j < sprites[i].numframes; j++)
{
const spriteframe_t *frame = &SpriteFrames[sprites[i].spriteframes + j];
for (k = 0; k < 16; k++)
{
FTextureID pic = frame->Texture[k];
if (pic.isValid())
{
texhitlist[pic.GetIndex()] = FTextureManager::HIT_Sprite;
}
}
}
}
}
delete[] spritelist;
int cnt = TexMan.NumTextures();
for (int i = cnt - 1; i >= 0; i--)
{
PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]);
}
}
void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target)
{
if (V_IsPolyRenderer())
{
PolyRenderer::Instance()->Viewpoint = r_viewpoint;
PolyRenderer::Instance()->Viewwindow = r_viewwindow;
PolyRenderer::Instance()->RenderView(player, target);
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);
r_viewpoint = mScene.MainThread()->Viewport->viewpoint;
r_viewwindow = mScene.MainThread()->Viewport->viewwindow;
}
FCanvasTextureInfo::UpdateAll();
}
void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
{
DCanvas *pic = new DSimpleCanvas (width, height, false);
PalEntry palette[256];
// 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;
}
screen->GetFlashedPalette (palette);
M_CreatePNG (file, pic->GetPixels(), palette, SS_PAL, width, height, pic->GetPitch(), Gamma);
delete pic;
}
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;
}
}
void FSoftwareRenderer::OnModeSet ()
{
// This does not work if the SW renderer is not in use.
if (!V_IsHardwareRenderer())
mScene.ScreenResized();
}
void FSoftwareRenderer::SetClearColor(int color)
{
mScene.SetClearColor(color);
}
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, 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;
// Grab global state shared with rest of zdoom
cameraViewpoint = r_viewpoint;
cameraViewwindow = r_viewwindow;
uint8_t *Pixels = renderTarget->IsBgra() ? (uint8_t*)tex->GetPixelsBgra() : (uint8_t*)tex->GetPixels(DefaultRenderStyle());
DSimpleCanvas *Canvas = renderTarget->IsBgra() ? tex->GetCanvasBgra() : tex->GetCanvas();
// curse Doom's overuse of global variables in the renderer.
// These get clobbered by rendering to a camera texture but they need to be preserved so the final rendering can be done with the correct palette.
CameraLight savedCameraLight = *CameraLight::Instance();
DAngle savedfov = cameraViewpoint.FieldOfView;
R_SetFOV (cameraViewpoint, fov);
if (V_IsPolyRenderer())
PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
else
mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
R_SetFOV (cameraViewpoint, savedfov);
if (Canvas->IsBgra())
{
if (Pixels == Canvas->GetPixels())
{
FTexture::FlipSquareBlockBgra((uint32_t*)Pixels, tex->GetWidth(), tex->GetHeight());
}
else
{
FTexture::FlipNonSquareBlockBgra((uint32_t*)Pixels, (const uint32_t*)Canvas->GetPixels(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch());
}
}
else
{
if (Pixels == Canvas->GetPixels())
{
FTexture::FlipSquareBlockRemap(Pixels, tex->GetWidth(), tex->GetHeight(), GPalette.Remap);
}
else
{
FTexture::FlipNonSquareBlockRemap(Pixels, Canvas->GetPixels(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch(), GPalette.Remap);
}
}
if (renderTarget->IsBgra())
{
// True color render still sometimes uses palette textures (for sprites, mostly).
// We need to make sure that both pixel buffers contain data:
int width = tex->GetWidth();
int height = tex->GetHeight();
uint8_t *palbuffer = (uint8_t *)tex->GetPixels(DefaultRenderStyle());
uint32_t *bgrabuffer = (uint32_t*)tex->GetPixelsBgra();
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
uint32_t color = bgrabuffer[y];
int r = RPART(color);
int g = GPART(color);
int b = BPART(color);
palbuffer[y] = RGB32k.RGB[r >> 3][g >> 3][b >> 3];
}
palbuffer += height;
bgrabuffer += height;
}
}
tex->SetUpdated();
*CameraLight::Instance() = savedCameraLight;
// Sync state back to zdoom
r_viewpoint = cameraViewpoint;
r_viewwindow = cameraViewwindow;
}
void FSoftwareRenderer::SetColormap()
{
// This just sets the default colormap for the spftware renderer.
NormalLight.Maps = realcolormaps.Maps;
NormalLight.ChangeColor(PalEntry(255, 255, 255), 0);
NormalLight.ChangeFade(level.fadeto);
if (level.fadeto == 0)
{
SetDefaultColormap(level.info->FadeTable);
}
}