Example #1
0
        public void SetHeights(int x, int z, Serializable2DFloatArray heights, int heightRes, Serializable2DFloatArray stencil = null)
        {
            if (heights == null)
            {
                return;
            }
            if (Heights == null || Heights.Width != heightRes || Heights.Height != heightRes)
            {
                Heights = new Serializable2DFloatArray(heightRes, heightRes);
            }
            var width  = heights.Width;
            var height = heights.Height;

            for (var u = x; u < x + width; ++u)
            {
                for (var v = z; v < z + height; ++v)
                {
                    var hx = u - x;
                    var hz = v - z;
                    try
                    {
                        var heightsSample = heights[hx, hz];
                        heightsSample = Mathf.Clamp01(heightsSample);
                        if (stencil == null)
                        {
                            Heights[u, v] = heightsSample;
                        }
                        else
                        {
                            float val;
                            int   key;
                            MiscUtilities.DecompressStencil(stencil[u, v], out key, out val);
                            Heights[u, v] = Mathf.Lerp(Heights[u, v], heightsSample, val);
                        }
                    }
                    catch (IndexOutOfRangeException e)
                    {
                        Debug.LogError(string.Format("x {0} y {1}", hx, hz));
                        throw e;
                    }
                }
            }

#if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(this);
#endif
        }
Example #2
0
        public override Texture2D ToTexture2D(bool normalise, Texture2D tex = null)
        {
            if (tex == null || tex.width != Width || tex.height != Height)
            {
                tex = new Texture2D(Width, Height);
            }
            var colors = new Color32[Width * Height];

            OnBeforeSerialize();
            for (int i = 0; i < Data.Length; i++)
            {
                int   stencilKey;
                float value;
                MiscUtilities.DecompressStencil(Data[i], out stencilKey, out value);
                colors[i] = Color.Lerp(Color.black, ColorUtils.GetIndexColor(stencilKey), value);
            }
            tex.SetPixels32(colors);
            tex.Apply();
            return(tex);
        }
Example #3
0
        public void Process(global::MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null)
        {
            if (stop != null && stop(0))
            {
                return;
            }

            Matrix result = new Matrix(rect);

            foreach (MadMapsStencilOutput gen in gens.GeneratorsOfType <MadMapsStencilOutput>(onlyEnabled: true, checkBiomes: true))
            {
                Matrix input = (Matrix)gen.input.GetObject(results);
                if (input == null)
                {
                    continue;
                }

                //loading biome matrix
                Matrix biomeMask = null;
                if (gen.biome != null)
                {
                    object biomeMaskObj = gen.biome.mask.GetObject(results);
                    if (biomeMaskObj == null)
                    {
                        continue;                       //adding nothing if biome has no mask
                    }
                    biomeMask = (Matrix)biomeMaskObj;
                    if (biomeMask == null)
                    {
                        continue;
                    }
                    if (biomeMask.IsEmpty())
                    {
                        continue;                      //optimizing empty biomes
                    }
                }

                //adding to final result
                if (gen.biome == null)
                {
                    result.Add(input);
                }
                else if (biomeMask != null)
                {
                    result.Add(input, biomeMask);
                }
            }

            //creating 2d array
            if (stop != null && stop(0))
            {
                return;
            }

            int heightSize = terrainSize.resolution;
            var stencil    = new Stencil(heightSize, heightSize);
            int key        = 1;

            for (int x = 0; x < heightSize - 1; x++)
            {
                for (int z = 0; z < heightSize - 1; z++)
                {
                    float strength;
                    int   disposableKey;
                    MiscUtilities.DecompressStencil(stencil[x, z], out disposableKey, out strength);

                    var writeValue = result[x + results.heights.rect.offset.x, z + results.heights.rect.offset.z];

                    stencil[x, z] = MiscUtilities.CompressStencil(key, strength + writeValue);
                }
            }

            //pushing to apply
            if (stop != null && stop(0))
            {
                return;
            }
            results.apply.CheckAdd(typeof(MadMapsStencilOutput), stencil, replace: true);
        }
Example #4
0
        public override void ProcessHeights(TerrainWrapper wrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            if (!Network || Configuration == null)
            {
                return;
            }
            var config = Configuration.GetConfig <Config>();

            if (config == null)
            {
                Debug.LogError("Invalid configuration! Expected ConnectionTerrainHeightConfiguration");
                return;
            }
            var terrain     = wrapper.Terrain;
            var terrainPos  = wrapper.Terrain.GetPosition();
            var terrainSize = wrapper.Terrain.terrainData.size;
            var heightRes   = terrain.terrainData.heightmapResolution;

            var mainSpline   = NodeConnection.GetSpline();
            var radius       = config.Radius;
            var falloffCurve = config.Falloff;
            var heightCurve  = config.Height;

            // Create bounds to encapsulate spline (axis aligned)
            var bounds = mainSpline.GetApproximateBounds();

            bounds.Expand(radius * 2 * Vector3.one);

            // Create object bounds
            var objectBounds = mainSpline.GetApproximateXZObjectBounds();

            objectBounds.Expand(radius * 2 * Vector3.one);
            objectBounds.Expand(Vector3.up * 10000);

            // Early cull
            var axisBounds    = objectBounds.ToAxisBounds();
            var terrainBounds = terrain.GetComponent <Collider>().bounds;

            terrainBounds.Expand(Vector3.up * 10000);
            if (!terrainBounds.Intersects(axisBounds))
            {
                return;
            }

            // Get matrix space min/max
            var matrixMin = terrain.WorldToHeightmapCoord(bounds.min, TerrainX.RoundType.Floor) - Coord.One;

            matrixMin = matrixMin.Clamp(0, heightRes);
            var matrixMax = terrain.WorldToHeightmapCoord(bounds.max, TerrainX.RoundType.Ceil) + Coord.One;

            matrixMax = matrixMax.Clamp(0, heightRes);

            var xDelta = matrixMax.x - matrixMin.x;
            var zDelta = matrixMax.z - matrixMin.z;

            var floatArraySize = new Common.Coord(
                Mathf.Min(xDelta, terrain.terrainData.heightmapResolution - matrixMin.x),
                Mathf.Min(zDelta, terrain.terrainData.heightmapResolution - matrixMin.z));

            float planeGive = (wrapper.Terrain.terrainData.size.x / wrapper.Terrain.terrainData.heightmapResolution) * 0;
            Plane startPlane, endPlane;

            GenerateSplinePlanes(planeGive, mainSpline, out startPlane, out endPlane);

            var layerHeights = layer.GetHeights(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, heightRes) ??
                               new Serializable2DFloatArray(floatArraySize.x, floatArraySize.z);

            stencilKey = GetStencilKey();
            if (layer.Stencil == null || layer.Stencil.Width != heightRes || layer.Stencil.Height != heightRes)
            {
                layer.Stencil = new Stencil(heightRes, heightRes);
            }

            for (var dz = 0; dz < floatArraySize.z; ++dz)
            {
                for (var dx = 0; dx < floatArraySize.x; ++dx)
                {
                    var coordX = matrixMin.x + dx;
                    var coordZ = matrixMin.z + dz;

                    var worldPos = terrain.HeightmapCoordToWorldPos(new Common.Coord(coordX, coordZ));
                    worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);
                    if (!terrain.ContainsPointXZ(worldPos) ||
                        !objectBounds.Contains(worldPos) ||
                        !GeometryExtensions.BetweenPlanes(worldPos, startPlane, endPlane))
                    {
                        // Cull if we're outside of the approx bounds
                        continue;
                    }

                    var uniformT                   = mainSpline.GetClosestUniformTimeOnSplineXZ(worldPos.xz()); // Expensive!
                    var closestOnSpline            = mainSpline.GetUniformPointOnSpline(uniformT);
                    var normalizedFlatDistToSpline = (worldPos - closestOnSpline).xz().magnitude / (radius);
                    if (normalizedFlatDistToSpline >= 1)
                    {
                        continue;
                    }

                    var maskValue   = Mathf.Clamp01(falloffCurve.Evaluate(normalizedFlatDistToSpline));
                    var heightDelta = heightCurve.Evaluate(normalizedFlatDistToSpline);

                    float existingStencilStrength;
                    int   existingStencilKey;
                    MiscUtilities.DecompressStencil(layer.Stencil[coordX, coordZ], out existingStencilKey, out existingStencilStrength);

                    if (existingStencilKey != stencilKey &&
                        existingStencilKey > stencilKey &&
                        !(existingStencilStrength < maskValue && maskValue > 0))
                    {
                        continue;
                    }

                    // Refine our worldposition to be on the same XZ plane as the spline point
                    worldPos = new Vector3(worldPos.x, closestOnSpline.y, worldPos.z);

                    // Find the point on the spline closest to this given point
                    var naturalT = mainSpline.UniformToNaturalTime(uniformT);

                    // Get the upvec from the natural time
                    var up = mainSpline.GetUpVector(naturalT).normalized;

                    // Create a plane and cast against it
                    var plane = new Plane(up, closestOnSpline);

                    float dist    = 0;
                    var   castRay = new Ray(worldPos, Vector3.down);
                    plane.Raycast(castRay, out dist);
                    var castPoint     = castRay.GetPoint(dist);
                    var heightAtPoint = (castPoint.y + heightDelta);

                    heightAtPoint -= terrainPos.y;
                    heightAtPoint /= terrainSize.y;
                    heightAtPoint  = MiscUtilities.FloorToUshort(heightAtPoint);

                    var existingHeight = layerHeights[dx, dz];
                    var newHeight      = Mathf.Lerp(existingHeight, heightAtPoint, Mathf.Clamp01(maskValue));

                    layerHeights[dx, dz] = newHeight;

                    var key = maskValue > existingStencilStrength ? stencilKey : existingStencilKey;
                    var newRawStencilValue = MiscUtilities.CompressStencil(key, /*stencilKey == existingStencilKey ?*/ Mathf.Max(maskValue, existingStencilStrength) /* : maskValue + existingStencilStrength*/);
                    //newRawStencilValue = MiscUtilities.CompressStencil(key, 1);

                    layer.Stencil[coordX, coordZ] = newRawStencilValue;
                }
            }

            layer.SetHeights(matrixMin.x, matrixMin.z,
                             layerHeights, wrapper.Terrain.terrainData.heightmapResolution);
        }
Example #5
0
        public override void ProcessStencil(TerrainWrapper terrainWrapper, LayerBase baseLayer, int stencilKey)
        {
            var layer = baseLayer as MMTerrainLayer;

            if (layer == null)
            {
                Debug.LogWarning(string.Format("Attempted to write {0} to incorrect layer type! Expected Layer {1} to be {2}, but it was {3}", name, baseLayer.name, GetLayerType(), baseLayer.GetType()), this);
                return;
            }
            stencilKey = GetPriority();
            var objectBounds  = GetObjectBounds();
            var flatObjBounds = objectBounds.Flatten();
            var flatBounds    = flatObjBounds.ToAxisBounds();
            var terrainSize   = terrainWrapper.Terrain.terrainData.size;
            var hRes          = terrainWrapper.Terrain.terrainData.heightmapResolution;

            var matrixMin = terrainWrapper.Terrain.WorldToHeightmapCoord(flatBounds.min,
                                                                         TerrainX.RoundType.Floor);
            var matrixMax = terrainWrapper.Terrain.WorldToHeightmapCoord(flatBounds.max,
                                                                         TerrainX.RoundType.Ceil);

            matrixMin = new Common.Coord(Mathf.Clamp(matrixMin.x, 0, hRes), Mathf.Clamp(matrixMin.z, 0, hRes));
            matrixMax = new Common.Coord(Mathf.Clamp(matrixMax.x, 0, hRes), Mathf.Clamp(matrixMax.z, 0, hRes));

            var floatArraySize = new Common.Coord(matrixMax.x - matrixMin.x, matrixMax.z - matrixMin.z);


            layer.BlendMode = MMTerrainLayer.EMMTerrainLayerBlendMode.Stencil;

            if (layer.Stencil == null || layer.Stencil.Width != hRes || layer.Stencil.Height != hRes)
            {
                layer.Stencil = new Stencil(hRes, hRes);
            }
            var layerHeights = layer.GetHeights(matrixMin.x, matrixMin.z, floatArraySize.x, floatArraySize.z, hRes) ??
                               new Serializable2DFloatArray(floatArraySize.x, floatArraySize.z);

            var objectBoundsPlane = new Plane((objectBounds.Rotation * Vector3.up).normalized, objectBounds.center);

            for (var dz = 0; dz < floatArraySize.z; ++dz)
            {
                for (var dx = 0; dx < floatArraySize.x; ++dx)
                {
                    var coordX = matrixMin.x + dx;
                    var coordZ = matrixMin.z + dz;

                    int   existingStencilKey;
                    float existingStencilVal;
                    MiscUtilities.DecompressStencil(layer.Stencil[coordX, coordZ], out existingStencilKey,
                                                    out existingStencilVal);

                    var worldPos = terrainWrapper.Terrain.HeightmapCoordToWorldPos(new Common.Coord(coordX, coordZ));
                    worldPos = new Vector3(worldPos.x, objectBounds.center.y, worldPos.z);
                    if (!flatObjBounds.Contains(new Vector3(worldPos.x, flatObjBounds.center.y, worldPos.z)))
                    {
                        continue;
                    }

                    var localPos = Quaternion.Inverse(objectBounds.Rotation) * (worldPos - objectBounds.min);
                    var xDist    = localPos.x / objectBounds.size.x;
                    var zDist    = localPos.z / objectBounds.size.z;

                    float falloff = GetFalloff(new Vector2(xDist, zDist));
                    if (Mathf.Approximately(falloff, 0))
                    {
                        continue;
                    }

                    var   planeRay = new Ray(worldPos, Vector3.up);
                    float dist;

                    objectBoundsPlane.Raycast(planeRay, out dist);

                    var heightAtPoint  = (planeRay.GetPoint(dist) - terrainWrapper.transform.position).y / terrainSize.y;
                    var blendedHeight  = heightAtPoint;
                    var existingHeight = layerHeights[dx, dz];

                    if (SetHeights)
                    {
                        if (BlendMode == HeightBlendMode.Max && existingHeight > heightAtPoint)
                        {
                            layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(0, 0);
                            continue;
                        }
                        if (BlendMode == HeightBlendMode.Min && existingHeight < heightAtPoint)
                        {
                            layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(0, 0);
                            continue;
                        }
                    }

                    switch (BlendMode)
                    {
                    case HeightBlendMode.Set:
                        blendedHeight = Mathf.Lerp(existingHeight, blendedHeight, falloff);
                        break;

                    case HeightBlendMode.Max:
                        blendedHeight = Mathf.Max(existingHeight, blendedHeight);
                        break;

                    case HeightBlendMode.Min:
                        blendedHeight = Mathf.Min(existingHeight, blendedHeight);
                        break;

                    case HeightBlendMode.Average:
                        blendedHeight = (existingHeight + blendedHeight) / 2;
                        break;
                    }

                    layer.Stencil[matrixMin.x + dx, matrixMin.z + dz] = MiscUtilities.CompressStencil(stencilKey, 1);
                }
            }
        }