예제 #1
0
        internal static bool Apply(CameraUpdate update, NiTransform transform, NiPoint3 result)
        {
            init();

            if (update == null || transform == null || result == null)
            {
                return(false);
            }

            if (update.Values.CollisionEnabled.CurrentValue < 0.5)
            {
                return(false);
            }

            var actor = update.Target.Actor;

            if (actor == null)
            {
                return(false);
            }

            var cell = actor.ParentCell;

            if (cell == null)
            {
                return(false);
            }

            float safety = (float)(update.Values.NearClip.CurrentValue + 1.0);

            if (safety < 1.0f)
            {
                safety = 1.0f;
            }

            float safety2 = Math.Max(0.0f, Settings.Instance.CameraCollisionSafety);

            var tpos = transform.Position;

            TempPoint1.CopyFrom(actor.Position);
            TempPoint1.Z = tpos.Z;

            if (safety2 > 0.0f)
            {
                TempSafety.Y = -safety2 * 0.5f;
                TempTransform.CopyFrom(transform);
                TempTransform.Position.CopyFrom(TempPoint1);
                TempTransform.Translate(TempSafety, TempPoint1);
            }

            TempNormal.X = tpos.X - TempPoint1.X;
            TempNormal.Y = tpos.Y - TempPoint1.Y;
            TempNormal.Z = tpos.Z - TempPoint1.Z;

            float len = TempNormal.Length;

            if (len <= 0.0f)
            {
                return(false);
            }

            TempNormal.Normalize(TempNormal);
            TempNormal.Multiply(len + safety + safety2, TempNormal);

            TempPoint2.X = TempPoint1.X + TempNormal.X;
            TempPoint2.Y = TempPoint1.Y + TempNormal.Y;
            TempPoint2.Z = TempPoint1.Z + TempNormal.Z;

            var ls = TESObjectCELL.RayCast(new RayCastParameters()
            {
                Cell  = cell,
                Begin = new float[] { TempPoint1.X, TempPoint1.Y, TempPoint1.Z },
                End   = new float[] { TempPoint2.X, TempPoint2.Y, TempPoint2.Z }
            });

            if (ls == null || ls.Count == 0)
            {
                return(false);
            }

            RayCastResult     best     = null;
            float             bestDist = 0.0f;
            List <NiAVObject> ignore   = new List <NiAVObject>(3);

            {
                var sk = actor.GetSkeletonNode(true);
                if (sk != null)
                {
                    ignore.Add(sk);
                }
            }
            {
                var sk = actor.GetSkeletonNode(false);
                if (sk != null)
                {
                    ignore.Add(sk);
                }
            }
            if (update.CachedMounted)
            {
                var mount = actor.GetMount();
                if (mount != null)
                {
                    var sk = mount.GetSkeletonNode(false);
                    if (sk != null)
                    {
                        ignore.Add(sk);
                    }
                }
            }

            foreach (var r in ls)
            {
                if (!IsValid(r, ignore))
                {
                    continue;
                }

                float dist = r.Fraction;
                if (best == null)
                {
                    best     = r;
                    bestDist = dist;
                }
                else if (dist < bestDist)
                {
                    best     = r;
                    bestDist = dist;
                }
            }

            if (best == null)
            {
                return(false);
            }

            bestDist *= len + safety + safety2;
            bestDist -= safety + safety2;
            bestDist /= len + safety + safety2;

            // Negative is ok!

            result.X = (TempPoint2.X - TempPoint1.X) * bestDist + TempPoint1.X;
            result.Y = (TempPoint2.Y - TempPoint1.Y) * bestDist + TempPoint1.Y;
            result.Z = (TempPoint2.Z - TempPoint1.Z) * bestDist + TempPoint1.Z;

            return(true);
        }