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);
LoadCharPanel();
LoadSpellIcons();
LoadLargeSpellIcons();
{
const OwnedClxSpriteList sprite = LoadCel("ctrlpan\\panel8", GetMainPanel().size.width);
ClxDraw(*pBtmBuff, { 0, (GetMainPanel().size.height + 16) - 1 }, sprite[0]);
@ -962,7 +962,7 @@ void FreeControlPan()
pBtmBuff = std::nullopt;
pManaBuff = std::nullopt;
pLifeBuff = std::nullopt;
FreeSpellIcons();
FreeLargeSpellIcons();
FreeSpellBook();
pPanelButtons = 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);
#ifdef UNPACKED_MPQS
DrawSpellCel(out, spellIconPositions[slot], (*pSBkIconsForeground)[SpellITbl[splId]], (*pSBkIconsBackground)[0]);
#else
DrawSpellCel(out, spellIconPositions[slot], (*pSBkIconCels)[SpellITbl[splId]]);
#endif
DrawSmallSpellIcon(out, spellIconPositions[slot], splId);
RenderClxSprite(out, (*hintBox)[0], hintBoxPositions[slot]);
}
}

3
Source/controls/plrctrls.cpp

@ -30,6 +30,7 @@
#include "levels/trigs.h"
#include "minitext.h"
#include "missiles.h"
#include "panels/spell_icons.hpp"
#include "panels/spell_list.hpp"
#include "panels/ui_panels.hpp"
#include "qol/chatlog.h"
@ -40,8 +41,6 @@
#include "utils/log.hpp"
#include "utils/str_cat.hpp"
#define SPLICONLENGTH 56
namespace devilution {
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);
}
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 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);
/**
* 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
* @param start Tile coordinate

33
Source/panels/spell_book.cpp

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

7
Source/panels/spell_book.hpp

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

99
Source/panels/spell_icons.cpp

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

51
Source/panels/spell_icons.hpp

@ -9,34 +9,51 @@
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 position Buffer coordinates.
* @param nCel Index of the cel frame to draw. 0 based.
* @param position Buffer coordinates (bottom-left).
* @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 position Buffer coordinates.
* @param sprite Icons sprite sheet.
* @param position Buffer coordinates (bottom-left).
* @param spell Spell ID.
*/
#ifdef UNPACKED_MPQS
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite, ClxSprite background);
#else
void DrawSpellCel(const Surface &out, Point position, ClxSprite sprite);
#endif
void DrawLargeSpellIconBorder(const Surface &out, Point position, uint8_t color);
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 LoadSpellIcons();
void FreeSpellIcons();
void LoadLargeSpellIcons();
void FreeLargeSpellIcons();
void LoadSmallSpellIcons();
void FreeSmallSpellIcons();
} // 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)
{
Point rect { position };
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);
DrawLargeSpellIconBorder(out, position, rectColorIndex);
// Align the spell type text with bottom of spell icon
position += Displacement { SPLICONLENGTH / 2 - GetLineWidth(text) / 2, (IsSmallFontTall() ? -19 : -15) };
@ -122,9 +105,8 @@ void DrawSpell(const Surface &out)
st = RSPLTYPE_INVALID;
SetSpellTrans(st);
const int nCel = SpellITbl[spl];
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);
if (hotkeyName)
@ -152,7 +134,7 @@ void DrawSpellList(const Surface &out)
}
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);

Loading…
Cancel
Save