private void RecalculateFitnessFunctionValues()
        {
            var   minFitnessFunctionValue = _population.Individuals[0].FitnessFunctionValue;
            float fitnessFunctionSum      = 0;

            for (int i = 1; i < _population.Count; i++)
            {
                if (_population.Individuals[i].FitnessFunctionValue < minFitnessFunctionValue)
                {
                    minFitnessFunctionValue = _population.Individuals[i].FitnessFunctionValue;
                }
            }

            for (int i = 0; i < _population.Count; i++)
            {
                _population.Individuals[i].FitnessFunctionValue = _population.Individuals[i].FitnessFunctionValue + 2 * MathF.Abs(minFitnessFunctionValue);
                fitnessFunctionSum += _population.Individuals[i].FitnessFunctionValue;
            }

            _population.FitnessFunctionSum = fitnessFunctionSum;
        }
Пример #2
0
        private static (Size, Rectangle) CalculateCropRectangle(
            Size source,
            ResizeOptions options,
            int width,
            int height)
        {
            if (width <= 0 || height <= 0)
            {
                return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
            }

            float ratio;
            int   sourceWidth  = source.Width;
            int   sourceHeight = source.Height;

            int destinationX      = 0;
            int destinationY      = 0;
            int destinationWidth  = width;
            int destinationHeight = height;

            // Fractional variants for preserving aspect ratio.
            float percentHeight = MathF.Abs(height / (float)sourceHeight);
            float percentWidth  = MathF.Abs(width / (float)sourceWidth);

            if (percentHeight < percentWidth)
            {
                ratio = percentWidth;

                if (options.CenterCoordinates.Any())
                {
                    float center = -(ratio * sourceHeight) * options.CenterCoordinates.ToArray()[1];
                    destinationY = (int)MathF.Round(center + (height / 2F));

                    if (destinationY > 0)
                    {
                        destinationY = 0;
                    }

                    if (destinationY < (int)MathF.Round(height - (sourceHeight * ratio)))
                    {
                        destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
                    }
                }
                else
                {
                    switch (options.Position)
                    {
                    case AnchorPositionMode.Top:
                    case AnchorPositionMode.TopLeft:
                    case AnchorPositionMode.TopRight:
                        destinationY = 0;
                        break;

                    case AnchorPositionMode.Bottom:
                    case AnchorPositionMode.BottomLeft:
                    case AnchorPositionMode.BottomRight:
                        destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
                        break;

                    default:
                        destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F);
                        break;
                    }
                }

                destinationHeight = (int)MathF.Ceiling(sourceHeight * percentWidth);
            }
            else
            {
                ratio = percentHeight;

                if (options.CenterCoordinates.Any())
                {
                    float center = -(ratio * sourceWidth) * options.CenterCoordinates.First();
                    destinationX = (int)MathF.Round(center + (width / 2F));

                    if (destinationX > 0)
                    {
                        destinationX = 0;
                    }

                    if (destinationX < (int)MathF.Round(width - (sourceWidth * ratio)))
                    {
                        destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
                    }
                }
                else
                {
                    switch (options.Position)
                    {
                    case AnchorPositionMode.Left:
                    case AnchorPositionMode.TopLeft:
                    case AnchorPositionMode.BottomLeft:
                        destinationX = 0;
                        break;

                    case AnchorPositionMode.Right:
                    case AnchorPositionMode.TopRight:
                    case AnchorPositionMode.BottomRight:
                        destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
                        break;

                    default:
                        destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F);
                        break;
                    }
                }

                destinationWidth = (int)MathF.Ceiling(sourceWidth * percentHeight);
            }

            return(new Size(width, height),
                   new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
        }
Пример #3
0
        private static (Size, Rectangle) CalculateBoxPadRectangle(
            Size source,
            ResizeOptions options,
            int width,
            int height)
        {
            if (width <= 0 || height <= 0)
            {
                return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
            }

            int sourceWidth  = source.Width;
            int sourceHeight = source.Height;

            // Fractional variants for preserving aspect ratio.
            float percentHeight = MathF.Abs(height / (float)sourceHeight);
            float percentWidth  = MathF.Abs(width / (float)sourceWidth);

            int boxPadHeight = height > 0 ? height : (int)MathF.Round(sourceHeight * percentWidth);
            int boxPadWidth  = width > 0 ? width : (int)MathF.Round(sourceWidth * percentHeight);

            // Only calculate if upscaling.
            if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight)
            {
                int destinationX;
                int destinationY;
                int destinationWidth  = sourceWidth;
                int destinationHeight = sourceHeight;
                width  = boxPadWidth;
                height = boxPadHeight;

                switch (options.Position)
                {
                case AnchorPositionMode.Left:
                    destinationY = (height - sourceHeight) / 2;
                    destinationX = 0;
                    break;

                case AnchorPositionMode.Right:
                    destinationY = (height - sourceHeight) / 2;
                    destinationX = width - sourceWidth;
                    break;

                case AnchorPositionMode.TopRight:
                    destinationY = 0;
                    destinationX = width - sourceWidth;
                    break;

                case AnchorPositionMode.Top:
                    destinationY = 0;
                    destinationX = (width - sourceWidth) / 2;
                    break;

                case AnchorPositionMode.TopLeft:
                    destinationY = 0;
                    destinationX = 0;
                    break;

                case AnchorPositionMode.BottomRight:
                    destinationY = height - sourceHeight;
                    destinationX = width - sourceWidth;
                    break;

                case AnchorPositionMode.Bottom:
                    destinationY = height - sourceHeight;
                    destinationX = (width - sourceWidth) / 2;
                    break;

                case AnchorPositionMode.BottomLeft:
                    destinationY = height - sourceHeight;
                    destinationX = 0;
                    break;

                default:
                    destinationY = (height - sourceHeight) / 2;
                    destinationX = (width - sourceWidth) / 2;
                    break;
                }

                return(new Size(width, height),
                       new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
            }

            // Switch to pad mode to downscale and calculate from there.
            return(CalculatePadRectangle(source, options, width, height));
        }
Пример #4
0
 private static float Diff(float a, float b) => MathF.Abs((a * 65535F) - (b * 65535F));
Пример #5
0
            GraphicsMemoryRegion <GraphicsResource> CreateTexture3DRegion(GraphicsContext graphicsContext, GraphicsBuffer textureStagingBuffer, bool isQuickAndDirty)
            {
                var textureWidth  = isQuickAndDirty ? 64u : 256u;
                var textureHeight = isQuickAndDirty ? 64u : 256u;
                var textureDepth  = isQuickAndDirty ? (ushort)64 : (ushort)256;
                var textureDz     = textureWidth * textureHeight;
                var texturePixels = textureDz * textureDepth;

                var texture3D       = graphicsContext.Device.MemoryAllocator.CreateTexture(GraphicsTextureKind.ThreeDimensional, GraphicsResourceCpuAccess.None, textureWidth, textureHeight, textureDepth, texelFormat: TexelFormat.R8G8B8A8_UNORM);
                var texture3DRegion = texture3D.Allocate(texture3D.Size, alignment: 4);
                var pTextureData    = textureStagingBuffer.Map <uint>(in texture3DRegion);

                var random = new Random(Seed: 1);

                var isOnBlurring = true;

                // start with random speckles
                for (uint n = 0; n < texturePixels; n++)
                {
                    // convert n to indices
                    float x = n % textureWidth;
                    float y = n % textureDz / textureWidth;
                    float z = n / textureDz;

                    // convert indices to fractions in the range [0, 1)
                    x /= textureWidth;
                    y /= textureHeight;
                    z /= textureHeight;

                    // make x,z relative to texture center
                    x -= 0.5f;
                    z -= 0.5f;

                    // get radius from center, clamped to 0.5
                    var radius = MathF.Abs(x); // MathF.Sqrt(x * x + z * z);
                    if (radius > 0.5f)
                    {
                        radius = 0.5f;
                    }

                    // scale as 1 in center, tapering off to the edge
                    var scale = 2 * MathF.Abs(0.5f - radius);

                    // random value scaled by the above
                    var rand = (float)random.NextDouble();
                    if (isOnBlurring && (rand < 0.99))
                    {
                        rand = 0;
                    }
                    uint value = (byte)(rand * scale * 255);
                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                }

                if (isOnBlurring)
                {
                    // now smear them out to smooth smoke splotches

                    var dy            = textureWidth;
                    var dz            = dy * textureHeight;
                    var falloffFactor = _isQuickAndDirty ? 0.9f : 0.95f;

                    for (var z = 0; z < textureDepth; z++)
                    {
                        for (var y = 0; y < textureHeight; y++)
                        {
                            for (var x = 1; x < textureWidth; x++)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - 1] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n - 1] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var x = (int)textureWidth - 2; x >= 0; x--)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + 1] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n + 1] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                        }
                    }
                    for (var z = 0; z < textureDepth; z++)
                    {
                        for (var x = 0; x < textureWidth; x++)
                        {
                            for (var y = 1; y < textureHeight; y++)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n - dy] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var y = 0; y <= 0; y++)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy + dz] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n - dy + dz] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var y = 1; y < textureHeight; y++)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n - dy] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var y = (int)textureHeight - 2; y >= 0; y--)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n + dy] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var y = (int)textureHeight - 1; y >= (int)textureHeight - 1; y--)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy - dz] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n + dy - dz] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var y = (int)textureHeight - 2; y >= 0; y--)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n + dy] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                        }
                    }
                    for (var y = 0; y < textureHeight; y++)
                    {
                        for (var x = 0; x < textureWidth; x++)
                        {
                            for (var z = 1; z < textureDepth; z++)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dz] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n - 1] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                            for (var z = (int)textureDepth - 0; z >= 0; z--)
                            {
                                var n = x + (y * dy) + (z * dz);
                                if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dz] & 0xFF))
                                {
                                    uint value = (byte)(falloffFactor * (pTextureData[n + 1] & 0xFF));
                                    pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24));
                                }
                            }
                        }
                    }
                }

                textureStagingBuffer.UnmapAndWrite(in texture3DRegion);
                graphicsContext.Copy(texture3D, textureStagingBuffer);

                return(texture3DRegion);
            }
Пример #6
0
 public static bool IsZero(float num)
 {
     return(MathF.Abs(num) < ZeroTolerance);
 }
Пример #7
0
        /// <inheritdoc/>
        protected override void OnFrameApply(
            ImageFrame <TPixel> source,
            Rectangle sourceRectangle,
            Configuration configuration)
        {
            int brushSize = this.definition.BrushSize;

            if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width)
            {
                throw new ArgumentOutOfRangeException(nameof(brushSize));
            }

            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int maxY   = endY - 1;
            int maxX   = endX - 1;

            int radius = brushSize >> 1;
            int levels = this.definition.Levels;

            using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size()))
            {
                source.CopyTo(targetPixels);

                var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY);
                ParallelHelper.IterateRows(
                    workingRect,
                    configuration,
                    rows =>
                {
                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        Span <TPixel> sourceRow = source.GetPixelRowSpan(y);
                        Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                        for (int x = startX; x < endX; x++)
                        {
                            int maxIntensity = 0;
                            int maxIndex     = 0;

                            var intensityBin = new int[levels];
                            var redBin       = new float[levels];
                            var blueBin      = new float[levels];
                            var greenBin     = new float[levels];

                            for (int fy = 0; fy <= radius; fy++)
                            {
                                int fyr     = fy - radius;
                                int offsetY = y + fyr;

                                offsetY = offsetY.Clamp(0, maxY);

                                Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY);

                                for (int fx = 0; fx <= radius; fx++)
                                {
                                    int fxr     = fx - radius;
                                    int offsetX = x + fxr;
                                    offsetX     = offsetX.Clamp(0, maxX);

                                    var vector = sourceOffsetRow[offsetX].ToVector4();

                                    float sourceRed   = vector.X;
                                    float sourceBlue  = vector.Z;
                                    float sourceGreen = vector.Y;

                                    int currentIntensity = (int)MathF.Round(
                                        (sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));

                                    intensityBin[currentIntensity]++;
                                    blueBin[currentIntensity]  += sourceBlue;
                                    greenBin[currentIntensity] += sourceGreen;
                                    redBin[currentIntensity]   += sourceRed;

                                    if (intensityBin[currentIntensity] > maxIntensity)
                                    {
                                        maxIntensity = intensityBin[currentIntensity];
                                        maxIndex     = currentIntensity;
                                    }
                                }

                                float red   = MathF.Abs(redBin[maxIndex] / maxIntensity);
                                float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
                                float blue  = MathF.Abs(blueBin[maxIndex] / maxIntensity);

                                ref TPixel pixel = ref targetRow[x];
                                pixel.FromVector4(
                                    new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                            }
                        }
                    }
                });

                Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels);
            }
        }
    /// <summary>
    /// Run a single cart-pole simulation/trial on the given black box, and with the given initial model state.
    /// </summary>
    /// <param name="box">The black box (neural net) to evaluate.</param>
    /// <param name="cartPos">Cart position on the track.</param>
    /// <param name="poleAngle">Pole angle in radians.</param>
    /// <returns>Fitness score.</returns>
    public float RunTrial(
        IBlackBox <double> box,
        float cartPos,
        float poleAngle)
    {
        // Reset black box state.
        box.Reset();

        // Reset model state.
        _physics.ResetState(cartPos, poleAngle);

        // Get a local variable ref to the internal model state array.
        float[] state = _physics.State;

        // Get the blackbox input and output spans.
        var inputs  = box.Inputs.Span;
        var outputs = box.Outputs.Span;

        // Run the cart-pole simulation.
        int timestep = 0;

        for (; timestep < _maxTimesteps; timestep++)
        {
            // Provide model state to the black box inputs (normalised to +-1.0).
            inputs[0] = 1.0;                                     // Bias input.
            inputs[1] = state[0] * __TrackLengthHalf_Reciprocal; // Cart X position range is +-__TrackLengthHalf; here we normalize to [-1,1].
            inputs[2] = state[2] * __MaxPoleAngle_Reciprocal;    // Pole angle range is +-__MaxPoleAngle radians; here we normalize to [-1,1].

            // Activate the network.
            box.Activate();

            // Read the output to determine the force to be applied to the cart by the controller.
            float force = (float)(outputs[0] - 0.5) * 2f;
            ClipForce(ref force);
            force *= __MaxForce;

            // Update model state, i.e. move the model forward by one timestep.
            _physics.Update(force);

            // Check for failure state. I.e. has the cart run off the ends of the track, or has the pole
            // angle exceeded the defined threshold.
            if (MathF.Abs(state[0]) > __TrackLengthHalf || MathF.Abs(state[2]) > __MaxPoleAngle)
            {
                break;
            }
        }

        // Fitness is given by the combination of four fitness components:
        // 1) Amount of simulation time that elapsed before the pole angle and/or cart position threshold was exceeded. Max score is 80 if the
        //    end of the trial is reached without exceeding any thresholds.
        // 2) Cart position component. Max fitness of 1.0 for a cart position of zero (i.e. the cart is in the middle of the track range);
        // 3) Pole angle component. Max fitness of 9.5 for a pole angle of 0 degrees (vertical pole).
        // 4) Pole angular velocity component. Maximum fitness 9.5 for a zero velocity.
        //
        // Therefore the maximum possible fitness is 100.0, when the pole is perfectly stationary, and the cart is in the middle of the track.
        float fitness =
            (timestep * _maxTimesteps_Reciprocal * 80f)
            + (1f - (MathF.Min(MathF.Abs(state[0]), __TrackLengthHalf) * __TrackLengthHalf_Reciprocal))
            + ((1f - (MathF.Min(MathF.Abs(state[2]), __MaxPoleAngle) * __MaxPoleAngle_Reciprocal)) * 9.5f)
            + ((1f - MathF.Min(MathF.Abs(state[3]), 1f)) * 9.5f);

        return(fitness);
    }
Пример #9
0
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            // Paint checkered background
            if (this.backBrush != null)
            {
                Point offset = this.GetDisplayPos(Vector2.Zero);
                this.backBrush.ResetTransform();
                this.backBrush.TranslateTransform(offset.X, offset.Y);
                e.Graphics.FillRectangle(this.backBrush, this.ClientRectangle);
            }

            // Draw image outline
            if (this.image != null)
            {
                Rectangle outlineRect = this.GetDisplayRect(new Rect(this.targetPixmap.Width, this.targetPixmap.Height));

                // Offset the rect, so that it won't overlap the actual image area
                outlineRect.Inflate(1, 1);

                e.Graphics.DrawRectangle(
                    Pens.Red,
                    outlineRect);
            }

            // Draw target image
            if (this.image != null)
            {
                bool isIntScaling = MathF.Abs(MathF.RoundToInt(this.scaleFactor) - this.scaleFactor) < 0.0001f;

                // Choose filtering mode depending on whether we're scaling by a full Nx factor
                e.Graphics.InterpolationMode =
                    isIntScaling ?
                    InterpolationMode.NearestNeighbor :
                    InterpolationMode.HighQualityBicubic;
                e.Graphics.PixelOffsetMode =
                    isIntScaling ?
                    PixelOffsetMode.Half :
                    PixelOffsetMode.None;

                Rectangle scrolledImageRect = this.imageRect;
                scrolledImageRect.X += this.AutoScrollPosition.X;
                scrolledImageRect.Y += this.AutoScrollPosition.Y;
                e.Graphics.DrawImage(this.image, scrolledImageRect);

                e.Graphics.InterpolationMode = InterpolationMode.Default;
                e.Graphics.PixelOffsetMode   = PixelOffsetMode.Default;
            }

            // Draw rect outlines and indices
            if (this.targetPixmap != null && this.targetPixmap.Atlas != null)
            {
                for (int i = 0; i < this.targetPixmap.Atlas.Count; i++)
                {
                    Rect      atlasRect   = this.targetPixmap.Atlas[i];
                    Rectangle displayRect = this.GetDisplayRect(atlasRect);
                    e.Graphics.DrawRectangle(
                        this.RectPen,
                        displayRect);

                    bool isHoveredOrSelected = (this.hoveredRectIndex == i || this.selectedRectIndex == i);
                    if (this.rectNumbering == PixmapNumberingStyle.All ||
                        (this.rectNumbering == PixmapNumberingStyle.Hovered && isHoveredOrSelected))
                    {
                        this.DrawRectIndex(e.Graphics, displayRect, i);
                    }
                }

                // Draw selected outline on top of all others
                if (this.selectedRectIndex != -1)
                {
                    Rect      atlasRect   = this.GetAtlasRect(this.selectedRectIndex);
                    Rectangle displayRect = this.GetDisplayRect(atlasRect);
                    e.Graphics.DrawRectangle(
                        this.SelectedRectPen,
                        displayRect);
                }
            }

            if (this.PaintContentOverlay != null)
            {
                this.PaintContentOverlay(this, e);
            }
        }
Пример #10
0
        public void Update()
        {
            UpdateReagents();

            var curTime = _gameTiming.CurTime;

            if (ForceUpdate)
            {
                ForceUpdate = false;
            }
            else if (curTime < (_lastCycle + _cycleDelay))
            {
                if (_updateSpriteAfterUpdate)
                {
                    UpdateSprite();
                }
                return;
            }

            _lastCycle = curTime;


            // Weeds like water and nutrients! They may appear even if there's not a seed planted.
            if (WaterLevel > 10 && NutritionLevel > 2 && _random.Prob(Seed == null ? 0.05f : 0.01f))
            {
                WeedLevel += 1 * HydroponicsSpeedMultiplier * WeedCoefficient;

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // There's a chance for a weed explosion to happen if weeds take over.
            // Plants that are themselves weeds (WeedTolerance > 8) are unaffected.
            if (WeedLevel >= 10 && _random.Prob(0.1f))
            {
                if (Seed == null || WeedLevel >= Seed.WeedTolerance + 2)
                {
                    WeedInvasion();
                }
            }

            // If we have no seed planted, or the plant is dead, stop processing here.
            if (Seed == null || Dead)
            {
                if (_updateSpriteAfterUpdate)
                {
                    UpdateSprite();
                }

                return;
            }

            // There's a small chance the pest population increases.
            // Can only happen when there's a live seed planted.
            if (_random.Prob(0.01f))
            {
                PestLevel += 0.5f * HydroponicsSpeedMultiplier;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Advance plant age here.
            if (SkipAging > 0)
            {
                SkipAging--;
            }
            else
            {
                if (_random.Prob(0.8f))
                {
                    Age += (int)(1 * HydroponicsSpeedMultiplier);
                }

                _updateSpriteAfterUpdate = true;
            }

            // Nutrient consumption.
            if (Seed.NutrientConsumption > 0 && NutritionLevel > 0 && _random.Prob(0.75f))
            {
                NutritionLevel -= MathF.Max(0f, Seed.NutrientConsumption * HydroponicsSpeedMultiplier);
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Water consumption.
            if (Seed.WaterConsumption > 0 && WaterLevel > 0 && _random.Prob(0.75f))
            {
                WaterLevel -= MathF.Max(0f, Seed.NutrientConsumption * HydroponicsConsumptionMultiplier * HydroponicsSpeedMultiplier);
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            var healthMod = _random.Next(1, 3) * HydroponicsSpeedMultiplier;

            // Make sure the plant is not starving.
            if (_random.Prob(0.35f))
            {
                if (NutritionLevel > 2)
                {
                    Health += healthMod;
                }
                else
                {
                    AffectGrowth(-1);
                    Health -= healthMod;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Make sure the plant is not thirsty.
            if (_random.Prob(0.35f))
            {
                if (WaterLevel > 10)
                {
                    Health += healthMod;
                }
                else
                {
                    AffectGrowth(-1);
                    Health -= healthMod;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            var tileAtmos   = Owner.Transform.Coordinates.GetTileAtmosphere();
            var environment = tileAtmos?.Air ?? GasMixture.SpaceGas;

            if (Seed.ConsumeGasses.Count > 0)
            {
                _missingGas = 0;

                foreach (var(gas, amount) in Seed.ConsumeGasses)
                {
                    if (environment.GetMoles(gas) < amount)
                    {
                        _missingGas++;
                        continue;
                    }

                    environment.AdjustMoles(gas, -amount);
                }

                if (_missingGas > 0)
                {
                    Health -= _missingGas * HydroponicsSpeedMultiplier;
                    if (DrawWarnings)
                    {
                        _updateSpriteAfterUpdate = true;
                    }
                }
            }

            // Seed pressure resistance.
            var pressure = environment.Pressure;

            if (pressure < Seed.LowPressureTolerance || pressure > Seed.HighPressureTolerance)
            {
                Health          -= healthMod;
                ImproperPressure = true;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else
            {
                ImproperPressure = false;
            }

            // Seed ideal temperature.
            if (MathF.Abs(environment.Temperature - Seed.IdealHeat) > Seed.HeatTolerance)
            {
                Health      -= healthMod;
                ImproperHeat = true;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else
            {
                ImproperHeat = false;
            }

            // Gas production.
            var exudeCount = Seed.ExudeGasses.Count;

            if (exudeCount > 0)
            {
                foreach (var(gas, amount) in Seed.ExudeGasses)
                {
                    environment.AdjustMoles(gas, MathF.Max(1f, MathF.Round((amount * MathF.Round(Seed.Potency)) / exudeCount)));
                }
            }

            // Toxin levels beyond the plant's tolerance cause damage.
            // They are, however, slowly reduced over time.
            if (Toxins > 0)
            {
                var toxinUptake = MathF.Max(1, MathF.Round(Toxins / 10f));
                if (Toxins > Seed.ToxinsTolerance)
                {
                    Health -= toxinUptake;
                }

                Toxins -= toxinUptake;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Weed levels.
            if (PestLevel > 0)
            {
                // TODO: Carnivorous plants?
                if (PestLevel > Seed.PestTolerance)
                {
                    Health -= HydroponicsSpeedMultiplier;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            // Weed levels.
            if (WeedLevel > 0)
            {
                // TODO: Parasitic plants.
                if (WeedLevel >= Seed.WeedTolerance)
                {
                    Health -= HydroponicsSpeedMultiplier;
                }

                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }

            if (Age > Seed.Lifespan)
            {
                Health -= _random.Next(3, 5) * HydroponicsSpeedMultiplier;
                if (DrawWarnings)
                {
                    _updateSpriteAfterUpdate = true;
                }
            }
            else if (Age < 0) // Revert back to seed packet!
            {
                Seed.SpawnSeedPacket(Owner.Transform.Coordinates);
                RemovePlant();
                ForceUpdate = true;
                Update();
            }

            CheckHealth();

            if (Harvest && Seed.HarvestRepeat == HarvestType.SelfHarvest)
            {
                AutoHarvest();
            }

            // If enough time has passed since the plant was harvested, we're ready to harvest again!
            if (!Dead && Seed.ProductPrototypes.Count > 0)
            {
                if (Age > Seed.Production)
                {
                    if ((Age - _lastProduce) > Seed.Production && !Harvest)
                    {
                        Harvest      = true;
                        _lastProduce = Age;
                    }
                }
                else
                {
                    if (Harvest)
                    {
                        Harvest      = false;
                        _lastProduce = Age;
                    }
                }
            }

            CheckLevelSanity();

            if (_updateSpriteAfterUpdate)
            {
                UpdateSprite();
            }
        }
Пример #11
0
 public static Vector4 Abs(Vector4 value)
 {
     return(new Vector4(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z), MathF.Abs(value.W)));
 }
Пример #12
0
 /// <summary>
 /// Get the distance between 2 vectors.
 /// </summary>
 public static float Distance(Vector from, Vector to) => MathF.Sqrt(
     MathF.Abs((to.X - from.X) * (to.X - from.X) + (to.Y - from.Y) * (to.Y - from.Y))
     );
Пример #13
0
 /// <summary>
 /// 获取均价
 /// </summary>
 /// <returns></returns>
 public float GetAvg()
 {
     return(MathF.Abs(V_OpenPrice - V_ClosePrice) / 2 + (V_OpenPrice > V_ClosePrice?V_ClosePrice:V_OpenPrice));
 }
Пример #14
0
        public bool IsMatch(Dictionary <int, KLineCache> klineDataDic, float btcLSPercent, List <int> MACycleList)
        {
            switch (type)
            {
            case MatchConditionType.MA:

                int value = (int)args1;

                if (!klineDataDic.ContainsKey(value) && value % 1440 == 0)
                {
                    int        merge = value / 1440;
                    KLineCache cache = new KLineCache();
                    cache.RefreshData(klineDataDic[1440].GetMergeKLine(merge));
                    klineDataDic[value] = cache;
                }

                if (klineDataDic.ContainsKey(value))
                {
                    KLineCache kLineCache = klineDataDic[value];

                    List <float> maList = new List <float>();

                    List <float> perList = new List <float>();

                    for (int i = 0; i < paramsList1.Count; i++)
                    {
                        int maIndex = (int)paramsList1[i];

                        float maValue = 0;

                        if (maIndex == 0)
                        {
                            maValue = kLineCache.V_KLineData[0].V_ClosePrice;
                        }
                        else
                        {
                            if (MACycleList[maIndex - 1] > kLineCache.V_KLineData.Count)
                            {
                                return(false);
                            }

                            maValue = MA.GetMA(MACycleList[maIndex - 1], kLineCache.V_KLineData);
                        }


                        maList.Add(maValue);


                        float perValue = MathF.Abs((kLineCache.V_KLineData[0].V_ClosePrice - maValue) / maValue * 100);

                        perList.Add(perValue);
                    }

                    bool match = true;
                    for (int i = 0; i < maList.Count - 1; i++)
                    {
                        float perValue = MathF.Abs((maList[i] - maList[i + 1]) / maList[i + 1] * 100);

                        if (perValue > 1 && maList[i] < maList[i + 1])
                        {
                            match = false;
                            break;
                        }
                    }

                    if (match)
                    {
                        for (int i = 0; i < paramsList2.Count; i++)
                        {
                            if (paramsList2[i] < 0)
                            {
                                if (perList[i] < MathF.Abs(paramsList2[i]))
                                {
                                    match = false;
                                    break;
                                }
                            }
                            else
                            {
                                if (perList[i] > paramsList2[i])
                                {
                                    match = false;
                                    break;
                                }
                            }
                        }
                    }

                    return(match);
                }

                break;

            case MatchConditionType.EMA:

                value = (int)args1;

                if (klineDataDic.ContainsKey(value))
                {
                    KLineCache kLineCache = klineDataDic[value];

                    List <float> maList = new List <float>();

                    List <float> perList = new List <float>();

                    for (int i = 0; i < paramsList1.Count; i++)
                    {
                        int maIndex = (int)paramsList1[i];

                        float maValue = 0;

                        if (maIndex == 0)
                        {
                            maValue = kLineCache.V_KLineData[0].V_ClosePrice;
                        }
                        else
                        {
                            if (MACycleList[maIndex - 1] > kLineCache.V_KLineData.Count)
                            {
                                return(false);
                            }
                            maValue = EMA.GetEMA(MACycleList[maIndex - 1], kLineCache.V_KLineData);
                        }

                        maList.Add(maValue);


                        float perValue = MathF.Abs((kLineCache.V_KLineData[0].V_ClosePrice - maValue) / maValue * 100);

                        perList.Add(perValue);
                    }

                    bool match = true;
                    for (int i = 0; i < maList.Count - 1; i++)
                    {
                        if (maList[i] < maList[i + 1])
                        {
                            match = false;
                            break;
                        }
                    }

                    if (match)
                    {
                        for (int i = 0; i < paramsList2.Count; i++)
                        {
                            if (paramsList2[i] < 0)
                            {
                                if (perList[i] < MathF.Abs(paramsList2[i]))
                                {
                                    match = false;
                                    break;
                                }
                            }
                            else
                            {
                                if (perList[i] > paramsList2[i])
                                {
                                    match = false;
                                    break;
                                }
                            }
                        }
                    }

                    return(match);
                }
                break;

            case MatchConditionType.BtcLSPercent:

                if (args1 < 0)
                {
                    if (btcLSPercent < MathF.Abs(args1))
                    {
                        return(false);
                    }

                    return(true);
                }
                else
                {
                    if (btcLSPercent > args1)
                    {
                        return(false);
                    }

                    return(true);
                }

                break;

            case MatchConditionType.PriceList:

                value = (int)args1;

                if (klineDataDic.ContainsKey(value))
                {
                    KLineCache kLineCache = klineDataDic[value];

                    bool match = true;

                    int count = (int)paramsList1[0];

                    if (Math.Abs(count) + 1 > kLineCache.V_KLineData.Count)
                    {
                        return(false);
                    }

                    if (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            if (kLineCache.V_KLineData[i].GetAvg() < kLineCache.V_KLineData[i + 1].GetAvg())
                            {
                                match = false;
                                break;
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < -count; i++)
                        {
                            if (kLineCache.V_KLineData[i].GetAvg() > kLineCache.V_KLineData[i + 1].GetAvg())
                            {
                                match = false;
                                break;
                            }
                        }
                    }
                    return(match);
                }
                break;

            case MatchConditionType.OldPrice:

                value = (int)args1;

                if (klineDataDic.ContainsKey(value))
                {
                    KLineCache kLineCache = klineDataDic[value];

                    bool match = false;

                    int startInedx = (int)paramsList1[0];
                    int dir        = (int)paramsList1[1];
                    int count      = Math.Abs(dir);

                    float curValue = kLineCache.V_KLineData[0].V_ClosePrice;

                    if (startInedx < kLineCache.V_KLineData.Count)
                    {
                        float p1 = kLineCache.V_KLineData[startInedx].GetAvg();
                        float p2 = kLineCache.V_KLineData[startInedx - count].GetAvg();

                        float percent = MathF.Abs((p1 - p2) / p2 * 100);

                        if (percent > 2)
                        {
                            if (dir > 0)
                            {
                                if (p1 < p2 && curValue < p1)
                                {
                                    match = true;
                                }
                            }
                            else
                            {
                                if (p1 > p2 && curValue > p1)
                                {
                                    match = true;
                                }
                            }
                        }
                    }
                    return(match);
                }
                break;

            default:
                break;
            }

            return(false);
        }
Пример #15
0
    public void method6(Span <SkelBoneState> boneStateOut, float timeChanged, float distanceChanged, float rotationChanged)
    {
        // In ToEE, boneIdx is never set to anything other than -1

        if (duration > 0)
        {
            // Decide what the effective advancement in the animation stream will be
            float effectiveAdvancement;
            switch (animation.DriveType)
            {
            case SkelAnimDriver.Time:
                effectiveAdvancement = timeChanged;
                break;

            case SkelAnimDriver.Distance:
                effectiveAdvancement = ownerAnim.scaleInv * distanceChanged;
                break;

            case SkelAnimDriver.Rotation:
                // TODO: Weirdly enough, in the other function it's using the absolute value of it
                // Does this mean that rotation-based animations will not properly trigger events???
                effectiveAdvancement = MathF.Abs(rotationChanged);
                break;

            default:
                throw new AasException($"Unknown animation drive type: {animation.DriveType}");
            }

            // Same logic as in AddTime for events, just different data fields and no event handling
            currentTime += effectiveAdvancement;
            if (currentTime > duration)
            {
                if (animation.Loopable)
                {
                    var extraTime = currentTime - duration;
                    currentTime = extraTime;
                    if (currentTime > duration)
                    {
                        if (extraTime - effectiveAdvancement == 0.0f)
                        {
                            currentTime = 0.0f;
                        }
                        else
                        {
                            currentTime = duration;
                        }
                    }
                }
                else
                {
                    currentTime = duration;
                }
            }

            // Propagate the frame index derived from the current time to all streams
            for (int i = 0; i < streamCount; i++)
            {
                var frame = streamFps[i] * currentTime;
                streams[i].SetFrame(frame);
            }
        }

        if (streamCount != 1 || ownerAnim.variationCount != 1 || weight != 1.0f)
        {
            // Get the bone data for each stream
            Span <SkelBoneState> boneData = stackalloc SkelBoneState[4 * 1024];            // 4 streams with at most 1024 bones each
            for (int i = 0; i < streamCount; i++)
            {
                streams[i].GetBoneState(boneData.Slice(i * 1024, 1024));
            }

            var boneCount = ownerAnim.skeleton.Bones.Count;
            Trace.Assert(boneCount <= 1024);

            Span <SkelBoneState> boneDataTemp = stackalloc SkelBoneState[1024];
            var boneDataBuf = boneDataTemp;
            if (weight == 1.0f)
            {
                boneDataBuf = boneStateOut;
            }

            // Copy over the first stream's bone data
            boneData.Slice(1024 * streamVariationIndices[0], boneDataBuf.Length).CopyTo(boneDataBuf);

            // LERP the rest
            for (var i = 1; i < ownerAnim.variationCount; i++)
            {
                if (streamVariationIndices[i] < 4)
                {
                    var factor = ownerAnim.variations[i].factor;
                    SkelBoneState.Lerp(boneDataBuf, boneDataBuf, boneData.Slice(1024 * streamVariationIndices[i], 1024), boneCount, factor);
                }
            }

            SkelBoneState.Lerp(boneStateOut, boneStateOut, boneDataBuf, boneCount, weight);
        }
        else
        {
            streams[0].GetBoneState(boneStateOut);
        }
    }
Пример #16
0
        internal void Update()
        {
            this.AcquireConfigObjects();

            Transform transform = this.GameObj.Transform;
            float     scaledRad = this.radius * transform.Scale;

            Agent[] otherAgents = AgentManager.Instance.FindNeighborAgents(this).ToArray();
            this.sampler.Reset();

            bool    keepSampling = true;
            Vector2 bestVelocity = Vector2.Zero;
            float   bestScore    = float.PositiveInfinity;

            while (keepSampling)
            {
                Vector2 sample = this.sampler.GetCurrentSample(this) * this.characteristics.MaxSpeed;

                // penalities
                float toiPenality = 0f;

                // check against every obstacle
                foreach (Agent otherAgent in otherAgents)
                {
                    Transform otherTransform = otherAgent.GameObj.Transform;
                    float     curToiPenality = 0f;

                    // calculate helper variables for RVO
                    Vector2 relPos = otherTransform.Pos.Xy - transform.Pos.Xy;
                    // -> calculate side (only sign is of interest) for HRVO
                    Vector2 averageVel = 0.5f * (transform.Vel.Xy + otherTransform.Vel.Xy);
                    float   side       = Vector2.Dot(relPos.PerpendicularRight, sample - averageVel);

                    float selfFactor  = 0f;
                    float otherFactor = 1f;
                    if (side >= 0f)
                    {
                        // this is different from original RVO - we use the ratio of the observed velocities to determine
                        // how much responsibility one agent has
                        float selfSpeed  = transform.Vel.Xy.Length;
                        float otherSpeed = otherTransform.Vel.Xy.Length;

                        selfFactor = 0.5f;
                        var selfPlusOtherSpeed = selfSpeed + otherSpeed;
                        if (selfPlusOtherSpeed > float.Epsilon)
                        {
                            selfFactor = otherSpeed / selfPlusOtherSpeed;
                        }
                        otherFactor = 1f - selfFactor;
                    }

                    // check time of impact
                    float   curMinToi;
                    float   curMaxToi;
                    Vector2 expectedRelVel = sample - (selfFactor * transform.Vel.Xy + otherFactor * otherTransform.Vel.Xy);
                    float   otherScaledRad = otherAgent.radius * otherTransform.Scale;
                    if (ToiCircleCircle(relPos, scaledRad + otherScaledRad, expectedRelVel, out curMinToi, out curMaxToi) && 0f < curMaxToi)
                    {
                        if (curMinToi <= 0f)
                        {
                            // we collided - check which way we get here out
                            if (MathF.Abs(curMinToi) < MathF.Abs(curMaxToi))
                            {
                                // => if minT (which is behind us) is lower then it's a bad idea to keep going because the
                                // other way would bring us out earlier
                                curToiPenality = float.PositiveInfinity;
                            }
                            else
                            {
                                curToiPenality = curMaxToi;
                            }
                        }
                        else
                        {
                            // this is a new minimum toi
                            // => calculate penality
                            curToiPenality = MathF.Max(0f, this.toiHorizon - curMinToi) / this.toiHorizon;
                        }
                    }
                    toiPenality = MathF.Max(toiPenality, curToiPenality);
                }

                // ask the characteristics implementation how good this sample is
                float score = characteristics.CalculateVelocityCost(this, sample, toiPenality);

                // update sampler and check if we should stop
                keepSampling = sampler.SetCurrentCost(score);

                // check if this velocity is better then everything else we've seen so far
                if (score < bestScore)
                {
                    bestScore    = score;
                    bestVelocity = sample;
                }

                #region visual logging of all sampled velocities
#if DEBUG
                if (DebugVisualizationMode != VisualLoggingMode.None &&
                    DebugVisualizationMode != VisualLoggingMode.VelocityOnly &&
                    DebugVisualizationMode != VisualLoggingMode.AllVelocities)
                {
                    Vector2 debugPos         = sample / this.characteristics.MaxSpeed * DebugVelocityRadius;
                    float   debugColorFactor = 0.0f;
                    switch (DebugVisualizationMode)
                    {
                    case VisualLoggingMode.Cost:
                        debugColorFactor = score;
                        break;

                    case VisualLoggingMode.ToiPenalty:
                        debugColorFactor = toiPenality;
                        break;
                    }
                    ColorRgba debugColor = ColorRgba.Lerp(ColorRgba.White, ColorRgba.Black, MathF.Pow(debugColorFactor, 1f / 4f));
                    VisualDebugLog.DrawCircle(debugPos.X, debugPos.Y, 4f).AnchorAt(this.GameObj).WithColor(debugColor);
                }
#endif
                #endregion
            }

            this.suggestedVel = bestVelocity;

            #region visual logging of the velocities
#if DEBUG
            if (DebugVisualizationMode == VisualLoggingMode.AllVelocities)
            {
                Vector2 selfDebugVelocity = transform.Vel.Xy / Characteristics.MaxSpeed * DebugVelocityRadius;
                VisualDebugLog.DrawVector(0f, 0f, selfDebugVelocity.X, selfDebugVelocity.Y).AnchorAt(GameObj).WithColor(ColorRgba.DarkGrey);

                foreach (var otherAgent in otherAgents)
                {
                    Transform otherTransform = otherAgent.GameObj.Transform;
                    Vector2   debugVelocity  = otherTransform.Vel.Xy / otherAgent.Characteristics.MaxSpeed * DebugVelocityRadius;
                    VisualDebugLog.DrawVector(0f, 0f, debugVelocity.X, debugVelocity.Y).AnchorAt(otherAgent.GameObj).WithColor(ColorRgba.DarkGrey);
                }
            }
            if (DebugVisualizationMode != VisualLoggingMode.None)
            {
                Vector2 curVelocity = transform.Vel.Xy / Characteristics.MaxSpeed * DebugVelocityRadius;
                VisualDebugLog.DrawVector(0f, 0f, curVelocity.X, curVelocity.Y).AnchorAt(GameObj).WithColor(ColorRgba.DarkGrey);

                var debugVelocity = this.suggestedVel / characteristics.MaxSpeed * DebugVelocityRadius;
                VisualDebugLog.DrawVector(0f, 0f, debugVelocity.X, debugVelocity.Y).AnchorAt(this.GameObj);
            }
#endif
            #endregion
        }
Пример #17
0
        public bool filter(CombatUnit unit)
        {
            switch (rangeType)
            {
            case RangeType.none:
                return(MathF.Abs(unit.position - pivotPos) <= maxDistance && minDistance <= MathF.Abs(unit.position - pivotPos));

            case RangeType.lefthand:
                return((pivotPos - unit.position) <= maxDistance && minDistance <= (pivotPos - unit.position));

            case RangeType.righthand:
                return(-(pivotPos - unit.position) <= maxDistance && minDistance <= -(pivotPos - unit.position));
            }
            return(MathF.Abs(unit.position - pivotPos) <= maxDistance && minDistance <= MathF.Abs(unit.position - pivotPos));
        }
        protected internal override void OnCollectDrawcalls(Canvas canvas)
        {
            base.OnCollectDrawcalls(canvas);
            List <RigidBody> visibleColliders = this.QueryVisibleColliders().ToList();

            this.RetrieveResources();
            RigidBody selectedBody = this.QuerySelectedCollider();

            canvas.State.TextFont           = Font.GenericMonospace10;
            canvas.State.TextInvariantScale = true;
            canvas.State.ZOffset            = -1;
            Font textFont = canvas.State.TextFont.Res;

            // Draw Shape layer
            foreach (RigidBody c in visibleColliders)
            {
                if (!c.Shapes.Any())
                {
                    continue;
                }
                float   colliderAlpha = c == selectedBody ? 1.0f : (selectedBody != null ? 0.25f : 0.5f);
                float   maxDensity    = c.Shapes.Max(s => s.Density);
                float   minDensity    = c.Shapes.Min(s => s.Density);
                float   avgDensity    = (maxDensity + minDensity) * 0.5f;
                Vector3 colliderPos   = c.GameObj.Transform.Pos;
                float   colliderScale = c.GameObj.Transform.Scale;
                int     index         = 0;
                foreach (ShapeInfo s in c.Shapes)
                {
                    CircleShapeInfo circle = s as CircleShapeInfo;
                    PolyShapeInfo   poly   = s as PolyShapeInfo;
                    //	EdgeShapeInfo edge = s as EdgeShapeInfo;
                    LoopShapeInfo loop = s as LoopShapeInfo;

                    float     shapeAlpha      = colliderAlpha * (selectedBody == null || this.View.ActiveState.SelectedObjects.Any(sel => sel.ActualObject == s) ? 1.0f : 0.5f);
                    float     densityRelative = MathF.Abs(maxDensity - minDensity) < 0.01f ? 1.0f : s.Density / avgDensity;
                    ColorRgba clr             = s.IsSensor ? this.ShapeSensorColor : this.ShapeColor;
                    ColorRgba fontClr         = this.FgColor;
                    Vector2   center          = Vector2.Zero;

                    if (!c.IsAwake)
                    {
                        clr = clr.ToHsva().WithSaturation(0.0f).ToRgba();
                    }
                    if (!s.IsValid)
                    {
                        clr = this.ShapeErrorColor;
                    }

                    if (circle != null)
                    {
                        Vector2 circlePos = circle.Position * colliderScale;
                        MathF.TransformCoord(ref circlePos.X, ref circlePos.Y, c.GameObj.Transform.Angle);

                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha)));
                        canvas.FillCircle(
                            colliderPos.X + circlePos.X,
                            colliderPos.Y + circlePos.Y,
                            colliderPos.Z,
                            circle.Radius * colliderScale);
                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha)));
                        canvas.DrawCircle(
                            colliderPos.X + circlePos.X,
                            colliderPos.Y + circlePos.Y,
                            colliderPos.Z,
                            circle.Radius * colliderScale);

                        center = circlePos;
                    }
                    else if (poly != null)
                    {
                        Vector2[] polyVert = poly.Vertices.ToArray();
                        for (int i = 0; i < polyVert.Length; i++)
                        {
                            center += polyVert[i];
                            Vector2.Multiply(ref polyVert[i], colliderScale, out polyVert[i]);
                            MathF.TransformCoord(ref polyVert[i].X, ref polyVert[i].Y, c.GameObj.Transform.Angle);
                        }
                        center /= polyVert.Length;
                        Vector2.Multiply(ref center, colliderScale, out center);
                        MathF.TransformCoord(ref center.X, ref center.Y, c.GameObj.Transform.Angle);

                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha)));
                        canvas.FillPolygon(polyVert, colliderPos.X, colliderPos.Y, colliderPos.Z);
                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha)));
                        canvas.DrawPolygon(polyVert, colliderPos.X, colliderPos.Y, colliderPos.Z);
                    }
                    else if (loop != null)
                    {
                        Vector2[] loopVert = loop.Vertices.ToArray();
                        for (int i = 0; i < loopVert.Length; i++)
                        {
                            center += loopVert[i];
                            Vector2.Multiply(ref loopVert[i], colliderScale, out loopVert[i]);
                            MathF.TransformCoord(ref loopVert[i].X, ref loopVert[i].Y, c.GameObj.Transform.Angle);
                        }
                        center /= loopVert.Length;
                        Vector2.Multiply(ref center, colliderScale, out center);
                        MathF.TransformCoord(ref center.X, ref center.Y, c.GameObj.Transform.Angle);

                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha)));
                        canvas.DrawPolygon(loopVert, colliderPos.X, colliderPos.Y, colliderPos.Z);
                    }

                    // Draw shape index
                    if (c == selectedBody)
                    {
                        Vector2 textSize = textFont.MeasureText(index.ToString(CultureInfo.InvariantCulture));
                        canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, fontClr.WithAlpha((shapeAlpha + 1.0f) * 0.5f)));
                        canvas.State.TransformHandle = textSize * 0.5f;
                        canvas.DrawText(index.ToString(CultureInfo.InvariantCulture),
                                        colliderPos.X + center.X,
                                        colliderPos.Y + center.Y,
                                        colliderPos.Z);
                        canvas.State.TransformHandle = Vector2.Zero;
                    }

                    index++;
                }

                // Draw center of mass
                if (c.BodyType == BodyType.Dynamic)
                {
                    Vector2 localMassCenter = c.LocalMassCenter;
                    MathF.TransformCoord(ref localMassCenter.X, ref localMassCenter.Y, c.GameObj.Transform.Angle, c.GameObj.Transform.Scale);
                    canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, this.MassCenterColor.WithAlpha(colliderAlpha)));
                    canvas.DrawLine(
                        colliderPos.X + localMassCenter.X - 5.0f,
                        colliderPos.Y + localMassCenter.Y,
                        colliderPos.Z,
                        colliderPos.X + localMassCenter.X + 5.0f,
                        colliderPos.Y + localMassCenter.Y,
                        colliderPos.Z);
                    canvas.DrawLine(
                        colliderPos.X + localMassCenter.X,
                        colliderPos.Y + localMassCenter.Y - 5.0f,
                        colliderPos.Z,
                        colliderPos.X + localMassCenter.X,
                        colliderPos.Y + localMassCenter.Y + 5.0f,
                        colliderPos.Z);
                }
            }
        }
Пример #19
0
 public override Color At(Vector4 point) =>
 MathF.Abs((MathF.Floor(point.X) + MathF.Floor(point.Y) + MathF.Floor(point.Z)) % 2) <= Constants.EpsilonLow ? A : B;
Пример #20
0
        protected override void UpdateBase(Color3 gridColor, float alpha, int gridAxisIndex, float sceneUnit)
        {
            var cameraService = Game.EditorServices.Get <IEditorGameCameraService>();

            if (cameraService == null)
            {
                return;
            }

            // update the grid color
            GridMaterial.Passes[0].Parameters.Set(GridColorKey, Color4.PremultiplyAlpha(new Color4(gridColor, alpha)));

            // Determine the up vector depending on view matrix and projection mode
            // -> When orthographic, if we are looking along a coordinate axis, place the grid perpendicular to that axis.
            // -> Place the grid perpendicular to its default axis otherwise.
            var viewAxisIndex = gridAxisIndex;
            var upVector      = new Vector3(0)
            {
                [gridAxisIndex] = 1
            };
            var viewInvert = Matrix.Invert(cameraService.ViewMatrix);

            if (cameraService.IsOrthographic)
            {
                for (var i = 0; i < 3; i++)
                {
                    var coordinateAxis = new Vector3 {
                        [i] = 1.0f
                    };
                    var dotProduct = Vector3.Dot(viewInvert.Forward, coordinateAxis);

                    if (MathF.Abs(dotProduct) > 0.99f)
                    {
                        upVector      = coordinateAxis;
                        viewAxisIndex = i;
                    }
                }
            }

            // Check if the inverted View Matrix is valid (since it will be use for mouse picking, check the translation vector only)
            if (float.IsNaN(viewInvert.TranslationVector.X) ||
                float.IsNaN(viewInvert.TranslationVector.Y) ||
                float.IsNaN(viewInvert.TranslationVector.Z))
            {
                return;
            }

            // The position of the grid and the origin in the scene
            var snappedPosition = Vector3.Zero;
            var originPosition  = Vector3.Zero;

            // Add a small offset along the Up axis to avoid depth-fight with objects positioned at height=0
            snappedPosition[viewAxisIndex] = MathF.Sign(viewInvert[3, viewAxisIndex]) * GridVerticalOffset * sceneUnit;

            // Move the grid origin in slightly in front the grid to have it in the foreground
            originPosition[viewAxisIndex] = snappedPosition[viewAxisIndex] + MathF.Sign(viewInvert[3, viewAxisIndex]) * 0.001f * sceneUnit;

            // Determine the intersection point of the center of the vieport with the grid plane
            var ray          = EditorGameHelper.CalculateRayFromMousePosition(cameraService.Component, new Vector2(0.5f), viewInvert);
            var plane        = new Plane(Vector3.Zero, upVector);
            var intersection = EditorGameHelper.ProjectOnPlaneWithLimitAngle(ray, plane, MaximumViewAngle);

            // Detemine the scale of the grid depending of the distance of the camera to the grid plane
            // For orthographic projections, use a distance close to the one, at which the perspective projection would map to the viewport area.
            var gridScale      = sceneUnit;
            var distanceToGrid = cameraService.IsOrthographic ? cameraService.Component.OrthographicSize * 1.5f : (viewInvert.TranslationVector - intersection).Length();

            if (distanceToGrid < 1.5f * sceneUnit)
            {
                gridScale = 0.1f * sceneUnit;
            }
            if (distanceToGrid > 40f * sceneUnit)
            {
                gridScale = 10f * sceneUnit;
            }
            if (distanceToGrid > 400f * sceneUnit)
            {
                gridScale = 100f * sceneUnit;
            }

            // Snap the grid the closest possible to the intersection point
            var gridStringLineUnit = gridScale;

            for (var i = 0; i < 3; i++)
            {
                if (viewAxisIndex != i)
                {
                    snappedPosition[i] += MathF.Round(intersection[i] / gridStringLineUnit) * gridStringLineUnit;
                }
            }

            // Apply positions
            grid.Transform.Position            = snappedPosition;
            originAxis.TransformValue.Position = originPosition;
            for (int axis = 0; axis < 3; axis++)
            {
                originAxes[axis].TransformValue.Position[axis] = snappedPosition[axis];
            }

            // Apply the scale (Note: scale cannot be applied at root or sub-position is scaled too)
            grid.Transform.Scale = new Vector3(gridScale);
            for (int axis = 0; axis < 3; axis++)
            {
                originAxes[axis].TransformValue.Scale = new Vector3(gridScale);
            }

            // Determine and apply the rotation to the grid and origin axis entities
            SetPlaneEntityRotation(2, upVector, grid);
            for (var axis = 0; axis < 3; axis++)
            {
                SetPlaneEntityRotation((axis + 2) % 3, upVector, originAxes[axis]);
            }

            // Update the color of the origin axes and hide the grid axis
            for (int axis = 0; axis < 3; axis++)
            {
                // Make the axes alpha higher than the grid alpha so they are visible
                float axesAlpha = alpha * 4;
                var   color     = Color4.PremultiplyAlpha(new Color4(GetAxisDefaultColor(axis), axesAlpha));
                originAxes[axis].GetChild(0).Get <ModelComponent>().GetMaterial(0).Passes[0].Parameters.Set(GridColorKey, color);

                originAxes[axis].GetChild(0).Get <ModelComponent>().Enabled = axis != viewAxisIndex;
            }
        }
Пример #21
0
        /// <summary>
        /// Updates host viewport transform and clipping state based on current GPU state.
        /// </summary>
        /// <param name="state">Current GPU state</param>
        private void UpdateViewportTransform(GpuState state)
        {
            DepthMode depthMode = state.Get <DepthMode>(MethodOffset.DepthMode);

            _context.Renderer.Pipeline.SetDepthMode(depthMode);

            YControl yControl = state.Get <YControl>(MethodOffset.YControl);

            bool   flipY  = yControl.HasFlag(YControl.NegateY);
            Origin origin = yControl.HasFlag(YControl.TriangleRastFlip) ? Origin.LowerLeft : Origin.UpperLeft;

            _context.Renderer.Pipeline.SetOrigin(origin);

            // The triangle rast flip flag only affects rasterization, the viewport is not flipped.
            // Setting the origin mode to upper left on the host, however, not only affects rasterization,
            // but also flips the viewport.
            // We negate the effects of flipping the viewport by flipping it again using the viewport swizzle.
            if (origin == Origin.UpperLeft)
            {
                flipY = !flipY;
            }

            Span <Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];

            for (int index = 0; index < Constants.TotalViewports; index++)
            {
                var transform = state.Get <ViewportTransform>(MethodOffset.ViewportTransform, index);
                var extents   = state.Get <ViewportExtents>  (MethodOffset.ViewportExtents, index);

                float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
                float y = transform.TranslateY - MathF.Abs(transform.ScaleY);

                float width  = MathF.Abs(transform.ScaleX) * 2;
                float height = MathF.Abs(transform.ScaleY) * 2;

                float scale = TextureManager.RenderTargetScale;
                if (scale != 1f)
                {
                    x      *= scale;
                    y      *= scale;
                    width  *= scale;
                    height *= scale;
                }

                RectangleF region = new RectangleF(x, y, width, height);

                ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
                ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
                ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
                ViewportSwizzle swizzleW = transform.UnpackSwizzleW();

                if (transform.ScaleX < 0)
                {
                    swizzleX ^= ViewportSwizzle.NegativeFlag;
                }

                if (flipY)
                {
                    swizzleY ^= ViewportSwizzle.NegativeFlag;
                }

                if (transform.ScaleY < 0)
                {
                    swizzleY ^= ViewportSwizzle.NegativeFlag;
                }

                if (transform.ScaleZ < 0)
                {
                    swizzleZ ^= ViewportSwizzle.NegativeFlag;
                }

                viewports[index] = new Viewport(
                    region,
                    swizzleX,
                    swizzleY,
                    swizzleZ,
                    swizzleW,
                    extents.DepthNear,
                    extents.DepthFar);
            }

            _context.Renderer.Pipeline.SetViewports(0, viewports);
        }
Пример #22
0
        internal string GetInfo(MainPage.PolygonUnit polygonUnitValue)
        {
            if (CurrentIndex.IsValid())
            {
                var m_path = Paths[CurrentIndex.BlockIndex];
                if (polygonUnitValue == PolygonUnit.Symmetry)
                {
                    if (CurrentIndex.BlockIndex == Paths.Count - 1)
                    {
                        Vector2 start = m_path[0].GetPoint();
                        Vector2 end   = m_path[1].GetPoint();

                        var v1 = end - start;
                        var a1 = MathF.Atan2(v1.Y, v1.X);


                        string text = string.Format("始点({0:0.00},{1:0.00}) 終点({2:0.00},{3:0.00}) 角度({4:0.0}) ", start.X, start.Y, end.X, end.Y, CmUtils.ToAngle(a1));


                        return(text);
                    }
                    else
                    {
                        Vector2 start = new Vector2();
                        Vector2 end   = new Vector2();
                        var     item  = m_path[CurrentIndex.ItemIndex];
                        var     p     = item.GetPoint(CurrentIndex.PartIndex);
                        if (RulerEnabled)
                        {
                            var ruler = Paths[Paths.Count - 1];
                            start = ruler[0].GetPoint();
                            end   = ruler[1].GetPoint();
                        }
                        else
                        {
                            CalcReferenceLine(ref start, ref end);
                        }

                        /*
                         *
                         */

                        var v1 = end - start;
                        var a1 = MathF.Atan2(v1.Y, v1.X);
                        var v2 = p - start;
                        var a2 = MathF.Atan2(v2.Y, v2.X);
                        var l  = MathF.Abs(MathF.Sin(a2 - a1) * MathF.Sqrt(MathF.Pow(v2.X, 2) + MathF.Pow(v2.Y, 2)));
                        var l2 = MathF.Cos(a2 - a1) * MathF.Sqrt(MathF.Pow(v2.X, 2) + MathF.Pow(v2.Y, 2));


                        string text = string.Format("基準から:{1:0.0} 中心線から:{0:0.0} $$  ", l, l2);

                        string info = item.GetInfo(CurrentIndex.PartIndex, true);
                        return(text + info);
                    }
                }
                else if (polygonUnitValue == PolygonUnit.RulerOrigin)
                {
                    if (RulerVisible)
                    {
                        var ruler = Paths[Paths.Count - 1];
                        var v     = ruler[0].GetPoint();

                        var    item = m_path[CurrentIndex.ItemIndex];
                        string info = item.GetInfo(CurrentIndex.PartIndex, true);


                        string text = string.Format("原点:{0:0.0} {1:0.0}", v.X, v.Y);

                        var   p   = item.GetPoint();
                        var   ofy = p.Y - v.Y;
                        var   ofx = p.X - v.X;
                        float r   = MathF.Sqrt(MathF.Pow(ofx, 2) + MathF.Pow(ofy, 2));

                        var a = MathF.Atan2(ofy, ofx);

                        text += string.Format(" 半径 {0:0.00} 角度 {1:0.00}", r, ToAngle(a));


                        return(text + info);
                    }
                }
                else if (polygonUnitValue != MainPage.PolygonUnit.none)
                {
                    int unit  = (int)polygonUnitValue;
                    var count = m_path.Count - 1;
                    if (IsSameLast(m_path))
                    {
                        count--;
                    }
                    if (count >= unit * 2 && count % 2 == 0)
                    {
                        var    PolygonCenter = CalcCenter(m_path);
                        string text          = string.Format("中心:{0:0.0} {1:0.0}", PolygonCenter.X, PolygonCenter.Y);
                        var    index         = CurrentIndex.ItemIndex;//
                        if (index >= 0)
                        {
                            var   item = m_path[index];
                            var   p    = item.GetPoint();
                            var   v    = PolygonCenter;
                            var   ofy  = p.Y - v.Y;
                            var   ofx  = p.X - v.X;
                            float r    = MathF.Sqrt(MathF.Pow(ofx, 2) + MathF.Pow(ofy, 2));

                            var a = MathF.Atan2(ofy, ofx);

                            text += string.Format(" 半径 {0:0.00} 角度 {1:0.00}", r, ToAngle(a));


                            var    partIndex = CurrentIndex.PartIndex; //
                            string info      = item.GetInfo(partIndex, true);
                            text += info;
                        }
                        return(text);
                    }
                }
                {
                    var index     = CurrentIndex.ItemIndex; //
                    var partIndex = CurrentIndex.PartIndex; //
                    if (index >= 0)
                    {
                        var    item = m_path[index];
                        string info = item.GetInfo(partIndex);

                        return(info);
                    }
                }
            }
            return("選択されていません");
        }
Пример #23
0
 public static bool AreRoughlyTheSame(float a, float b, float threshold = float.Epsilon)
 {
     return(MathF.Abs(a - b) < threshold);
 }
Пример #24
0
 public static Vector3 Abs(Vector3 value)
 {
     return(new Vector3(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z)));
 }
Пример #25
0
        /// <summary>
        /// Pre calculations for flat microscale terrain
        /// </summary>
        public static void Calculate()
        {
            Console.WriteLine();
            Console.WriteLine("FLOW FIELD COMPUTATION WITHOUT TOPOGRAPHY");

            Program.KADVMAX         = 1;
            Program.SubDomainRefPos = new IntPoint(1, 1);
            int inumm = Program.MetProfileNumb;

            //set wind-speed components equal to zero
            Parallel.For(1, Program.NII + 2, Program.pOptions, i =>
            {
                for (int j = 1; j <= Program.NJJ + 1; j++)
                {
                    float[] UK_L = Program.UK[i][j];
                    float[] VK_L = Program.VK[i][j];
                    float[] WK_L = Program.WK[i][j];
                    for (int k = 1; k <= Program.NKK; k++)
                    {
                        UK_L[k] = 0;
                        VK_L[k] = 0;
                        WK_L[k] = 0;
                    }
                }
            });

            //Set initial wind components of the GRAL wind field
            object obj = new object();

            //Parallel.For(1, Program.NII + 1, Program.pOptions, i =>
            Parallel.ForEach(Partitioner.Create(1, Program.NII + 1, Math.Max(4, (int)(Program.NII / Program.pOptions.MaxDegreeOfParallelism))), range =>
            {
                int KADVMAX1 = 1;

                for (int i = range.Item1; i < range.Item2; i++)
                {
                    for (int j = 1; j <= Program.NJJ; j++)
                    {
                        Program.AHK[i][j]   = 0;
                        Program.KKART[i][j] = 0;

                        //Pointers (to speed up the computations)
                        float[] UK_L  = Program.UK[i][j];
                        float[] VK_L  = Program.VK[i][j];
                        float[] UKi_L = Program.UK[i + 1][j];
                        float[] VKj_L = Program.VK[i][j + 1];
                        double UXint;
                        double UYint;
                        float vertk;
                        float exponent;
                        float dumfac;
                        float ObLength = Program.Ob[1][1];
                        if (Program.AdaptiveRoughnessMax > 0)
                        {
                            ObLength = Program.OLGral[i][j];
                        }

                        for (int k = Program.NKK; k >= 1; k--)
                        {
                            vertk = Program.HOKART[k - 1] + Program.DZK[k] * 0.5F;
                            if (vertk > Program.CUTK[i][j])
                            {
                                //interpolation between observations
                                if (vertk <= Program.MeasurementHeight[1])
                                {
                                    if (ObLength <= 0)
                                    {
                                        exponent = MathF.Max(0.35F - 0.4F * MathF.Pow(MathF.Abs(ObLength), -0.15F), 0.05F);
                                    }
                                    else
                                    {
                                        exponent = 0.56F * MathF.Pow(ObLength, -0.15F);
                                    }

                                    dumfac = MathF.Pow(vertk / Program.MeasurementHeight[1], exponent);
                                    UXint  = Program.ObsWindU[1] * dumfac;
                                    UYint  = Program.ObsWindV[1] * dumfac;
                                }
                                else if (vertk > Program.MeasurementHeight[inumm])
                                {
                                    if (inumm == 1)
                                    {
                                        if (ObLength <= 0)
                                        {
                                            exponent = MathF.Max(0.35F - 0.4F * MathF.Pow(MathF.Abs(ObLength), -0.15F), 0.05F);
                                        }
                                        else
                                        {
                                            exponent = 0.56F * MathF.Pow(ObLength, -0.15F);
                                        }

                                        dumfac = MathF.Pow(vertk / Program.MeasurementHeight[inumm], exponent);
                                        UXint  = Program.ObsWindU[inumm] * dumfac;
                                        UYint  = Program.ObsWindV[inumm] * dumfac;
                                    }
                                    else
                                    {
                                        UXint = Program.ObsWindU[inumm];
                                        UYint = Program.ObsWindV[inumm];
                                    }
                                }
                                else
                                {
                                    int ipo = 1;
                                    for (int iprof = 1; iprof <= inumm; iprof++)
                                    {
                                        if (vertk > Program.MeasurementHeight[iprof])
                                        {
                                            ipo = iprof + 1;
                                        }
                                    }
                                    UXint = Program.ObsWindU[ipo - 1] + (Program.ObsWindU[ipo] - Program.ObsWindU[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) *
                                            (vertk - Program.MeasurementHeight[ipo - 1]);
                                    UYint = Program.ObsWindV[ipo - 1] + (Program.ObsWindV[ipo] - Program.ObsWindV[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) *
                                            (vertk - Program.MeasurementHeight[ipo - 1]);
                                }

                                //finally get wind speeds outside obstacles
                                UK_L[k] = (float)UXint;
                                VK_L[k] = (float)UYint;
                                if (i > 1)
                                {
                                    if (vertk <= Program.CUTK[i - 1][j])
                                    {
                                        UK_L[k] = 0;
                                    }
                                }
                                if (j > 1)
                                {
                                    if (vertk <= Program.CUTK[i][j - 1])
                                    {
                                        VK_L[k] = 0;
                                    }
                                }
                                Program.UK[Program.NII + 1][j][k] = Program.UK[Program.NII][j][k];
                                Program.VK[i][Program.NJJ + 1][k] = Program.VK[i][Program.NJJ][k];
                            }
                            else
                            {
                                //set wind speed zero inside obstacles
                                UK_L[k] = 0;
                                if (i < Program.NII)
                                {
                                    UKi_L[k] = 0;
                                }

                                VK_L[k] = 0;
                                if (j < Program.NJJ)
                                {
                                    VKj_L[k] = 0;
                                }

                                Program.AHK[i][j]        = Math.Max(Program.HOKART[k], Program.AHK[i][j]);
                                Program.BUI_HEIGHT[i][j] = Program.AHK[i][j];
                                Program.KKART[i][j]      = Convert.ToInt16(Math.Max(k, Program.KKART[i][j]));
                                if (Program.CUTK[i][j] > 0)
                                {
                                    KADVMAX1 = Math.Max(Program.KKART[i][j], KADVMAX1);
                                }
                            }
                        }
                    }
                }
                if (KADVMAX1 > Program.KADVMAX)
                {
                    lock (obj) { Program.KADVMAX = Math.Max(Program.KADVMAX, KADVMAX1); }
                }
            });
            obj = null;

            //maximum z-index up to which the microscale flow field is being computed
            Program.KADVMAX = Math.Min(Program.NKK, Program.KADVMAX + Program.VertCellsFF);

            Program.AHMIN = 0;

            //in case of the diagnostic approach, a boundary layer is established near the obstacle's walls
            if (Program.FlowFieldLevel <= 1)
            {
                Parallel.For((1 + Program.IGEB), (Program.NII - Program.IGEB + 1), Program.pOptions, i =>
                {
                    for (int j = 1 + Program.IGEB; j <= Program.NJJ - Program.IGEB; j++)
                    {
                        double entf = 0;
                        double vertk;
                        double abmind;
                        for (int k = 1; k < Program.NKK; k++)
                        {
                            abmind = 1;
                            vertk  = Program.HOKART[k - 1] + Program.DZK[k] * 0.5;

                            //search towards west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((i - ig) * Program.DXK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((i - ig) * Program.DXK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south for obstacles
                            for (int jg = j - Program.IGEB; jg < j; jg++)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((j - jg) * Program.DYK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north for obstacles
                            for (int jg = j + Program.IGEB; jg >= j + 1; jg--)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((j - jg) * Program.DYK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north/east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                int jg = j + ig - i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south/west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                int jg = j + ig - i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south/east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                int jg = j - ig + i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north/west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                int jg = j - ig + i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            Program.UK[i][j][k] *= (float)abmind;
                            Program.VK[i][j][k] *= (float)abmind;
                        }
                    }
                });
            }

            //computing flow field either with diagnostic or prognostic approach
            if (Program.FlowFieldLevel > 0)
            {
                //diagnostic approach
                if (Program.FlowFieldLevel == 1)
                {
                    Console.WriteLine("DIAGNOSTIC WIND FIELD AROUND OBSTACLES");
                    DiagnosticFlowfield.Calculate();
                }

                //prognostic approach
                if (Program.FlowFieldLevel == 2)
                {
                    //read vegetation only one times
                    if (Program.VEG[0][0][0] < 0)
                    {
                        ProgramReaders Readclass = new ProgramReaders();
                        Readclass.ReadVegetationDomain(null);
                        Readclass.ReadVegetation();
                    }

                    Console.WriteLine("PROGNOSTIC WIND FIELD AROUND OBSTACLES");
                    PrognosticFlowfield.Calculate();
                }

                //Final mass conservation using poisson equation for pressure after advection has been computed with level 2
                if (Program.FlowFieldLevel == 2)
                {
                    DiagnosticFlowfield.Calculate();
                }
            }

            //in diagnostic mode mass-conservation is finally achieved by adjusting the vertical velocity in each cell
            if (Program.FlowFieldLevel < 2)
            {
                Parallel.For(2, Program.NII, Program.pOptions, i =>
                {
                    for (int j = 2; j < Program.NJJ; j++)
                    {
                        //Pointers (to speed up the computations)
                        float[] UK_L  = Program.UK[i][j];
                        float[] UKi_L = Program.UK[i + 1][j];
                        float[] VK_L  = Program.VK[i][j];
                        float[] VKj_L = Program.VK[i][j + 1];
                        float[] WK_L  = Program.WK[i][j];
                        double fwo1   = 0;
                        double fwo2   = 0;
                        double fsn1   = 0;
                        double fsn2   = 0;
                        double fbt1   = 0;
                        int KKART     = Program.KKART[i][j];

                        for (int k = 1; k < Program.NKK; k++)
                        {
                            if (k > KKART)
                            {
                                if (k <= Program.KKART[i - 1][j])
                                {
                                    fwo1 = 0;
                                }
                                else
                                {
                                    fwo1 = Program.DZK[k] * Program.DYK * UK_L[k];
                                }

                                if (k <= Program.KKART[i + 1][j])
                                {
                                    fwo2 = 0;
                                }
                                else
                                {
                                    fwo2 = Program.DZK[k] * Program.DYK * UKi_L[k];
                                }

                                if (k <= Program.KKART[i][j - 1])
                                {
                                    fsn1 = 0;
                                }
                                else
                                {
                                    fsn1 = Program.DZK[k] * Program.DXK * VK_L[k];
                                }

                                if (k <= Program.KKART[i][j + 1])
                                {
                                    fsn2 = 0;
                                }
                                else
                                {
                                    fsn2 = Program.DZK[k] * Program.DXK * VKj_L[k];
                                }

                                if ((k <= KKART + 1) || (k == 1))
                                {
                                    fbt1 = 0;
                                }
                                else
                                {
                                    fbt1 = Program.DXK * Program.DYK * WK_L[k];
                                }

                                WK_L[k + 1] = (float)((fwo1 - fwo2 + fsn1 - fsn2 + fbt1) / (Program.DXK * Program.DYK));
                            }
                        }
                    }
                });
            }
        }
Пример #26
0
        protected override unsafe int ProcessBlock(float *input, float *output, int count, int outputCount, out int inputIndex)
        {
            inputIndex = 0;
            int outputIndex = 0;
            int consumable  = count - 8;

            //Loop through until we run out of space for something
            while (outputIndex < outputCount && inputIndex < consumable)
            {
                //Produce output
                output[outputIndex] = Interpolate(&input[inputIndex], mu);
                float mm_val = Binaryify(lastSample) * output[outputIndex] - Binaryify(output[outputIndex]) * lastSample;
                lastSample = output[outputIndex];

                //Calculate error
                omega = omega + gainOmega * mm_val;
                omega = omegaMid + (0.5f * (MathF.Abs((omega - omegaMid) + omegaLim) - MathF.Abs((omega - omegaMid) - omegaLim)));
                mu    = mu + omega + gainMu * mm_val;

                //Offset by error
                inputIndex += (int)MathF.Floor(mu);
                mu          = mu - MathF.Floor(mu);
                outputIndex++;
            }
            return(outputIndex);
        }
Пример #27
0
        private static (Size, Rectangle) CalculatePadRectangle(
            Size source,
            ResizeOptions options,
            int width,
            int height)
        {
            if (width <= 0 || height <= 0)
            {
                return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
            }

            float ratio;
            int   sourceWidth  = source.Width;
            int   sourceHeight = source.Height;

            int destinationX      = 0;
            int destinationY      = 0;
            int destinationWidth  = width;
            int destinationHeight = height;

            // Fractional variants for preserving aspect ratio.
            float percentHeight = MathF.Abs(height / (float)sourceHeight);
            float percentWidth  = MathF.Abs(width / (float)sourceWidth);

            if (percentHeight < percentWidth)
            {
                ratio            = percentHeight;
                destinationWidth = (int)MathF.Round(sourceWidth * percentHeight);

                switch (options.Position)
                {
                case AnchorPositionMode.Left:
                case AnchorPositionMode.TopLeft:
                case AnchorPositionMode.BottomLeft:
                    destinationX = 0;
                    break;

                case AnchorPositionMode.Right:
                case AnchorPositionMode.TopRight:
                case AnchorPositionMode.BottomRight:
                    destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
                    break;

                default:
                    destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F);
                    break;
                }
            }
            else
            {
                ratio             = percentWidth;
                destinationHeight = (int)MathF.Round(sourceHeight * percentWidth);

                switch (options.Position)
                {
                case AnchorPositionMode.Top:
                case AnchorPositionMode.TopLeft:
                case AnchorPositionMode.TopRight:
                    destinationY = 0;
                    break;

                case AnchorPositionMode.Bottom:
                case AnchorPositionMode.BottomLeft:
                case AnchorPositionMode.BottomRight:
                    destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
                    break;

                default:
                    destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F);
                    break;
                }
            }

            return(new Size(width, height),
                   new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
        }
Пример #28
0
        /// <inheritdoc/>
        protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            int startY = sourceRectangle.Y;
            int endY   = sourceRectangle.Bottom;
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;
            int radius = this.BrushSize >> 1;
            int levels = this.Levels;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height))
            {
                source.CopyTo(targetPixels);

                Parallel.For(
                    minY,
                    maxY,
                    this.ParallelOptions,
                    y =>
                {
                    Span <TPixel> sourceRow = source.GetRowSpan(y);
                    Span <TPixel> targetRow = targetPixels.GetRowSpan(y);

                    for (int x = startX; x < endX; x++)
                    {
                        int maxIntensity = 0;
                        int maxIndex     = 0;

                        int[] intensityBin = new int[levels];
                        float[] redBin     = new float[levels];
                        float[] blueBin    = new float[levels];
                        float[] greenBin   = new float[levels];

                        for (int fy = 0; fy <= radius; fy++)
                        {
                            int fyr     = fy - radius;
                            int offsetY = y + fyr;

                            offsetY = offsetY.Clamp(0, maxY);

                            Span <TPixel> sourceOffsetRow = source.GetRowSpan(offsetY);

                            for (int fx = 0; fx <= radius; fx++)
                            {
                                int fxr     = fx - radius;
                                int offsetX = x + fxr;
                                offsetX     = offsetX.Clamp(0, maxX);

                                var vector = sourceOffsetRow[offsetX].ToVector4();

                                float sourceRed   = vector.X;
                                float sourceBlue  = vector.Z;
                                float sourceGreen = vector.Y;

                                int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1));

                                intensityBin[currentIntensity] += 1;
                                blueBin[currentIntensity]      += sourceBlue;
                                greenBin[currentIntensity]     += sourceGreen;
                                redBin[currentIntensity]       += sourceRed;

                                if (intensityBin[currentIntensity] > maxIntensity)
                                {
                                    maxIntensity = intensityBin[currentIntensity];
                                    maxIndex     = currentIntensity;
                                }
                            }

                            float red   = MathF.Abs(redBin[maxIndex] / maxIntensity);
                            float green = MathF.Abs(greenBin[maxIndex] / maxIntensity);
                            float blue  = MathF.Abs(blueBin[maxIndex] / maxIntensity);

                            ref TPixel pixel = ref targetRow[x];
                            pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
                        }
                    }
                });

                source.SwapPixelsBuffers(targetPixels);
            }
        }
Пример #29
0
        /// <inheritdoc/>
        protected override void BeforeApply(ImageBase <TPixel> source, Rectangle sourceRectangle)
        {
            if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon)
            {
                return;
            }

            this.processMatrix = Matrix3x2Extensions.CreateRotation(-this.Angle, new Point(0, 0));
            if (this.Expand)
            {
                this.CreateNewCanvas(sourceRectangle, this.processMatrix);
            }
        }
Пример #30
0
        private void DrawLayer(IDrawDevice device, ref TileMapLayer layer, int cacheIndex)
        {
            if (!layer.Visible)
            {
                return;
            }

            Vector2 viewSize   = device.TargetSize;
            Vector3 viewCenter = device.RefCoord;

            Point2  tileCount = new Point2(layer.LayoutWidth, layer.Layout.Length / layer.LayoutWidth);
            Vector2 tileSize  = new Vector2(tileset.TileSize, tileset.TileSize);

            // Update offsets for moving layers
            if (MathF.Abs(layer.AutoSpeedX) > 0)
            {
                layer.OffsetX += layer.AutoSpeedX * Time.TimeMult;
                if (layer.RepeatX)
                {
                    if (layer.AutoSpeedX > 0)
                    {
                        while (layer.OffsetX > (tileCount.X * 32))
                        {
                            layer.OffsetX -= (tileCount.X * 32);
                        }
                    }
                    else
                    {
                        while (layer.OffsetX < 0)
                        {
                            layer.OffsetX += (tileCount.X * 32);
                        }
                    }
                }
            }
            if (MathF.Abs(layer.AutoSpeedY) > 0)
            {
                layer.OffsetY += layer.AutoSpeedY * Time.TimeMult;
                if (layer.RepeatY)
                {
                    if (layer.AutoSpeedY > 0)
                    {
                        while (layer.OffsetY > (tileCount.Y * 32))
                        {
                            layer.OffsetY -= (tileCount.Y * 32);
                        }
                    }
                    else
                    {
                        while (layer.OffsetY < 0)
                        {
                            layer.OffsetY += (tileCount.Y * 32);
                        }
                    }
                }
            }

            // Get current layer offsets and speeds
            float loX = layer.OffsetX;
            float loY = layer.OffsetY - (layer.UseInherentOffset ? (viewSize.Y - 200) / 2 : 0);

            // Find out coordinates for a tile from outside the boundaries from topleft corner of the screen
            float x1 = viewCenter.X - 70 - (viewSize.X * 0.5f);
            float y1 = viewCenter.Y - 70 - (viewSize.Y * 0.5f);

            if (layer.BackgroundStyle != BackgroundStyle.Plain && tileCount.Y == 8 && tileCount.X == 8)
            {
                const float PerspectiveSpeedX = 0.4f;
                const float PerspectiveSpeedY = 0.16f;
                RenderTexturedBackground(device, ref layer, cacheIndex,
                                         (x1 * PerspectiveSpeedX + loX),
                                         (y1 * PerspectiveSpeedY + loY));
            }
            else
            {
                // Figure out the floating point offset from the calculated coordinates and the actual tile
                // corner coordinates
                float xt = TranslateCoordinate(x1, layer.SpeedX, loX, false, viewSize.Y, viewSize.X);
                float yt = TranslateCoordinate(y1, layer.SpeedY, loY, true, viewSize.Y, viewSize.X);

                float remX = xt % 32f;
                float remY = yt % 32f;

                // Calculate the index (on the layer map) of the first tile that needs to be drawn to the
                // position determined earlier
                int tileX, tileY, tileAbsX, tileAbsY;

                // Get the actual tile coords on the layer layout
                if (xt > 0)
                {
                    tileAbsX = (int)Math.Floor(xt / 32f);
                    tileX    = tileAbsX % tileCount.X;
                }
                else
                {
                    tileAbsX = (int)Math.Ceiling(xt / 32f);
                    tileX    = tileAbsX % tileCount.X;
                    while (tileX < 0)
                    {
                        tileX += tileCount.X;
                    }
                }

                if (yt > 0)
                {
                    tileAbsY = (int)Math.Floor(yt / 32f);
                    tileY    = tileAbsY % tileCount.Y;
                }
                else
                {
                    tileAbsY = (int)Math.Ceiling(yt / 32f);
                    tileY    = tileAbsY % tileCount.Y;
                    while (tileY < 0)
                    {
                        tileY += tileCount.Y;
                    }
                }

                // update x1 and y1 with the remainder so that we start at the tile boundary
                // minus 1 because indices are updated in the beginning of the loops
                x1 -= remX - 32f;
                y1 -= remY - 32f;

                // Save the tile Y at the left border so that we can roll back to it at the start of
                // every row iteration
                int tileYs = tileY;

                // Calculate the last coordinates we want to draw to
                float x3 = x1 + 100 + viewSize.X;
                float y3 = y1 + 100 + viewSize.Y;

                Material  material  = null;
                Texture   texture   = null;
                ColorRgba mainColor = ColorRgba.White;

                // Reserve the required space for vertex data in our locally cached buffer
                VertexC1P3T2[] vertexData;

                int neededVertices = (int)((((x3 - x1) / 32) + 1) * (((y3 - y1) / 32) + 1) * 4);
                if (cachedVertices[cacheIndex] == null || cachedVertices[cacheIndex].Length < neededVertices)
                {
                    cachedVertices[cacheIndex] = vertexData = new VertexC1P3T2[neededVertices];
                }
                else
                {
                    vertexData = cachedVertices[cacheIndex];
                }

                int vertexBaseIndex = 0;

                int tile_xo = -1;
                for (float x2 = x1; x2 < x3; x2 += 32)
                {
                    tileX = (tileX + 1) % tileCount.X;
                    tile_xo++;
                    if (!layer.RepeatX)
                    {
                        // If the current tile isn't in the first iteration of the layer horizontally, don't draw this column
                        if (tileAbsX + tile_xo + 1 < 0 || tileAbsX + tile_xo + 1 >= tileCount.X)
                        {
                            continue;
                        }
                    }
                    tileY = tileYs;
                    int tile_yo = -1;
                    for (float y2 = y1; y2 < y3; y2 += 32)
                    {
                        tileY = (tileY + 1) % tileCount.Y;
                        tile_yo++;

                        LayerTile tile = layer.Layout[tileX + tileY * layer.LayoutWidth];

                        if (!layer.RepeatY)
                        {
                            // If the current tile isn't in the first iteration of the layer vertically, don't draw it
                            if (tileAbsY + tile_yo + 1 < 0 || tileAbsY + tile_yo + 1 >= tileCount.Y)
                            {
                                continue;
                            }
                        }

                        Point2 offset;
                        bool   isFlippedX, isFlippedY;
                        if (tile.IsAnimated)
                        {
                            if (tile.TileID < animatedTiles.Count)
                            {
                                offset     = animatedTiles[tile.TileID].CurrentTile.MaterialOffset;
                                isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX);
                                isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY);

                                //mainColor.A = tile.MaterialAlpha;
                                mainColor.A = animatedTiles[tile.TileID].CurrentTile.MaterialAlpha;
                            }
                            else
                            {
                                continue;
                            }
                        }
                        else
                        {
                            offset     = tile.MaterialOffset;
                            isFlippedX = tile.IsFlippedX;
                            isFlippedY = tile.IsFlippedY;

                            mainColor.A = tile.MaterialAlpha;
                        }

                        if (material != tile.Material)
                        {
                            // Submit all the vertices as one draw batch
                            device.AddVertices(
                                material,
                                VertexMode.Quads,
                                vertexData,
                                0,
                                vertexBaseIndex);

                            vertexBaseIndex = 0;

                            material = tile.Material.Res;
                            texture  = material.MainTexture.Res;
                        }

                        Rect uvRect = new Rect(
                            offset.X * texture.UVRatio.X / texture.ContentWidth,
                            offset.Y * texture.UVRatio.Y / texture.ContentHeight,
                            tileset.TileSize * texture.UVRatio.X / texture.ContentWidth,
                            tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight
                            );

                        // ToDo: Flip normal map somehow
                        if (isFlippedX)
                        {
                            uvRect.X += uvRect.W;
                            uvRect.W *= -1;
                        }
                        if (isFlippedY)
                        {
                            uvRect.Y += uvRect.H;
                            uvRect.H *= -1;
                        }

                        Vector3 renderPos = new Vector3(x2, y2, layer.Depth);
                        float   scale     = 1.0f;
                        device.PreprocessCoords(ref renderPos, ref scale);

                        renderPos.X = MathF.Round(renderPos.X);
                        renderPos.Y = MathF.Round(renderPos.Y);
                        if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2)
                        {
                            renderPos.X += 0.5f;
                        }
                        if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2)
                        {
                            renderPos.Y += 0.5f;
                        }

                        vertexData[vertexBaseIndex + 0].Pos.X      = renderPos.X;
                        vertexData[vertexBaseIndex + 0].Pos.Y      = renderPos.Y;
                        vertexData[vertexBaseIndex + 0].Pos.Z      = renderPos.Z;
                        vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X;
                        vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y;
                        vertexData[vertexBaseIndex + 0].Color      = mainColor;

                        vertexData[vertexBaseIndex + 1].Pos.X      = renderPos.X;
                        vertexData[vertexBaseIndex + 1].Pos.Y      = renderPos.Y + tileSize.Y;
                        vertexData[vertexBaseIndex + 1].Pos.Z      = renderPos.Z;
                        vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X;
                        vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H;
                        vertexData[vertexBaseIndex + 1].Color      = mainColor;

                        vertexData[vertexBaseIndex + 2].Pos.X      = renderPos.X + tileSize.X;
                        vertexData[vertexBaseIndex + 2].Pos.Y      = renderPos.Y + tileSize.Y;
                        vertexData[vertexBaseIndex + 2].Pos.Z      = renderPos.Z;
                        vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.X + uvRect.W;
                        vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H;
                        vertexData[vertexBaseIndex + 2].Color      = mainColor;

                        vertexData[vertexBaseIndex + 3].Pos.X      = renderPos.X + tileSize.X;
                        vertexData[vertexBaseIndex + 3].Pos.Y      = renderPos.Y;
                        vertexData[vertexBaseIndex + 3].Pos.Z      = renderPos.Z;
                        vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W;
                        vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y;
                        vertexData[vertexBaseIndex + 3].Color      = mainColor;

                        vertexBaseIndex += 4;
                    }
                }

                // Submit all the vertices as one draw batch
                device.AddVertices(
                    material,
                    VertexMode.Quads,
                    vertexData,
                    0,
                    vertexBaseIndex);
            }
        }