From 5666e4c805a27fba3d5c8c5239b60861e5b6e939 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Dec 2018 00:01:45 +0100 Subject: [PATCH] - made camera textures operational again. Now with proper separation of software rendering logic from the main part of the class. --- src/CMakeLists.txt | 2 + src/dobjgc.cpp | 1 - src/g_level.cpp | 1 + src/g_levellocals.h | 2 + src/gl/renderer/gl_renderer.cpp | 8 +- src/gl/system/gl_framebuffer.cpp | 19 -- src/gl/system/gl_framebuffer.h | 3 +- src/p_acs.cpp | 2 +- src/p_saveg.cpp | 2 +- src/p_setup.cpp | 2 +- src/r_data/r_canvastexture.cpp | 210 ++++++++++++++++++++ src/r_data/r_canvastexture.h | 25 +++ src/r_renderer.h | 3 - src/r_utility.cpp | 192 ------------------ src/r_utility.h | 20 -- src/scripting/vmthunks.cpp | 13 ++ src/swrenderer/r_swrenderer.cpp | 65 +----- src/swrenderer/r_swrenderer.h | 2 +- src/swrenderer/textures/r_swtexture.cpp | 3 +- src/swrenderer/textures/r_swtexture.h | 33 ++- src/swrenderer/textures/swcanvastexture.cpp | 189 ++++++++++++++++++ src/textures/formats/canvastexture.cpp | 119 ----------- src/textures/image.cpp | 10 +- src/textures/imagehelpers.h | 2 +- src/textures/textures.h | 38 ++-- src/v_framebuffer.cpp | 5 - src/v_video.h | 4 - 27 files changed, 517 insertions(+), 458 deletions(-) create mode 100644 src/r_data/r_canvastexture.cpp create mode 100644 src/r_data/r_canvastexture.h create mode 100644 src/swrenderer/textures/swcanvastexture.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d43c03f369..2f3a94d497 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1144,6 +1144,7 @@ set (PCH_SOURCES r_data/voxels.cpp r_data/renderinfo.cpp r_data/renderstyle.cpp + r_data/r_canvastexture.cpp r_data/r_interpolate.cpp r_data/r_vanillatrans.cpp r_data/r_sections.cpp @@ -1249,6 +1250,7 @@ set (PCH_SOURCES sound/wildmidi/wm_error.cpp swrenderer/textures/r_swtexture.cpp swrenderer/textures/warptexture.cpp + swrenderer/textures/swcanvastexture.cpp events.cpp ) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index cd1b49a103..51e95313db 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -322,7 +322,6 @@ static void MarkRoot() M_MarkMenus(); Mark(DIntermissionController::CurrentIntermission); DThinker::MarkRoots(); - FCanvasTextureInfo::Mark(); Mark(E_FirstEventHandler); Mark(E_LastEventHandler); level.Mark(); diff --git a/src/g_level.cpp b/src/g_level.cpp index 873bcf97d0..a0e380b086 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1959,6 +1959,7 @@ void FLevelLocals::Tick () void FLevelLocals::Mark() { + canvasTextureInfo.Mark(); for (auto &s : sectorPortals) { GC::Mark(s.mSkybox); diff --git a/src/g_levellocals.h b/src/g_levellocals.h index c39da92503..2d76c39b27 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -44,6 +44,7 @@ #include "p_local.h" #include "p_destructible.h" #include "r_data/r_sections.h" +#include "r_data/r_canvastexture.h" struct FLevelLocals { @@ -103,6 +104,7 @@ struct FLevelLocals TArray portalGroups; TArray linePortalSpans; FSectionContainer sections; + FCanvasTextureInfo canvasTextureInfo; int NumMapSections; diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index af6a3acac3..79ae7655f7 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -254,7 +254,10 @@ sector_t *FGLRenderer::RenderView(player_t* player) bool saved_niv = NoInterpolateView; NoInterpolateView = false; // prepare all camera textures that have been used in the last frame - FCanvasTextureInfo::UpdateAll(); + level.canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) + { + RenderTextureView(camtex, camera, fov); + }); NoInterpolateView = saved_niv; @@ -324,7 +327,8 @@ void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, doub EndOffscreen(); - tex->SetUpdated(); + tex->SetUpdated(true); + static_cast(screen)->camtexcount++; } //=========================================================================== diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index 050ff41ff1..58cc8be228 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -186,25 +186,6 @@ void OpenGLFrameBuffer::Update() Super::Update(); } -//=========================================================================== -// -// -// -//=========================================================================== - -void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - if (!V_IsHardwareRenderer()) - { - Super::RenderTextureView(tex, Viewpoint, FOV); - } - else if (GLRenderer != nullptr) - { - GLRenderer->RenderTextureView(tex, Viewpoint, FOV); - camtexcount++; - } -} - //=========================================================================== // // Render the view to a savegame picture diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index 72ec2a9c22..60929d9473 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -30,7 +30,6 @@ public: void CleanForRestart() override; void UpdatePalette() override; uint32_t GetCaps() override; - void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) override; void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; sector_t *RenderView(player_t *player) override; void SetTextureFilterMode() override; @@ -65,7 +64,7 @@ public: FTexture *WipeStartScreen() override; FTexture *WipeEndScreen() override; -private: + int camtexcount = 0; }; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 2456e4a8f8..ab7ca86b89 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9900,7 +9900,7 @@ scriptwait: } else { - FCanvasTextureInfo::Add (camera, picnum, STACK(1)); + level.canvasTextureInfo.Add(camera, picnum, STACK(1)); } } sp -= 3; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 5436cfbe7b..68f642c781 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1012,7 +1012,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) StatusBar->SerializeMessages(arc); AM_SerializeMarkers(arc); FRemapTable::StaticSerializeTranslations(arc); - FCanvasTextureInfo::Serialize(arc); + level.canvasTextureInfo.Serialize(arc); P_SerializePlayers(arc, hubload); P_SerializeSounds(arc); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index fa7de9d7f8..16f6091526 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3555,7 +3555,6 @@ void P_FreeLevelData () MapThingsUserDataIndex.Clear(); MapThingsUserData.Clear(); linemap.Clear(); - FCanvasTextureInfo::EmptyList(); R_FreePastViewers(); P_ClearUDMFKeys(); @@ -3594,6 +3593,7 @@ void P_FreeLevelData () FBehavior::StaticUnloadModules (); + level.canvasTextureInfo.EmptyList(); level.sections.Clear(); level.segs.Clear(); level.sectors.Clear(); diff --git a/src/r_data/r_canvastexture.cpp b/src/r_data/r_canvastexture.cpp new file mode 100644 index 0000000000..a64f50b874 --- /dev/null +++ b/src/r_data/r_canvastexture.cpp @@ -0,0 +1,210 @@ +/* +** r_canvastexture.cpp +** Maintenance data for camera textures +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 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 "actor.h" +#include "r_canvastexture.h" +#include "g_levellocals.h" +#include "serializer.h" + +//========================================================================== +// +// FCanvasTextureInfo :: Add +// +// Assigns a camera to a canvas texture. +// +//========================================================================== + +void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) +{ + FCanvasTexture *texture; + + if (!picnum.isValid()) + { + return; + } + texture = static_cast(TexMan.GetTexture(picnum)); + if (!texture->bHasCanvas) + { + Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); + return; + } + + // Is this texture already assigned to a camera? + unsigned index = List.FindEx([=](auto &entry) { return entry.Texture == texture; }); + if (index < List.Size()) + { + auto probe = &List[index]; + // Yes, change its assignment to this new camera + if (probe->Viewpoint != viewpoint || probe->FOV != fov) + { + texture->bFirstUpdate = true; + } + probe->Viewpoint = viewpoint; + probe->FOV = fov; + return; + } + // No, create a new assignment + auto probe = &List[List.Reserve(1)]; + probe->Viewpoint = viewpoint; + probe->Texture = texture; + probe->PicNum = picnum; + probe->FOV = fov; + texture->bFirstUpdate = true; +} + +//========================================================================== +// +// SetCameraToTexture +// +// [ZZ] expose this to ZScript +// +//========================================================================== + +void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov) +{ + FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + if (textureid.isValid()) + { + // Only proceed if the texture actually has a canvas. + FTexture *tex = TexMan.GetTexture(textureid); + if (tex && tex->isCanvas()) + { + level.canvasTextureInfo.Add(viewpoint, textureid, fov); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: UpdateAll +// +// Updates all canvas textures that were visible in the last frame. +// +//========================================================================== + +void FCanvasTextureInfo::UpdateAll(std::function callback) +{ + for (auto &probe : List) + { + if (probe.Viewpoint != nullptr && probe.Texture->bNeedsUpdate) + { + callback(probe.Viewpoint, probe.Texture, probe.FOV); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: EmptyList +// +// Removes all camera->texture assignments. +// +//========================================================================== + +void FCanvasTextureInfo::EmptyList () +{ + List.Clear(); +} + +//========================================================================== +// +// FCanvasTextureInfo :: Serialize +// +// Reads or writes the current set of mappings in an archive. +// +//========================================================================== + +void FCanvasTextureInfo::Serialize(FSerializer &arc) +{ + if (arc.isWriting()) + { + if (List.Size() > 0) + { + if (arc.BeginArray("canvastextures")) + { + for (auto &probe : List) + { + if (probe.Texture != nullptr && probe.Viewpoint != nullptr) + { + if (arc.BeginObject(nullptr)) + { + arc("viewpoint", probe.Viewpoint) + ("fov", probe.FOV) + ("texture", probe.PicNum) + .EndObject(); + } + } + } + arc.EndArray(); + } + } + } + else + { + if (arc.BeginArray("canvastextures")) + { + AActor *viewpoint = nullptr; + double fov; + FTextureID picnum; + while (arc.BeginObject(nullptr)) + { + arc("viewpoint", viewpoint) + ("fov", fov) + ("texture", picnum) + .EndObject(); + Add(viewpoint, picnum, fov); + } + arc.EndArray(); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: Mark +// +// Marks all viewpoints in the list for the collector. +// +//========================================================================== + +void FCanvasTextureInfo::Mark() +{ + for (auto & info : List) + { + GC::Mark(info.Viewpoint); + } +} + diff --git a/src/r_data/r_canvastexture.h b/src/r_data/r_canvastexture.h new file mode 100644 index 0000000000..8a82eb6e7d --- /dev/null +++ b/src/r_data/r_canvastexture.h @@ -0,0 +1,25 @@ +#pragma once + +class FCanvasTexture; +// This list keeps track of the cameras that draw into canvas textures. +struct FCanvasTextureEntry +{ + FCanvasTextureInfo *Next; + TObjPtr Viewpoint; + FCanvasTexture *Texture; + FTextureID PicNum; + double FOV; +}; + + +struct FCanvasTextureInfo +{ + TArray List; + + void Add (AActor *viewpoint, FTextureID picnum, double fov); + void UpdateAll (std::function callback); + void EmptyList (); + void Serialize(FSerializer &arc); + void Mark(); + +}; \ No newline at end of file diff --git a/src/r_renderer.h b/src/r_renderer.h index 225d577403..46fd9a4303 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -28,9 +28,6 @@ struct FRenderer // renders view to a savegame picture virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height) = 0; - // render to a camera texture - virtual void RenderTextureView(FCanvasTexture *tex, AActor *viewpoint, double fov) = 0; - // draws player sprites with hardware acceleration (only useful for software rendering) virtual void DrawRemainingPlayerSprites() = 0; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 6adfbc5ac4..9117fc01f4 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -146,8 +146,6 @@ int validcount = 1; // increment every time a check is made int dl_validcount = 1; // increment every time a check is made int freelookviewheight; -FCanvasTextureInfo *FCanvasTextureInfo::List; - DVector3a view; DAngle viewpitch; @@ -433,7 +431,6 @@ static void R_Shutdown () SWRenderer = nullptr; R_DeinitTranslationTables(); R_DeinitColormaps (); - FCanvasTextureInfo::EmptyList(); } //========================================================================== @@ -1052,195 +1049,6 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor } -//========================================================================== -// -// FCanvasTextureInfo :: Add -// -// Assigns a camera to a canvas texture. -// -//========================================================================== - -void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) -{ - FCanvasTextureInfo *probe; - FCanvasTexture *texture; - - if (!picnum.isValid()) - { - return; - } - texture = static_cast(TexMan.GetTexture(picnum)); - if (!texture->bHasCanvas) - { - Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); - return; - } - - // Is this texture already assigned to a camera? - for (probe = List; probe != NULL; probe = probe->Next) - { - if (probe->Texture == texture) - { - // Yes, change its assignment to this new camera - if (probe->Viewpoint != viewpoint || probe->FOV != fov) - { - texture->bFirstUpdate = true; - } - probe->Viewpoint = viewpoint; - probe->FOV = fov; - return; - } - } - // No, create a new assignment - probe = new FCanvasTextureInfo; - probe->Viewpoint = viewpoint; - probe->Texture = texture; - probe->PicNum = picnum; - probe->FOV = fov; - probe->Next = List; - texture->bFirstUpdate = true; - List = probe; -} - -// [ZZ] expose this to ZScript -void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov) -{ - FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); - if (textureid.isValid()) - { - // Only proceed if the texture actually has a canvas. - FTexture *tex = TexMan.GetTexture(textureid); - if (tex && tex->isCanvas()) - { - FCanvasTextureInfo::Add(viewpoint, textureid, fov); - } - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(viewpoint, AActor); - PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. - PARAM_FLOAT(fov); - SetCameraToTexture(viewpoint, texturename, fov); - return 0; -} - -//========================================================================== -// -// FCanvasTextureInfo :: UpdateAll -// -// Updates all canvas textures that were visible in the last frame. -// -//========================================================================== - -void FCanvasTextureInfo::UpdateAll () -{ - FCanvasTextureInfo *probe; - - for (probe = List; probe != NULL; probe = probe->Next) - { - if (probe->Viewpoint != NULL && probe->Texture->bNeedsUpdate) - { - screen->RenderTextureView(probe->Texture, probe->Viewpoint, probe->FOV); - } - } -} - -//========================================================================== -// -// FCanvasTextureInfo :: EmptyList -// -// Removes all camera->texture assignments. -// -//========================================================================== - -void FCanvasTextureInfo::EmptyList () -{ - FCanvasTextureInfo *probe, *next; - - for (probe = List; probe != NULL; probe = next) - { - next = probe->Next; - //probe->Texture->Unload(); - delete probe; - } - List = NULL; -} - -//========================================================================== -// -// FCanvasTextureInfo :: Serialize -// -// Reads or writes the current set of mappings in an archive. -// -//========================================================================== - -void FCanvasTextureInfo::Serialize(FSerializer &arc) -{ - if (arc.isWriting()) - { - if (List != nullptr) - { - if (arc.BeginArray("canvastextures")) - { - FCanvasTextureInfo *probe; - - for (probe = List; probe != nullptr; probe = probe->Next) - { - if (probe->Texture != nullptr && probe->Viewpoint != nullptr) - { - if (arc.BeginObject(nullptr)) - { - arc("viewpoint", probe->Viewpoint) - ("fov", probe->FOV) - ("texture", probe->PicNum) - .EndObject(); - } - } - } - arc.EndArray(); - } - } - } - else - { - if (arc.BeginArray("canvastextures")) - { - AActor *viewpoint = nullptr; - double fov; - FTextureID picnum; - while (arc.BeginObject(nullptr)) - { - arc("viewpoint", viewpoint) - ("fov", fov) - ("texture", picnum) - .EndObject(); - Add(viewpoint, picnum, fov); - } - arc.EndArray(); - } - } -} - -//========================================================================== -// -// FCanvasTextureInfo :: Mark -// -// Marks all viewpoints in the list for the collector. -// -//========================================================================== - -void FCanvasTextureInfo::Mark() -{ - for (FCanvasTextureInfo *probe = List; probe != NULL; probe = probe->Next) - { - GC::Mark(probe->Viewpoint); - } -} - - //========================================================================== // // CVAR transsouls diff --git a/src/r_utility.h b/src/r_utility.h index e5ac4a2b8b..1eb93096a4 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -138,25 +138,5 @@ double R_ClampVisibility(double vis); extern void R_FreePastViewers (); extern void R_ClearPastViewer (AActor *actor); -class FCanvasTexture; -// This list keeps track of the cameras that draw into canvas textures. -struct FCanvasTextureInfo -{ - FCanvasTextureInfo *Next; - TObjPtr Viewpoint; - FCanvasTexture *Texture; - FTextureID PicNum; - double FOV; - - static void Add (AActor *viewpoint, FTextureID picnum, double fov); - static void UpdateAll (); - static void EmptyList (); - static void Serialize(FSerializer &arc); - static void Mark(); - -private: - static FCanvasTextureInfo *List; -}; - #endif diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 737d2f81b0..ad44203b11 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -1584,6 +1584,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, ReplaceTextures, ReplaceTextures) return 0; } +void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov); + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(viewpoint, AActor); + PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. + PARAM_FLOAT(fov); + SetCameraToTexture(viewpoint, texturename, fov); + return 0; +} + + //===================================================================================== // // secplane_t exports diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index 9cd3fb309e..873f5c85d3 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -52,6 +52,7 @@ #include "p_setup.h" #include "g_levellocals.h" #include "image.h" +#include "imagehelpers.h" // [BB] Use ZDoom's freelook limit for the sotfware renderer. // Note: ZDoom's limit is chosen such that the sky is rendered properly. @@ -201,7 +202,10 @@ void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *vide r_viewwindow = mScene.MainThread()->Viewport->viewwindow; } - FCanvasTextureInfo::UpdateAll(); + level.canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) + { + RenderTextureView(camtex, camera, fov); + }); } void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height) @@ -255,9 +259,8 @@ void FSoftwareRenderer::SetClearColor(int color) mScene.SetClearColor(color); } -void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) +void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewpoint, double fov) { -#if 0 // This will require a complete redesign. 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; @@ -265,8 +268,9 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoin // Grab global state shared with rest of zdoom cameraViewpoint = r_viewpoint; cameraViewwindow = r_viewwindow; + + auto tex = static_cast(camtex->GetSoftwareTexture()); - uint8_t *Pixels = renderTarget->IsBgra() ? (uint8_t*)tex->GetPixelsBgra() : (uint8_t*)tex->GetPixels(DefaultRenderStyle()); DCanvas *Canvas = renderTarget->IsBgra() ? tex->GetCanvasBgra() : tex->GetCanvas(); // curse Doom's overuse of global variables in the renderer. @@ -277,66 +281,19 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoin R_SetFOV (cameraViewpoint, fov); if (V_IsPolyRenderer()) - PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate); + PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate); else - mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate); + mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->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(); + tex->UpdatePixels(renderTarget->IsBgra()); *CameraLight::Instance() = savedCameraLight; // Sync state back to zdoom r_viewpoint = cameraViewpoint; r_viewwindow = cameraViewwindow; -#endif } void FSoftwareRenderer::SetColormap() diff --git a/src/swrenderer/r_swrenderer.h b/src/swrenderer/r_swrenderer.h index b9bb280194..61d0044ff5 100644 --- a/src/swrenderer/r_swrenderer.h +++ b/src/swrenderer/r_swrenderer.h @@ -21,7 +21,7 @@ struct FSoftwareRenderer : public FRenderer void DrawRemainingPlayerSprites() override; void SetClearColor(int color) override; - void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) override; + void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov); void SetColormap() override; void Init() override; diff --git a/src/swrenderer/textures/r_swtexture.cpp b/src/swrenderer/textures/r_swtexture.cpp index 5e3721fe97..1008252520 100644 --- a/src/swrenderer/textures/r_swtexture.cpp +++ b/src/swrenderer/textures/r_swtexture.cpp @@ -43,7 +43,8 @@ FSoftwareTexture *FTexture::GetSoftwareTexture() { if (!SoftwareTexture) { - if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped); + if (bHasCanvas) SoftwareTexture = new FSWCanvasTexture(this); + else if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped); else SoftwareTexture = new FSoftwareTexture(this); } return SoftwareTexture; diff --git a/src/swrenderer/textures/r_swtexture.h b/src/swrenderer/textures/r_swtexture.h index 791619e778..14810b0719 100644 --- a/src/swrenderer/textures/r_swtexture.h +++ b/src/swrenderer/textures/r_swtexture.h @@ -2,6 +2,7 @@ #include "textures/textures.h" #include "v_video.h" + struct FSoftwareTextureSpan { uint16_t TopOffset; @@ -62,7 +63,6 @@ public: int GetHeight () { return mTexture->GetHeight(); } int GetWidthBits() { return WidthBits; } int GetHeightBits() { return HeightBits; } - bool Mipmapped() { return mTexture->Mipmapped(); } int GetScaledWidth () { return mTexture->GetScaledWidth(); } int GetScaledHeight () { return mTexture->GetScaledHeight(); } @@ -95,7 +95,7 @@ public: DVector2 GetScale() const { return mTexture->Scale; } - void Unload() + virtual void Unload() { Pixels.Reset(); PixelsBgra.Reset(); @@ -112,6 +112,9 @@ public: void GenerateBgraMipmapsFast(); int MipmapLevels(); + // Returns true if GetPixelsBgra includes mipmaps + virtual bool Mipmapped() { return true; } + // Returns a single column of the texture virtual const uint8_t *GetColumn(int style, unsigned int column, const FSoftwareTextureSpan **spans_out); @@ -166,3 +169,29 @@ private: int NextPo2 (int v); // [mxd] void SetupMultipliers (int width, int height); // [mxd] }; + +class FSWCanvasTexture : public FSoftwareTexture +{ + void MakeTexture(); + void MakeTextureBgra(); + + DCanvas *Canvas = nullptr; + DCanvas *CanvasBgra = nullptr; + +public: + + FSWCanvasTexture(FTexture *source) : FSoftwareTexture(source) {} + ~FSWCanvasTexture(); + + // Returns the whole texture, stored in column-major order + const uint32_t *GetPixelsBgra() override; + const uint8_t *GetPixels(int style) override; + + virtual void Unload() override; + void UpdatePixels(bool truecolor); + + DCanvas *GetCanvas() { return Canvas; } + DCanvas *GetCanvasBgra() { return CanvasBgra; } + bool Mipmapped() override { return false; } + +}; \ No newline at end of file diff --git a/src/swrenderer/textures/swcanvastexture.cpp b/src/swrenderer/textures/swcanvastexture.cpp new file mode 100644 index 0000000000..8c47ad1523 --- /dev/null +++ b/src/swrenderer/textures/swcanvastexture.cpp @@ -0,0 +1,189 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 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 "r_swtexture.h" +#include "bitmap.h" +#include "m_alloc.h" +#include "imagehelpers.h" + + +FSWCanvasTexture::~FSWCanvasTexture() +{ + if (Canvas != nullptr) + { + delete Canvas; + Canvas = nullptr; + } + + if (CanvasBgra != nullptr) + { + delete CanvasBgra; + CanvasBgra = nullptr; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +const uint8_t *FSWCanvasTexture::GetPixels(int style) +{ + static_cast(mTexture)->NeedUpdate(); + if (Canvas == nullptr) + { + MakeTexture(); + } + return Pixels.Data(); + +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint32_t *FSWCanvasTexture::GetPixelsBgra() +{ + static_cast(mTexture)->NeedUpdate(); + if (CanvasBgra == nullptr) + { + MakeTextureBgra(); + } + return PixelsBgra.Data(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::MakeTexture () +{ + Canvas = new DCanvas (GetWidth(), GetHeight(), false); + Pixels.Resize(GetWidth() * GetHeight()); + + // Draw a special "unrendered" initial texture into the buffer. + memset (Pixels.Data(), 0, GetWidth() * GetHeight() / 2); + memset (Pixels.Data() + GetWidth() * GetHeight() / 2, 255, GetWidth() * GetHeight() / 2); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::MakeTextureBgra() +{ + CanvasBgra = new DCanvas(GetWidth(), GetHeight(), true); + PixelsBgra.Resize(GetWidth() * GetHeight()); + + // Draw a special "unrendered" initial texture into the buffer. + memset(PixelsBgra.Data(), 0, 4* GetWidth() * GetHeight() / 2); + memset(PixelsBgra.Data() + GetWidth() * GetHeight() / 2, 255, 4* GetWidth() * GetHeight() / 2); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::Unload () +{ + if (Canvas != nullptr) + { + delete Canvas; + Canvas = nullptr; + } + + if (CanvasBgra != nullptr) + { + delete CanvasBgra; + CanvasBgra = nullptr; + } + + FSoftwareTexture::Unload(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::UpdatePixels(bool truecolor) +{ + + if (Canvas->IsBgra()) + { + ImageHelpers::FlipNonSquareBlock(PixelsBgra.Data(), (const uint32_t*)Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch()); + } + else + { + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch(), GPalette.Remap); + } + + if (truecolor) + { + // True color render still sometimes uses palette textures (for sprites, mostly). + // We need to make sure that both pixel buffers contain data: + int width = GetWidth(); + int height = GetHeight(); + uint8_t *palbuffer = const_cast(GetPixels(0)); + const uint32_t *bgrabuffer = 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; + } + } + + static_cast(mTexture)->SetUpdated(false); +} \ No newline at end of file diff --git a/src/textures/formats/canvastexture.cpp b/src/textures/formats/canvastexture.cpp index da63589283..d2ddcea959 100644 --- a/src/textures/formats/canvastexture.cpp +++ b/src/textures/formats/canvastexture.cpp @@ -36,123 +36,4 @@ #include "doomtype.h" #include "v_video.h" -FCanvasTexture::FCanvasTexture (const char *name, int width, int height) -{ - Name = name; - Width = width; - Height = height; - bMasked = false; - UseType = ETextureType::Wall; - bNeedsUpdate = true; - bDidUpdate = false; - bHasCanvas = true; - bFirstUpdate = true; - bPixelsAllocated = false; -} - - -#if 0 -const uint8_t *FCanvasTexture::Get8BitPixels(bool alphatex) -{ - bNeedsUpdate = true; - if (Canvas == NULL) - { - MakeTexture (style); - } - return Pixels; -} - -const uint32_t *FCanvasTexture::GetPixelsBgra() -{ - bNeedsUpdate = true; - if (CanvasBgra == NULL) - { - MakeTextureBgra(); - } - return PixelsBgra; -} - -void FCanvasTexture::MakeTexture (FRenderStyle) // This ignores the render style because making it work as alpha texture is impractical. -{ - Canvas = new DCanvas (Width, Height, false); - - if (Width != Height || Width != Canvas->GetPitch()) - { - Pixels = new uint8_t[Width*Height]; - bPixelsAllocated = true; - } - else - { - Pixels = (uint8_t*)Canvas->GetPixels(); - bPixelsAllocated = false; - } - - // Draw a special "unrendered" initial texture into the buffer. - memset (Pixels, 0, Width*Height/2); - memset (Pixels+Width*Height/2, 255, Width*Height/2); -} -#endif - -void FCanvasTexture::MakeTextureBgra() -{ - CanvasBgra = new DCanvas(Width, Height, true); - - if (Width != Height || Width != CanvasBgra->GetPitch()) - { - PixelsBgra = new uint32_t[Width*Height]; - bPixelsAllocatedBgra = true; - } - else - { - PixelsBgra = (uint32_t*)CanvasBgra->GetPixels(); - bPixelsAllocatedBgra = false; - } - - // Draw a special "unrendered" initial texture into the buffer. - memset(PixelsBgra, 0, Width*Height / 2 * 4); - memset(PixelsBgra + Width*Height / 2, 255, Width*Height / 2 * 4); -} - -#if 0 -void FCanvasTexture::Unload () -{ - if (bPixelsAllocated) - { - if (Pixels != NULL) delete[] Pixels; - bPixelsAllocated = false; - Pixels = NULL; - } - - if (bPixelsAllocatedBgra) - { - if (PixelsBgra != NULL) delete[] PixelsBgra; - bPixelsAllocatedBgra = false; - PixelsBgra = NULL; - } - - if (Canvas != NULL) - { - delete Canvas; - Canvas = nullptr; - } - - if (CanvasBgra != NULL) - { - delete CanvasBgra; - CanvasBgra = nullptr; - } - - FTexture::Unload(); -} -#endif - -bool FCanvasTexture::CheckModified (FRenderStyle) -{ - if (bDidUpdate) - { - bDidUpdate = false; - return true; - } - return false; -} diff --git a/src/textures/image.cpp b/src/textures/image.cpp index c08ef0931c..04d0833c0e 100644 --- a/src/textures/image.cpp +++ b/src/textures/image.cpp @@ -225,20 +225,20 @@ FBitmap FImageSource::GetCachedBitmap(PalEntry *remap, int conversion, int *ptra trans = cache->TransInfo; if (cache->RefCount > 1) { - Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); + //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); ret.Copy(cache->Pixels, false); cache->RefCount--; } else if (cache->Pixels.GetPixels()) { - Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); + //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); ret = std::move(cache->Pixels); precacheDataRgba.Delete(index); } else { // This should never happen if the function is implemented correctly - Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); + //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); ret.Create(Width, Height); trans = CopyPixels(&ret, normal); } @@ -250,13 +250,13 @@ FBitmap FImageSource::GetCachedBitmap(PalEntry *remap, int conversion, int *ptra if (!info || info->first <= 1 || conversion != normal) { // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. - Printf("returning fresh copy of %s\n", name.GetChars()); + //Printf("returning fresh copy of %s\n", name.GetChars()); ret.Create(Width, Height); trans = CopyPixels(&ret, conversion); } else { - Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->first); + //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->first); // This is the first time it gets accessed and needs to be placed in the cache. PrecacheDataRgba *pdr = &precacheDataRgba[precacheDataRgba.Reserve(1)]; diff --git a/src/textures/imagehelpers.h b/src/textures/imagehelpers.h index 16b5e1876f..39cd83e67c 100644 --- a/src/textures/imagehelpers.h +++ b/src/textures/imagehelpers.h @@ -104,7 +104,7 @@ namespace ImageHelpers { for (int i = 0; i < x; ++i) { - uint8_t *corner = block + x*i + i; + T *corner = block + x*i + i; int count = x - i; for (int j = 0; j < count; j++) { diff --git a/src/textures/textures.h b/src/textures/textures.h index 56a90608bf..c5249cd151 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -392,9 +392,6 @@ protected: } } - // Returns true if GetPixelsBgra includes mipmaps - virtual bool Mipmapped() { return true; } - void SetSpeed(float fac) { shaderspeed = fac; } int GetWidth () { return Width; } @@ -673,34 +670,27 @@ class AActor; class FCanvasTexture : public FTexture { public: - FCanvasTexture (const char *name, int width, int height); + FCanvasTexture(const char *name, int width, int height) + { + Name = name; + Width = width; + Height = height; - //const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out); - //const uint32_t *GetPixelsBgra() override; + bMasked = false; + bHasCanvas = true; + bTranslucent = false; + UseType = ETextureType::Wall; + } - //const uint8_t *Get8BitPixels(bool alphatex); - bool CheckModified (FRenderStyle) /*override*/; - void NeedUpdate() { bNeedsUpdate=true; } - void SetUpdated() { bNeedsUpdate = false; bDidUpdate = true; bFirstUpdate = false; } - DCanvas *GetCanvas() { return Canvas; } - DCanvas *GetCanvasBgra() { return CanvasBgra; } - bool Mipmapped() override { return false; } - void MakeTextureBgra (); + void NeedUpdate() { bNeedsUpdate = true; } + void SetUpdated(bool rendertype) { bNeedsUpdate = false; bFirstUpdate = false; bLastUpdateType = rendertype; } protected: - DCanvas *Canvas = nullptr; - DCanvas *CanvasBgra = nullptr; - uint8_t *Pixels = nullptr; - uint32_t *PixelsBgra = nullptr; - //FSoftwareTextureSpan DummySpans[2]; + bool bLastUpdateType = false; bool bNeedsUpdate = true; - bool bDidUpdate = false; - bool bPixelsAllocated = false; - bool bPixelsAllocatedBgra = false; public: - bool bFirstUpdate; - + bool bFirstUpdate = true; friend struct FCanvasTextureInfo; }; diff --git a/src/v_framebuffer.cpp b/src/v_framebuffer.cpp index dd697d9433..43204c8bea 100644 --- a/src/v_framebuffer.cpp +++ b/src/v_framebuffer.cpp @@ -359,11 +359,6 @@ uint32_t DFrameBuffer::GetCaps() return (uint32_t)FlagSet; } -void DFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - SWRenderer->RenderTextureView(tex, Viewpoint, FOV); -} - void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) { SWRenderer->WriteSavePic(player, file, width, height); diff --git a/src/v_video.h b/src/v_video.h index 918c572e36..bdf556edd3 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -318,9 +318,6 @@ class FUniquePalette; class IHardwareTexture; class FTexture; -// A canvas that represents the actual display. The video code is responsible -// for actually implementing this. Built on top of SimpleCanvas, because it -// needs a system memory buffer when buffered output is enabled. class DFrameBuffer { @@ -472,7 +469,6 @@ public: void InitPalette(); void SetClearColor(int color); virtual uint32_t GetCaps(); - virtual void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height); virtual sector_t *RenderView(player_t *player) { return nullptr; }