Browse Source

Simplify spell icon handling

Hide the internals of spell icon rendering behind simple functions.
pull/5522/head
Gleb Mazovetskiy 3 years ago committed by Anders Jenbo
parent
commit
46e755f680
  1. 4
      Source/control.cpp
  2. 6
      Source/controls/modifier_hints.cpp
  3. 3
      Source/controls/plrctrls.cpp
  4. 19
      Source/engine.cpp
  5. 9
      Source/engine.h
  6. 33
      Source/panels/spell_book.cpp
  7. 7
      Source/panels/spell_book.hpp
  8. 99
      Source/panels/spell_icons.cpp
  9. 51
      Source/panels/spell_icons.hpp
  10. 24
      Source/panels/spell_list.cpp

4
Source/control.cpp

@ -646,7 +646,7 @@ void InitControlPan()
pLifeBuff.emplace(88, 88); pLifeBuff.emplace(88, 88);
LoadCharPanel(); LoadCharPanel();
LoadSpellIcons(); LoadLargeSpellIcons();
{ {
const OwnedClxSpriteList sprite = LoadCel("ctrlpan\\panel8", GetMainPanel().size.width); const OwnedClxSpriteList sprite = LoadCel("ctrlpan\\panel8", GetMainPanel().size.width);
ClxDraw(*pBtmBuff, { 0, (GetMainPanel().size.height + 16) - 1 }, sprite[0]); ClxDraw(*pBtmBuff, { 0, (GetMainPanel().size.height + 16) - 1 }, sprite[0]);
@ -962,7 +962,7 @@ void FreeControlPan()
pBtmBuff = std::nullopt; pBtmBuff = std::nullopt;
pManaBuff = std::nullopt; pManaBuff = std::nullopt;
pLifeBuff = std::nullopt; pLifeBuff = std::nullopt;
FreeSpellIcons(); FreeLargeSpellIcons();
FreeSpellBook(); FreeSpellBook();
pPanelButtons = std::nullopt; pPanelButtons = std::nullopt;
multiButtons = std::nullopt; multiButtons = std::nullopt;

6
Source/controls/modifier_hints.cpp

@ -139,11 +139,7 @@ void DrawSpellsCircleMenuHint(const Surface &out, const Point &origin)
} }
SetSpellTrans(splType); SetSpellTrans(splType);
#ifdef UNPACKED_MPQS DrawSmallSpellIcon(out, spellIconPositions[slot], splId);
DrawSpellCel(out, spellIconPositions[slot], (*pSBkIconsForeground)[SpellITbl[splId]], (*pSBkIconsBackground)[0]);
#else
DrawSpellCel(out, spellIconPositions[slot], (*pSBkIconCels)[SpellITbl[splId]]);
#endif
RenderClxSprite(out, (*hintBox)[0], hintBoxPositions[slot]); RenderClxSprite(out, (*hintBox)[0], hintBoxPositions[slot]);
} }
} }

3
Source/controls/plrctrls.cpp

@ -30,6 +30,7 @@
#include "levels/trigs.h" #include "levels/trigs.h"
#include "minitext.h" #include "minitext.h"
#include "missiles.h" #include "missiles.h"
#include "panels/spell_icons.hpp"
#include "panels/spell_list.hpp" #include "panels/spell_list.hpp"
#include "panels/ui_panels.hpp" #include "panels/ui_panels.hpp"
#include "qol/chatlog.h" #include "qol/chatlog.h"
@ -40,8 +41,6 @@
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/str_cat.hpp" #include "utils/str_cat.hpp"
#define SPLICONLENGTH 56
namespace devilution { namespace devilution {
ControlTypes ControlMode = ControlTypes::None; ControlTypes ControlMode = ControlTypes::None;

19
Source/engine.cpp

@ -163,6 +163,25 @@ void DrawHalfTransparentRectTo(const Surface &out, int sx, int sy, int width, in
DrawHalfTransparentBlendedRectTo(out, sx, sy, width, height); DrawHalfTransparentBlendedRectTo(out, sx, sy, width, height);
} }
void UnsafeDrawBorder2px(const Surface &out, Rectangle rect, uint8_t color)
{
const size_t width = rect.size.width;
const size_t height = rect.size.height;
uint8_t *buf = &out[rect.position];
std::memset(buf, color, width);
buf += out.pitch();
std::memset(buf, color, width);
buf += out.pitch();
for (size_t i = 4; i < height; ++i) {
buf[0] = buf[1] = color;
buf[width - 2] = buf[width - 1] = color;
buf += out.pitch();
}
std::memset(buf, color, width);
buf += out.pitch();
std::memset(buf, color, width);
}
Direction GetDirection(Point start, Point destination) Direction GetDirection(Point start, Point destination)
{ {
Direction md; Direction md;

9
Source/engine.h

@ -104,6 +104,15 @@ void UnsafeDrawVerticalLine(const Surface &out, Point from, int height, std::uin
*/ */
void DrawHalfTransparentRectTo(const Surface &out, int sx, int sy, int width, int height); void DrawHalfTransparentRectTo(const Surface &out, int sx, int sy, int width, int height);
/**
* Draws a 2px inset border.
*
* @param out Target buffer
* @param rect The rectangle that border pixels are rendered inside of.
* @param color Border color.
*/
void UnsafeDrawBorder2px(const Surface &out, Rectangle rect, uint8_t color);
/** /**
* @brief Calculate the best fit direction between two points * @brief Calculate the best fit direction between two points
* @param start Tile coordinate * @param start Tile coordinate

33
Source/panels/spell_book.cpp

@ -21,13 +21,6 @@
namespace devilution { namespace devilution {
#ifdef UNPACKED_MPQS
OptionalOwnedClxSpriteList pSBkIconsBackground;
OptionalOwnedClxSpriteList pSBkIconsForeground;
#else
OptionalOwnedClxSpriteList pSBkIconCels;
#endif
namespace { namespace {
OptionalOwnedClxSpriteList pSBkBtnCel; OptionalOwnedClxSpriteList pSBkBtnCel;
@ -88,12 +81,7 @@ void InitSpellBook()
{ {
pSpellBkCel = LoadCel("data\\spellbk", static_cast<uint16_t>(SidePanelSize.width)); pSpellBkCel = LoadCel("data\\spellbk", static_cast<uint16_t>(SidePanelSize.width));
pSBkBtnCel = LoadCel("data\\spellbkb", gbIsHellfire ? 61 : 76); pSBkBtnCel = LoadCel("data\\spellbkb", gbIsHellfire ? 61 : 76);
#ifdef UNPACKED_MPQS LoadSmallSpellIcons();
pSBkIconsBackground = LoadClx("data\\spelli2_bg.clx");
pSBkIconsForeground = LoadClx("data\\spelli2_fg.clx");
#else
pSBkIconCels = LoadCel("data\\spelli2", 37);
#endif
Player &player = *MyPlayer; Player &player = *MyPlayer;
if (player._pClass == HeroClass::Warrior) { if (player._pClass == HeroClass::Warrior) {
@ -113,12 +101,7 @@ void InitSpellBook()
void FreeSpellBook() void FreeSpellBook()
{ {
#ifdef UNPACKED_MPQS FreeSmallSpellIcons();
pSBkIconsForeground = std::nullopt;
pSBkIconsBackground = std::nullopt;
#else
pSBkIconCels = std::nullopt;
#endif
pSBkBtnCel = std::nullopt; pSBkBtnCel = std::nullopt;
pSpellBkCel = std::nullopt; pSpellBkCel = std::nullopt;
} }
@ -149,18 +132,10 @@ void DrawSpellBook(const Surface &out)
spell_type st = GetSBookTrans(sn, true); spell_type st = GetSBookTrans(sn, true);
SetSpellTrans(st); SetSpellTrans(st);
const Point spellCellPosition = GetPanelPosition(UiPanels::Spell, { 11, yp + SpellBookDescription.height }); const Point spellCellPosition = GetPanelPosition(UiPanels::Spell, { 11, yp + SpellBookDescription.height });
#ifdef UNPACKED_MPQS DrawSmallSpellIcon(out, spellCellPosition, sn);
DrawSpellCel(out, spellCellPosition, (*pSBkIconsForeground)[SpellITbl[sn]], (*pSBkIconsBackground)[0]);
#else
DrawSpellCel(out, spellCellPosition, (*pSBkIconCels)[SpellITbl[sn]]);
#endif
if (sn == player._pRSpell && st == player._pRSplType) { if (sn == player._pRSpell && st == player._pRSplType) {
SetSpellTrans(RSPLTYPE_SKILL); SetSpellTrans(RSPLTYPE_SKILL);
#ifdef UNPACKED_MPQS DrawSmallSpellIconBorder(out, spellCellPosition);
DrawSpellBorder(out, spellCellPosition, (*pSBkIconsForeground)[SpellITbl[sn]]);
#else
DrawSpellBorder(out, spellCellPosition, (*pSBkIconCels)[SpellITbl[sn]]);
#endif
} }
const Point line0 { 0, yp + textPaddingTop }; const Point line0 { 0, yp + textPaddingTop };

7
Source/panels/spell_book.hpp

@ -5,13 +5,6 @@
namespace devilution { namespace devilution {
#ifdef UNPACKED_MPQS
extern OptionalOwnedClxSpriteList pSBkIconsBackground;
extern OptionalOwnedClxSpriteList pSBkIconsForeground;
#else
extern OptionalOwnedClxSpriteList pSBkIconCels;
#endif
void InitSpellBook(); void InitSpellBook();
void FreeSpellBook(); void FreeSpellBook();
void CheckSBook(); void CheckSBook();

99
Source/panels/spell_icons.cpp

@ -1,5 +1,6 @@
#include "panels/spell_icons.hpp" #include "panels/spell_icons.hpp"
#include "engine.h"
#include "engine/load_cel.hpp" #include "engine/load_cel.hpp"
#include "engine/load_clx.hpp" #include "engine/load_clx.hpp"
#include "engine/palette.h" #include "engine/palette.h"
@ -10,17 +11,19 @@
namespace devilution { namespace devilution {
namespace { namespace {
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
OptionalOwnedClxSpriteList pSpellIconsBackground; OptionalOwnedClxSpriteList LargeSpellIconsBackground;
OptionalOwnedClxSpriteList pSpellIconsForeground; OptionalOwnedClxSpriteList SmallSpellIconsBackground;
#else
OptionalOwnedClxSpriteList pSpellCels;
#endif #endif
OptionalOwnedClxSpriteList SmallSpellIcons;
OptionalOwnedClxSpriteList LargeSpellIcons;
uint8_t SplTransTbl[256]; uint8_t SplTransTbl[256];
} // namespace
const char SpellITbl[] = { /** Maps from spell_id to spelicon.cel frame number. */
const uint8_t SpellITbl[] = {
26, 26,
0, 0,
1, 1,
@ -75,76 +78,82 @@ const char SpellITbl[] = {
34, 34,
}; };
void LoadSpellIcons() } // namespace
void LoadLargeSpellIcons()
{ {
if (!gbIsHellfire) { if (!gbIsHellfire) {
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
pSpellIconsForeground = LoadClx("ctrlpan\\spelicon_fg.clx"); LargeSpellIcons = LoadClx("ctrlpan\\spelicon_fg.clx");
pSpellIconsBackground = LoadClx("ctrlpan\\spelicon_bg.clx"); LargeSpellIconsBackground = LoadClx("ctrlpan\\spelicon_bg.clx");
#else #else
pSpellCels = LoadCel("ctrlpan\\spelicon", SPLICONLENGTH); LargeSpellIcons = LoadCel("ctrlpan\\spelicon", SPLICONLENGTH);
#endif #endif
} else { } else {
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
pSpellIconsForeground = LoadClx("data\\spelicon_fg.clx"); LargeSpellIcons = LoadClx("data\\spelicon_fg.clx");
pSpellIconsBackground = LoadClx("data\\spelicon_bg.clx"); LargeSpellIconsBackground = LoadClx("data\\spelicon_bg.clx");
#else #else
pSpellCels = LoadCel("data\\spelicon", SPLICONLENGTH); LargeSpellIcons = LoadCel("data\\spelicon", SPLICONLENGTH);
#endif #endif
} }
SetSpellTrans(RSPLTYPE_SKILL); SetSpellTrans(RSPLTYPE_SKILL);
} }
void FreeSpellIcons() void FreeLargeSpellIcons()
{ {
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
pSpellIconsBackground = std::nullopt; LargeSpellIconsBackground = std::nullopt;
pSpellIconsForeground = std::nullopt;
#else
pSpellCels = std::nullopt;
#endif #endif
LargeSpellIcons = std::nullopt;
} }
void DrawSpellCel(const Surface &out, Point position, int nCel) void LoadSmallSpellIcons()
{ {
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
DrawSpellCel(out, position, (*pSpellIconsForeground)[nCel], (*pSpellIconsBackground)[0]); SmallSpellIcons = LoadClx("data\\spelli2_fg.clx");
SmallSpellIconsBackground = LoadClx("data\\spelli2_bg.clx");
#else #else
DrawSpellCel(out, position, (*pSpellCels)[nCel]); SmallSpellIcons = LoadCel("data\\spelli2", 37);
#endif #endif
} }
#ifdef UNPACKED_MPQS void FreeSmallSpellIcons()
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite, ClxSprite background)
{ {
ClxDrawTRN(out, position, background, SplTransTbl); #ifdef UNPACKED_MPQS
ClxDrawTRN(out, position, sprite, SplTransTbl); SmallSpellIconsBackground = std::nullopt;
#endif
SmallSpellIcons = std::nullopt;
} }
#else
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite) void DrawLargeSpellIcon(const Surface &out, Point position, spell_id spell)
{ {
ClxDrawTRN(out, position, sprite, SplTransTbl); #ifdef UNPACKED_MPQS
ClxDrawTRN(out, position, (*LargeSpellIconsBackground)[0], SplTransTbl);
#endif
ClxDrawTRN(out, position, (*LargeSpellIcons)[SpellITbl[spell]], SplTransTbl);
} }
void DrawSmallSpellIcon(const Surface &out, Point position, spell_id spell)
{
#ifdef UNPACKED_MPQS
ClxDrawTRN(out, position, (*SmallSpellIconsBackground)[0], SplTransTbl);
#endif #endif
ClxDrawTRN(out, position, (*SmallSpellIcons)[SpellITbl[spell]], SplTransTbl);
}
void DrawSpellBorder(const Surface &out, Point position, ClxSprite sprite) void DrawLargeSpellIconBorder(const Surface &out, Point position, uint8_t color)
{ {
const uint8_t color = SplTransTbl[PAL8_YELLOW + 2]; const int width = (*LargeSpellIcons)[0].width();
const size_t width = sprite.width(); const int height = (*LargeSpellIcons)[0].height();
const size_t height = sprite.height(); UnsafeDrawBorder2px(out, Rectangle { Point { position.x, position.y - height + 1 }, Size { width, height } }, color);
position.y -= static_cast<int>(height); }
uint8_t *buf = &out[position];
std::memset(buf, color, width); void DrawSmallSpellIconBorder(const Surface &out, Point position)
buf += out.pitch(); {
std::memset(buf, color, width); const int width = (*SmallSpellIcons)[0].width();
for (size_t i = 4; i < sprite.height(); ++i) { const int height = (*SmallSpellIcons)[0].height();
buf[0] = buf[1] = color; UnsafeDrawBorder2px(out, Rectangle { Point { position.x, position.y - height + 1 }, Size { width, height } }, SplTransTbl[PAL8_YELLOW + 2]);
buf[width - 2] = buf[width - 1] = color;
buf += out.pitch();
}
std::memset(buf, color, width);
buf += out.pitch();
std::memset(buf, color, width);
} }
void SetSpellTrans(spell_type t) void SetSpellTrans(spell_type t)

51
Source/panels/spell_icons.hpp

@ -9,34 +9,51 @@
namespace devilution { namespace devilution {
/** Maps from spell_id to spelicon.cel frame number. */ /**
extern const char SpellITbl[]; * Draw a large (56x56) spell icon onto the given buffer.
*
* @param out Output buffer.
* @param position Buffer coordinates (bottom-left).
* @param spell Spell ID.
*/
void DrawLargeSpellIcon(const Surface &out, Point position, spell_id spell);
/** /**
* Draw spell icon onto the given buffer. * Draw a small (37x38) spell icon onto the given buffer.
*
* @param out Output buffer. * @param out Output buffer.
* @param position Buffer coordinates. * @param position Buffer coordinates (bottom-left).
* @param nCel Index of the cel frame to draw. 0 based. * @param spell Spell ID.
*/ */
void DrawSpellCel(const Surface &out, Point position, int nCel); void DrawSmallSpellIcon(const Surface &out, Point position, spell_id spell);
/** /**
* Draw spell icon onto the given buffer. * Draw an inset 2px border for a large (56x56) spell icon.
*
* @param out Output buffer. * @param out Output buffer.
* @param position Buffer coordinates. * @param position Buffer coordinates (bottom-left).
* @param sprite Icons sprite sheet. * @param spell Spell ID.
*/ */
#ifdef UNPACKED_MPQS void DrawLargeSpellIconBorder(const Surface &out, Point position, uint8_t color);
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite, ClxSprite background);
#else
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite);
#endif
void DrawSpellBorder(const Surface &out, Point position, ClxSprite sprite); /**
* Draw an inset 2px border for a small (37x38) spell icon.
*
* @param out Output buffer.
* @param position Buffer coordinates (bottom-left).
* @param spell Spell ID.
*/
void DrawSmallSpellIconBorder(const Surface &out, Point position);
/**
* @brief Set the color mapping for the `Draw(Small|Large)SpellIcon(Border)` calls.
*/
void SetSpellTrans(spell_type t); void SetSpellTrans(spell_type t);
void LoadSpellIcons(); void LoadLargeSpellIcons();
void FreeSpellIcons(); void FreeLargeSpellIcons();
void LoadSmallSpellIcons();
void FreeSmallSpellIcons();
} // namespace devilution } // namespace devilution

24
Source/panels/spell_list.cpp

@ -25,24 +25,7 @@ namespace {
void PrintSBookSpellType(const Surface &out, Point position, string_view text, uint8_t rectColorIndex) void PrintSBookSpellType(const Surface &out, Point position, string_view text, uint8_t rectColorIndex)
{ {
Point rect { position }; DrawLargeSpellIconBorder(out, position, rectColorIndex);
rect += Displacement { 0, -SPLICONLENGTH + 1 };
// Top
DrawHorizontalLine(out, rect, SPLICONLENGTH, rectColorIndex);
DrawHorizontalLine(out, rect + Displacement { 0, 1 }, SPLICONLENGTH, rectColorIndex);
// Bottom
DrawHorizontalLine(out, rect + Displacement { 0, SPLICONLENGTH - 2 }, SPLICONLENGTH, rectColorIndex);
DrawHorizontalLine(out, rect + Displacement { 0, SPLICONLENGTH - 1 }, SPLICONLENGTH, rectColorIndex);
// Left Side
DrawVerticalLine(out, rect, SPLICONLENGTH, rectColorIndex);
DrawVerticalLine(out, rect + Displacement { 1, 0 }, SPLICONLENGTH, rectColorIndex);
// Right Side
DrawVerticalLine(out, rect + Displacement { SPLICONLENGTH - 2, 0 }, SPLICONLENGTH, rectColorIndex);
DrawVerticalLine(out, rect + Displacement { SPLICONLENGTH - 1, 0 }, SPLICONLENGTH, rectColorIndex);
// Align the spell type text with bottom of spell icon // Align the spell type text with bottom of spell icon
position += Displacement { SPLICONLENGTH / 2 - GetLineWidth(text) / 2, (IsSmallFontTall() ? -19 : -15) }; position += Displacement { SPLICONLENGTH / 2 - GetLineWidth(text) / 2, (IsSmallFontTall() ? -19 : -15) };
@ -122,9 +105,8 @@ void DrawSpell(const Surface &out)
st = RSPLTYPE_INVALID; st = RSPLTYPE_INVALID;
SetSpellTrans(st); SetSpellTrans(st);
const int nCel = SpellITbl[spl];
const Point position = GetMainPanel().position + Displacement { 565, 119 }; const Point position = GetMainPanel().position + Displacement { 565, 119 };
DrawSpellCel(out, position, nCel); DrawLargeSpellIcon(out, position, spl);
std::optional<string_view> hotkeyName = GetHotkeyName(spl, myPlayer._pRSplType); std::optional<string_view> hotkeyName = GetHotkeyName(spl, myPlayer._pRSplType);
if (hotkeyName) if (hotkeyName)
@ -152,7 +134,7 @@ void DrawSpellList(const Surface &out)
} }
SetSpellTrans(transType); SetSpellTrans(transType);
DrawSpellCel(out, spellListItem.location, SpellITbl[static_cast<size_t>(spellId)]); DrawLargeSpellIcon(out, spellListItem.location, spellId);
std::optional<string_view> hotkeyName = GetHotkeyName(spellId, spellListItem.type); std::optional<string_view> hotkeyName = GetHotkeyName(spellId, spellListItem.type);

Loading…
Cancel
Save