示例#1
0
        public void DrawDepthSlice(AnimationSet animationSet, Position position, bool flipX, int sliceY, Color frontColor, Color backColor, Color overColor)
        {
            if (animationSet.physicsHeight == 0)
            {
                return;
            }

            sliceY = sliceY.Clamp(0, animationSet.physicsHeight - 1);

            DepthSlice slice = animationSet.depthBounds.GetSlice(sliceY);

            int direction = flipX ? -1 : 1;
            int startX    = direction * slice.xOffset;

            if (backColor != Color.Transparent)
            {
                for (int i = 0; i < slice.depths.Length; i++)
                {
                    if (slice.depths[i].back + 1 != slice.depths[i].front)
                    {
                        DrawPixel(position + new Position(startX + i * direction, sliceY, slice.zOffset + slice.depths[i].back), backColor);
                    }
                    else // "over"
                    {
                        DrawPixel(position + new Position(startX + i * direction, sliceY, slice.zOffset + slice.depths[i].back), overColor);
                    }
                }
            }

            if (frontColor != Color.Transparent)
            {
                for (int i = 0; i < slice.depths.Length; i++)
                {
                    if (slice.depths[i].back + 1 != slice.depths[i].front)
                    {
                        DrawPixel(position + new Position(startX + i * direction, sliceY, slice.zOffset + slice.depths[i].front), frontColor);
                    }
                }
            }
        }
示例#2
0
        /// <summary>Returns a negative number if a is behind b, returns a positive number if b is behind a</summary>
        public static int Compare(AnimationSet aAnimationSet, AnimationSet bAnimationSet, Position aPosition, Position bPosition, bool aFlipX, bool bFlipX, ReportComparisonDelegate report)
        {
            // Try front/back first (because we don't have to look at the heightmap)
            {
                int aFront = aPosition.Z + aAnimationSet.physicsStartZ; // inclusive
                int aBack  = aPosition.Z + aAnimationSet.physicsEndZ;   // exclusive
                int bFront = bPosition.Z + bAnimationSet.physicsStartZ; // inclusive
                int bBack  = bPosition.Z + bAnimationSet.physicsEndZ;   // exclusive
                if (aFront >= bBack)
                {
                    return(-1);
                }
                if (bFront >= aBack)
                {
                    return(1);
                }

                // Check co-planar priority:
                if (aFront == bFront)
                {
                    if (aFront == aBack && aAnimationSet.coplanarPriority > bAnimationSet.coplanarPriority)
                    {
                        return(1);
                    }
                    if (bFront == bBack && bAnimationSet.coplanarPriority > aAnimationSet.coplanarPriority)
                    {
                        return(-1);
                    }
                }
            }


            // Try vertical position
            {
                int aBottom = aPosition.Y;                               // inclusive
                int aTop    = aPosition.Y + aAnimationSet.physicsHeight; // exclusive
                int bBottom = bPosition.Y;                               // inclusive
                int bTop    = bPosition.Y + bAnimationSet.physicsHeight; // exclusive
                if (aBottom >= bTop)
                {
                    return(1);
                }
                if (bBottom >= aTop)
                {
                    return(-1);
                }
            }

            // Special handling for carpets (a little bit of a hack)
            if (aAnimationSet.physicsHeight == 0 || bAnimationSet.physicsHeight == 0)
            {
                if (aPosition.Y > bPosition.Y)
                {
                    return(1);
                }
                else if (aPosition.Y < bPosition.Y)
                {
                    return(-1);
                }
            }


            // Handle the case where an object requests an "above" check:
            bool aDoAboveCheck = aAnimationSet.doAboveCheck & (aAnimationSet.Heightmap != null);
            bool bDoAboveCheck = bAnimationSet.doAboveCheck & (bAnimationSet.Heightmap != null);

            if (aDoAboveCheck | bDoAboveCheck)
            {
                bool bAboveA = false, aAboveB = false;

                if (aDoAboveCheck)
                {
                    bAboveA = DoAboveCheck(aAnimationSet, bAnimationSet, aPosition, bPosition, aFlipX, bFlipX);
                }
                if (bDoAboveCheck)
                {
                    aAboveB = DoAboveCheck(bAnimationSet, aAnimationSet, bPosition, aPosition, bFlipX, aFlipX);
                }

                if (bAboveA | aAboveB)
                {
                    if (aAboveB)
                    {
                        return(1);
                    }
                    else if (bAboveA)
                    {
                        return(-1);
                    }
                    else
                    {
                        return(0); // <- both are above
                    }
                }
            }


            // Handle the case where we don't have the data to do a depth-bound check
            if (aAnimationSet.depthBounds.slices == null || bAnimationSet.depthBounds.slices == null)
            {
                return(0);
            }

            // At this point, object bounds are intersecting. Use the tighter wrapped bounds:
            {
                // Find the minimum shared Y-slice on both objects
                int worldHorizontalSlice = Math.Max(aPosition.Y, bPosition.Y);
                int aHorizontalSlice     = worldHorizontalSlice - aPosition.Y;
                int bHorizontalSlice     = worldHorizontalSlice - bPosition.Y;

                // Get the bounds for that slice
                DepthSlice aDepthBounds = aAnimationSet.depthBounds.GetSlice(aHorizontalSlice);
                DepthSlice bDepthBounds = bAnimationSet.depthBounds.GetSlice(bHorizontalSlice);

                int aWorldStartX;
                if (!aFlipX)
                {
                    aWorldStartX = aPosition.X + aDepthBounds.xOffset;
                }
                else
                {
                    aWorldStartX = aPosition.X + (1 - (aDepthBounds.xOffset + aDepthBounds.Width));
                }
                int aWorldEndX = aWorldStartX + aDepthBounds.Width;

                int bWorldStartX;
                if (!bFlipX)
                {
                    bWorldStartX = bPosition.X + bDepthBounds.xOffset;
                }
                else
                {
                    bWorldStartX = bPosition.X + (1 - (bDepthBounds.xOffset + bDepthBounds.Width));
                }
                int bWorldEndX = bWorldStartX + bDepthBounds.Width;


                // Region of the overlap (if one exists)
                int worldStartX = Math.Max(aWorldStartX, bWorldStartX);
                int worldEndX   = Math.Min(aWorldEndX, bWorldEndX);
                int count       = worldEndX - worldStartX;

                int aDirection = aFlipX ? -1 : 1;
                int bDirection = bFlipX ? -1 : 1;

                int aStartIndex, bStartIndex;
                if (count > 0) // We have an overlap
                {
                    aStartIndex = worldStartX - aWorldStartX;
                    bStartIndex = worldStartX - bWorldStartX;
                }
                else // Just check one pixel from the edge of each. NOTE: This allows us to disregard bounding boxes when comparing depths.
                {
                    count = 1;

                    if (aWorldEndX <= bWorldStartX)
                    {
                        aStartIndex = aDepthBounds.Width - 1;
                        bStartIndex = 0;
                    }
                    else
                    {
                        Debug.Assert(bWorldEndX <= aWorldStartX);
                        aStartIndex = 0;
                        bStartIndex = bDepthBounds.Width - 1;
                    }
                }

                if (aFlipX)
                {
                    aStartIndex = aDepthBounds.Width - aStartIndex - 1;
                }
                if (bFlipX)
                {
                    bStartIndex = bDepthBounds.Width - bStartIndex - 1;
                }

                int aZStart = aPosition.Z + aDepthBounds.zOffset;
                int bZStart = bPosition.Z + bDepthBounds.zOffset;

                int zAccumulate    = 0;
                int frontMostPixel = int.MaxValue;
                int zTieBreak      = 0; // <- who has the frontmost pixel?
                int zAbove         = 0;
                for (int i = 0; i < count; i++)
                {
                    int aFront = aDepthBounds.depths[i * aDirection + aStartIndex].front;
                    int aBack  = aDepthBounds.depths[i * aDirection + aStartIndex].back - 1; // inclusive
                    int bFront = bDepthBounds.depths[i * bDirection + bStartIndex].front;
                    int bBack  = bDepthBounds.depths[i * bDirection + bStartIndex].back - 1; // inclusive

                    int aWorldFront = aZStart + aFront;
                    int aWorldBack  = aZStart + aBack;
                    int bWorldFront = bZStart + bFront;
                    int bWorldBack  = bZStart + bBack;

                    bool aBelow = (aWorldFront == aWorldBack + 2);
                    bool bBelow = (bWorldFront == bWorldBack + 2);


                    if (aBelow && bBelow)
                    {
                        // No useful data
                    }
                    else if (aBelow) // NOTE: We could do fancier things with the "back" value (accumulate behind if we are behind)
                    {
                        zAbove--;
                    }
                    else if (bBelow)
                    {
                        zAbove++;
                    }
                    else
                    {
                        // In hindsight this is not a great test, because it doesn't preference "who has the frontmost overlapping pixel"
                        // so it doesn't work so well for cover-shims on walls, which we expect to interpenetrate with things like boxes
                        int aBehindBy = Math.Max(0, aWorldFront - bWorldBack);
                        int bBehindBy = Math.Max(0, bWorldFront - aWorldBack);

                        if (aBehindBy != 0 || bBehindBy != 0)
                        {
                            zAccumulate -= aBehindBy;
                            zAccumulate += bBehindBy;
                        }
                        else
                        {
                            // Kind of a hack: if we are interpenetrating, but we have the very frontmost pixel, pay a lot of attention to that!
                            // (This may be unnecessary / unwanted given the code below that does a proper frontmost check)
                            if (aZStart < bZStart && aFront == 0)
                            {
                                zAccumulate += 4;
                            }
                            if (bZStart < aZStart && bFront == 0)
                            {
                                zAccumulate -= 4;
                            }
                        }


                        // zTieBreak += bWorldFront - aWorldFront; // <- old version (accumulate points)
                        if (aWorldFront == bWorldFront)
                        {
                            if (aWorldFront < frontMostPixel)
                            {
                                frontMostPixel = aWorldFront;
                                zTieBreak      = 0;
                            }
                        }
                        else if (aWorldFront < bWorldFront)
                        {
                            if (aWorldFront < frontMostPixel)
                            {
                                frontMostPixel = aWorldFront;
                                zTieBreak      = 1;
                            }
                        }
                        else // bWorldFront < aWorldFront
                        {
                            if (bWorldFront < frontMostPixel)
                            {
                                frontMostPixel = bWorldFront;
                                zTieBreak      = -1;
                            }
                        }
                    }
                }


                if (report != null)
                {
                    report(aAnimationSet, bAnimationSet, aPosition, bPosition, aFlipX, bFlipX, aHorizontalSlice, bHorizontalSlice, zAccumulate, zTieBreak, zAbove);
                }

                if (zAccumulate != 0)
                {
                    return(zAccumulate);
                }
                else if (zTieBreak != 0)
                {
                    return(zTieBreak);
                }
                else
                {
                    return(zAbove);
                }
            }
        }