/// <summary>
        /// Called when the surface becomes available.
        /// </summary>
        /// <param name="delayedRequest">A request that was delayed until surface becomes available.</param>
        protected override void OnSurfaceAvailable(PathfindingRequest delayedRequest)
        {
            if (currentFace == null ||
                !AlchemyNavigationSystem.Current.ContainsFace(Layer, currentFace.source))
            {
                var ray = new Ray(position, Vector3.down);
                if (AlchemyNavigationSystem.Current.Raycast(ray, Layer, AreaMask, out var result))
                {
                    currentFace = new CachedFace(result.face);
                    position    = result.position;
                    ApplyPosition();
                }
                else
                {
                    Debug.LogWarning("Agent couldn't be placed on navigation surface.");
                    gameObject.SetActive(false);
                    return;
                }
            }

            if (delayedRequest != null)
            {
                CancelAllRequests();
                RequestPath(position, delayedRequest.endPosition, PathType, currentFace.source);
            }
            else if (IsPathWalking)
            {
                Vector3 destination = progress.pointPath[progress.pointsCount - 1];
                CancelAllRequests();
                RequestPath(position, destination, PathType, currentFace.source);
            }
        }
        private void Move(Vector3 move)
        {
            Vector3 displacement = Vector3.ProjectOnPlane(move, currentFace.plane.normal);

            Vector3 potentialPosition = position + displacement;

            if (currentFace.source.IsPointInsideFace(potentialPosition, EpsilonOffset))
            {
                position = potentialPosition;
            }
            else
            {
                Vector3 clampedPosition     = currentFace.SnapToFace(position, displacement);
                Vector3 clampedDisplacement = clampedPosition - position;
                position = clampedPosition;
                Vector3 cutDisplacement = displacement.normalized * (displacement.magnitude - clampedDisplacement.magnitude); // + 2 * EpsilonOffset
                if (progress != null && progress.HasNextFace && progress.NextFace.IsPointInsideFace(position, EpsilonOffset))
                {
                    progress.currentFace++;
                    currentFace = new CachedFace(progress.CurrentFace);
                    var ray = new Ray(position, Vector3.down);
                    currentFace.plane.Raycast(ray, out float enter);
                    position = ray.GetPoint(enter);
                    while (progress.HasNextPoint && !progress.IsCurrentPointOnCurrentOrNextFaces())
                    {
                        progress.currentPoint++;
                    }
                    Move(cutDisplacement);
                }
                else
                {
                    position += currentFace.CastDisplacementOnClosestEdge(position, cutDisplacement);
                }
            }
        }
 /// <summary>
 /// Called when the agent becomes enabled and active.
 /// </summary>
 protected override void OnAgentEnable()
 {
     currentFace = null;
     velocity    = Vector3.zero;
     position    = transform.position;
     ApplyPosition();
     ReloadMovementModifiers();
 }
Exemplo n.º 4
0
 /// <summary>
 /// Store the mesh and texture.
 /// </summary>
 public CachedPlanet CachePlanet()
 {
     CachedFace[] cachedFaces = new CachedFace[6];
     for (int i = 0; i < 6; i++)
     {
         cachedFaces[i] = new CachedFace(terrainFaces[i].mesh, terrainFaces[i].texture);
     }
     return(new CachedPlanet(cachedFaces));
 }
Exemplo n.º 5
0
        public void AppendText(char *text, int count, TextFormat format)
        {
            // look up the cache entry for the given font and size
            var font = format.Font;
            var size = FontFace.ComputePixelSize(format.Size, Dpi);
            var key  = new CacheKey(font.Id, size);

            if (!cache.TryGetValue(key, out var cachedFace))
            {
                cache.Add(key, cachedFace = new CachedFace(font, size));
            }

            // process each character in the string
            var nextBreak = BreakCategory.None;
            var previous  = new CodePoint();
            var end       = text + count;

            while (text != end)
            {
                // handle surrogate pairs properly
                CodePoint codePoint;
                var       c = *text++;
                if (char.IsSurrogate(c) && text != end)
                {
                    codePoint = new CodePoint(c, *text++);
                }
                else
                {
                    codePoint = c;
                }

                // ignore linefeeds directly after a carriage return
                if (c == '\n' && (char)previous == '\r')
                {
                    continue;
                }

                // get the glyph data
                if (!cachedFace.Glyphs.TryGetValue(codePoint, out var glyph) && !char.IsControl(c))
                {
                    var data   = font.GetGlyph(codePoint, size);
                    var width  = data.RenderWidth;
                    var height = data.RenderHeight;
                    if (width > atlas.Width || height > atlas.Height)
                    {
                        throw new InvalidOperationException("Glyph is larger than the size of the provided atlas.");
                    }

                    var rect = new Rect();
                    if (width > 0 && height > 0)
                    {
                        // render the glyph
                        var memSize = width * height;
                        var mem     = memoryBuffer;
                        if (mem == null)
                        {
                            memoryBuffer = mem = new MemoryBuffer(memSize);
                        }

                        mem.Clear(memSize);
                        data.RenderTo(new Surface
                        {
                            Bits   = mem.Pointer,
                            Width  = width,
                            Height = height,
                            Pitch  = width
                        });

                        // save the rasterized glyph in the user's atlas
                        rect = packer.Insert(width, height);
                        if (rect.Height == 0)
                        {
                            // didn't fit in the atlas... start a new sheet
                            currentPage++;
                            packer.Clear(atlas.Width, atlas.Height);
                            rect = packer.Insert(width, height);
                            if (rect.Height == 0)
                            {
                                throw new InvalidOperationException("Failed to insert glyph into fresh page.");
                            }
                        }
                        atlas.Insert(currentPage, rect.X, rect.Y, rect.Width, rect.Height, mem.Pointer);
                    }

                    glyph = new CachedGlyph(rect, data.HorizontalMetrics.Bearing, data.HorizontalMetrics.Advance);
                    cachedFace.Glyphs.Add(codePoint, glyph);
                }

                // check for a kerning offset
                var kerning = font.GetKerning(previous, codePoint, size);
                previous = codePoint;

                // figure out whether this character can serve as a line break point
                // TODO: more robust character class handling
                var breakCategory = BreakCategory.None;
                if (char.IsWhiteSpace(c))
                {
                    if (c == '\r' || c == '\n')
                    {
                        breakCategory = BreakCategory.Mandatory;
                    }
                    else
                    {
                        breakCategory = BreakCategory.Opportunity;
                    }
                }

                // the previous character might make us think that this one should be a break opportunity
                if (nextBreak > breakCategory)
                {
                    breakCategory = nextBreak;
                }
                if (c == '-')
                {
                    nextBreak = BreakCategory.Opportunity;
                }

                // alright, we have all the right glyph data cached and loaded
                // append relevant info to our buffer; we'll do the actual layout later
                buffer.Add(new BufferEntry
                {
                    GlyphData = glyph,
                    Kerning   = kerning,
                    Break     = breakCategory
                });
            }
        }