/** * @file engine.cpp * * Implementation of basic engine helper functions: * - Sprite blitting * - Drawing * - Angle calculation * - RNG * - Memory allocation * - File loading * - Video playback */ #include #include "engine/render/common_impl.h" #include "lighting.h" #include "movie.h" #include "options.h" namespace devilution { namespace { void DrawHalfTransparentBlendedRectTo(const Surface &out, int sx, int sy, int width, int height) { BYTE *pix = out.at(sx, sy); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { *pix = paletteTransparencyLookup[0][*pix]; pix++; } pix += out.pitch() - width; } } void DrawHalfTransparentStippledRectTo(const Surface &out, int sx, int sy, int width, int height) { BYTE *pix = out.at(sx, sy); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { if (((row & 1) != 0 && (col & 1) != 0) || ((row & 1) == 0 && (col & 1) == 0)) *pix = 0; pix++; } pix += out.pitch() - width; } } } // namespace void DrawHorizontalLine(const Surface &out, Point from, int width, std::uint8_t colorIndex) { if (from.y < 0 || from.y >= out.h() || from.x >= out.w() || width <= 0 || from.x + width <= 0) return; if (from.x < 0) { width += from.x; from.x = 0; } if (from.x + width > out.w()) width = out.w() - from.x; return UnsafeDrawHorizontalLine(out, from, width, colorIndex); } void UnsafeDrawHorizontalLine(const Surface &out, Point from, int width, std::uint8_t colorIndex) { std::memset(&out[from], colorIndex, width); } void DrawVerticalLine(const Surface &out, Point from, int height, std::uint8_t colorIndex) { if (from.x < 0 || from.x >= out.w() || from.y >= out.h() || height <= 0 || from.y + height <= 0) return; if (from.y < 0) { height += from.y; from.y = 0; } if (from.y + height > out.h()) height = (from.y + height) - out.h(); return UnsafeDrawVerticalLine(out, from, height, colorIndex); } void UnsafeDrawVerticalLine(const Surface &out, Point from, int height, std::uint8_t colorIndex) { auto *dst = &out[from]; const auto pitch = out.pitch(); while (height-- > 0) { *dst = colorIndex; dst += pitch; } } void DrawHalfTransparentRectTo(const Surface &out, int sx, int sy, int width, int height) { if (sx + width < 0) return; if (sy + height < 0) return; if (sx >= out.w()) return; if (sy >= out.h()) return; if (sx < 0) { width += sx; sx = 0; } else if (sx + width >= out.w()) { width = out.w() - sx; } if (sy < 0) { height += sy; sy = 0; } else if (sy + height >= out.h()) { height = out.h() - sy; } if (sgOptions.Graphics.bBlendedTransparancy) { DrawHalfTransparentBlendedRectTo(out, sx, sy, width, height); } else { DrawHalfTransparentStippledRectTo(out, sx, sy, width, height); } } /** * @brief Returns the direction a vector from p1(x1, y1) to p2(x2, y2) is pointing to. * * W SW S * ^ * | * NW ----+---> SE * | * | * N NE E * * @param x1 the x coordinate of p1 * @param y1 the y coordinate of p1 * @param x2 the x coordinate of p2 * @param y2 the y coordinate of p2 * @return the direction of the p1->p2 vector */ Direction GetDirection(Point start, Point destination) { Direction md = DIR_S; int mx = destination.x - start.x; int my = destination.y - start.y; if (mx >= 0) { if (my >= 0) { if (5 * mx <= (my * 2)) // mx/my <= 0.4, approximation of tan(22.5) return DIR_SW; md = DIR_S; } else { my = -my; if (5 * mx <= (my * 2)) return DIR_NE; md = DIR_E; } if (5 * my <= (mx * 2)) // my/mx <= 0.4 md = DIR_SE; } else { mx = -mx; if (my >= 0) { if (5 * mx <= (my * 2)) return DIR_SW; md = DIR_W; } else { my = -my; if (5 * mx <= (my * 2)) return DIR_NE; md = DIR_N; } if (5 * my <= (mx * 2)) md = DIR_NW; } return md; } int CalculateWidth2(int width) { return (width - 64) / 2; } } // namespace devilution