Exemplo n.º 1
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
            {
                return(true);
            }

            PolyMesh     mesh = context.PolyMesh;
            PolyMeshData data = mesh.GetData(false);

            if (data.polyCount == 0)
            {
                return(true);
            }

            bool applied = false;

            for (int i = 0; i < mAreas.Length; i++)
            {
                byte   area  = mAreas[i];
                ushort flags = mFlags[i];

                int marked = 0;

                for (int iPoly = 0; iPoly < data.polyCount; iPoly++)
                {
                    if (data.areas[iPoly] == area)
                    {
                        data.flags[iPoly] |= flags;
                        marked++;
                    }
                }

                if (marked > 0)
                {
                    string msg = string.Format(
                        "{0} : Added '0x{1:X}' flag(s) to {2} poylgons assigned to area {3}."
                        , Name, flags, marked, area);

                    context.Log(msg, this);

                    applied = true;
                }
            }

            if (applied)
            {
                mesh.Load(data);
            }
            else
            {
                context.Log(Name + ": No flags applied.", this);
            }

            return(true);
        }
Exemplo n.º 2
0
 private TileBuildTask(int tx, int tz
                       , PolyMeshData polyData
                       , PolyMeshDetailData detailData
                       , ConnectionSet connections
                       , bool bvTreeEnabled
                       , bool isThreadSafe
                       , int priority)
     : base(priority)
 {
     mTileX         = tx;
     mTileZ         = tz;
     mPolyData      = polyData;
     mDetailData    = detailData;
     mConnections   = connections;
     mBVTreeEnabled = bvTreeEnabled;
     mIsThreadSafe  = isThreadSafe;
 }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a new task.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The task should only be marked as thread-safe if the data parameters are treated
        /// as immutable while the task is running.
        /// </para>
        /// <para>
        /// Creation will fail on null parameters, invalid tile indices, and an empty
        /// polygon mesh.
        /// </para>
        /// </remarks>
        /// <param name="tx">The x-index of the tile within the tile grid. (x, z)</param>
        /// <param name="tz">The z-index of the tile within the tile grid. (x, z)</param>
        /// <param name="polyData">The polygon mesh data.</param>
        /// <param name="detailData">The detail mesh data. (Optional)</param>
        /// <param name="conns">The off-mesh connection set.</param>
        /// <param name="bvTreeEnabled">True if bounding volumes should be generated.</param>
        /// <param name="isThreadSafe">True if the task is safe to run on its own thread.</param>
        /// <param name="priority">The task priority.</param>
        /// <returns>A new task, or null on error.</returns>
        public static TileBuildTask Create(int tx, int tz
                                           , PolyMeshData polyData
                                           , PolyMeshDetailData detailData
                                           , ConnectionSet conns
                                           , bool bvTreeEnabled
                                           , bool isThreadSafe
                                           , int priority)
        {
            if (tx < 0 || tz < 0 ||
                polyData == null || polyData.polyCount == 0 ||
                conns == null)
            {
                return(null);
            }

            return(new TileBuildTask(tx, tz
                                     , polyData, detailData, conns, bvTreeEnabled, isThreadSafe, priority));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>True</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
            {
                return(true);
            }

            PolyMeshData data = context.PolyMesh.GetData(false);

            for (int i = 0; i < data.flags.Length; i++)
            {
                data.flags[i] |= mFlags;
            }

            context.PolyMesh.Load(data);
            context.Log(string.Format("{0}: Applied flag(s) to all polys. Flag(s): 0x{1:X}"
                                      , Name, mFlags)
                        , this);

            return(true);
        }
Exemplo n.º 5
0
        private void SetBleedingObjects(PolyMeshData meshData, Renderer renderer)
        {
            var meshRenderer    = renderer as MeshRenderer;
            var skinnedRenderer = renderer as SkinnedMeshRenderer;

            GameObject blood = null;

            if (meshRenderer != null)
            {
                // add blood object
                Vector3 position  = AVG(meshData.vertices);
                Vector3 direction = AVG(meshData.normals).normalized;
                var     rotation  = Quaternion.FromToRotation(_prefubDirection, direction);
                blood = Instantiate(_bloodPrefub, renderer.gameObject.transform);

                blood.transform.localPosition = position;
                blood.transform.localRotation = rotation;
            }
            else if (skinnedRenderer != null)
            {
                var     bones      = skinnedRenderer.bones;
                float[] weightSums = new float[bones.Length];
                for (int i = 0; i < meshData.boneWeights.Length; i++)
                {
                    var w = meshData.boneWeights[i];
                    weightSums[w.boneIndex0] += w.weight0;
                    weightSums[w.boneIndex1] += w.weight1;
                    weightSums[w.boneIndex2] += w.weight2;
                    weightSums[w.boneIndex3] += w.weight3;
                }

                // detect most weightful bone for this PolyMeshData
                int maxIndex = 0;
                for (int i = 0; i < weightSums.Length; i++)
                {
                    float maxValue = weightSums[maxIndex];
                    float current  = weightSums[i];

                    if (current > maxValue)
                    {
                        maxIndex = i;
                    }
                }
                Transform bone = bones[maxIndex];

                // add blood object to the bone
                Vector3 position = AVG(meshData.vertices);
                Vector3 normal   = AVG(meshData.normals).normalized;
                var     rotation = Quaternion.FromToRotation(_prefubDirection, normal);

                var m = skinnedRenderer.sharedMesh.bindposes[maxIndex];
                position = m.MultiplyPoint3x4(position);

                blood = Instantiate(_bloodPrefub, bone);
                blood.transform.localPosition = position;
                blood.transform.localRotation = rotation;
            }

            if (_alignPrefSize)
            {
                var parentScale = blood.transform.parent.lossyScale;
                var newScale    = new Vector3(
                    1f / parentScale.x,
                    1f / parentScale.y,
                    1f / parentScale.z);

                blood.transform.localScale = Vector3.Scale(newScale, blood.transform.localScale);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Draws a debug view of a <see cref="PolyMeshData"/> object.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Meant to be called during the MonoBehavior.OnRenderObject() method.
        /// </para>
        /// </remarks>
        /// <param name="polyData">The polygon mesh to draw.</param>
        public static void Draw(PolyMeshData polyData)
        {
            DebugDraw.SimpleMaterial.SetPass(0);

            Color walkableColor   = new Color(0, 0.75f, 1.0f, 0.25f);
            Color nullRegionColor = new Color(0, 0, 0, 0.25f);

            int[] pTargetVert = new int[3];

            GL.Begin(GL.TRIANGLES);
            for (int iPoly = 0; iPoly < polyData.polyCount; iPoly++)
            {
                int pPoly = iPoly * polyData.maxVertsPerPoly * 2;

                if (polyData.areas[iPoly] == NMGen.MaxArea)
                {
                    GL.Color(walkableColor);
                }
                else if (polyData.areas[iPoly] == NMGen.NullRegion)
                {
                    GL.Color(nullRegionColor);
                }
                else
                {
                    GL.Color(ColorUtil.IntToColor(polyData.areas[iPoly], 1.0f));
                }

                pTargetVert[0] = polyData.polys[pPoly + 0] * 3;
                for (int iPolyVert = 2
                     ; iPolyVert < polyData.maxVertsPerPoly
                     ; iPolyVert++)
                {
                    if (polyData.polys[pPoly + iPolyVert]
                        == PolyMesh.NullIndex)
                    {
                        break;
                    }

                    pTargetVert[1] =
                        polyData.polys[pPoly + iPolyVert] * 3;
                    pTargetVert[2] =
                        polyData.polys[pPoly + iPolyVert - 1] * 3;

                    for (int i = 0; i < 3; i++)
                    {
                        int p = pTargetVert[i];
                        int x = polyData.verts[p + 0];
                        // Offset y a little to ensure it clears the
                        // source geometry.
                        int y = polyData.verts[p + 1] + 1;
                        int z = polyData.verts[p + 2];
                        GL.Vertex3(polyData.boundsMin[0] + x * polyData.xzCellSize
                                   , polyData.boundsMin[1] + y * polyData.yCellSize
                                   , polyData.boundsMin[2] + z * polyData.xzCellSize);
                    }
                }
            }
            GL.End();

            Color internalEdgeColor = new Color(0, 0.2f, 0.25f, 0.25f);
            Color boundaryEdgeColor = new Color(0.65f, 0.2f, 0, 0.9f);

            GL.Begin(GL.LINES);
            for (int iPoly = 0; iPoly < polyData.polyCount; iPoly++)
            {
                int pPoly = iPoly * polyData.maxVertsPerPoly * 2;

                for (int iPolyVert = 0; iPolyVert < polyData.maxVertsPerPoly; iPolyVert++)
                {
                    int iv = polyData.polys[pPoly + iPolyVert];

                    if (iv == PolyMesh.NullIndex)
                    {
                        break;
                    }

                    if (polyData.polys[pPoly + polyData.maxVertsPerPoly + iPolyVert]
                        == PolyMesh.NullIndex)
                    {
                        GL.Color(boundaryEdgeColor);
                    }
                    else
                    {
                        GL.Color(internalEdgeColor);
                    }

                    // Note: Using only first two indexes.
                    pTargetVert[0] = iv * 3;

                    if (iPolyVert + 1 >= polyData.maxVertsPerPoly)
                    {
                        // Reached hard end of polygon.  Loop back.
                        iv = polyData.polys[pPoly + 0];
                    }
                    else
                    {
                        iv = polyData.polys[pPoly + iPolyVert + 1];

                        if (iv == PolyMesh.NullIndex)
                        {
                            // Reached soft end of polygon.  Loop back.
                            iv = polyData.polys[pPoly + 0];
                        }
                    }

                    pTargetVert[1] = iv * 3;

                    for (int i = 0; i < 2; i++)
                    {
                        int p = pTargetVert[i];
                        int x = polyData.verts[p + 0];
                        // Offset y a little to ensure it clears the
                        // source geometry.
                        int y = polyData.verts[p + 1] + 1;
                        int z = polyData.verts[p + 2];

                        GL.Vertex3(polyData.boundsMin[0] + x * polyData.xzCellSize
                                   , polyData.boundsMin[1] + y * polyData.yCellSize
                                   , polyData.boundsMin[2] + z * polyData.xzCellSize);
                    }
                }
            }
            GL.End();
        }
Exemplo n.º 7
0
 /// <summary>
 /// Finalize the task.
 /// </summary>
 protected override void FinalizeTask()
 {
     mPolyData    = null;
     mDetailData  = null;
     mConnections = null;
 }
Exemplo n.º 8
0
        /// <summary>
        /// Creates a standard <see cref="NavmeshTileBuildData"/> object from the provided
        /// parameters.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Errors will be logged to the build context.
        /// </para>
        /// </remarks>
        /// <param name="tx">The x-index of the tile.</param>
        /// <param name="tz">The z-index of the tile.</param>
        /// <param name="polyMesh">The polygon mesh data.</param>
        /// <param name="detailMesh">The detail mesh data. (Optional)</param>
        /// <param name="connections">The off-mesh connections. (Null allowed.)</param>
        /// <param name="bvTreeEnabled">True if bounding volumes should be generated.</param>
        /// <param name="context">The build context.</param>
        /// <returns>The tile build data, or null on error.</returns>
        public static NavmeshTileBuildData GetBuildData(BuildContext context
                                                        , int tx, int tz
                                                        , PolyMeshData polyMesh, PolyMeshDetailData detailMesh
                                                        , ConnectionSet connections
                                                        , bool bvTreeEnabled)
        {
            if (context == null)
            {
                // Silent.
                return(null);
            }

            Vector3[] verts   = null;
            float[]   radii   = null;
            byte[]    dirs    = null;
            byte[]    areas   = null;
            ushort[]  flags   = null;
            uint[]    userIds = null;

            Vector3 bmin = polyMesh.boundsMin;
            Vector3 bmax = polyMesh.boundsMax;

            int connCount = (connections == null)
                ? 0
                : connections.GetConnections(bmin.x, bmin.z, bmax.x, bmax.z
                                             , out verts, out radii, out dirs, out areas, out flags, out userIds);

            NavmeshTileBuildData result = new NavmeshTileBuildData(
                polyMesh.vertCount
                , polyMesh.polyCount
                , polyMesh.maxVertsPerPoly
                , (detailMesh == null ? 0 : detailMesh.vertCount)
                , (detailMesh == null ? 0 : detailMesh.triCount)
                , connCount);

            if (!result.LoadBase(tx, tz, 0, 0
                                 , polyMesh.boundsMin
                                 , polyMesh.boundsMax
                                 , polyMesh.xzCellSize
                                 , polyMesh.yCellSize
                                 , polyMesh.walkableHeight
                                 , polyMesh.walkableRadius
                                 , polyMesh.walkableStep
                                 , bvTreeEnabled))
            {
                context.LogError("Base data load failed. Bad configuration data or internal error."
                                 , null);
                return(null);
            }

            if (!result.LoadPolys(polyMesh.verts
                                  , polyMesh.vertCount
                                  , polyMesh.polys
                                  , polyMesh.flags
                                  , polyMesh.areas
                                  , polyMesh.polyCount))
            {
                context.LogError("Polygon load failed. Bad mesh data or internal error.", null);
                return(null);
            }

            if (detailMesh != null)
            {
                if (!result.LoadDetail(detailMesh.verts
                                       , detailMesh.vertCount
                                       , detailMesh.tris
                                       , detailMesh.triCount
                                       , detailMesh.meshes
                                       , detailMesh.meshCount))
                {
                    context.LogError("Detail load failed. Bad mesh data or internal error.", null);
                    return(null);
                }
            }

            if (connCount > 0)
            {
                if (!result.LoadConns(verts, radii, dirs, areas, flags, userIds, connCount))
                {
                    context.LogError("Off-mesh connection load failed. Bad data or internal error."
                                     , null);
                    return(null);
                }
            }

            return(result);
        }