#![allow(unused_parens)]
use std::cell::Cell;
use crate::aacoverage::c_nShift;
use crate::bezier::CMILBezier;
use crate::helpers::Int32x32To64;
use crate::matrix::CMILMatrix;
use crate::nullable_ref::Ref;
use crate::real::CFloatFPU;
use crate::types::*;
use typed_arena_nomut::Arena;
const S_OK: HRESULT = 0;
#[cfg(debug_assertions)]
macro_rules! EDGE_STORE_STACK_NUMBER {
() => {
10
};
}
#[cfg(debug_assertions)]
macro_rules! EDGE_STORE_ALLOCATION_NUMBER { () => { 11 }; }
#[cfg(debug_assertions)]
macro_rules! INACTIVE_LIST_NUMBER { () => { 12 }; }
#[cfg(debug_assertions)]
macro_rules! ENUMERATE_BUFFER_NUMBER { () => { 15 }; }
#[cfg(not(debug_assertions))]
macro_rules! EDGE_STORE_STACK_NUMBER { () => { (1600 / std::mem::size_of::<CEdge>()) }; }
#[cfg(not(debug_assertions))]
macro_rules! EDGE_STORE_ALLOCATION_NUMBER { () => { (4032 / std::mem::size_of::<CEdge>()) as u32 }; }
#[cfg(not(debug_assertions))]
macro_rules! INACTIVE_LIST_NUMBER { () => { EDGE_STORE_STACK_NUMBER!() }; }
#[cfg(not(debug_assertions))]
macro_rules! ENUMERATE_BUFFER_NUMBER { () => { 32 }; }
macro_rules! ASSERTACTIVELIST {
($list: expr, $y: expr) => {
_ = $y;
#[cfg(debug_assertions)]
AssertActiveList($list, $y);
};
}
pub struct CEdge<'a> {
pub Next: Cell<Ref<'a, CEdge<'a>>>, pub X: Cell<INT>, pub Dx: INT, pub Error: Cell<INT>, pub ErrorUp: INT, pub ErrorDown: INT, pub StartY: INT, pub EndY: INT, pub WindingDirection: INT, }
impl<'a> std::default::Default for CEdge<'a> {
fn default() -> Self {
Self {
Next: Cell::new(unsafe { Ref::null() }),
X: Default::default(),
Dx: Default::default(),
Error: Default::default(),
ErrorUp: Default::default(),
ErrorDown: Default::default(),
StartY: Default::default(),
EndY: Default::default(),
WindingDirection: Default::default(),
}
}
}
#[derive(Clone)]
pub struct CInactiveEdge<'a> {
Edge: Ref<'a, CEdge<'a>>, Yx: LONGLONG, }
impl<'a> Default for CInactiveEdge<'a> {
fn default() -> Self {
Self {
Edge: unsafe { Ref::null() },
Yx: Default::default(),
}
}
}
macro_rules! ASSERTACTIVELISTORDER {
($list: expr) => {
#[cfg(debug_assertions)]
AssertActiveListOrder($list)
};
}
pub fn AdvanceDDAAndUpdateActiveEdgeList(nSubpixelYCurrent: INT, pEdgeActiveList: Ref<CEdge>) {
let mut outOfOrder = false;
let mut pEdgePrevious: Ref<CEdge> = pEdgeActiveList;
let mut pEdgeCurrent: Ref<CEdge> = pEdgeActiveList.Next.get();
let mut prevX = pEdgePrevious.X.get();
loop {
if (pEdgeCurrent.EndY <= nSubpixelYCurrent) {
if (pEdgeCurrent.EndY == INT::MIN) {
break; }
pEdgeCurrent = pEdgeCurrent.Next.get();
pEdgePrevious.Next.set(pEdgeCurrent);
continue; }
let mut x = pEdgeCurrent.X.get() + pEdgeCurrent.Dx;
let mut error = pEdgeCurrent.Error.get() + pEdgeCurrent.ErrorUp;
if (error >= 0) {
error -= pEdgeCurrent.ErrorDown;
x += 1;
}
pEdgeCurrent.X.set(x);
pEdgeCurrent.Error.set(error);
outOfOrder |= (prevX > x);
pEdgePrevious = pEdgeCurrent;
pEdgeCurrent = pEdgeCurrent.Next.get();
prevX = x;
}
if (outOfOrder) {
SortActiveEdges(pEdgeActiveList);
}
ASSERTACTIVELISTORDER!(pEdgeActiveList);
}
const SORT_EDGES_INCLUDING_SLOPE: bool = false;
macro_rules! QUOTIENT_REMAINDER {
($ulNumerator: ident, $ulDenominator: ident, $ulQuotient: ident, $ulRemainder: ident) => {
$ulQuotient = (($ulNumerator as ULONG) / ($ulDenominator as ULONG)) as _;
$ulRemainder = (($ulNumerator as ULONG) % ($ulDenominator as ULONG)) as _;
};
}
macro_rules! QUOTIENT_REMAINDER_64_32 {
($ulNumerator: ident, $ulDenominator: ident, $ulQuotient: ident, $ulRemainder: ident) => {
$ulQuotient = (($ulNumerator as ULONGLONG) / (($ulDenominator as ULONG) as ULONGLONG)) as _;
$ulRemainder =
(($ulNumerator as ULONGLONG) % (($ulDenominator as ULONG) as ULONGLONG)) as _;
};
}
macro_rules! SWAP {
($temp: ident, $a: expr, $b: expr) => {
$temp = $a;
$a = $b;
$b = $temp;
};
}
struct CEdgeAllocation {
Next: *mut CEdgeAllocation, Count: UINT,
EdgeArray: [CEdge<'static>; EDGE_STORE_STACK_NUMBER!()],
}
impl Default for CEdgeAllocation {
fn default() -> Self {
Self { Next: NULL(), Count: Default::default(), EdgeArray: [(); EDGE_STORE_STACK_NUMBER!()].map(|_| Default::default()) }
}
}
pub fn AssertActiveList(mut list: Ref<CEdge>, yCurrent: INT) -> bool {
let mut b = true;
let mut activeCount = 0;
assert!((*list).X.get() == INT::MIN);
b &= ((*list).X.get() == INT::MIN);
list = (*list).Next.get();
while ((*list).X.get() != INT::MAX) {
assert!((*list).X.get() != INT::MIN);
b &= ((*list).X.get() != INT::MIN);
assert!((*list).X <= (*(*list).Next.get()).X);
b &= ((*list).X <= (*(*list).Next.get()).X);
assert!(((*list).StartY <= yCurrent) && (yCurrent < (*list).EndY));
b &= (((*list).StartY <= yCurrent) && (yCurrent < (*list).EndY));
activeCount += 1;
list = (*list).Next.get();
}
assert!((*list).X.get() == INT::MAX);
b &= ((*list).X.get() == INT::MAX);
assert!((activeCount & 1) == 0);
b &= ((activeCount & 1) == 0);
return (b);
}
fn AssertActiveListOrder(mut list: Ref<CEdge>) {
assert!((*list).X.get() == INT::MIN);
list = (*list).Next.get();
while ((*list).X.get() != INT::MAX) {
assert!((*list).X.get() != INT::MIN);
assert!((*list).X <= (*(*list).Next.get()).X);
list = (*list).Next.get();
}
assert!((*list).X.get() == INT::MAX);
}
fn ClipEdge(edgeBuffer: &mut CEdge, yClipTopInteger: INT, dMOriginal: INT) {
let mut xDelta: INT;
let mut error: INT;
let dN: INT = edgeBuffer.ErrorDown;
let mut bigNumerator: LONGLONG = Int32x32To64(dMOriginal, yClipTopInteger - edgeBuffer.StartY)
+ (edgeBuffer.Error.get() + dN) as LONGLONG;
if (bigNumerator >= 0) {
QUOTIENT_REMAINDER_64_32!(bigNumerator, dN, xDelta, error);
} else {
bigNumerator = -bigNumerator;
QUOTIENT_REMAINDER_64_32!(bigNumerator, dN, xDelta, error);
xDelta = -xDelta;
if (error != 0) {
xDelta -= 1;
error = dN - error;
}
}
edgeBuffer.StartY = yClipTopInteger;
edgeBuffer.X.set(edgeBuffer.X.get() + xDelta);
edgeBuffer.Error.set(error - dN); }
pub fn CheckValidRange28_4(x: f32, y: f32) -> bool {
let rPixelCoordinateMax = (1 << (26 - c_nShift)) as f32;
let rPixelCoordinateMin = -rPixelCoordinateMax;
return x <= rPixelCoordinateMax && x >= rPixelCoordinateMin
&& y <= rPixelCoordinateMax && y >= rPixelCoordinateMin;
}
fn TransformRasterizerPointsTo28_4(
pmat: &CMILMatrix,
mut pPtsSource: &[MilPoint2F],
mut cPoints: UINT,
mut pPtsDest: &mut [POINT], ) -> HRESULT {
let hr = S_OK;
debug_assert!(cPoints > 0);
while {
let rPixelX =
(pmat.GetM11() * pPtsSource[0].X) + (pmat.GetM21() * pPtsSource[0].Y) + pmat.GetDx();
let rPixelY =
(pmat.GetM12() * pPtsSource[0].X) + (pmat.GetM22() * pPtsSource[0].Y) + pmat.GetDy();
if !CheckValidRange28_4(rPixelX, rPixelY) {
return WGXERR_BADNUMBER;
}
pPtsDest[0].x = CFloatFPU::Round(rPixelX);
pPtsDest[0].y = CFloatFPU::Round(rPixelY);
pPtsDest = &mut pPtsDest[1..];
pPtsSource = &pPtsSource[1..];
cPoints -= 1;
cPoints != 0
} {}
return hr;
}
pub fn AppendScaleToMatrix(pmat: &mut CMILMatrix, scaleX: REAL, scaleY: REAL) {
pmat.SetM11(pmat.GetM11() * scaleX);
pmat.SetM21(pmat.GetM21() * scaleX);
pmat.SetM12(pmat.GetM12() * scaleY);
pmat.SetM22(pmat.GetM22() * scaleY);
pmat.SetDx(pmat.GetDx() * scaleX);
pmat.SetDy(pmat.GetDy() * scaleY);
}
pub struct CInitializeEdgesContext<'a> {
pub MaxY: INT, pub ClipRect: Option<&'a RECT>, pub Store: &'a Arena<CEdge<'a>>, pub AntiAliasMode: MilAntiAliasMode,
}
impl<'a> CInitializeEdgesContext<'a> {
pub fn new(store: &'a Arena<CEdge<'a>>) -> Self {
CInitializeEdgesContext { MaxY: Default::default(), ClipRect: Default::default(), Store: store, AntiAliasMode: MilAntiAliasMode::None }
}
}
fn InitializeEdges(
pEdgeContext: &mut CInitializeEdgesContext,
mut pointArray: &mut [POINT], vertexCount: UINT,
) -> HRESULT {
let hr = S_OK;
let mut xStart;
let mut yStart;
let mut yStartInteger;
let mut yEndInteger;
let mut dMOriginal;
let mut dM: i32;
let mut dN: i32;
let mut dX: i32;
let mut errorUp: i32;
let mut quotient: i32;
let mut remainder: i32;
let mut error: i32;
let mut windingDirection;
let bufferCount: UINT = 0;
let mut yClipTopInteger;
let mut yClipTop;
let mut yClipBottom;
let mut xClipLeft;
let mut xClipRight;
let mut yMax = pEdgeContext.MaxY;
let _store = &mut pEdgeContext.Store;
let clipRect = pEdgeContext.ClipRect;
let mut edgeCount = vertexCount - 1;
assert!(edgeCount >= 1);
if let Some(clipRect) = clipRect {
yClipTopInteger = clipRect.top >> 4;
yClipTop = clipRect.top;
yClipBottom = clipRect.bottom;
xClipLeft = clipRect.left;
xClipRight = clipRect.right;
assert!(yClipBottom > 0);
assert!(yClipTop <= yClipBottom);
} else {
yClipBottom = 0;
yClipTopInteger = INT::MIN >> c_nShift;
yClipTop = 0;
xClipLeft = 0;
xClipRight = 0;
}
if (pEdgeContext.AntiAliasMode != MilAntiAliasMode::None) {
let mut point = &mut *pointArray;
let mut i = vertexCount;
while {
point[0].x = (point[0].x + 8) << c_nShift;
point[0].y = (point[0].y + 8) << c_nShift;
point = &mut point[1..];
i -= 1;
i != 0
} {}
yClipTopInteger <<= c_nShift;
yClipTop <<= c_nShift;
yClipBottom <<= c_nShift;
xClipLeft <<= c_nShift;
xClipRight <<= c_nShift;
}
yClipBottom -= 16;
'outer: loop { loop {
if (yClipBottom >= 0) {
let clipHigh = ((pointArray[0]).y <= yClipTop) && ((pointArray[1]).y <= yClipTop);
let clipLow = ((pointArray[0]).y > yClipBottom) && ((pointArray[1]).y > yClipBottom);
#[cfg(debug_assertions)]
{
let (mut yRectTop, mut yRectBottom, y0, y1, yTop, yBottom);
let mut clipped = false;
if let Some(clipRect) = clipRect {
yRectTop = clipRect.top >> 4;
yRectBottom = clipRect.bottom >> 4;
if (pEdgeContext.AntiAliasMode != MilAntiAliasMode::None) {
yRectTop <<= c_nShift;
yRectBottom <<= c_nShift;
}
y0 = ((pointArray[0]).y + 15) >> 4;
y1 = ((pointArray[1]).y + 15) >> 4;
yTop = y0.min(y1);
yBottom = y0.max(y1);
clipped = ((yTop >= yRectBottom) || (yBottom <= yRectTop));
}
assert!(clipped == (clipHigh || clipLow));
}
if (clipHigh || clipLow) {
break; }
if (edgeCount > 1) {
if (((pointArray[0]).x < xClipLeft)
&& ((pointArray[1]).x < xClipLeft)
&& ((pointArray[2]).x < xClipLeft))
{
pointArray[1] = pointArray[0];
break; }
if (((pointArray[0]).x > xClipRight)
&& ((pointArray[1]).x > xClipRight)
&& ((pointArray[2]).x > xClipRight))
{
pointArray[1] = pointArray[0];
break; }
}
}
dM = (pointArray[1]).x - (pointArray[0]).x;
dN = (pointArray[1]).y - (pointArray[0]).y;
if (dN >= 0) {
xStart = (pointArray[0]).x;
yStart = (pointArray[0]).y;
yStartInteger = (yStart + 15) >> 4;
yEndInteger = ((pointArray[1]).y + 15) >> 4;
windingDirection = 1;
} else {
dN = -dN;
dM = -dM;
xStart = (pointArray[1]).x;
yStart = (pointArray[1]).y;
yStartInteger = (yStart + 15) >> 4;
yEndInteger = ((pointArray[0]).y + 15) >> 4;
windingDirection = -1;
}
if (yEndInteger > yStartInteger) {
yMax = yMax.max(yEndInteger);
dMOriginal = dM;
if (dM < 0) {
dM = -dM;
if (dM < dN)
{
dX = -1;
errorUp = dN - dM;
} else {
QUOTIENT_REMAINDER!(dM, dN, quotient, remainder);
dX = -quotient;
errorUp = remainder;
if (remainder > 0) {
dX = -quotient - 1;
errorUp = dN - remainder;
}
}
} else {
if (dM < dN) {
dX = 0;
errorUp = dM;
} else {
QUOTIENT_REMAINDER!(dM, dN, quotient, remainder);
dX = quotient;
errorUp = remainder;
}
}
error = -1;
if ((yStart & 15) != 0) {
let mut i = 16 - (yStart & 15);
while i != 0 {
xStart += dX;
error += errorUp;
if (error >= 0)
{
error -= dN;
xStart += 1;
}
i -= 1;
}
}
if ((xStart & 15) != 0) {
error -= dN * (16 - (xStart & 15));
xStart += 15; }
xStart >>= 4;
error >>= 4;
if (bufferCount == 0) {
}
let mut edge = CEdge {
Next: Cell::new(unsafe { Ref::null() } ),
X: Cell::new(xStart),
Dx: dX,
Error: Cell::new(error),
ErrorUp: errorUp,
ErrorDown: dN,
WindingDirection: windingDirection,
StartY: yStartInteger,
EndY: yEndInteger, };
assert!(error < 0);
if (yClipTopInteger > yStartInteger) {
assert!(edge.EndY > yClipTopInteger);
ClipEdge(&mut edge, yClipTopInteger, dMOriginal);
}
pEdgeContext.Store.alloc(edge);
}
break;
}
pointArray = &mut pointArray[1..];
edgeCount -= 1;
if edgeCount == 0 {
break 'outer;
}
}
pEdgeContext.MaxY = yMax;
return hr;
}
fn ValidatePathTypes(typesArray: &[BYTE], mut count: INT) -> bool {
let mut types = typesArray;
if (count == 0) {
return (true);
}
loop {
if ((types[0] & PathPointTypePathTypeMask) != PathPointTypeStart) {
TraceTag!((tagMILWarning, "Bad subpath start"));
return (false);
}
count -= 1;
if (count == 0) {
TraceTag!((tagMILWarning, "Path ended after start-path"));
return (false);
}
if ((types[1] & PathPointTypePathTypeMask) == PathPointTypeStart) {
TraceTag!((tagMILWarning, "Can't have a start followed by a start!"));
return (false);
}
loop {
match (types[1] & PathPointTypePathTypeMask) {
PathPointTypeLine => {
types = &types[1..];
count -= 1;
if (count == 0) {
return (true);
}
}
PathPointTypeBezier => {
if (count < 3) {
TraceTag!((
tagMILWarning,
"Path ended before multiple of 3 Bezier points"
));
return (false);
}
if ((types[1] & PathPointTypePathTypeMask) != PathPointTypeBezier) {
TraceTag!((tagMILWarning, "Bad subpath start"));
return (false);
}
types = &types[1..];
count -= 3;
if (count == 0) {
return (true);
}
}
_ => {
TraceTag!((tagMILWarning, "Illegal type"));
return (false);
}
}
if !(!((types[0] & PathPointTypeCloseSubpath) != 0)
&& ((types[1] & PathPointTypePathTypeMask) != PathPointTypeStart)) {
types = &types[1..];
break;
}
}
}
}
macro_rules! ASSERTPATH {
($types: expr, $points: expr) => {
#[cfg(debug_assertions)]
AssertPath($types, $points)
};
}
fn AssertPath(rgTypes: &[BYTE], cPoints: UINT) {
assert!(ValidatePathTypes(rgTypes, cPoints as INT));
}
pub fn FixedPointPathEnumerate(
rgpt: &[POINT],
rgTypes: &[BYTE],
cPoints: UINT,
_matrix: &CMILMatrix,
clipRect: Option<&RECT>, enumerateContext: &mut CInitializeEdgesContext,
) -> HRESULT {
let hr = S_OK;
let mut bufferStart: [POINT; ENUMERATE_BUFFER_NUMBER!()] = [(); ENUMERATE_BUFFER_NUMBER!()].map(|_| Default::default());
let mut bezierBuffer: [POINT; 4] = Default::default();
let mut buffer: &mut [POINT];
let mut bufferSize: usize;
let mut startFigure: [POINT; 1] = Default::default();
let mut iPoint: usize;
let mut iType: usize;
let mut runSize: usize;
let mut thisCount: usize;
let mut isMore: bool = false;
let mut xLast: INT;
let mut yLast: INT;
ASSERTPATH!(rgTypes, cPoints);
iPoint = 0;
iType = 0;
assert!(cPoints > 1);
while (iPoint < cPoints as usize - 1) {
assert!((rgTypes[iType] & PathPointTypePathTypeMask) == PathPointTypeStart);
assert!((rgTypes[iType + 1] & PathPointTypePathTypeMask) != PathPointTypeStart);
startFigure[0] = rgpt[iPoint];
bufferStart[0].x = startFigure[0].x;
bufferStart[0].y = startFigure[0].y;
let bufferStartPtr = bufferStart.as_ptr();
buffer = &mut bufferStart[1..];
bufferSize = ENUMERATE_BUFFER_NUMBER!() - 1;
iPoint += 1;
iType += 1;
while {
if ((rgTypes[iType] & PathPointTypePathTypeMask) == PathPointTypeLine) {
runSize = 1;
while ((iPoint + runSize < cPoints as usize)
&& ((rgTypes[iType + runSize] & PathPointTypePathTypeMask) == PathPointTypeLine))
{
runSize += 1;
}
loop {
thisCount = bufferSize.min(runSize);
buffer[0 .. thisCount].copy_from_slice(&rgpt[iPoint .. iPoint + thisCount]);
__analysis_assume!(
buffer + bufferSize == bufferStart + ENUMERATE_BUFFER_NUMBER
);
assert!(buffer.as_ptr().wrapping_offset(bufferSize as isize) == bufferStartPtr.wrapping_offset(ENUMERATE_BUFFER_NUMBER!()) );
iPoint += thisCount;
iType += thisCount;
buffer = &mut buffer[thisCount..];
runSize -= thisCount;
bufferSize -= thisCount;
if (bufferSize > 0) {
break;
}
xLast = bufferStart[ENUMERATE_BUFFER_NUMBER!() - 1].x;
yLast = bufferStart[ENUMERATE_BUFFER_NUMBER!() - 1].y;
IFR!(InitializeEdges(
enumerateContext,
&mut bufferStart,
ENUMERATE_BUFFER_NUMBER!()
));
bufferStart[0].x = xLast;
bufferStart[0].y = yLast;
buffer = &mut bufferStart[1..];
bufferSize = ENUMERATE_BUFFER_NUMBER!() - 1;
if !(runSize != 0) {
break;
}
}
} else {
assert!(iPoint + 3 <= cPoints as usize);
assert!((rgTypes[iType] & PathPointTypePathTypeMask) == PathPointTypeBezier);
bezierBuffer.copy_from_slice(&rgpt[(iPoint - 1) .. iPoint + 3]);
iPoint += 3;
iType += 1;
let mut bezier = CMILBezier::new(&bezierBuffer, clipRect);
loop {
thisCount = bezier.Flatten(buffer, &mut isMore) as usize;
__analysis_assume!(
buffer + bufferSize == bufferStart + ENUMERATE_BUFFER_NUMBER!()
);
assert!(buffer.as_ptr().wrapping_offset(bufferSize as isize) == bufferStartPtr.wrapping_offset(ENUMERATE_BUFFER_NUMBER!()));
buffer = &mut buffer[thisCount..];
bufferSize -= thisCount;
if (bufferSize > 0) {
break;
}
xLast = bufferStart[ENUMERATE_BUFFER_NUMBER!() - 1].x;
yLast = bufferStart[ENUMERATE_BUFFER_NUMBER!() - 1].y;
IFR!(InitializeEdges(
enumerateContext,
&mut bufferStart,
ENUMERATE_BUFFER_NUMBER!()
));
bufferStart[0].x = xLast;
bufferStart[0].y = yLast;
buffer = &mut bufferStart[1..];
bufferSize = ENUMERATE_BUFFER_NUMBER!() - 1;
if !isMore {
break;
}
}
}
((iPoint < cPoints as usize)
&& ((rgTypes[iType] & PathPointTypePathTypeMask) != PathPointTypeStart))
} {}
buffer[0].x = startFigure[0].x;
buffer[0].y = startFigure[0].y;
bufferSize -= 1;
let verticesInBatch = ENUMERATE_BUFFER_NUMBER!() - bufferSize;
if (verticesInBatch > 1) {
IFR!(InitializeEdges(
enumerateContext,
&mut bufferStart,
(verticesInBatch) as UINT
));
}
}
return hr;
}
fn YX(x: INT, y: INT, p: &mut LONGLONG) {
*p = (((y as u64) << 32) | (((x as i64 + i32::MAX as i64) as u64) & 0xffffffff)) as i64;
}
const QUICKSORT_THRESHOLD: isize = 8;
fn QuickSortEdges(inactive: &mut [CInactiveEdge],
f: usize,
l: usize,
) {
let mut e: Ref<CEdge>;
let mut y: LONGLONG;
let mut first: LONGLONG;
let mut second: LONGLONG;
let mut last: LONGLONG;
let m = f + ((l - f) >> 1);
SWAP!(y, inactive[f + 1].Yx, inactive[m].Yx);
SWAP!(e, inactive[f + 1].Edge, inactive[m].Edge);
if {second = inactive[f + 1].Yx; second > {last = inactive[l].Yx; last}} {
inactive[f + 1].Yx = last;
inactive[l].Yx = second;
SWAP!(e, inactive[f + 1].Edge, inactive[l].Edge);
}
if {first = inactive[f].Yx; first} > {last = inactive[l].Yx; last} {
inactive[f].Yx = last;
inactive[l].Yx = first;
SWAP!(e, inactive[f].Edge, inactive[l].Edge);
}
if {second = inactive[f + 1].Yx; second} > {first = inactive[f].Yx; first} {
inactive[f + 1].Yx = first;
inactive[f].Yx = second;
SWAP!(e, inactive[f + 1].Edge, inactive[f].Edge);
}
debug_assert!((inactive[f + 1].Yx <= inactive[f].Yx) && (inactive[f].Yx <= inactive[l].Yx));
let median = inactive[f].Yx;
let mut i = f + 2;
while (inactive[i].Yx < median) {
i += 1;
}
let mut j = l - 1;
while (inactive[j].Yx > median) {
j -= 1;
}
while (i < j) {
SWAP!(y, inactive[i].Yx, inactive[j].Yx);
SWAP!(e, inactive[i].Edge, inactive[j].Edge);
while {
i = i + 1;
inactive[i].Yx < median
} {}
while {
j = j - 1 ;
inactive[j].Yx > median
} {}
}
SWAP!(y, inactive[f].Yx, inactive[j].Yx);
SWAP!(e, inactive[f].Edge, inactive[j].Edge);
let a = j - f;
let b = l - j;
if (a <= b) {
if (a > QUICKSORT_THRESHOLD as usize) {
QuickSortEdges(inactive, f, j - 1);
QuickSortEdges(inactive, j + 1, l);
} else if (b > QUICKSORT_THRESHOLD as usize) {
QuickSortEdges(inactive, j + 1, l);
}
} else {
if (b > QUICKSORT_THRESHOLD as usize) {
QuickSortEdges(inactive, j + 1 , l);
QuickSortEdges(inactive, f, j + 1);
} else if (a > QUICKSORT_THRESHOLD as usize) {
QuickSortEdges(inactive, f, j -1);
}
}
}
fn InsertionSortEdges(
mut inactive: &mut [CInactiveEdge],
mut count: INT,
) {
let mut e: Ref<CEdge>;
let mut y: LONGLONG;
let mut yPrevious: LONGLONG;
assert!(inactive[0].Yx == i64::MIN);
assert!(count >= 2);
let mut indx = 2; count -= 1;
while {
let mut p = indx;
e = (inactive[indx]).Edge;
y = (inactive[indx]).Yx;
while (y < {yPrevious = inactive[p-1].Yx; yPrevious}) {
inactive[p].Yx = yPrevious;
inactive[p].Edge = inactive[p-1].Edge;
p -= 1;
}
inactive[p].Yx = y;
inactive[p].Edge = e;
assert!((indx - p) <= QUICKSORT_THRESHOLD as usize);
indx += 1;
count -= 1;
count != 0
} {}
}
macro_rules! ASSERTINACTIVEARRAY {
($inactive: expr, $count: expr) => {
#[cfg(debug_assertions)]
AssertInactiveArray($inactive, $count);
};
}
fn AssertInactiveArray(
mut inactive: &[CInactiveEdge], mut count: INT,
) {
assert!(inactive[0].Yx == i64::MIN);
assert!(inactive[1].Yx != i64::MIN);
while {
let mut yx: LONGLONG = 0;
YX((*inactive[1].Edge).X.get(), (*inactive[1].Edge).StartY, &mut yx);
assert!(inactive[1].Yx == yx);
assert!(inactive[1].Yx >= inactive[0].Yx);
inactive = &inactive[1..];
count -= 1;
count != 0
} {}
assert!((*inactive[1].Edge).StartY == INT::MAX);
}
pub fn InitializeInactiveArray<'a>(
pEdgeStore: &'a Arena<CEdge<'a>>,
rgInactiveArray: &mut [CInactiveEdge<'a>],
count: UINT,
tailEdge: Ref<'a, CEdge<'a>> ) -> INT {
let rgInactiveArrayPtr = rgInactiveArray.as_mut_ptr();
let mut pInactiveEdge = &mut rgInactiveArray[1..];
for e in pEdgeStore.iter() {
pInactiveEdge[0].Edge = Ref::new(e);
YX(e.X.get(), e.StartY, &mut pInactiveEdge[0].Yx);
pInactiveEdge = &mut pInactiveEdge[1..];
}
assert!(unsafe { pInactiveEdge.as_mut_ptr().offset_from(rgInactiveArrayPtr) } as UINT == count + 1);
pInactiveEdge[0].Edge = tailEdge;
rgInactiveArray[0].Yx = i64::MIN;
if (count as isize > QUICKSORT_THRESHOLD) {
QuickSortEdges(rgInactiveArray, 1, count as usize);
}
InsertionSortEdges(rgInactiveArray, count as i32);
ASSERTINACTIVEARRAY!(rgInactiveArray, count as i32);
return (*rgInactiveArray[1].Edge).StartY;
}
pub fn InsertNewEdges<'a>(
mut pActiveList: Ref<'a, CEdge<'a>>,
iCurrentY: INT,
ppInactiveEdge: &'a mut [CInactiveEdge<'a>],
pYNextInactive: &mut INT, ) -> &'a mut [CInactiveEdge<'a>] {
let mut inactive: &mut [CInactiveEdge] = ppInactiveEdge;
assert!((*inactive[0].Edge).StartY == iCurrentY);
while {
let newActive: Ref<CEdge> = inactive[0].Edge;
while ((*(*pActiveList).Next.get()).X < (*newActive).X) {
pActiveList = (*pActiveList).Next.get();
}
if SORT_EDGES_INCLUDING_SLOPE {
while (((*(*pActiveList).Next.get()).X == (*newActive).X) && ((*(*pActiveList).Next.get()).Dx < (*newActive).Dx)) {
pActiveList = (*pActiveList).Next.get();
}
}
(*newActive).Next.set((*pActiveList).Next.get());
(*pActiveList).Next.set(newActive);
inactive = &mut inactive[1..];
(*(inactive[0]).Edge).StartY == iCurrentY
} {}
*pYNextInactive = (*(inactive[0]).Edge).StartY;
return inactive;
}
fn SortActiveEdges(list: Ref<CEdge>) {
let mut swapOccurred: bool;
let mut tmp: Ref<CEdge>;
assert!((*(*list).Next.get()).X.get() != INT::MAX);
while {
swapOccurred = false;
let mut previous = list;
let mut current = (*list).Next.get();
let mut next = (*current).Next.get();
let mut nextX = (*next).X.get();
while {
if (nextX < (*current).X.get()) {
swapOccurred = true;
(*previous).Next.set(next);
(*current).Next.set((*next).Next.get());
(*next).Next.set(current);
SWAP!(tmp, next, current);
}
previous = current;
current = next;
next = (*next).Next.get();
nextX = (*next).X.get();
nextX != INT::MAX
} {}
swapOccurred
} {}
}