Example #1
0
 /// <summary>
 /// Adjusts the current min, max accordingly in case
 /// the new point lies outside the current box.
 /// </summary>
 /// <param name="Point"></param>
 public void ExtendByPoint(V3 Point)
 {
     if (Point.X < Min.X) Min.X = Point.X;
     if (Point.X > Max.X) Max.X = Point.X;
     if (Point.Y < Min.Y) Min.Y = Point.Y;
     if (Point.Y > Max.Y) Max.Y = Point.Y;
     if (Point.Z < Min.Z) Min.Z = Point.Z;
     if (Point.Z > Max.Z) Max.Z = Point.Z;
 }
Example #2
0
        /// <summary>
        /// Constructor using two initial points.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        public BoundingBox3D(V3 P1, V3 P2)
        {
            // these initial values make sure
            // any first point will replace them
            this.Min.X = Real.MaxValue;
            this.Min.Y = Real.MaxValue;
            this.Min.Z = Real.MaxValue;
            this.Max.X = Real.MinValue;
            this.Max.Y = Real.MinValue;
            this.Max.Z = Real.MinValue;

            ExtendByPoint(P1);
            ExtendByPoint(P2);
        }
Example #3
0
        /// <summary>
        /// Checks for intersection of 3D line and 3D triangle.
        /// </summary>
        /// <remarks>
        /// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
        /// </remarks>
        /// <param name="S">Start</param>
        /// <param name="E">End</param>
        /// <param name="P1">Triangle P1</param>
        /// <param name="P2">Triangle P2</param>
        /// <param name="P3">Triangle P3</param>
        /// <param name="I">Intersection Point</param>
        /// <returns>True or False</returns>
        public static bool IntersectLineTriangle(ref V3 S, ref V3 E, ref V3 P1, ref V3 P2, ref V3 P3, ref V3 I)
        {
            const float EPS = 0.001f;

            V3   e1, e2, p, q, t, d;
            Real u, v, f, inv_det, det;

            // vectors
            d  = E - S;              // line vector    S->E
            e1 = P2 - P1;            // triangle edge P1->P2
            e2 = P3 - P1;            // triangle edge P1->P3
            p  = d.CrossProduct(e2); // used to calculate determinant and u,v parms

            // if determinant is near zero, ray lies in plane of triangle
            det = e1 * p;
            if (det < EPS && det > -EPS)
            {
                return(false);
            }

            inv_det = 1.0f / det;

            // calculate distance from P1 to line start
            t = S - P1;

            // calculate u parameter and test bound
            u = (t * p) * inv_det;
            if ((u < 0.0f) || (u > 1.0f))
            {
                return(false);
            }

            // prepare to test v parameter
            q = t.CrossProduct(e1);

            // calculate v parameter and test bound
            v = (d * q) * inv_det;
            if ((v < 0.0f) || (u + v > 1.0f))
            {
                return(false);
            }

            // note: we additionally check for < 1.0f
            // = LINE intersection, not ray
            f = (e2 * q) * inv_det;
            if ((f >= 0.0f) && (f <= 1.0f))
            {
                I = S + d * f;
                return(true);
            }

            return(false);
        }
Example #4
0
        /// <summary>
        /// Checks if this object is visible from a position
        /// in a room.
        /// </summary>
        /// <param name="Position"></param>
        /// <param name="Room"></param>
        /// <returns></returns>
        public bool IsVisibleFrom(V3 Position, RooFile Room)
        {
            if (Room != null)
            {
                // roo format variants
                V3 rooStart = Position.Clone();
                V3 rooEnd = Position3D.Clone();

                // add offset for playerheight to not use the groundheight
                rooStart.Y += GeometryConstants.PLAYERHEIGHT;
                rooEnd.Y += GeometryConstants.PLAYERHEIGHT;

                // convert to ROO format
                rooStart.ConvertToROO();
                rooEnd.ConvertToROO();

                // verify the object is visible
                return Room.VerifySight(rooStart, rooEnd);
            }
            else
                return false;
        }
        /// <summary>
        /// Checks if this wall blocks a
        /// move between Start and End
        /// </summary>
        /// <param name="Start">A 3D location</param>
        /// <param name="End">A 2D location</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns></returns>
        public bool IsBlocking(V3 Start, V2 End, Real PlayerHeight)
        {
            V2 Start2D = new V2(Start.X, Start.Z);

            // calculate the sides of the points (returns -1, 0 or 1)
            int startside = Start2D.GetSide(P1, P2);
            int endside = End.GetSide(P1, P2);

            // if points are not on same side
            // the infinite lines cross
            if (startside != endside)
            {
                // verify also the finite line segments cross
                V2 intersect;

                LineLineIntersectionType intersecttype =
                    MathUtil.IntersectLineLine(Start2D, End, P1, P2, out intersect);

                if (intersecttype == LineLineIntersectionType.OneIntersection ||
                    intersecttype == LineLineIntersectionType.OneBoundaryPoint ||
                    intersecttype == LineLineIntersectionType.FullyCoincide ||
                    intersecttype == LineLineIntersectionType.PartiallyCoincide)
                {
                    // verify the side we've crossed is flaggged as "nonpassable"
                    // if so, we actually have a collision
                    if ((startside < 0 && LeftSide != null && !LeftSide.Flags.IsPassable) ||
                        (startside > 0 && RightSide != null && !RightSide.Flags.IsPassable))
                    {
                        return true;
                    }

                    // still check the stepheight from oldheight to new floor if passable
                    // for too high steps
                    Real endheight = 0.0f;
                    Real diff;

                    if (endside <= 0 && LeftSector != null)
                        endheight = LeftSector.CalculateFloorHeight((int)End.X, (int)End.Y, true);

                    else if (endside > 0 && RightSector != null)
                        endheight = RightSector.CalculateFloorHeight((int)End.X, (int)End.Y, true);

                    diff = endheight - Start.Y;

                    // diff is bigger than max. step height, we have a collision
                    if (diff > GeometryConstants.MAXSTEPHEIGHT)
                        return true;

                    // check the ceiling heights
                    if (endside <= 0 && LeftSector != null)
                        endheight = LeftSector.CalculateCeilingHeight((int)End.X, (int)End.Y);

                    else if (endside > 0 && RightSector != null)
                        endheight = RightSector.CalculateCeilingHeight((int)End.X, (int)End.Y);

                    // diff is bigger than max. step height, we have a collision
                    if (endheight < Start.Y + PlayerHeight)
                        return true;
                }
            }

            return false;
        }
Example #6
0
        /// <summary>
        /// Checks if this wall blocks a
        /// move between Start and End
        /// </summary>
        /// <param name="Start">A 3D location</param>
        /// <param name="End">A 2D location</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns></returns>
        public bool IsBlockingMove(V3 Start, V2 End, Real PlayerHeight)
        {          
            // get distance of end to finite line segment
            Real distEnd = End.MinSquaredDistanceToLineSegment(P1, P2);

            // end is far enough away, no block
            if (distEnd >= GeometryConstants.WALLMINDISTANCE2)
                return false;

            /*************************************************************************/
            // end is too 'too' close to wall
            
            V2 start2D      = new V2(Start.X, Start.Z);
            int startside   = start2D.GetSide(P1, P2);
            int endside     = End.GetSide(P1, P2);
            Real endheight;
            ushort bgfbmp;

            /*************************************************************************/
            // allow moving away from wall

            if (startside == endside)
            { 
                Real distStart = start2D.MinSquaredDistanceToLineSegment(P1, P2);

                if (distEnd > distStart)
                    return false;
            }

            /*************************************************************************/
            // prevent moving through non-passable side

            if ((startside < 0 && LeftSide != null && !LeftSide.Flags.IsPassable) ||
                (startside > 0 && RightSide != null && !RightSide.Flags.IsPassable))
                return true;         

            /*************************************************************************/
            // check step-height

            endheight = 0.0f;

            if (startside >= 0)
            {
                endheight = (LeftSector != null) ? LeftSector.CalculateFloorHeight(End.X, End.Y, true) : 0.0f;
                bgfbmp = (RightSide != null) ? RightSide.LowerTexture : (ushort)0;
            }
            else
            {
                endheight = (RightSector != null) ? RightSector.CalculateFloorHeight(End.X, End.Y, true) : 0.0f;
                bgfbmp = (LeftSide != null) ? LeftSide.LowerTexture : (ushort)0;
            }

            if (bgfbmp > 0 && (endheight - Start.Y > GeometryConstants.MAXSTEPHEIGHT))
                return true;
            
            /*************************************************************************/
            // check head collision with ceiling

            endheight = 0.0f;

            if (startside >= 0)
            {
                endheight = (LeftSector != null) ? LeftSector.CalculateCeilingHeight(End.X, End.Y) : 0.0f;
                bgfbmp = (RightSide != null) ? RightSide.UpperTexture : (ushort)0;
            }
            else
            {
                endheight = (RightSector != null) ? RightSector.CalculateCeilingHeight(End.X, End.Y) : 0.0f;
                bgfbmp = (LeftSide != null) ? LeftSide.UpperTexture : (ushort)0;
            }

            if (bgfbmp > 0 && (endheight < Start.Y + PlayerHeight))
                return true;

            /*************************************************************************/

            return false;
        }
        /// <summary>
        /// Collisions with wall segments for user movements using the BSP tree.
        /// Therefore with logarithmic rather than linear costs.
        /// </summary>
        /// <remarks>
        /// The algorithm goes like this (starts at root)
        /// (1) Get the sides of both endpoints (start, end) using the splitter (node)
        /// (2) If both endpoints are on the same side, there is no collision with any wall in the splitter
        ///     and only one of the two subtrees must be visited then.
        /// (3) If there is an intersection with the infinite splitter, check the finite wall segments
        ///     in the splitter for intersection. If none found, split up the vector (start, end) at the intersection
        ///     and recusively start again for both subtrees using the just created two chunks of start vector.
        /// </remarks>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <param name="PlayerHeight"></param>
        /// <returns></returns>
        protected RooWall VerifyMoveTree(RooBSPItem Node, V3 Start, V2 End, Real PlayerHeight)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return null;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;

            int side1 = Math.Sign(line.A * Start.X + line.B * Start.Z + line.C);
            int side2 = Math.Sign(line.A * End.X + line.B * End.Y + line.C);

            /*************************************************************/

            // both endpoints on the same side of splitter -> no intersection
            // climb down only one of the two subtrees of the node
            if (side1 == side2 && side1 != 0)
            {
                // left
                if (side1 < 0)
                    return VerifyMoveTree(line.LeftChild, Start, End, PlayerHeight);

                // right
                else
                    return VerifyMoveTree(line.RightChild, Start, End, PlayerHeight);
            }

            /*************************************************************/

            // endpoints are on different sides or both on infinite line
            else
            {
                RooWall wall = line.Wall;
                V2 intersect;
                V2 start2D = new V2(Start.X, Start.Z);

                if (wall == null)
                    return null;

                /*************************************************************/

                // intersect with infinite splitter
                LineInfiniteLineIntersectionType typ =
                    MathUtil.IntersectLineInfiniteLine(start2D, End, wall.P1, wall.P2, out intersect);

                /*************************************************************/

                // see if intersection with infinite splitter is on a wall segment in plane
                while (wall != null)
                {
                    if (wall.IsBlocking(Start, End, PlayerHeight))
                        return wall;

                    // loop over next wall in same plane
                    wall = wall.NextWallInPlane;
                }

                /*************************************************************/

                // no finite wallsegment in splitter plane intersects:
                // if vector is fully in splitter, we're done
                if (side1 == 0 && side2 == 0)
                    return null;

                // otherwise split up the vector in left and right half
                // and possible check both
                else if (side1 < 0 && side2 > 0)
                {
                    RooWall wl = VerifyMoveTree(line.LeftChild, Start, intersect, PlayerHeight);

                    if (wl != null)
                        return wl;

                    else
                        return VerifyMoveTree(line.RightChild, new V3(intersect.X, Start.Y, intersect.Y), End, PlayerHeight);
                }
                else
                {
                    RooWall wl = VerifyMoveTree(line.RightChild, Start, intersect, PlayerHeight);

                    if (wl != null)
                        return wl;

                    else
                        return VerifyMoveTree(line.LeftChild, new V3(intersect.X, Start.Y, intersect.Y), End, PlayerHeight);
                }
            }
        }
        /// <summary>
        /// Checks a movement vector (Start->End) for wall collisions and
        /// returns a possibly adjusted movement vector to use instead.
        /// This might be a slide along a wall or a zero-vector for a full block.
        /// </summary>
        /// <param name="Start">Startpoint of movement (in ROO coords)</param>
        /// <param name="End">Endpoint of movement (in ROO coords)</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns>Same or adjusted delta vector between Start and end (in ROO coords)</returns>
        public V2 VerifyMove(V3 Start, V2 End, Real PlayerHeight)
        {
            V2 Start2D = new V2(Start.X, Start.Z);

            // the move, if everything OK with this move
            // this is the untouched return
            V2 diff = End - Start2D;

            // an extension to the delta for min. wall distance
            V2 ext = diff.Clone();
            ext.ScaleToLength(GeometryConstants.WALLMINDISTANCE);

            // this holds a possible collision wall
            RooWall intersectWall = VerifyMoveTree(BSPTree[0], Start, End + ext, PlayerHeight);

            // if there was an intersection, try to slide along wall
            if (intersectWall != null)
            {
                V2 newend = intersectWall.SlideAlong(Start2D, End);
                diff = newend - Start2D;

                // an extension to the delta for min. wall distance
                ext = diff.Clone();
                ext.ScaleToLength(GeometryConstants.WALLMINDISTANCE);

                // recheck slide for intersect with other walls
                // this is necessary in case you get into a corner
                // to not slide through other wall there
                if (VerifyMoveTree(BSPTree[0], Start, newend + ext, PlayerHeight) != null)
                {
                    diff.X = 0;
                    diff.Y = 0;
                }
            }

            return diff;
        }
Example #9
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <param name="PlayerHeight"></param>
        /// <returns></returns>
        protected RooWall VerifyMoveByList(V3 Start, V2 End, Real PlayerHeight)
        {
            foreach (RooWall wall in Walls)
                if (wall.IsBlockingMove(Start, End, PlayerHeight))
                    return wall;

            return null;
        }
Example #10
0
        /// <summary>
        /// Checks a movement vector (Start->End) for wall collisions and
        /// returns a possibly adjusted movement vector to use instead.
        /// This might be a slide along a wall or a zero-vector for a full block.
        /// </summary>
        /// <param name="Start">Startpoint of movement. In FINENESS units (1:1024), Y is height.</param>
        /// <param name="End">Endpoint of movement. In FINENESS units (1:1024).</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns>Same or adjusted delta vector between Start and end (in ROO coords)</returns>
        public V2 VerifyMove(V3 Start, V2 End, Real PlayerHeight)
        {                       
            V2 Start2D = new V2(Start.X, Start.Z);
            V2 newend = End;           
            V2 rot;
            RooWall wall;

            const int MAXATTEMPTS = 8;
            const Real ANGLESTEP = GeometryConstants.QUARTERPERIOD / 8;

            /**************************************************************/

            // first collision check
            wall = VerifyMoveByTree(BSPTree[0], Start, End, PlayerHeight);
            
            // no collision with untouched move
            if (wall == null)
                return End - Start2D;

            /**************************************************************/

            // try to slide along collision wall
            newend  = wall.SlideAlong(Start2D, End);
            wall    = VerifyMoveByTree(BSPTree[0], Start, newend, PlayerHeight);
            
            // no collision with 'slide along' move
            if (wall == null)
                return newend - Start2D;
           
            /**************************************************************/

            // try find another collision wall
            wall = VerifyMoveByTree(BSPTree[0], Start, End, PlayerHeight, wall);

            if (wall != null)
            {
                // try to slide along other collision wall
                newend  = wall.SlideAlong(Start2D, End);
                wall    = VerifyMoveByTree(BSPTree[0], Start, newend, PlayerHeight);

                // slide along other collision wall was ok
                if (wall == null)
                    return newend - Start2D;          
            }

            /**************************************************************/

            // sliding on collision walls does not work, try rotate a bit
            for(int i = 0; i < MAXATTEMPTS; i++)
            {
                rot = End - Start2D;
                rot.Rotate(-ANGLESTEP * (Real)i);
                newend = Start2D + rot;

                wall = VerifyMoveByTree(BSPTree[0], Start, newend, PlayerHeight);
                
                // no collision
                if (wall == null)
                    return newend - Start2D;

                rot = End - Start2D;
                rot.Rotate(ANGLESTEP * (Real)i);
                newend = Start2D + rot;

                wall = VerifyMoveByTree(BSPTree[0], Start, newend, PlayerHeight);

                // no collision
                if (wall == null)
                    return newend - Start2D;
            }

            return new V2(0.0f, 0.0f);
        }
Example #11
0
        public override int ReadFrom(byte[] Buffer, int StartIndex = 0)
        {
            int cursor = StartIndex;

            cursor += base.ReadFrom(Buffer, StartIndex);         
           
            ushort coordinateY = BitConverter.ToUInt16(Buffer, cursor);          
            cursor += TypeSizes.SHORT;

            ushort coordinateX = BitConverter.ToUInt16(Buffer, cursor);
            cursor += TypeSizes.SHORT;

            position3D = new V3(coordinateX, 0.0f, coordinateY);

            angle = MathUtil.BinaryAngleToRadian(BitConverter.ToUInt16(Buffer, cursor));
            cursor += TypeSizes.SHORT;

            if ((AnimationType)Buffer[cursor] == AnimationType.TRANSLATION)                   // check if there is a colortranslation or effect as 1. anim     
            {
                motionFirstAnimationType = (AnimationType)Buffer[cursor];
                cursor++;

                motionColorTranslation = Buffer[cursor];                    // RoomObjectColorTranslation (1 byte)
                cursor++;
            }
            else if (((AnimationType)Buffer[cursor] == AnimationType.EFFECT))
            {
                motionFirstAnimationType = (AnimationType)Buffer[cursor];
                cursor++;

                motionEffect = Buffer[cursor];                              // RoomObjectEffect (1 byte)
                cursor++;
            }

            if (flags.Drawing == ObjectFlags.DrawingType.SecondTrans)
                motionColorTranslation = ColorTransformation.FILTERWHITE90;

            motionAnimation = Animation.ExtractAnimation(Buffer, cursor);   // Animation (n bytes)
            cursor += motionAnimation.ByteLength;

            motionAnimation.PropertyChanged += OnMotionAnimationPropertyChanged;

            byte subOverlaysCount = Buffer[cursor];                             // RoomObjectSubOverlaysCount (1 byte)
            cursor++;

            motionSubOverlays.Clear();
            for (byte i = 0; i < subOverlaysCount; i++)
            {
                SubOverlay obj = new SubOverlay(Buffer, cursor);
                cursor += obj.ByteLength;
                
                if (flags.Drawing == ObjectFlags.DrawingType.SecondTrans)
                    obj.ColorTranslation = ColorTransformation.FILTERWHITE90;

                obj.PropertyChanged += OnMotionSubOverlayPropertyChanged;
                
                motionSubOverlays.Add(obj);
            }

            return cursor - StartIndex;   
        }
Example #12
0
        /// <summary>
        /// Resets the object to default state/values
        /// </summary>
        /// <param name="RaiseChangedEvent"></param>
        public override void Clear(bool RaiseChangedEvent)
        {
            base.Clear(RaiseChangedEvent);

            if (RaiseChangedEvent)
            {
                Position3D = new V3(0, 0, 0);
                Angle = 0.0f;
                MotionFirstAnimationType = 0;
                MotionColorTranslation = 0;
                MotionEffect = 0;

                if (motionAnimation != null)
                    motionAnimation.PropertyChanged -= OnMotionAnimationPropertyChanged;

                MotionAnimation = new AnimationNone();
                MotionAnimation.PropertyChanged += OnMotionAnimationPropertyChanged;

                motionSubOverlays.Clear();
                
                IsMoving = false;
                IsTarget = false;
                IsHighlighted = false;
                VerticalSpeed = 0.0f;
            }
            else
            {
                position3D = new V3(0, 0, 0);
                angle = 0.0f;
                motionFirstAnimationType = 0;
                motionColorTranslation = 0;
                motionEffect = 0;

                if (motionAnimation != null)
                    motionAnimation.PropertyChanged -= OnMotionAnimationPropertyChanged;

                motionAnimation = new AnimationNone();
                motionAnimation.PropertyChanged += OnMotionAnimationPropertyChanged;

                motionSubOverlays.Clear();
                
                isMoving = false;
                isTarget = false;
                isHighlighted = false;
                verticalSpeed = 0.0f;
            }
        }
Example #13
0
        public RoomObject(
            uint ID,
            uint Count,           
            uint OverlayFileRID,
            uint NameRID, 
            uint Flags,
            ushort LightFlags, 
            byte LightIntensity, 
            ushort LightColor, 
            AnimationType FirstAnimationType, 
            byte ColorTranslation, 
            byte Effect, 
            Animation Animation, 
            IEnumerable<SubOverlay> SubOverlays,            
            V3 Position3D,
            ushort Angle, 
            AnimationType MotionFirstAnimationType, 
            byte MotionColorTranslation, 
            byte MotionEffect, 
            Animation MotionAnimation, 
            IEnumerable<SubOverlay> MotionSubOverlays)            
            : base(
                ID, Count, 
                OverlayFileRID, NameRID, Flags, 
                LightFlags, LightIntensity, LightColor, 
                FirstAnimationType, ColorTranslation, Effect, Animation, SubOverlays)
        {
            // attach motionsuboverlays listener
            motionSubOverlays.ListChanged += OnMotionSubOverlaysListChanged;

            // coordinates & angle
            position3D = Position3D;
            angle = Angle;

            // roomobject stuff (like object)
            motionFirstAnimationType = MotionFirstAnimationType;
            motionColorTranslation = MotionColorTranslation;
            motionEffect = MotionEffect;
            motionAnimation = MotionAnimation;
            motionAnimation.PropertyChanged += OnMotionAnimationPropertyChanged;

            // special handling for secondtrans
            if (flags.Drawing == ObjectFlags.DrawingType.SecondTrans)
            {
                motionColorTranslation = ColorTransformation.FILTERWHITE90;

                foreach (SubOverlay subOv in MotionSubOverlays)
                    subOv.ColorTranslation = ColorTransformation.FILTERWHITE90;
            }

            // motionsuboverlays
            motionSubOverlays.AddRange(MotionSubOverlays);
        }
Example #14
0
        public override unsafe void ReadFrom(ref byte* Buffer)
        {
            base.ReadFrom(ref Buffer);

            ushort coordinateY = *((ushort*)Buffer);
            Buffer += TypeSizes.SHORT;

            ushort coordinateX = *((ushort*)Buffer);
            Buffer += TypeSizes.SHORT;

            position3D = new V3(coordinateX, 0.0f, coordinateY);

            angle = MathUtil.BinaryAngleToRadian(*((ushort*)Buffer));
            Buffer += TypeSizes.SHORT;

            if ((AnimationType)Buffer[0] == AnimationType.TRANSLATION)
            {
                motionFirstAnimationType = (AnimationType)Buffer[0];
                Buffer++;

                motionColorTranslation = Buffer[0];
                Buffer++;
            }
            else if (((AnimationType)Buffer[0] == AnimationType.EFFECT))
            {
                motionFirstAnimationType = (AnimationType)Buffer[0];
                Buffer++;

                motionEffect = Buffer[0];
                Buffer++;
            }

            if (flags.Drawing == ObjectFlags.DrawingType.SecondTrans)
                motionColorTranslation = ColorTransformation.FILTERWHITE90;

            motionAnimation = Animation.ExtractAnimation(ref Buffer);
            motionAnimation.PropertyChanged += OnMotionAnimationPropertyChanged;

            byte subOverlaysCount = Buffer[0];
            Buffer++;

            motionSubOverlays.Clear();
            for (byte i = 0; i < subOverlaysCount; i++)
            {
                SubOverlay subov = new SubOverlay(ref Buffer);

                if (flags.Drawing == ObjectFlags.DrawingType.SecondTrans)
                    subov.ColorTranslation = ColorTransformation.FILTERWHITE90;

                subov.PropertyChanged += OnMotionSubOverlayPropertyChanged;
                motionSubOverlays.Add(subov);
            }
        }
Example #15
0
 /// <summary>
 /// Typed equals
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 public bool Equals(V3 obj)
 {
     return (obj.X == X && obj.Y == Y && obj.Z == Z);
 }
Example #16
0
 /// <summary>
 /// Returns the crossproduct of this
 /// and another V3 vector.
 /// </summary>
 /// <param name="v"></param>
 /// <returns></returns>
 public V3 CrossProduct(V3 v)
 {
     return new V3(
         Y * v.Z - Z * v.Y,
         Z * v.X - X * v.Z,
         X * v.Y - Y * v.X);
 }
Example #17
0
        /// <summary>
        /// Collisions with wall segments for user movements using the BSP tree.
        /// Therefore with logarithmic rather than linear costs.
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <param name="PlayerHeight"></param>
        /// <param name="IgnoreWall"></param>
        /// <returns></returns>
        protected RooWall VerifyMoveByTree(RooBSPItem Node, V3 Start, V2 End, Real PlayerHeight, RooWall IgnoreWall = null)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return null;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;
            RooWall wall = line.Wall;
            V2 start2D = new V2(Start.X, Start.Z);

            /*************************************************************/
            
            // check node boundingbox
            if (!line.BoundingBox.IsInside(End, GeometryConstants.WALLMINDISTANCE) && 
                !line.BoundingBox.IsInside(start2D, GeometryConstants.WALLMINDISTANCE))
                return null;
       
            /*************************************************************/

            // test walls of splitter
            while (wall != null)
            {
                if (wall != IgnoreWall && wall.IsBlockingMove(Start, End, PlayerHeight))
                    return wall;

                // loop over next wall in same plane
                wall = wall.NextWallInPlane;
            }

            /*************************************************************/

            RooWall wl = VerifyMoveByTree(line.LeftChild, Start, End, PlayerHeight, IgnoreWall);

            if (wl != null)
                return wl;

            else
                return VerifyMoveByTree(line.RightChild, Start, End, PlayerHeight, IgnoreWall);
        }
        /// <summary>
        /// Verifies if any wall blocks a ray from Start to End
        /// </summary>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <returns>True if OK, false if collision.</returns>
        public bool VerifySight(V3 Start, V3 End)
        {
            // look for blocking wall
            foreach (RooWall wall in Walls)
                if (wall.IsBlockingSight(Start, End))
                    return false;

            return true;
        }
Example #19
0
 /// <summary>
 /// Verifies Line of Sight from Start to End.
 /// Checking against Walls only (no sectors/ceilings).
 /// </summary>
 /// <param name="Start"></param>
 /// <param name="End"></param>
 /// <returns>True if OK, false if collision.</returns>
 public bool VerifySight(V3 Start, V3 End)
 {
     return VerifySightByTree(BSPTree[0], Start, End);
     //return VerifySightByList(Start, End);
 }
        public void Calculate()
        {
            // texture orientation
            Real radangle = MathUtil.BinaryAngleToRadian((ushort)TextureAngle);
            Real texorientx = (Real)System.Math.Cos(radangle);
            Real texorienty = (Real)System.Math.Sin(radangle);
            Real texorientz = 0;
            TextureOrientation = new V3(texorientx, texorienty, texorientz);

            // generate other endpoints from plane normal, texture origin, and texture
            //  orientation which determine the orientation of the texture's u v space
            //  in the 3d world's x, y, z space
            
            // plane normal
            V3 planeNormal = new V3(A, B, C);

            // first point
            // calculate z of texture origin from x, y, and plane equation            
            Real z = (-A * X0 - B * Y0 - D) / C;
            P0 = new V3(X0, Y0, z);
                      
            // cross normal with texture orientation to get vector perpendicular to texture
            //  orientation and normal = v axis direction
            V3 v2 = planeNormal.CrossProduct(TextureOrientation);
            v2.ScaleToLength(GeometryConstants.FINENESS);

            // cross normal with v axis direction vector to get vector perpendicular to v axis
            //  and normal = u axis direction vector
            V3 v1 = v2.CrossProduct(planeNormal);
            v1.ScaleToLength(GeometryConstants.FINENESS);

            // add vectors to origin to get endpoints
            P1 = P0 + v1;
            P2 = P0 + v2;
        }
Example #21
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <returns>True if OK, false if collision.</returns>
        protected bool VerifySightByTree(RooBSPItem Node, V3 Start, V3 End)
        {
            if (Node == null || Node.Type != RooBSPItem.NodeType.Node)
                return true;

            /*************************************************************/

            RooPartitionLine line = (RooPartitionLine)Node;
            RooWall wall = line.Wall;
            V2 start2D = new V2(Start.X, Start.Z);
            V2 end2D = new V2(End.X, End.Z);

            /*************************************************************/

            Real startDist  = line.GetDistance(start2D);
            Real endDist    = line.GetDistance(end2D);

            /*************************************************************/

            // both endpoints on negative side
            if (startDist < 0.0f && endDist < 0.0f)
                return VerifySightByTree(line.LeftChild, Start, End);

            // both endpoints on positive side
            else if (startDist > 0.0f && endDist > 0.0f)
                return VerifySightByTree(line.RightChild, Start, End);

            // crosses infinite splitter or one or both points on splitter
            else
            {
                // test walls of splitter
                while (wall != null)
                {
                    if (wall.IsBlockingSight(Start, End))
                        return false;

                    // loop over next wall in same plane
                    wall = wall.NextWallInPlane;
                }

                // must climb down both subtrees, go left first
                bool wl = VerifySightByTree(line.LeftChild, Start, End);

                // return collision if already found
                if (wl == false)
                    return wl;

                // try other subtree otherwise
                else
                    return VerifySightByTree(line.RightChild, Start, End);
            }           
        }
        /// <summary>
        /// Tries to resolve the source and target RoomObject
        /// references from RoomObjects parameter, also sets the start position.
        /// </summary>
        /// <param name="RoomObjects"></param>
        /// <param name="RaiseChangedEvent"></param>
        public void ResolveSourceTarget(IList<RoomObject> RoomObjects, bool RaiseChangedEvent)
        {
            if (RaiseChangedEvent)
            {
                foreach (RoomObject roomObject in RoomObjects)
                {
                    if (roomObject.ID == source.ID)
                    {
                        SourceObject = roomObject;
                        Position3D = SourceObject.Position3D.Clone();
                    }

                    else if (roomObject.ID == target.ID)
                        TargetObject = roomObject;
                }
            }
            else
            {
                foreach (RoomObject roomObject in RoomObjects)
                {
                    if (roomObject.ID == source.ID)
                    {
                        sourceObject = roomObject;
                        position3D = sourceObject.Position3D.Clone();
                    }
                    else if (roomObject.ID == target.ID)
                        targetObject = roomObject;
                }
            }
        }
Example #23
0
 /// <summary>
 /// Typed equals
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 public bool Equals(V3 obj)
 {
     return(obj.X == X && obj.Y == Y && obj.Z == Z);
 }
        /// <summary>
        /// Checks if this wall blocks
        /// a view ray from Start to End
        /// </summary>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <returns>True if blocked, false if OK</returns>
        public bool IsBlockingSight(V3 Start, V3 End)
        {
            // 2D
            V2 Start2D = new V2(Start.X, Start.Z);
            V2 End2D = new V2(End.X, End.Z);

            // calculate the sides of the points (returns -1, 0 or 1)
            int startside = Start2D.GetSide(P1, P2);
            int endside = End2D.GetSide(P1, P2);

            // if points are not on same side
            // the infinite lines cross
            if (startside != endside)
            {
                // verify also the finite line segments cross
                V2 intersect;
                LineLineIntersectionType intersecttype =
                    MathUtil.IntersectLineLine(Start2D, End2D, P1, P2, out intersect);

                if (intersecttype == LineLineIntersectionType.OneIntersection ||
                    intersecttype == LineLineIntersectionType.OneBoundaryPoint ||
                    intersecttype == LineLineIntersectionType.FullyCoincide ||
                    intersecttype == LineLineIntersectionType.PartiallyCoincide)
                {
                    // the vector/ray between start and end
                    V3 diff = End - Start;

                    // solve 3d linear equation to get rayheight R2
                    // (height of possible intersection)
                    //
                    // ( R1 )   (P1)            (Q1)
                    // ( R2 ) = (P2) + lambda * (Q2)
                    // ( R3 )   (P3)            (Q3)
                    //
                    // using:
                    // R = intersect
                    // P = Start
                    // Q = diff (Direction)

                    // get lambda scale
                    Real lambda = 1.0f;
                    if (diff.X != 0)
                        lambda = (intersect.X - Start.X) / diff.X;

                    else if (diff.Z != 0)
                        lambda = (intersect.Y - Start.Z) / diff.Z;

                    // calculate the rayheight based on linear 3d equation
                    Real rayheight = Start.Y + lambda * diff.Y;

                    // compare height with wallheights
                    // use average of both endpoints (in case its sloped)
                    // do not care about the sides
                    Real h3 = (z3 + zz3) / 2.0f;
                    Real h2 = (z2 + zz2) / 2.0f;
                    Real h1 = (z1 + zz1) / 2.0f;
                    Real h0 = (z0 + zz0) / 2.0f;
                    bool a, b;

                    // test upper part
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceUpper != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent));
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceUpper != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent));
                    if ((a || b) &&
                        rayheight < h3 &&
                        rayheight > h2)
                        return true;

                    // test middle part
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceMiddle != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent));
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceMiddle != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent));
                    if ((a || b) &&
                        rayheight < h2 &&
                        rayheight > h1)
                        return true;

                    // test lower part (nolookthrough)
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceLower != null);
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceLower != null);
                    if ((a || b) &&
                        rayheight < h1 &&
                        rayheight > h0)
                        return true;
                }
            }

            return false;
        }
Example #25
0
        /// <summary>
        /// Updates the P, UV and Normal properties for either floor or ceiling.
        /// Fills in current 3D data for the subsector vertices.
        /// Note: Z component is the height here.
        /// </summary>
        /// <param name="IsFloor">Whether to create for floor or ceiling</param>
        /// <param name="Scale">Optional additional scale to apply.</param>
        public void UpdateVertexData(bool IsFloor, Real Scale = 1.0f)
        {
            const Real INV64 = 1.0f / (Real)(64 << 4);  // from old code..

            V3 normal;
            V3[] p          = new V3[Vertices.Count];
            V2[] uv         = new V2[Vertices.Count];
            Real left        = 0;
            Real top         = 0;
            Real oneOverC   = 0.0f;

            RooSectorSlopeInfo slopeInfo = 
                (IsFloor) ? Sector.SlopeInfoFloor : Sector.SlopeInfoCeiling;
            
            /*****************************************************************/

            // find most top left vertex and get its coordinates
            if (slopeInfo != null)
            {
                left = (int)slopeInfo.X0;
                top = (int)slopeInfo.Y0;
                oneOverC = 1.0f / slopeInfo.C;
            }
            else
            {
                for (int i = 0; i < Vertices.Count; i++)
                {
                    if (Vertices[i].X < left)
                        left = Vertices[i].X;

                    if (Vertices[i].Y < top)
                        top = Vertices[i].Y;
                }
            }

            /*****************************************************************/

            for (int count = 0; count < Vertices.Count; count++)
            {
                // 1: Fill in vertex coordinates
                if (slopeInfo != null)
                {
                    p[count].X = Vertices[count].X;
                    p[count].Y = Vertices[count].Y;
                    p[count].Z = (-slopeInfo.A * p[count].X - slopeInfo.B * p[count].Y - slopeInfo.D) *oneOverC;
                }
                else
                {
                    p[count].X = Vertices[count].X;
                    p[count].Y = Vertices[count].Y;
                    p[count].Z = (IsFloor) ? (Sector.FloorHeight * 16.0f) : (Sector.CeilingHeight * 16.0f);                   
                }
              
                // 2.1: UV with slope
                if (slopeInfo != null)
                {
                    V3 intersectTop;
                    V3 intersectLeft;          
                    V3 vectorU;
                    V3 vectorV;
                    V3 vector;
                    Real distance;
                    Real U, temp;
                    
                    // calc distance from top line (vector u)
                    U = ((p[count].X - slopeInfo.P0.X) * (slopeInfo.P1.X - slopeInfo.P0.X)) +
                        ((p[count].Z - slopeInfo.P0.Z) * (slopeInfo.P1.Z - slopeInfo.P0.Z)) +
                        ((p[count].Y - slopeInfo.P0.Y) * (slopeInfo.P1.Y - slopeInfo.P0.Y));

                    temp = ((slopeInfo.P1.X - slopeInfo.P0.X) * (slopeInfo.P1.X - slopeInfo.P0.X)) +
                        ((slopeInfo.P1.Z - slopeInfo.P0.Z) * (slopeInfo.P1.Z - slopeInfo.P0.Z)) +
                        ((slopeInfo.P1.Y - slopeInfo.P0.Y) * (slopeInfo.P1.Y - slopeInfo.P0.Y));

                    if (temp == 0.0f)
                        temp = 1.0f;

                    U /= temp;

                    intersectTop.X = slopeInfo.P0.X + U * (slopeInfo.P1.X - slopeInfo.P0.X);
                    intersectTop.Z = slopeInfo.P0.Z + U * (slopeInfo.P1.Z - slopeInfo.P0.Z);
                    intersectTop.Y = slopeInfo.P0.Y + U * (slopeInfo.P1.Y - slopeInfo.P0.Y);

                    uv[count].X = (Real)System.Math.Sqrt(
                                    (p[count].X - intersectTop.X) * (p[count].X - intersectTop.X) +
                                    (p[count].Z - intersectTop.Z) * (p[count].Z - intersectTop.Z) +
                                    (p[count].Y - intersectTop.Y) * (p[count].Y - intersectTop.Y));

                    // calc distance from left line (vector v)
                    U = ((p[count].X - slopeInfo.P0.X) * (slopeInfo.P2.X - slopeInfo.P0.X)) +
                        ((p[count].Z - slopeInfo.P0.Z) * (slopeInfo.P2.Z - slopeInfo.P0.Z)) +
                        ((p[count].Y - slopeInfo.P0.Y) * (slopeInfo.P2.Y - slopeInfo.P0.Y));

                    temp = ((slopeInfo.P2.X - slopeInfo.P0.X) * (slopeInfo.P2.X - slopeInfo.P0.X)) +
                        ((slopeInfo.P2.Z - slopeInfo.P0.Z) * (slopeInfo.P2.Z - slopeInfo.P0.Z)) +
                        ((slopeInfo.P2.Y - slopeInfo.P0.Y) * (slopeInfo.P2.Y - slopeInfo.P0.Y));

                    if (temp == 0.0f)
                        temp = 1.0f;

                    U /= temp;

                    intersectLeft.X = slopeInfo.P0.X + U * (slopeInfo.P2.X - slopeInfo.P0.X);
                    intersectLeft.Z = slopeInfo.P0.Z + U * (slopeInfo.P2.Z - slopeInfo.P0.Z);
                    intersectLeft.Y = slopeInfo.P0.Y + U * (slopeInfo.P2.Y - slopeInfo.P0.Y);

                    uv[count].Y = (Real)System.Math.Sqrt(
                                    (p[count].X - intersectLeft.X) * (p[count].X - intersectLeft.X) +
                                    (p[count].Z - intersectLeft.Z) * (p[count].Z - intersectLeft.Z) +
                                    (p[count].Y - intersectLeft.Y) * (p[count].Y - intersectLeft.Y));

                    uv[count].X += (Sector.TextureY << 4) / 2.0f;
                    uv[count].Y += (Sector.TextureX << 4) / 2.0f;

                    vectorU.X = slopeInfo.P1.X - slopeInfo.P0.X;
                    vectorU.Z = slopeInfo.P1.Z - slopeInfo.P0.Z;
                    vectorU.Y = slopeInfo.P1.Y - slopeInfo.P0.Y;

                    distance = (Real)System.Math.Sqrt((vectorU.X * vectorU.X) + (vectorU.Y * vectorU.Y));

                    if (distance == 0.0f)
                        distance = 1.0f;

                    vectorU.X /= distance;
                    vectorU.Z /= distance;
                    vectorU.Y /= distance;

                    vectorV.X = slopeInfo.P2.X - slopeInfo.P0.X;
                    vectorV.Z = slopeInfo.P2.Z - slopeInfo.P0.Z;
                    vectorV.Y = slopeInfo.P2.Y - slopeInfo.P0.Y;

                    distance = (Real)System.Math.Sqrt((vectorV.X * vectorV.X) + (vectorV.Y * vectorV.Y));

                    if (distance == 0.0f)
                        distance = 1.0f;

                    vectorV.X /= distance;
                    vectorV.Z /= distance;
                    vectorV.Y /= distance;

                    vector.X = p[count].X - slopeInfo.P0.X;
                    vector.Y = p[count].Y - slopeInfo.P0.Y;

                    distance = (Real)System.Math.Sqrt((vector.X * vector.X) + (vector.Y * vector.Y));

                    if (distance == 0)
                        distance = 1.0f;

                    vector.X /= distance;
                    vector.Y /= distance;

                    if (((vector.X * vectorU.X) +
                        (vector.Y * vectorU.Y)) <= 0)
                        uv[count].Y = -uv[count].Y;

                    if (((vector.X * vectorV.X) +
                        (vector.Y * vectorV.Y)) > 0)
                        uv[count].X = -uv[count].X;
                }

                // 2.2: UV without slope
                else
                {
                    uv[count].X = System.Math.Abs(Vertices[count].Y - top) - (Sector.TextureY << 4);
                    uv[count].Y = System.Math.Abs(Vertices[count].X - left) - (Sector.TextureX << 4);
                }

                uv[count].X *= INV64;
                uv[count].Y *= INV64;

                // apply additional userscale
                p[count] *= Scale;
            }

            /*****************************************************************/

            // Calculate the normal
            if (slopeInfo != null)
            {
                // if the sector is sloped, we get the normal from slopeinfo
                normal.X = slopeInfo.A;
                normal.Y = slopeInfo.B;
                normal.Z = slopeInfo.C;

                normal.Normalize();
            }
            else if (IsFloor)
            {
                // default normal for non sloped floor
                normal.X = 0.0f;
                normal.Y = 0.0f;
                normal.Z = 1.0f;
            }
            else
            {
                // default normal for non sloped ceilings
                normal.X = 0.0f;
                normal.Y = 0.0f;
                normal.Z = -1.0f;
            }

            /*****************************************************************/

            // save in class properties depending on floor/ceiling
            if (IsFloor)
            {
                FloorP = p;
                FloorUV = uv;
                FloorNormal = normal;
            }
            else
            {
                CeilingP = p;
                CeilingUV = uv;
                CeilingNormal = normal;
            }
        }