Browse Source

Clip control.cpp draw calls

No longer crashes there when running at a resolution smaller than
640x480
pull/2184/head
Gleb Mazovetskiy 5 years ago committed by Anders Jenbo
parent
commit
982260d94e
  1. 27
      Source/control.cpp
  2. 46
      Source/engine.cpp
  3. 34
      Source/engine.h

27
Source/control.cpp

@ -27,6 +27,7 @@
#include "towners.h"
#include "trigs.h"
#include "utils/language.h"
#include "utils/sdl_geometry.h"
namespace devilution {
namespace {
@ -545,12 +546,7 @@ void ClearPanel()
void DrawPanelBox(const CelOutputBuffer &out, SDL_Rect srcRect, Point targetPosition)
{
const BYTE *src = pBtmBuff.at(srcRect.x, srcRect.y);
BYTE *dst = &out[targetPosition];
for (int hgt = srcRect.h; hgt != 0; hgt--, src += pBtmBuff.pitch(), dst += out.pitch()) {
memcpy(dst, src, srcRect.w);
}
out.BlitFrom(pBtmBuff, srcRect, targetPosition);
}
/**
@ -565,11 +561,7 @@ void DrawPanelBox(const CelOutputBuffer &out, SDL_Rect srcRect, Point targetPosi
*/
static void DrawFlaskTop(const CelOutputBuffer &out, Point position, const CelOutputBuffer &celBuf, int y0, int y1)
{
const BYTE *src = celBuf.at(0, y0);
BYTE *dst = &out[position];
for (int h = y1 - y0; h != 0; --h, src += celBuf.pitch(), dst += out.pitch())
memcpy(dst, src, celBuf.w());
out.BlitFrom(celBuf, SDL_Rect { 0, static_cast<decltype(SDL_Rect {}.y)>(y0), celBuf.w(), y1 - y0 }, position);
}
/**
@ -584,17 +576,8 @@ static void DrawFlaskTop(const CelOutputBuffer &out, Point position, const CelOu
*/
static void DrawFlask(const CelOutputBuffer &out, const CelOutputBuffer &celBuf, Point sourcePosition, Point targetPosition, int h)
{
const BYTE *src = &celBuf[sourcePosition];
BYTE *dst = &out[targetPosition];
for (int hgt = h; hgt != 0; hgt--, src += celBuf.pitch() - 59, dst += out.pitch() - 59) {
for (int wdt = 59; wdt != 0; wdt--) {
if (*src != 0)
*dst = *src;
src++;
dst++;
}
}
constexpr int FlaskWidth = 59;
out.BlitFromSkipColorIndexZero(celBuf, MakeSdlRect(sourcePosition.x, sourcePosition.y, FlaskWidth, h), targetPosition);
}
void DrawLifeFlask(const CelOutputBuffer &out)

46
Source/engine.cpp

@ -36,6 +36,52 @@ const uint32_t RndInc = 1;
*/
const uint32_t RndMult = 0x015A4E35;
namespace {
template <bool SkipColorIndexZero>
void BufferBlit(const CelOutputBuffer &src, SDL_Rect srcRect, const CelOutputBuffer &dst, Point dstPosition)
{
// We do not use `SDL_BlitSurface` here because the palettes may be different objects
// and SDL would attempt to map them.
dst.Clip(&srcRect, &dstPosition);
if (srcRect.w <= 0 || srcRect.h <= 0)
return;
const std::uint8_t *srcBuf = src.at(srcRect.x, srcRect.y);
const auto srcPitch = src.pitch();
std::uint8_t *dstBuf = &dst[dstPosition];
const auto dstPitch = dst.pitch();
for (unsigned h = srcRect.h; h != 0; --h) {
if (SkipColorIndexZero) {
for (unsigned w = srcRect.w; w != 0; --w) {
if (*srcBuf != 0)
*dstBuf = *srcBuf;
++srcBuf, ++dstBuf;
}
srcBuf += srcPitch - srcRect.w;
dstBuf += dstPitch - srcRect.w;
} else {
std::memcpy(dstBuf, srcBuf, srcRect.w);
srcBuf += srcPitch;
dstBuf += dstPitch;
}
}
}
} // namespace
void CelOutputBuffer::BlitFrom(const CelOutputBuffer &src, SDL_Rect srcRect, Point targetPosition) const
{
BufferBlit</*SkipColorIndexZero=*/false>(src, srcRect, *this, targetPosition);
}
void CelOutputBuffer::BlitFromSkipColorIndexZero(const CelOutputBuffer &src, SDL_Rect srcRect, Point targetPosition) const
{
BufferBlit</*SkipColorIndexZero=*/true>(src, srcRect, *this, targetPosition);
}
CelSprite LoadCel(const char *pszName, int width)
{
return CelSprite(LoadFileInMem(pszName), width);

34
Source/engine.h

@ -432,6 +432,40 @@ struct CelOutputBuffer {
subregion.h = h;
return CelOutputBuffer(surface, subregion);
}
/**
* @brief Clips srcRect and targetPosition to this output buffer.
*/
void Clip(SDL_Rect *srcRect, Point *targetPosition) const
{
if (targetPosition->x < 0) {
srcRect->x -= targetPosition->x;
srcRect->w += targetPosition->x;
targetPosition->x = 0;
}
if (targetPosition->y < 0) {
srcRect->y -= targetPosition->y;
srcRect->h += targetPosition->y;
targetPosition->y = 0;
}
if (targetPosition->x + srcRect->w > region.w) {
srcRect->w = region.w - targetPosition->x;
}
if (targetPosition->y + srcRect->h > region.h) {
srcRect->h = region.h - targetPosition->y;
}
}
/**
* @brief Copies the `srcRect` portion of the given buffer to this buffer at `targetPosition`.
*/
void BlitFrom(const CelOutputBuffer &src, SDL_Rect srcRect, Point targetPosition) const;
/**
* @brief Copies the `srcRect` portion of the given buffer to this buffer at `targetPosition`.
* Source pixels with index 0 are not copied.
*/
void BlitFromSkipColorIndexZero(const CelOutputBuffer &src, SDL_Rect srcRect, Point targetPosition) const;
};
/**

Loading…
Cancel
Save