public override JobHandle ScheduleGenerateSamplesJob(ref MapPixelData mapPixel)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Divisor ensures continuous 0-1 range of height samples
            float div = (HeightmapDimension - 1) / 3f;

            // Read neighbouring height samples for this map pixel
            int  mx   = mapPixel.mapPixelX;
            int  my   = mapPixel.mapPixelY;
            byte sDim = 4;
            NativeArray <byte> shm = new NativeArray <byte>(dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange1Dim(mx - 2, my - 2, sDim), Allocator.TempJob);

            // Convert & flatten large height samples 2d array into 1d native array.
            byte[,] lhm2 = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3);
            NativeArray <byte> lhm = new NativeArray <byte>(lhm2.Length, Allocator.TempJob);
            byte lDim = (byte)lhm2.GetLength(0);
            int  i    = 0;

            for (int y = 0; y < lDim; y++)
            {
                for (int x = 0; x < lDim; x++)
                {
                    lhm[i++] = lhm2[x, y];
                }
            }

            // Add both working native arrays to disposal list.
            mapPixel.nativeArrayList.Add(shm);
            mapPixel.nativeArrayList.Add(lhm);

            // Extract height samples for all chunks
            int hDim = HeightmapDimension;
            GenerateSamplesJob generateSamplesJob = new GenerateSamplesJob
            {
                shm              = shm,
                lhm              = lhm,
                heightmapData    = mapPixel.heightmapData,
                sd               = sDim,
                ld               = lDim,
                hDim             = hDim,
                div              = div,
                mapPixelX        = mapPixel.mapPixelX,
                mapPixelY        = mapPixel.mapPixelY,
                maxTerrainHeight = MaxTerrainHeight,
            };

            JobHandle generateSamplesHandle = generateSamplesJob.Schedule(hDim * hDim, 64);     // Batch = 1 breaks it since shm not copied... test again later

            return(generateSamplesHandle);
        }
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            var generateSamplesJobHandle = new GenerateSamplesJob
            {
                ResultQueue = this.SamplesQueue.AsParallelWriter(),
                Cells       = this._cellGroup.ToComponentDataArray <PoissonCellComponent>(Allocator.TempJob),
                Radiuses    = this._radiusGroup.ToComponentDataArray <PoissonRadiusComponent>(Allocator.TempJob),
                RandomSeed  = this._random.NextInt()
            }.Schedule(this, inputDeps);

            var createResponseJobHandle = new CreateResponseJob
            {
                CommandBuffer = this._endFrameBarrier.CreateCommandBuffer().ToConcurrent(),
                SamplesQueue  = SamplesQueue
            }.Schedule(generateSamplesJobHandle);

            var cleanUpRequestsJobHandle = new CleanUpRequestsJob
            {
                CommandBuffer = this._endFrameBarrier.CreateCommandBuffer().ToConcurrent(),
            }.Schedule(this, generateSamplesJobHandle);

            var cleanUpCellsJobHandle = new CleanUpCellsJob
            {
                CommandBuffer = this._endFrameBarrier.CreateCommandBuffer().ToConcurrent(),
            }.Schedule(this, generateSamplesJobHandle);

            var cleanUpRadiusesJobHandle = new CleanUpRadiusesJob
            {
                CommandBuffer = this._endFrameBarrier.CreateCommandBuffer().ToConcurrent(),
            }.Schedule(this, generateSamplesJobHandle);

            var deps = JobHandle.CombineDependencies(createResponseJobHandle, cleanUpRequestsJobHandle,
                                                     JobHandle.CombineDependencies(cleanUpCellsJobHandle, cleanUpRadiusesJobHandle));

            this._endFrameBarrier.AddJobHandleForProducer(deps);

            return(deps);
        }
        public override JobHandle ScheduleGenerateSamplesJob(ref MapPixelData mapPixel)
        {
            DaggerfallUnity dfUnity = DaggerfallUnity.Instance;

            // Divisor ensures continuous 0-1 range of tile samples
            float div = (float)(HeightmapDimension - 1) / 3f;

            // Read neighbouring height samples for this map pixel
            int mx = mapPixel.mapPixelX;
            int my = mapPixel.mapPixelY;

            // Seed random with terrain key
            UnityEngine.Random.InitState(TerrainHelper.MakeTerrainKey(mx, my));

            byte[,] shm = dfUnity.ContentReader.WoodsFileReader.GetHeightMapValuesRange(mx - 2, my - 2, 4);
            byte[,] lhm = dfUnity.ContentReader.WoodsFileReader.GetLargeHeightMapValuesRange(mx - 1, my, 3);

            float[,] baseHeightValue = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));

                    baseHeightValue[x, y] = shm[x, y] * ImprovedWorldTerrain.computeHeightMultiplier(mapPixelX, mapPixelY);
                }
            }

            float[,] waterMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    if (shm[x, y] <= 2) // mappixel is water
                    {
                        waterMap[x, y] = 0.0f;
                    }
                    else
                    {
                        waterMap[x, y] = 1.0f;
                    }
                }
            }

            float[,] climateMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    climateMap[x, y] = GetNoiseMapScaleBasedOnClimate(mapPixelX, mapPixelY);
                }
            }

            float[,] waterDistanceMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    int mapPixelX = Math.Max(0, Math.Min(mx + x - 2, WoodsFile.mapWidthValue));
                    int mapPixelY = Math.Max(0, Math.Min(my + y - 2, WoodsFile.mapHeightValue));
                    waterDistanceMap[x, y] = (float)Math.Sqrt(ImprovedWorldTerrain.MapDistanceSquaredFromWater[mapPixelY * WoodsFile.mapWidthValue + mapPixelX]);
                }
            }

            float[,] noiseHeightMultiplierMap = new float[4, 4];
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    // interpolation multiplier taking near coast map pixels into account
                    // (multiply with 0 at coast line and 1 at interpolationEndDistanceFromWaterForNoiseScaleMultiplier)
                    float multFact = (Mathf.Min(interpolationEndDistanceFromWaterForNoiseScaleMultiplier, waterDistanceMap[x, y]) / interpolationEndDistanceFromWaterForNoiseScaleMultiplier);

                    // blend watermap with climatemap taking into account multFact
                    noiseHeightMultiplierMap[x, y] = waterMap[x, y] * climateMap[x, y] * multFact;
                }
            }

            float extraNoiseScaleBasedOnClimate = GetExtraNoiseScaleBasedOnClimate(mx, my);

            byte sDim = 4;
            NativeArray <float> baseHeightValueNativeArray = new NativeArray <float>(shm.Length, Allocator.TempJob);
            int i = 0;

            for (int y = 0; y < sDim; y++)
            {
                for (int x = 0; x < sDim; x++)
                {
                    baseHeightValueNativeArray[i++] = baseHeightValue[x, y];
                }
            }

            i = 0;
            NativeArray <float> noiseHeightMultiplierNativeArray = new NativeArray <float>(noiseHeightMultiplierMap.Length, Allocator.TempJob);

            for (int y = 0; y < sDim; y++)
            {
                for (int x = 0; x < sDim; x++)
                {
                    noiseHeightMultiplierNativeArray[i++] = noiseHeightMultiplierMap[x, y];
                }
            }

            // TODO - shortcut conversion & flattening.
            NativeArray <byte> lhmNativeArray = new NativeArray <byte>(lhm.Length, Allocator.TempJob);
            byte lDim = (byte)lhm.GetLength(0);

            i = 0;
            for (int y = 0; y < lDim; y++)
            {
                for (int x = 0; x < lDim; x++)
                {
                    lhmNativeArray[i++] = lhm[x, y];
                }
            }

            // Add the working native arrays to list for later disposal.
            mapPixel.nativeArrayList.Add(baseHeightValueNativeArray);
            mapPixel.nativeArrayList.Add(noiseHeightMultiplierNativeArray);
            mapPixel.nativeArrayList.Add(lhmNativeArray);

            // Extract height samples for all chunks
            int hDim = HeightmapDimension;
            GenerateSamplesJob generateSamplesJob = new GenerateSamplesJob
            {
                baseHeightValue          = baseHeightValueNativeArray,
                lhm                      = lhmNativeArray,
                noiseHeightMultiplierMap = noiseHeightMultiplierNativeArray,
                heightmapData            = mapPixel.heightmapData,
                sd               = sDim,
                ld               = lDim,
                hDim             = hDim,
                div              = div,
                mapPixelX        = mapPixel.mapPixelX,
                mapPixelY        = mapPixel.mapPixelY,
                maxTerrainHeight = MaxTerrainHeight,
                extraNoiseScaleBasedOnClimate = extraNoiseScaleBasedOnClimate,
            };

            JobHandle generateSamplesHandle = generateSamplesJob.Schedule(hDim * hDim, 64);     // Batch = 1 breaks it since shm not copied... test again later

            return(generateSamplesHandle);
        }