Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
3.9 kB
2
Indexable
Never
using System;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;

namespace Game.World.Views.Spreads.Jobs
{
    [BurstCompile]
    public struct CreateGradationMapJob : IJob
    {
        public NativeArray<int> GradationMap;
        public int Gradations;
        public int Width;
        public int Height;

        public NativeArray<int2> InitialPoints;
        public NativeArray<bool> Filled;

        private int _pixelsCount;
        private int _pixelsPerColor;

        public void Execute()
        {
            _pixelsCount = Width * Height;
            _pixelsPerColor = _pixelsCount / Gradations;

            NativeArray<NativeList<int2>> queues = new NativeArray<NativeList<int2>>(Gradations, Allocator.Temp);

            for (int colorId = 0; colorId < Gradations; colorId++)
            {
                queues[colorId] = new NativeList<int2>(Allocator.Temp);
                int2 startPoint = InitialPoints[colorId];
                if (startPoint.x >= 0 && startPoint.x < Width && startPoint.y >= 0 && startPoint.y < Height)
                {
                    queues[colorId].Add(startPoint);
                }
            }

            int radius = 0;
            int[] filledCounts = new int[Gradations];

            while (true)
            {
                bool anyQueueHasPoints = false;

                for (int colorId = 0; colorId < Gradations; colorId++)
                {
                    if (filledCounts[colorId] >= _pixelsPerColor) continue;

                    NativeList<int2> newPoints = new NativeList<int2>(Allocator.Temp);
                    NativeList<int2> queue = queues[colorId];

                    if (queue.Length > 0) anyQueueHasPoints = true;

                    for (int i = 0; i < queue.Length; i++)
                    {
                        int2 point = queue[i];
                        int x = point.x;
                        int y = point.y;

                        if (Fill(x, y, colorId))
                        {
                            filledCounts[colorId]++;
                        }
                    }

                    for (int angle = 0; angle < 360; angle++)
                    {
                        float rad = math.radians(angle);
                        int2 startPoint = InitialPoints[colorId];
                        int newX = startPoint.x + (int)(radius * math.cos(rad));
                        int newY = startPoint.y + (int)(radius * math.sin(rad));

                        if (newX >= 0 && newX < Width && newY >= 0 && newY < Height && !GetFilledValue(newX, newY))
                        {
                            newPoints.Add(new int2(newX, newY));
                        }
                    }

                    queue.Clear();
                    queue.AddRange(newPoints);
                    newPoints.Dispose();
                }

                if (!anyQueueHasPoints) break;
                radius++;
            }

            for (int colorId = 0; colorId < Gradations; colorId++)
            {
                queues[colorId].Dispose();
            }
            queues.Dispose();
        }

        private bool Fill(int x, int y, int colorId)
        {
            if (x < 0 || x >= Width || y < 0 || y >= Height || GetFilledValue(x, y))
            {
                return false;
            }

            int index = x + y * Width;
            SetFilledValue(x, y, true);
            GradationMap[index] = colorId;
            return true;
        }

        private bool GetFilledValue(int x, int y)
        {
            int index = y * Width + x;
            return Filled[index];
        }

        private void SetFilledValue(int x, int y, bool value)
        {
            int index = y * Width + x;
            Filled[index] = value;
        }
    }
}
Leave a Comment