mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
Add ellipse plotter and oval drawing
This commit is contained in:
411
PortabilityLayer/EllipsePlotter.cpp
Normal file
411
PortabilityLayer/EllipsePlotter.cpp
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
#include "EllipsePlotter.h"
|
||||||
|
|
||||||
|
#include "Rect2i.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static int32_t SquareInt32(int32_t v)
|
||||||
|
{
|
||||||
|
return v * v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace PortabilityLayer
|
||||||
|
{
|
||||||
|
EllipsePlotter::EllipsePlotter()
|
||||||
|
: m_2center(0, 0)
|
||||||
|
, m_point(0, 0)
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER 1
|
||||||
|
, m_2offsetFromCenter(0, 0)
|
||||||
|
#endif
|
||||||
|
, m_quadrant(Quadrant_PxPy)
|
||||||
|
, m_sqDistFromEdge(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PlotDirection EllipsePlotter::PlotNext()
|
||||||
|
{
|
||||||
|
// distance = (m_2offsetFromCenter.x*m_diameters.y)^2 + (m_2offsetFromCenter.y*m_diameters.x)^2 <= (m_diameters.x*m_diameters.y)^2
|
||||||
|
// We want to minimize distance while keeping it less than (m_diameters.x*m_diameters.y)^2
|
||||||
|
|
||||||
|
// Stepping X:
|
||||||
|
// ((m_2offsetFromCenter.x + n)*m_diameters.y)^2 = (m_2offsetFromCenter.x*m_diameters.y)^2 + t
|
||||||
|
// t = ((m_2offsetFromCenter.x + n)*m_diameters.y)^2 - (m_2offsetFromCenter.x*m_diameters.y)^2
|
||||||
|
// t = (m_2offsetFromCenter.x*m_diameters.y + n*m_diameters.y)^2 - (m_2offsetFromCenter.x*m_diameters.y)^2
|
||||||
|
// t = 2*(m_2offsetFromCenter.x*m_diameters.y*n*m_diameters.y) + (n*m_diameters.y)^2
|
||||||
|
|
||||||
|
// For n=2:
|
||||||
|
// t = 2 * (m_2offsetFromCenter.x*m_diameters.y*2*m_diameters.y) + (2*m_diameters.y) ^ 2
|
||||||
|
// t = m_2offsetFromCenter.x * 4 * (m_diameters.y*)^2 + 4*(m_diameters.y) ^ 2
|
||||||
|
|
||||||
|
// For n=-2
|
||||||
|
// t = 2 * (m_2offsetFromCenter.x*m_diameters.y*-2*m_diameters.y) + (-2*m_diameters.y) ^ 2
|
||||||
|
// t = m_2offsetFromCenter.x * -4 * (m_diameters.y*m_diameters.y) + 4 * (m_diameters.y) ^ 2
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
{
|
||||||
|
const int32_t diameterSq = SquareInt32(m_diameters.m_x*m_diameters.m_y);
|
||||||
|
const int32_t sqDistX = SquareInt32(m_2offsetFromCenter.m_x*m_diameters.m_y);
|
||||||
|
const int32_t sqDistY = SquareInt32(m_2offsetFromCenter.m_y*m_diameters.m_x);
|
||||||
|
|
||||||
|
assert(m_sqDistFromEdge >= 0);
|
||||||
|
assert(sqDistX + sqDistY >= diameterSq);
|
||||||
|
assert(sqDistX + sqDistY - diameterSq == m_sqDistFromEdge);
|
||||||
|
assert(m_xChangeCostDynamicFactor == m_2offsetFromCenter.m_x * 4 * SquareInt32(m_diameters.m_y));
|
||||||
|
assert(m_yChangeCostDynamicFactor == m_2offsetFromCenter.m_y * 4 * SquareInt32(m_diameters.m_x));
|
||||||
|
|
||||||
|
Vec2i actualCoordinate = (m_2center + m_2offsetFromCenter);
|
||||||
|
actualCoordinate.m_x /= 2;
|
||||||
|
actualCoordinate.m_y /= 2;
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PlotDirection plotDir = PlotDirection_Exhausted;
|
||||||
|
|
||||||
|
switch (m_quadrant)
|
||||||
|
{
|
||||||
|
case Quadrant_PxPy:
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = -m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
const int32_t yStepCost = m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
const int32_t diagonalCostDelta = xStepCost + yStepCost;
|
||||||
|
|
||||||
|
if (diagonalCostDelta < 0)
|
||||||
|
{
|
||||||
|
// Diagonal movement will move closer to the edge (first octant)
|
||||||
|
IncrementY();
|
||||||
|
|
||||||
|
const int32_t distWithDiagonalMovement = m_sqDistFromEdge + xStepCost;
|
||||||
|
if (distWithDiagonalMovement >= 0)
|
||||||
|
{
|
||||||
|
DecrementX();
|
||||||
|
plotDir = PlotDirection_NegX_PosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_0X_PosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Diagonal movement will move farther from the center (second octant)
|
||||||
|
DecrementX();
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge < 0)
|
||||||
|
{
|
||||||
|
IncrementY();
|
||||||
|
plotDir = PlotDirection_NegX_PosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_NegX_0Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_xChangeCostDynamicFactor <= 0)
|
||||||
|
m_quadrant = Quadrant_NxPy;
|
||||||
|
|
||||||
|
return plotDir;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Quadrant_NxPy:
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = -m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
const int32_t yStepCost = -m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
const int32_t diagonalCostDelta = xStepCost + yStepCost;
|
||||||
|
|
||||||
|
if (diagonalCostDelta < 0)
|
||||||
|
{
|
||||||
|
// Diagonal movement will move closer to the edge (first octant)
|
||||||
|
DecrementX();
|
||||||
|
|
||||||
|
const int32_t distWithDiagonalMovement = m_sqDistFromEdge + yStepCost;
|
||||||
|
if (distWithDiagonalMovement >= 0)
|
||||||
|
{
|
||||||
|
DecrementY();
|
||||||
|
plotDir = PlotDirection_NegX_NegY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_NegX_0Y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Diagonal movement will move farther from the center (second octant)
|
||||||
|
DecrementY();
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge < 0)
|
||||||
|
{
|
||||||
|
DecrementX();
|
||||||
|
plotDir = PlotDirection_NegX_NegY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_0X_NegY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_yChangeCostDynamicFactor <= 0)
|
||||||
|
m_quadrant = Quadrant_NxNy;
|
||||||
|
|
||||||
|
return plotDir;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Quadrant_NxNy:
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
const int32_t yStepCost = -m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
const int32_t diagonalCostDelta = xStepCost + yStepCost;
|
||||||
|
|
||||||
|
if (diagonalCostDelta < 0)
|
||||||
|
{
|
||||||
|
// Diagonal movement will move closer to the edge (first octant)
|
||||||
|
DecrementY();
|
||||||
|
|
||||||
|
const int32_t distWithDiagonalMovement = m_sqDistFromEdge + xStepCost;
|
||||||
|
if (distWithDiagonalMovement >= 0)
|
||||||
|
{
|
||||||
|
IncrementX();
|
||||||
|
plotDir = PlotDirection_PosX_NegY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_0X_NegY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Diagonal movement will move farther from the center (second octant)
|
||||||
|
IncrementX();
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge < 0)
|
||||||
|
{
|
||||||
|
DecrementY();
|
||||||
|
plotDir = PlotDirection_PosX_NegY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_PosX_0Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_xChangeCostDynamicFactor >= 0)
|
||||||
|
m_quadrant = Quadrant_PxNy;
|
||||||
|
|
||||||
|
return plotDir;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Quadrant_PxNy:
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
const int32_t yStepCost = m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
const int32_t diagonalCostDelta = xStepCost + yStepCost;
|
||||||
|
|
||||||
|
if (diagonalCostDelta < 0)
|
||||||
|
{
|
||||||
|
// Diagonal movement will move closer to the edge (first octant)
|
||||||
|
IncrementX();
|
||||||
|
|
||||||
|
const int32_t distWithDiagonalMovement = m_sqDistFromEdge + yStepCost;
|
||||||
|
if (distWithDiagonalMovement >= 0)
|
||||||
|
{
|
||||||
|
IncrementY();
|
||||||
|
plotDir = PlotDirection_PosX_PosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_PosX_0Y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Diagonal movement will move farther from the center
|
||||||
|
IncrementY();
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge < 0)
|
||||||
|
{
|
||||||
|
IncrementX();
|
||||||
|
plotDir = PlotDirection_PosX_PosY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
plotDir = PlotDirection_0X_PosY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_yChangeCostDynamicFactor >= 0)
|
||||||
|
m_quadrant = Quadrant_Finished;
|
||||||
|
|
||||||
|
return plotDir;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Quadrant_Finished:
|
||||||
|
return PlotDirection_Exhausted;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return PlotDirection_Exhausted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EllipsePlotter::IncrementX()
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
|
||||||
|
m_sqDistFromEdge += xStepCost;
|
||||||
|
m_xChangeCostDynamicFactor += m_xChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_x++;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_x += 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EllipsePlotter::ConditionalIncrementX()
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge + xStepCost >= 0)
|
||||||
|
{
|
||||||
|
m_sqDistFromEdge += xStepCost;
|
||||||
|
m_xChangeCostDynamicFactor += m_xChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_x++;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_x += 2;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EllipsePlotter::IncrementY()
|
||||||
|
{
|
||||||
|
const int32_t yStepCost = m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
m_sqDistFromEdge += yStepCost;
|
||||||
|
m_yChangeCostDynamicFactor += m_yChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_y++;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_y += 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EllipsePlotter::ConditionalIncrementY()
|
||||||
|
{
|
||||||
|
const int32_t yStepCost = m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge + yStepCost >= 0)
|
||||||
|
{
|
||||||
|
m_sqDistFromEdge += yStepCost;
|
||||||
|
m_yChangeCostDynamicFactor += m_yChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_y++;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_y += 2;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EllipsePlotter::DecrementX()
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = -m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
|
||||||
|
m_sqDistFromEdge += xStepCost;
|
||||||
|
m_xChangeCostDynamicFactor -= m_xChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_x--;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_x -= 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EllipsePlotter::ConditionalDecrementX()
|
||||||
|
{
|
||||||
|
const int32_t xStepCost = -m_xChangeCostDynamicFactor + m_xChangeCostStaticFactor;
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge + xStepCost >= 0)
|
||||||
|
{
|
||||||
|
m_sqDistFromEdge += xStepCost;
|
||||||
|
m_xChangeCostDynamicFactor -= m_xChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_x--;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_x -= 2;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EllipsePlotter::DecrementY()
|
||||||
|
{
|
||||||
|
const int32_t yStepCost = -m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
m_sqDistFromEdge += yStepCost;
|
||||||
|
m_yChangeCostDynamicFactor -= m_yChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_y--;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_y -= 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EllipsePlotter::ConditionalDecrementY()
|
||||||
|
{
|
||||||
|
const int32_t yStepCost = -m_yChangeCostDynamicFactor + m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
if (m_sqDistFromEdge + yStepCost >= 0)
|
||||||
|
{
|
||||||
|
m_sqDistFromEdge += yStepCost;
|
||||||
|
m_yChangeCostDynamicFactor -= m_yChangeCostDynamicFactorStep;
|
||||||
|
m_point.m_y--;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter.m_y -= 2;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vec2i &EllipsePlotter::GetPoint() const
|
||||||
|
{
|
||||||
|
return m_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EllipsePlotter::Reset(const Rect2i &bounds)
|
||||||
|
{
|
||||||
|
assert(bounds.IsValid());
|
||||||
|
m_quadrant = Quadrant_PxPy;
|
||||||
|
|
||||||
|
m_2center = bounds.m_topLeft + bounds.m_bottomRight - Vec2i(1, 1);
|
||||||
|
m_diameters = bounds.m_bottomRight - bounds.m_topLeft - Vec2i(1, 1);
|
||||||
|
|
||||||
|
m_point.m_x = bounds.m_bottomRight.m_x - 1;
|
||||||
|
m_point.m_y = (m_2center.m_y + 1) / 2;
|
||||||
|
|
||||||
|
const Vec2i offsetFromCenterTimes2 = (m_point + m_point) - m_2center;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER
|
||||||
|
m_2offsetFromCenter = offsetFromCenterTimes2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_sqDistFromEdge = SquareInt32(offsetFromCenterTimes2.m_x * m_diameters.m_y) + SquareInt32(offsetFromCenterTimes2.m_y * m_diameters.m_x) - SquareInt32(m_diameters.m_x * m_diameters.m_y);
|
||||||
|
|
||||||
|
const int32_t xCostMultiplier = 4 * SquareInt32(m_diameters.m_y);
|
||||||
|
const int32_t yCostMultiplier = 4 * SquareInt32(m_diameters.m_x);
|
||||||
|
|
||||||
|
m_xChangeCostDynamicFactorStep = 2 * xCostMultiplier;
|
||||||
|
m_yChangeCostDynamicFactorStep = 2 * yCostMultiplier;
|
||||||
|
m_xChangeCostStaticFactor = 4 * SquareInt32(m_diameters.m_y);
|
||||||
|
m_yChangeCostStaticFactor = 4 * SquareInt32(m_diameters.m_x);
|
||||||
|
|
||||||
|
m_xChangeCostDynamicFactor = offsetFromCenterTimes2.m_x * xCostMultiplier;
|
||||||
|
m_yChangeCostDynamicFactor = offsetFromCenterTimes2.m_y * yCostMultiplier;
|
||||||
|
}
|
||||||
|
}
|
62
PortabilityLayer/EllipsePlotter.h
Normal file
62
PortabilityLayer/EllipsePlotter.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IPlotter.h"
|
||||||
|
#include "PlotDirection.h"
|
||||||
|
#include "Vec2i.h"
|
||||||
|
|
||||||
|
#define PL_DEBUG_ELLIPSE_PLOTTER 1
|
||||||
|
|
||||||
|
namespace PortabilityLayer
|
||||||
|
{
|
||||||
|
struct Rect2i;
|
||||||
|
|
||||||
|
class EllipsePlotter final : public IPlotter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EllipsePlotter();
|
||||||
|
PlotDirection PlotNext() override;
|
||||||
|
const Vec2i &GetPoint() const override;
|
||||||
|
|
||||||
|
void Reset(const Rect2i &bounds);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Quadrant
|
||||||
|
{
|
||||||
|
Quadrant_NxNy,
|
||||||
|
Quadrant_NxPy,
|
||||||
|
Quadrant_PxNy,
|
||||||
|
Quadrant_PxPy,
|
||||||
|
|
||||||
|
Quadrant_Finished
|
||||||
|
};
|
||||||
|
|
||||||
|
void IncrementX();
|
||||||
|
bool ConditionalIncrementX();
|
||||||
|
|
||||||
|
void IncrementY();
|
||||||
|
bool ConditionalIncrementY();
|
||||||
|
|
||||||
|
void DecrementX();
|
||||||
|
bool ConditionalDecrementX();
|
||||||
|
|
||||||
|
void DecrementY();
|
||||||
|
bool ConditionalDecrementY();
|
||||||
|
|
||||||
|
Vec2i m_2center;
|
||||||
|
Vec2i m_point;
|
||||||
|
Vec2i m_diameters;
|
||||||
|
int32_t m_sqDistFromEdge;
|
||||||
|
Quadrant m_quadrant;
|
||||||
|
|
||||||
|
int32_t m_xChangeCostDynamicFactor;
|
||||||
|
int32_t m_yChangeCostDynamicFactor;
|
||||||
|
int32_t m_xChangeCostDynamicFactorStep;
|
||||||
|
int32_t m_yChangeCostDynamicFactorStep;
|
||||||
|
int32_t m_xChangeCostStaticFactor;
|
||||||
|
int32_t m_yChangeCostStaticFactor;
|
||||||
|
|
||||||
|
#if PL_DEBUG_ELLIPSE_PLOTTER 1
|
||||||
|
Vec2i m_2offsetFromCenter;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
@@ -1,16 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "IPlotter.h"
|
||||||
#include "PlotDirection.h"
|
#include "PlotDirection.h"
|
||||||
#include "Vec2i.h"
|
#include "Vec2i.h"
|
||||||
|
|
||||||
namespace PortabilityLayer
|
namespace PortabilityLayer
|
||||||
{
|
{
|
||||||
class LinePlotter
|
class LinePlotter final : public IPlotter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LinePlotter();
|
LinePlotter();
|
||||||
PlotDirection PlotNext();
|
PlotDirection PlotNext() override;
|
||||||
const Vec2i &GetPoint() const;
|
const Vec2i &GetPoint() const override;
|
||||||
|
|
||||||
void Reset(const Vec2i &pointA, const Vec2i &pointB);
|
void Reset(const Vec2i &pointA, const Vec2i &pointB);
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
#include "ResTypeID.h"
|
#include "ResTypeID.h"
|
||||||
#include "RGBAColor.h"
|
#include "RGBAColor.h"
|
||||||
#include "ScanlineMask.h"
|
#include "ScanlineMask.h"
|
||||||
|
#include "ScanlineMaskConverter.h"
|
||||||
#include "ScanlineMaskIterator.h"
|
#include "ScanlineMaskIterator.h"
|
||||||
#include "QDStandardPalette.h"
|
#include "QDStandardPalette.h"
|
||||||
#include "WindowManager.h"
|
#include "WindowManager.h"
|
||||||
@@ -571,7 +572,15 @@ void PaintRect(const Rect *rect)
|
|||||||
|
|
||||||
void PaintOval(const Rect *rect)
|
void PaintOval(const Rect *rect)
|
||||||
{
|
{
|
||||||
PL_NotYetImplemented_TODO("Ovals");
|
if (!rect->IsValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
PortabilityLayer::ScanlineMask *mask = PortabilityLayer::ScanlineMaskConverter::CompileEllipse(PortabilityLayer::Rect2i(rect->top, rect->left, rect->bottom, rect->right));
|
||||||
|
if (mask)
|
||||||
|
{
|
||||||
|
FillScanlineMask(mask);
|
||||||
|
mask->Destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillScanlineSpan(uint8_t *rowStart, size_t startCol, size_t endCol)
|
void FillScanlineSpan(uint8_t *rowStart, size_t startCol, size_t endCol)
|
||||||
|
@@ -139,6 +139,7 @@
|
|||||||
<ClInclude Include="ClientAudioChannelContext.h" />
|
<ClInclude Include="ClientAudioChannelContext.h" />
|
||||||
<ClInclude Include="DataTypes.h" />
|
<ClInclude Include="DataTypes.h" />
|
||||||
<ClInclude Include="DisplayDeviceManager.h" />
|
<ClInclude Include="DisplayDeviceManager.h" />
|
||||||
|
<ClInclude Include="EllipsePlotter.h" />
|
||||||
<ClInclude Include="FileManager.h" />
|
<ClInclude Include="FileManager.h" />
|
||||||
<ClInclude Include="FilePermission.h" />
|
<ClInclude Include="FilePermission.h" />
|
||||||
<ClInclude Include="FilePos.h" />
|
<ClInclude Include="FilePos.h" />
|
||||||
@@ -261,6 +262,7 @@
|
|||||||
<ClCompile Include="ByteSwap.cpp" />
|
<ClCompile Include="ByteSwap.cpp" />
|
||||||
<ClCompile Include="CFileStream.cpp" />
|
<ClCompile Include="CFileStream.cpp" />
|
||||||
<ClCompile Include="DisplayDeviceManager.cpp" />
|
<ClCompile Include="DisplayDeviceManager.cpp" />
|
||||||
|
<ClCompile Include="EllipsePlotter.cpp" />
|
||||||
<ClCompile Include="FileManager.cpp" />
|
<ClCompile Include="FileManager.cpp" />
|
||||||
<ClCompile Include="FontFamily.cpp" />
|
<ClCompile Include="FontFamily.cpp" />
|
||||||
<ClCompile Include="FontManager.cpp" />
|
<ClCompile Include="FontManager.cpp" />
|
||||||
|
@@ -393,6 +393,9 @@
|
|||||||
<ClInclude Include="ScanlineMaskDataStorage.h">
|
<ClInclude Include="ScanlineMaskDataStorage.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="EllipsePlotter.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="CFileStream.cpp">
|
<ClCompile Include="CFileStream.cpp">
|
||||||
@@ -596,5 +599,8 @@
|
|||||||
<ClCompile Include="ScanlineMaskIterator.cpp">
|
<ClCompile Include="ScanlineMaskIterator.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="EllipsePlotter.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@@ -19,7 +19,7 @@ namespace PortabilityLayer
|
|||||||
Rect2i(const Rect2i &other);
|
Rect2i(const Rect2i &other);
|
||||||
explicit Rect2i(const Rect &other);
|
explicit Rect2i(const Rect &other);
|
||||||
Rect2i(const Vec2i &topLeft, const Vec2i &bottomRight);
|
Rect2i(const Vec2i &topLeft, const Vec2i &bottomRight);
|
||||||
Rect2i(int32_t left, int32_t top, int32_t bottom, int32_t right);
|
Rect2i(int32_t top, int32_t left, int32_t bottom, int32_t right);
|
||||||
|
|
||||||
Rect2i operator+(const Vec2i &other) const;
|
Rect2i operator+(const Vec2i &other) const;
|
||||||
Rect2i operator-(const Vec2i &other) const;
|
Rect2i operator-(const Vec2i &other) const;
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
#include "ScanlineMaskConverter.h"
|
#include "ScanlineMaskConverter.h"
|
||||||
|
|
||||||
|
#include "EllipsePlotter.h"
|
||||||
|
#include "Rect2i.h"
|
||||||
#include "ScanlineMask.h"
|
#include "ScanlineMask.h"
|
||||||
#include "Vec2i.h"
|
#include "Vec2i.h"
|
||||||
#include "LinePlotter.h"
|
#include "LinePlotter.h"
|
||||||
@@ -252,6 +255,33 @@ namespace PortabilityLayer
|
|||||||
return ScanlineMask::Create(Rect::Create(minPoint.m_y, minPoint.m_x, minPoint.m_y + static_cast<int16_t>(height), minPoint.m_x + static_cast<int16_t>(width)), maskBuilder);
|
return ScanlineMask::Create(Rect::Create(minPoint.m_y, minPoint.m_x, minPoint.m_y + static_cast<int16_t>(height), minPoint.m_x + static_cast<int16_t>(width)), maskBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SinglePointPlotter final : public IPlotter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SinglePointPlotter(const Vec2i &point);
|
||||||
|
|
||||||
|
PlotDirection PlotNext() override;
|
||||||
|
const Vec2i &GetPoint() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Vec2i &m_point;
|
||||||
|
};
|
||||||
|
|
||||||
|
SinglePointPlotter::SinglePointPlotter(const Vec2i &point)
|
||||||
|
: m_point(point)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PlotDirection SinglePointPlotter::PlotNext()
|
||||||
|
{
|
||||||
|
return PlotDirection_Exhausted;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vec2i &SinglePointPlotter::GetPoint() const
|
||||||
|
{
|
||||||
|
return m_point;
|
||||||
|
}
|
||||||
|
|
||||||
class PolyPlotter final : public IPlotter
|
class PolyPlotter final : public IPlotter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -322,4 +352,34 @@ namespace PortabilityLayer
|
|||||||
PolyPlotter polyPlotter(points, numPoints);
|
PolyPlotter polyPlotter(points, numPoints);
|
||||||
return ComputePlot(width, height, minPoint, polyPlotter);
|
return ComputePlot(width, height, minPoint, polyPlotter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScanlineMask *ScanlineMaskConverter::CompileEllipse(const Rect2i &rect)
|
||||||
|
{
|
||||||
|
if (!rect.IsValid() || rect.m_topLeft.m_x == rect.m_bottomRight.m_x || rect.m_topLeft.m_y == rect.m_bottomRight.m_y)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const uint32_t width = rect.m_bottomRight.m_x - rect.m_topLeft.m_x;
|
||||||
|
const uint32_t height = rect.m_bottomRight.m_y - rect.m_topLeft.m_y;
|
||||||
|
|
||||||
|
if (width == 1 || height == 1)
|
||||||
|
{
|
||||||
|
if (width == 1 && height == 1)
|
||||||
|
{
|
||||||
|
SinglePointPlotter plotter(rect.m_topLeft);
|
||||||
|
return ComputePlot(1, 1, rect.m_topLeft, plotter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LinePlotter plotter;
|
||||||
|
plotter.Reset(rect.m_topLeft, rect.m_bottomRight - Vec2i(1, 1));
|
||||||
|
return ComputePlot(width, height, rect.m_topLeft, plotter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EllipsePlotter plotter;
|
||||||
|
plotter.Reset(rect);
|
||||||
|
return ComputePlot(width, height, rect.m_topLeft, plotter);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,10 +6,12 @@ namespace PortabilityLayer
|
|||||||
{
|
{
|
||||||
class ScanlineMask;
|
class ScanlineMask;
|
||||||
struct Vec2i;
|
struct Vec2i;
|
||||||
|
struct Rect2i;
|
||||||
|
|
||||||
class ScanlineMaskConverter
|
class ScanlineMaskConverter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static ScanlineMask *CompilePoly(const Vec2i *points, size_t numPoints);
|
static ScanlineMask *CompilePoly(const Vec2i *points, size_t numPoints);
|
||||||
|
static ScanlineMask *CompileEllipse(const Rect2i &rect);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user