Browse Source

Overhaul backbuffer state handling

When rendering directly to the output buffer, we need to maintain the
state of what has been drawn and what needs redrawing per-buffer.

We previously tried to do it implicitly by checking `SDL_DOUBLEBUF` and
other flags. The previous implementation was broken in several
ways, resulting in rendering issues on devices that support 8-bit output
directly.

Changes this mechanism to explicitly maintain buffer state per output
buffer. The new mechanism doesn't require knowledge of the number of
buffers, and thus also works correctly with triple-buffering.

Fixes #5447
pull/5458/head
Gleb Mazovetskiy 3 years ago
parent
commit
680ab5ec40
  1. 1
      Source/CMakeLists.txt
  2. 13
      Source/DiabloUI/progress.cpp
  3. 3
      Source/capture.cpp
  4. 32
      Source/control.cpp
  5. 3
      Source/control.h
  6. 3
      Source/cursor.cpp
  7. 7
      Source/debug.cpp
  8. 34
      Source/diablo.cpp
  9. 1
      Source/diablo.h
  10. 98
      Source/engine/backbuffer_state.cpp
  11. 40
      Source/engine/backbuffer_state.hpp
  12. 2
      Source/engine/dx.h
  13. 3
      Source/engine/palette.cpp
  14. 170
      Source/engine/render/scrollrt.cpp
  15. 11
      Source/gamemenu.cpp
  16. 7
      Source/init.cpp
  17. 12
      Source/interfac.cpp
  18. 8
      Source/inv.cpp
  19. 1
      Source/inv.h
  20. 37
      Source/items.cpp
  21. 15
      Source/missiles.cpp
  22. 5
      Source/movie.cpp
  23. 5
      Source/msg.cpp
  24. 45
      Source/objects.cpp
  25. 3
      Source/panels/spell_book.cpp
  26. 5
      Source/panels/spell_list.cpp
  27. 33
      Source/player.cpp
  28. 13
      Source/spells.cpp
  29. 5
      Source/stores.cpp
  30. 14
      Source/utils/display.cpp
  31. 2
      Source/utils/display.h

1
Source/CMakeLists.txt

@ -96,6 +96,7 @@ set(libdevilutionx_SRCS
engine/actor_position.cpp
engine/animationinfo.cpp
engine/assets.cpp
engine/backbuffer_state.cpp
engine/direction.cpp
engine/dx.cpp
engine/load_cel.cpp

13
Source/DiabloUI/progress.cpp

@ -96,14 +96,19 @@ bool UiProgressDialog(int (*fnfunc)())
// Blit the background once and then free it.
ProgressLoadBackground();
ProgressRenderBackground();
if (RenderDirectlyToOutputSurface && IsDoubleBuffered()) {
// Blit twice for triple buffering.
for (unsigned i = 0; i < 2; ++i) {
UiFadeIn();
if (RenderDirectlyToOutputSurface && PalSurface != nullptr) {
// Render into all the backbuffers if there are multiple.
const void *initialPixels = PalSurface->pixels;
UiFadeIn();
while (PalSurface->pixels != initialPixels) {
ProgressRenderBackground();
UiFadeIn();
}
}
ProgressFreeBackground();
ProgressLoadForeground();

3
Source/capture.cpp

@ -8,6 +8,7 @@
#include <fstream>
#include "DiabloUI/diabloui.h"
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "engine/palette.h"
#include "utils/file_util.h"
@ -195,7 +196,7 @@ void CaptureScreen()
system_palette[i] = palette[i];
}
palette_update();
force_redraw = 255;
RedrawEverything();
}
} // namespace devilution

32
Source/control.cpp

@ -16,6 +16,7 @@
#include "controls/modifier_hints.h"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/load_cel.hpp"
#include "engine/render/clx_render.hpp"
@ -57,18 +58,10 @@
namespace devilution {
/**
* @brief Set if the life flask needs to be redrawn during next frame
*/
bool drawhpflag;
bool dropGoldFlag;
bool chrbtn[4];
bool lvlbtndown;
int dropGoldValue;
/**
* @brief Set if the mana flask needs to be redrawn during the next frame
*/
bool drawmanaflag;
bool chrbtnactive;
UiFlags InfoColor;
int sbooktab;
@ -76,7 +69,6 @@ int8_t initialDropGoldIndex;
bool talkflag;
bool sbookflag;
bool chrflag;
bool drawbtnflag;
StringOrView InfoString;
bool panelflag;
int initialDropGoldValue;
@ -251,7 +243,7 @@ void DrawFlaskLower(const Surface &out, const Surface &sourceBuffer, int offset,
void SetButtonStateDown(int btnId)
{
PanelButtons[btnId] = true;
drawbtnflag = true;
RedrawComponent(PanelDrawComponent::ControlButtons);
panbtndown = true;
}
@ -703,8 +695,8 @@ void InitControlPan()
buttonEnabled = false;
chrbtnactive = false;
InfoString = {};
drawhpflag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Health);
RedrawComponent(PanelDrawComponent::Mana);
chrflag = false;
spselflag = false;
sbooktab = 0;
@ -758,7 +750,7 @@ void ClearPanBtn()
{
for (bool &panelButton : PanelButtons)
panelButton = false;
drawbtnflag = true;
RedrawComponent(PanelDrawComponent::ControlButtons);
panbtndown = false;
}
@ -772,7 +764,7 @@ void DoPanBtn()
if (MousePosition.x >= PanBtnPos[i].x + mainPanelPosition.x && MousePosition.x <= x) {
if (MousePosition.y >= PanBtnPos[i].y + mainPanelPosition.y && MousePosition.y <= y) {
PanelButtons[i] = true;
drawbtnflag = true;
RedrawComponent(PanelDrawComponent::ControlButtons);
panbtndown = true;
}
}
@ -782,7 +774,7 @@ void DoPanBtn()
Player &myPlayer = *MyPlayer;
myPlayer._pRSpell = SPL_INVALID;
myPlayer._pRSplType = RSPLTYPE_INVALID;
force_redraw = 255;
RedrawEverything();
return;
}
DoSpeedBook();
@ -889,7 +881,7 @@ void CheckBtnUp()
bool gamemenuOff = true;
const Point mainPanelPosition = GetMainPanel().position;
drawbtnflag = true;
RedrawComponent(PanelDrawComponent::ControlButtons);
panbtndown = false;
for (int i = 0; i < 8; i++) {
@ -1223,8 +1215,6 @@ void DrawTalkPan(const Surface &out)
if (!talkflag)
return;
force_redraw = 255;
const Point mainPanelPosition = GetMainPanel().position;
DrawPanelBox(out, MakeSdlRect(175, sgbPlrTalkTbl + 20, 294, 5), mainPanelPosition + Displacement { 175, 4 });
@ -1329,7 +1319,7 @@ void control_type_message()
if (!IsChatAvailable())
return;
talkflag = true;
RedrawComponent(PanelDrawComponent::ChatInput);
SDL_Rect rect = MakeSdlRect(GetMainPanel().position.x + 200, GetMainPanel().position.y + 22, 250, 39);
SDL_SetTextInputRect(&rect);
TalkMessage[0] = '\0';
@ -1337,7 +1327,7 @@ void control_type_message()
talkButtonDown = false;
}
sgbPlrTalkTbl = GetMainPanel().size.height + 16;
force_redraw = 255;
RedrawEverything();
TalkSaveIndex = NextTalkSave;
SDL_StartTextInput();
}
@ -1347,7 +1337,7 @@ void control_reset_talk()
talkflag = false;
SDL_StopTextInput();
sgbPlrTalkTbl = 0;
force_redraw = 255;
RedrawEverything();
}
bool IsTalkActive()

3
Source/control.h

@ -32,12 +32,10 @@ namespace devilution {
constexpr Size SidePanelSize { 320, 352 };
extern bool drawhpflag;
extern bool dropGoldFlag;
extern bool chrbtn[4];
extern bool lvlbtndown;
extern int dropGoldValue;
extern bool drawmanaflag;
extern bool chrbtnactive;
extern UiFlags InfoColor;
extern int sbooktab;
@ -45,7 +43,6 @@ extern int8_t initialDropGoldIndex;
extern bool talkflag;
extern bool sbookflag;
extern bool chrflag;
extern bool drawbtnflag;
extern StringOrView InfoString;
extern bool panelflag;
extern int initialDropGoldValue;

3
Source/cursor.cpp

@ -12,6 +12,7 @@
#include "controls/plrctrls.h"
#include "doom.h"
#include "engine.h"
#include "engine/backbuffer_state.hpp"
#include "engine/load_cel.hpp"
#include "engine/point.hpp"
#include "engine/render/clx_render.hpp"
@ -381,7 +382,7 @@ void CheckCursMove()
ObjectUnderCursor = nullptr;
pcursitem = -1;
if (pcursinvitem != -1) {
drawsbarflag = true;
RedrawComponent(PanelDrawComponent::Belt);
}
pcursinvitem = -1;
pcursstashitem = uint16_t(-1);

7
Source/debug.cpp

@ -14,6 +14,7 @@
#include "automap.h"
#include "control.h"
#include "cursor.h"
#include "engine/backbuffer_state.hpp"
#include "engine/load_cel.hpp"
#include "engine/point.hpp"
#include "error.h"
@ -550,8 +551,8 @@ std::string DebugCmdRefillHealthMana(const string_view parameter)
Player &myPlayer = *MyPlayer;
myPlayer.RestoreFullLife();
myPlayer.RestoreFullMana();
drawhpflag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Health);
RedrawComponent(PanelDrawComponent::Mana);
return "Ready for more.";
}
@ -589,7 +590,7 @@ std::string DebugCmdChangeMana(const string_view parameter)
int newMana = myPlayer._pMana + (change * 64);
myPlayer._pMana = newMana;
myPlayer._pManaBase = myPlayer._pMana + myPlayer._pMaxManaBase - myPlayer._pMaxMana;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
return "Mana has changed.";
}

34
Source/diablo.cpp

@ -25,6 +25,7 @@
#include "discord/discord.h"
#include "doom.h"
#include "encrypt.h"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/demomode.h"
#include "engine/dx.h"
@ -105,7 +106,6 @@ bool ReturnToMainMenu;
bool gbProcessPlayers;
bool gbLoadGame;
bool cineflag;
int force_redraw;
int PauseMode;
bool gbBard;
bool gbBarbarian;
@ -202,7 +202,7 @@ bool ProcessInput()
plrctrls_every_frame();
if (!gbIsMultiplayer && gmenu_is_active()) {
force_redraw |= 1;
RedrawViewport();
return false;
}
@ -704,7 +704,7 @@ void GameEventHandler(const SDL_Event &event, uint16_t modState)
LastMouseButtonAction = MouseActionType::None;
sgbMouseDown = CLICK_NONE;
ShowProgress(GetCustomEvent(event.type));
force_redraw = 255;
RedrawEverything();
DrawAndBlit();
LoadPWaterPalette();
if (gbRunGame)
@ -730,11 +730,20 @@ void RunGameLoop(interface_mode uMsg)
gbRunGame = true;
gbProcessPlayers = true;
gbRunGameResult = true;
force_redraw = 255;
DrawAndBlit();
RedrawEverything();
if (!HeadlessMode) {
while (IsRedrawEverything()) {
// In direct rendering mode with double/triple buffering, we need
// to prepare all buffers before fading in.
DrawAndBlit();
}
}
LoadPWaterPalette();
PaletteFadeIn(8);
force_redraw = 255;
InitBackbufferState();
RedrawEverything();
gbGameLoopStartup = true;
nthread_ignore_mutex(false);
@ -780,7 +789,7 @@ void RunGameLoop(interface_mode uMsg)
ProcessInput();
if (!drawGame)
continue;
force_redraw |= 1;
RedrawViewport();
DrawAndBlit();
continue;
}
@ -807,7 +816,7 @@ void RunGameLoop(interface_mode uMsg)
PaletteFadeOut(8);
NewCursor(CURSOR_NONE);
ClearScreenBuffer();
force_redraw = 255;
RedrawEverything();
scrollrt_draw_game_screen();
previousHandler = SetEventHandler(previousHandler);
assert(HeadlessMode || previousHandler == GameEventHandler);
@ -1324,7 +1333,7 @@ void GameLogic()
sound_update();
CheckTriggers();
CheckQuests();
force_redraw |= 1;
RedrawViewport();
pfile_update(false);
plrctrls_after_game_logic();
@ -1340,7 +1349,7 @@ void TimeoutCursor(bool bTimeout)
AddPanelString(_("-- Network timeout --"));
AddPanelString(_("-- Waiting for players --"));
NewCursor(CURSOR_HOURGLASS);
force_redraw = 255;
RedrawEverything();
}
scrollrt_draw_game_screen();
} else if (sgnTimeoutCurs != CURSOR_NONE) {
@ -1351,7 +1360,7 @@ void TimeoutCursor(bool bTimeout)
NewCursor(sgnTimeoutCurs);
sgnTimeoutCurs = CURSOR_NONE;
InfoString = {};
force_redraw = 255;
RedrawEverything();
}
}
@ -2427,7 +2436,7 @@ void diablo_pause_game()
LastMouseButtonAction = MouseActionType::None;
}
force_redraw = 255;
RedrawEverything();
}
}
@ -2584,7 +2593,6 @@ void LoadGameLevel(bool firstflag, lvl_entry lvldir)
if (firstflag) {
CloseInventory();
drawsbarflag = false;
qtextflag = false;
if (!HeadlessMode) {
InitInv();

1
Source/diablo.h

@ -66,7 +66,6 @@ extern bool ReturnToMainMenu;
extern bool gbProcessPlayers;
extern DVL_API_FOR_TEST bool gbLoadGame;
extern bool cineflag;
extern int force_redraw;
/* These are defined in fonts.h */
extern void FontsCleanup();
extern DVL_API_FOR_TEST int PauseMode;

98
Source/engine/backbuffer_state.cpp

@ -0,0 +1,98 @@
#include "engine/backbuffer_state.hpp"
#include <unordered_map>
#include "engine/dx.h"
#include "utils/enum_traits.h"
namespace devilution {
namespace {
struct RedrawState {
enum {
RedrawNone,
RedrawViewportOnly,
RedrawAll
} Redraw;
std::array<bool, enum_size<PanelDrawComponent>::value> redrawComponents;
};
struct BackbufferState {
RedrawState redrawState;
DrawnCursor cursor;
};
std::unordered_map<void *, BackbufferState> States;
BackbufferState &GetBackbufferState()
{
// `PalSurface` is null in headless mode.
void *ptr = PalSurface != nullptr ? PalSurface->pixels : nullptr;
auto result = States.emplace(std::piecewise_construct, std::forward_as_tuple(ptr), std::forward_as_tuple());
BackbufferState &state = result.first->second;
if (result.second)
state.redrawState.Redraw = RedrawState::RedrawAll;
return state;
}
} // namespace
bool IsRedrawEverything()
{
return GetBackbufferState().redrawState.Redraw == RedrawState::RedrawAll;
}
void RedrawViewport()
{
for (auto &&it : States) {
if (it.second.redrawState.Redraw != RedrawState::RedrawAll) {
it.second.redrawState.Redraw = RedrawState::RedrawViewportOnly;
}
}
}
bool IsRedrawViewport()
{
return GetBackbufferState().redrawState.Redraw == RedrawState::RedrawViewportOnly;
}
void RedrawComplete()
{
GetBackbufferState().redrawState.Redraw = RedrawState::RedrawNone;
}
void RedrawEverything()
{
for (auto &&it : States) {
it.second.redrawState.Redraw = RedrawState::RedrawAll;
}
}
void InitBackbufferState()
{
States.clear();
}
void RedrawComponent(PanelDrawComponent component)
{
for (auto &&it : States) {
it.second.redrawState.redrawComponents[static_cast<size_t>(component)] = true;
}
}
bool IsRedrawComponent(PanelDrawComponent component)
{
return GetBackbufferState().redrawState.redrawComponents[static_cast<size_t>(component)];
}
void RedrawComponentComplete(PanelDrawComponent component)
{
GetBackbufferState().redrawState.redrawComponents[static_cast<size_t>(component)] = false;
}
DrawnCursor &GetDrawnCursor()
{
return GetBackbufferState().cursor;
}
} // namespace devilution

40
Source/engine/backbuffer_state.hpp

@ -0,0 +1,40 @@
#pragma once
#include <cstdint>
#include "engine/rectangle.hpp"
#include "engine/surface.hpp"
namespace devilution {
enum class PanelDrawComponent {
Health,
Mana,
ControlButtons,
Belt,
ChatInput,
FIRST = Health,
LAST = ChatInput
};
struct DrawnCursor {
Rectangle rect;
uint8_t behindBuffer[8192];
};
void InitBackbufferState();
void RedrawEverything();
bool IsRedrawEverything();
void RedrawViewport();
bool IsRedrawViewport();
void RedrawComplete();
void RedrawComponent(PanelDrawComponent component);
bool IsRedrawComponent(PanelDrawComponent component);
void RedrawComponentComplete(PanelDrawComponent component);
DrawnCursor &GetDrawnCursor();
} // namespace devilution

2
Source/engine/dx.h

@ -12,6 +12,8 @@ namespace devilution {
/** Whether we render directly to the screen surface, i.e. `PalSurface == GetOutputSurface()` */
extern bool RenderDirectlyToOutputSurface;
extern SDL_Surface *PalSurface;
Surface GlobalBackBuffer();
void dx_init();

3
Source/engine/palette.cpp

@ -7,6 +7,7 @@
#include <fmt/compile.h>
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "engine/load_file.hpp"
#include "engine/random.hpp"
@ -195,7 +196,7 @@ void ApplyGamma(SDL_Color *dst, const SDL_Color *src, int n)
dst[i].g = static_cast<Uint8>(pow(src[i].g / 256.0, g) * 256.0);
dst[i].b = static_cast<Uint8>(pow(src[i].b / 256.0, g) * 256.0);
}
force_redraw = 255;
RedrawEverything();
}
void palette_init()

170
Source/engine/render/scrollrt.cpp

@ -11,6 +11,7 @@
#include "cursor.h"
#include "dead.h"
#include "doom.h"
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "engine/render/clx_render.hpp"
#include "engine/render/dun_render.hpp"
@ -91,6 +92,7 @@ extern void DrawControllerModifierHints(const Surface &out);
bool frameflag;
namespace {
/**
* @brief Hash algorithm for point
*/
@ -186,21 +188,6 @@ void UpdateMissilesRendererData()
}
}
uint32_t sgdwCursWdtOld;
int sgdwCursX;
int sgdwCursY;
/**
* Lower bound of back buffer.
*/
uint32_t sgdwCursHgt;
int sgdwCursXOld;
int sgdwCursYOld;
uint32_t sgdwCursWdt;
uint8_t sgSaveBack[8192];
uint32_t sgdwCursHgtOld;
/**
* @brief Keeps track of which tiles have been rendered already.
*/
@ -223,10 +210,12 @@ const char *const PlayerModeNames[] = {
"quitting"
};
void BlitCursor(uint8_t *dst, std::uint32_t dstPitch, uint8_t *src, std::uint32_t srcPitch)
Rectangle PrevCursorRect;
void BlitCursor(uint8_t *dst, uint32_t dstPitch, uint8_t *src, uint32_t srcPitch, uint32_t srcWidth, uint32_t srcHeight)
{
for (std::uint32_t i = 0; i < sgdwCursHgt; ++i, src += srcPitch, dst += dstPitch) {
memcpy(dst, src, sgdwCursWdt);
for (std::uint32_t i = 0; i < srcHeight; ++i, src += srcPitch, dst += dstPitch) {
memcpy(dst, src, srcWidth);
}
}
@ -235,17 +224,9 @@ void BlitCursor(uint8_t *dst, std::uint32_t dstPitch, uint8_t *src, std::uint32_
*/
void UndrawCursor(const Surface &out)
{
if (sgdwCursWdt == 0) {
return;
}
BlitCursor(out.at(sgdwCursX, sgdwCursY), out.pitch(), sgSaveBack, sgdwCursWdt);
sgdwCursXOld = sgdwCursX;
sgdwCursYOld = sgdwCursY;
sgdwCursWdtOld = sgdwCursWdt;
sgdwCursHgtOld = sgdwCursHgt;
sgdwCursWdt = 0;
DrawnCursor &cursor = GetDrawnCursor();
BlitCursor(&out[cursor.rect.position], out.pitch(), cursor.behindBuffer, cursor.rect.size.width, cursor.rect.size.width, cursor.rect.size.height);
PrevCursorRect = cursor.rect;
}
bool ShouldShowCursor()
@ -267,23 +248,23 @@ bool ShouldShowCursor()
*/
void DrawCursor(const Surface &out)
{
DrawnCursor &cursor = GetDrawnCursor();
if (pcurs <= CURSOR_NONE || !ShouldShowCursor()) {
cursor.rect.size.width = 0;
return;
}
Size cursSize = GetInvItemSize(pcurs);
if (cursSize.width == 0 || cursSize.height == 0) {
cursor.rect.size.width = 0;
return;
}
// Copy the buffer before the item cursor and its 1px outline are drawn to a temporary buffer.
const int outlineWidth = !MyPlayer->HoldItem.isEmpty() ? 1 : 0;
if (MousePosition.x < -cursSize.width - outlineWidth || MousePosition.x - outlineWidth >= out.w() || MousePosition.y < -cursSize.height - outlineWidth || MousePosition.y - outlineWidth >= out.h())
return;
constexpr auto Clip = [](int &pos, std::uint32_t &length, std::uint32_t posEnd) {
if (pos < 0) {
constexpr auto Clip = [](int &pos, int &length, int posEnd) {
if (pos + length <= 0 || pos >= posEnd) {
pos = 0;
length = 0;
} else if (pos < 0) {
length += pos;
pos = 0;
} else if (pos + length > posEnd) {
@ -291,15 +272,22 @@ void DrawCursor(const Surface &out)
}
};
sgdwCursX = MousePosition.x - outlineWidth;
sgdwCursWdt = cursSize.width + 2 * outlineWidth;
Clip(sgdwCursX, sgdwCursWdt, out.w());
// Copy the buffer before the item cursor and its 1px outline are drawn to a temporary buffer.
const int outlineWidth = !MyPlayer->HoldItem.isEmpty() ? 1 : 0;
Rectangle &rect = cursor.rect;
rect.position.x = MousePosition.x - outlineWidth;
rect.size.width = cursSize.width + 2 * outlineWidth;
Clip(rect.position.x, rect.size.width, out.w());
sgdwCursY = MousePosition.y - outlineWidth;
sgdwCursHgt = cursSize.height + 2 * outlineWidth;
Clip(sgdwCursY, sgdwCursHgt, out.h());
rect.position.y = MousePosition.y - outlineWidth;
rect.size.height = cursSize.height + 2 * outlineWidth;
Clip(rect.position.y, rect.size.height, out.h());
BlitCursor(sgSaveBack, sgdwCursWdt, out.at(sgdwCursX, sgdwCursY), out.pitch());
if (rect.size.width == 0 || rect.size.height == 0)
return;
BlitCursor(cursor.behindBuffer, rect.size.width, &out[rect.position], out.pitch(), rect.size.width, rect.size.height);
DrawSoftwareCursor(out, MousePosition + Displacement { 0, cursSize.height - 1 }, pcurs);
}
@ -1058,7 +1046,7 @@ void DrawView(const Surface &out, Point startPosition)
bool debugGridTextNeeded = IsDebugGridTextNeeded();
if (debugGridTextNeeded || DebugGrid) {
// force redrawing or debug stuff stays on panel on 640x480 resolution
force_redraw = 255;
RedrawEverything();
char debugGridTextBuffer[10];
bool megaTiles = IsDebugGridInMegatiles();
@ -1225,7 +1213,8 @@ void DoBlitScreen(Sint16 dwX, Sint16 dwY, Uint16 dwWdt, Uint16 dwHgt)
}
/**
* @brief Check render pipeline and blit individual screen parts
* @brief Check render pipeline and update individual screen parts
* @param out Output surface.
* @param dwHgt Section of screen to update from top to bottom
* @param drawDesc Render info box
* @param drawHp Render health bar
@ -1233,7 +1222,7 @@ void DoBlitScreen(Sint16 dwX, Sint16 dwY, Uint16 dwWdt, Uint16 dwHgt)
* @param drawSbar Render belt
* @param drawBtn Render panel buttons
*/
void DrawMain(int dwHgt, bool drawDesc, bool drawHp, bool drawMana, bool drawSbar, bool drawBtn)
void DrawMain(const Surface &out, int dwHgt, bool drawDesc, bool drawHp, bool drawMana, bool drawSbar, bool drawBtn)
{
if (!gbActive || RenderDirectlyToOutputSurface) {
return;
@ -1267,11 +1256,12 @@ void DrawMain(int dwHgt, bool drawDesc, bool drawHp, bool drawMana, bool drawSba
DoBlitScreen(mainPanelPosition.x + 524, mainPanelPosition.y + 91, 36, 32);
}
}
if (sgdwCursWdtOld != 0) {
DoBlitScreen(sgdwCursXOld, sgdwCursYOld, sgdwCursWdtOld, sgdwCursHgtOld);
if (PrevCursorRect.size.width != 0 && PrevCursorRect.size.height != 0) {
DoBlitScreen(PrevCursorRect.position.x, PrevCursorRect.position.y, PrevCursorRect.size.width, PrevCursorRect.size.height);
}
if (sgdwCursWdt != 0) {
DoBlitScreen(sgdwCursX, sgdwCursY, sgdwCursWdt, sgdwCursHgt);
Rectangle &cursorRect = GetDrawnCursor().rect;
if (cursorRect.size.width != 0 && cursorRect.size.height != 0) {
DoBlitScreen(cursorRect.position.x, cursorRect.position.y, cursorRect.size.width, cursorRect.size.height);
}
}
}
@ -1301,8 +1291,7 @@ Displacement GetOffsetForWalking(const AnimationInfo &animationInfo, const Direc
void ClearCursor() // CODE_FIX: this was supposed to be in cursor.cpp
{
sgdwCursWdt = 0;
sgdwCursWdtOld = 0;
PrevCursorRect = {};
}
void ShiftGrid(int *x, int *y, int horizontal, int vertical)
@ -1510,24 +1499,23 @@ void scrollrt_draw_game_screen()
int hgt = 0;
if (force_redraw == 255) {
force_redraw = 0;
if (IsRedrawEverything()) {
RedrawComplete();
hgt = gnScreenHeight;
}
const Surface &out = GlobalBackBuffer();
UndrawCursor(out);
DrawMain(out, hgt, false, false, false, false, false);
if (IsHardwareCursor()) {
SetHardwareCursorVisible(ShouldShowCursor());
} else {
DrawCursor(GlobalBackBuffer());
DrawCursor(out);
}
DrawMain(hgt, false, false, false, false, false);
RenderPresent();
if (!IsHardwareCursor()) {
UndrawCursor(GlobalBackBuffer());
}
}
void DrawAndBlit()
@ -1537,53 +1525,55 @@ void DrawAndBlit()
}
int hgt = 0;
bool ddsdesc = false;
bool ctrlPan = false;
bool drawHealth = IsRedrawComponent(PanelDrawComponent::Health);
bool drawMana = IsRedrawComponent(PanelDrawComponent::Mana);
bool drawControlButtons = IsRedrawComponent(PanelDrawComponent::ControlButtons);
bool drawBelt = IsRedrawComponent(PanelDrawComponent::Belt);
bool drawChatInput = IsRedrawComponent(PanelDrawComponent::ChatInput);
bool drawInfoBox = false;
bool drawCtrlPan = false;
const Rectangle &mainPanel = GetMainPanel();
if (gnScreenWidth > mainPanel.size.width || force_redraw == 255 || IsHighlightingLabelsEnabled()) {
drawhpflag = true;
drawmanaflag = true;
drawbtnflag = true;
drawsbarflag = true;
ddsdesc = false;
ctrlPan = true;
if (gnScreenWidth > mainPanel.size.width || IsRedrawEverything() || IsHighlightingLabelsEnabled()) {
drawHealth = true;
drawMana = true;
drawControlButtons = true;
drawBelt = true;
drawInfoBox = false;
drawCtrlPan = true;
hgt = gnScreenHeight;
} else if (force_redraw == 1) {
ddsdesc = true;
ctrlPan = false;
} else if (IsRedrawViewport()) {
drawInfoBox = true;
drawCtrlPan = false;
hgt = gnViewportHeight;
}
force_redraw = 0;
const Surface &out = GlobalBackBuffer();
UndrawCursor(out);
nthread_UpdateProgressToNextGameTick();
DrawView(out, ViewPosition);
if (ctrlPan) {
if (drawCtrlPan) {
DrawCtrlPan(out);
}
if (drawhpflag) {
if (drawHealth) {
DrawLifeFlaskLower(out);
}
if (drawmanaflag) {
if (drawMana) {
DrawManaFlaskLower(out);
DrawSpell(out);
}
if (drawbtnflag) {
if (drawControlButtons) {
DrawCtrlBtns(out);
}
if (drawsbarflag) {
if (drawBelt) {
DrawInvBelt(out);
}
if (talkflag) {
if (drawChatInput) {
DrawTalkPan(out);
hgt = gnScreenHeight;
}
DrawXPBar(out);
if (*sgOptions.Graphics.showHealthValues)
@ -1599,14 +1589,16 @@ void DrawAndBlit()
DrawFPS(out);
DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag);
DrawMain(out, hgt, drawInfoBox, drawHealth, drawMana, drawBelt, drawControlButtons);
RenderPresent();
RedrawComplete();
for (PanelDrawComponent component : enum_values<PanelDrawComponent>()) {
if (IsRedrawComponent(component)) {
RedrawComponentComplete(component);
}
}
drawhpflag = false;
drawmanaflag = false;
drawbtnflag = false;
drawsbarflag = false;
RenderPresent();
}
} // namespace devilution

11
Source/gamemenu.cpp

@ -6,6 +6,7 @@
#include "gamemenu.h"
#include "cursor.h"
#include "engine/backbuffer_state.hpp"
#include "engine/sound.h"
#include "engine/sound_defs.hpp"
#include "error.h"
@ -102,7 +103,7 @@ void GamemenuNewGame(bool /*bActivate*/)
MyPlayerIsDead = false;
if (!HeadlessMode) {
force_redraw = 255;
RedrawEverything();
scrollrt_draw_game_screen();
}
CornerStone.activated = false;
@ -293,14 +294,14 @@ void gamemenu_load_game(bool /*bActivate*/)
gamemenu_off();
NewCursor(CURSOR_NONE);
InitDiabloMsg(EMSG_LOADING);
force_redraw = 255;
RedrawEverything();
DrawAndBlit();
LoadGame(false);
ClrDiabloMsg();
CornerStone.activated = false;
PaletteFadeOut(8);
MyPlayerIsDead = false;
force_redraw = 255;
RedrawEverything();
DrawAndBlit();
LoadPWaterPalette();
PaletteFadeIn(8);
@ -324,11 +325,11 @@ void gamemenu_save_game(bool /*bActivate*/)
NewCursor(CURSOR_NONE);
gamemenu_off();
InitDiabloMsg(EMSG_SAVING);
force_redraw = 255;
RedrawEverything();
DrawAndBlit();
SaveGame();
ClrDiabloMsg();
force_redraw = 255;
RedrawEverything();
NewCursor(CURSOR_HAND);
if (CornerStone.activated) {
CornerstoneSave();

7
Source/init.cpp

@ -14,6 +14,7 @@
#include "DiabloUI/diabloui.h"
#include "engine/assets.hpp"
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "hwcursor.hpp"
#include "miniwin/misc_msg.h"
@ -332,10 +333,10 @@ void MainWndProc(const SDL_Event &event)
break;
case SDL_WINDOWEVENT_SHOWN:
gbActive = false;
force_redraw = 255;
RedrawEverything();
break;
case SDL_WINDOWEVENT_EXPOSED:
force_redraw = 255;
RedrawEverything();
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
ReinitializeHardwareCursor();
@ -343,7 +344,7 @@ void MainWndProc(const SDL_Event &event)
case SDL_WINDOWEVENT_LEAVE:
sgbMouseDown = CLICK_NONE;
LastMouseButtonAction = MouseActionType::None;
force_redraw = 255;
RedrawEverything();
break;
case SDL_WINDOWEVENT_CLOSE:
diablo_quit(0);

12
Source/interfac.cpp

@ -293,13 +293,17 @@ void ShowProgress(interface_mode uMsg)
// Blit the background once and then free it.
LoadCutsceneBackground(uMsg);
DrawCutsceneBackground();
if (RenderDirectlyToOutputSurface && IsDoubleBuffered()) {
// Blit twice for triple buffering.
for (unsigned i = 0; i < 2; ++i) {
if (RenderDirectlyToOutputSurface && PalSurface != nullptr) {
// Render into all the backbuffers if there are multiple.
const void *initialPixels = PalSurface->pixels;
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
while (PalSurface->pixels != initialPixels) {
DrawCutsceneBackground();
if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr);
RenderPresent();
DrawCutsceneBackground();
}
}
FreeCutsceneBackground();

8
Source/inv.cpp

@ -11,6 +11,7 @@
#include "DiabloUI/ui_flags.hpp"
#include "controls/plrctrls.h"
#include "cursor.h"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/load_cel.hpp"
#include "engine/render/clx_render.hpp"
@ -37,7 +38,6 @@
namespace devilution {
bool invflag;
bool drawsbarflag;
/**
* Maps from inventory slot to screen position. The inventory slots are
@ -566,7 +566,7 @@ void CheckInvPaste(Player &player, Point cursorPosition)
if (&player == MyPlayer) {
NetSendCmdChBeltItem(false, ii);
}
drawsbarflag = true;
RedrawComponent(PanelDrawComponent::Belt);
} break;
case ILOC_NONE:
case ILOC_INVALID:
@ -1235,7 +1235,7 @@ bool AutoPlaceItemInBelt(Player &player, const Item &item, bool persistItem)
if (persistItem) {
beltItem = item;
player.CalcScrolls();
drawsbarflag = true;
RedrawComponent(PanelDrawComponent::Belt);
if (&player == MyPlayer) {
size_t beltIndex = std::distance<const Item *>(&player.SpdList[0], &beltItem);
NetSendCmdChBeltItem(false, beltIndex);
@ -1907,7 +1907,7 @@ int8_t CheckInvHLight()
pi = &myPlayer.InvList[ii];
} else if (r >= SLOTXY_BELT_FIRST) {
r -= SLOTXY_BELT_FIRST;
drawsbarflag = true;
RedrawComponent(PanelDrawComponent::Belt);
pi = &myPlayer.SpdList[r];
if (pi->isEmpty())
return -1;

1
Source/inv.h

@ -83,7 +83,6 @@ enum item_color : uint8_t {
};
extern bool invflag;
extern bool drawsbarflag;
extern const Point InvRect[73];
void InvDrawSlotBack(const Surface &out, Point targetPosition, Size size, item_quality itemQuality);

37
Source/items.cpp

@ -20,6 +20,7 @@
#include "controls/plrctrls.h"
#include "cursor.h"
#include "doom.h"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/dx.h"
#include "engine/load_cel.hpp"
@ -823,11 +824,11 @@ int SaveItemPower(const Player &player, Item &item, ItemPower &power)
break;
case IPL_MANA:
item._iPLMana += r << 6;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
case IPL_MANA_CURSE:
item._iPLMana -= r << 6;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
case IPL_DUR: {
int bonus = r * item._iMaxDur / 100;
@ -883,7 +884,7 @@ int SaveItemPower(const Player &player, Item &item, ItemPower &power)
break;
case IPL_NOMANA:
item._iFlags |= ItemSpecialEffect::NoMana;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
case IPL_ABSHALFTRAP:
item._iFlags |= ItemSpecialEffect::HalfTrapDamage;
@ -902,14 +903,14 @@ int SaveItemPower(const Player &player, Item &item, ItemPower &power)
item._iFlags |= ItemSpecialEffect::StealMana3;
if (power.param1 == 5)
item._iFlags |= ItemSpecialEffect::StealMana5;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
case IPL_STEALLIFE:
if (power.param1 == 3)
item._iFlags |= ItemSpecialEffect::StealLife3;
if (power.param1 == 5)
item._iFlags |= ItemSpecialEffect::StealLife5;
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
break;
case IPL_TARGAC:
if (gbIsHellfire)
@ -2719,8 +2720,8 @@ void CalcPlrItemVals(Player &player, bool loadgfx)
}
}
drawmanaflag = true;
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Mana);
RedrawComponent(PanelDrawComponent::Health);
}
void CalcPlrInv(Player &player, bool loadgfx)
@ -3813,25 +3814,25 @@ void UseItem(size_t pnum, item_misc_id mid, spell_id spl)
case IMISC_HEAL:
player.RestorePartialLife();
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
break;
case IMISC_FULLHEAL:
player.RestoreFullLife();
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
break;
case IMISC_MANA:
player.RestorePartialMana();
if (&player == MyPlayer) {
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
break;
case IMISC_FULLMANA:
player.RestoreFullMana();
if (&player == MyPlayer) {
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
break;
case IMISC_ELIXSTR:
@ -3842,7 +3843,7 @@ void UseItem(size_t pnum, item_misc_id mid, spell_id spl)
if (gbIsHellfire) {
player.RestoreFullMana();
if (&player == MyPlayer) {
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
}
break;
@ -3854,7 +3855,7 @@ void UseItem(size_t pnum, item_misc_id mid, spell_id spl)
if (gbIsHellfire) {
player.RestoreFullLife();
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
}
break;
@ -3862,16 +3863,16 @@ void UseItem(size_t pnum, item_misc_id mid, spell_id spl)
player.RestorePartialLife();
player.RestorePartialMana();
if (&player == MyPlayer) {
drawhpflag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Health);
RedrawComponent(PanelDrawComponent::Mana);
}
} break;
case IMISC_FULLREJUV:
player.RestoreFullLife();
player.RestoreFullMana();
if (&player == MyPlayer) {
drawhpflag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Health);
RedrawComponent(PanelDrawComponent::Mana);
}
break;
case IMISC_SCROLL:
@ -3910,7 +3911,7 @@ void UseItem(size_t pnum, item_misc_id mid, spell_id spl)
Stash.RefreshItemStatFlags();
}
}
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
case IMISC_MAPOFDOOM:
doom_init();

15
Source/missiles.cpp

@ -14,6 +14,7 @@
#ifdef _DEBUG
#include "debug.h"
#endif
#include "engine/backbuffer_state.hpp"
#include "engine/load_file.hpp"
#include "engine/points_in_rectangle_range.hpp"
#include "engine/random.hpp"
@ -1323,7 +1324,7 @@ void AddStealPotions(Missile &missile, AddMissileParameter & /*parameter*/)
hasPlayedSFX = true;
}
}
force_redraw = 255;
RedrawEverything();
return false;
});
@ -1344,7 +1345,7 @@ void AddManaTrap(Missile &missile, AddMissileParameter & /*parameter*/)
player._pMana = 0;
player._pManaBase = player._pMana + player._pMaxManaBase - player._pMaxMana;
CalcPlrInv(player, false);
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
PlaySfxLoc(TSFX_COW7, *trappedPlayerPosition);
}
@ -1535,7 +1536,7 @@ void AddMana(Missile &missile, AddMissileParameter & /*parameter*/)
if (player._pManaBase > player._pMaxManaBase)
player._pManaBase = player._pMaxManaBase;
missile._miDelFlag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
void AddMagi(Missile &missile, AddMissileParameter & /*parameter*/)
@ -1545,7 +1546,7 @@ void AddMagi(Missile &missile, AddMissileParameter & /*parameter*/)
player._pMana = player._pMaxMana;
player._pManaBase = player._pMaxManaBase;
missile._miDelFlag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
void AddRing(Missile &missile, AddMissileParameter & /*parameter*/)
@ -2264,7 +2265,7 @@ void AddHeal(Missile &missile, AddMissileParameter & /*parameter*/)
player._pHPBase = std::min(player._pHPBase + hp, player._pMaxHPBase);
missile._miDelFlag = true;
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
void AddHealOther(Missile &missile, AddMissileParameter & /*parameter*/)
@ -2394,7 +2395,7 @@ void AddBlodboil(Missile &missile, AddMissileParameter &parameter)
int lvl = player._pLevel * 2;
missile._mirange = lvl + 10 * missile._mispllvl + 245;
CalcPlrItemVals(player, true);
force_redraw = 255;
RedrawEverything();
player.Say(HeroSpeech::Aaaaargh);
}
@ -3788,7 +3789,7 @@ void MI_Blodboil(Missile &missile)
CalcPlrItemVals(player, true);
ApplyPlrDamage(player, 0, 1, hpdif);
force_redraw = 255;
RedrawEverything();
player.Say(HeroSpeech::HeavyBreathing);
}

5
Source/movie.cpp

@ -7,6 +7,7 @@
#include "controls/plrctrls.h"
#include "diablo.h"
#include "effects.h"
#include "engine/backbuffer_state.hpp"
#include "engine/demomode.h"
#include "engine/sound.h"
#include "hwcursor.hpp"
@ -74,10 +75,10 @@ void PlayInGameMovie(const char *pszMovie)
PaletteFadeOut(8);
play_movie(pszMovie, false);
ClearScreenBuffer();
force_redraw = 255;
RedrawEverything();
scrollrt_draw_game_screen();
PaletteFadeIn(8);
force_redraw = 255;
RedrawEverything();
}
} // namespace devilution

5
Source/msg.cpp

@ -16,6 +16,7 @@
#include "control.h"
#include "dead.h"
#include "encrypt.h"
#include "engine/backbuffer_state.hpp"
#include "engine/random.hpp"
#include "engine/world_tile.hpp"
#include "gamemenu.h"
@ -2235,7 +2236,7 @@ size_t OnString(const TCmd *pCmd, Player &player)
size_t OnFriendlyMode(const TCmd *pCmd, Player &player) // NOLINT(misc-unused-parameters)
{
player.friendlyMode = !player.friendlyMode;
force_redraw = 255;
RedrawEverything();
return sizeof(*pCmd);
}
@ -2262,7 +2263,7 @@ size_t OnCheatExperience(const TCmd *pCmd, size_t pnum) // NOLINT(misc-unused-pa
else if (Players[pnum]._pLevel < MaxCharacterLevel) {
Players[pnum]._pExperience = Players[pnum]._pNextExper;
if (*sgOptions.Gameplay.experienceBar) {
force_redraw = 255;
RedrawEverything();
}
NextPlrLevel(Players[pnum]);
}

45
Source/objects.cpp

@ -17,6 +17,7 @@
#ifdef _DEBUG
#include "debug.h"
#endif
#include "engine/backbuffer_state.hpp"
#include "engine/load_cel.hpp"
#include "engine/load_file.hpp"
#include "engine/points_in_rectangle_range.hpp"
@ -2289,7 +2290,7 @@ void OperateShrineMysterious(Player &player)
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_MYSTERIOUS);
}
@ -2432,7 +2433,7 @@ void OperateShrineStone(Player &player)
item._iCharges = item._iMaxCharges;
}
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_STONE);
}
@ -2530,7 +2531,7 @@ void OperateShrineCostOfWisdom(Player &player, spell_id spellId, diablo_message
player._pMaxManaBase = 0;
}
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(message);
}
@ -2555,7 +2556,7 @@ void OperateShrineCryptic(Player &player)
InitDiabloMsg(EMSG_SHRINE_CRYPTIC);
force_redraw = 255;
RedrawEverything();
}
void OperateShrineEldritch(Player &player)
@ -2586,7 +2587,7 @@ void OperateShrineEldritch(Player &player)
}
}
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_ELDRITCH);
}
@ -2599,7 +2600,7 @@ void OperateShrineEerie(Player &player)
ModifyPlrMag(player, 2);
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_EERIE);
}
@ -2628,7 +2629,7 @@ void OperateShrineDivine(Player &player, Point spawnPosition)
player._pHitPoints = player._pMaxHP;
player._pHPBase = player._pMaxHPBase;
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_DIVINE);
}
@ -2676,7 +2677,7 @@ void OperateShrineSpooky(const Player &player)
myPlayer._pMana = myPlayer._pMaxMana;
myPlayer._pManaBase = myPlayer._pMaxManaBase;
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_SPOOKY2);
}
@ -2689,7 +2690,7 @@ void OperateShrineAbandoned(Player &player)
ModifyPlrDex(player, 2);
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_ABANDONED);
}
@ -2702,7 +2703,7 @@ void OperateShrineCreepy(Player &player)
ModifyPlrStr(player, 2);
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_CREEPY);
}
@ -2715,7 +2716,7 @@ void OperateShrineQuiet(Player &player)
ModifyPlrVit(player, 2);
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_QUIET);
}
@ -2744,7 +2745,7 @@ void OperateShrineGlimmering(Player &player)
}
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_GLIMMERING);
}
@ -2772,7 +2773,7 @@ void OperateShrineTainted(const Player &player)
CheckStats(myPlayer);
CalcPlrInv(myPlayer, true);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_TAINTED2);
}
@ -2813,7 +2814,7 @@ void OperateShrineOily(Player &player, Point spawnPosition)
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
AddMissile(
spawnPosition,
@ -2843,7 +2844,7 @@ void OperateShrineGlowing(Player &player)
player._pExperience = 0;
CheckStats(player);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_GLOWING);
}
@ -2857,7 +2858,7 @@ void OperateShrineMendicant(Player &player)
AddPlrExperience(player, player._pLevel, gold);
TakePlrsMoney(gold);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_MENDICANT);
}
@ -2884,7 +2885,7 @@ void OperateShrineSparkling(Player &player, Point spawnPosition)
3 * currlevel + 2,
0);
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_SPARKLING);
}
@ -2920,7 +2921,7 @@ void OperateShrineShimmering(Player &player)
player._pMana = player._pMaxMana;
player._pManaBase = player._pMaxManaBase;
force_redraw = 255;
RedrawEverything();
InitDiabloMsg(EMSG_SHRINE_SHIMMERING);
}
@ -2949,7 +2950,7 @@ void OperateShrineSolar(Player &player)
CheckStats(player);
CalcPlrInv(player, true);
force_redraw = 255;
RedrawEverything();
}
void OperateShrineMurphys(Player &player)
@ -3200,7 +3201,7 @@ void OperateGoatShrine(Player &player, Object &object, _sfx_id sType)
object._oVar1 = FindValidShrine();
OperateShrine(player, object, sType);
object._oAnimDelay = 2;
force_redraw = 255;
RedrawEverything();
}
void OperateCauldron(Player &player, Object &object, _sfx_id sType)
@ -3210,7 +3211,7 @@ void OperateCauldron(Player &player, Object &object, _sfx_id sType)
OperateShrine(player, object, sType);
object._oAnimFrame = 3;
object._oAnimFlag = false;
force_redraw = 255;
RedrawEverything();
}
bool OperateFountains(Player &player, Object &fountain)
@ -3309,7 +3310,7 @@ bool OperateFountains(Player &player, Object &fountain)
default:
break;
}
force_redraw = 255;
RedrawEverything();
return applied;
}

3
Source/panels/spell_book.cpp

@ -3,6 +3,7 @@
#include <fmt/format.h>
#include "control.h"
#include "engine/backbuffer_state.hpp"
#include "engine/clx_sprite.hpp"
#include "engine/load_cel.hpp"
#include "engine/rectangle.hpp"
@ -202,7 +203,7 @@ void CheckSBook()
}
player._pRSpell = sn;
player._pRSplType = st;
force_redraw = 255;
RedrawEverything();
}
return;
}

5
Source/panels/spell_list.cpp

@ -4,6 +4,7 @@
#include "control.h"
#include "engine.h"
#include "engine/backbuffer_state.hpp"
#include "engine/palette.h"
#include "engine/render/text_render.hpp"
#include "inv_iterators.hpp"
@ -280,7 +281,7 @@ void SetSpell()
myPlayer._pRSpell = pSpell;
myPlayer._pRSplType = pSplType;
force_redraw = 255;
RedrawEverything();
}
void SetSpeedSpell(size_t slot)
@ -331,7 +332,7 @@ void ToggleSpell(size_t slot)
if ((spells & GetSpellBitmask(spellId)) != 0) {
myPlayer._pRSpell = spellId;
myPlayer._pRSplType = myPlayer._pSplTHotKey[slot];
force_redraw = 255;
RedrawEverything();
}
}

33
Source/player.cpp

@ -16,6 +16,7 @@
#ifdef _DEBUG
#include "debug.h"
#endif
#include "engine/backbuffer_state.hpp"
#include "engine/load_cl2.hpp"
#include "engine/load_file.hpp"
#include "engine/points_in_rectangle_range.hpp"
@ -841,7 +842,7 @@ bool PlrHitMonst(Player &player, Monster &monster, bool adjacentDamage = false)
if (player._pHPBase > player._pMaxHPBase) {
player._pHPBase = player._pMaxHPBase;
}
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
if (HasAnyOf(player._pIFlags, ItemSpecialEffect::StealMana3 | ItemSpecialEffect::StealMana5) && HasNoneOf(player._pIFlags, ItemSpecialEffect::NoMana)) {
if (HasAnyOf(player._pIFlags, ItemSpecialEffect::StealMana3)) {
@ -858,7 +859,7 @@ bool PlrHitMonst(Player &player, Monster &monster, bool adjacentDamage = false)
if (player._pManaBase > player._pMaxManaBase) {
player._pManaBase = player._pMaxManaBase;
}
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
if (HasAnyOf(player._pIFlags, ItemSpecialEffect::StealLife3 | ItemSpecialEffect::StealLife5)) {
if (HasAnyOf(player._pIFlags, ItemSpecialEffect::StealLife3)) {
@ -875,7 +876,7 @@ bool PlrHitMonst(Player &player, Monster &monster, bool adjacentDamage = false)
if (player._pHPBase > player._pMaxHPBase) {
player._pHPBase = player._pMaxHPBase;
}
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
#ifdef _DEBUG
if (DebugGodMode) {
@ -947,7 +948,7 @@ bool PlrHitPlr(Player &attacker, Player &target)
if (attacker._pHPBase > attacker._pMaxHPBase) {
attacker._pHPBase = attacker._pMaxHPBase;
}
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
if (&attacker == MyPlayer) {
NetSendCmdDamage(true, target.getId(), skdam);
@ -1630,7 +1631,7 @@ void ValidatePlayer()
if (myPlayer._pExperience > myPlayer._pNextExper) {
myPlayer._pExperience = myPlayer._pNextExper;
if (*sgOptions.Gameplay.experienceBar) {
force_redraw = 255;
RedrawEverything();
}
}
@ -1828,7 +1829,7 @@ void Player::RemoveSpdBarItem(int iv)
SpdList[iv].clear();
CalcScrolls();
force_redraw = 255;
RedrawEverything();
}
[[nodiscard]] size_t Player::getId() const
@ -1974,7 +1975,7 @@ void Player::ReadySpellFromEquipment(inv_body_loc bodyLocation)
if (item._itype == ItemType::Staff && IsValidSpell(item._iSpell) && item._iCharges > 0) {
_pRSpell = item._iSpell;
_pRSplType = RSPLTYPE_CHARGES;
force_redraw = 255;
RedrawEverything();
}
}
@ -2629,7 +2630,7 @@ void NextPlrLevel(Player &player)
player._pHPBase = player._pMaxHPBase;
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
int mana = 128;
@ -2647,7 +2648,7 @@ void NextPlrLevel(Player &player)
}
if (&player == MyPlayer) {
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
if (ControlMode != ControlTypes::KeyboardAndMouse)
@ -2684,7 +2685,7 @@ void AddPlrExperience(Player &player, int lvl, int exp)
player._pExperience = std::min(player._pExperience + clampedExp, MaxExperience);
if (*sgOptions.Gameplay.experienceBar) {
force_redraw = 255;
RedrawEverything();
}
if (player._pExperience >= ExpLvlsTbl[49]) {
@ -2904,7 +2905,7 @@ void StartPlrHit(Player &player, int dam, bool forcehit)
player.Say(HeroSpeech::ArghClang);
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
if (player._pClass == HeroClass::Barbarian) {
if (dam >> 6 < player._pLevel + player._pLevel / 4 && !forcehit) {
return;
@ -2986,7 +2987,7 @@ StartPlayerKill(Player &player, int earflag)
SetPlayerOld(player);
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
if (!player.HoldItem.isEmpty()) {
DeadItem(player, std::move(player.HoldItem), { 0, 0 });
@ -3066,7 +3067,7 @@ void ApplyPlrDamage(Player &player, int dam, int minHP /*= 0*/, int frac /*= 0*/
totalDamage += totalDamage / -player.GetManaShieldDamageReduction();
}
if (&player == MyPlayer)
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
if (player._pMana >= totalDamage) {
player._pMana -= totalDamage;
player._pManaBase -= totalDamage;
@ -3086,7 +3087,7 @@ void ApplyPlrDamage(Player &player, int dam, int minHP /*= 0*/, int frac /*= 0*/
if (totalDamage == 0)
return;
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
player._pHitPoints -= totalDamage;
player._pHPBase -= totalDamage;
if (player._pHitPoints > player._pMaxHP) {
@ -3274,7 +3275,7 @@ void ProcessPlayers()
if (HasAnyOf(player._pIFlags, ItemSpecialEffect::NoMana) && player._pManaBase > 0) {
player._pManaBase -= player._pMana;
player._pMana = 0;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
}
@ -3633,7 +3634,7 @@ void SetPlayerHitPoints(Player &player, int val)
player._pHPBase = val + player._pMaxHPBase - player._pMaxHP;
if (&player == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
}

13
Source/spells.cpp

@ -10,6 +10,7 @@
#ifdef _DEBUG
#include "debug.h"
#endif
#include "engine/backbuffer_state.hpp"
#include "engine/point.hpp"
#include "engine/random.hpp"
#include "gamemenu.h"
@ -55,12 +56,12 @@ void ClearReadiedSpell(Player &player)
{
if (player._pRSpell != SPL_INVALID) {
player._pRSpell = SPL_INVALID;
force_redraw = 255;
RedrawEverything();
}
if (player._pRSplType != RSPLTYPE_INVALID) {
player._pRSplType = RSPLTYPE_INVALID;
force_redraw = 255;
RedrawEverything();
}
}
@ -191,7 +192,7 @@ void ConsumeSpell(Player &player, spell_id sn)
int ma = GetManaAmount(player, sn);
player._pMana -= ma;
player._pManaBase -= ma;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
break;
}
if (sn == SPL_FLARE) {
@ -273,8 +274,8 @@ void DoResurrect(size_t pnum, Player &target)
if (&target == MyPlayer) {
MyPlayerIsDead = false;
gamemenu_off();
drawhpflag = true;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Health);
RedrawComponent(PanelDrawComponent::Mana);
}
ClrPlrPath(target);
@ -327,7 +328,7 @@ void DoHealOther(const Player &caster, Player &target)
target._pHPBase = std::min(target._pHPBase + hp, target._pMaxHPBase);
if (&target == MyPlayer) {
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
}

5
Source/stores.cpp

@ -11,6 +11,7 @@
#include "controls/plrctrls.h"
#include "cursor.h"
#include "engine/backbuffer_state.hpp"
#include "engine/load_cel.hpp"
#include "engine/random.hpp"
#include "engine/render/clx_render.hpp"
@ -695,7 +696,7 @@ void FillManaPlayer()
}
myPlayer._pMana = myPlayer._pMaxMana;
myPlayer._pManaBase = myPlayer._pMaxManaBase;
drawmanaflag = true;
RedrawComponent(PanelDrawComponent::Mana);
}
void StartWitch()
@ -1090,7 +1091,7 @@ void HealPlayer()
}
myPlayer._pHitPoints = myPlayer._pMaxHP;
myPlayer._pHPBase = myPlayer._pMaxHPBase;
drawhpflag = true;
RedrawComponent(PanelDrawComponent::Health);
}
void StartHealer()

14
Source/utils/display.cpp

@ -24,6 +24,7 @@
#include "controls/devices/kbcontroller.h"
#include "controls/game_controls.h"
#include "controls/touch/gamepad.h"
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "options.h"
#include "utils/log.hpp"
@ -449,7 +450,7 @@ void SetFullscreenMode()
}
InitializeVirtualGamepad();
#endif
force_redraw = 255;
RedrawEverything();
}
void ResizeWindow()
@ -473,7 +474,7 @@ void ResizeWindow()
#endif
CreateBackBuffer();
force_redraw = 255;
RedrawEverything();
}
SDL_Surface *GetOutputSurface()
@ -493,15 +494,6 @@ SDL_Surface *GetOutputSurface()
#endif
}
bool IsDoubleBuffered()
{
#ifdef USE_SDL1
return (GetOutputSurface()->flags & SDL_DOUBLEBUF) == SDL_DOUBLEBUF;
#else
return true;
#endif
}
bool OutputRequiresScaling()
{
#ifdef USE_SDL1

2
Source/utils/display.h

@ -40,8 +40,6 @@ bool IsFullScreen();
// SDL2, upscale: Renderer texture surface.
SDL_Surface *GetOutputSurface();
bool IsDoubleBuffered();
// Whether the output surface requires software scaling.
// Always returns false on SDL2.
bool OutputRequiresScaling();

Loading…
Cancel
Save