public void NextPoints(Point a, Point b)
 {
     Assert.AreEqual(b, poly.NextVertex(a));
 }
Esempio n. 2
0
File: Light.cs Progetto: mokujin/DN
        public void CastShadow(ConvexPolygon poly, Vector2 position, bool penumbra)
        {
            // get the line that blocks light for the blocker and light combination
            // move the light position towards blocker by its sourceradius to avoid
            // popping of penumbrae
            int[] edgeIndices = poly.GetBackfacingEdgeIndices((this.Position + Vector2.Multiply(Vector2.Normalize(position - this.Position), this.Size)) - position);

            Vector2[] shadowLine = new Vector2[edgeIndices.Length + 1];
            shadowLine[0] = position + poly[edgeIndices[0]];
            for (int i = 0; i < edgeIndices.Length; i++)
                shadowLine[i + 1] = position + poly.NextVertex(edgeIndices[i]);

            // if the light source is completely surrounded by the blocker, don't draw its shadow
            if (shadowLine.Length == poly.Count + 1)
                return;
            //
            // build penumbrae (soft shadows), cast from the edges
            //

            Penumbra rightpenumbra;
            {
                Vector2 startdir = extendDir(shadowLine[0] - (this.Position - getLightDisplacement(position, shadowLine[0])));
                rightpenumbra.sections = new List<Penumbra.Section>();
                rightpenumbra.sections.Add(new Penumbra.Section(shadowLine[0], startdir, 0));

                for (int i = 0; i < shadowLine.Length - 1; ++i)
                {
                    float wanted = Math.Abs(MathUtils.AngleBetween(startdir, getTotalShadowStartDirection(position, shadowLine[i])));
                    float available = Math.Abs(MathUtils.AngleBetween(startdir, shadowLine[i + 1] - shadowLine[i]));

                    if (wanted < available)
                    {
                        rightpenumbra.sections.Add(new Penumbra.Section(
                            shadowLine[i],
                            getTotalShadowStartDirection(position, shadowLine[i]),
                            1));
                        break;
                    }
                    else
                    {
                        rightpenumbra.sections.Add(new Penumbra.Section(
                            shadowLine[i + 1],
                            extendDir(shadowLine[i + 1] - shadowLine[i]),
                            available / wanted));
                    }
                }
            }

            Penumbra leftpenumbra;
            {
                Vector2 startdir = extendDir(shadowLine[shadowLine.Length - 1] - (this.Position - getLightDisplacement(position, shadowLine[shadowLine.Length - 1])));
                leftpenumbra.sections = new List<Penumbra.Section>();
                leftpenumbra.sections.Add(new Penumbra.Section(
                    shadowLine[shadowLine.Length - 1],
                    startdir,
                    0));
                for (int i = 0; i < shadowLine.Length - 1; ++i)
                {
                    float wanted = Math.Abs(MathUtils.AngleBetween(startdir, getTotalShadowStartDirection(position, shadowLine[shadowLine.Length - i - 1])));
                    float available = Math.Abs(MathUtils.AngleBetween(startdir, shadowLine[shadowLine.Length - i - 2] - shadowLine[shadowLine.Length - i - 1]));

                    if (wanted < available)
                    {
                        leftpenumbra.sections.Add(new Penumbra.Section(
                            shadowLine[shadowLine.Length - i - 1],
                            getTotalShadowStartDirection(position, shadowLine[shadowLine.Length - i - 1]),
                            1));
                        break;
                    }
                    else
                    {
                        leftpenumbra.sections.Add(new Penumbra.Section(
                            shadowLine[shadowLine.Length - i - 2],
                            extendDir(shadowLine[shadowLine.Length - i - 2] - shadowLine[shadowLine.Length - i - 1]),
                            available / wanted));
                    }
                }
            }

            //
            // build umbrae (hard shadows), cast between the insides of penumbrae
            //

            Umbra umbra;
            umbra.sections = new List<Umbra.Section>();

            umbra.sections.Add(new Umbra.Section(rightpenumbra.sections.Last()._base, rightpenumbra.sections.Last().direction));

            for (int i = rightpenumbra.sections.Count - 1; i < shadowLine.Length - leftpenumbra.sections.Count + 1; i++)
                umbra.sections.Add(new Umbra.Section(shadowLine[i], extendDir(Vector2.Multiply(leftpenumbra.sections.Last().direction + rightpenumbra.sections.Last().direction, 0.5f))));

            umbra.sections.Add(new Umbra.Section(leftpenumbra.sections.Last()._base, leftpenumbra.sections.Last().direction));

            //
            // draw shadows to alpha
            //
            umbra.draw();
            rightpenumbra.draw();
            leftpenumbra.draw();
        }