public void NextPoints(Point a, Point b) { Assert.AreEqual(b, poly.NextVertex(a)); }
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(); }