2016-03-01 15:47:10 +00:00
|
|
|
/*
|
|
|
|
** 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.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2017-01-12 15:21:46 +00:00
|
|
|
#include "swrenderer/scene/r_scene.h"
|
|
|
|
#include "swrenderer/scene/r_viewport.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/things/r_playersprite.h"
|
2017-01-12 15:21:46 +00:00
|
|
|
#include "swrenderer/scene/r_scene.h"
|
|
|
|
#include "swrenderer/scene/r_viewport.h"
|
|
|
|
#include "swrenderer/scene/r_light.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
#include "v_palette.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "m_png.h"
|
|
|
|
#include "r_swrenderer.h"
|
2017-01-11 19:42:39 +00:00
|
|
|
#include "scene/r_opaque_pass.h"
|
2016-12-27 05:31:55 +00:00
|
|
|
#include "scene/r_3dfloors.h"
|
2017-01-05 03:55:26 +00:00
|
|
|
#include "scene/r_portal.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
#include "textures/textures.h"
|
|
|
|
#include "r_data/voxels.h"
|
2016-12-27 05:31:55 +00:00
|
|
|
#include "drawers/r_draw_rgba.h"
|
|
|
|
#include "drawers/r_drawers.h"
|
|
|
|
#include "polyrenderer/poly_renderer.h"
|
2016-11-30 23:42:14 +00:00
|
|
|
#include "p_setup.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2016-12-20 22:21:34 +00:00
|
|
|
void gl_ParseDefs();
|
|
|
|
void gl_InitData();
|
2017-01-15 00:36:57 +00:00
|
|
|
void gl_SetActorLights(AActor *);
|
|
|
|
void gl_PreprocessLevel();
|
|
|
|
void gl_CleanLevelData();
|
2016-12-20 22:21:34 +00:00
|
|
|
|
2016-06-12 20:54:23 +00:00
|
|
|
EXTERN_CVAR(Bool, r_shadercolormaps)
|
2016-11-14 13:19:48 +00:00
|
|
|
EXTERN_CVAR(Float, maxviewpitch) // [SP] CVAR from GZDoom
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2016-11-30 23:42:14 +00:00
|
|
|
CUSTOM_CVAR(Bool, r_polyrenderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
|
|
|
{
|
|
|
|
if (self == 1 && !hasglnodes)
|
|
|
|
{
|
|
|
|
Printf("No GL BSP detected. You must restart the map before rendering will be correct\n");
|
|
|
|
}
|
2016-12-05 21:05:33 +00:00
|
|
|
|
|
|
|
if (usergame)
|
|
|
|
{
|
|
|
|
// [SP] Update pitch limits to the netgame/gamesim.
|
|
|
|
players[consoleplayer].SendPitchLimits();
|
|
|
|
}
|
2016-11-30 23:42:14 +00:00
|
|
|
}
|
|
|
|
|
2016-12-01 01:38:32 +00:00
|
|
|
using namespace swrenderer;
|
|
|
|
|
2016-09-29 00:10:14 +00:00
|
|
|
FSoftwareRenderer::FSoftwareRenderer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
FSoftwareRenderer::~FSoftwareRenderer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-03-01 15:47:10 +00:00
|
|
|
void FSoftwareRenderer::Init()
|
|
|
|
{
|
2016-12-20 22:21:34 +00:00
|
|
|
gl_ParseDefs();
|
|
|
|
|
2017-02-01 15:02:21 +00:00
|
|
|
RenderViewport::Instance()->r_swtruecolor = screen->IsBgra();
|
2017-01-14 01:25:02 +00:00
|
|
|
RenderScene::Instance()->Init();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FSoftwareRenderer::UsesColormap() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache)
|
|
|
|
{
|
2017-01-15 00:36:57 +00:00
|
|
|
bool isbgra = screen->IsBgra();
|
|
|
|
|
2016-03-01 15:47:10 +00:00
|
|
|
if (tex != NULL)
|
|
|
|
{
|
|
|
|
if (cache & FTextureManager::HIT_Columnmode)
|
|
|
|
{
|
|
|
|
const FTexture::Span *spanp;
|
2017-01-15 00:36:57 +00:00
|
|
|
if (isbgra)
|
2016-06-13 01:16:48 +00:00
|
|
|
tex->GetColumnBgra(0, &spanp);
|
2016-06-13 19:39:55 +00:00
|
|
|
else
|
2016-06-13 01:16:48 +00:00
|
|
|
tex->GetColumn(0, &spanp);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
else if (cache != 0)
|
|
|
|
{
|
2017-01-15 00:36:57 +00:00
|
|
|
if (isbgra)
|
2016-06-14 21:05:20 +00:00
|
|
|
tex->GetPixelsBgra();
|
2016-06-13 01:16:48 +00:00
|
|
|
else
|
|
|
|
tex->GetPixels ();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tex->Unload ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-01 20:47:36 +00:00
|
|
|
void FSoftwareRenderer::Precache(BYTE *texhitlist, TMap<PClassActor*, bool> &actorhitlist)
|
|
|
|
{
|
|
|
|
BYTE *spritelist = new BYTE[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 (int i = 0; i < cls->NumOwnedStates; i++)
|
|
|
|
{
|
|
|
|
spritelist[cls->OwnedStates[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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 15:47:10 +00:00
|
|
|
void FSoftwareRenderer::RenderView(player_t *player)
|
|
|
|
{
|
2016-11-30 23:42:14 +00:00
|
|
|
if (r_polyrenderer)
|
2017-01-15 01:46:43 +00:00
|
|
|
PolyRenderer::Instance()->RenderView(player);
|
2017-01-15 00:36:57 +00:00
|
|
|
else
|
2017-01-15 01:46:43 +00:00
|
|
|
RenderScene::Instance()->RenderView(player);
|
2016-06-12 20:54:23 +00:00
|
|
|
|
2017-01-15 01:46:43 +00:00
|
|
|
FCanvasTextureInfo::UpdateAll();
|
2017-01-15 00:36:57 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
void FSoftwareRenderer::RemapVoxels()
|
|
|
|
{
|
|
|
|
for (unsigned i=0; i<Voxels.Size(); i++)
|
|
|
|
{
|
|
|
|
Voxels[i]->Remap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-21 07:01:12 +00:00
|
|
|
void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2016-05-31 07:36:18 +00:00
|
|
|
DCanvas *pic = new DSimpleCanvas (width, height, false);
|
2016-03-01 15:47:10 +00:00
|
|
|
PalEntry palette[256];
|
|
|
|
|
|
|
|
// Take a snapshot of the player's view
|
|
|
|
pic->ObjectFlags |= OF_Fixed;
|
|
|
|
pic->Lock ();
|
2016-11-30 23:42:14 +00:00
|
|
|
if (r_polyrenderer)
|
2016-12-03 13:58:56 +00:00
|
|
|
PolyRenderer::Instance()->RenderViewToCanvas(player->mo, pic, 0, 0, width, height, true);
|
2016-11-30 23:42:14 +00:00
|
|
|
else
|
2017-01-14 01:25:02 +00:00
|
|
|
RenderScene::Instance()->RenderViewToCanvas (player->mo, pic, 0, 0, width, height);
|
2016-03-01 15:47:10 +00:00
|
|
|
screen->GetFlashedPalette (palette);
|
|
|
|
M_CreatePNG (file, pic->GetBuffer(), palette, SS_PAL, width, height, pic->GetPitch());
|
|
|
|
pic->Unlock ();
|
|
|
|
pic->Destroy();
|
|
|
|
pic->ObjectFlags |= OF_YesReallyDelete;
|
|
|
|
delete pic;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSoftwareRenderer::DrawRemainingPlayerSprites()
|
|
|
|
{
|
2016-11-21 14:19:24 +00:00
|
|
|
if (!r_polyrenderer)
|
2016-11-14 13:19:48 +00:00
|
|
|
{
|
2017-01-24 03:15:54 +00:00
|
|
|
RenderPlayerSprites::Instance()->RenderRemaining();
|
2016-11-14 13:19:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-12-03 13:58:56 +00:00
|
|
|
PolyRenderer::Instance()->RenderRemainingPlayerSprites();
|
2016-11-14 13:19:48 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int FSoftwareRenderer::GetMaxViewPitch(bool down)
|
|
|
|
{
|
2017-01-15 00:36:57 +00:00
|
|
|
const int MAX_DN_ANGLE = 56; // Max looking down angle
|
|
|
|
const int MAX_UP_ANGLE = 32; // Max looking up angle
|
2016-11-21 14:19:24 +00:00
|
|
|
return (r_polyrenderer) ? int(maxviewpitch) : (down ? MAX_DN_ANGLE : MAX_UP_ANGLE);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 11:07:07 +00:00
|
|
|
bool FSoftwareRenderer::RequireGLNodes()
|
|
|
|
{
|
2016-12-20 22:21:34 +00:00
|
|
|
return true;
|
2016-11-09 11:07:07 +00:00
|
|
|
}
|
|
|
|
|
2016-03-01 15:47:10 +00:00
|
|
|
void FSoftwareRenderer::OnModeSet ()
|
|
|
|
{
|
2017-01-14 01:25:02 +00:00
|
|
|
RenderScene::Instance()->ScreenResized();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-15 02:21:35 +00:00
|
|
|
void FSoftwareRenderer::SetClearColor(int color)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-15 02:19:03 +00:00
|
|
|
RenderScene::Instance()->SetClearColor(color);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, int fov)
|
|
|
|
{
|
2017-02-01 15:02:21 +00:00
|
|
|
auto viewport = RenderViewport::Instance();
|
|
|
|
|
|
|
|
BYTE *Pixels = viewport->r_swtruecolor ? (BYTE*)tex->GetPixelsBgra() : (BYTE*)tex->GetPixels();
|
|
|
|
DSimpleCanvas *Canvas = viewport->r_swtruecolor ? tex->GetCanvasBgra() : tex->GetCanvas();
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
// 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.
|
2017-01-26 09:22:54 +00:00
|
|
|
CameraLight savedCameraLight = *CameraLight::Instance();
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2016-04-28 11:59:06 +00:00
|
|
|
DAngle savedfov = FieldOfView;
|
|
|
|
R_SetFOV ((double)fov);
|
2017-01-15 00:36:57 +00:00
|
|
|
|
2016-11-30 23:42:14 +00:00
|
|
|
if (r_polyrenderer)
|
2016-12-03 13:58:56 +00:00
|
|
|
PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
|
2016-11-30 23:42:14 +00:00
|
|
|
else
|
2017-01-14 01:25:02 +00:00
|
|
|
RenderScene::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate);
|
2017-01-15 00:36:57 +00:00
|
|
|
|
2016-03-01 15:47:10 +00:00
|
|
|
R_SetFOV (savedfov);
|
2016-06-13 01:16:48 +00:00
|
|
|
|
|
|
|
if (Canvas->IsBgra())
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2016-06-13 01:16:48 +00:00
|
|
|
if (Pixels == Canvas->GetBuffer())
|
|
|
|
{
|
|
|
|
FTexture::FlipSquareBlockBgra((uint32_t*)Pixels, tex->GetWidth(), tex->GetHeight());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FTexture::FlipNonSquareBlockBgra((uint32_t*)Pixels, (const uint32_t*)Canvas->GetBuffer(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch());
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-06-13 01:16:48 +00:00
|
|
|
if (Pixels == Canvas->GetBuffer())
|
|
|
|
{
|
|
|
|
FTexture::FlipSquareBlockRemap(Pixels, tex->GetWidth(), tex->GetHeight(), GPalette.Remap);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FTexture::FlipNonSquareBlockRemap(Pixels, Canvas->GetBuffer(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch(), GPalette.Remap);
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2016-06-17 08:14:33 +00:00
|
|
|
|
2017-02-01 15:02:21 +00:00
|
|
|
if (viewport->r_swtruecolor)
|
2016-06-17 08:14:33 +00:00
|
|
|
{
|
|
|
|
// 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();
|
|
|
|
BYTE *palbuffer = (BYTE *)tex->GetPixels();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-17 08:16:34 +00:00
|
|
|
tex->SetUpdated();
|
|
|
|
|
2017-01-26 09:22:54 +00:00
|
|
|
*CameraLight::Instance() = savedCameraLight;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-03 17:55:12 +00:00
|
|
|
sector_t *FSoftwareRenderer::FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-11 19:42:39 +00:00
|
|
|
return RenderOpaquePass::Instance()->FakeFlat(sec, tempsec, floorlightlevel, ceilinglightlevel, nullptr, 0, 0, 0, 0);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
|
2017-01-15 00:36:57 +00:00
|
|
|
void FSoftwareRenderer::StateChanged(AActor *actor)
|
|
|
|
{
|
|
|
|
gl_SetActorLights(actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSoftwareRenderer::PreprocessLevel()
|
|
|
|
{
|
|
|
|
gl_PreprocessLevel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSoftwareRenderer::CleanLevelData()
|
|
|
|
{
|
|
|
|
gl_CleanLevelData();
|
|
|
|
}
|