/// <summary>
        /// Calculates exact intersection point (in uniform grid coordinates) from stored havok's hit info object obtained during FindClosest grid.
        /// Returns position of intersected object in uniform grid coordinates.
        /// </summary>
        protected Vector3D?GetIntersectedBlockData(ref MatrixD inverseGridWorldMatrix, out Vector3D intersection, out MySlimBlock intersectedBlock, out ushort?compoundBlockId)
        {
            Debug.Assert(m_hitInfo != null);
            Debug.Assert(m_hitInfo.Value.HkHitInfo.Body.GetEntity() == CurrentGrid);

            intersection     = Vector3D.Zero;
            intersectedBlock = null;
            compoundBlockId  = null;

            double   distance             = double.MaxValue;
            Vector3D?intersectedObjectPos = null;

            var      line     = new LineD(IntersectionStart, IntersectionStart + IntersectionDirection * IntersectionDistance);
            Vector3I position = Vector3I.Zero;

            if (!CurrentGrid.GetLineIntersectionExactGrid(ref line, ref position, ref distance, m_hitInfo.Value))
            {
                return(null);
            }

            distance             = Math.Sqrt(distance);
            intersectedObjectPos = position;

            intersectedBlock = CurrentGrid.GetCubeBlock(position);
            if (intersectedBlock == null)
            {
                return(null);
            }

            // Compound block - get index of internal block for removing
            if (intersectedBlock.FatBlock is MyCompoundCubeBlock)
            {
                MyCompoundCubeBlock compoundBlock = intersectedBlock.FatBlock as MyCompoundCubeBlock;
                ushort?idInCompound = null;

                ushort blockId;
                MyIntersectionResultLineTriangleEx?triIntersection;

                if (compoundBlock.GetIntersectionWithLine(ref line, out triIntersection, out blockId))
                {
                    idInCompound = blockId;
                }
                else if (compoundBlock.GetBlocksCount() == 1) // If not intersecting with any internal block and there is only one then set the index to it
                {
                    idInCompound = compoundBlock.GetBlockId(compoundBlock.GetBlocks()[0]);
                }

                compoundBlockId = idInCompound;
            }

            Debug.Assert(intersectedObjectPos != null);
            Vector3D rayStart = Vector3D.Transform(IntersectionStart, inverseGridWorldMatrix);
            Vector3D rayDir   = Vector3D.Normalize(Vector3D.TransformNormal(IntersectionDirection, inverseGridWorldMatrix));

            intersection  = rayStart + distance * rayDir;
            intersection *= 1.0f / CurrentGrid.GridSize;

            return(intersectedObjectPos);
        }
Beispiel #2
0
        protected bool GetBlockAddPosition(float gridSize, bool placingSmallGridOnLargeStatic, out MySlimBlock intersectedBlock, out Vector3D intersectedBlockPos, out Vector3D intersectExactPos,
                                           out Vector3I addPositionBlock, out Vector3I addDirectionBlock, out ushort?compoundBlockId)
        {
            intersectedBlock    = null;
            intersectedBlockPos = new Vector3D();
            intersectExactPos   = new Vector3();
            addDirectionBlock   = new Vector3I();
            addPositionBlock    = new Vector3I();
            compoundBlockId     = null;

            if (CurrentVoxelBase != null)
            {
                Vector3 hitInfoNormal = m_hitInfo.Value.HkHitInfo.Normal;
                Base6Directions.Direction closestDir = Base6Directions.GetClosestDirection(hitInfoNormal);
                Vector3I hitNormal = Base6Directions.GetIntVector(closestDir);

                double distance = IntersectionDistance * m_hitInfo.Value.HkHitInfo.HitFraction;

                Vector3D rayStart     = IntersectionStart;
                Vector3D rayDir       = Vector3D.Normalize(IntersectionDirection);
                Vector3D intersection = rayStart + distance * rayDir;

                // Get cube block placement position (add little threshold to hit normal direction to avoid wavy surfaces).
                addPositionBlock    = MyCubeGrid.StaticGlobalGrid_WorldToUGInt(intersection + 0.1f * Vector3.Half * hitNormal * gridSize, gridSize, CubeBuilderDefinition.BuildingSettings.StaticGridAlignToCenter);
                addDirectionBlock   = hitNormal;
                intersectedBlockPos = addPositionBlock - hitNormal;

                // Exact intersection in uniform grid coords.
                intersectExactPos = MyCubeGrid.StaticGlobalGrid_WorldToUG(intersection, gridSize, CubeBuilderDefinition.BuildingSettings.StaticGridAlignToCenter);
                // Project exact intersection to cube face of intersected block.
                intersectExactPos = ((Vector3.One - Vector3.Abs(hitNormal)) * intersectExactPos) + ((intersectedBlockPos + 0.5f * hitNormal) * Vector3.Abs(hitNormal));

                return(true);
            }

            Vector3D?intersectedObjectPos = GetIntersectedBlockData(ref m_invGridWorldMatrix, out intersectExactPos, out intersectedBlock, out compoundBlockId);

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

            intersectedBlockPos = intersectedObjectPos.Value;

            Vector3I removePos;

            if (!GetCubeAddAndRemovePositions(Vector3I.Round(intersectedBlockPos), placingSmallGridOnLargeStatic, out addPositionBlock, out addDirectionBlock, out removePos))
            {
                return(false);
            }

            if (!placingSmallGridOnLargeStatic)
            {
                if (MyFakes.ENABLE_BLOCK_PLACING_ON_INTERSECTED_POSITION)
                {
                    Vector3I newRemovepos = Vector3I.Round(intersectedBlockPos);

                    if (newRemovepos != removePos)
                    {
                        if (m_hitInfo.HasValue)
                        {
                            Vector3 hitInfoNormal = m_hitInfo.Value.HkHitInfo.Normal;
                            Base6Directions.Direction closestDir = Base6Directions.GetClosestDirection(hitInfoNormal);
                            Vector3I hitNormal = Base6Directions.GetIntVector(closestDir);
                            addDirectionBlock = hitNormal;
                        }
                        removePos        = newRemovepos;
                        addPositionBlock = removePos + addDirectionBlock;
                    }
                }
                else
                {
                    if (CurrentGrid.CubeExists(addPositionBlock))
                    {
                        return(false);
                    }
                }
            }

            if (placingSmallGridOnLargeStatic)
            {
                removePos = Vector3I.Round(intersectedBlockPos);
            }

            intersectedBlockPos = removePos;
            intersectedBlock    = CurrentGrid.GetCubeBlock(removePos);
            if (intersectedBlock == null)
            {
                Debug.Assert(false, "No intersected block");
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Calculates exact intersection point (in uniform grid coordinates) from stored havok's hit info object obtained during FindClosest grid.
        /// Returns position of intersected object in uniform grid coordinates.
        /// </summary>
        protected Vector3D?GetIntersectedBlockData(ref MatrixD inverseGridWorldMatrix, out Vector3D intersection, out MySlimBlock intersectedBlock, out ushort?compoundBlockId)
        {
            Debug.Assert(m_hitInfo != null);
            Debug.Assert(m_hitInfo.Value.HkHitInfo.Body.GetEntity() == CurrentGrid);

            intersection     = Vector3D.Zero;
            intersectedBlock = null;
            compoundBlockId  = null;

            double   distance             = double.MaxValue;
            Vector3D?intersectedObjectPos = null;

            var      line     = new LineD(IntersectionStart, IntersectionStart + IntersectionDirection * IntersectionDistance);
            Vector3I position = Vector3I.Zero;

            if (!CurrentGrid.GetLineIntersectionExactGrid(ref line, ref position, ref distance, m_hitInfo.Value))
            {
                return(null);
            }

            distance             = Math.Sqrt(distance);
            intersectedObjectPos = position;

            intersectedBlock = CurrentGrid.GetCubeBlock(position);
            if (intersectedBlock == null)
            {
                return(null);
            }

            // Compound block - get index of internal block for removing
            if (intersectedBlock.FatBlock is MyCompoundCubeBlock)
            {
                MyCompoundCubeBlock      compoundBlock        = intersectedBlock.FatBlock as MyCompoundCubeBlock;
                ListReader <MySlimBlock> slimBlocksInCompound = compoundBlock.GetBlocks();
                double distanceSquaredInCompound = double.MaxValue;
                ushort?idInCompound = null;
                for (int i = 0; i < slimBlocksInCompound.Count; ++i)
                {
                    MySlimBlock cmpSlimBlock = slimBlocksInCompound.ItemAt(i);
                    MyIntersectionResultLineTriangleEx?intersectionTriResult;
                    if (cmpSlimBlock.FatBlock.GetIntersectionWithLine(ref line, out intersectionTriResult) && intersectionTriResult != null)
                    {
                        Vector3D startToIntersection = intersectionTriResult.Value.IntersectionPointInWorldSpace - IntersectionStart;
                        double   instrDistanceSq     = startToIntersection.LengthSquared();
                        if (instrDistanceSq < distanceSquaredInCompound)
                        {
                            distanceSquaredInCompound = instrDistanceSq;
                            idInCompound = compoundBlock.GetBlockId(cmpSlimBlock);
                        }
                    }
                }

                // If not intersecting with any internal block and there is only one then set the index to it
                if (idInCompound == null && compoundBlock.GetBlocksCount() == 1)
                {
                    idInCompound = compoundBlock.GetBlockId(compoundBlock.GetBlocks()[0]);
                }

                compoundBlockId = idInCompound;
            }

            Debug.Assert(intersectedObjectPos != null);
            Vector3D rayStart = Vector3D.Transform(IntersectionStart, inverseGridWorldMatrix);
            Vector3D rayDir   = Vector3D.Normalize(Vector3D.TransformNormal(IntersectionDirection, inverseGridWorldMatrix));

            intersection  = rayStart + distance * rayDir;
            intersection *= 1.0f / CurrentGrid.GridSize;

            return(intersectedObjectPos);
        }