public void FillCircle(FPoint center, float radius, int sides, Color color)
        {
#if DEBUG
            IncRenderSpriteCount(sides);
#endif

            float angle      = FloatMath.TAU / sides;
            float sideWidth  = FloatMath.Asin(angle / 2) * 2 * radius;
            float rectHeight = FloatMath.Sin(FloatMath.RAD_POS_090 - angle / 2) * radius;


            var r = new FRectangle(center.X - sideWidth / 2, center.Y, sideWidth, rectHeight);

            for (int i = 0; i < sides; i++)
            {
                internalBatch.Draw(
                    StaticTextures.SinglePixel.Texture,
                    null,
                    r.Round(),
                    StaticTextures.SinglePixel.Bounds,
                    new Vector2(0.5f, 0),
                    angle * i,
                    Vector2.One,
                    color);
            }
        }
Exemple #2
0
        private List <Tuple <BulletPathBlueprint, float> > FindLaserPaths(LevelBlueprint lvl, World wBase, World wCollision, int sourceID, FPoint rcStart, List <Tuple <Vector2, Vector2> > sourcerays, float startRadians, float cannonRadians, int remainingRecasts, bool inGlassBlock, object objIgnore)
        {
            var none = new List <Tuple <BulletPathBlueprint, float> >();

            if (remainingRecasts <= 0)
            {
                return(none);
            }

            var rays = sourcerays.ToList();

            var rcEnd = rcStart + new Vector2(2048, 0).Rotate(startRadians);

            var traceResult  = RayCastLaser(wBase, rcStart, rcEnd, objIgnore);
            var traceResult2 = RayCastLaser(wCollision, rcStart, rcEnd, objIgnore);

            if (traceResult2 != null && traceResult != null && traceResult2.Item1.UserData != traceResult.Item1.UserData)
            {
                // Dirty hit
                return(none);
            }

            if (traceResult == null)
            {
                return(none);
            }

            foreach (var r in rays)
            {
                if (Math2D.LineIntersectionExt(rcStart, traceResult.Item2, r.Item1.ToFPoint(), r.Item2.ToFPoint(), -0.1f, out _, out _, out _))
                {
                    return(none);
                }
            }


            var fCannon = traceResult.Item1.UserData as ICannonBlueprint;

            if (fCannon != null)
            {
                if (fCannon.CannonID == sourceID)
                {
                    return(none);
                }

                var quality = Math2D.LinePointDistance(rcStart, traceResult.Item2, new FPoint(fCannon.X, fCannon.Y));
                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));
                var path = new BulletPathBlueprint(fCannon.CannonID, cannonRadians, rays.ToArray());
                return(new List <Tuple <BulletPathBlueprint, float> > {
                    Tuple.Create(path, quality)
                });
            }

            var fGlassBlock = traceResult.Item1.UserData as MarkerRefractionEdge;

            if (fGlassBlock != null)
            {
                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                var pNewStart = traceResult.Item2;

                var normal = traceResult.Item3;
                var aIn    = (rcStart - rcEnd).ToAngle() - normal.ToAngle();

                // sin(aIn) / sin(aOut) = currRefractIdx / Glass.RefractIdx

                var n = inGlassBlock ? (GlassBlockBlueprint.REFRACTION_INDEX / 1f) : (1f / GlassBlockBlueprint.REFRACTION_INDEX);

                var sinaOut = FloatMath.Sin(aIn) * n;

                var dat = new List <Tuple <BulletPathBlueprint, float> >();

                var isRefracting = sinaOut <1 && sinaOut> -1;
                var isReflecting = FloatMath.Abs(aIn) > LaserNetwork.MIN_REFRACT_ANGLE && (!inGlassBlock || (inGlassBlock && !isRefracting));

                if (isRefracting)                 // refraction
                {
                    // refraction

                    var aOut          = FloatMath.Asin(sinaOut);
                    var pRefractAngle = (-normal).ToAngle() + aOut;

                    var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pRefractAngle, cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlock);
                    dat.AddRange(sub);
                }

                if (isReflecting)
                {
                    // reflection

                    var pReflectVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3);

                    var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pReflectVec.ToAngle(), cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlock);
                    dat.AddRange(sub);
                }

                return(dat);
            }

            var fGlassBlockCorner = traceResult.Item1.UserData as MarkerRefractionCorner;

            if (fGlassBlockCorner != null)
            {
                if (NO_LASER_CORNER_HITS)
                {
                    return(none);
                }

                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                var pNewStart = traceResult.Item2;

                var dat = new List <Tuple <BulletPathBlueprint, float> >();

                if (!inGlassBlock)
                {
                    // reflection

                    var pReflectVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3);

                    var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pReflectVec.ToAngle(), cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlockCorner);
                    dat.AddRange(sub);
                }

                return(dat);
            }

            var fMirrorBlock = traceResult.Item1.UserData as MirrorBlockBlueprint;

            if (fMirrorBlock != null)
            {
                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                var pNewStart = traceResult.Item2;
                var pVec      = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3);

                return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fMirrorBlock));
            }

            var fMirrorCircle = traceResult.Item1.UserData as MirrorCircleBlueprint;

            if (fMirrorCircle != null)
            {
                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                var pNewStart = traceResult.Item2;
                var pVec      = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3);

                return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fMirrorCircle));
            }

            var fVoidWall = traceResult.Item1.UserData as VoidWallBlueprint;

            if (fVoidWall != null)
            {
                return(none);
            }

            var fVoidCircle = traceResult.Item1.UserData as VoidCircleBlueprint;

            if (fVoidCircle != null)
            {
                return(none);
            }

            var fPortal = traceResult.Item1.UserData as PortalBlueprint;

            if (fPortal != null)
            {
                bool hit = FloatMath.DiffRadiansAbs(traceResult.Item3.ToAngle(), FloatMath.ToRadians(fPortal.Normal)) < FloatMath.RAD_POS_005;

                if (!hit)
                {
                    return(none);
                }

                rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                var dat = new List <Tuple <BulletPathBlueprint, float> >();
                foreach (var outportal in lvl.BlueprintPortals.Where(p => p.Side != fPortal.Side && p.Group == fPortal.Group))
                {
                    var cIn  = new FPoint(fPortal.X, fPortal.Y);
                    var cOut = new FPoint(outportal.X, outportal.Y);

                    var rot     = FloatMath.ToRadians(outportal.Normal - fPortal.Normal + 180);
                    var stretch = outportal.Length / fPortal.Length;

                    var newAngle = FloatMath.NormalizeAngle(startRadians + rot);
                    var newStart = cOut + stretch * (traceResult.Item2 - cIn).Rotate(rot);

                    newStart = newStart.MirrorAtNormal(cOut, Vector2.UnitX.Rotate(FloatMath.ToRadians(outportal.Normal)));

                    var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, newStart, rays, newAngle, cannonRadians, remainingRecasts - 1, inGlassBlock, outportal);
                    dat.AddRange(sub);
                }
                return(dat);
            }

            var fBorder = traceResult.Item1.UserData as MarkerCollisionBorder;

            if (fBorder != null)
            {
                if (lvl.WrapMode == LevelBlueprint.WRAPMODE_DONUT)
                {
                    rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                    var pNewStartX = traceResult.Item2.X;
                    var pNewStartY = traceResult.Item2.Y;
                    switch (fBorder.Side)
                    {
                    case FlatAlign4.NN: pNewStartY += lvl.LevelHeight; break;

                    case FlatAlign4.EE: pNewStartX -= lvl.LevelWidth; break;

                    case FlatAlign4.SS: pNewStartY -= lvl.LevelHeight; break;

                    case FlatAlign4.WW: pNewStartX += lvl.LevelWidth; break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    var pVec      = rcEnd - rcStart;
                    var pNewStart = new FPoint(pNewStartX, pNewStartY);

                    return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fBorder));
                }
                else if (lvl.WrapMode == LevelBlueprint.WRAPMODE_SOLID)
                {
                    rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D()));

                    var pNewStart = traceResult.Item2;
                    var pVec      = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3);

                    return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fBorder));
                }
                throw new Exception("Unsupported WrapMode: " + lvl.WrapMode);
            }

            throw new Exception("Unknown rayTrace resturn ficture: " + traceResult.Item1.UserData);
        }
Exemple #3
0
        private void RecalcFromRay(LaserSource src, FPoint istart, FPoint iend, int idepth, bool iinglass, object iignore, LaserRay isrc, float idist, bool nofault)
        {
            Stack <Tuple <FPoint, FPoint, int, bool, object, LaserRay, float> > remaining = new Stack <Tuple <FPoint, FPoint, int, bool, object, LaserRay, float> >();

            remaining.Push(Tuple.Create(istart, iend, idepth, iinglass, iignore, isrc, idist));

            while (remaining.Any())
            {
                var pop = remaining.Pop();

                var start     = pop.Item1;
                var end       = pop.Item2;
                var depth     = pop.Item3;
                var inglass   = pop.Item4;
                var ignore    = pop.Item5;
                var source    = pop.Item6;
                var startdist = pop.Item7;

                if (src.Lasers.Count + 1 >= MAX_LASER_PER_SOURCE)
                {
                    continue;
                }
                if (depth >= MAX_LASER_RAYCOUNT)
                {
                    continue;
                }
                if (!start.IsValid)
                {
                    continue;
                }
                if (!end.IsValid)
                {
                    continue;
                }
                if (start.EpsilonEquals(end, FloatMath.EPSILON6))
                {
                    continue;
                }

                var result = RayCast(start, end, ignore);

                #region OOB
                if (result == null)
                {
                    var ray = new LaserRay(start, end, source, LaserRayTerminator.OOB, depth, inglass, ignore, null, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                #region Cannon
                var resultCannon = result.Item1.UserData as Cannon;
                if (resultCannon != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Target, depth, inglass, ignore, resultCannon, startdist, resultCannon, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                #region GlassBlockRefraction
                var resultGlassBlockRefrac = result.Item1.UserData as MarkerRefractionEdge;
                if (resultGlassBlockRefrac != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Glass, depth, inglass, ignore, resultGlassBlockRefrac, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    // sin(aIn) / sin(aOut) = currRefractIdx / Glass.RefractIdx
                    var aIn = (start - end).ToAngle() - result.Item3.ToAngle();
                    var n   = inglass ? (GlassBlock.REFRACTION_INDEX / 1f) : (1f / GlassBlock.REFRACTION_INDEX);

                    var sinaOut = FloatMath.Sin(aIn) * n;

                    var isRefracting = sinaOut <1 && sinaOut> -1;
                    var isReflecting = FloatMath.Abs(aIn) > MIN_REFRACT_ANGLE && (!inglass || (inglass && !isRefracting));

                    if (isRefracting)                     // refraction
                    {
                        var aOut          = FloatMath.Asin(sinaOut);
                        var pRefractAngle = (-result.Item3).ToAngle() + aOut;

                        remaining.Push(Tuple.Create(result.Item2, result.Item2 + new Vector2(_rayLength, 0).Rotate(pRefractAngle), depth + 1, !inglass, (object)resultGlassBlockRefrac, ray, startdist + ray.Length));
                    }

                    if (isReflecting)
                    {
                        var reflect_end = result.Item2 + Vector2.Reflect(end - start, result.Item3).WithLength(_rayLength);
                        remaining.Push(Tuple.Create(result.Item2, reflect_end, depth + 1, inglass, (object)resultGlassBlockRefrac, ray, startdist + ray.Length));
                    }

                    continue;
                }
                #endregion

                #region GlassBlockRefraction (Corner)
                var resultGlassCornerRefrac = result.Item1.UserData as MarkerRefractionCorner;
                if (resultGlassCornerRefrac != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.VoidObject, depth, inglass, ignore, resultGlassCornerRefrac, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    // sin(aIn) / sin(aOut) = currRefractIdx / Glass.RefractIdx
                    var aIn = (start - end).ToAngle() - result.Item3.ToAngle();
                    var n   = inglass ? (GlassBlock.REFRACTION_INDEX / 1f) : (1f / GlassBlock.REFRACTION_INDEX);

                    var sinaOut = FloatMath.Sin(aIn) * n;

                    var isRefracting = sinaOut <1 && sinaOut> -1;
                    if (isRefracting)                     // refraction
                    {
                        // No refrac in corner
                    }

                    if (!inglass)
                    {
                        var reflect_end = result.Item2 + Vector2.Reflect(end - start, result.Item3).WithLength(_rayLength);
                        remaining.Push(Tuple.Create(result.Item2, reflect_end, depth + 1, inglass, (object)resultGlassCornerRefrac, ray, startdist + ray.Length));
                        continue;
                    }
                    else
                    {
                        // No funtime in corner
                        continue;
                    }
                }
                #endregion

                #region MirrorBlock
                var resultMirrorBlock = result.Item1.UserData as MirrorBlock;
                if (resultMirrorBlock != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Mirror, depth, inglass, ignore, resultMirrorBlock, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    var reflect_end = result.Item2 + Vector2.Reflect(end - start, result.Item3).WithLength(_rayLength);
                    remaining.Push(Tuple.Create(result.Item2, reflect_end, depth + 1, inglass, (object)resultMirrorBlock, ray, startdist + ray.Length));
                    continue;
                }
                #endregion

                #region MirrorCircle
                var resultMirrorCircle = result.Item1.UserData as MirrorCircle;
                if (resultMirrorCircle != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Mirror, depth, inglass, ignore, resultMirrorCircle, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    var reflect_end = result.Item2 + Vector2.Reflect(end - start, result.Item3).WithLength(_rayLength);
                    remaining.Push(Tuple.Create(result.Item2, reflect_end, depth + 1, inglass, (object)resultMirrorCircle, ray, startdist + ray.Length));
                    continue;
                }
                #endregion

                #region VoidWall
                var resultVoidWall = result.Item1.UserData as VoidWall;
                if (resultVoidWall != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.VoidObject, depth, inglass, ignore, resultVoidWall, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                #region VoidCircle
                var resultVoidCircle = result.Item1.UserData as VoidCircle;
                if (resultVoidCircle != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.VoidObject, depth, inglass, ignore, resultVoidCircle, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                #region Shield
                var resultShield = result.Item1.UserData as ShieldCollisionMarker;
                if (resultShield != null)
                {
                    if (resultShield.Active)
                    {
                        var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Target, depth, inglass, ignore, resultShield, startdist, resultShield.Source, src.Type);
                        src.Lasers.Add(ray);
                        if (TestForLaserCollision(src, ray, nofault))
                        {
                            continue;
                        }

                        continue;
                    }
                    else if (src.Type == RayType.Shield && src.LaserFraction == resultShield.Source.Fraction)
                    {
                        var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Target, depth, inglass, ignore, resultShield, startdist, resultShield.Source, src.Type);
                        src.Lasers.Add(ray);
                        if (TestForLaserCollision(src, ray, nofault))
                        {
                            continue;
                        }

                        continue;
                    }
                    else
                    {
                        continue;
                    }
                }
                #endregion

                #region Portal
                var resultPortal = result.Item1.UserData as Portal;
                if (resultPortal != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Portal, depth, inglass, ignore, resultPortal, startdist, null, src.Type);
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    var  inPortal = resultPortal;
                    var  normal   = result.Item3;
                    bool hit      = FloatMath.DiffRadiansAbs(normal.ToAngle(), inPortal.Normal) < FloatMath.RAD_POS_001;

                    if (!hit)
                    {
                        continue;                           // back-side hit
                    }
                    if (inPortal.Links.Count == 0)
                    {
                        continue;                                                // void portal
                    }
                    foreach (var outportal in inPortal.Links)
                    {
                        var rot    = outportal.Normal - inPortal.Normal + FloatMath.RAD_POS_180;
                        var projec = result.Item2.ProjectOntoLine(inPortal.Position, inPortal.VecDirection);

                        var newVelocity = (end - start).Rotate(rot);
                        var newStart    = outportal.Position + outportal.VecDirection * (-projec) + outportal.VecNormal * (Portal.WIDTH / 2f);

                        var newEnd = newStart + newVelocity.WithLength(_rayLength);

                        remaining.Push(Tuple.Create(newStart, newEnd, depth + 1, false, (object)outportal, ray, startdist + ray.Length));
                    }
                    continue;
                }
                #endregion

                #region Border
                var resultBorderMarker = result.Item1.UserData as MarkerCollisionBorder;
                if (resultBorderMarker != null)
                {
                    if (_wrapMode == GameWrapMode.Reflect)
                    {
                        var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Mirror, depth, inglass, ignore, resultBorderMarker, startdist, null, src.Type);
                        src.Lasers.Add(ray);
                        if (TestForLaserCollision(src, ray, nofault))
                        {
                            continue;
                        }

                        var reflect_end = result.Item2 + Vector2.Reflect(end - start, result.Item3).WithLength(_rayLength);
                        remaining.Push(Tuple.Create(result.Item2, reflect_end, depth + 1, inglass, (object)resultBorderMarker, ray, startdist + ray.Length));
                        continue;
                    }
                    else if (_wrapMode == GameWrapMode.Donut)
                    {
                        var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.Portal, depth, inglass, ignore, resultBorderMarker, startdist, null, src.Type);
                        src.Lasers.Add(ray);
                        if (TestForLaserCollision(src, ray, nofault))
                        {
                            continue;
                        }

                        var pNewStartX = result.Item2.X;
                        var pNewStartY = result.Item2.Y;
                        switch (resultBorderMarker.Side)
                        {
                        case FlatAlign4.NN: pNewStartY += _screen.Blueprint.LevelHeight; break;

                        case FlatAlign4.EE: pNewStartX -= _screen.Blueprint.LevelWidth; break;

                        case FlatAlign4.SS: pNewStartY -= _screen.Blueprint.LevelHeight; break;

                        case FlatAlign4.WW: pNewStartX += _screen.Blueprint.LevelWidth; break;

                        default:
                            SAMLog.Error("LASER::EnumSwitch_RFR", "value: " + resultBorderMarker.Side);
                            break;
                        }

                        var newStart = new FPoint(pNewStartX, pNewStartY);
                        var newEnd   = newStart + (end - start);

                        remaining.Push(Tuple.Create(newStart, newEnd, depth + 1, inglass, (object)null, ray, startdist + ray.Length));
                        continue;
                    }
                    else
                    {
                        SAMLog.Error("LASER::UnknownWrap", "Unknown wrapmode: " + _wrapMode);
                    }

                    continue;
                }
                #endregion

                #region Bullet
                var resultBullet = result.Item1.UserData as Bullet;
                if (resultBullet != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.BulletTerm, depth, inglass, ignore, resultBullet, startdist, null, src.Type);
                    ray.TerminatorBullet = resultBullet;
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                #region RemoteBullet
                var resultRemoteBullet = result.Item1.UserData as RemoteBullet;
                if (resultRemoteBullet != null)
                {
                    var ray = new LaserRay(start, result.Item2, source, LaserRayTerminator.BulletTerm, depth, inglass, ignore, resultRemoteBullet, startdist, null, src.Type);
                    ray.TerminatorBullet = resultRemoteBullet;
                    src.Lasers.Add(ray);
                    if (TestForLaserCollision(src, ray, nofault))
                    {
                        continue;
                    }

                    continue;
                }
                #endregion

                // wud ???
                SAMLog.Error("LASER::UnknownFixture", string.Format("Ray collided with unkown fixture: {0}", result?.Item1?.UserData ?? "<NULL>"));
            }
        }