diff --git a/PolygonalMapGenerator.uplugin b/PolygonalMapGenerator.uplugin index f5481f3..4fa7e53 100644 --- a/PolygonalMapGenerator.uplugin +++ b/PolygonalMapGenerator.uplugin @@ -14,10 +14,20 @@ "IsBetaVersion": true, "Installed": false, "Modules": [ + { + "Name": "Delaunator", + "Type": "Runtime", + "LoadingPhase": "PreDefault" + }, + { + "Name": "DualMesh", + "Type": "Runtime", + "LoadingPhase": "PreDefault" + }, { "Name": "PolygonalMapGenerator", "Type": "Runtime", - "LoadingPhase": "Default" + "LoadingPhase": "PreDefault" } ] } \ No newline at end of file diff --git a/README.md b/README.md index 0f0f578..63d8cd2 100644 --- a/README.md +++ b/README.md @@ -31,98 +31,8 @@ If you don't have a `"Modules"` section, then that usually means that your proje 2. Open up your project in Unreal. If you get a prompt asking for an Unreal Engine version, you probably missed a comma somewhere in your .uproject file -- make sure all the commas and syntax are correct and try again. If Unreal does start to load, you might be told that your project is out of date, and the editor will ask if you want to rebuild your project. Go ahead and say yes so the plugin can be installed properly, keeping in mind that it might take a while to rebuild). After that, open up the Plugins menu, scroll down to the bottom, and ensure that the "PolygonalMapGenerator" plugin is enabled. -3. **Very important!** This project uses Unreal's FGameplayTags system that got brought out of experimental with Unreal Engine 4.15. In order for the system to work properly, you ***need*** to also enable the "GameplayTags" plugin in the Plugins menu (if it's not enabled already). - -![Enable the GameplayTags Plugin](https://cloud.githubusercontent.com/assets/2058763/23337272/035e0798-fb9d-11e6-88ad-86426ac5cd6d.jpg) - -Once you restart the Unreal Editor, you need to go to your Project Settings/GameplayTags and find `Gameplay Tag Table List`. Add two elements to the array, pointing to `/PolygonalMapGenerator/GameplayTags/BiomeTags` and `/PolygonalMapGenerator/GameplayTags/MapMetadataTags`. - -![Add to the GameplayTags array](https://cloud.githubusercontent.com/assets/2058763/23337280/35faf58a-fb9d-11e6-9cbd-029c59499250.jpg) - - -If you don't see anything in the array, you need to go to enable your content browser to show plugin content. In the bottom-left of the content browser, you'll see "View Options". Make sure "Show Plugin Content" is checked, then go back into your Project Settings and see if you can add the GameplayTag tables. - -![Enabling "Show Plugin Content"](https://cloud.githubusercontent.com/assets/2058763/23337287/4ac9d03a-fb9d-11e6-9138-263c55c5f059.jpg) - - -Once you've added the two tables to your GameplayTags array, restart the editor one more time (I know, it's a pain) so the GameplayTag array gets populated properly. - -4. Once the editor has reloaded, you can either spawn in the `IslandMapGenerator` Actor raw, or create a Blueprint asset inheriting from it. Tweak the settings in `IslandData` to your liking -- you likely want to set `IslandType` to `RadialIsland` and `Island Point Selector` to `RandomPointGenerator`. - -![An example settings panel](https://cloud.githubusercontent.com/assets/2058763/23337290/7bb8f068-fb9d-11e6-93a9-25b623c9b017.jpg) - -Place the Actor in your level somewhere and call `CreateMap` on the `IslandMapGenerator`. This will create the actual map and notify you on completion. More details about how to use the data inside `IslandMapGenerator` are provided below. - -![Blueprint example](https://cloud.githubusercontent.com/assets/2058763/23337302/bfde088c-fb9d-11e6-9ec4-7d5ef6792a6c.jpg) - -![Output](https://cloud.githubusercontent.com/assets/2058763/23337305/cff8818e-fb9d-11e6-9290-b3c82c3bb004.jpg) - -#Example Project - -An example project using this system [can be found here](https://github.com/Jay2645/UnrealPolygonalMapGenExample). - -#Changes from Source Article - -There have been a few changes from the ActionScript source. There's nothing too drastic, just a couple changes for better ease-of-use: - -* There has been an implementation of a "tag" system to provide more variety. This tag system uses Unreal's `FGameplayTag` class, which is fast, user-extensible, and can quickly and easily add classifications to things on the map. As an example, users can specify part of the map as a volcano by making a new GameplayTag like "MapData.MetaData.Volcano", which is then something that can be taken into account during Biome generation by extending the current classes. This tag system also replaces hardcoded booleans to determine whether part of the map is water, ocean, coast, etc. - -* Most of the original ActionScript code was placed in a single class, `Map`, with a couple helper classes for the shape of the island (`IslandShape` in this project) and selecting which points to use (`PointGeneratior` in this project). This code has been further encapsulated, with the `Map` class (`IslandMapGenerator` here) being broken down into various stages. Each stage is its own class, which can be overridden and users can provide their own implementation if the default one isn't to their liking. - -#How Maps Are Made - -The actual map generation works by generating an array of points using a user-specified PointGeneratior (inheriting from UPointGenerator), which is triangulated using a [Delaunay Triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation). The Delaunay Triangulation is a dual graph of a [Voronoi Diagram](https://en.wikipedia.org/wiki/Voronoi_diagram), which provides us with 2 sets of points. This approach is called a "polygonal" map generation because we use the points of our Delaunay Triangulation as centers of polygons, with the vertices of that polygon given by the dual graph of the Voronoi Diagram. - -Once a map is created, it will generate 3 different arrays: - -* `FMapCenter`: This is the "center" of our polygon, and for all intents and purposes is treated as it being a polygon itself. This polygon can have any number (>=3) of sides, the vertices of which are contained in the `Corners` array. - -* `FMapCorner`: This is a "vertex" of our polygon, which runs along the edge of the polygon. Rivers and such flow from FMapCorner to FMapCorner. A valid `FMapCorner` will ALWAYS be bordered by 3 `FMapCenter` structures, accessible from the `Touches` array. This means that a `FMapCorner` structure can be roughly associated with a triangle, with the three `FMapCenter` structures acting as vertices. - -* `FMapEdge`: This is a helper class, and contains details on two different graphs. The Delaunay Triangulation can be found by looking at the DelaunayEdge, linking together two neighboring FMapCenters. The Voronoi Diagram can be found by looking at the VoronoiEdge, linking together two neighboring FMapCorners. Note that the order in which Center/Corner comes first cannot be guaranteed; sometimes it may be left-to-right, while other times it may be right-to-left. - -Both the FMapCenter and FMapCorner contain an FMapData struct on the inside, which contains data specific to that point in space -- elevation, moisture, whether a polygon is water, etc. - -#Using in Unreal - -To use in Unreal, simply place an `AIslandMapGenerator` actor in your level and call `CreateMap` on it. `CreateMap` takes a delegate which will be called when the map is complete. After the map is complete, you can access map corners, centers, or edges by calling `GetCorner`, `GetCenter`, or `GetEdge`, all of which ask for an index of the element in question, which is bound between 0 and `GetCornerNum`, `GetCenterNum`, or `GetEdgeNum`. - -Keep in mind that the above functions all return ***copies*** of objects; once modified, you need to call `UpdateCorner`, `UpdateCenter`, or `UpdateEdge`. You can also access an array of ***all** MapData objects across the entire graph; that is to say, it is an array of every single MapData object within every MapCorner and MapCenter. Doing this can give you a representation of the entire map as a whole, which can then be converted into a heightmap for whatever you need. - -This system doesn't physically create anything inside the Unreal Engine itself, except for perhaps a debug diagram if the user chooses. It is up to the user to find or implement a system which can take the data from this graph and transform it into something tangible within the engine itself. - -There is a class provided, `UPolygonalMapHeightmap`, which can create a heightmap from a `UPolygonMap`. To get this heightmap, call the function `CreateHeightmap()` and supply a function callback. This function will asynchronously generate a heightmap array, which can take several seconds. Once the array is complete, the callback will be called and you can safely access the heightmap array through `AIslandMapGenerator::GetHeightmap()`. - -The `UPolygonalMapHeightmap` class provides a couple helper classes: - -* `GetMapData()` provides a copy of the raw array of FMapData objects with size `FIslandData::Size` by `FIslandData::Size`, which the user can iterate over. - -* `GetMapPoint()` takes in an integer X and Y value and safely outputs the FMapData object corresponding to that location. If that location is outside of the heightmap, it will output a "blank" FMapData object. - -This array of FMapData objects can be turned into a 2D grayscale image by the user (using `FMapData::Elevation` to create the color value), or it can be used to create data points in a 3D voxel implementation. - # Credits The original ActionScript code was released under the MIT Open Source license; this C++ port of the code is also released under the MIT Open Source license. -This project also uses [Bl4ckb0ne's C++ Delaunay Triangulation algorithm](https://github.com/Bl4ckb0ne/delaunay-triangulation), modified slightly to work with the Unreal Engine. This code is also used under the MIT License. - -Conversion from Delaunay to Voronoi is (very loosely) based off of [Joseph Marshall's voronoi-c++ code](https://bitbucket.org/jlm/voronoi-c/src/b06aa9cccba6392d28ad7d7cae9a7361efb22c94?at=default), also modified under an MIT License. - -The Markov Chain generator for generating strings from an array of FText was [based off of a version built in C# for the Unity game engine, created by Dave Carlile](http://crappycoding.com/2015/02/procedural-names/) used under the MIT license and converted to C++/modified to work with Unreal. This might be split off into a separate project at some point in the future, as it is only tangentally related to map generation. - -Also used is a noise generator, which is heavily based on the [Jordan Peck's FastNoise code](https://github.com/Auburns/FastNoise) and is used under the MIT License. Minor modifications have been made to make it work with the Unreal Editor. - -# Future Changes - -* Right now, all operations take place on the main gameplay thread. In the future, it would be nice if this was done asynchronously, to allow for a "loading" bar or something similar. - -* There is a lot of missing documentation, and the whole project could do with more comments clarifying how things work. - -* More in-editor visualizations would be nice -- for example, seeing a view of the moisture distribution, or what biomes are where, or general debugging stuff like that. - -* There should be a way to have the generator select a number of "player start" positions, so that the player always gets placed in a playable spot. - -* Some of the map needs to be "cleaned up" -- there are random "spikes" which randomly occur along water edges for some reason, as an example. - -* I still don't like how UPolygonMap handles its graph data objects. Essentially, right now everything is stored as an index to an array contained within the UPolygonMap object. I'd like to have them all be pointers to the actual elements in that array, but as it stands Unreal's `TArray` class (to my knowledge) doesn't support that behavior. Everything is thus accessed by indices to avoid any problems with mistakenly "cloning" graph objects. +Delaunay Triangulation is created [using Delaunator](https://github.com/delfrrr/delaunator-cpp). \ No newline at end of file diff --git a/Source/Delaunator/Delaunator.Build.cs b/Source/Delaunator/Delaunator.Build.cs new file mode 100644 index 0000000..2e4f8d4 --- /dev/null +++ b/Source/Delaunator/Delaunator.Build.cs @@ -0,0 +1,54 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class Delaunator : ModuleRules +{ + public Delaunator(ReadOnlyTargetRules ROTargetRules) : base(ROTargetRules) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "GameplayTags" + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore" + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Source/Delaunator/Private/Delaunator.cpp b/Source/Delaunator/Private/Delaunator.cpp new file mode 100644 index 0000000..8fa1344 --- /dev/null +++ b/Source/Delaunator/Private/Delaunator.cpp @@ -0,0 +1,22 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "Delaunator.h" + +#define LOCTEXT_NAMESPACE "FDelaunatorModule" + +DEFINE_LOG_CATEGORY(LogDelaunator); + +void FDelaunatorModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FDelaunatorModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FDelaunatorModule, Delaunator) \ No newline at end of file diff --git a/Source/Delaunator/Public/Delaunator.h b/Source/Delaunator/Public/Delaunator.h new file mode 100644 index 0000000..bbccb82 --- /dev/null +++ b/Source/Delaunator/Public/Delaunator.h @@ -0,0 +1,17 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ModuleManager.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogDelaunator, Log, All); + +class FDelaunatorModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; \ No newline at end of file diff --git a/Source/DualMesh/DualMesh.Build.cs b/Source/DualMesh/DualMesh.Build.cs new file mode 100644 index 0000000..e0a33dd --- /dev/null +++ b/Source/DualMesh/DualMesh.Build.cs @@ -0,0 +1,55 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class DualMesh : ModuleRules +{ + public DualMesh(ReadOnlyTargetRules ROTargetRules) : base(ROTargetRules) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + "GameplayTags" + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "Delaunator", + "CoreUObject", + "Engine", + "Slate", + "SlateCore" + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Source/DualMesh/Private/DualMesh.cpp b/Source/DualMesh/Private/DualMesh.cpp new file mode 100644 index 0000000..f36fcc9 --- /dev/null +++ b/Source/DualMesh/Private/DualMesh.cpp @@ -0,0 +1,22 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "DualMesh.h" + +#define LOCTEXT_NAMESPACE "FDualMeshModule" + +DEFINE_LOG_CATEGORY(LogDualMesh); + +void FDualMeshModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FDualMeshModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FDualMeshModule, DualMesh) \ No newline at end of file diff --git a/Source/DualMesh/Public/DualMesh.h b/Source/DualMesh/Public/DualMesh.h new file mode 100644 index 0000000..8abf331 --- /dev/null +++ b/Source/DualMesh/Public/DualMesh.h @@ -0,0 +1,17 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "ModuleManager.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogDualMesh, Log, All); + +class FDualMeshModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Classes/Diagrams/Delaunay.h b/Source/PolygonalMapGenerator/Classes/Diagrams/Delaunay.h deleted file mode 100644 index 139479e..0000000 --- a/Source/PolygonalMapGenerator/Classes/Diagrams/Delaunay.h +++ /dev/null @@ -1,20 +0,0 @@ -// Original Work Copyright (c) 2015 Simon Zeni (simonzeni@gmail.com), Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "DelaunayTriangle.h" -#include "Vector2D.h" - -#include - -class Delaunay -{ -public: - const std::vector& triangulate(TArray &vertices); - const std::vector& getTriangles() const { return _triangles; }; - const std::vector& getEdges() const { return _edges; }; - -private: - std::vector _triangles; - std::vector _edges; -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Classes/Diagrams/DelaunayTriangle.h b/Source/PolygonalMapGenerator/Classes/Diagrams/DelaunayTriangle.h deleted file mode 100644 index 69216b3..0000000 --- a/Source/PolygonalMapGenerator/Classes/Diagrams/DelaunayTriangle.h +++ /dev/null @@ -1,47 +0,0 @@ -// Original Work Copyright (c) 2015 Simon Zeni (simonzeni@gmail.com), Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Vector2D.h" - -class DelaunayEdge -{ -public: - DelaunayEdge() {}; - - DelaunayEdge(const FVector2D &_p1, const FVector2D &_p2) : p1(_p1), p2(_p2) {}; - - DelaunayEdge(const DelaunayEdge &e) : p1(e.p1), p2(e.p2) {}; - - FVector2D p1; - FVector2D p2; -}; - -inline bool operator == (const DelaunayEdge & e1, const DelaunayEdge & e2) -{ - return (e1.p1 == e2.p1 && e1.p2 == e2.p2) || - (e1.p1 == e2.p2 && e1.p2 == e2.p1); -} - -class DelaunayTriangle -{ -public: - DelaunayTriangle(const FVector2D &_p1, const FVector2D &_p2, const FVector2D &_p3); - - bool containsVertex(const FVector2D &v); - bool circumCircleContains(const FVector2D &v); - DelaunayEdge e1; - DelaunayEdge e2; - DelaunayEdge e3; - FVector2D circumCircleVertex; - FVector2D p1; - FVector2D p2; - FVector2D p3; -}; - -inline bool operator == (const DelaunayTriangle &t1, const DelaunayTriangle &t2) -{ - return (t1.p1 == t2.p1 || t1.p1 == t2.p2 || t1.p1 == t2.p3) && - (t1.p2 == t2.p1 || t1.p2 == t2.p2 || t1.p2 == t2.p3) && - (t1.p3 == t2.p1 || t1.p3 == t2.p2 || t1.p3 == t2.p3); -} diff --git a/Source/PolygonalMapGenerator/Classes/Diagrams/Voronoi.h b/Source/PolygonalMapGenerator/Classes/Diagrams/Voronoi.h deleted file mode 100644 index 7789d5d..0000000 --- a/Source/PolygonalMapGenerator/Classes/Diagrams/Voronoi.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -* Copyright (c) 2012 by Joseph Marshall, Modified Work Copyright (c) 2016 Jay M Stevens -* -* Parts of this code were originally written by Steven Fortune. -* -* Permission to use, copy, modify, and distribute this software for any -* purpose without fee is hereby granted, provided that this entire notice -* is included in all copies of any software which is or includes a copy -* or modification of this software and in all copies of the supporting -* documentation for such software. -* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY -* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -*/ - -#pragma once - -#include "Delaunay.h" -#include - -struct VEdge -{ - FVector4 vEdge; - FVector4 dEdge; -}; - -class VSite { -public: - VSite() = default; - TArray edges; -}; - -class Voronoi -{ -public: - Voronoi(TArray &points); - Voronoi(Delaunay delaunay); - - TArray sites; -private: - Delaunay DelaunayData; - - void MakeSites(std::vector triangles); - - VSite MakeSite(DelaunayTriangle tri); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Classes/DummyObject.h b/Source/PolygonalMapGenerator/Classes/DummyObject.h deleted file mode 100644 index a6f55a7..0000000 --- a/Source/PolygonalMapGenerator/Classes/DummyObject.h +++ /dev/null @@ -1,17 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Object.h" -#include "DummyObject.generated.h" - -/** - * This is a dummy class with no functionality whatsoever. - * There is a bug in the Unreal Header Tool (UHT) which causes Plugins to not work - * unless there is this dummy file created as the first thing in the project. - */ -UCLASS() -class UDummyObject : public UObject -{ - GENERATED_BODY() -}; diff --git a/Source/PolygonalMapGenerator/Classes/Maps/Heightmap/HeightmapPointTask.h b/Source/PolygonalMapGenerator/Classes/Maps/Heightmap/HeightmapPointTask.h deleted file mode 100644 index c69ec27..0000000 --- a/Source/PolygonalMapGenerator/Classes/Maps/Heightmap/HeightmapPointTask.h +++ /dev/null @@ -1,107 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "Array.h" -#include "Maps/Biomes/BiomeManager.h" -#include "Maps/PolygonMap.h" -#include "Async/TaskGraphInterfaces.h" - -struct FMapData; -class UPolygonalMapHeightmap; - -enum EPointSelectionMode : uint8 -{ - // Each pixel is a reflection of the entire polygon with no blending. - // This creates a "stepped" look and is very fast. - UsePolygon, - // This uses the cached MapData array and interpolates between the nearest point. - // This provides decent results, but is slow. - Interpolated, - // The same as using interpolated, but biomes are just fetched from the parent polygon. - // This provides consistent results (free from errors generated from interpolation), - // but polygon edges are very distinct - InterpolatedWithPolygonBiome -}; - -/** - * - */ -class FHeightmapPointTask -{ - -public: - FHeightmapPointTask(int32 XCoord, int32 YCoord, int32 NumberOfPoints, EPointSelectionMode SelectionMode) - { - X = XCoord; - Y = YCoord; - NumberOfPointsToAverage = NumberOfPoints; - PointSelectionMode = SelectionMode; - } - - int32 X; - int32 Y; - // How many points to take into account when generating an interpolated heightmap - int32 NumberOfPointsToAverage; - // What mode to be in for generating the heightmap. - EPointSelectionMode PointSelectionMode; - - /** return the name of the task **/ - static const TCHAR* GetTaskName() - { - return TEXT("FHeightmapPointTask"); - } - FORCEINLINE static TStatId GetStatId() - { - RETURN_QUICK_DECLARE_CYCLE_STAT(FHeightmapPointTask, STATGROUP_TaskGraphTasks); - } - /** return the thread for this task **/ - static ENamedThreads::Type GetDesiredThread() - { - return ENamedThreads::AnyThread; - } - - static ESubsequentsMode::Type GetSubsequentsMode() - { - return ESubsequentsMode::FireAndForget; - } - - // Creates a map point at the given pixel position and adds it to the end of the HeightmapData array. - FMapData MakeMapPoint(FVector2D PixelPosition, UPolygonMap* MapGraph, UBiomeManager* BiomeManager); - - // Do the task - void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent); -}; - -class FHeightmapPointGenerator -{ -public: - // The heightmap generator - static UPolygonalMapHeightmap* MapHeightmap; - static UPolygonMap* MapGraph; - static UBiomeManager* BiomeManager; - - // Results of the threads - static TArray HeightmapData; - static TArray StartingMapDataArray; - - // This is the array of thread completions, used to determine if all threads are done - static FGraphEventArray CompletionEvents; - - // How many threads have completed so far. - static int32 CompletedThreads; - // How many threads there are total. - static int32 TotalNumberOfThreads; - // The delegate to call when all points are complete. - static FIslandGeneratorDelegate OnAllPointsComplete; - - // Are all tasks complete? - static bool TasksAreComplete(); - - // Initiation point to start the heightmap generation process. - static void GenerateHeightmapPoints(const int32 HeightmapSize, int32 NumberOfPointsToAverage, UPolygonalMapHeightmap* HeightmapGenerator, UPolygonMap* Graph, UBiomeManager* BiomeMgr, const FIslandGeneratorDelegate OnComplete); - - // Check to see if all threads are complete. - // If so, call the OnAllPointsComplete delegate. - static void CheckComplete(); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Classes/Noise/PolygonalMapGenNoise.h b/Source/PolygonalMapGenerator/Classes/Noise/PolygonalMapGenNoise.h deleted file mode 100644 index 462e989..0000000 --- a/Source/PolygonalMapGenerator/Classes/Noise/PolygonalMapGenNoise.h +++ /dev/null @@ -1,298 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "UObject/NoExportTypes.h" -#include "PolygonalMapGenNoise.generated.h" - -UENUM(BlueprintType) //"BlueprintType" is essential to include -enum class ENoiseType : uint8 -{ - Value UMETA(DisplayName = "Value"), - ValueFractal UMETA(DisplayName = "ValueFractal"), - Gradient UMETA(DisplayName = "Gradient"), - GradientFractal UMETA(DisplayName = "GradientFractal"), - Simplex UMETA(DisplayName = "Simplex"), - SimplexFractal UMETA(DisplayName = "SimplexFractal"), - Cellular UMETA(DisplayName = "Cellular"), - WhiteNoise UMETA(DisplayName = "WhiteNoise") -}; - -UENUM(BlueprintType) //"BlueprintType" is essential to include -enum class EInterp : uint8 -{ - InterpLinear UMETA(DisplayName = "InterpLinear"), - InterpHermite UMETA(DisplayName = "InterpHermite"), - InterpQuintic UMETA(DisplayName = "InterpQuintic") -}; - -UENUM(BlueprintType) //"BlueprintType" is essential to include -enum class EFractalType : uint8 -{ - FBM UMETA(DisplayName = "FBM"), - Billow UMETA(DisplayName = "Billow"), - RigidMulti UMETA(DisplayName = "RigidMulti") -}; - - -UENUM(BlueprintType) //"BlueprintType" is essential to include -enum class ECellularDistanceFunction : uint8 -{ - Euclidean UMETA(DisplayName = "Euclidean"), - Manhattan UMETA(DisplayName = "Manhattan"), - Natural UMETA(DisplayName = "Natural") -}; - -UENUM(BlueprintType) //"BlueprintType" is essential to include -enum class ECellularReturnType : uint8 -{ - CellValue UMETA(DisplayName = "CellValue"), - NoiseLookup UMETA(DisplayName = "NoiseLookup"), - Distance UMETA(DisplayName = "Distance"), - Distance2 UMETA(DisplayName = "Distance2"), - Distance2Add UMETA(DisplayName = "Distance2Add"), - Distance2Sub UMETA(DisplayName = "Distance2Sub"), - Distance2Mul UMETA(DisplayName = "Distance2Mul"), - Distance2Div UMETA(DisplayName = "Distance2Div") -}; - -USTRUCT(BlueprintType) -struct FNoiseSettings -{ - GENERATED_BODY() - - // The seed of our fractal - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - int32 Seed; - - // The number of octaves that the noise generator will use. More octaves creates "messier" noise. - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - int32 NoiseOctaves; - - // The frequency of the noise - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - float NoiseFrequency; - - // The detail found in the noise - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - float Lacunarity; - - // The contrast of the noise - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - float Gain; - - // The type of fractal to use to generate the noise - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - EFractalType FractalType; - - // The type of noise to use - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - ENoiseType NoiseType; - - // How to interpolate the noise - // Linear produces the smoothest result - // Hermite produces a slightly more rough result - // Quintic gives the roughest result - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - EInterp NoiseInterpolation; - - UPROPERTY(Category = "Noise Settings", BlueprintReadWrite, EditAnywhere) - FVector2D NoiseRange; - //Constructor - FNoiseSettings() - { - Seed = 123; - NoiseOctaves = 3; - NoiseFrequency = 0.01f; - Lacunarity = 2.0f; - Gain = 0.5f; - NoiseType = ENoiseType::SimplexFractal; - NoiseInterpolation = EInterp::InterpLinear; - FractalType = EFractalType::FBM; - NoiseRange = FVector2D(0.0f, 1.0f); - } -}; - -USTRUCT(BlueprintType) -struct FNoiseProfile -{ - GENERATED_BODY() - - UPROPERTY(Category = "Voxel Biome", BlueprintReadWrite, EditAnywhere) - FName ProfileName; - - UPROPERTY(Category = "Voxel Biome", BlueprintReadWrite, EditAnywhere) - int32 MaterialIndex; - - UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) - FNoiseSettings NoiseSettings; - - // How "squished" the noise is - UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) - float TerrainHeightScale; - - UPROPERTY(Category = "Voxel Terrain", BlueprintReadWrite, EditAnywhere) - float NoiseVerticalOffset; - - //Constructor - FNoiseProfile() - { - MaterialIndex = 0; - TerrainHeightScale = 0.5f; - NoiseVerticalOffset = 0.0f; - ProfileName = NAME_None; - } -}; - -/** - * - */ -class PolygonalMapGenNoise -{ - public: - PolygonalMapGenNoise(int seed = 1337) { SetSeed(seed); }; - ~PolygonalMapGenNoise() { delete m_cellularNoiseLookup; } - - //enum ENoiseType { Value, ValueFractal, Gradient, GradientFractal, Simplex, SimplexFractal, Cellular, WhiteNoise }; - //enum EInterp { InterpLinear, InterpHermite, InterpQuintic }; - //enum EFractalType { FBM, Billow, RigidMulti }; - //enum ECellularDistanceFunction { Euclidean, Manhattan, Natural }; - //enum ECellularReturnType { CellValue, NoiseLookup, Distance, Distance2, Distance2Add, Distance2Sub, Distance2Mul, Distance2Div }; - - void SetSeed(int seed); - int GetSeed(void) const { return m_seed; } - void SetNoiseSettings(FNoiseSettings m_noiseSettings); - void SetFrequency(float frequency) { m_frequency = frequency; } - void SetInterp(EInterp interp) { m_interp = interp; } - void SetNoiseType(ENoiseType noiseType) { m_noiseType = noiseType; } - - void SetFractalOctaves(unsigned int octaves) { m_octaves = octaves; } - void SetFractalLacunarity(float lacunarity) { m_lacunarity = lacunarity; } - void SetFractalGain(float gain) { m_gain = gain; } - void SetFractalType(EFractalType fractalType) { m_fractalType = fractalType; } - - void SetCellularDistanceFunction(ECellularDistanceFunction cellularDistanceFunction) { m_cellularDistanceFunction = cellularDistanceFunction; } - void SetCellularReturnType(ECellularReturnType cellularReturnType) { m_cellularReturnType = cellularReturnType; } - void SetCellularNoiseLookup(PolygonalMapGenNoise* noise) { m_cellularNoiseLookup = noise; } - - /* - Timing below are averages of time taken for 1 million iterations on a single thread - Default noise settings - CPU: i7 4790k @ 4.0Ghz - VS 2013 - C++ Console Application - */ - - //3D // Win32 x64 - float GetValue(float x, float y, float z); // 14 ms 14 ms - float GetValueFractal(float x, float y, float z); // 48 ms 49 ms - - float GetGradient(float x, float y, float z); // 23 ms 22 ms - float GetGradientFractal(float x, float y, float z);// 80 ms 73 ms - - float GetSimplex(float x, float y, float z); // 30 ms 30 ms - float GetSimplexFractal(float x, float y, float z); // 98 ms 101 ms - - float GetCellular(float x, float y, float z); // 123 ms 113 ms - - float GetWhiteNoise(float x, float y, float z); // 1.5 ms 1.5 ms - float GetWhiteNoiseInt(int x, int y, int z); - - float GetNoise(float x, float y, float z); - - //2D // Win32 x64 - float GetValue(float x, float y); // 8 ms 8 ms - float GetValueFractal(float x, float y); // 29 ms 29 ms - - float GetGradient(float x, float y); // 12 ms 11 ms - float GetGradientFractal(float x, float y); // 43 ms 40 ms - - float GetSimplex(float x, float y); // 17 ms 17 ms - float GetSimplexFractal(float x, float y); // 55 ms 52 ms - - float GetCellular(float x, float y); // 35 ms 33 ms - - float GetWhiteNoise(float x, float y); // 1 ms 1 ms - float GetWhiteNoiseInt(int x, int y); // 1 ms 1 ms - - float GetNoise(float x, float y); - - //4D - float GetSimplex(float x, float y, float z, float w); - - float GetWhiteNoise(float x, float y, float z, float w); - float GetWhiteNoiseInt(int x, int y, int z, int w); - - protected: - unsigned char m_perm[512]; - unsigned char m_perm12[512]; - - int m_seed = 1337; - float m_frequency = 0.01f; - EInterp m_interp = EInterp::InterpQuintic; - ENoiseType m_noiseType = ENoiseType::Simplex; - - unsigned int m_octaves = 3; - float m_lacunarity = 2.0f; - float m_gain = 0.5f; - EFractalType m_fractalType = EFractalType::FBM; - FVector2D m_noiseRange = FVector2D(0.0f, 1.0f); - - ECellularDistanceFunction m_cellularDistanceFunction = ECellularDistanceFunction::Euclidean; - ECellularReturnType m_cellularReturnType = ECellularReturnType::CellValue; - PolygonalMapGenNoise* m_cellularNoiseLookup = nullptr; - - //2D - float SingleValueFractalFBM(float x, float y); - float SingleValueFractalBillow(float x, float y); - float SingleValueFractalRigidMulti(float x, float y); - float SingleValue(unsigned char offset, float x, float y); - - float SingleGradientFractalFBM(float x, float y); - float SingleGradientFractalBillow(float x, float y); - float SingleGradientFractalRigidMulti(float x, float y); - float SingleGradient(unsigned char offset, float x, float y); - - float SingleSimplexFractalFBM(float x, float y); - float SingleSimplexFractalBillow(float x, float y); - float SingleSimplexFractalRigidMulti(float x, float y); - float SingleSimplex(unsigned char offset, float x, float y); - - float SingleCellular(float x, float y); - float SingleCellular2Edge(float x, float y); - - //3D - float SingleValueFractalFBM(float x, float y, float z); - float SingleValueFractalBillow(float x, float y, float z); - float SingleValueFractalRigidMulti(float x, float y, float z); - float SingleValue(unsigned char offset, float x, float y, float z); - - float SingleGradientFractalFBM(float x, float y, float z); - float SingleGradientFractalBillow(float x, float y, float z); - float SingleGradientFractalRigidMulti(float x, float y, float z); - float SingleGradient(unsigned char offset, float x, float y, float z); - - float SingleSimplexFractalFBM(float x, float y, float z); - float SingleSimplexFractalBillow(float x, float y, float z); - float SingleSimplexFractalRigidMulti(float x, float y, float z); - float SingleSimplex(unsigned char offset, float x, float y, float z); - - float SingleCellular(float x, float y, float z); - float SingleCellular2Edge(float x, float y, float z); - - //4D - float SingleSimplex(unsigned char offset, float x, float y, float z, float w); - - private: - inline unsigned char Index2D_12(unsigned char offset, int x, int y); - inline unsigned char Index3D_12(unsigned char offset, int x, int y, int z); - inline unsigned char Index4D_32(unsigned char offset, int x, int y, int z, int w); - inline unsigned char Index2D_256(unsigned char offset, int x, int y); - inline unsigned char Index3D_256(unsigned char offset, int x, int y, int z); - inline unsigned char Index4D_256(unsigned char offset, int x, int y, int z, int w); - - inline float ValCoord2DFast(unsigned char offset, int x, int y); - inline float ValCoord3DFast(unsigned char offset, int x, int y, int z); - inline float GradCoord2D(unsigned char offset, int x, int y, float xd, float yd); - inline float GradCoord3D(unsigned char offset, int x, int y, int z, float xd, float yd, float zd); - inline float GradCoord4D(unsigned char offset, int x, int y, int z, int w, float xd, float yd, float zd, float wd); -}; diff --git a/Source/PolygonalMapGenerator/PolygonalMapGenerator.Build.cs b/Source/PolygonalMapGenerator/PolygonalMapGenerator.Build.cs index 25d3105..dea8847 100644 --- a/Source/PolygonalMapGenerator/PolygonalMapGenerator.Build.cs +++ b/Source/PolygonalMapGenerator/PolygonalMapGenerator.Build.cs @@ -6,7 +6,8 @@ public class PolygonalMapGenerator : ModuleRules { public PolygonalMapGenerator(ReadOnlyTargetRules ROTargetRules) : base(ROTargetRules) { - PrivatePCHHeaderFile = "Private/PolygonalMapGeneratorPrivatePCH.h"; + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... @@ -25,8 +26,7 @@ public class PolygonalMapGenerator : ModuleRules new string[] { "Core", - "RHI", - "RenderCore" + "GameplayTags" // ... add other public dependencies that you statically link with here ... } ); @@ -35,11 +35,11 @@ public class PolygonalMapGenerator : ModuleRules PrivateDependencyModuleNames.AddRange( new string[] { + "DualMesh", "CoreUObject", "Engine", "Slate", - "SlateCore", - "GameplayTags", + "SlateCore" // ... add private dependencies that you statically link with here ... } ); diff --git a/Source/PolygonalMapGenerator/Private/Diagrams/Delaunay.cpp b/Source/PolygonalMapGenerator/Private/Diagrams/Delaunay.cpp deleted file mode 100644 index b3377e5..0000000 --- a/Source/PolygonalMapGenerator/Private/Diagrams/Delaunay.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// Original Work Copyright (c) 2015 Simon Zeni (simonzeni@gmail.com), Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Diagrams/Delaunay.h" -#include - -const std::vector& Delaunay::triangulate(TArray &vertices) -{ - // Determinate the super triangle - float minX = vertices[0].X; - float minY = vertices[0].Y; - float maxX = minX; - float maxY = minY; - - for (std::size_t i = 0; i < (std::size_t)vertices.Num(); ++i) - { - if (vertices[i].X < minX) minX = vertices[i].X; - if (vertices[i].Y < minY) minY = vertices[i].Y; - if (vertices[i].X > maxX) maxX = vertices[i].X; - if (vertices[i].Y > maxY) maxY = vertices[i].Y; - } - - float dx = maxX - minX; - float dy = maxY - minY; - float deltaMax = std::max(dx, dy); - float midx = (minX + maxX) / 2.f; - float midy = (minY + maxY) / 2.f; - - FVector2D p1(midx - 20 * deltaMax, midy - deltaMax); - FVector2D p2(midx, midy + 20 * deltaMax); - FVector2D p3(midx + 20 * deltaMax, midy - deltaMax); - - //std::cout << "Super triangle " << std::endl << DelaunayTriangle(p1, p2, p3) << std::endl; - - // Create a list of triangles, and add the supertriangle in it - _triangles.push_back(DelaunayTriangle(p1, p2, p3)); - - for (int i = 0; i < vertices.Num(); i++) - { - FVector2D p = vertices[i]; - //std::cout << "Traitement du point " << *p << std::endl; - //std::cout << "_triangles contains " << _triangles.size() << " elements" << std::endl; - - std::vector badTriangles; - std::vector polygon; - - for (auto t = begin(_triangles); t != end(_triangles); t++) - { - //std::cout << "Processing " << std::endl << *t << std::endl; - - if (t->circumCircleContains(p)) - { - //std::cout << "Pushing bad triangle " << *t << std::endl; - badTriangles.push_back(*t); - polygon.push_back(t->e1); - polygon.push_back(t->e2); - polygon.push_back(t->e3); - } - else - { - //std::cout << " does not contains " << *p << " in his circum center" << std::endl; - } - } - - _triangles.erase(std::remove_if(begin(_triangles), end(_triangles), [badTriangles](DelaunayTriangle &t) { - for (auto bt = begin(badTriangles); bt != end(badTriangles); bt++) - { - if (*bt == t) - { - //std::cout << "Removing bad triangle " << std::endl << *bt << " from _triangles" << std::endl; - return true; - } - } - return false; - }), end(_triangles)); - - std::vector badEdges; - for (auto e1 = begin(polygon); e1 != end(polygon); e1++) - { - for (auto e2 = begin(polygon); e2 != end(polygon); e2++) - { - if (e1 == e2) - continue; - - if (*e1 == *e2) - { - badEdges.push_back(*e1); - badEdges.push_back(*e2); - } - } - } - - polygon.erase(std::remove_if(begin(polygon), end(polygon), [badEdges](DelaunayEdge &e) { - for (auto it = begin(badEdges); it != end(badEdges); it++) - { - if (*it == e) - return true; - } - return false; - }), end(polygon)); - - for (auto e = begin(polygon); e != end(polygon); e++) - _triangles.push_back(DelaunayTriangle(e->p1, e->p2, p)); - - } - - _triangles.erase(std::remove_if(begin(_triangles), end(_triangles), [p1, p2, p3](DelaunayTriangle &t) { - return t.containsVertex(p1) || t.containsVertex(p2) || t.containsVertex(p3); - }), end(_triangles)); - - for (auto t = begin(_triangles); t != end(_triangles); t++) - { - _edges.push_back(t->e1); - _edges.push_back(t->e2); - _edges.push_back(t->e3); - } - - return _triangles; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Diagrams/DelaunayTriangle.cpp b/Source/PolygonalMapGenerator/Private/Diagrams/DelaunayTriangle.cpp deleted file mode 100644 index 861d293..0000000 --- a/Source/PolygonalMapGenerator/Private/Diagrams/DelaunayTriangle.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Original Work Copyright (c) 2015 Simon Zeni (simonzeni@gmail.com), Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Diagrams/Delaunay.h" -#include "Diagrams/DelaunayTriangle.h" - -#include -#include - - -DelaunayTriangle::DelaunayTriangle(const FVector2D &_p1, const FVector2D &_p2, const FVector2D &_p3) -{ - p1 = _p1; - p2 = _p2; - p3 = _p3; - e1 = DelaunayEdge(p1, p2); - e2 = DelaunayEdge(p2, p3); - e3 = DelaunayEdge(p3, p1); - - float ab = (p1.X * p1.X) + (p1.Y * p1.Y); - float cd = (p2.X * p2.X) + (p2.Y * p2.Y); - float ef = (p3.X * p3.X) + (p3.Y * p3.Y); - float circum_x = (ab * (p3.Y - p2.Y) + cd * (p1.Y - p3.Y) + ef * (p2.Y - p1.Y)) / (p1.X * (p3.Y - p2.Y) + p2.X * (p1.Y - p3.Y) + p3.X * (p2.Y - p1.Y)) / 2.f; - float circum_y = (ab * (p3.X - p2.X) + cd * (p1.X - p3.X) + ef * (p2.X - p1.X)) / (p1.Y * (p3.X - p2.X) + p2.Y * (p1.X - p3.X) + p3.Y * (p2.X - p1.X)) / 2.f; - circumCircleVertex = FVector2D(circum_x, circum_y); -} - -bool DelaunayTriangle::containsVertex(const FVector2D &v) -{ - return p1 == v || p2 == v || p3 == v; -} - -bool DelaunayTriangle::circumCircleContains(const FVector2D &v) -{ - float ab = (p1.X * p1.X) + (p1.Y * p1.Y); - float cd = (p2.X * p2.X) + (p2.Y * p2.Y); - float ef = (p3.X * p3.X) + (p3.Y * p3.Y); - float circum_x = (ab * (p3.Y - p2.Y) + cd * (p1.Y - p3.Y) + ef * (p2.Y - p1.Y)) / (p1.X * (p3.Y - p2.Y) + p2.X * (p1.Y - p3.Y) + p3.X * (p2.Y - p1.Y)) / 2.f; - float circum_y = (ab * (p3.X - p2.X) + cd * (p1.X - p3.X) + ef * (p2.X - p1.X)) / (p1.Y * (p3.X - p2.X) + p2.Y * (p1.X - p3.X) + p3.Y * (p2.X - p1.X)) / 2.f; - float circum_radius = sqrtf(((p1.X - circum_x) * (p1.X - circum_x)) + ((p1.Y - circum_y) * (p1.Y - circum_y))); - - float dist = sqrtf(((v.X - circum_x) * (v.X - circum_x)) + ((v.Y - circum_y) * (v.Y - circum_y))); - return dist <= circum_radius; -} diff --git a/Source/PolygonalMapGenerator/Private/Diagrams/Voronoi.cpp b/Source/PolygonalMapGenerator/Private/Diagrams/Voronoi.cpp deleted file mode 100644 index cb257fa..0000000 --- a/Source/PolygonalMapGenerator/Private/Diagrams/Voronoi.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* -* Copyright (c) 2012 by Joseph Marshall, Modified Work Copyright (c) 2016 Jay M Stevens -* -* Parts of this code were originally written by Steven Fortune. -* -* Permission to use, copy, modify, and distribute this software for any -* purpose without fee is hereby granted, provided that this entire notice -* is included in all copies of any software which is or includes a copy -* or modification of this software and in all copies of the supporting -* documentation for such software. -* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY -* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -*/ - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Diagrams/Voronoi.h" - -Voronoi::Voronoi(TArray &points) -{ - Delaunay triangulation; - std::vector triangles = triangulation.triangulate(points); - DelaunayData = triangulation; - MakeSites(triangles); -} - -Voronoi::Voronoi(Delaunay delaunay) -{ - DelaunayData = delaunay; - MakeSites(DelaunayData.getTriangles()); -} - -void Voronoi::MakeSites(std::vector triangles) -{ - for (auto t = begin(triangles); t != end(triangles); t++) - { - DelaunayTriangle tri = *t; - sites.Add(MakeSite(tri)); - } -} - -VSite Voronoi::MakeSite(DelaunayTriangle tri) -{ - VSite site; - - - bool bE1HasNeighbor = false; - bool bE2HasNeighbor = false; - bool bE3HasNeighbor = false; - FVector2D tri0Circum = tri.circumCircleVertex; - - for (auto d = begin(DelaunayData.getTriangles()); d != end(DelaunayData.getTriangles()); d++) - { - DelaunayTriangle tri2 = *d; - if (tri == tri2) - { - continue; - } - FVector2D tri1Circum = tri2.circumCircleVertex; - if (tri.e1 == tri2.e1 || tri.e1 == tri2.e2 || tri.e1 == tri2.e3) - { - bE1HasNeighbor = true; - VEdge edge; - edge.dEdge = FVector4(tri.e1.p1.X, tri.e1.p1.Y, tri.e1.p2.X, tri.e1.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, tri1Circum.X, tri1Circum.Y); - site.edges.Add(edge); - } - if (tri.e2 == tri2.e1 || tri.e2 == tri2.e2 || tri.e2 == tri2.e3) - { - bE2HasNeighbor = true; - VEdge edge; - edge.dEdge = FVector4(tri.e2.p1.X, tri.e2.p1.Y, tri.e2.p2.X, tri.e2.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, tri1Circum.X, tri1Circum.Y); - site.edges.Add(edge); - } - if (tri.e3 == tri2.e1 || tri.e3 == tri2.e2 || tri.e3 == tri2.e3) - { - bE3HasNeighbor = true; - VEdge edge; - edge.dEdge = FVector4(tri.e3.p1.X, tri.e3.p1.Y, tri.e3.p2.X, tri.e3.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, tri1Circum.X, tri1Circum.Y); - site.edges.Add(edge); - } - } - - if (!bE1HasNeighbor) - { - VEdge edge; - edge.dEdge = FVector4(tri.e1.p1.X, tri.e1.p1.Y, tri.e1.p2.X, tri.e1.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, INFINITY, INFINITY); - site.edges.Add(edge); - } - if (!bE2HasNeighbor) - { - VEdge edge; - edge.dEdge = FVector4(tri.e2.p1.X, tri.e2.p1.Y, tri.e2.p2.X, tri.e2.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, INFINITY, INFINITY); - site.edges.Add(edge); - } - if (!bE3HasNeighbor) - { - VEdge edge; - edge.dEdge = FVector4(tri.e3.p1.X, tri.e3.p1.Y, tri.e3.p2.X, tri.e3.p2.Y); - edge.vEdge = FVector4(tri0Circum.X, tri0Circum.Y, INFINITY, INFINITY); - site.edges.Add(edge); - } - return site; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/IO/MapTextureRenderer.cpp b/Source/PolygonalMapGenerator/Private/IO/MapTextureRenderer.cpp deleted file mode 100644 index c5108c8..0000000 --- a/Source/PolygonalMapGenerator/Private/IO/MapTextureRenderer.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Engine/Texture2D.h" -#include "Runtime/Engine/Public/TextureResource.h" -#include "HighResScreenshot.h" -#include "Kismet/KismetRenderingLibrary.h" -#include "Misc/Paths.h" -#include "MapTextureRenderer.h" - -/*bool UMapTextureRenderer::SaveTextureFromHeightmap(UPolygonalMapHeightmap* MapHeightmap, FString Filename) -{ - if (MapHeightmap->GetMapData().Num() == 0) - { - UE_LOG(LogTemp, Warning, TEXT("Did not create heightmap yet!")); - // Didn't generate heightmap yet - return false; - } - UE_LOG(LogTemp, Warning, TEXT("Attempting to generate map heightmap!")); - - uint32 dtWidth = MapHeightmap->HeightmapSize; - uint32 dtHeight = MapHeightmap->HeightmapSize; - uint32 pixelCount = dtWidth * dtHeight; - uint32 dtBytesPerPixel = 4; - uint32 dtBufferSize = dtWidth * dtHeight * dtBytesPerPixel; - uint32 dtBufferSizeSqrt = dtWidth * dtBytesPerPixel; - - TArray colors; - colors.SetNumZeroed(pixelCount); - - for (uint32 x = 0; x < dtWidth; x++) - { - for (uint32 y = 0; y < dtHeight; y++) - { - FMapData pointData = MapHeightmap->GetMapPoint(x, y); - colors[dtWidth * y + x] = FColor(uint8(pointData.Elevation * 255), uint8(pointData.Elevation * 255), uint8(pointData.Elevation * 255), 255); - } - } - - FIntPoint destSize(dtWidth, dtHeight); - FString resultPath; - FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig(); - - FString filePath = FPaths::Combine(FPaths::GameSavedDir(), Filename); - - return HighResScreenshotConfig.SaveImage(filePath, colors, destSize, &resultPath); -}*/ - -/*void UMapTextureRenderer::CreateTextureFromHeightmap(UPolygonalMapHeightmap* MapHeightmap, UTextureRenderTarget2D* IslandRenderTarget, UMaterialInstanceDynamic* IslandMaterialInstanceDynamic) -{ - if (MapHeightmap->GetMapData().Num() == 0) - { - UE_LOG(LogTemp, Warning, TEXT("Did not create heightmap yet!")); - // Didn't generate heightmap yet - return; - } - UE_LOG(LogTemp, Warning, TEXT("Attempting to generate map heightmap!")); - - uint32 dtWidth = MapHeightmap->HeightmapSize; - uint32 dtHeight = MapHeightmap->HeightmapSize; - - //IslandRenderTarget->bHDR = 0; - //IslandRenderTarget->InitAutoFormat(dtWidth, dtHeight); - //IslandRenderTarget->UpdateResource(); - UE_LOG(LogTemp, Log, TEXT("Set map render target!")); - - UTexture2D* dtTexture = UTexture2D::CreateTransient(dtWidth, dtHeight); - dtTexture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps; - dtTexture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap; - dtTexture->SRGB = 0; - dtTexture->AddToRoot(); // Guarantee no garbage collection by adding it as a root reference - dtTexture->UpdateResource(); // Update the texture with new variable values. - - int32 pixelCount = dtWidth * dtHeight; - - TArray colors; - colors.SetNumZeroed(pixelCount); - - for (uint32 x = 0; x < dtWidth; x++) - { - for (uint32 y = 0; y < dtHeight; y++) - { - FMapData pointData = MapHeightmap->GetMapPoint(x, y); - colors[dtWidth * y + x] = FColor(uint8(pointData.Elevation * 255), uint8(pointData.Elevation * 255), uint8(pointData.Elevation * 255), 255); - //colors[dtWidth * y + x] = FColor::Red; - } - } - - UE_LOG(LogTemp, Log, TEXT("Created colors!")); - - if (IslandMaterialInstanceDynamic) - { - UE_LOG(LogTemp, Warning, TEXT("Time to generate texture!")); - CreateTexture(dtTexture, colors); - UE_LOG(LogTemp, Log, TEXT("All done, setting the material instance.")); - IslandMaterialInstanceDynamic->SetTextureParameterValue(FName("DynamicTextureParam"), dtTexture); - - //UKismetRenderingLibrary::DrawMaterialToRenderTarget(this, IslandRenderTarget, dtMaterialInstanceDynamic); - } - else - { - UE_LOG(LogTemp, Error, TEXT("Could not initialize material instance!")); - } -} - -void UMapTextureRenderer::CreateTexture(UTexture2D* TargetTexture, TArray Colors) -{ - if (TargetTexture) - { - UE_LOG(LogTemp, Warning, TEXT("Target texture is valid.")); - - uint32 dtWidth = TargetTexture->GetSizeX(); - uint32 dtHeight = TargetTexture->GetSizeY(); - UE_LOG(LogTemp, Warning, TEXT("Got size!")); - - uint32 dtBytesPerPixel = 4; - - uint32 dtBufferSize = dtWidth * dtHeight * dtBytesPerPixel; - - UE_LOG(LogTemp, Log, TEXT("Color length: %d; Size of buffer: %d, Texture dimensions: %d x %d."), Colors.Num(), dtBufferSize, dtWidth, dtHeight); - if ((uint32)Colors.Num() > dtBufferSize) - { - UE_LOG(LogTemp, Error, TEXT("Buffer size too small!")); - return; - } - else if ((uint32)Colors.Num() * dtBytesPerPixel < dtBufferSize) - { - UE_LOG(LogTemp, Warning, TEXT("Not enough colors in buffer!")); - } - - uint32 dtBufferSizeSqrt = dtWidth * dtBytesPerPixel; - // This is the data that we Memcpy into the dynamic texture - uint8* dtBuffer = new uint8[dtBufferSize]; - FUpdateTextureRegion2D* updateTextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, dtWidth, dtHeight); - - for (int i = 0; i < Colors.Num(); i++) - { - int iBlue = i * 4 + 0; - int iGreen = i * 4 + 1; - int iRed = i * 4 + 2; - int iAlpha = i * 4 + 3; - - dtBuffer[iBlue] = Colors[i].B; - dtBuffer[iGreen] = Colors[i].G; - dtBuffer[iRed] = Colors[i].R; - dtBuffer[iAlpha] = Colors[i].A; - } - UE_LOG(LogTemp, Log, TEXT("Done parsing colors, moving on to updating region.")); - - UpdateTextureRegions(TargetTexture, 0, 1, updateTextureRegion, dtBufferSizeSqrt, dtBytesPerPixel, dtBuffer, false); - } - else - { - UE_LOG(LogTemp, Error, TEXT("Invalid texture!")); - } -} - -void UMapTextureRenderer::UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData) -{ - if (Texture && Texture->Resource && Regions) - { - struct FUpdateTextureRegionsData - { - FTexture2DResource* Texture2DResource; - int32 MipIndex; - uint32 NumRegions; - FUpdateTextureRegion2D* Regions; - uint32 SrcPitch; - uint32 SrcBpp; - uint8* SrcData; - }; - UE_LOG(LogTemp, Log, TEXT("Creating region data!")); - - FUpdateTextureRegionsData* RegionData = new FUpdateTextureRegionsData; - - RegionData->Texture2DResource = (FTexture2DResource*)Texture->Resource; - RegionData->MipIndex = MipIndex; - RegionData->NumRegions = NumRegions; - RegionData->Regions = Regions; - RegionData->SrcPitch = SrcPitch; - RegionData->SrcBpp = SrcBpp; - RegionData->SrcData = SrcData; - - UE_LOG(LogTemp, Log, TEXT("Handing off to the GPU!")); - - ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER( - UpdateTextureRegionsData, - FUpdateTextureRegionsData*, RegionData, RegionData, - bool, bFreeData, bFreeData, - { - for (uint32 RegionIndex = 0; RegionIndex < RegionData->NumRegions; ++RegionIndex) - { - int32 CurrentFirstMip = RegionData->Texture2DResource->GetCurrentFirstMip(); - if (RegionData->MipIndex >= CurrentFirstMip) - { - RHIUpdateTexture2D( - RegionData->Texture2DResource->GetTexture2DRHI(), - RegionData->MipIndex - CurrentFirstMip, - RegionData->Regions[RegionIndex], - RegionData->SrcPitch, - RegionData->SrcData - + RegionData->Regions[RegionIndex].SrcY * RegionData->SrcPitch - + RegionData->Regions[RegionIndex].SrcX * RegionData->SrcBpp - ); - } - } - if (bFreeData) - { - FMemory::Free(RegionData->Regions); - FMemory::Free(RegionData->SrcData); - } - delete RegionData; - }); - UE_LOG(LogTemp, Warning, TEXT("GPU is done creating texture!")); - } - else - { - UE_LOG(LogTemp, Error, TEXT("Attempted to access an invalid texture!")); - } -} - -bool UMapTextureRenderer::SaveTextureToDisk(UTexture2D* Texture, FString Filename) -{ - Texture->UpdateResource(); - FTexture2DMipMap* MM = &Texture->PlatformData->Mips[0]; - - TArray OutBMP; - int w = MM->SizeX; - int h = MM->SizeY; - - OutBMP.InsertZeroed(0, w*h); - - FByteBulkData* RawImageData = &MM->BulkData; - - FColor* FormatedImageData = static_cast(RawImageData->Lock(LOCK_READ_ONLY)); - - for (int i = 0; i < (w*h); ++i) - { - OutBMP[i] = FormatedImageData[i]; - OutBMP[i].A = 255; - } - - RawImageData->Unlock(); - FIntPoint DestSize(w, h); - - FString ResultPath; - FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig(); - return HighResScreenshotConfig.SaveImage(Filename, OutBMP, DestSize, &ResultPath); -}*/ \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/Biomes/BiomeManager.cpp b/Source/PolygonalMapGenerator/Private/Maps/Biomes/BiomeManager.cpp deleted file mode 100644 index 91eb70e..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Biomes/BiomeManager.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/MapDataHelper.h" -#include "BiomeManager.h" - -const FName UBiomeManager::BIOME_OceanTag = TEXT("MapData.Biome.Water.Ocean"); -const FName UBiomeManager::BIOME_CoastTag = TEXT("MapData.Biome.Coast"); - -// Sets default values for this component's properties -UBiomeManager::UBiomeManager() -{ - // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features - // off to improve performance if you don't need them. - PrimaryComponentTick.bCanEverTick = false; - - // By default, we only assign two kinds of biomes: ocean and coast - // To add more, override this class and add them by hand - FBiome oceanBiome; - oceanBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_OceanTag); - oceanBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); - Biomes.Add(oceanBiome); - - FBiome coastalBiome; - coastalBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_CoastTag); - coastalBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Coast"))); - Biomes.Add(coastalBiome); -} - -FGameplayTag UBiomeManager::DetermineBiome_Implementation(const FMapData& MapData) -{ - //UE_LOG(LogWorldGen, Warning, TEXT("Beginning new point: %f, %f"), MapData.Point.X, MapData.Point.Y); - for (int i = 0; i < Biomes.Num(); i++) - { - if (!Biomes[i].BiomeTag.IsValid()) - { - UE_LOG(LogWorldGen, Error, TEXT("Biome number %d in the biome generator has an invalid tag!"), i); - continue; - } - // If we don't allow snow and this is a frozen biome, continue - if (!bAllowSnow && Biomes[i].BiomeTag.MatchesTag(FGameplayTag::RequestGameplayTag(TEXT("MapData.Biome.Frozen")))) - { - //UE_LOG(LogWorldGen, Log, TEXT("Passing on %s because we don't allow snow."), *Biomes[i].BiomeTag.ToString()); - continue; - } - - // Verify that the biome is in the right elevation with the right moisture level - if (MapData.Elevation > Biomes[i].MaxElevation || MapData.Elevation < Biomes[i].MinElevation || - MapData.Moisture > Biomes[i].MaxMoisture || MapData.Moisture < Biomes[i].MinMoisture) - { - continue; - } - - // Verify that the biome has the required tags - bool bHasRequiredTags = Biomes[i].RequiredTags.Num() == 0; - - if(!bHasRequiredTags) - { - // Reset the required tags flag - bHasRequiredTags = true; - // Iterate over all required tags and see if we have them all - for (int j = 0; j < Biomes[i].RequiredTags.Num(); j++) - { - if (!UMapDataHelper::HasTag(MapData, Biomes[i].RequiredTags.GetByIndex(j))) - { - // We're missing one, so we need to move on - - //UE_LOG(LogWorldGen, Log, TEXT("Passing on %s because the map data struct is missing the tag %s."), *Biomes[i].BiomeTag.ToString(), *Biomes[i].RequiredTags.GetByIndex(j).ToString()); - bHasRequiredTags = false; - break; - } - } - } - if (bHasRequiredTags) - { - //UE_LOG(LogWorldGen, Warning, TEXT("Selected biome %s!"), *Biomes[i].BiomeTag.ToString()); - return Biomes[i].BiomeTag; - } - } - UE_LOG(LogWorldGen, Warning, TEXT("A MapData point was missing a biome! Point: (%f, %f); Elevation: %f; Moisture: %f"), MapData.Point.X, MapData.Point.Y, MapData.Elevation, MapData.Moisture); - return FGameplayTag::EmptyTag; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/Biomes/WhittakerBiomeManager.cpp b/Source/PolygonalMapGenerator/Private/Maps/Biomes/WhittakerBiomeManager.cpp deleted file mode 100644 index 8f434c8..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Biomes/WhittakerBiomeManager.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2017 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "WhittakerBiomeManager.h" - -const FName UWhittakerBiomeManager::BIOME_IceTag = TEXT("MapData.Biome.Frozen.Ice"); -const FName UWhittakerBiomeManager::BIOME_MarshTag = TEXT("MapData.Biome.Water.Marsh"); -const FName UWhittakerBiomeManager::BIOME_LakeTag = TEXT("MapData.Biome.Water.Lake"); -const FName UWhittakerBiomeManager::BIOME_SnowTag = TEXT("MapData.Biome.Frozen.Snow"); -const FName UWhittakerBiomeManager::BIOME_TundraTag = TEXT("MapData.Biome.Frozen.Tundra"); -const FName UWhittakerBiomeManager::BIOME_BareTag = TEXT("MapData.Biome.Bare"); -const FName UWhittakerBiomeManager::BIOME_ScorchedTag = TEXT("MapData.Biome.Scorched"); -const FName UWhittakerBiomeManager::BIOME_TaigaTag = TEXT("MapData.Biome.Frozen.Taiga"); -const FName UWhittakerBiomeManager::BIOME_ShrublandTag = TEXT("MapData.Biome.Shrubland"); -const FName UWhittakerBiomeManager::BIOME_TemperateDesertTag = TEXT("MapData.Biome.TemperateDesert"); -const FName UWhittakerBiomeManager::BIOME_TemperateRainForestTag = TEXT("MapData.Biome.TemperateRainForest"); -const FName UWhittakerBiomeManager::BIOME_TemperateDeciduousForestTag = TEXT("MapData.Biome.TemperateDeciduousForest"); -const FName UWhittakerBiomeManager::BIOME_GrasslandTag = TEXT("MapData.Biome.Grassland"); -const FName UWhittakerBiomeManager::BIOME_TropicalRainForestTag = TEXT("MapData.Biome.TropicalRainForest"); -const FName UWhittakerBiomeManager::BIOME_TropicalSeasonalForestTag = TEXT("MapData.Biome.TropicalSeasonalForest"); -const FName UWhittakerBiomeManager::BIOME_SubtropicalDesertTag = TEXT("MapData.Biome.SubtropicalDesert"); - -UWhittakerBiomeManager::UWhittakerBiomeManager() -{ - Biomes.Empty(); - - FBiome oceanBiome; - oceanBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_OceanTag); - oceanBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); - Biomes.Add(oceanBiome); - BiomeEnumMap.Add(oceanBiome.BiomeTag, EWhittakerBiome::Ocean); - - FBiome iceBiome; - iceBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_IceTag); - iceBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); - iceBiome.MinElevation = 0.75f; - Biomes.Add(iceBiome); - BiomeEnumMap.Add(iceBiome.BiomeTag, EWhittakerBiome::Ice); - - FBiome marshBiome; - marshBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_MarshTag); - marshBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); - marshBiome.MaxElevation = 0.25f; - Biomes.Add(marshBiome); - BiomeEnumMap.Add(marshBiome.BiomeTag, EWhittakerBiome::Marsh); - - FBiome lakeBiome; - lakeBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_LakeTag); - lakeBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); - lakeBiome.MinElevation = 0.25f; - lakeBiome.MaxElevation = 0.75f; - Biomes.Add(lakeBiome); - BiomeEnumMap.Add(lakeBiome.BiomeTag, EWhittakerBiome::Lake); - - FBiome coastalBiome; - coastalBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_CoastTag); - coastalBiome.RequiredTags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Coast"))); - Biomes.Add(coastalBiome); - BiomeEnumMap.Add(coastalBiome.BiomeTag, EWhittakerBiome::Coast); - - FBiome snowBome; - snowBome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_SnowTag); - snowBome.MinElevation = 0.75f; - snowBome.MinMoisture = 0.5f; - Biomes.Add(snowBome); - BiomeEnumMap.Add(snowBome.BiomeTag, EWhittakerBiome::Snow); - - FBiome tundraBiome; - tundraBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TundraTag); - tundraBiome.MinElevation = 0.75f; - tundraBiome.MaxMoisture = 0.5f; - tundraBiome.MinMoisture = 0.33f; - Biomes.Add(tundraBiome); - BiomeEnumMap.Add(tundraBiome.BiomeTag, EWhittakerBiome::Tundra); - - FBiome bareBiome; - bareBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_BareTag); - bareBiome.MinElevation = 0.75f; - bareBiome.MinMoisture = 0.16f; - Biomes.Add(bareBiome); - BiomeEnumMap.Add(bareBiome.BiomeTag, EWhittakerBiome::Bare); - - FBiome scorchedBiome; - scorchedBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_ScorchedTag); - scorchedBiome.MinElevation = 0.75f; - scorchedBiome.MaxMoisture = 0.16f; - Biomes.Add(scorchedBiome); - BiomeEnumMap.Add(scorchedBiome.BiomeTag, EWhittakerBiome::Scorched); - - FBiome taigaBiome; - taigaBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TaigaTag); - taigaBiome.MaxElevation = 0.75f; - taigaBiome.MinElevation = 0.5f; - taigaBiome.MinMoisture = 0.66f; - Biomes.Add(taigaBiome); - BiomeEnumMap.Add(taigaBiome.BiomeTag, EWhittakerBiome::Taiga); - - FBiome shrublandBiome; - shrublandBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_ShrublandTag); - shrublandBiome.MaxElevation = 0.75f; - shrublandBiome.MinElevation = 0.5f; - shrublandBiome.MinMoisture = 0.33f; - Biomes.Add(shrublandBiome); - BiomeEnumMap.Add(shrublandBiome.BiomeTag, EWhittakerBiome::Shrubland); - - FBiome temperateDesertBiomeLow; - temperateDesertBiomeLow.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TemperateDesertTag); - temperateDesertBiomeLow.MaxElevation = 0.5f; - temperateDesertBiomeLow.MinElevation = 0.25f; - temperateDesertBiomeLow.MaxMoisture = 0.16f; - Biomes.Add(temperateDesertBiomeLow); - BiomeEnumMap.Add(temperateDesertBiomeLow.BiomeTag, EWhittakerBiome::TemperateDesert); - - FBiome temperateDesertBiomeHigh; - temperateDesertBiomeHigh.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TemperateDesertTag); - temperateDesertBiomeHigh.MaxElevation = 0.75f; - temperateDesertBiomeHigh.MinElevation = 0.5f; - temperateDesertBiomeHigh.MaxMoisture = 0.33f; - Biomes.Add(temperateDesertBiomeHigh); - - FBiome temperateRainForestBiome; - temperateRainForestBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TemperateRainForestTag); - temperateRainForestBiome.MaxElevation = 0.5f; - temperateRainForestBiome.MinElevation = 0.25f; - temperateRainForestBiome.MinMoisture = 0.83f; - Biomes.Add(temperateRainForestBiome); - BiomeEnumMap.Add(temperateRainForestBiome.BiomeTag, EWhittakerBiome::TemperateRainForest); - - FBiome temperateDeciduousForestBiome; - temperateDeciduousForestBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TemperateDeciduousForestTag); - temperateDeciduousForestBiome.MaxElevation = 0.5f; - temperateDeciduousForestBiome.MinElevation = 0.25f; - temperateDeciduousForestBiome.MaxMoisture = 0.83f; - temperateDeciduousForestBiome.MinMoisture = 0.5f; - Biomes.Add(temperateDeciduousForestBiome); - BiomeEnumMap.Add(temperateDeciduousForestBiome.BiomeTag, EWhittakerBiome::TemperateDeciduousForest); - - FBiome grasslandBiomeHigh; - grasslandBiomeHigh.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_GrasslandTag); - grasslandBiomeHigh.MaxElevation = 0.5f; - grasslandBiomeHigh.MinElevation = 0.25f; - grasslandBiomeHigh.MaxMoisture = 0.5f; - grasslandBiomeHigh.MinMoisture = 0.16f; - Biomes.Add(grasslandBiomeHigh); - BiomeEnumMap.Add(grasslandBiomeHigh.BiomeTag, EWhittakerBiome::Grassland); - - FBiome grasslandBiomeLow; - grasslandBiomeLow.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_GrasslandTag); - grasslandBiomeLow.MaxElevation = 0.25f; - grasslandBiomeLow.MaxMoisture = 0.33f; - grasslandBiomeLow.MinMoisture = 0.16f; - Biomes.Add(grasslandBiomeLow); - - FBiome tropicalRainForestBiome; - tropicalRainForestBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TropicalRainForestTag); - tropicalRainForestBiome.MaxElevation = 0.25f; - tropicalRainForestBiome.MinMoisture = 0.66f; - Biomes.Add(tropicalRainForestBiome); - BiomeEnumMap.Add(tropicalRainForestBiome.BiomeTag, EWhittakerBiome::TropicalRainForest); - - FBiome tropicalSeasonalForestBiome; - tropicalSeasonalForestBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_TropicalSeasonalForestTag); - tropicalSeasonalForestBiome.MaxElevation = 0.25f; - tropicalSeasonalForestBiome.MaxMoisture = 0.66f; - tropicalSeasonalForestBiome.MinMoisture = 0.33f; - Biomes.Add(tropicalSeasonalForestBiome); - BiomeEnumMap.Add(tropicalSeasonalForestBiome.BiomeTag, EWhittakerBiome::TropicalSeasonalForest); - - FBiome subtropicalDesertBiome; - subtropicalDesertBiome.BiomeTag = FGameplayTag::RequestGameplayTag(BIOME_SubtropicalDesertTag); - subtropicalDesertBiome.MaxElevation = 0.25f; - subtropicalDesertBiome.MaxMoisture = 0.33f; - Biomes.Add(subtropicalDesertBiome); - BiomeEnumMap.Add(subtropicalDesertBiome.BiomeTag, EWhittakerBiome::SubtropicalDesert); -} - -EWhittakerBiome UWhittakerBiomeManager::ConvertToWhittakerBiomeEnum(const FGameplayTag& BiomeName) -{ - if (!BiomeName.IsValid()) - { - UE_LOG(LogWorldGen, Error, TEXT("Invalid biome! Defaulting to ocean.")); - return EWhittakerBiome::Ocean; - } - if (BiomeEnumMap.Contains(BiomeName)) - { - return BiomeEnumMap[BiomeName]; - } - else - { - UE_LOG(LogWorldGen, Warning, TEXT("Could not find biome for %s!"), *BiomeName.ToString()); - return EWhittakerBiome::Ocean; - } -} - -EWhittakerBiome UWhittakerBiomeManager::LookupWhittakerBiome(const FMapData& MapData) -{ - return ConvertToWhittakerBiomeEnum(MapData.Biome); -} - -EWhittakerBiome UWhittakerBiomeManager::WhittakerBiomeFromGraphPoint(UPolygonMap* MapGraph, const FVector2D& GraphPoint) -{ - FMapCenter center = MapGraph->FindMapCenterForCoordinate(GraphPoint); - if (center.Index < 0) - { - // Invalid center, probably out of bounds - return EWhittakerBiome::Ocean; - } - return ConvertToWhittakerBiomeEnum(center.CenterData.Biome); -} - -EWhittakerBiome UWhittakerBiomeManager::WhittakerBiomeFromWorldPoint(UPolygonMap* MapGraph, const FVector& WorldPoint) -{ - FVector2D graphPoint = MapGraph->ConvertWorldPointToGraphSpace(WorldPoint); - return WhittakerBiomeFromGraphPoint(MapGraph, graphPoint); -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/Elevations/ElevationDistributor.cpp b/Source/PolygonalMapGenerator/Private/Maps/Elevations/ElevationDistributor.cpp deleted file mode 100644 index 48954cc..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Elevations/ElevationDistributor.cpp +++ /dev/null @@ -1,240 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/IslandShapes/IslandShape.h" -#include "MapDataHelper.h" -#include "Maps/Elevations/ElevationDistributor.h" - - -void UElevationDistributor::SetGraph(UPolygonMap* graph) -{ - MapGraph = graph; -} - -void UElevationDistributor::AssignCornerElevations(UIslandShape* islandShape, bool bneedsMoreRandomness, FRandomStream& randomGenerator) -{ - TQueue cornerQueue; - - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - if (islandShape->IsPointLand(corner.CornerData.Point)) - { - corner.CornerData = UMapDataHelper::RemoveOcean(corner.CornerData); - } - else - { - corner.CornerData = UMapDataHelper::SetOcean(corner.CornerData); - } - - if (UMapDataHelper::IsBorder(corner.CornerData) || UMapDataHelper::IsWater(corner.CornerData)) - { - // The borders are the "base" of our map, and will have the lowest elevation - // As we expand the queue in the next loop, we will move towards the center - corner.CornerData.Elevation = 0.0f; - cornerQueue.Enqueue(i); - } - else - { - // Set any other corners to a high elevation so we can easily detect changes - // This will be rescaled later - corner.CornerData.Elevation = 100.0f; - } - MapGraph->UpdateCorner(corner); - } - - float queueOffsetAmount = 0.0f; - while (!cornerQueue.IsEmpty()) - { - int32 cornerIndex; - cornerQueue.Dequeue(cornerIndex); - FMapCorner corner = MapGraph->GetCorner(cornerIndex); - - for (int i = 0; i < corner.Adjacent.Num(); i++) - { - FMapCorner adjacent = MapGraph->GetCorner(corner.Adjacent[i]); - float newElevation = 0.1f + corner.CornerData.Elevation; - //newElevation += queueOffsetAmount; - if (!UMapDataHelper::IsWater(corner.CornerData) && !UMapDataHelper::IsWater(adjacent.CornerData)) - { - newElevation += 1.0f; - - // HACK: the map looks nice because of randomness of - // points, randomness of rivers, and randomness of - // edges. Without random point selection, I needed to - // inject some more randomness to make maps look - // nicer. I'm doing it here, with elevations, but I - // think there must be a better way. This hack is only - // used with square/hexagon grids. - if (bneedsMoreRandomness) - { - newElevation += randomGenerator.GetFraction(); - } - } - - // If this point changed, we'll add it to the queue so - // that we can process its neighbors too. This makes - // it so the middle regions have the highest elevation. - if (newElevation < adjacent.CornerData.Elevation) - { - adjacent.CornerData.Elevation = newElevation; - cornerQueue.Enqueue(adjacent.Index); - } - - MapGraph->UpdateCorner(adjacent); - } - - queueOffsetAmount += 0.05f; - } -} - -void UElevationDistributor::CalculateDownslopes() -{ - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - int32 downslopeIndex = corner.Index; - for (int j = 0; j < corner.Adjacent.Num(); j++) - { - FMapCorner adjacent = MapGraph->GetCorner(corner.Adjacent[j]); - if (adjacent.CornerData.Elevation <= MapGraph->GetCorner(downslopeIndex).CornerData.Elevation) - { - downslopeIndex = adjacent.Index; - } - } - corner.Downslope = downslopeIndex; - MapGraph->UpdateCorner(corner); - } -} - -void UElevationDistributor::RedistributeElevations(TArray landCorners) -{ - TArray mapCorners; - - for (int i = 0; i < landCorners.Num(); i++) - { - mapCorners.Add(MapGraph->GetCorner(landCorners[i])); - } - - // Sort by elevation - mapCorners.HeapSort(); - - float maxElevation = -1.0f; - for (int i = 0; i < mapCorners.Num(); i++) - { - // Let y(x) be the total area that we want at elevation <= x. - // We want the higher elevations to occur less than lower - // ones, and set the area to be y(x) = 1 - (1-x)^2. - float y = i / (mapCorners.Num() - 1.0f); - // Since the data is sorted by elevation, this will linearly increase the elevation as the loop goes on. - float x = FMath::Sqrt(1.1f) - FMath::Sqrt(1.1f * (1.0f - y)); - if (x > maxElevation) - { - maxElevation = x; - } - FMapCorner corner = MapGraph->GetCorner(mapCorners[i].Index); - corner.CornerData.Elevation = x; - MapGraph->UpdateCorner(corner); - } - - // Now we normalize all the elevations relative to the largest elevation we have - // This places all elevations between 0 and 1 - for (int i = 0; i < mapCorners.Num(); i++) - { - FMapCorner corner = MapGraph->GetCorner(mapCorners[i].Index); - corner.CornerData.Elevation /= maxElevation; - MapGraph->UpdateCorner(corner); - } -} - -void UElevationDistributor::FlattenWaterElevations() -{ - TArray processedCorners; - processedCorners.SetNumZeroed(MapGraph->GetCornerNum()); - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - if (processedCorners[i]) - { - // Already finished this corner - continue; - } - - FMapCorner corner = MapGraph->GetCorner(i); - if (UMapDataHelper::IsOcean(corner.CornerData)) - { - corner.CornerData.Elevation = 0.0f; - MapGraph->UpdateCorner(corner); - processedCorners[i] = true; - } - /*else if (UMapDataHelper::IsFreshwater(corner.CornerData)) - { - float currentElevation = corner.CornerData.Elevation; - - TArray waterBiomeCorners; - TArray toProcess; - toProcess.Add(corner); - - while(toProcess.Num() > 0) - { - FMapCorner current = toProcess[0]; - toProcess.RemoveAt(0); - - // Keep track of all corners in this biome - waterBiomeCorners.Add(current); - - // Iterate over all the adjacent corners - for (int j = 0; j < current.Adjacent.Num(); j++) - { - // Check to see if we've already processed this neighbor - if (processedCorners[current.Adjacent[j]]) - { - // Already processed - continue; - } - - FMapCorner neighbor = MapGraph->GetCorner(current.Adjacent[j]); - if (!UMapDataHelper::IsFreshwater(neighbor.CornerData)) - { - // Ignore non-water corners - continue; - } - - // Minimum elevation is given by the minimum of the current elevation vs. this neighbor's elevation - // This will give us a flat water level - currentElevation = FMath::Min(currentElevation, neighbor.CornerData.Elevation); - // Add the neighbor to the process list to process its neighbors - toProcess.Add(neighbor); - - // Mark the processing on this corner as done - processedCorners[current.Adjacent[j]] = true; - } - } - - // Done finding all the corners to process for this biome - // We also found the water level we're aiming for - // Now we need to give that water level to all corners in the biome - for (int j = 0; j < waterBiomeCorners.Num(); j++) - { - waterBiomeCorners[j].CornerData.Elevation = currentElevation; - MapGraph->UpdateCorner(waterBiomeCorners[j]); - } - }*/ - } -} - -void UElevationDistributor::AssignPolygonElevations() -{ - for (int i = 0; i < MapGraph->GetCenterNum(); i++) - { - float sumElevation = 0.0f; - FMapCenter center = MapGraph->GetCenter(i); - for (int32 j = 0; j < center.Corners.Num(); j++) - { - FMapCorner corner = MapGraph->GetCorner(center.Corners[j]); - sumElevation += corner.CornerData.Elevation; - } - float elevation = sumElevation / center.Corners.Num(); - center.CenterData.Elevation = elevation; - MapGraph->UpdateCenter(center); - } -} diff --git a/Source/PolygonalMapGenerator/Private/Maps/Elevations/SimplexNoiseElevationDistributor.cpp b/Source/PolygonalMapGenerator/Private/Maps/Elevations/SimplexNoiseElevationDistributor.cpp deleted file mode 100644 index 5544616..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Elevations/SimplexNoiseElevationDistributor.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/MapDataHelper.h" -#include "SimplexNoiseElevationDistributor.h" - -USimplexNoiseElevationDistributor::USimplexNoiseElevationDistributor() -{ - NoiseSettings.NoiseOctaves = 16; - NoiseSettings.NoiseType = ENoiseType::Simplex; -} - -void USimplexNoiseElevationDistributor::AssignCornerElevations(UIslandShape* islandShape, bool bneedsMoreRandomness, FRandomStream& randomGenerator) -{ - int32 islandSize = islandShape->Size; - - PolygonalMapGenNoise noise; - NoiseSettings.Seed = randomGenerator.GetCurrentSeed(); - noise.SetNoiseSettings(NoiseSettings); - - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - /*noise.SetPersistence(0.5f); - noise.SetScale(scale); - noise.SetBounds(-0.25f, 1.0f);*/ - - float gradient = GetGradient(corner.CornerData.Point.X, corner.CornerData.Point.Y, islandSize); - - float noiseValue = noise.GetNoise(corner.CornerData.Point.X * NoiseScale, corner.CornerData.Point.Y * NoiseScale); - UE_LOG(LogTemp, Log, TEXT("Noise value: %f"), noiseValue); - // Multiply by the inverse gradient several times to put a stronger bias in the center - noiseValue *= gradient; - - corner.CornerData = UMapDataHelper::RemoveCoast(corner.CornerData); - - if (noiseValue < OceanThreshold) - { - corner.CornerData = UMapDataHelper::SetOcean(corner.CornerData); - } - else if(!UMapDataHelper::IsBorder(corner.CornerData)) - { - corner.CornerData = UMapDataHelper::RemoveOcean(corner.CornerData); - } - - corner.CornerData.Elevation = noiseValue; - MapGraph->UpdateCorner(corner); - } -} - -/*void USimplexNoiseElevationDistributor::AssignOceanCoastAndLand(float lakeThreshold) -{ - -}*/ - -void USimplexNoiseElevationDistributor::RedistributeElevations(TArray landCorners) -{ - -} - -float USimplexNoiseElevationDistributor::GetGradient(float XCoord, float YCoord, int32 IslandSize) const -{ - if (GradientIterations <= 0) - { - return 1.0f; - } - float distanceX = FMath::Abs(XCoord - IslandSize * 0.5f); - float distanceY = FMath::Abs(YCoord - IslandSize * 0.5f); - float distance = FMath::Sqrt(distanceX * distanceX + distanceY * distanceY); // circular mask - - float maxWidth = IslandSize * 0.5f - 10.0f; - float delta = distance / maxWidth; - float gradient = delta * delta; - - float inverseGradient = FMath::Max(0.0f, 1.0f - gradient); - - gradient = 1.0f; - for (int i = 0; i < GradientIterations; i++) - { - gradient *= inverseGradient; - } - return gradient; -} - -/*void USimplexNoiseElevationDistributor::FlattenWaterElevations() -{ - -}*/ diff --git a/Source/PolygonalMapGenerator/Private/Maps/Heightmap/HeightmapPointTask.cpp b/Source/PolygonalMapGenerator/Private/Maps/Heightmap/HeightmapPointTask.cpp deleted file mode 100644 index 7c86381..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Heightmap/HeightmapPointTask.cpp +++ /dev/null @@ -1,333 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "PolygonalMapHeightmap.h" -#include "Async/Async.h" -#include "Maps/Heightmap/HeightmapPointTask.h" - -// The heightmap generator -UPolygonalMapHeightmap* FHeightmapPointGenerator::MapHeightmap = NULL; -UPolygonMap* FHeightmapPointGenerator::MapGraph = NULL; -UBiomeManager* FHeightmapPointGenerator::BiomeManager = NULL; - -// Results of the threads -TArray FHeightmapPointGenerator::HeightmapData = TArray(); -TArray FHeightmapPointGenerator::StartingMapDataArray = TArray(); - -// This is the array of thread completions, used to determine if all threads are done -FGraphEventArray FHeightmapPointGenerator::CompletionEvents = FGraphEventArray(); -int32 FHeightmapPointGenerator::CompletedThreads = 0; -int32 FHeightmapPointGenerator::TotalNumberOfThreads = 0; - -FIslandGeneratorDelegate FHeightmapPointGenerator::OnAllPointsComplete; - -bool FHeightmapPointGenerator::TasksAreComplete() -{ - //Check all thread completion events - return CompletedThreads == TotalNumberOfThreads; -} - -void FHeightmapPointGenerator::GenerateHeightmapPoints(const int32 HeightmapSize, int32 NumberOfPointsToAverage, UPolygonalMapHeightmap* HeightmapGenerator, UPolygonMap* Graph, UBiomeManager* BiomeMgr, const FIslandGeneratorDelegate OnComplete) -{ - MapHeightmap = HeightmapGenerator; - MapGraph = Graph; - BiomeManager = BiomeMgr; - OnAllPointsComplete = OnComplete; - - TotalNumberOfThreads = 0; - CompletedThreads = 0; - HeightmapData.Empty(); - - StartingMapDataArray = FHeightmapPointGenerator::MapGraph->GetAllMapData(); - - EPointSelectionMode pointSelectionMode = EPointSelectionMode::InterpolatedWithPolygonBiome; - - if (pointSelectionMode == EPointSelectionMode::Interpolated || pointSelectionMode == EPointSelectionMode::InterpolatedWithPolygonBiome) - { - int32 graphSize = FHeightmapPointGenerator::MapGraph->GetGraphSize(); - // First, insert a border around the map - for (int x = 0; x < graphSize; x++) - { - FMapData borderPoint = FMapData(); - borderPoint.Elevation = 0.0f; - borderPoint.Moisture = 0.0f; - borderPoint = UMapDataHelper::SetOcean(borderPoint); - borderPoint = UMapDataHelper::SetBorder(borderPoint); - borderPoint.Point = FVector2D(x, 0); - StartingMapDataArray.Add(borderPoint); - borderPoint.Point = FVector2D(x, graphSize - 1); - StartingMapDataArray.Add(borderPoint); - } - for (int y = 0; y < graphSize; y++) - { - FMapData borderPoint = FMapData(); - borderPoint.Elevation = 0.0f; - borderPoint.Moisture = 0.0f; - borderPoint = UMapDataHelper::SetOcean(borderPoint); - borderPoint = UMapDataHelper::SetBorder(borderPoint); - borderPoint.Point = FVector2D(0, y); - StartingMapDataArray.Add(borderPoint); - borderPoint.Point = FVector2D(graphSize - 1, y); - StartingMapDataArray.Add(borderPoint); - } - } - - // Add a task for each prime number - for (int32 x = 0; x < HeightmapSize; x++) - { - for(int32 y = 0; y < HeightmapSize; y++) - { - CompletionEvents.Add(TGraphTask::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(x, y, NumberOfPointsToAverage, pointSelectionMode)); - TotalNumberOfThreads++; - } - } -} - -void FHeightmapPointGenerator::CheckComplete() -{ - if(TasksAreComplete()) - { - FHeightmapPointGenerator::TotalNumberOfThreads = 0; - FHeightmapPointGenerator::CompletedThreads = 0; - - UE_LOG(LogWorldGen, Log, TEXT("Heightmap is complete!")); - - // Call the delegate on the game thread - AsyncTask(ENamedThreads::GameThread, []() { - OnAllPointsComplete.Execute(); - OnAllPointsComplete.Unbind(); - }); - } -} - -FMapData FHeightmapPointTask::MakeMapPoint(FVector2D PixelPosition, UPolygonMap* MapGraph, UBiomeManager* BiomeManager) -{ - /*if (PointSelectionMode == Interpolated || PointSelectionMode == InterpolatedWithPolygonBiome) - { - TArray closestPoints; - // Iterate over the entire mapData array to find how many points we need to average - for (int i = 0; i < MapData.Num(); i++) - { - if (closestPoints.Num() == 0) - { - closestPoints.Add(MapData[i]); - continue; - } - float distance = FVector2D::DistSquared(PixelPosition, MapData[i].Point); - if (distance <= 0.001f) - { - // Close enough - pixelData = MapData[i]; - return pixelData; - } - - // This will hold the index of first point we find that's further away than our point - int addPointIndex = -1; - for (int j = 0; j < closestPoints.Num(); j++) - { - // Get the distance of this point - float pointDist = FVector2D::DistSquared(PixelPosition, closestPoints[j].Point); - if (distance < pointDist) - { - addPointIndex = j; - break; - } - } - - // If we found a point that's further away than our point, place it in the array and move everything else down - if (addPointIndex >= 0) - { - FMapData last = MapData[i]; - for (int j = addPointIndex; j < closestPoints.Num(); j++) - { - FMapData temp = closestPoints[j]; - closestPoints[j] = last; - last = temp; - } - // If we are below the number of points we need to add, then add the furthest point to the end - if (closestPoints.Num() < NumberOfPointsToAverage) - { - closestPoints.Add(last); - } - } - else if (closestPoints.Num() < NumberOfPointsToAverage) - { - closestPoints.Add(MapData[i]); - } - } - - // Cache the distances - TArray closestPointDistances; - float totalDistance = 0.0f; - for (int i = 0; i < closestPoints.Num(); i++) - { - float distance = FVector2D::DistSquared(PixelPosition, closestPoints[i].Point); - totalDistance += distance; - closestPointDistances.Add(distance); - } - - float inversePercentageTotal = 0.0f; - - for (int i = 0; i < closestPoints.Num(); i++) - { - // Get the total percentage that this point contributed to the overall distance - float percentageOfDistance = closestPointDistances[i] / totalDistance; - - // Take the inverse of the distance percentage -- points which are closer get a larger weight - float inversePercentage = 1.0f - percentageOfDistance; - - // We re-add the inverse percentage to the array so we can make sure it all totals up to 1 - closestPointDistances[i] = inversePercentage; - inversePercentageTotal += inversePercentage; - } - - // Now gather the weighted distance for each point - TArray> pointWeights; - for (int i = 0; i < closestPoints.Num(); i++) - { - TPair weight; - weight.Key = closestPoints[i]; - weight.Value = closestPointDistances[i] / inversePercentageTotal; - pointWeights.Add(weight); - } - - float elevation = 0.0f; - float moisture = 0.0f; - - TMap tagWeights; - - for (int i = 0; i < pointWeights.Num(); i++) - { - FMapData curPoint = pointWeights[i].Key; - float weight = pointWeights[i].Value; - - elevation += (curPoint.Elevation * weight); - moisture += (curPoint.Moisture * weight); - - if(PointSelectionMode == EPointSelectionMode::Interpolated) - { - for (int j = 0; j < curPoint.Tags.Num(); j++) - { - FGameplayTag tag = curPoint.Tags.GetByIndex(i); - if (tag.MatchesTag(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.River")))) - { - // Rivers are handled later - continue; - } - float currentTagWeight = tagWeights.FindOrAdd(tag); - currentTagWeight += weight; - tagWeights[tag] = currentTagWeight; - } - } - } - pixelData.Elevation = elevation; - pixelData.Moisture = moisture; - pixelData.Point = PixelPosition; - if (PointSelectionMode == EPointSelectionMode::Interpolated) - { - pixelData.Tags.Reset(); - for (auto& elem : tagWeights) - { - if (elem.Value >= 0.5f) - { - pixelData.Tags.AddTagFast(elem.Key); - } - } - // Right now, this sometimes causes a crash - // TODO: Find out why it crashes (maybe due to multithreading?) - // In the meantime, use EPointSelectionMode::InterpolatedWithPolygonBiome instead - pixelData.Biome = BiomeManager->DetermineBiome(pixelData); - } - else if(PointSelectionMode == EPointSelectionMode::InterpolatedWithPolygonBiome) - { - FMapCenter center = FHeightmapPointGenerator::MapGraph->FindMapCenterForCoordinate(PixelPosition); - if (center.Index < 0) - { - //UE_LOG(LogWorldGen, Warning, TEXT("Could not find polygon! Returning what we have.")); - return pixelData; - } - pixelData.Tags = center.CenterData.Tags; - pixelData.Biome = center.CenterData.Biome; - } - return pixelData; - } - else if(PointSelectionMode == EPointSelectionMode::UsePolygon) - { - FMapCenter center = FHeightmapPointGenerator::MapGraph->FindMapCenterForCoordinate(PixelPosition); - if (center.Index < 0) - { - //UE_LOG(LogWorldGen, Warning, TEXT("Could not find polygon! Returning blank FMapData!")); - return FMapData(); - } - - pixelData = center.CenterData; - pixelData.Point = PixelPosition; - return pixelData; - } - else - { - // Should never get to this point - unimplemented(); - return FMapData(); - }*/ - - FMapData pixelData = FMapData(); - pixelData.Point = PixelPosition; - - FMapCorner triangleCenter; - float pointZPostion = MapGraph->CalculateZPosition(PixelPosition, triangleCenter); - if (triangleCenter.Index >= 0) - { - // The point is valid, populate from the triangle - pixelData.Elevation = pointZPostion; - if (PointSelectionMode == EPointSelectionMode::UsePolygon) - { - pixelData.Moisture = triangleCenter.CornerData.Moisture; - pixelData.Tags = triangleCenter.CornerData.Tags; - pixelData.Biome = triangleCenter.CornerData.Biome; - } - else - { - pixelData.Moisture = MapGraph->InterpolateMapDataMoisture(MapGraph->GetCenter(triangleCenter.Touches[0]).CenterData, MapGraph->GetCenter(triangleCenter.Touches[1]).CenterData, MapGraph->GetCenter(triangleCenter.Touches[2]).CenterData, PixelPosition); - // TODO: Interpolate tags - pixelData.Tags = triangleCenter.CornerData.Tags; - if (PointSelectionMode == EPointSelectionMode::InterpolatedWithPolygonBiome) - { - // Grab the biome directly from the CornerData - pixelData.Biome = triangleCenter.CornerData.Biome; - } - else - { - // Right now, this sometimes causes a crash - // TODO: Find out why it crashes (maybe due to multithreading?) - // In the meantime, use EPointSelectionMode::InterpolatedWithPolygonBiome instead - pixelData.Biome = BiomeManager->DetermineBiome(pixelData); - } - } - } - else - { - // If the point is invalid, the default constructor for the MapData struct is - // sufficient for making an ocean pixel. We just need to set the biome. - pixelData.Biome = FGameplayTag::RequestGameplayTag(TEXT("MapData.Biome.Water.Ocean")); - } - return pixelData; -} - -void FHeightmapPointTask::DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) -{ - FVector2D point = FVector2D(X, Y); - - // Now make the actual map point - FMapData mapData = MakeMapPoint(point, FHeightmapPointGenerator::MapGraph, FHeightmapPointGenerator::BiomeManager); - FHeightmapPointGenerator::HeightmapData.Add(mapData); - FHeightmapPointGenerator::CompletedThreads++; - - float percentComplete = (float)FHeightmapPointGenerator::CompletedThreads / (float)FHeightmapPointGenerator::TotalNumberOfThreads; - UE_LOG(LogWorldGen, Log, TEXT("Heightmap completion percent: %f percent."), percentComplete); - if (FHeightmapPointGenerator::CompletedThreads == FHeightmapPointGenerator::TotalNumberOfThreads) - { - // If we're all done, check in with the on completion delegate - FHeightmapPointGenerator::CheckComplete(); - } -} diff --git a/Source/PolygonalMapGenerator/Private/Maps/Heightmap/PolygonalMapHeightmap.cpp b/Source/PolygonalMapGenerator/Private/Maps/Heightmap/PolygonalMapHeightmap.cpp deleted file mode 100644 index 4f8e887..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Heightmap/PolygonalMapHeightmap.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/MapDataHelper.h" -#include "Biomes/BiomeManager.h" -#include "Moisture/MoistureDistributor.h" -#include "Maps/Heightmap/HeightmapPointTask.h" -#include "PolygonalMapHeightmap.h" - -void UPolygonalMapHeightmap::CreateHeightmap(UPolygonMap* PolygonMap, UBiomeManager* BiomeManager, UMoistureDistributor* MoistureDist, const int32 Size, const FIslandGeneratorDelegate OnComplete) -{ - if (PolygonMap == NULL) - { - return; - } - MoistureDistributor = MoistureDist; - HeightmapSize = Size; - OnGenerationComplete = OnComplete; - - // Interpolate between the actual points - CreateHeightmapTimer = FPlatformTime::Seconds(); - - FIslandGeneratorDelegate generatePoints; - generatePoints.BindDynamic(this, &UPolygonalMapHeightmap::CheckMapPointsDone); - FHeightmapPointGenerator::GenerateHeightmapPoints(HeightmapSize, NumberOfPointsToAverage, this, PolygonMap, BiomeManager, generatePoints); -} - -void UPolygonalMapHeightmap::CheckMapPointsDone() -{ - HeightmapData = FHeightmapPointGenerator::HeightmapData; - UE_LOG(LogWorldGen, Log, TEXT("%d map points created in %f seconds."), HeightmapSize * HeightmapSize, FPlatformTime::Seconds() - CreateHeightmapTimer); - - // Add the rivers - CreateHeightmapTimer = FPlatformTime::Seconds(); - for (int i = 0; i < MoistureDistributor->Rivers.Num(); i++) - { - MoistureDistributor->Rivers[i]->MoveRiverToHeightmap(this); - } - UE_LOG(LogWorldGen, Log, TEXT("Rivers placed in %f seconds."), FPlatformTime::Seconds() - CreateHeightmapTimer); - - if (OnGenerationComplete.IsBound()) - { - OnGenerationComplete.Execute(); - OnGenerationComplete.Unbind(); - } -} - -TArray UPolygonalMapHeightmap::GetMapData() -{ - return HeightmapData; -} - -FMapData UPolygonalMapHeightmap::GetMapPoint(int32 x, int32 y) -{ - int32 index = x + (y * HeightmapSize); - if (index < 0 || HeightmapData.Num() <= index) - { - UE_LOG(LogWorldGen, Warning, TEXT("Tried to fetch a pixel at %d, %d, but no pixel was found."), x, y); - return FMapData(); - } - else - { - return HeightmapData[index]; - } -} - -void UPolygonalMapHeightmap::SetMapPoint(int32 X, int32 Y, FMapData MapData) -{ - int32 index = X + (Y * HeightmapSize); - if (index < 0 || HeightmapData.Num() <= index) - { - UE_LOG(LogWorldGen, Warning, TEXT("Tried to fetch a pixel at %d, %d, but no pixel was found."), X, Y); - return; - } - else - { - HeightmapData[index] = MapData; - } -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/IslandMapGenerator.cpp b/Source/PolygonalMapGenerator/Private/Maps/IslandMapGenerator.cpp deleted file mode 100644 index 3b5082c..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/IslandMapGenerator.cpp +++ /dev/null @@ -1,478 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/MapDataHelper.h" -#include "MapDebugVisualizer.h" -#include "Maps/IslandMapGenerator.h" - -AIslandMapGenerator::AIslandMapGenerator() -{ - PrimaryActorTick.bCanEverTick = true; - PrimaryActorTick.bStartWithTickEnabled = true; - PrimaryActorTick.bTickEvenWhenPaused = true; - bCurrentStepIsDone = true; - bHasGeneratedHeightmap = false; - - - MapGraph = CreateDefaultSubobject(TEXT("Polygon Map")); -} - -void AIslandMapGenerator::Tick(float deltaSeconds) -{ - Super::Tick(deltaSeconds); - ExecuteNextMapStep(); -} - -void AIslandMapGenerator::SetData(FIslandData islandData) -{ - IslandData = islandData; -} - -void AIslandMapGenerator::ResetMap() -{ - if (IslandData.IslandType == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("IslandShape was null!")); - IslandShape = NewObject(this, TEXT("Island Shape")); - } - else - { - IslandShape = NewObject(this, IslandData.IslandType, TEXT("Island Shape")); - } - if (IslandData.IslandPointSelector == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("PointSelector was null!")); - PointSelector = NewObject(this, TEXT("Point Generator")); - } - else - { - PointSelector = NewObject(this, IslandData.IslandPointSelector, TEXT("Point Generator")); - } - - if (IslandData.BiomeManager == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("Biome Manager was null!")); - BiomeManager = NewObject(this,TEXT("Biome Manager")); - } - else - { - BiomeManager = NewObject(this,IslandData.BiomeManager,TEXT("Biome Manager")); - } - - if (IslandData.ElevationDistributor == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("Elevation Distributor was null!")); - ElevationDistributor = NewObject(this, TEXT("Elevation Distributor")); - } - else - { - ElevationDistributor = NewObject(this, IslandData.ElevationDistributor, TEXT("Elevation Distributor")); - } - - if (IslandData.MoistureDistributor == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("Moisture Distributor was null!")); - MoistureDistributor = NewObject(this, TEXT("Moisture Distributor")); - } - else - { - MoistureDistributor = NewObject(this, IslandData.MoistureDistributor, TEXT("Moisture Distributor")); - } - MoistureDistributor->RiverNameTable = IslandData.RiverNameTable; - - RandomGenerator.Initialize(IslandData.Seed); -} - -void AIslandMapGenerator::CreateMap(const FIslandGeneratorDelegate onComplete) -{ - MapStartGenerationTime = FPlatformTime::Seconds(); - OnGenerationComplete = onComplete; - AddMapSteps(); - ExecuteNextMapStep(); -} - -void AIslandMapGenerator::ExecuteNextMapStep() -{ - if (!bCurrentStepIsDone) - { - return; - } - if (IslandGeneratorSteps.IsEmpty() && OnGenerationComplete.IsBound()) - { - UE_LOG(LogWorldGen, Log, TEXT("Finished map generation. Total time to create map was %f seconds."), FPlatformTime::Seconds() - MapStartGenerationTime); - // Done with all steps, execute onComplete delegate - OnGenerationComplete.Execute(); - OnGenerationComplete.Unbind(); - return; - } - - FIslandGeneratorDelegate mapDelegate; - IslandGeneratorSteps.Dequeue(mapDelegate); - if (mapDelegate.IsBound()) - { - mapDelegate.Execute(); - mapDelegate.Unbind(); - } -} - -void AIslandMapGenerator::AddMapSteps_Implementation() -{ - UE_LOG(LogWorldGen, Log, TEXT("Generating a new map at %f."), FPlatformTime::Seconds()); - - // First step: Reset the map - FIslandGeneratorDelegate resetMap; - resetMap.BindDynamic(this, &AIslandMapGenerator::ResetMap); - AddGenerationStep(resetMap); - - // Second step: Empty MapGraph and initialize heightmap classes - FIslandGeneratorDelegate initialization; - initialization.BindDynamic(this, &AIslandMapGenerator::InitializeMapClasses); - AddGenerationStep(initialization); - - // Place the initial points - FIslandGeneratorDelegate buildGraph; - buildGraph.BindDynamic(this, &AIslandMapGenerator::BuildGraph); - AddGenerationStep(buildGraph); - - // Assign elevations to points - FIslandGeneratorDelegate assignElevation; - assignElevation.BindDynamic(this, &AIslandMapGenerator::AssignElevation); - AddGenerationStep(assignElevation); - - // Assign moisture to points - FIslandGeneratorDelegate assignMoisture; - assignMoisture.BindDynamic(this, &AIslandMapGenerator::AssignMoisture); - AddGenerationStep(assignMoisture); - - // Do any tasks which are needed after assigning elevation/moisture - FIslandGeneratorDelegate postProcess; - postProcess.BindDynamic(this, &AIslandMapGenerator::DoPointPostProcess); - AddGenerationStep(postProcess); - - // Normalize all values between 0 and 1 - FIslandGeneratorDelegate normalizePoints; - normalizePoints.BindDynamic(this, &AIslandMapGenerator::NormalizePoints); - AddGenerationStep(normalizePoints); - - // Work out which points correspond to which biome - FIslandGeneratorDelegate determineBiomes; - determineBiomes.BindDynamic(this, &AIslandMapGenerator::DetermineBiomes); - AddGenerationStep(determineBiomes); -} - -void AIslandMapGenerator::AddGenerationStep(const FIslandGeneratorDelegate step) -{ - IslandGeneratorSteps.Enqueue(step); -} - -void AIslandMapGenerator::ClearAllGenerationSteps() -{ - IslandGeneratorSteps.Empty(); -} - -void AIslandMapGenerator::InitializeMapClasses() -{ - CurrentGenerationTime = FPlatformTime::Seconds(); - - MapGraph->Corners.Empty(); - MapGraph->Edges.Empty(); - MapGraph->Centers.Empty(); - MapGraph->Points.Empty(); - - MapHeightmap = NewObject(); - IslandShape->SetSeed(IslandData.Seed, IslandData.Size); - PointSelector->InitializeSelector(IslandData.Size, IslandData.Seed); -} - -void AIslandMapGenerator::BuildGraph() -{ - if (MapGraph == NULL) - { - return; - } - CurrentGenerationTime = FPlatformTime::Seconds(); - // Place points - MapGraph->CreatePoints(PointSelector, IslandData.NumberOfPoints); - - // Build graph - MapGraph->BuildGraph(IslandData.Size, IslandData.PolygonMapSettings); - MapGraph->ImproveCorners(); - UE_LOG(LogWorldGen, Log, TEXT("Created graph in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} - -UPolygonMap* AIslandMapGenerator::GetGraph() const -{ - return MapGraph; -} - -UPolygonalMapHeightmap* AIslandMapGenerator::GetHeightmap() const -{ - return MapHeightmap; -} - -int32 AIslandMapGenerator::GetCenterNum() const -{ - if (MapGraph == NULL) - { - return -1; - } - return MapGraph->GetCenterNum(); -} -int32 AIslandMapGenerator::GetCornerNum() const -{ - if (MapGraph == NULL) - { - return -1; - } - return MapGraph->GetCornerNum(); -} -int32 AIslandMapGenerator::GetEdgeNum() const -{ - if (MapGraph == NULL) - { - return -1; - } - return MapGraph->GetEdgeNum(); -} - -FMapCenter AIslandMapGenerator::GetCenter(const int32 index) const -{ - return MapGraph->GetCenter(index); -} -FMapCorner AIslandMapGenerator::GetCorner(const int32 index) const -{ - return MapGraph->GetCorner(index); -} -FMapEdge AIslandMapGenerator::GetEdge(const int32 index) const -{ - return MapGraph->GetEdge(index); -} -FMapEdge AIslandMapGenerator::FindEdgeFromCenters(const FMapCenter& v0, const FMapCenter& v1) const -{ - return MapGraph->FindEdgeFromCenters(v0, v1); -} - -FMapEdge AIslandMapGenerator::FindEdgeFromCorners(const FMapCorner& v0, const FMapCorner& v1) const -{ - return MapGraph->FindEdgeFromCorners(v0, v1); -} - -void AIslandMapGenerator::UpdateCenter(const FMapCenter& center) -{ - if (MapGraph == NULL) - { - return; - } - MapGraph->UpdateCenter(center); -} -void AIslandMapGenerator::UpdateCorner(const FMapCorner& corner) -{ - if (MapGraph == NULL) - { - return; - } - MapGraph->UpdateCorner(corner); -} -void AIslandMapGenerator::UpdateEdge(const FMapEdge& edge) -{ - if (MapGraph == NULL) - { - return; - } - MapGraph->UpdateEdge(edge); -} - -void AIslandMapGenerator::AssignElevation() -{ - CurrentGenerationTime = FPlatformTime::Seconds(); - - ElevationDistributor->SetGraph(GetGraph()); - MoistureDistributor->SetGraph(MapGraph, IslandData.Size); - // Assign elevations - ElevationDistributor->AssignCornerElevations(IslandShape, PointSelector->NeedsMoreRandomness(), RandomGenerator); - // Determine polygon and corner type: ocean, coast, land. - MoistureDistributor->AssignOceanCoastAndLand(); - - // Change the overall distribution of elevations so that lower - // elevations are more common than higher - // elevations. Specifically, we want elevation X to have frequency - // (1-X). To do this we will sort the corners, then set each - // corner to its desired elevation. - ElevationDistributor->RedistributeElevations(MapGraph->FindLandCorners()); - ElevationDistributor->FlattenWaterElevations(); - ElevationDistributor->AssignPolygonElevations(); - - UE_LOG(LogWorldGen, Log, TEXT("Elevations assigned in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} - - -void AIslandMapGenerator::AssignMoisture() -{ - if (MapGraph == NULL) - { - return; - } - CurrentGenerationTime = FPlatformTime::Seconds(); - - // Moisture distribution - // Determine downslope paths. - ElevationDistributor->CalculateDownslopes(); - - // Determine watersheds: for every corner, where does it flow - // out into the ocean? - MoistureDistributor->CalculateWatersheds(); - - // Create rivers. - MoistureDistributor->CreateRivers(RandomGenerator); - - // Determine moisture at corners, starting at rivers - // and lakes, but not oceans. Then redistribute - // moisture to cover the entire range evenly from 0.0 - // to 1.0. Then assign polygon moisture as the average - // of the corner moisture. - MoistureDistributor->AssignCornerMoisture(); - MoistureDistributor->RedistributeMoisture(MapGraph->FindLandCorners()); - MoistureDistributor->AssignPolygonMoisture(); - - UE_LOG(LogWorldGen, Log, TEXT("Moisture distributed in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} - -void AIslandMapGenerator::DoPointPostProcess() -{ - // Intentionally left blank -} - -void AIslandMapGenerator::NormalizePoints() -{ - if (MapGraph == NULL) - { - return; - } - CurrentGenerationTime = FPlatformTime::Seconds(); - - for (int i = 0; i < GetCornerNum(); i++) - { - FMapCorner corner = GetCorner(i); - corner.CornerData.Elevation = FMath::Clamp(corner.CornerData.Elevation, 0.0f, 1.0f); - corner.CornerData.Moisture = FMath::Clamp(corner.CornerData.Moisture, 0.0f, 1.0f); - - if (!UMapDataHelper::IsOcean(corner.CornerData)) - { - // If this point is not ocean, raise it above ocean level - corner.CornerData.Elevation = FMath::Clamp(0.1f + (corner.CornerData.Elevation * 0.9f), 0.0f, 1.0f); - } - - UpdateCorner(corner); - } - - for (int i = 0; i < GetCenterNum(); i++) - { - FMapCenter center = GetCenter(i); - center.CenterData.Elevation = FMath::Clamp(center.CenterData.Elevation, 0.0f, 1.0f); - center.CenterData.Moisture = FMath::Clamp(center.CenterData.Moisture, 0.0f, 1.0f); - - if (!UMapDataHelper::IsOcean(center.CenterData)) - { - // If this point is not ocean, raise it above ocean level - center.CenterData.Elevation = FMath::Clamp(0.1f + (center.CenterData.Elevation * 0.9f), 0.0f, 1.0f); - } - UpdateCenter(center); - } - - UE_LOG(LogWorldGen, Log, TEXT("Points normalized in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} - -void AIslandMapGenerator::DetermineBiomes() -{ - if (MapGraph == NULL) - { - return; - } - - CurrentGenerationTime = FPlatformTime::Seconds(); - - for (int i = 0; i < GetCornerNum(); i++) - { - FMapCorner corner = GetCorner(i); - FGameplayTag biome = BiomeManager->DetermineBiome(corner.CornerData); - if (!biome.IsValid()) - { - UE_LOG(LogWorldGen, Error, TEXT("Invalid tag! Point: (%f, %f); Elevation: %f; Moisture: %f"), corner.CornerData.Point.X, corner.CornerData.Point.Y, corner.CornerData.Elevation, corner.CornerData.Moisture); - continue; - } - UE_LOG(LogTemp, Log, TEXT("Biome for corner %d: %s"), i, *biome.ToString()); - corner.CornerData.Biome = biome; - UpdateCorner(corner); - } - - for (int i = 0; i < GetCenterNum(); i++) - { - FMapCenter center = GetCenter(i); - FGameplayTag biome = BiomeManager->DetermineBiome(center.CenterData); - if (!biome.IsValid()) - { - UE_LOG(LogWorldGen, Error, TEXT("Invalid tag! Point: (%f, %f); Elevation: %f; Moisture: %f"), center.CenterData.Point.X, center.CenterData.Point.Y, center.CenterData.Elevation, center.CenterData.Moisture); - continue; - } - center.CenterData.Biome = biome; - UpdateCenter(center); - } - - UE_LOG(LogWorldGen, Log, TEXT("Biomes determined in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} -void AIslandMapGenerator::CreateHeightmap(const int32 HeightmapSize, const FIslandGeneratorDelegate OnHeightmapGenerationFinished) -{ - if (MapGraph == NULL) - { - return; - } - // Make the initial heightmap - CurrentGenerationTime = FPlatformTime::Seconds(); - - bHasGeneratedHeightmap = false; - MapGraph->CompileMapData(); - - OnHeightmapComplete = OnHeightmapGenerationFinished; - - FIslandGeneratorDelegate finalizationFinished; - finalizationFinished.BindDynamic(this, &AIslandMapGenerator::OnHeightmapFinished); - MapHeightmap->CreateHeightmap(MapGraph, BiomeManager, MoistureDistributor, HeightmapSize, finalizationFinished); -} - -void AIslandMapGenerator::OnHeightmapFinished() -{ - bHasGeneratedHeightmap = true; - if (OnHeightmapComplete.IsBound()) - { - OnHeightmapComplete.Execute(); - OnHeightmapComplete.Unbind(); - } - UE_LOG(LogWorldGen, Log, TEXT("Heightmap created in %f seconds."), FPlatformTime::Seconds() - CurrentGenerationTime); -} - -void AIslandMapGenerator::DrawVoronoiGraph() -{ - if (MapGraph == NULL) - { - return; - } - UMapDebugVisualizer::DrawDebugVoronoiGrid(this, IslandData.PolygonMapSettings, MapGraph); -} - -void AIslandMapGenerator::DrawDelaunayGraph() -{ - if (MapGraph == NULL) - { - return; - } - UMapDebugVisualizer::DrawDebugDelaunayGrid(this, IslandData.PolygonMapSettings, MapGraph); -} - -void AIslandMapGenerator::DrawHeightmap(float PixelSize) -{ - if (MapHeightmap == NULL || !bHasGeneratedHeightmap) - { - return; - } - UMapDebugVisualizer::DrawDebugPixelGrid(this, IslandData.PolygonMapSettings, MapHeightmap->GetMapData(), IslandData.Size, PixelSize); -} diff --git a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/IslandShape.cpp b/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/IslandShape.cpp deleted file mode 100644 index 06a7f40..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/IslandShape.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/IslandShapes/IslandShape.h" - -void UIslandShape::SetSeed_Implementation(int32 seed, int32 size) -{ - StreamRNG.Initialize(seed); - Size = size; -} - -// Default does nothing -bool UIslandShape::IsPointLand_Implementation(FVector2D point) -{ - return false; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/RadialIsland.cpp b/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/RadialIsland.cpp deleted file mode 100644 index 7358443..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/RadialIsland.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/IslandShapes/RadialIsland.h" -void URadialIsland::SetSeed_Implementation(int32 seed, int32 size) -{ - StreamRNG.Initialize(seed); - Size = size; - Bumps = StreamRNG.RandRange(BumpsMin, BumpsMax); - StartAngle = StreamRNG.FRandRange(StartAngleMin, StartAngleMax) * PI; - AngleOffset = StreamRNG.FRandRange(AngleOffsetMin, AngleOffsetMax) * PI; - MinAngle = StreamRNG.FRandRange(MinAngleMin, MinAngleMax); -} - -bool URadialIsland::IsPointLand_Implementation(FVector2D point) -{ - point.X = 2.0f * ((point.X / Size) - 0.5f); - point.Y = 2.0f * ((point.Y / Size) - 0.5f); - // Get the angle of the point from the center of the island - float angle = FMath::Atan2(point.Y, point.X); - // Get the normalized length of whichever axis is longer - float length = 0.5f * (FMath::Max(FMath::Abs(point.X), FMath::Abs(point.Y)) + FVector2D::Distance(FVector2D::ZeroVector, point)); - // The inner radius has to be smaller than the length for this to be land - float innerRadius; - // The outer radius has to be larger than the length for this to be land - float outerRadius; - - if ((FMath::Abs(angle - AngleOffset) < MinAngle - || FMath::Abs(angle - AngleOffset + 2.0f * PI) < MinAngle - || FMath::Abs(angle - AngleOffset - 2.0f * PI) < MinAngle)) - { - // Our angle is less than the minimum angle - innerRadius = 0.2f; - outerRadius = 0.2f; - } - else - { - innerRadius = 0.5f + 0.4f * FMath::Sin(StartAngle + Bumps * angle + FMath::Cos((Bumps + 3) * angle)); - outerRadius = 0.7f - 0.2f * FMath::Sin(StartAngle + Bumps * angle - FMath::Sin((Bumps + 2) * angle)); - } - - //return innerRadius * IslandFactor < length && length * IslandFactor < outerRadius; - return (length < innerRadius) || (length > innerRadius * IslandFactor && length < outerRadius); -} diff --git a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/SquareIsland.cpp b/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/SquareIsland.cpp deleted file mode 100644 index 81aedd6..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/IslandShapes/SquareIsland.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/IslandShapes/SquareIsland.h" - -bool USquareIsland::IsPointLand_Implementation(FVector2D point) -{ - return true; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/MapDataHelper.cpp b/Source/PolygonalMapGenerator/Private/Maps/MapDataHelper.cpp deleted file mode 100644 index 6bc474f..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/MapDataHelper.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Work Copyright (c) 2017 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "MapDataHelper.h" - -//const FName UMapDataHelper::TAG_Border = TEXT("Border"); -//const FName UMapDataHelper::TAG_Water = TEXT("Water"); -//const FName UMapDataHelper::TAG_Ocean = TEXT("Ocean"); -//const FName UMapDataHelper::TAG_Coast = TEXT("Coast"); -//const FName UMapDataHelper::TAG_River = TEXT("River"); - -bool UMapDataHelper::HasTag(const FMapData& MapData, const FGameplayTag& Tag) -{ - return MapData.Tags.HasTag(Tag); - //return MapData.Tags.Contains(Tag); -} - -bool UMapDataHelper::IsBorder(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Border"))); -} - -bool UMapDataHelper::IsFreshwater(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); -} - -bool UMapDataHelper::IsWater(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water"))); -} - -bool UMapDataHelper::IsOcean(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); -} - -bool UMapDataHelper::IsCoast(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Coast"))); -} - -bool UMapDataHelper::IsRiver(const FMapData& MapData) -{ - return HasTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.River"))); -} - -FMapData UMapDataHelper::SetMapTag(FMapData& MapData, const FGameplayTag& Tag) -{ - MapData.Tags.AddTag(Tag); - return MapData; -} - -FMapData UMapDataHelper::SetBorder(FMapData& MapData) -{ - return SetMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Border"))); -} - -FMapData UMapDataHelper::SetFreshwater(FMapData& MapData) -{ - return SetMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); -} - -FMapData UMapDataHelper::SetOcean(FMapData& MapData) -{ - return SetMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); -} - -FMapData UMapDataHelper::SetCoast(FMapData& MapData) -{ - return SetMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Coast"))); -} - -FMapData UMapDataHelper::SetRiver(FMapData& MapData) -{ - return SetMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.River"))); -} - -FMapData UMapDataHelper::RemoveMapTag(FMapData& MapData, const FGameplayTag& Tag) -{ - MapData.Tags.RemoveTag(Tag); - return MapData; -} - -FMapData UMapDataHelper::RemoveBorder(FMapData& MapData) -{ - return RemoveMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Border"))); -} - -FMapData UMapDataHelper::RemoveFreshwater(FMapData& MapData) -{ - return RemoveMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Freshwater"))); -} - -FMapData UMapDataHelper::RemoveOcean(FMapData& MapData) -{ - return RemoveMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); -} - -FMapData UMapDataHelper::RemoveCoast(FMapData& MapData) -{ - return RemoveMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Coast"))); -} - -FMapData UMapDataHelper::RemoveRiver(FMapData& MapData) -{ - return RemoveMapTag(MapData, FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.River"))); -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/MapDebugVisualizer.cpp b/Source/PolygonalMapGenerator/Private/Maps/MapDebugVisualizer.cpp deleted file mode 100644 index e50c85e..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/MapDebugVisualizer.cpp +++ /dev/null @@ -1,424 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "MapDataHelper.h" -#include "DrawDebugHelpers.h" -#include "PolygonMap.h" -#include "MapDebugVisualizer.h" - -void UMapDebugVisualizer::DrawDebugPixelGrid(AActor* Actor, const FWorldSpaceMapData& MapData, const TArray& HeightmapData, int32 HeightmapSize, float PixelSize) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - FVector offset = FVector(0.0f, 0.0f, 0.0f); - - for (int32 x = 0; x < HeightmapSize; x++) - { - for (int32 y = 0; y < HeightmapSize; y++) - { - FMapData mapData = HeightmapData[x + (y * HeightmapSize)]; - - FColor color = FColor(255, 255, 255); - if (UMapDataHelper::IsOcean(mapData)) - { - color = FColor(0, 27, 71); - } - else if (UMapDataHelper::IsCoast(mapData)) - { - color = FColor(236, 242, 135); - } - else if (UMapDataHelper::IsWater(mapData)) - { - color = FColor(87, 133, 209); - } - else if (UMapDataHelper::IsRiver(mapData)) - { - color = FColor(147, 198, 255); - } - - FVector v0 = offset + FVector(mapData.Point.X * PixelSize, mapData.Point.Y * PixelSize, FMath::FloorToInt(mapData.Elevation * (MapData.ElevationScale / 100.0f)) * PixelSize + 1.0f); - FVector v1 = FVector(v0.X, v0.Y + PixelSize, v0.Z); - FVector v2 = FVector(v0.X + PixelSize, v0.Y, v0.Z); - FVector v3 = FVector(v2.X, v1.Y, v0.Z); - //DrawDebugSphere(world, v0, 100, 4, color, true); - DrawDebugLine(world, v0, v1, color, true); - DrawDebugLine(world, v0, v2, color, true); - DrawDebugLine(world, v3, v2, color, true); - DrawDebugLine(world, v3, v1, color, true); - } - } -} - -void UMapDebugVisualizer::DrawDebugPixelRivers(AActor* Actor, const FWorldSpaceMapData& MapData, const TArray& HeightmapData, int32 HeightmapSize, float PixelSize) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - FVector offset = FVector(0.0f, 0.0f, 0.0f); - - for (int32 x = 0; x < HeightmapSize; x++) - { - for (int32 y = 0; y < HeightmapSize; y++) - { - FMapData mapData = HeightmapData[x + (y * HeightmapSize)]; - if (!UMapDataHelper::IsRiver(mapData)) - { - continue; - } - - FColor color = FColor(147, 198, 255); - - FVector v0 = offset + FVector(mapData.Point.X * PixelSize, mapData.Point.Y * PixelSize, FMath::FloorToInt(mapData.Elevation * (MapData.ElevationScale / 100.0f)) * PixelSize + 1.0f); - FVector v1 = FVector(v0.X, v0.Y + PixelSize, v0.Z); - FVector v2 = FVector(v0.X + PixelSize, v0.Y, v0.Z); - FVector v3 = FVector(v2.X, v1.Y, v0.Z); - //DrawDebugSphere(world, v0, 100, 4, color, true); - DrawDebugLine(world, v0, v1, color, true); - DrawDebugLine(world, v0, v2, color, true); - DrawDebugLine(world, v3, v2, color, true); - DrawDebugLine(world, v3, v1, color, true); - } - } -} - -void UMapDebugVisualizer::DrawDebugVoronoiGrid(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* PolygonMap) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - - TArray Corners = PolygonMap->GetCopyOfMapCornerArray(); - - for (int i = 0; i < Corners.Num(); i++) - { - FMapData mapData = Corners[i].CornerData; - - FColor color = FColor(255, 255, 255); - - if (UMapDataHelper::IsBorder(mapData)) - { - color = FColor(221, 24, 24); - } - else if (Corners[i].RiverSize > 0) - { - color = FColor(147, 198, 255); - } - if (UMapDataHelper::IsOcean(mapData)) - { - color = FColor(0, 27, 71); - } - else if (UMapDataHelper::IsCoast(mapData)) - { - color = FColor(236, 242, 135); - } - else if (UMapDataHelper::IsWater(mapData)) - { - color = FColor(87, 133, 209); - } - - FVector worldLocation = PolygonMap->ConvertGraphPointToWorldSpace(mapData); - DrawDebugSphere(world, worldLocation, MapData.PointSize, 4, color, true); - } - - TArray Edges = PolygonMap->GetCopyOfMapEdgeArray(); - for (int i = 0; i < Edges.Num(); i++) - { - int32 worldIndex0; - int32 worldIndex1; - - worldIndex0 = Edges[i].VoronoiEdge0; - if (worldIndex0 < 0) - { - continue; - } - FMapData v0Data = Corners[worldIndex0].CornerData; - FVector worldVertex0 = PolygonMap->ConvertGraphPointToWorldSpace(v0Data); - - worldIndex1 = Edges[i].VoronoiEdge1; - if (worldIndex1 < 0) - { - continue; - } - FMapData v1Data = Corners[worldIndex1].CornerData; - FVector worldVertex1 = PolygonMap->ConvertGraphPointToWorldSpace(v1Data); - - FColor color = FColor(255, 255, 255); - if (UMapDataHelper::IsBorder(v0Data) || UMapDataHelper::IsBorder(v1Data)) - { - color = FColor(221, 24, 24); - } - else if (Edges[i].RiverVolume > 0) - { - color = FColor(147, 198, 255); - } - else if (UMapDataHelper::IsOcean(v0Data) || UMapDataHelper::IsOcean(v1Data)) - { - color = FColor(0, 27, 71); - } - else if (UMapDataHelper::IsWater(v0Data) || UMapDataHelper::IsWater(v1Data)) - { - color = FColor(87, 133, 209); - } - else if (UMapDataHelper::IsCoast(v0Data) || UMapDataHelper::IsCoast(v1Data)) - { - color = FColor(236, 242, 135); - } - - DrawDebugLine(world, worldVertex0, worldVertex1, color, true); - } -} - -void UMapDebugVisualizer::DrawDebugDelaunayGrid(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* PolygonMap) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - - TArray Centers = PolygonMap->GetCopyOfMapCenterArray(); - // Draw centers - for (int i = 0; i < Centers.Num(); i++) - { - FMapData mapData = Centers[i].CenterData; - - FColor color = FColor(255, 255, 255); - /*if (Corners[i].bIsBorder) - { - color = FColor(255, 0, 0); - } - else */if (UMapDataHelper::IsOcean(mapData)) - { - color = FColor(0, 0, 255); - } - else if (UMapDataHelper::IsCoast(mapData)) - { - color = FColor(255, 255, 0); - } - else if (UMapDataHelper::IsWater(mapData)) - { - color = FColor(0, 255, 255); - } - - FVector worldLocation = PolygonMap->ConvertGraphPointToWorldSpace(mapData); - DrawDebugSphere(world, worldLocation, MapData.PointSize, 4, color, true); - } - - - TArray Edges = PolygonMap->GetCopyOfMapEdgeArray(); - for (int i = 0; i < Edges.Num(); i++) - { - int32 worldIndex0; - int32 worldIndex1; - - worldIndex0 = Edges[i].DelaunayEdge0; - if (worldIndex0 < 0) - { - UE_LOG(LogWorldGen, Error, TEXT("No Delaunay Edge 0 for %d!"), i); - continue; - } - FMapData d0Data = Centers[worldIndex0].CenterData; - FVector worldVertex0 = PolygonMap->ConvertGraphPointToWorldSpace(d0Data); - - worldIndex1 = Edges[i].DelaunayEdge1; - if (worldIndex1 < 0) - { - UE_LOG(LogWorldGen, Error, TEXT("No Delaunay Edge 1 for %d!"), i); - continue; - } - FMapData d1Data = Centers[worldIndex1].CenterData; - FVector worldVertex1 = PolygonMap->ConvertGraphPointToWorldSpace(d1Data); - - FColor color = FColor(255, 255, 255); - /*if (Centers[worldIndex0].bIsBorder && Centers[worldIndex1].bIsBorder) - { - color = FColor(255, 0, 0); - } - else */if (UMapDataHelper::IsOcean(d0Data) && UMapDataHelper::IsOcean(d1Data)) - { - color = FColor(0, 0, 255); - } - else if (UMapDataHelper::IsWater(d0Data) && UMapDataHelper::IsWater(d1Data)) - { - color = FColor(0, 255, 0); - } - else if (UMapDataHelper::IsCoast(d0Data) && UMapDataHelper::IsCoast(d1Data)) - { - color = FColor(255, 255, 0); - } - else if (UMapDataHelper::IsBorder(d0Data) || UMapDataHelper::IsBorder(d1Data)) - { - color = FColor(128, 10, 10); - } - else if (UMapDataHelper::IsOcean(d0Data) || UMapDataHelper::IsOcean(d1Data)) - { - color = FColor(10, 10, 128); - } - else if (UMapDataHelper::IsWater(d0Data) || UMapDataHelper::IsWater(d1Data)) - { - color = FColor(10, 128, 10); - } - else if (UMapDataHelper::IsCoast(d0Data) || UMapDataHelper::IsCoast(d1Data)) - { - color = FColor(128, 128, 10); - } - - DrawDebugLine(world, worldVertex0, worldVertex1, color, true); - } -} - -void UMapDebugVisualizer::DrawTriangle(AActor* Actor, FVector PointA, FVector PointB, FVector PointC) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - DrawDebugLine(world, PointA, PointB, FColor::White); - DrawDebugLine(world, PointB, PointC, FColor::White); - DrawDebugLine(world, PointC, PointA, FColor::White); -} - -void UMapDebugVisualizer::DrawRivers(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* MapGraph, const TArray& Rivers) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - - FColor color = FColor(147, 198, 255); - for (int r = 0; r < Rivers.Num(); r++) - { - URiver* river = Rivers[r]; - if (river->RiverCorners.Num() == 0) - { - continue; - } - FMapEdge lastEdge; - FMapEdge currentEdge; - FMapEdge nextEdge; - for (int i = 0; i < river->RiverCorners.Num() - 2; i++) - { - FMapCorner v0 = river->RiverCorners[i]; - FMapCorner v1 = river->RiverCorners[i + 1]; - FMapCorner v2 = river->RiverCorners[i + 2]; - lastEdge = currentEdge; - currentEdge = MapGraph->FindEdgeFromCorners(v0, v1); - nextEdge = MapGraph->FindEdgeFromCorners(v1, v2); - if (lastEdge.Index != -1 && nextEdge.Index != -1) - { - FVector worldLocation0 = MapGraph->ConvertGraphPointToWorldSpace(v0.CornerData); - worldLocation0.Z = 0.0f; - FVector worldLocation1 = MapGraph->ConvertGraphPointToWorldSpace(v1.CornerData); - worldLocation1.Z = 0.0f; - DrawDebugSphere(world, worldLocation0, MapData.PointSize, 4, color, true); - DrawDebugSphere(world, worldLocation1, MapData.PointSize, 4, color, true); - DrawBeizerCurve(Actor, MapData, lastEdge.Midpoint, v0.CornerData.Point, nextEdge.Midpoint, v1.CornerData.Point, color, MapGraph->GetGraphSize()); - } - } - } - - /*for (int i = 0; i < Corners.Num(); i++) - { - FMapData mapData = Corners[i].CornerData; - - FColor color = FColor(147, 198, 255); - - if (Corners[i].RiverSize > 0) - { - FVector worldLocation = UPolygonMap::ConvertGraphPointToWorldSpace(mapData, MapData, MapSize); - DrawDebugSphere(world, worldLocation, MapData.PointSize, 4, color, true); - } - } - - for (int i = 0; i < Edges.Num(); i++) - { - if (Edges[i].RiverVolume > 0) - { - int32 worldIndex0; - int32 worldIndex1; - - worldIndex0 = Edges[i].VoronoiEdge0; - if (worldIndex0 < 0) - { - continue; - } - FMapData v0Data = Corners[worldIndex0].CornerData; - FVector worldVertex0 = UPolygonMap::ConvertGraphPointToWorldSpace(v0Data, MapData, MapSize); - - worldIndex1 = Edges[i].VoronoiEdge1; - if (worldIndex1 < 0) - { - continue; - } - FMapData v1Data = Corners[worldIndex1].CornerData; - FVector worldVertex1 = UPolygonMap::ConvertGraphPointToWorldSpace(v1Data, MapData, MapSize); - - FColor color = FColor(147, 198, 255); - DrawDebugLine(world, worldVertex0, worldVertex1, color, true); - } - }*/ - -} - -void UMapDebugVisualizer::DrawBeizerCurve(AActor* Actor, const FWorldSpaceMapData& WorldData, FVector2D v0, FVector2D control0, FVector2D v1, FVector2D control1, FColor color, int32 MapSize) -{ - UWorld* world = Actor->GetWorld(); - if (world == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("World was null!")); - return; - } - FVector2D q0 = CalculateBezierPoint(0, v0, control0, control1, v1); - - float elevationOffset = WorldData.ElevationOffset; - float xyScale = WorldData.XYScaleFactor / MapSize; - float elevationScale = WorldData.ElevationScale; - - for (int i = 1; i <= 25; i++) - { - float t = i / 25.0f; - FVector2D q1 = CalculateBezierPoint(t, v0, control0, control1, v1); - - FVector vertex0 = FVector::ZeroVector; - vertex0.X = q0.X * MapSize * xyScale; - vertex0.Y = q0.Y * MapSize * xyScale; - FVector vertex1 = FVector::ZeroVector; - vertex1.X = q1.X * MapSize * xyScale; - vertex1.Y = q1.Y * MapSize * xyScale; - - DrawDebugLine(world, vertex0, vertex1, color, true); - q0 = q1; - } -} - -FVector2D UMapDebugVisualizer::CalculateBezierPoint(float t, FVector2D p0, FVector2D p1, FVector2D p2, FVector2D p3) -{ - float u = 1 - t; - float tt = t * t; - float uu = u * u; - float uuu = uu * u; - float ttt = tt * t; - - FVector2D p = uuu * p0; //first term - - p += 3 * uu * t * p1; //second term - p += 3 * u * tt * p2; //third term - p += ttt * p3; //fourth term - - return p; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/Moisture/MoistureDistributor.cpp b/Source/PolygonalMapGenerator/Private/Maps/Moisture/MoistureDistributor.cpp deleted file mode 100644 index 0232f5a..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Moisture/MoistureDistributor.cpp +++ /dev/null @@ -1,841 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "MapDataHelper.h" -#include "MoistureDistributor.h" - -void UMoistureDistributor::SetGraph(UPolygonMap* Graph, int32 Size) -{ - MapGraph = Graph; - MapSize = Size; -} - -void UMoistureDistributor::AssignOceanCoastAndLand() -{ - TQueue centerQueue; - // Compute polygon attributes 'ocean' and 'water' based on the - // corner attributes. Count the water corners per - // polygon. Oceans are all polygons connected to the edge of the - // map. In the first pass, mark the edges of the map as ocean; - // in the second pass, mark any water-containing polygon - // connected an ocean as ocean. - for (int32 i = 0; i < MapGraph->GetCenterNum(); i++) - { - uint16 numWater = 0; - FMapCenter center = MapGraph->GetCenter(i); - for (int32 j = 0; j < center.Corners.Num(); j++) - { - FMapCorner corner = MapGraph->GetCorner(center.Corners[j]); - if (UMapDataHelper::IsBorder(corner.CornerData)) - { - center.CenterData = UMapDataHelper::SetBorder(center.CenterData); - center.CenterData = UMapDataHelper::SetOcean(center.CenterData); - centerQueue.Enqueue(i); - } - if (UMapDataHelper::IsWater(corner.CornerData)) - { - numWater++; - } - MapGraph->UpdateCorner(corner); - } - if (!UMapDataHelper::IsOcean(center.CenterData) && numWater > center.Corners.Num() * LakeThreshold) - { - center.CenterData = UMapDataHelper::SetFreshwater(center.CenterData); - } - else - { - center.CenterData = UMapDataHelper::RemoveFreshwater(center.CenterData); - } - MapGraph->UpdateCenter(center); - } - - while (!centerQueue.IsEmpty()) - { - int32 centerIndex; - centerQueue.Dequeue(centerIndex); - FMapCenter center = MapGraph->GetCenter(centerIndex); - for (int32 i = 0; i < center.Neighbors.Num(); i++) - { - FMapCenter neighbor = MapGraph->GetCenter(center.Neighbors[i]); - if (UMapDataHelper::IsWater(neighbor.CenterData) && !UMapDataHelper::IsOcean(neighbor.CenterData)) - { - neighbor.CenterData = UMapDataHelper::SetOcean(neighbor.CenterData); - centerQueue.Enqueue(neighbor.Index); - } - MapGraph->UpdateCenter(neighbor); - } - } - - // Set the polygon attribute 'coast' based on its neighbors. If - // it has at least one ocean and at least one land neighbor, - // then this is a coastal polygon. - for (int32 i = 0; i < MapGraph->GetCenterNum(); i++) - { - uint16 numOcean = 0; - uint16 numLand = 0; - FMapCenter center = MapGraph->GetCenter(i); - for (int j = 0; j < center.Neighbors.Num(); j++) - { - FMapCenter neighbor = MapGraph->GetCenter(center.Neighbors[j]); - if (UMapDataHelper::IsOcean(neighbor.CenterData)) - { - numOcean++; - } - else if (!UMapDataHelper::IsWater(neighbor.CenterData)) - { - numLand++; - } - if (numOcean > 0 && numLand > 0) - { - break; - } - } - if (numOcean > 0 && numLand > 0) - { - center.CenterData = UMapDataHelper::SetCoast(center.CenterData); - } - else - { - center.CenterData = UMapDataHelper::RemoveCoast(center.CenterData); - } - MapGraph->UpdateCenter(center); - } - - // Set the corner attributes based on the computed polygon - // attributes. If all polygons connected to this corner are - // ocean, then it's ocean; if all are land, then it's land; - // otherwise it's coast. - for (int32 i = 0; i < MapGraph->GetCornerNum(); i++) - { - uint16 numOcean = 0; - uint16 numLand = 0; - FMapCorner corner = MapGraph->GetCorner(i); - for (int j = 0; j < corner.Touches.Num(); j++) - { - FMapCenter neighbor = MapGraph->GetCenter(corner.Touches[j]); - if (UMapDataHelper::IsOcean(neighbor.CenterData)) - { - numOcean++; - } - else if (!UMapDataHelper::IsWater(neighbor.CenterData)) - { - numLand++; - } - } - if (numOcean == corner.Touches.Num()) - { - corner.CornerData = UMapDataHelper::SetOcean(corner.CornerData); - } - else - { - corner.CornerData = UMapDataHelper::RemoveOcean(corner.CornerData); - } - if (numOcean > 0 && numLand > 0) - { - corner.CornerData = UMapDataHelper::SetCoast(corner.CornerData); - } - else - { - corner.CornerData = UMapDataHelper::RemoveCoast(corner.CornerData); - } - if (UMapDataHelper::IsBorder(corner.CornerData)) - { - corner.CornerData = UMapDataHelper::SetOcean(corner.CornerData); - } - else if (numLand != corner.Touches.Num() && !UMapDataHelper::IsCoast(corner.CornerData)) - { - corner.CornerData = UMapDataHelper::SetFreshwater(corner.CornerData); - } - MapGraph->UpdateCorner(corner); - } -} - -void UMoistureDistributor::CalculateWatersheds() -{ - // Calculate the watershed of every land point. The watershed is - // the last downstream land point in the downslope graph. TODO: - // watersheds are currently calculated on corners, but it'd be - // more useful to compute them on polygon centers so that every - // polygon can be marked as being in one watershed. - - // Initially the watershed pointer points downslope one step. - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - corner.Watershed = corner.Index; - if (!UMapDataHelper::IsOcean(corner.CornerData) && !UMapDataHelper::IsCoast(corner.CornerData)) - { - corner.Watershed = corner.Downslope; - } - MapGraph->UpdateCorner(corner); - } - - // Follow the downslope pointers to the coast. Limit to 100 - // iterations although most of the time with numPoints==2000 it - // only takes 20 iterations because most points are not far from - // a coast. - for (int i = 0; i < 100; i++) - { - bool bChanged = false; - for (int j = 0; j < MapGraph->GetCornerNum(); j++) - { - FMapCorner corner = MapGraph->GetCorner(j); - FMapCorner watershed = MapGraph->GetCorner(corner.Watershed); - if (!UMapDataHelper::IsOcean(corner.CornerData) && !UMapDataHelper::IsCoast(corner.CornerData) && !UMapDataHelper::IsCoast(watershed.CornerData)) - { - FMapCorner downstreamWatershed = MapGraph->GetCorner(watershed.Watershed); - if (!UMapDataHelper::IsOcean(downstreamWatershed.CornerData)) - { - corner.Watershed = downstreamWatershed.Index; - MapGraph->UpdateCorner(corner); - bChanged = true; - } - } - } - if (!bChanged) - { - break; - } - } - - // How big is each watershed? - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - FMapCorner watershed = MapGraph->GetCorner(corner.Watershed); - watershed.WatershedSize += 1; - MapGraph->UpdateCorner(watershed); - } -} - -void UMoistureDistributor::CreateRivers(FRandomStream& RandomGenerator) -{ - /*// The moisture distributor continues until it hits a coast tile - // First, we need to check to ensure that we have a coast tile - bool hasCoastTile = false; - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - if (UMapDataHelper::IsCoast(MapGraph->GetCorner(i).CornerData)) - { - hasCoastTile = true; - break; - } - } - if (!hasCoastTile) - { - UE_LOG(LogWorldGen, Error, TEXT("No tiles were marked as being coastline!")); - return; - } - - for (int i = 0; i < MapSize * RiverRatio; i++) - { - // Randomly select a corner - int cornerIndex = RandomGenerator.RandRange(0, MapGraph->GetCornerNum() - 1); - FMapCorner riverSource = MapGraph->GetCorner(cornerIndex); - if (UMapDataHelper::IsOcean(riverSource.CornerData)) - { - // Ignore it if it is ocean - continue; - } - while (!UMapDataHelper::IsCoast(riverSource.CornerData)) - { - // Continue downstream until we reach the coast - FMapCorner downslopeCorner = MapGraph->GetCorner(riverSource.Downslope); - if (downslopeCorner.Index == riverSource.Index || downslopeCorner.Index < 0) - { - break; - } - - FMapEdge edge = MapGraph->FindEdgeFromCorners(riverSource, downslopeCorner); - edge.RiverVolume++; - riverSource.RiverSize++; - riverSource.CornerData = UMapDataHelper::SetRiver(riverSource.CornerData); - riverSource.CornerData.Elevation -= 0.05f; - downslopeCorner.RiverSize++; - downslopeCorner.CornerData = UMapDataHelper::SetRiver(downslopeCorner.CornerData); - downslopeCorner.CornerData.Elevation -= 0.05f; - - MapGraph->UpdateEdge(edge); - MapGraph->UpdateCorner(riverSource); - MapGraph->UpdateCorner(downslopeCorner); - - riverSource = downslopeCorner; - } - }*/ - /*TArray cornerList; - cornerList.Append(MapGraph->Corners); - while (Rivers.Num() < RiverCount) - { - if (cornerList.Num() == 0) - { - UE_LOG(LogWorldGen, Warning, TEXT("Asked to generate %d rivers, but we could only generate %d!"), RiverCount, Rivers.Num()); - break; - } - int cornerIndex = RandomGenerator.RandRange(0, cornerList.Num() - 1); - FMapCorner riverSource = cornerList[cornerIndex]; - cornerList.RemoveAt(cornerIndex); - - if (UMapDataHelper::IsOcean(riverSource.CornerData)) - { - // Ignore it if it is ocean - continue; - } - // Verify it's far enough away from the coastline - if (UMapDataHelper::IsCoast(riverSource.CornerData)) - { - // Ignore it if it is ocean - continue; - } - // Verify it's not already part of a river - if (riverSource.RiverSize != 0) - { - continue; - } - // Verify it's within the correct elevation - if (riverSource.CornerData.Elevation < MinRiverStartElevation || riverSource.CornerData.Elevation > MaxRiverStartElevation) - { - continue; - } - // Verify it has multiple connections - if (riverSource.Adjacent.Num() <= 1) - { - continue; - } - - // River is valid! - // Start making the river - URiver* river = NewObject(); - FMapCorner currentCorner = riverSource; - bool bIsValid = true; - while (bIsValid && !UMapDataHelper::IsOcean(currentCorner.CornerData)) - { - for (int i = 0; i < river->RiverCorners.Num(); i++) - { - if (river->RiverCorners[i].Index == currentCorner.Index) - { - // River loops onto itself - bIsValid = false; - break; - } - } - if (!bIsValid) - { - break; - } - river->RiverCorners.Add(currentCorner); - - float randomValue = RandomGenerator.GetFraction(); - FMapCorner next; - if (currentCorner.Downslope != -1 && randomValue <= RiverDownstreamBias) - { - next = MapGraph->GetCorner(currentCorner.Downslope); - } - else - { - if (currentCorner.Adjacent.Num() == 0) - { - // No adjacent corners - bIsValid = false; - break; - } - // First, iterate over all the corners to try and find a good candidate by chance - for (int i = 0; i < currentCorner.Adjacent.Num(); i++) - { - bool bShouldSkip = false; - for (int j = 0; j < river->RiverCorners.Num(); j++) - { - if (river->RiverCorners[j].Index == currentCorner.Adjacent[i]) - { - // This corner is already in the river - bShouldSkip = true; - break; - } - } - if (bShouldSkip) - { - continue; - } - randomValue = RandomGenerator.GetFraction(); - if (randomValue <= StandingWaterBias && UMapDataHelper::IsWater(MapGraph->GetCorner(currentCorner.Adjacent[i]).CornerData)) - { - next = MapGraph->GetCorner(currentCorner.Adjacent[i]); - break; - } - } - if (next.Index == -1) - { - // No good candidates - while (next.Adjacent.Num() >= 1) - { - int randomIndex = RandomGenerator.RandRange(0, next.Adjacent.Num() - 1); - FMapCorner possibleNext = MapGraph->GetCorner(next.Adjacent[randomIndex]); - next.Adjacent.RemoveAt(randomIndex); - - bool bIsPossibleNextValid = true; - for (int i = 0; i < river->RiverCorners.Num(); i++) - { - if (river->RiverCorners[i].Index == possibleNext.Index) - { - // River loops onto itself - bIsPossibleNextValid = false; - break; - } - } - if (!bIsPossibleNextValid) - { - // Already have this point in the river - continue; - } - next = possibleNext; - if (next.RiverSize > 0) - { - randomValue = RandomGenerator.GetFraction(); - if (randomValue > RiverJoinBias) - { - continue; - } - } - break; - } - } - } - - if (next.Index == -1) - { - // Next point is invalid - bIsValid = false; - break; - } - - currentCorner = next; - } - - if (river->RiverCorners.Num() < MinRiverSectionCount) - { - bIsValid = false; - } - - if (!bIsValid) - { - continue; - } - - for (int i = 0; i < river->RiverCorners.Num(); i++) - { - river->RiverCorners[i].RiverSize += (int32)StartingRiverSize; - river->RiverCorners[i].RiverSize = FMath::Clamp(river->RiverCorners[i].RiverSize, 0, (int32)MaxRiverSize); - if (i + 1 < river->RiverCorners.Num()) - { - FMapEdge riverEdge = MapGraph->FindEdgeFromCorners(river->RiverCorners[i], river->RiverCorners[i + 1]); - if (riverEdge.Index != -1) - { - riverEdge.RiverVolume = river->RiverCorners[i].RiverSize; - MapGraph->UpdateEdge(riverEdge); - } - } - MapGraph->UpdateCorner(river->RiverCorners[i]); - } - - Rivers.Add(river); - }*/ - - // Create rivers along edges. Pick a random corner point, then - // move downslope. Mark the edges and corners as rivers. - TArray cornerList; - cornerList.Append(MapGraph->GetCopyOfMapCornerArray()); - while (Rivers.Num() < RiverCount) - { - if (cornerList.Num() == 0) - { - //Debug.LogWarning("Ran out of corners to check for rivers! " - // + "Using " + corners.Count + " corners and only made " + rivers.Count + " out of " + waterSettings.riverCount + " rivers!"); - break; - } - - // Get a random element in the list - int randomRiver = RandomGenerator.RandRange(0, cornerList.Num() - 1); - FMapCorner riverSource = cornerList[randomRiver]; - cornerList.RemoveAt(randomRiver); - - // Check to see if it's already in the ocean - if (UMapDataHelper::IsOcean(riverSource.CornerData)) - { - continue; - } - // Verify it's far enough away from the coastline - if (UMapDataHelper::IsCoast(riverSource.CornerData)) - { - continue; - } - // Verify it's not already part of a river - if (riverSource.River != NULL) - { - continue; - } - // Verify it's within the correct elevation - if (riverSource.CornerData.Elevation < MinRiverStartElevation || riverSource.CornerData.Elevation > MaxRiverStartElevation) - { - continue; - } - // Verify it has multiple connections - if (riverSource.Adjacent.Num() <= 1) - { - continue; - } - - // Source is valid, so start making a river - URiver* river = NewObject(); - river->MapGraph = MapGraph; - - FString invalidRiverReason; - FMapCorner current = riverSource; - while (!UMapDataHelper::IsOcean(current.CornerData)) - { - if (current.River != NULL) - { - current = river->AddCorner(current, 0); - if (!current.River->JoinRiver(river, current)) - { - invalidRiverReason = "river could not be joined."; - } - break; - } - else - { - river->AddCorner(current); - } - - FMapCorner next; - // Check to see if we should move downstream - float randomValue = RandomGenerator.GetFraction(); - if (randomValue <= RiverDownstreamBias && - current.Downslope != -1 && - current.Index != current.Downslope && - MapGraph->GetCorner(current.Downslope).River != river) - { - next = MapGraph->GetCorner(current.Downslope); - } - else - { - // Don't move downstream; find an adjacent corner to move to - TArray adjacent; - adjacent.Append(current.Adjacent); - if (adjacent.Num() == 0) - { - invalidRiverReason = "there were no adjacent corners."; - break; - } - - for(int i = 0; i < adjacent.Num(); i++) - { - FMapCorner neighbor = MapGraph->GetCorner(adjacent[i]); - if (neighbor.River == river) - { - continue; - } - randomValue = RandomGenerator.GetFraction(); - if (UMapDataHelper::IsWater(neighbor.CornerData) && randomValue <= StandingWaterBias) - { - next = neighbor; - break; - } - } - - if (next.Index == -1) - { - while (adjacent.Num() >= 1) - { - int randomIndex = RandomGenerator.RandRange(0, adjacent.Num() - 1); - FMapCorner possibleNext = MapGraph->GetCorner(adjacent[randomIndex]); - adjacent.RemoveAt(randomIndex); - if (possibleNext.River == river) - { - continue; - } - if (possibleNext.Adjacent.Num() < 1) - { - continue; - } - - next = possibleNext; - - if (next.River != NULL) - { - randomValue = RandomGenerator.GetFraction(); - if (randomValue > RiverJoinBias) - { - continue; - } - } - break; - } - } - } - - if (next.Index == -1) - { - invalidRiverReason = "there was no valid candidate for the next node."; - break; - } - else if (next.River == river) - { - invalidRiverReason = "the river would feed into itself."; - break; - } - - current = next; - } - - if (!invalidRiverReason.IsEmpty()) - { - // River was invalid, continue - //Debug.LogWarning("Tossing " + river + " because " + invalidRiverReason); - river->Clear(); - continue; - } - else - { - river->AddCorner(current); - if (river->Terminates()) - { - if (river->RiverCorners.Num() <= (int32)MinRiverSectionCount) - { - if (river->FeedsInto.Key == NULL) - { - //Debug.LogWarning("Tossing " + river + " because its length (" + river.Length + ") is smaller than the water settings count (" + waterSettings.minNumberRiverSectionCount + ")."); - river->Clear(); - continue; - } - else - { - river->MakeTributary(); - } - } - river->InitializeRiver(RiverNameTable, RandomGenerator); - Rivers.Add(river); - } - else - { - //Debug.LogWarning("Tossing " + river + " because it does not terminate properly."); - river->Clear(); - continue; - } - } - /*Corner q = corners[Random.Range(0, corners.Count)]; - if (q.ocean || q.coast || q.elevation < waterSettings.minRiverStartElevation || q.elevation > waterSettings.maxRiverStartElevation) - { - continue; - } - - River river = new River(graph, waterSettings.riverSize); - - while (!q.ocean) - { - if (q == q.downslope) - { - break; - } - Edge edge = graph.lookupEdgeFromCorner(q, q.downslope); - edge.river = edge.river + 1; - - river.AddCorner(q); - q.river++; - q.downslope.river++; // TODO: fix double count - q.river = Mathf.Min(q.river, waterSettings.maxRiverSize); - q.downslope.river = Mathf.Min(q.downslope.river, waterSettings.maxRiverSize); - q = q.downslope; - } - - rivers.Add(river)*/ - - // Find rivers to convert into lakes - TArray riverConnectionList; - riverConnectionList.Append(Rivers); - while (riverConnectionList.Num() > 0) - { - URiver* r1 = riverConnectionList[0]; - riverConnectionList.RemoveAt(0); - FMapCorner source1 = r1->GetCorner(0); - // If this is a coastal tile, turning it into a lake would just expand the ocean - // This would also impact the delta formation - if (UMapDataHelper::IsCoast(source1.CornerData)) - { - continue; - } - - TArray remove; - // Iterate over all our rivers - for(int i = 0; i < riverConnectionList.Num(); i++) - { - URiver* r2 = riverConnectionList[i]; - // If rivers are adjacent but one feeds into the other, don't make them into a lake - if (r1->FeedsInto.Key == r2 || r2->FeedsInto.Key == r1) - { - continue; - } - - - FMapCorner adjacent; - FMapCorner source2 = r2->GetCorner(0); - // If this is a coastal tile, turning it into a lake would just expand the ocean - if (UMapDataHelper::IsCoast(source2.CornerData)) - { - continue; - } - for(int j = 0; j < source1.Adjacent.Num(); j++) - { - FMapCorner adjacent1 = MapGraph->GetCorner(source1.Adjacent[j]); - if (UMapDataHelper::IsCoast(adjacent1.CornerData)) - { - continue; - } - if (adjacent1 == source2) - { - adjacent = adjacent1; - break; - } - } - - // If we have a valid adjacent corner - if (adjacent.Index != -1) - { - if (RiverLakeConversionFactor >= RandomGenerator.GetFraction()) - { - FMapCenter center = MapGraph->FindCenterFromCorners(source1, adjacent); - if (UMapDataHelper::IsCoast(center.CenterData)) - { - continue; - } - - // Set the polygon to be a lake - center.CenterData = UMapDataHelper::SetFreshwater(center.CenterData); - for(int j = 0; j < center.Corners.Num(); j++) - { - FMapCorner c = MapGraph->GetCorner(center.Corners[j]); - if (UMapDataHelper::IsCoast(c.CornerData)) - { - continue; - } - c.CornerData = UMapDataHelper::SetFreshwater(c.CornerData); - MapGraph->UpdateCorner(c); - } - MapGraph->UpdateCenter(center); - } - // Remove the second river from consideration - remove.Add(r2); - } - } - for(int i = 0; i < remove.Num(); i++) - { - riverConnectionList.Remove(remove[i]); - } - } - } - - for (int i = 0; i < Rivers.Num(); i++) - { - URiver* r = Rivers[i]; - for (int j = 0; j < r->RiverCorners.Num(); j++) - { - FMapCorner corner = r->GetCorner(j); - corner.RiverSize = FMath::Clamp(corner.RiverSize, 0, (int32)MaxRiverSize); - if(corner.RiverSize > 0) - { - corner.CornerData = UMapDataHelper::SetRiver(corner.CornerData); - } - MapGraph->UpdateCorner(corner); - } - } -} -void UMoistureDistributor::AssignCornerMoisture() -{ - TQueue moistureQueue; - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - if ((UMapDataHelper::IsWater(corner.CornerData) || UMapDataHelper::IsRiver(corner.CornerData)) && !UMapDataHelper::IsOcean(corner.CornerData)) - { - corner.CornerData.Moisture = UMapDataHelper::IsRiver(corner.CornerData) ? FMath::Min(3.0f, (0.2f * corner.RiverSize)) : 1.0f; - moistureQueue.Enqueue(corner); - } - else - { - corner.CornerData.Moisture = 0.0f; - MapGraph->UpdateCorner(corner); - } - } - - while (!moistureQueue.IsEmpty()) - { - FMapCorner corner; - moistureQueue.Dequeue(corner); - for (int i = 0; i < corner.Adjacent.Num(); i++) - { - FMapCorner neighbor = MapGraph->GetCorner(corner.Adjacent[i]); - float newMoisture = corner.CornerData.Moisture * 0.9f; - if (newMoisture > neighbor.CornerData.Moisture) - { - neighbor.CornerData.Moisture = newMoisture; - moistureQueue.Enqueue(neighbor); - } - } - MapGraph->UpdateCorner(corner); - } - - if (ExtraMoisture != 0.0f) - { - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - corner.CornerData.Moisture = FMath::Clamp(corner.CornerData.Moisture + ExtraMoisture, 0.0f, 1.0f); - MapGraph->UpdateCorner(corner); - } - } - - // Saltwater - for (int i = 0; i < MapGraph->GetCornerNum(); i++) - { - FMapCorner corner = MapGraph->GetCorner(i); - if (UMapDataHelper::IsCoast(corner.CornerData) || (UMapDataHelper::IsWater(corner.CornerData) && !UMapDataHelper::IsRiver(corner.CornerData))) - { - corner.CornerData.Moisture = 1.0f; - MapGraph->UpdateCorner(corner); - } - } -} - -void UMoistureDistributor::RedistributeMoisture(TArray landCorners) -{ - float maxMoisture = -1.0f; - for (int i = 0; i < landCorners.Num(); i++) - { - FMapCorner corner = MapGraph->GetCorner(landCorners[i]); - if (corner.CornerData.Moisture > maxMoisture) - { - maxMoisture = corner.CornerData.Moisture; - } - } - - for (int i = 0; i < landCorners.Num(); i++) - { - FMapCorner corner = MapGraph->GetCorner(landCorners[i]); - corner.CornerData.Moisture /= maxMoisture; - MapGraph->UpdateCorner(corner); - } -} - -void UMoistureDistributor::AssignPolygonMoisture() -{ - for (int i = 0; i < MapGraph->GetCenterNum(); i++) - { - FMapCenter center = MapGraph->GetCenter(i); - float sumMoisture = 0.0f; - for (int j = 0; j < center.Corners.Num(); j++) - { - FMapCorner corner = MapGraph->GetCorner(center.Corners[j]); - sumMoisture = corner.CornerData.Moisture; - } - center.CenterData.Moisture = sumMoisture / center.Corners.Num(); - MapGraph->UpdateCenter(center); - } -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/Moisture/River.cpp b/Source/PolygonalMapGenerator/Private/Maps/Moisture/River.cpp deleted file mode 100644 index 028486d..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/Moisture/River.cpp +++ /dev/null @@ -1,322 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "MapDataHelper.h" -#include "Naming/ProceduralNameGenerator.h" -#include "River.h" - -TMap URiver::RiverLookup = TMap(); - -URiver::~URiver() -{ - //Clear(); -} - -bool URiver::IsTributary() const -{ - return bIsTributary; -} - -bool URiver::Terminates() const -{ - return RiverCorners.Num() > 0 && (UMapDataHelper::IsOcean(RiverCorners[RiverCorners.Num() - 1].CornerData) || (FeedsInto.Key != NULL && FeedsInto.Key->Terminates())); -} - -FMapCorner URiver::GetCorner(const int32 Index) const -{ - return RiverCorners[Index]; -} - -FVector2D URiver::GetPointAtIndex(const int32 Index) const -{ - return GetCorner(Index).CornerData.Point; -} - -FVector2D URiver::GetCenter() const -{ - if (RiverCorners.Num() % 2 == 0) - { - // Even number of points - int32 halfLength = RiverCorners.Num() / 2; - FMapEdge edge = GetDownstreamEdge(halfLength - 1); // Subtract one because array starts at 0 - return edge.Midpoint; - } - else - { - // Odd number of points - int32 oddCount = FMath::FloorToInt(RiverCorners.Num() / 2.0f); - return GetPointAtIndex(oddCount); - } -} - -FMapEdge URiver::GetDownstreamEdge(const int32 Index) const -{ - if (Index + 1 >= RiverCorners.Num()) - { - if (FeedsInto.Key != NULL) - { - return FeedsInto.Key->GetDownstreamEdge(FeedsInto.Value + 1); - } - else - { - return FMapEdge(); - } - } - else - { - return MapGraph->FindEdgeFromCorners(RiverCorners[Index], RiverCorners[Index + 1]); - } -} - -void URiver::InitializeRiver(UDataTable* NameDataTable, FRandomStream& RandomGenerator) -{ - if (NameDataTable == NULL) - { - UE_LOG(LogWorldGen, Error, TEXT("No River Name Table found! Did you remember to set it in your Island Generation Settings?")); - return; - } - - TArray textArray; - FString contextString; - TArray rowNames; - rowNames = NameDataTable->GetRowNames(); - - for ( auto& name : rowNames ) - { - FMarkovData* row = NameDataTable->FindRow(name, contextString); - if (row) - { - FText rowText = row->MarkovText; - textArray.Add(rowText); - } - } - - const uint8 randomOrder = 2; - const uint8 minLength = 3; - const uint8 maxLength = 16; - const bool bConvertToTitleCase = true; - const bool bUseNamePattern = false; - - RiverName = UProceduralNameGenerator::GenerateRandomWord(textArray, RandomGenerator, randomOrder, minLength, maxLength, bConvertToTitleCase, bUseNamePattern); - FString lastAttempt = RiverName; - while(RiverLookup.Contains(RiverName)) - { - int32 nextSeed = RandomGenerator.RandRange(0, 2147483647); - RandomGenerator.Initialize(nextSeed); - RiverName = UProceduralNameGenerator::GenerateRandomWord(textArray, RandomGenerator, randomOrder, minLength, maxLength, bConvertToTitleCase, bUseNamePattern); - if (RiverName.Equals(lastAttempt)) - { - UE_LOG(LogWorldGen, Error, TEXT("Generated the same name (%s) twice in a row! Random seed: %d"), *lastAttempt, nextSeed); - break; - } - lastAttempt = RiverName; - } - RiverLookup.Add(RiverName, this); -} - -FMapCorner URiver::AddCorner(FMapCorner Corner, const int32 IncreaseRiverAmount /*= 1*/) -{ - if (RiverCorners.Contains(Corner)) - { - return Corner; - } - Corner.River = this; - Corner.RiverSize += IncreaseRiverAmount; - Corner.RiverIndex = RiverCorners.Num(); - //c.AddToRiver(this, Length, increaseRiverVolumeAmount); - //if (Length > 1) - //{ - //Edge edge = graph.lookupEdgeFromCorner(corners[Length - 1], c); - //edge.river = edge.river + 1; - //} - RiverCorners.Add(Corner); - - if (!IsTributary()) - { - /*if (nameSuffixID <= 0 && corners.Count > MIN_RIVER_NAME_SIZE / 2) - { - nameSuffixID = 1; - } - else if (nameSuffixID == 1 && corners.Count > MIN_RIVER_NAME_SIZE) - { - nameSuffixID = 2; - }*/ - } - MapGraph->UpdateCorner(Corner); - return Corner; -} - -bool URiver::JoinRiver(URiver* FeederRiver, FMapCorner JoinLocation, bool bIncreaseRiverVolume /*= true*/) -{ - if (FeederRiver == NULL || FeederRiver == this || FeederRiver == FeedsInto.Key) - { - return false; - } - - // The join index is the location along the river that - int joinIndex = JoinLocation.RiverIndex; - if (bIncreaseRiverVolume) - { - for (int i = joinIndex; i < RiverCorners.Num(); i++) - { - RiverCorners[i].RiverSize++; - MapGraph->UpdateCorner(RiverCorners[i]); - } - } - - FeederRiver->FeedsInto.Key = this; - FeederRiver->FeedsInto.Value = joinIndex; - - /*FFeederRiver feederRiverList = FeederRivers.FindOrAdd(joinIndex); - feederRiverList.FeederRivers.Add(FeederRiver); - FeederRivers[joinIndex] = feederRiverList;*/ - FeederRiverCount++; - /*if (nameSuffixID == 0 && feederRiverCount >= MIN_RIVER_NAME_TRIBUTARY_COUNT / 2) - { - nameSuffixID = 1; - } - else if (nameSuffixID == 1 && feederRiverCount >= MIN_RIVER_NAME_TRIBUTARY_COUNT) - { - nameSuffixID = 2; - }*/ - return true; -} - -void URiver::MakeTributary() -{ - bIsTributary = true; - //nameSuffixID = Random.Range(0, 2); -} - -void URiver::Clear() -{ - for (int i = 0; i < RiverCorners.Num(); i++) - { - FMapCorner corner = MapGraph->GetCorner(RiverCorners[i].Index); - corner.RiverIndex = -1; - corner.River = NULL; - corner.RiverSize -= 1; - MapGraph->UpdateCorner(corner); - } - /*foreach(Corner c in corners) - { - c.AddToRiver(null, -1); - } - riverNameLookup.Remove(Name);*/ -} - -void URiver::ClearRiverLookupCache() -{ - //riverNameLookup.Clear(); -} - -void URiver::MoveRiverToHeightmap(UPolygonalMapHeightmap* MapHeightmap) -{ - if (RiverCorners.Num() == 0) - { - return; - } - FMapEdge lastEdge; - FMapEdge currentEdge; - FMapEdge nextEdge; - for (int i = 0; i < RiverCorners.Num() - 2; i++) - { - FMapCorner v0 = RiverCorners[i]; - FMapCorner v1 = RiverCorners[i + 1]; - FMapCorner v2 = RiverCorners[i + 2]; - lastEdge = currentEdge; - currentEdge = MapGraph->FindEdgeFromCorners(v0, v1); - nextEdge = MapGraph->FindEdgeFromCorners(v1, v2); - if (lastEdge.Index != -1 && nextEdge.Index != -1) - { - DrawBeizerCurve(MapHeightmap, lastEdge.Midpoint, v0.CornerData.Point, nextEdge.Midpoint, v1.CornerData.Point); - } - } -} - -void URiver::DrawBeizerCurve(UPolygonalMapHeightmap* MapHeightmap, FVector2D v0, FVector2D control0, FVector2D v1, FVector2D control1) -{ - FVector2D q0 = CalculateBezierPoint(0, v0, control0, control1, v1); - - for (int i = 1; i <= 25; i++) - { - float t = i / 25.0f; - FVector2D q1 = CalculateBezierPoint(t, v0, control0, control1, v1); - - DrawLineOnHeightmap(MapHeightmap, q0, q1); - q0 = q1; - } -} - -FVector2D URiver::CalculateBezierPoint(float t, FVector2D p0, FVector2D p1, FVector2D p2, FVector2D p3) -{ - float u = 1 - t; - float tt = t * t; - float uu = u * u; - float uuu = uu * u; - float ttt = tt * t; - - FVector2D p = uuu * p0; //first term - - p += 3 * uu * t * p1; //second term - p += 3 * u * tt * p2; //third term - p += ttt * p3; //fourth term - - return p; -} - -void URiver::DrawLineOnHeightmap(UPolygonalMapHeightmap* MapHeightmap, const FVector2D& point1, const FVector2D& point2) -{ - float deltaX = point2.X - point1.X; - if (deltaX == 0) - { - // Line is vertical - int32 x = FMath::RoundToInt(point1.X); - for (int32 y = FMath::RoundToInt(point1.Y); y <= FMath::RoundToInt(point2.Y); y++) - { - for(int xOffset = -1; xOffset <= 1; xOffset++) - { - for (int yOffset = -1; yOffset <= 1; yOffset++) - { - FMapData point = MapHeightmap->GetMapPoint(x + xOffset, y + yOffset); - if (point.Elevation == 0.0f && point.Point == FVector2D::ZeroVector && point.Moisture == 0.0f) - { - // Empty point - continue; - } - point = UMapDataHelper::SetRiver(point); - MapHeightmap->SetMapPoint(x + xOffset, y + yOffset, point); - } - } - } - return; - } - float deltaY = point2.Y - point1.Y; - float deltaError = FMath::Abs(deltaY / deltaX); - float error = deltaError - 0.5f; - int32 y = FMath::RoundToInt(point1.Y); - for (int x = FMath::RoundToInt(point1.X); x < FMath::RoundToInt(point2.X); x++) - { - for (int xOffset = -1; xOffset <= 1; xOffset++) - { - for (int yOffset = -1; yOffset <= 1; yOffset++) - { - FMapData point = MapHeightmap->GetMapPoint(x + xOffset, y + yOffset); - if (point.Elevation == 0.0f && point.Point == FVector2D::ZeroVector && point.Moisture == 0.0f) - { - // Empty point - continue; - } - point = UMapDataHelper::SetRiver(point); - MapHeightmap->SetMapPoint(x + xOffset, y + yOffset, point); - } - } - - error += deltaError; - if (error >= 0.5f) - { - y++; - error -= 1.0f; - } - } -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/PointGenerator.cpp b/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/PointGenerator.cpp deleted file mode 100644 index 915ea16..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/PointGenerator.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/PointGenerators/PointGenerator.h" - -void UPointGenerator::InitializeSelector(int32 mapSize, int32 seed, int32 border) -{ - MapSize = mapSize; - RandomGenerator.Initialize(seed); - Border = border; -} - -bool UPointGenerator::NeedsMoreRandomness() -{ - return bNeedsMoreRandomness; -} - -int32 UPointGenerator::MinPoint() -{ - return Border; -} - -int32 UPointGenerator::MaxPoint() -{ - return MapSize - Border; -} - -bool UPointGenerator::PointIsOnBorder(FVector2D point) -{ - if (point.X <= (Border * 2) || point.Y <= (Border * 2)) - { - return true; - } - if (point.X >= MapSize - (Border * 2) || point.Y >= MapSize - (Border * 2)) - { - return true; - } - return false; -} - -TArray UPointGenerator::GeneratePoints_Implementation(int32 numberOfPoints) -{ - TArray pointArray; - pointArray.AddDefaulted(numberOfPoints); - return pointArray; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/RandomPointGenerator.cpp b/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/RandomPointGenerator.cpp deleted file mode 100644 index d94130e..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/RandomPointGenerator.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/PointGenerators/RandomPointGenerator.h" - -// Random Point Selector -TArray URandomPointGenerator::GeneratePoints_Implementation(int32 numberOfPoints) -{ - TArray pointArray; - for (int32 i = 0; i < numberOfPoints; i++) - { - float randomX = RandomGenerator.FRandRange(Border, MapSize - Border); - float randomY = RandomGenerator.FRandRange(Border, MapSize - Border); - pointArray.Add(FVector2D(randomX, randomY)); - } - return pointArray; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/SquarePointGenerator.cpp b/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/SquarePointGenerator.cpp deleted file mode 100644 index 5f79f4f..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/PointGenerators/SquarePointGenerator.cpp +++ /dev/null @@ -1,24 +0,0 @@ - // Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/PointGenerators/SquarePointGenerator.h" - -TArray USquarePointGenerator::GeneratePoints_Implementation(int32 numberOfPoints) -{ - TArray pointArray; - int32 gridSize = FMath::RoundToInt(FMath::Sqrt((uint32)numberOfPoints)); - - for (int32 x = 0; x < gridSize; x++) - { - for (int32 y = 0; y < gridSize; y++) - { - FVector2D point = FVector2D((0.5f + x) / gridSize * MapSize, (0.5f + y) / gridSize * MapSize); - if (point.X < Border || point.Y < Border || point.X > MapSize - Border || point.Y > MapSize - Border) - { - continue; - } - pointArray.Add(point); - } - } - return pointArray; -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/Maps/PolygonMap.cpp b/Source/PolygonalMapGenerator/Private/Maps/PolygonMap.cpp deleted file mode 100644 index b576442..0000000 --- a/Source/PolygonalMapGenerator/Private/Maps/PolygonMap.cpp +++ /dev/null @@ -1,764 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Maps/PointGenerators/PointGenerator.h" -#include "Maps/PolygonMap.h" -#include "MapDebugVisualizer.h" -#include "Maps/MapDataHelper.h" -#include "Classes/Diagrams/Voronoi.h" - -DEFINE_LOG_CATEGORY(LogWorldGen); - -void UPolygonMap::CreatePoints(UPointGenerator* pointSelector, const int32& numberOfPoints) -{ - if (pointSelector == NULL) - { - return; - } - - PointSelector = pointSelector; - Points = PointSelector->GeneratePoints(numberOfPoints); - MinPointLocation = PointSelector->MinPoint(); - MaxPointLocation = PointSelector->MaxPoint(); -} - -void UPolygonMap::BuildGraph(const int32& mapSize, const FWorldSpaceMapData& data) -{ - MapSize = mapSize; - WorldData = data; - Voronoi voronoi(Points); - for (int i = 0; i < voronoi.sites.Num(); i++) - { - VSite site = voronoi.sites[i]; - - // Create centers, corners, and edges - for (auto siteEdge : site.edges) - { - // Voronoi Edge (corner to corner) - FVector4 vEdge = siteEdge.vEdge; - // Delaunay Edge (center to center) - FVector4 dEdge = siteEdge.dEdge; - - // Corners come from edge vertices - FMapCorner cornerOne = MakeCorner(FVector2D(vEdge.X, vEdge.Y)); - FMapCorner cornerTwo = MakeCorner(FVector2D(vEdge.Z, vEdge.W)); - FMapCenter centerOne = MakeCenter(FVector2D(dEdge.X, dEdge.Y)); - FMapCenter centerTwo = MakeCenter(FVector2D(dEdge.Z, dEdge.W)); - - FMapEdge edge; - edge.DelaunayEdge0 = centerOne.Index; - edge.DelaunayEdge1 = centerTwo.Index; - edge.VoronoiEdge0 = cornerOne.Index; - edge.VoronoiEdge1 = cornerTwo.Index; - if(cornerOne.Index >=0 && cornerTwo.Index >= 0) - { - edge.Midpoint = FVector2D(FMath::Lerp(vEdge.X, vEdge.Z, 0.5f), FMath::Lerp(vEdge.Y, vEdge.W, 0.5f)); - } - edge.Index = Edges.Num(); - Edges.Add(edge); - - /*int32 edgeIndex = -1; - for (int32 j = 0; j < Edges.Num(); j++) - { - int32 d0 = Edges[j].DelaunayEdge0; - int32 d1 = Edges[j].DelaunayEdge1; - int32 v0 = Edges[j].VoronoiEdge0; - int32 v1 = Edges[j].VoronoiEdge1; - - if (((d0 == centerOne.Index && d1 == centerTwo.Index) || (d0 == centerTwo.Index && d1 == centerOne.Index)) && - ((v0 == cornerOne.Index && v1 == cornerTwo.Index) || (v0 == cornerTwo.Index && v1 == cornerOne.Index))) - { - edgeIndex = j; - break; - } - } - - - if (edgeIndex < 0) - { - // Create edge object - FMapEdge edge; - // Edges point to corners - edge.VoronoiEdge0 = cornerOne.Index; - edge.VoronoiEdge1 = cornerTwo.Index; - // Edges point to centers - edge.DelaunayEdge0 = centerOne.Index; - edge.DelaunayEdge1 = centerTwo.Index; - - edge.Index = Edges.Num(); - edgeIndex = edge.Index; - if (cornerOne.Index >= 0 && cornerTwo.Index >= 0) - { - edge.Midpoint = FVector2D(FMath::Lerp(vEdge.X, vEdge.Z, 0.5f), FMath::Lerp(vEdge.Y, vEdge.W, 0.5f)); - } - Edges.Add(edge); - }*/ - - // Corners point to edges - if (cornerOne.Index >= 0) { cornerOne.Protrudes.AddUnique(edge.Index); } - if (cornerTwo.Index >= 0) { cornerTwo.Protrudes.AddUnique(edge.Index); } - // Centers point to edges - if (centerOne.Index >= 0) { centerOne.Borders.AddUnique(edge.Index); } - if (centerTwo.Index >= 0) { centerTwo.Borders.AddUnique(edge.Index); } - - // Centers point to centers - if (centerOne.Index >= 0 && centerTwo.Index >= 0) - { - centerOne.Neighbors.AddUnique(centerTwo.Index); - centerTwo.Neighbors.AddUnique(centerOne.Index); - } - - // Corners point to corners - if (cornerOne.Index >= 0 && cornerTwo.Index >= 0) - { - cornerOne.Adjacent.AddUnique(cornerTwo.Index); - cornerTwo.Adjacent.AddUnique(cornerOne.Index); - } - - // Centers point to corners - if (centerOne.Index >= 0) - { - if (cornerOne.Index >= 0) { centerOne.Corners.AddUnique(cornerOne.Index); } - if (cornerTwo.Index >= 0) { centerOne.Corners.AddUnique(cornerTwo.Index); } - } - if (centerTwo.Index >= 0) - { - if (cornerOne.Index >= 0) { centerTwo.Corners.AddUnique(cornerOne.Index); } - if (cornerTwo.Index >= 0) { centerTwo.Corners.AddUnique(cornerTwo.Index); } - } - - // Corners point to centers - if (cornerOne.Index >= 0) - { - if (centerOne.Index >= 0) { cornerOne.Touches.AddUnique(centerOne.Index); } - if (centerOne.Index >= 0) { cornerOne.Touches.AddUnique(centerTwo.Index); } - } - if (cornerTwo.Index >= 0) - { - if (centerTwo.Index >= 0) { cornerTwo.Touches.AddUnique(centerOne.Index); } - if (centerTwo.Index >= 0) { cornerTwo.Touches.AddUnique(centerTwo.Index); } - } - - // Update Array (it won't update automatically) - UpdateCenter(centerOne); - UpdateCenter(centerTwo); - UpdateCorner(cornerOne); - UpdateCorner(cornerTwo); - } - } - UE_LOG(LogWorldGen, Log, TEXT("Created a total of %d Centers, %d Corners, and %d Edges."), Centers.Num(), Corners.Num(), Edges.Num()); -} - -FMapCenter UPolygonMap::MakeCenter(const FVector2D& point) -{ - if (CenterLookup.Contains(point)) - { - return GetCenter(CenterLookup[point]); - } - - FMapCenter center; - center.CenterData.Point = point; - center.CenterData = UMapDataHelper::RemoveBorder(center.CenterData); - center.CenterData = UMapDataHelper::RemoveOcean(center.CenterData); - center.Index = Centers.Num(); - - Centers.Add(center); - CenterLookup.Add(point, center.Index); - - return GetCenter(center.Index); -} - -FMapCenter UPolygonMap::GetCenter(const int32& index) const -{ - if (index < 0) - { - return FMapCenter(); - } - return Centers[index]; -} - -FMapCorner UPolygonMap::MakeCorner(const FVector2D& point) -{ - if (CornerLookup.Contains(point)) - { - return GetCorner(CornerLookup[point]); - } - - FMapCorner corner; - corner.CornerData.Point = point; - corner.Index = Corners.Num(); - corner.CornerData = UMapDataHelper::RemoveOcean(corner.CornerData); - if (PointSelector->PointIsOnBorder(corner.CornerData.Point)) - { - corner.CornerData = UMapDataHelper::SetBorder(corner.CornerData); - } - else - { - corner.CornerData = UMapDataHelper::RemoveBorder(corner.CornerData); - } - - Corners.Add(corner); - CornerLookup.Add(point, corner.Index); - - return GetCorner(corner.Index); -} - -FMapCorner UPolygonMap::GetCorner(const int32& index) const -{ - if (index < 0) - { - return FMapCorner(); - } - return Corners[index]; -} - -FMapEdge UPolygonMap::GetEdge(const int32& index) const -{ - if (index < 0) - { - return FMapEdge(); - } - return Edges[index]; -} -FMapEdge UPolygonMap::FindEdgeFromCenters(const FMapCenter& v0, const FMapCenter& v1) const -{ - if (v0.Index < 0 || v0.Index >= Edges.Num() || v1.Index <0 || v1.Index >= Edges.Num()) - { - return GetEdge(-1); - } - for (int i = 0; i < Edges.Num(); i++) - { - if ((Edges[i].DelaunayEdge0 == v0.Index && Edges[i].DelaunayEdge1 == v1.Index) || (Edges[i].DelaunayEdge0 == v1.Index && Edges[i].DelaunayEdge1 == v0.Index)) - { - return GetEdge(i); - } - } - return GetEdge(-1); -} -FMapEdge UPolygonMap::FindEdgeFromCorners(const FMapCorner& v0, const FMapCorner& v1) const -{ - if (v0.Index < 0 || v0.Index >= Edges.Num() || v1.Index <0 || v1.Index >= Edges.Num()) - { - return GetEdge(-1); - } - for (int i = 0; i < Edges.Num(); i++) - { - if ((Edges[i].VoronoiEdge0 == v0.Index && Edges[i].VoronoiEdge1 == v1.Index) || (Edges[i].VoronoiEdge0 == v1.Index && Edges[i].VoronoiEdge1 == v0.Index)) - { - return GetEdge(i); - } - } - return GetEdge(-1); -} - -FMapCenter UPolygonMap::FindCenterFromCorners(FMapCorner CornerA, FMapCorner CornerB) const -{ - for (int i = 0; i < CornerA.Touches.Num(); i++) - { - for (int j = 0; j < CornerB.Touches.Num(); j++) - { - if (CornerA.Touches[i] == CornerB.Touches[j]) - { - return GetCenter(CornerA.Touches[i]); - } - } - } - return GetCenter(-1); -} - -int32 UPolygonMap::GetCenterNum() const -{ - return Centers.Num(); -} -int32 UPolygonMap::GetCornerNum() const -{ - return Corners.Num(); -} -int32 UPolygonMap::GetEdgeNum() const -{ - return Edges.Num(); -} - -int32 UPolygonMap::GetGraphSize() const -{ - return MapSize; -} - -void UPolygonMap::UpdateCenter(const FMapCenter& center) -{ - if (center.Index < 0 || center.Index >= Centers.Num()) - { - return; - } - Centers[center.Index] = center; -} -void UPolygonMap::UpdateCorner(const FMapCorner& corner) -{ - if (corner.Index < 0 || corner.Index >= Corners.Num()) - { - return; - } - checkf(!(Corners[corner.Index].CornerData.Biome.IsValid() && !corner.CornerData.Biome.IsValid()), TEXT("Attempted to set corner %d from biome %s to an invalid biome!"), corner.Index, *Corners[corner.Index].CornerData.Biome.ToString()) - Corners[corner.Index] = corner; -} -void UPolygonMap::UpdateEdge(const FMapEdge& edge) -{ - if (edge.Index < 0 || edge.Index >= Edges.Num()) - { - return; - } - Edges[edge.Index] = edge; -} - -void UPolygonMap::ImproveCorners() -{ - TArray newCorners; - newCorners.SetNumZeroed(Corners.Num()); - - // First we compute the average of the centers next to each corner. - for (int i = 0; i < Corners.Num(); i++) - { - if (UMapDataHelper::IsBorder(Corners[i].CornerData)) - { - newCorners[i] = Corners[i].CornerData.Point; - } - else - { - FVector2D point = FVector2D::ZeroVector; - int32 touchesLength = Corners[i].Touches.Num(); - for (int j = 0; j < touchesLength; j++) - { - int32 centerIndex = Corners[i].Touches[j]; - point += Centers[centerIndex].CenterData.Point; - } - point /= touchesLength; - newCorners[i] = point; - } - } - - // Move the corners to the new locations. - for (int i = 0; i < Corners.Num(); i++) - { - Corners[i].CornerData.Point = newCorners[i]; - } - - // The edge midpoints were computed for the old corners and need - // to be recomputed. - for (int i = 0; i < Edges.Num(); i++) - { - if (Edges[i].VoronoiEdge0 >= 0 && Edges[i].VoronoiEdge1 >= 0) - { - FVector2D edgeVertexOne = Corners[Edges[i].VoronoiEdge0].CornerData.Point; - FVector2D edgeVertexTwo = Corners[Edges[i].VoronoiEdge1].CornerData.Point; - Edges[i].Midpoint = FVector2D(FMath::Lerp(edgeVertexOne.X, edgeVertexTwo.X, 0.5f), FMath::Lerp(edgeVertexOne.Y, edgeVertexTwo.Y, 0.5f)); - } - } -} - -TArray UPolygonMap::FindLandCorners() const -{ - TArray landCorners; - for (int i = 0; i < Corners.Num(); i++) - { - FMapCorner corner = Corners[i]; - if (UMapDataHelper::IsOcean(corner.CornerData) || UMapDataHelper::IsCoast(corner.CornerData)) - { - continue; - } - landCorners.Emplace(i); - } - return landCorners; -} - -TArray& UPolygonMap::GetAllMapData() -{ - return CachedMapData; -} - -TArray UPolygonMap::GetCopyOfMapCornerArray() -{ - return Corners; -} - -TArray UPolygonMap::GetCopyOfMapEdgeArray() -{ - return Edges; -} - -TArray UPolygonMap::GetCopyOfMapCenterArray() -{ - return Centers; -} - -void UPolygonMap::CompileMapData() -{ - CachedMapData.Empty(); - for (int i = 0; i < GetCenterNum(); i++) - { - CachedMapData.Add(GetCenter(i).CenterData); - } - for (int i = 0; i < GetCornerNum(); i++) - { - CachedMapData.Add(GetCorner(i).CornerData); - } -} - -FVector2D UPolygonMap::ConvertWorldPointToGraphSpace(const FVector WorldPoint) -{ - - FVector2D graphLocation = FVector2D::ZeroVector; - graphLocation.X = WorldPoint.X / WorldData.XYScaleFactor; - graphLocation.Y = WorldPoint.Y / WorldData.XYScaleFactor; - - return graphLocation; -} - -FVector UPolygonMap::ConvertGraphPointToWorldSpace(const FMapData& MapPointData) -{ - FVector worldLocation = FVector::ZeroVector; - worldLocation.X = MapPointData.Point.X * WorldData.XYScaleFactor; - worldLocation.Y = MapPointData.Point.Y * WorldData.XYScaleFactor; - worldLocation.Z = (MapPointData.Elevation * WorldData.ElevationScale) + WorldData.ElevationOffset; - - return worldLocation; -} - -FMapCenter UPolygonMap::FindMapCenterForCoordinate(const FVector2D& Point) -{ - if (Point.X > MaxPointLocation || Point.Y > MaxPointLocation || Point.X < MinPointLocation || Point.Y < MinPointLocation) - { - // Point out of bounds - return FMapCenter(); - } - - FVector2D intMapCoordinates = Point; - intMapCoordinates.X = FMath::RoundToInt(Point.X); - intMapCoordinates.Y = FMath::RoundToInt(Point.Y); - if (CenterLookup.Contains(intMapCoordinates)) - { - return GetCenter(CenterLookup[intMapCoordinates]); - } - - FMapCenter center = FMapCenter(); - for (int i = 0; i < Centers.Num(); i++) - { - if (CenterContainsPoint(Point, Centers[i])) - { - center = Centers[i]; - break; - } - } - - CenterLookup.Add(intMapCoordinates, center.Index); - return center; -} - -FMapCorner UPolygonMap::FindMapCornerForCoordinate(const FVector2D& Point) -{ - if (Point.X > MaxPointLocation || Point.Y > MaxPointLocation || Point.X < MinPointLocation || Point.Y < MinPointLocation) - { - // Point out of bounds; don't even bother putting it in the cache - return FMapCorner(); - } - - FVector2D intMapCoordinates = Point; - intMapCoordinates.X = FMath::RoundToInt(Point.X); - intMapCoordinates.Y = FMath::RoundToInt(Point.Y); - if (CornerLookup.Contains(intMapCoordinates)) - { - return GetCorner(CornerLookup[intMapCoordinates]); - } - - FMapCorner corner = FMapCorner(); - for (int i = 0; i < Corners.Num(); i++) - { - if (CornerContainsPoint(Point, Corners[i])) - { - corner = Corners[i]; - if (corner.Touches.Num() == 0) - { - corner = FMapCorner(); - } - else if (corner.Touches.Num() != 3) - { - UE_LOG(LogTemp, Error, TEXT("Polygon at coordinates (%f, %f) was not a triangle (%d vertices)."), intMapCoordinates.X, intMapCoordinates.Y, corner.Touches.Num()); - corner = FMapCorner(); - } - break; - } - } - CornerLookup.Add(intMapCoordinates, corner.Index); - return corner; -} - -bool UPolygonMap::CenterContainsPoint(const FVector2D& Point, const FMapCenter& Center) const -{ - float minX = Center.CenterData.Point.X; - float maxX = Center.CenterData.Point.X; - float minY = Center.CenterData.Point.Y; - float maxY = Center.CenterData.Point.Y; - for (int i = 0; i < Center.Corners.Num(); i++) - { - // Iterate over the borders, creating a bounding box for the polygon - FMapCorner corner = GetCorner(Center.Corners[i]); - if(corner.Index < 0) - { - // Invalid corner - continue; - } - maxX = FMath::Max(maxX, corner.CornerData.Point.X); - minX = FMath::Min(minX, corner.CornerData.Point.X); - maxY = FMath::Max(maxY, corner.CornerData.Point.Y); - minY = FMath::Min(minY, corner.CornerData.Point.Y); - } - - // Check to see if bounding box contains point - if(Point.X < minX || Point.X > maxX || Point.Y < minY || Point.Y > maxY) - { - // Not even in the polygon's bounding box - return false; - } - - // Set the padding to be 1% of the polygon size - float epsilon = ((maxX - minX) / 100.0f); - FVector2D pointTarget = FVector2D(minX - epsilon, Point.Y); - - int32 intersections = 0; - for (int i = 0; i < Center.Borders.Num(); i++) - { - FMapEdge border = GetEdge(Center.Borders[i]); - if (border.Index < 0) - { - // Invalid index - UE_LOG(LogWorldGen, Warning, TEXT("Invalid border! Center number %d, Edge index was %d."), Center.Index, Center.Borders[i]); - continue; - } - if (SegementsIntersect(border, Point, pointTarget)) - { - intersections++; - //UE_LOG(LogWorldGen, Log, TEXT("Checking if point (%f, %f)-(%f, %f) and point (%f, %f)-(%f, %f) intersect."), p1.X, p1.Y, q1.X, q1.Y, p2.X, p2.Y, q2.X, q2.Y); - } - } - - return (intersections & 1) == 1; // True if point is odd (inside of polygon) -} - -bool UPolygonMap::CornerContainsPoint(const FVector2D& Point, const FMapCorner& Corner) const -{ - if (Corner.Touches.Num() != 3) - { - return false; - } - FVector2D p1 = GetCenter(Corner.Touches[0]).CenterData.Point; - FVector2D p2 = GetCenter(Corner.Touches[1]).CenterData.Point; - FVector2D p3 = GetCenter(Corner.Touches[2]).CenterData.Point; - - float y1 = p1.Y; - float y2 = p2.Y; - float y3 = p3.Y; - - float x1 = p1.X; - float x2 = p2.X; - float x3 = p3.X; - - // Calculate determinant - float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); - if (det == 0.0f) - { - // Shouldn't happen, but okay - return false; - } - - float x = Point.X; - float y = Point.Y; - - // https://stackoverflow.com/questions/36090269/finding-height-of-point-on-height-map-triangles - float a = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det; - float b = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / det; - float c = 1 - a - b; - - // p lies in T if and only if 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1 - return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1; -} - -float UPolygonMap::CalculateZPosition(FVector2D MapLocation, FMapCorner& OutMapCorner) -{ - OutMapCorner = FindMapCornerForCoordinate(MapLocation); - if (OutMapCorner.Index < 0) - { - // Not a valid corner - return 0.0f; - } - - return CalculateZPositionBetweenCenters(GetCenter(OutMapCorner.Touches[0]), GetCenter(OutMapCorner.Touches[1]), GetCenter(OutMapCorner.Touches[2]), MapLocation); -} - - -float UPolygonMap::CalculateZPositionBetweenCenters(FMapCenter CenterA, FMapCenter CenterB, FMapCenter CenterC, FVector2D MapLocation) const -{ - FVector p1 = FVector(CenterA.CenterData.Point.X, CenterA.CenterData.Point.Y, CenterA.CenterData.Elevation); - FVector p2 = FVector(CenterB.CenterData.Point.X, CenterB.CenterData.Point.Y, CenterB.CenterData.Elevation); - FVector p3 = FVector(CenterC.CenterData.Point.X, CenterC.CenterData.Point.Y, CenterC.CenterData.Elevation); - - float y1 = p1.Y; - float y2 = p2.Y; - float y3 = p3.Y; - - float x1 = p1.X; - float x2 = p2.X; - float x3 = p3.X; - - // Calculate determinant - float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); - if (det == 0.0f) - { - // Shouldn't happen, but okay - return 0.0f; - } - - float x = MapLocation.X; - float y = MapLocation.Y; - - // https://stackoverflow.com/questions/36090269/finding-height-of-point-on-height-map-triangles - float lambda1 = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det; - float lambda2 = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / det; - float lambda3 = 1 - lambda1 - lambda2; - - float z1 = p1.Z; - float z2 = p2.Z; - float z3 = p3.Z; - - // Calculate Z coordinate - return ((lambda1 * z1 + lambda2 * z2 + lambda3 * z3) * WorldData.ElevationScale) + WorldData.ElevationOffset; -} - -float UPolygonMap::CalculateMoistureAtPoint(FVector2D MapLocation, FMapCorner& OutMapCorner) -{ - OutMapCorner = FindMapCornerForCoordinate(MapLocation); - if (OutMapCorner.Index < 0) - { - // Not a valid corner - return 0.0f; - } - - return InterpolateMapDataMoisture(GetCenter(OutMapCorner.Touches[0]).CenterData, GetCenter(OutMapCorner.Touches[1]).CenterData, GetCenter(OutMapCorner.Touches[2]).CenterData, MapLocation); -} - - -float UPolygonMap::InterpolateMapDataMoisture(FMapData PointA, FMapData PointB, FMapData PointC, FVector2D MapLocation) const -{ - FVector p1 = FVector(PointA.Point.X, PointA.Point.Y, PointA.Moisture); - FVector p2 = FVector(PointB.Point.X, PointB.Point.Y, PointB.Moisture); - FVector p3 = FVector(PointC.Point.X, PointC.Point.Y, PointC.Moisture); - - float y1 = p1.Y; - float y2 = p2.Y; - float y3 = p3.Y; - - float x1 = p1.X; - float x2 = p2.X; - float x3 = p3.X; - - // Calculate determinant - float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3); - if (det == 0.0f) - { - // Shouldn't happen, but okay - return 0.0f; - } - - float x = MapLocation.X; - float y = MapLocation.Y; - - // https://stackoverflow.com/questions/36090269/finding-height-of-point-on-height-map-triangles - float lambda1 = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det; - float lambda2 = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / det; - float lambda3 = 1 - lambda1 - lambda2; - - float z1 = p1.Z; - float z2 = p2.Z; - float z3 = p3.Z; - - // Calculate moisture - return lambda1 * z1 + lambda2 * z2 + lambda3 * z3; -} - -// The main function that returns true if line segment 'p1q1' -// and 'p2q2' intersect. -bool UPolygonMap::SegementsIntersect(const FMapEdge& Edge, const FVector2D& StartPoint, const FVector2D& EndPoint) const -{ - FMapCorner corner1 = GetCorner(Edge.VoronoiEdge0); - FMapCorner corner2 = GetCorner(Edge.VoronoiEdge1); - if (corner1.Index < 0 || corner2.Index < 0) - { - // Invalid corner - UE_LOG(LogWorldGen, Warning, TEXT("Invalid corner! Edge number %d, Corner 1 index was %d, Corner 2 index was %d."), Edge.Index, Edge.VoronoiEdge0, Edge.VoronoiEdge1); - return false; - } - const float v1x1 = corner1.CornerData.Point.X; - const float v1y1 = corner1.CornerData.Point.Y; - const float v1x2 = corner2.CornerData.Point.X; - const float v1y2 = corner2.CornerData.Point.Y; - const float v2x1 = StartPoint.X; - const float v2y1 = StartPoint.Y; - const float v2x2 = EndPoint.X; - const float v2y2 = EndPoint.Y; - - float d1, d2; - float a1, a2, b1, b2, c1, c2; - - // Convert the first vector to a line of infinite length - // We want this line in a linear equation - a1 = v1y2 - v1y1; - b1 = v1x1 - v1x2; - c1 = (v1x2 * v1y1) - (v1x1 * v1y2); - - // Every point (x, y) that solves the equation above is on the line. - // Every point that does not solve it is not. - // The equation will have a positive result if it is on one side of the line - // and a negative result if it is on the other. - // We insert our start and end points into the equation above. - d1 = (a1 * v2x1) + (b1 * v2y1) + c1; - d2 = (a1 * v2x2) + (b1 * v2y2) + c1; - - // If d1 and d2 have the same sign, they are both on the same side of our Edge. - // In this case, no intersection is possible. - // 0 is a special case, which is why < and > are used instead of <= and >=. - if((d1 > 0 && d2 > 0) || (d1 < 0 && d2 < 0)) - { - return false; - } - - // If we have gotten to this point, the infinite lines intersect somewhere (i.e., they are not parallel). - // However, we are looking for an intersection in a specific interval (the edge). - // The edge is a subset of the infinite line, and it is possible that the intersection happened before or after that interval - // In order to know for sure, we have to do the same test the other way around. - // Starting with converting the second segment into an infinite line: - a2 = v2y2 - v2y1; - b2 = v2x1 - v2x2; - c2 = (v2x2 * v2y1) - (v2x1 * v2y2); - - // Calculate d1 and d2 again, using the other segment - d1 = (a2 * v1x1) + (b2 * v1y1) + c2; - d2 = (a2 * v1x2) + (b2 * v1y2) + c2; - - // Again, if both have the same sign, no intersection is possible - if ((d1 > 0 && d2 > 0) || (d1 < 0 && d2 < 0)) - { - return false; - } - - // Now we have 2 options. - // Either they intersect at exactly one point, or they are colinear and intersect at any number of points. - // We treat colinear lines as failing this test. - if((a1 * b2) - (a2 * b1) < 0.001f) - { - // Points are colinear - return false; - } - else - { - // Points intersect somewhere - return true; - } -} diff --git a/Source/PolygonalMapGenerator/Private/Naming/ProceduralNameGenerator.cpp b/Source/PolygonalMapGenerator/Private/Naming/ProceduralNameGenerator.cpp deleted file mode 100644 index c11a4cc..0000000 --- a/Source/PolygonalMapGenerator/Private/Naming/ProceduralNameGenerator.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Dave Carlile -Modifications made in 2017 Jay Stevens - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Misc/Char.h" -#include -#include "ProceduralNameGenerator.h" - -uint8 UProceduralNameGenerator::Order = 0; -TMap> UProceduralNameGenerator::Chains = TMap>(); -TSet UProceduralNameGenerator::WordPatterns = TSet(); - -bool UProceduralNameGenerator::IsVowel(TCHAR ch) -{ - FString vowels = FString(TEXT("aeiou")); - //FString extendedVowels = FString(TEXT("����������������������")); - int32 index; - return vowels.FindChar(ch, index); -} - -FString UProceduralNameGenerator::GetWordPattern(FString word) -{ - // This takes a string and converts it to a pattern - // The pattern is the ratio of vowels to consonants - // As an example, "consonants" would be "cvccvcvccc" - std::string pattern = ""; - - TArray wordArray = word.GetCharArray(); - for(int i = 0; i < wordArray.Num(); i++) - { - TCHAR ch = wordArray[i]; - pattern += IsVowel(ch) ? "v" : "c"; - } - - return FString(pattern.c_str()); -} - -void UProceduralNameGenerator::IdentifyWordPattern(FString word) -{ - // Determines the word's pattern and adds it - // to the list of word patterns - WordPatterns.Add(GetWordPattern(word)); -} - -void UProceduralNameGenerator::AddCharacter(FString key, TCHAR ch) -{ - TArray chain; - - // Ensure that the dictionary contains the key - if (Chains.Contains(key)) - { - chain = Chains[key]; - } - else - { - Chains.Add(key, chain); - } - - // Check to see if it is already in this chain - bool bFound = false; - for (int i = 0; i < chain.Num(); i++) - { - if (chain[i].Letter == ch) - { - // We have a match! - // Update the number of instances of this letter - chain[i].Instances++; - bFound = true; - break; - } - } - - // If we didn't find a match, update the chain with a new letter - if (!bFound) - { - FMarkovCharacter letter = FMarkovCharacter(); - letter.Letter = ch; - letter.Instances = 1; - chain.Add(letter); - } - - // Update the main Chains array - Chains[key] = chain; -} - -void UProceduralNameGenerator::ProcessWord(FString word) -{ - std::string wordStr = ""; - // Convert to a std string - // Begin with a few underscores - for (int i = 0; i < Order; i++) - { - wordStr += '_'; - } - // Actually convert the string - for (int i = 0; i < word.Len(); i++) - { - wordStr += word[i]; - } - // Terminate with an underscore - wordStr += '_'; - - // Add the keys to the Chains array - for (int i = 0; i < wordStr.size() - Order; i++) - { - // Each key is a substring from the current index plus the order - std::string key = wordStr.substr(i, Order); - FString unrealKey = FString(key.c_str()); - // Now add each character to the array - // We add Order to the index to compensate for the underscores we added - AddCharacter(unrealKey, wordStr[i + Order]); - } -} - -void UProceduralNameGenerator::AnalyzeWord(FString word) -{ - IdentifyWordPattern(word); - ProcessWord(word); -} - -void UProceduralNameGenerator::CalculateProbability() -{ - TMap> newChains; - - for (TPair>& kvp : Chains) - { - if(kvp.Key.IsEmpty() || kvp.Value.Num() == 0) - { - continue; - } - float totalInstances = 0.0f; - TArray characterArray = kvp.Value; - for (int i = 0; i < characterArray.Num(); i++) - { - totalInstances += characterArray[i].Instances; - } - for (int i = 0; i < characterArray.Num(); i++) - { - characterArray[i].Probability = characterArray[i].Instances / totalInstances; - } - characterArray.HeapSort(); - newChains.Add(kvp.Key, characterArray); - } - - Chains.Empty(); - Chains = newChains; -} - -void UProceduralNameGenerator::AnalyzeWords(TArray words, uint8 order) -{ - Order = order; - - Chains.Empty(); - WordPatterns.Empty(); - - for(int i = 0; i < words.Num(); i++) - { - AnalyzeWord(words[i].ToLower()); - } - - CalculateProbability(); -} - -FMarkovCharacter* UProceduralNameGenerator::GetCharacterByProbability(FString key, float probability) -{ - TArray chain; - if (!Chains.Contains(key)) - { - UE_LOG(LogWorldGen, Warning, TEXT("Chain does not contain %s!"), *key); - return NULL; - } - else - { - chain = Chains[key]; - } - - float cumulative = 0; - FMarkovCharacter* result = NULL; - - for (int i = 0; i < chain.Num(); i++) - { - cumulative += chain[i].Probability; - if (probability < cumulative) - { - result = new FMarkovCharacter(); - result->Instances = chain[i].Instances; - result->Letter = chain[i].Letter; - result->Probability = chain[i].Probability; - break; - } - } - - return result; -} - -FString UProceduralNameGenerator::GenerateRandomWord(TArray Words, FRandomStream RandomGenerator, uint8 WordOrder, uint8 MinLength, uint8 MaxLength, bool bConvertToTitleCase, bool bMatchWordPattern) -{ - TArray wordStrings; - wordStrings.SetNumZeroed(Words.Num()); - for(int i = 0; i < Words.Num(); i++) - { - wordStrings[i] = Words[i].ToString(); - } - AnalyzeWords(wordStrings, WordOrder); - for (int i = 0; i < 64; i++) - { - FString word = GenerateRandomWord(MinLength, MaxLength, RandomGenerator, bConvertToTitleCase); - if (word.Len() < MinLength) - { - continue; - } - if (!bMatchWordPattern) - { - UE_LOG(LogWorldGen, Log, TEXT("Generated word: %s"), *word); - return word; - } - if (WordPatterns.Contains(GetWordPattern(word))) - { - UE_LOG(LogWorldGen, Log, TEXT("Generated word: %s"), *word); - return word; - } - } - - UE_LOG(LogWorldGen, Error, TEXT("Could not generate word!")); - return FString(); -} - -FString UProceduralNameGenerator::GenerateRandomWord(uint8 minLength, uint8 maxLength, FRandomStream& RandomGenerator, bool bConvertToTitleCase) -{ - std::string result; - - result = ""; - std::string key = ""; - for (int i = 0; i < Order; i++) - { - key += '_'; - } - - while (result.length() < maxLength) - { - FMarkovCharacter* character = GetCharacterByProbability(FString(key.c_str()), RandomGenerator.GetFraction()); - char ch = character == NULL ? '_' : character->Letter; - delete character; - if (ch == '_') break; - - result += ch; - key += ch; - - key = key.substr(key.length() - Order); - } - if (bConvertToTitleCase) - { - return UppercaseWords(FString(result.c_str())); - } - else - { - result[0] = TChar::ToUpper(result[0]); - return FString(result.c_str()); - } -} - -FString UProceduralNameGenerator::UppercaseWords(FString value) -{ - TArray charArray = value.GetCharArray(); - // Handle the first letter in the FString. - if (charArray.Num() >= 1) - { - if (TChar::IsLower(charArray[0])) - { - charArray[0] = TChar::ToUpper(charArray[0]); - } - } - // Scan through the letters, checking for spaces. - // ... Uppercase the lowercase letters following spaces. - for (int i = 1; i < charArray.Num(); i++) - { - if (charArray[i - 1] == ' ') - { - if (TChar::IsLower(charArray[i])) - { - charArray[i] = TChar::ToUpper(charArray[i]); - } - } - } - std::string finishedString = ""; - for (int i = 0; i < charArray.Num(); i++) - { - finishedString += charArray[i]; - } - return FString(finishedString.c_str()); -} diff --git a/Source/PolygonalMapGenerator/Private/Noise/PolygonalMapGenNoise.cpp b/Source/PolygonalMapGenerator/Private/Noise/PolygonalMapGenNoise.cpp deleted file mode 100644 index d0af70c..0000000 --- a/Source/PolygonalMapGenerator/Private/Noise/PolygonalMapGenNoise.cpp +++ /dev/null @@ -1,1951 +0,0 @@ -// PolygonalMapGenNoise.cpp -// -// MIT License -// -// Copyright(c) 2016 Jordan Peck -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// The developer's email is jorzixdan.me2@gzixmail.com (for great email, take -// off every 'zix'.) -// - -#include "PolygonalMapGeneratorPrivatePCH.h" -#include "Noise/PolygonalMapGenNoise.h" - -#include -#include -#include - -const float GRAD_X[] = -{ - 1, -1, 1, -1, - 1, -1, 1, -1, - 0, 0, 0, 0 -}; -const float GRAD_Y[] = -{ - 1, 1, -1, -1, - 0, 0, 0, 0, - 1, -1, 1, -1 -}; -const float GRAD_Z[] = -{ - 0, 0, 0, 0, - 1, 1, -1, -1, - 1, 1, -1, -1 -}; - -const float GRAD_4D[] = -{ - 0,1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1, - 0,-1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1, - 1,0,1,1,1,0,1,-1,1,0,-1,1,1,0,-1,-1, - -1,0,1,1,-1,0,1,-1,-1,0,-1,1,-1,0,-1,-1, - 1,1,0,1,1,1,0,-1,1,-1,0,1,1,-1,0,-1, - -1,1,0,1,-1,1,0,-1,-1,-1,0,1,-1,-1,0,-1, - 1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1,0, - -1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1,0 -}; - -const float VAL_LUT[] = -{ - 0.3490196078f, 0.4352941176f, -0.4509803922f, 0.6392156863f, 0.5843137255f, -0.1215686275f, 0.7176470588f, -0.1058823529f, 0.3960784314f, 0.0431372549f, -0.03529411765f, 0.3176470588f, 0.7254901961f, 0.137254902f, 0.8588235294f, -0.8196078431f, - -0.7960784314f, -0.3333333333f, -0.6705882353f, -0.3882352941f, 0.262745098f, 0.3254901961f, -0.6470588235f, -0.9215686275f, -0.5294117647f, 0.5294117647f, -0.4666666667f, 0.8117647059f, 0.3803921569f, 0.662745098f, 0.03529411765f, -0.6156862745f, - -0.01960784314f, -0.3568627451f, -0.09019607843f, 0.7490196078f, 0.8352941176f, -0.4039215686f, -0.7490196078f, 0.9529411765f, -0.0431372549f, -0.9294117647f, -0.6549019608f, 0.9215686275f, -0.06666666667f, -0.4431372549f, 0.4117647059f, -0.4196078431f, - -0.7176470588f, -0.8117647059f, -0.2549019608f, 0.4901960784f, 0.9137254902f, 0.7882352941f, -1.0f, -0.4745098039f, 0.7960784314f, 0.8509803922f, -0.6784313725f, 0.4588235294f, 1.0f, -0.1843137255f, 0.4509803922f, 0.1450980392f, - -0.231372549f, -0.968627451f, -0.8588235294f, 0.4274509804f, 0.003921568627f, -0.003921568627f, 0.2156862745f, 0.5058823529f, 0.7647058824f, 0.2078431373f, -0.5921568627f, 0.5764705882f, -0.1921568627f, -0.937254902f, 0.08235294118f, -0.08235294118f, - 0.9058823529f, 0.8274509804f, 0.02745098039f, -0.168627451f, -0.7803921569f, 0.1137254902f, -0.9450980392f, 0.2f, 0.01960784314f, 0.5607843137f, 0.2705882353f, 0.4431372549f, -0.9607843137f, 0.6156862745f, 0.9294117647f, -0.07450980392f, - 0.3098039216f, 0.9921568627f, -0.9137254902f, -0.2941176471f, -0.3411764706f, -0.6235294118f, -0.7647058824f, -0.8901960784f, 0.05882352941f, 0.2392156863f, 0.7333333333f, 0.6549019608f, 0.2470588235f, 0.231372549f, -0.3960784314f, -0.05098039216f, - -0.2235294118f, -0.3725490196f, 0.6235294118f, 0.7019607843f, -0.8274509804f, 0.4196078431f, 0.07450980392f, 0.8666666667f, -0.537254902f, -0.5058823529f, -0.8039215686f, 0.09019607843f, -0.4823529412f, 0.6705882353f, -0.7882352941f, 0.09803921569f, - -0.6078431373f, 0.8039215686f, -0.6f, -0.3254901961f, -0.4117647059f, -0.01176470588f, 0.4823529412f, 0.168627451f, 0.8745098039f, -0.3647058824f, -0.1607843137f, 0.568627451f, -0.9921568627f, 0.9450980392f, 0.5137254902f, 0.01176470588f, - -0.1450980392f, -0.5529411765f, -0.5764705882f, -0.1137254902f, 0.5215686275f, 0.1607843137f, 0.3725490196f, -0.2f, -0.7254901961f, 0.631372549f, 0.7098039216f, -0.568627451f, 0.1294117647f, -0.3098039216f, 0.7411764706f, -0.8509803922f, - 0.2549019608f, -0.6392156863f, -0.5607843137f, -0.3176470588f, 0.937254902f, 0.9843137255f, 0.5921568627f, 0.6941176471f, 0.2862745098f, -0.5215686275f, 0.1764705882f, 0.537254902f, -0.4901960784f, -0.4588235294f, -0.2078431373f, -0.2156862745f, - 0.7725490196f, 0.3647058824f, -0.2392156863f, 0.2784313725f, -0.8823529412f, 0.8980392157f, 0.1215686275f, 0.1058823529f, -0.8745098039f, -0.9843137255f, -0.7019607843f, 0.9607843137f, 0.2941176471f, 0.3411764706f, 0.1529411765f, 0.06666666667f, - -0.9764705882f, 0.3019607843f, 0.6470588235f, -0.5843137255f, 0.05098039216f, -0.5137254902f, -0.137254902f, 0.3882352941f, -0.262745098f, -0.3019607843f, -0.1764705882f, -0.7568627451f, 0.1843137255f, -0.5450980392f, -0.4980392157f, -0.2784313725f, - -0.9529411765f, -0.09803921569f, 0.8901960784f, -0.2862745098f, -0.3803921569f, 0.5529411765f, 0.7803921569f, -0.8352941176f, 0.6862745098f, 0.7568627451f, 0.4980392157f, -0.6862745098f, -0.8980392157f, -0.7725490196f, -0.7098039216f, -0.2470588235f, - -0.9058823529f, 0.9764705882f, 0.1921568627f, 0.8431372549f, -0.05882352941f, 0.3568627451f, 0.6078431373f, 0.5450980392f, 0.4039215686f, -0.7333333333f, -0.4274509804f, 0.6f, 0.6784313725f, -0.631372549f, -0.02745098039f, -0.1294117647f, - 0.3333333333f, -0.8431372549f, 0.2235294118f, -0.3490196078f, -0.6941176471f, 0.8823529412f, 0.4745098039f, 0.4666666667f, -0.7411764706f, -0.2705882353f, 0.968627451f, 0.8196078431f, -0.662745098f, -0.4352941176f, -0.8666666667f, -0.1529411765f, -}; - -const float CELL_2D_X[] = -{ - -0.4313539279f, -0.1733316799f, -0.2821957395f, -0.2806473808f, 0.3125508975f, 0.3383018443f, -0.4393982022f, -0.4460443703f, -0.302223039f, -0.212681052f, -0.2991156529f, 0.2293323691f, 0.4475439151f, 0.1777518f, 0.1688522499f, -0.0976597166f, - 0.08450188373f, -0.4098760448f, 0.3476585782f, -0.3350670039f, 0.2298190031f, -0.01069924099f, -0.4460141246f, 0.3650293864f, -0.349479423f, -0.4122720642f, -0.267327811f, 0.322124041f, 0.2880445931f, 0.3892170926f, 0.4492085018f, -0.4497724772f, - 0.1278175387f, -0.03572100503f, -0.4297407068f, -0.3217817723f, -0.3057158873f, -0.414503978f, -0.3738139881f, 0.2236891408f, 0.002967775577f, 0.1747128327f, -0.4423772489f, -0.2763960987f, -0.4019385906f, 0.3871414161f, -0.430008727f, -0.03037574274f, - -0.3486181573f, 0.04553517144f, -0.0375802926f, 0.3266408905f, 0.06540017593f, 0.03409025829f, -0.4449193635f, -0.4255936157f, 0.449917292f, 0.05242606404f, -0.4495305179f, -0.1204775703f, -0.341986385f, 0.3865320182f, 0.04506097811f, -0.06283465979f, - 0.3932600341f, 0.4472261803f, 0.3753571011f, -0.273662295f, 0.1700461538f, 0.4102692229f, 0.323227187f, -0.2882310238f, 0.2050972664f, 0.4414085979f, -0.1684700334f, -0.003978032396f, -0.2055133639f, -0.006095674897f, -0.1196228124f, 0.3901528491f, - 0.01723531752f, -0.3015070339f, -0.01514262423f, -0.4142574071f, -0.1916377265f, 0.3749248747f, -0.2237774255f, -0.4166343106f, 0.3619171625f, 0.1891126846f, -0.3127425077f, -0.3281807787f, -0.2294806661f, -0.3445266136f, -0.4167095422f, -0.257890321f, - -0.3612037825f, 0.2267996491f, 0.207157062f, 0.08355176718f, -0.4312233307f, 0.3257055497f, 0.177701095f, -0.445182522f, 0.3955143435f, -0.4264613988f, -0.3793799665f, 0.04617599081f, -0.371405428f, 0.2563570295f, 0.03476646309f, -0.3065454405f, - -0.2256979823f, 0.4116448463f, -0.2907745828f, 0.2842278468f, 0.3114589359f, 0.4464155859f, -0.3037334033f, 0.4079607166f, -0.3486948919f, 0.3264821436f, 0.3211142406f, 0.01183382662f, 0.4333844092f, 0.3118668416f, -0.272753471f, -0.422228622f, - -0.1009700099f, -0.2741171231f, -0.1465125133f, 0.2302279044f, -0.3699435608f, 0.105700352f, -0.2646713633f, 0.3521828122f, -0.1864187807f, 0.1994492955f, 0.3937065066f, -0.3226158377f, 0.3796235338f, 0.1482921929f, -0.407400394f, 0.4212853031f, - -0.2621297173f, -0.2536986953f, -0.2100236383f, 0.3624152444f, -0.3645038479f, 0.2318486784f, -0.3260457004f, -0.2130045332f, 0.3814998766f, -0.342977305f, -0.4355865605f, -0.2104679605f, 0.3348364681f, 0.3430468811f, -0.2291836801f, 0.2547707298f, - 0.4236174945f, -0.15387742f, -0.4407449312f, -0.06805276192f, 0.4453517192f, 0.2562464609f, 0.3278198355f, -0.4122774207f, 0.3354090914f, 0.446632869f, -0.1608953296f, -0.09463954939f, -0.02637688324f, 0.447102804f, -0.4365670908f, -0.3959858651f, - -0.4240048207f, -0.3882794568f, -0.4283652566f, 0.3303888091f, 0.3321434919f, -0.413021046f, 0.08403060337f, -0.3822882919f, -0.3712395594f, 0.4472363971f, -0.4466591209f, 0.0486272539f, -0.4203101295f, 0.2205360833f, -0.3624900666f, -0.4036086833f, - 0.2152727807f, -0.4359392962f, 0.4178354266f, 0.2007630161f, -0.07278067175f, 0.3644748615f, -0.4317451775f, -0.297436456f, -0.2998672222f, -0.2673674124f, 0.2808423357f, 0.3498946567f, -0.2229685561f, 0.3305823267f, -0.2436681211f, -0.03402776529f, - -0.319358823f, 0.4454633477f, 0.4483504221f, -0.4427358436f, 0.05452298565f, -0.2812560807f, 0.1266696921f, -0.3735981243f, 0.2959708351f, -0.3714377181f, -0.404467102f, 0.1636165687f, 0.3289185495f, -0.2494824991f, 0.03283133272f, -0.166306057f, - -0.106833179f, 0.06440260376f, -0.4483230967f, -0.421377757f, 0.05097920662f, 0.2050584153f, 0.4178098529f, -0.3565189504f, 0.4478398129f, -0.3399999602f, 0.3767121994f, -0.3138934434f, -0.1462001792f, 0.3970290489f, 0.4459149305f, -0.4104889426f, - 0.1475103971f, 0.09258030352f, -0.1589664637f, 0.2482445008f, 0.4383624232f, 0.06242802956f, 0.2846591015f, -0.344202744f, 0.1198188883f, -0.243590703f, 0.2958191174f, -0.1164007991f, 0.1274037151f, 0.368047306f, 0.2451436949f, -0.4314509715f, -}; -const float CELL_2D_Y[] = -{ - 0.1281943404f, 0.415278375f, -0.3505218461f, 0.3517627718f, -0.3237467165f, -0.2967353402f, -0.09710417025f, -0.05953502905f, 0.3334085102f, -0.3965687458f, 0.3361990872f, 0.3871778202f, -0.04695150755f, 0.41340573f, -0.4171197882f, 0.4392750616f, - 0.4419948321f, -0.1857461384f, -0.2857157906f, -0.30038326f, -0.3868891648f, 0.449872789f, -0.05976119672f, 0.2631606867f, 0.2834856838f, 0.1803655873f, 0.3619887311f, -0.3142230135f, -0.3457315612f, -0.2258540565f, -0.02667811596f, 0.01430799601f, - -0.4314657307f, 0.4485799926f, -0.1335025276f, 0.3145735065f, 0.3302087162f, 0.1751754899f, 0.2505256519f, -0.3904653228f, -0.4499902136f, -0.4146991995f, -0.08247647938f, -0.355112935f, -0.2023496216f, -0.2293938184f, 0.1326367019f, -0.4489736231f, - 0.2845441624f, -0.4476902368f, 0.4484280562f, 0.3095250049f, -0.4452222108f, 0.448706869f, 0.06742966669f, -0.1461850686f, 0.008627302568f, 0.4469356864f, -0.02055026661f, 0.4335725488f, -0.2924813028f, 0.2304191809f, -0.447738214f, 0.4455915232f, - -0.2187385324f, -0.04988730975f, -0.2482076684f, 0.357223947f, 0.4166344988f, 0.1848760794f, -0.3130881435f, -0.3455761521f, 0.4005435199f, -0.08751256895f, 0.4172743077f, 0.4499824166f, 0.4003301853f, -0.4499587123f, -0.4338091548f, -0.2242337048f, - 0.4496698165f, 0.3340561458f, -0.4497451511f, -0.1757577897f, -0.4071547394f, 0.2488600778f, 0.3904147331f, -0.1700466149f, 0.267424695f, -0.4083336779f, 0.323561623f, 0.307891826f, 0.3870899429f, 0.2894847362f, -0.1698621719f, -0.3687717212f, - 0.2683874578f, 0.3886668486f, 0.3994821043f, -0.4421754202f, 0.1286329626f, 0.3105090899f, -0.4134275279f, 0.06566979625f, 0.2146355146f, 0.1436338239f, -0.2420141339f, -0.4476245948f, -0.2540826796f, -0.3698392535f, 0.4486549822f, 0.3294387544f, - 0.3893076172f, -0.1817925206f, -0.3434387019f, -0.348876097f, -0.3247973695f, -0.0566844308f, -0.3320331606f, 0.1899159123f, -0.2844501228f, 0.3096924441f, 0.3152548881f, 0.4498443737f, 0.1211526057f, 0.324405723f, 0.3579183483f, -0.1556373694f, - -0.4385260051f, -0.3568750521f, 0.4254810025f, -0.3866459777f, 0.2562064828f, -0.4374099171f, 0.3639355292f, 0.2801200935f, -0.4095705534f, -0.4033856449f, 0.2179339044f, 0.3137180602f, 0.2416318948f, 0.4248640083f, 0.1911149365f, 0.1581729856f, - 0.3657704353f, -0.3716678248f, 0.3979825013f, 0.2667493029f, -0.2638881295f, 0.3856762766f, 0.3101519002f, -0.3963950918f, -0.2386584257f, 0.2913186713f, 0.1129794154f, 0.3977477059f, -0.3006402163f, 0.2912367377f, -0.3872658529f, -0.3709337882f, - -0.151816397f, 0.4228731957f, 0.09079595574f, -0.444824484f, -0.06451237284f, -0.3699158705f, -0.3082761026f, -0.1803533432f, -0.3000012356f, -0.05494615882f, 0.4202531296f, 0.4399356268f, -0.4492262904f, -0.05098119915f, 0.1091291678f, 0.2137643437f, - -0.1507312575f, 0.2274622243f, -0.1378521198f, 0.305521251f, -0.3036127481f, -0.1786438231f, -0.4420846725f, 0.2373934748f, -0.2543249683f, -0.04979563372f, 0.05473234629f, -0.4473649407f, -0.1607463688f, 0.39225481f, 0.2666476169f, -0.1989975647f, - 0.3951678503f, -0.1116106179f, 0.1670735057f, 0.4027334247f, -0.4440754146f, -0.2639281632f, 0.126870413f, 0.3376855855f, 0.3355289094f, 0.3619594822f, 0.3516071423f, 0.2829730186f, 0.390877248f, 0.3053118493f, -0.3783197679f, 0.4487116125f, - 0.3170330301f, -0.06373700535f, 0.03849544189f, -0.08052932871f, 0.4466847255f, 0.3512762688f, 0.4318041097f, 0.2508474468f, -0.3389708908f, 0.254035473f, -0.1972469604f, -0.419201167f, -0.3071035458f, -0.3745109914f, 0.4488007393f, -0.4181414777f, - 0.4371346153f, -0.4453676062f, 0.03881238203f, -0.1579265206f, -0.4471030312f, -0.4005634111f, -0.167137449f, -0.2745801121f, 0.04403977727f, -0.2947881053f, 0.2461461331f, 0.3224451987f, -0.4255884251f, -0.2118205239f, -0.06049689889f, -0.1843877112f, - -0.4251360756f, 0.4403735771f, -0.4209865359f, 0.3753327428f, -0.1016778537f, 0.4456486745f, -0.3485243118f, -0.2898697484f, -0.4337550392f, 0.3783696201f, -0.3391033025f, 0.4346847754f, -0.4315881062f, 0.2589231171f, 0.3773652989f, 0.12786735f, -}; -const float CELL_3D_X[] = -{ - 0.1453787434f, -0.01242829687f, 0.2877979582f, -0.07732986802f, 0.1107205875f, 0.2755209141f, 0.294168941f, 0.4000921098f, -0.1697304074f, -0.1483224484f, 0.2623596946f, -0.2709003183f, -0.03516550699f, -0.1267712655f, 0.02952021915f, -0.2806854217f, - -0.171159547f, 0.2113227183f, -0.1024352839f, -0.3304249877f, 0.2091111325f, 0.344678154f, 0.1984478035f, -0.2929008603f, -0.1617332831f, -0.3582060271f, -0.1852067326f, 0.3046301062f, -0.03816768434f, -0.4084952196f, -0.02687443361f, -0.03801098351f, - 0.2371120802f, 0.4447660503f, 0.01985147278f, 0.4274339143f, -0.2072988631f, -0.3791240978f, -0.2098721267f, 0.01582798878f, -0.1888129464f, 0.1612988974f, -0.08974491322f, 0.07041229526f, -0.1082925611f, 0.2474100658f, -0.1068836661f, 0.2396452163f, - -0.3063886072f, 0.1593342891f, 0.2709690528f, -0.1519780427f, 0.1699773681f, -0.1986155616f, -0.1887482106f, 0.2659103394f, -0.08838976154f, -0.04201869311f, -0.3230334656f, 0.2612720941f, 0.385713046f, 0.07654967953f, 0.4317038818f, -0.2890436293f, - -0.2201947582f, 0.4161322773f, 0.2204718095f, -0.1040307469f, -0.1432122615f, 0.3978380468f, -0.2599274663f, 0.4032618332f, -0.08953470255f, 0.118937202f, 0.02167047076f, -0.3411343612f, 0.3162964612f, 0.2355138889f, -0.02874541518f, -0.2461455173f, - 0.04208029445f, 0.2727458746f, -0.1347522818f, 0.3829624424f, -0.3547613644f, 0.2305790207f, -0.08323845599f, 0.2993663085f, -0.2154865723f, 0.01683355354f, 0.05240429123f, 0.00940104872f, 0.3465688735f, -0.3706867948f, 0.2741169781f, 0.06413433865f, - -0.388187972f, 0.06419469312f, -0.1986120739f, -0.203203009f, -0.1389736354f, -0.06555641638f, -0.2529246486f, 0.1444476522f, -0.3643780054f, 0.4286142488f, 0.165872923f, 0.2219610524f, 0.04322940318f, -0.08481269795f, 0.1822082075f, -0.3269323334f, - -0.4080485344f, 0.2676025294f, 0.3024892441f, 0.1448494052f, 0.4198402157f, -0.3008872161f, 0.3639310428f, 0.3295806598f, 0.2776259487f, 0.4149000507f, 0.145016715f, 0.09299023471f, 0.1028907093f, 0.2683057049f, -0.4227307273f, -0.1781224702f, - 0.4390788626f, 0.2972583585f, -0.1707002821f, 0.3806686614f, -0.1751445661f, -0.2227237566f, 0.1369633021f, -0.3529503428f, -0.2590744185f, -0.3784019401f, -0.05635805671f, 0.3251428613f, -0.4190995804f, -0.3253150961f, 0.2857945863f, -0.2733604046f, - 0.219003657f, 0.3182767252f, -0.03222023115f, -0.3087780231f, -0.06487611647f, 0.3921171432f, -0.1606404506f, -0.03767771199f, 0.1394866832f, -0.4345093872f, -0.1044637494f, 0.2658727501f, 0.2051461999f, -0.266085566f, 0.07849405464f, -0.2160686338f, - -0.185779186f, 0.02492421743f, -0.120167831f, -0.02160084693f, 0.2597670064f, -0.1611553854f, -0.3278896792f, 0.2822734956f, 0.03169341113f, 0.2202613604f, 0.2933396046f, -0.3194922995f, -0.3441586045f, 0.2703645948f, 0.2298568861f, 0.09326603877f, - -0.1116165319f, 0.2172907365f, 0.1991339479f, -0.0541918155f, 0.08871336998f, 0.2787673278f, -0.322166438f, -0.4277366384f, 0.240131882f, 0.1448607981f, -0.3837065682f, -0.4382627882f, -0.37728353f, 0.1259579313f, -0.1406285511f, -0.1580694418f, - 0.2477612106f, 0.2916132853f, 0.07365265219f, -0.26126526f, -0.3721862032f, -0.3691191571f, 0.2278441737f, 0.363398169f, -0.304231482f, -0.3199312232f, 0.2874852279f, -0.1451096801f, 0.3220090754f, -0.1247400865f, -0.2829555867f, 0.1069384374f, - -0.1420661144f, -0.250548338f, 0.3265787872f, 0.07646097258f, 0.3451771584f, 0.298137964f, 0.2812250376f, 0.4390345476f, 0.2148373234f, 0.2595421179f, 0.3182823114f, -0.4089859285f, -0.2826749061f, 0.3483864637f, -0.3226415069f, 0.4330734858f, - -0.08717822568f, -0.2149678299f, -0.2687330705f, 0.2105665099f, 0.4361845915f, 0.05333333359f, -0.05986216652f, 0.3664988455f, -0.2341015558f, -0.04730947785f, -0.2391566239f, -0.1242081035f, 0.2614832715f, -0.2728794681f, 0.007892900508f, -0.01730330376f, - 0.2054835762f, -0.3231994983f, -0.2669545963f, -0.05554372779f, -0.2083935713f, 0.06989323478f, 0.3847566193f, -0.3026215288f, 0.3450735512f, 0.1814473292f, -0.03855010448f, 0.3533670318f, -0.007945601311f, 0.4063099273f, -0.2016773589f, -0.07527055435f, -}; -const float CELL_3D_Y[] = -{ - -0.4149781685f, -0.1457918398f, -0.02606483451f, 0.2377094325f, -0.3552302079f, 0.2640521179f, 0.1526064594f, -0.2034056362f, 0.3970864695f, -0.3859694688f, -0.2354852944f, 0.3505271138f, 0.3885234328f, 0.1920044036f, 0.4409685861f, -0.266996757f, - 0.2141185563f, 0.3902405947f, 0.2128044156f, -0.1566986703f, 0.3133278055f, -0.1944240454f, -0.3214342325f, 0.2262915116f, 0.006314769776f, -0.148303178f, -0.3454119342f, 0.1026310383f, -0.2551766358f, 0.1805950793f, -0.2749741471f, 0.3277859044f, - 0.2900386767f, 0.03946930643f, -0.01503183293f, 0.03345994256f, 0.2871414597f, 0.1281177671f, -0.1007087278f, 0.4263894424f, -0.3160996813f, -0.1974805082f, 0.229148752f, 0.4150230285f, -0.1586061639f, -0.3309414609f, -0.2701644537f, 0.06803600538f, - 0.2597428179f, -0.3114350249f, 0.1412648683f, 0.3623355133f, 0.3456012883f, 0.3836276443f, -0.2050154888f, 0.3015631259f, -0.4288819642f, 0.3099592485f, 0.201549922f, 0.2759854499f, 0.2193460345f, 0.3721732183f, -0.02577753072f, -0.3418179959f, - 0.383023377f, -0.1669634289f, 0.02654238946f, 0.3890079625f, 0.371614387f, -0.06206669342f, 0.2616724959f, -0.1124593585f, -0.3048244735f, -0.2875221847f, -0.03284630549f, 0.2500031105f, 0.3082064153f, -0.3439334267f, -0.3955933019f, 0.02020282325f, - -0.4470439576f, 0.2288471896f, -0.02720848277f, 0.1231931484f, 0.1271702173f, 0.3063895591f, -0.1922245118f, -0.2619918095f, 0.2706747713f, -0.2680655787f, 0.4335128183f, -0.4472890582f, 0.01141914583f, -0.2551104378f, 0.2139972417f, 0.1708718512f, - -0.03973280434f, -0.2803682491f, -0.3391173584f, -0.3871641506f, -0.2775901578f, 0.342253257f, -0.2904227915f, 0.1069184044f, -0.2447099973f, -0.1358496089f, -0.3136808464f, -0.3658139958f, -0.3832730794f, -0.4404869674f, -0.3953259299f, 0.3036542563f, - 0.04227858267f, -0.01299671652f, -0.1009990293f, 0.425921681f, 0.08062320474f, -0.333040905f, -0.1291284382f, 0.0184175994f, -0.2974929052f, -0.144793182f, -0.0398992945f, -0.299732164f, -0.361266869f, -0.07076041213f, -0.07933161816f, 0.1806857196f, - -0.02841848598f, 0.2382799621f, 0.2215845691f, 0.1471852559f, -0.274887877f, -0.2316778837f, 0.1341343041f, -0.2472893463f, -0.2985577559f, 0.2199816631f, 0.1485737441f, 0.09666046873f, 0.1406751354f, -0.3080335042f, -0.05796152095f, 0.1973770973f, - 0.2410037886f, -0.271342949f, -0.3331161506f, 0.1992794134f, -0.4311322747f, -0.06294284106f, -0.358928121f, -0.2290351443f, -0.3602213994f, 0.005751117145f, 0.4168128432f, 0.2551943237f, 0.1975390727f, 0.23483312f, -0.3300346342f, 0.05376451292f, - 0.2148499206f, -0.3229954284f, 0.4017266681f, -0.06885389554f, 0.3096300784f, -0.09823036005f, 0.1461670309f, 0.03754421121f, 0.347405252f, -0.3460788041f, 0.3031973659f, 0.2453752201f, -0.1698856132f, -0.3574277231f, 0.3744156221f, -0.3170108894f, - -0.2985018719f, -0.3460005203f, 0.3820341668f, -0.2103145071f, 0.2012117383f, 0.3505404674f, 0.3067213525f, 0.132066775f, -0.1612516055f, -0.2387819045f, -0.2206398454f, -0.09082753406f, 0.05445141085f, 0.348394558f, -0.270877371f, 0.4162931958f, - -0.2927867412f, 0.3312535401f, -0.1666159848f, -0.2422237692f, 0.252790166f, -0.255281188f, -0.3358364886f, -0.2310190248f, -0.2698452035f, 0.316332536f, 0.1642275508f, 0.3277541114f, 0.0511344108f, -0.04333605335f, -0.3056190617f, 0.3491024667f, - -0.3055376754f, 0.3156466809f, 0.1871229129f, -0.3026690852f, 0.2757120714f, 0.2852657134f, 0.3466716415f, -0.09790429955f, 0.1850172527f, -0.07946825393f, -0.307355516f, -0.04647718411f, 0.07417482322f, 0.225442246f, -0.1420585388f, -0.118868561f, - -0.3909896417f, 0.3939973956f, 0.322686276f, -0.1961317136f, -0.1105517485f, -0.313639498f, 0.1361029153f, 0.2550543014f, -0.182405731f, -0.4222150243f, -0.2577696514f, 0.4256953395f, -0.3650179274f, -0.3499628774f, -0.1672771315f, 0.2978486637f, - -0.3252600376f, 0.1564282844f, 0.2599343665f, 0.3170813944f, -0.310922837f, -0.3156141536f, -0.1605309138f, -0.3001537679f, 0.08611519592f, -0.2788782453f, 0.09795110726f, 0.2665752752f, 0.140359426f, -0.1491768253f, 0.008816271194f, -0.425643481f, -}; -const float CELL_3D_Z[] = -{ - -0.0956981749f, -0.4255470325f, -0.3449535616f, 0.3741848704f, -0.2530858567f, -0.238463215f, 0.3044271714f, 0.03244149937f, -0.1265461359f, 0.1775613147f, 0.2796677792f, -0.07901746678f, 0.2243054374f, 0.3867342179f, 0.08470692262f, 0.2289725438f, - 0.3568720405f, -0.07453178509f, -0.3830421561f, 0.2622305365f, -0.2461670583f, -0.2142341261f, -0.2445373252f, 0.2559320961f, -0.4198838754f, -0.2284613961f, -0.2211087107f, 0.314908508f, -0.3686842991f, 0.05492788837f, 0.3551999201f, 0.3059600725f, - -0.2493099024f, 0.05590469027f, -0.4493105419f, -0.1366772882f, -0.2776273824f, 0.2057929936f, -0.3851122467f, 0.1429738373f, -0.2587096108f, -0.3707885038f, -0.3767448739f, -0.1590534329f, 0.4069604477f, 0.1782302128f, -0.3436379634f, -0.3747549496f, - 0.2028785103f, -0.2830561951f, -0.3303331794f, 0.2193527988f, 0.2327390037f, -0.1260225743f, -0.353330953f, -0.2021172246f, -0.1036702021f, 0.3235115047f, -0.2398478873f, -0.2409749453f, 0.07491837764f, 0.241095919f, 0.1243675091f, -0.04598084447f, - -0.08548310451f, -0.03817251927f, -0.391391981f, -0.2008741118f, -0.2095065525f, 0.2009293758f, -0.2578084893f, 0.1650235939f, 0.3186935478f, 0.325092195f, -0.4482761547f, 0.1537068389f, -0.08640228117f, -0.1695376245f, 0.2125550295f, -0.3761704803f, - 0.02968078139f, -0.2752065618f, -0.4284874806f, -0.2016512234f, 0.2459107769f, 0.2354968222f, 0.3982726409f, -0.2103333191f, 0.287751117f, -0.3610505186f, -0.1087217856f, 0.04841609928f, -0.2868093776f, 0.003156692623f, -0.2855959784f, 0.4113266307f, - -0.2241236325f, 0.3460819069f, 0.2192091725f, 0.1063600375f, -0.3257760473f, -0.2847192729f, 0.2327739768f, 0.4125570634f, -0.09922543227f, -0.01829506817f, -0.2767498872f, 0.1393320198f, 0.2318037215f, -0.03574965489f, 0.1140946023f, 0.05838957105f, - -0.184956522f, 0.36155217f, -0.3174892964f, -0.0104580805f, 0.1404780841f, -0.03241355801f, -0.2310412139f, -0.3058388149f, -0.1921504723f, -0.09691688386f, 0.4241205002f, -0.3225111565f, 0.247789732f, -0.3542668666f, -0.1323073187f, -0.3716517945f, - -0.09435116353f, -0.2394997452f, 0.3525077196f, -0.1895464869f, 0.3102596268f, 0.3149912482f, -0.4071228836f, -0.129514612f, -0.2150435121f, -0.1044989934f, 0.4210102279f, -0.2957006485f, -0.08405978803f, -0.04225456877f, 0.3427271751f, -0.2980207554f, - -0.3105713639f, 0.1660509868f, -0.300824678f, -0.2596995338f, 0.1114273361f, -0.2116183942f, -0.2187812825f, 0.3855169162f, 0.2308332918f, 0.1169124335f, -0.1336202785f, 0.2582393035f, 0.3484154868f, 0.2766800993f, -0.2956616708f, -0.3910546287f, - 0.3490352499f, -0.3123343347f, 0.1633259825f, 0.4441762538f, 0.1978643903f, 0.4085091653f, 0.2713366126f, -0.3484423997f, -0.2842624114f, -0.1849713341f, 0.1565989581f, -0.200538455f, -0.2349334659f, 0.04060059933f, 0.0973588921f, 0.3054595587f, - 0.3177080142f, -0.1885958001f, -0.1299829458f, 0.39412061f, 0.3926114802f, 0.04370535101f, 0.06804996813f, 0.04582286686f, 0.344723946f, 0.3528435224f, 0.08116235683f, -0.04664855374f, 0.2391488697f, 0.2554522098f, -0.3306796947f, -0.06491553533f, - -0.2353514536f, 0.08793624968f, 0.411478311f, 0.2748965434f, 0.008634938242f, 0.03290232422f, 0.1944244981f, 0.1306597909f, 0.1926830856f, -0.008816977938f, -0.304764754f, -0.2720669462f, 0.3101538769f, -0.4301882115f, -0.1703910946f, -0.2630430352f, - -0.2982682484f, -0.2002316239f, 0.2466400438f, 0.324106687f, -0.0856480183f, 0.179547284f, 0.05684409612f, -0.01278335452f, 0.3494474791f, 0.3589187731f, -0.08203022006f, 0.1818526372f, 0.3421885344f, -0.1740766085f, -0.2796816575f, -0.02859407492f, - -0.2050050172f, -0.03247898316f, -0.1617284888f, -0.3459683451f, 0.004616608544f, -0.3182543336f, -0.4247264031f, -0.05590974511f, 0.3382670703f, -0.1483114513f, -0.2808182972f, -0.07652336246f, 0.02980623099f, 0.07458404908f, 0.4176793787f, -0.3368779738f, - -0.2334146693f, -0.2712420987f, -0.2523278991f, -0.3144428146f, -0.2497981362f, 0.3130537363f, -0.1693876312f, -0.1443188342f, 0.2756962409f, -0.3029914042f, 0.4375151083f, 0.08105160988f, -0.4274764309f, -0.1231199324f, -0.4021797064f, -0.1251477955f, -}; - -static int FastFloor(float f) { return (f >= 0.0f ? (int)f : (int)f - 1); } -static int FastRound(float f) { return (f >= 0.0f) ? (int)(f + 0.5f) : (int)(f - 0.5f); } -static float FastAbs(float f) { return fabsf(f); } -static int FastAbs(int i) { return abs(i); } -static float Lerp(float a, float b, float t) { return a + t * (b - a); } -static void LerpVector3(float* out, float* a, float* b, float t) -{ - out[0] = Lerp(a[0], b[0], t); - out[1] = Lerp(a[1], b[1], t); - out[2] = Lerp(a[2], b[2], t); -} - -static float InterpHermiteFunc(float t) { return t*t*(3 - 2 * t); } -static float InterpQuinticFunc(float t) { return t*t*t*(t*(t * 6 - 15) + 10); } - -void PolygonalMapGenNoise::SetSeed(int seed) -{ - m_seed = seed; - - std::mt19937 gen(seed); - - for (int i = 0; i < 256; i++) - m_perm[i] = i; - - for (int j = 0; j < 256; j++) - { - std::uniform_int_distribution<> dis(0, 256 - j); - int k = dis(gen) + j; - int l = m_perm[j]; - m_perm[j] = m_perm[j + 256] = m_perm[k]; - m_perm[k] = l; - m_perm12[j] = m_perm12[j + 256] = m_perm[j] % 12; - } -} - -unsigned char PolygonalMapGenNoise::Index2D_12(unsigned char offset, int x, int y) -{ - return m_perm12[(x & 0xff) + m_perm[(y & 0xff) + offset]]; -} -unsigned char PolygonalMapGenNoise::Index3D_12(unsigned char offset, int x, int y, int z) -{ - return m_perm12[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + offset]]]; -} -unsigned char PolygonalMapGenNoise::Index4D_32(unsigned char offset, int x, int y, int z, int w) -{ - return m_perm[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + m_perm[(w & 0xff) + offset]]]] & 31; -} -unsigned char PolygonalMapGenNoise::Index2D_256(unsigned char offset, int x, int y) -{ - return m_perm[(x & 0xff) + m_perm[(y & 0xff) + offset]]; -} -unsigned char PolygonalMapGenNoise::Index3D_256(unsigned char offset, int x, int y, int z) -{ - return m_perm[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + offset]]]; -} -unsigned char PolygonalMapGenNoise::Index4D_256(unsigned char offset, int x, int y, int z, int w) -{ - return m_perm[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + m_perm[(w & 0xff) + offset]]]]; -} - -// Hashing -#define X_PRIME 1619 -#define Y_PRIME 31337 -#define Z_PRIME 6971 -#define W_PRIME 1013 - -static float ValCoord2D(int seed, int x, int y) -{ - int n = X_PRIME * x; - n += Y_PRIME * y; - n += seed; - n &= 0x7fffffff; - n = (n >> 13) ^ n; - return 9.311924889611565e-10f * (((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff) - 1073891824); -} -static float ValCoord3D(int seed, int x, int y, int z) -{ - int n = X_PRIME * x; - n += Y_PRIME * y; - n += Z_PRIME * z; - n += seed; - n &= 0x7fffffff; - n = (n >> 13) ^ n; - return 9.311924889611565e-10f * (((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff) - 1073891824); -} -static float ValCoord4D(int seed, int x, int y, int z, int w) -{ - int n = X_PRIME * x; - n += Y_PRIME * y; - n += Z_PRIME * z; - n += W_PRIME * w; - n += seed; - n &= 0x7fffffff; - n = (n >> 13) ^ n; - return 9.311924889611565e-10f * (((n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff) - 1073891824); -} - -float PolygonalMapGenNoise::ValCoord2DFast(unsigned char offset, int x, int y) -{ - return VAL_LUT[Index2D_256(x, y, offset)]; -} -float PolygonalMapGenNoise::ValCoord3DFast(unsigned char offset, int x, int y, int z) -{ - return VAL_LUT[Index3D_256(x, y, z, offset)]; -} - -float PolygonalMapGenNoise::GradCoord2D(unsigned char offset, int x, int y, float xd, float yd) -{ - unsigned char lutPos = Index2D_12(x, y, offset); - - return xd*GRAD_X[lutPos] + yd*GRAD_Y[lutPos]; -} -float PolygonalMapGenNoise::GradCoord3D(unsigned char offset, int x, int y, int z, float xd, float yd, float zd) -{ - unsigned char lutPos = Index3D_12(x, y, z, offset); - - return xd*GRAD_X[lutPos] + yd*GRAD_Y[lutPos] + zd*GRAD_Z[lutPos]; -} -float PolygonalMapGenNoise::GradCoord4D(unsigned char offset, int x, int y, int z, int w, float xd, float yd, float zd, float wd) -{ - unsigned char lutPos = Index4D_32(x, y, z, w, offset) << 2; - - return xd*GRAD_4D[lutPos] + yd*GRAD_4D[lutPos + 1] + zd*GRAD_4D[lutPos + 2] + wd*GRAD_4D[lutPos + 3]; -} - -void PolygonalMapGenNoise::SetNoiseSettings(FNoiseSettings m_noiseSettings) -{ - SetFractalType(m_noiseSettings.FractalType); - SetNoiseType(m_noiseSettings.NoiseType); - SetInterp(m_noiseSettings.NoiseInterpolation); - - SetSeed((uint32)m_noiseSettings.Seed); - SetFrequency(m_noiseSettings.NoiseFrequency); - SetFractalOctaves((uint32)m_noiseSettings.NoiseOctaves); - SetFractalLacunarity(m_noiseSettings.Lacunarity); - SetFractalGain(m_noiseSettings.Gain); -} - -float PolygonalMapGenNoise::GetNoise(float x, float y, float z) -{ - x *= m_frequency; - y *= m_frequency; - z *= m_frequency; - - switch (m_noiseType) - { - case ENoiseType::Value: - return SingleValue(0, x, y, z); - case ENoiseType::ValueFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleValueFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleValueFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleValueFractalRigidMulti(x, y, z); - default: - return 0.0f; - } - case ENoiseType::Gradient: - return SingleGradient(0, x, y, z); - case ENoiseType::GradientFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleGradientFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleGradientFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleGradientFractalRigidMulti(x, y, z); - default: - return 0.0f; - } - case ENoiseType::Simplex: - return SingleSimplex(0, x, y, z); - case ENoiseType::SimplexFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleSimplexFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleSimplexFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleSimplexFractalRigidMulti(x, y, z); - default: - return 0.0f; - } - case ENoiseType::Cellular: - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - case ECellularReturnType::NoiseLookup: - case ECellularReturnType::Distance: - return SingleCellular(x, y, z); - default: - return SingleCellular2Edge(x, y, z); - } - case ENoiseType::WhiteNoise: - return GetWhiteNoise(x, y, z); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::GetNoise(float x, float y) -{ - x *= m_frequency; - y *= m_frequency; - - switch (m_noiseType) - { - case ENoiseType::Value: - return SingleValue(0, x, y); - case ENoiseType::ValueFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleValueFractalFBM(x, y); - case EFractalType::Billow: - return SingleValueFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleValueFractalRigidMulti(x, y); - default: - return 0.0f; - } - case ENoiseType::Gradient: - return SingleGradient(0, x, y); - case ENoiseType::GradientFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleGradientFractalFBM(x, y); - case EFractalType::Billow: - return SingleGradientFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleGradientFractalRigidMulti(x, y); - default: - return 0.0f; - } - case ENoiseType::Simplex: - return SingleSimplex(0, x, y); - case ENoiseType::SimplexFractal: - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleSimplexFractalFBM(x, y); - case EFractalType::Billow: - return SingleSimplexFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleSimplexFractalRigidMulti(x, y); - default: - return 0.0f; - } - case ENoiseType::Cellular: - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - case ECellularReturnType::NoiseLookup: - case ECellularReturnType::Distance: - return SingleCellular(x, y); - default: - return SingleCellular2Edge(x, y); - } - case ENoiseType::WhiteNoise: - return GetWhiteNoise(x, y); - default: - return 0.0f; - } -} - -// White Noise -float PolygonalMapGenNoise::GetWhiteNoise(float x, float y, float z, float w) -{ - float noiseAmount = ValCoord4D(m_seed, - *reinterpret_cast(&x) ^ (*reinterpret_cast(&x) >> 16), - *reinterpret_cast(&y) ^ (*reinterpret_cast(&y) >> 16), - *reinterpret_cast(&z) ^ (*reinterpret_cast(&z) >> 16), - *reinterpret_cast(&w) ^ (*reinterpret_cast(&w) >> 16)); - - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -float PolygonalMapGenNoise::GetWhiteNoise(float x, float y, float z) -{ - float noiseAmount = ValCoord3D(m_seed, - *reinterpret_cast(&x) ^ (*reinterpret_cast(&x) >> 16), - *reinterpret_cast(&y) ^ (*reinterpret_cast(&y) >> 16), - *reinterpret_cast(&z) ^ (*reinterpret_cast(&z) >> 16)); - - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -float PolygonalMapGenNoise::GetWhiteNoise(float x, float y) -{ - float noiseAmount = ValCoord2D(m_seed, - *reinterpret_cast(&x) ^ (*reinterpret_cast(&x) >> 16), - *reinterpret_cast(&y) ^ (*reinterpret_cast(&y) >> 16)); - - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -float PolygonalMapGenNoise::GetWhiteNoiseInt(int x, int y, int z, int w) -{ - return ValCoord4D(m_seed, x, y, z, w); -} - -float PolygonalMapGenNoise::GetWhiteNoiseInt(int x, int y, int z) -{ - return ValCoord3D(m_seed, x, y, z); -} - -float PolygonalMapGenNoise::GetWhiteNoiseInt(int x, int y) -{ - return ValCoord2D(m_seed, x, y); -} - -// Value Noise -float PolygonalMapGenNoise::GetValueFractal(float x, float y, float z) -{ - x *= m_frequency; - y *= m_frequency; - z *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleValueFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleValueFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleValueFractalRigidMulti(x, y, z); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleValueFractalFBM(float x, float y, float z) -{ - float sum = SingleValue(m_perm[0], x, y, z); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleValue(m_perm[i], x, y, z) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleValueFractalBillow(float x, float y, float z) -{ - float sum = FastAbs(SingleValue(m_perm[0], x, y, z)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleValue(m_perm[i], x, y, z)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleValueFractalRigidMulti(float x, float y, float z) -{ - float sum = 1.0f - FastAbs(SingleValue(m_perm[0], x, y, z)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleValue(m_perm[i], x, y, z))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetValue(float x, float y, float z) -{ - return SingleValue(0, x * m_frequency, y * m_frequency, z * m_frequency); -} - -float PolygonalMapGenNoise::SingleValue(unsigned char offset, float x, float y, float z) -{ - int x0 = FastFloor(x); - int y0 = FastFloor(y); - int z0 = FastFloor(z); - int x1 = x0 + 1; - int y1 = y0 + 1; - int z1 = z0 + 1; - - float xs, ys, zs; - switch (m_interp) - { - case EInterp::InterpLinear: - xs = x - (float)x0; - ys = y - (float)y0; - zs = z - (float)z0; - break; - case EInterp::InterpHermite: - xs = InterpHermiteFunc(x - (float)x0); - ys = InterpHermiteFunc(y - (float)y0); - zs = InterpHermiteFunc(z - (float)z0); - break; - case EInterp::InterpQuintic: - xs = InterpQuinticFunc(x - (float)x0); - ys = InterpQuinticFunc(y - (float)y0); - zs = InterpQuinticFunc(z - (float)z0); - break; - default: - xs = 0.0f; - ys = 0.0f; - zs = 0.0f; - } - - float xf00 = Lerp(ValCoord3DFast(offset, x0, y0, z0), ValCoord3DFast(offset, x1, y0, z0), xs); - float xf10 = Lerp(ValCoord3DFast(offset, x0, y1, z0), ValCoord3DFast(offset, x1, y1, z0), xs); - float xf01 = Lerp(ValCoord3DFast(offset, x0, y0, z1), ValCoord3DFast(offset, x1, y0, z1), xs); - float xf11 = Lerp(ValCoord3DFast(offset, x0, y1, z1), ValCoord3DFast(offset, x1, y1, z1), xs); - - float yf0 = Lerp(xf00, xf10, ys); - float yf1 = Lerp(xf01, xf11, ys); - - return Lerp(yf0, yf1, zs); -} - -float PolygonalMapGenNoise::GetValueFractal(float x, float y) -{ - x *= m_frequency; - y *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleValueFractalFBM(x, y); - case EFractalType::Billow: - return SingleValueFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleValueFractalRigidMulti(x, y); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleValueFractalFBM(float x, float y) -{ - float sum = SingleValue(m_perm[0], x, y); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleValue(m_perm[i], x, y) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleValueFractalBillow(float x, float y) -{ - float sum = FastAbs(SingleValue(m_perm[0], x, y)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleValue(m_perm[i], x, y)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleValueFractalRigidMulti(float x, float y) -{ - float sum = 1.0f - FastAbs(SingleValue(m_perm[0], x, y)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleValue(m_perm[i], x, y))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetValue(float x, float y) -{ - return SingleValue(0, x * m_frequency, y * m_frequency); -} - -float PolygonalMapGenNoise::SingleValue(unsigned char offset, float x, float y) -{ - int x0 = FastFloor(x); - int y0 = FastFloor(y); - int x1 = x0 + 1; - int y1 = y0 + 1; - - float xs, ys; - switch (m_interp) - { - case EInterp::InterpLinear: - xs = x - (float)x0; - ys = y - (float)y0; - break; - case EInterp::InterpHermite: - xs = InterpHermiteFunc(x - (float)x0); - ys = InterpHermiteFunc(y - (float)y0); - break; - case EInterp::InterpQuintic: - xs = InterpQuinticFunc(x - (float)x0); - ys = InterpQuinticFunc(y - (float)y0); - break; - default: - xs = 0.0f; - ys = 0.0f; - break; - } - - float xf0 = Lerp(ValCoord2DFast(offset, x0, y0), ValCoord2DFast(offset, x1, y0), xs); - float xf1 = Lerp(ValCoord2DFast(offset, x0, y1), ValCoord2DFast(offset, x1, y1), xs); - - return Lerp(xf0, xf1, ys); -} - -// Gradient Noise -float PolygonalMapGenNoise::GetGradientFractal(float x, float y, float z) -{ - x *= m_frequency; - y *= m_frequency; - z *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleGradientFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleGradientFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleGradientFractalRigidMulti(x, y, z); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleGradientFractalFBM(float x, float y, float z) -{ - float sum = SingleGradient(m_perm[0], x, y, z); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleGradient(m_perm[i], x, y, z) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleGradientFractalBillow(float x, float y, float z) -{ - float sum = FastAbs(SingleGradient(m_perm[0], x, y, z)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleGradient(m_perm[i], x, y, z)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleGradientFractalRigidMulti(float x, float y, float z) -{ - float sum = 1.0f - FastAbs(SingleGradient(m_perm[0], x, y, z)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleGradient(m_perm[i], x, y, z))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetGradient(float x, float y, float z) -{ - return SingleGradient(0, x * m_frequency, y * m_frequency, z * m_frequency); -} - -float PolygonalMapGenNoise::SingleGradient(unsigned char offset, float x, float y, float z) -{ - int x0 = FastFloor(x); - int y0 = FastFloor(y); - int z0 = FastFloor(z); - int x1 = x0 + 1; - int y1 = y0 + 1; - int z1 = z0 + 1; - - float xs, ys, zs; - switch (m_interp) - { - case EInterp::InterpLinear: - xs = x - (float)x0; - ys = y - (float)y0; - zs = z - (float)z0; - break; - case EInterp::InterpHermite: - xs = InterpHermiteFunc(x - (float)x0); - ys = InterpHermiteFunc(y - (float)y0); - zs = InterpHermiteFunc(z - (float)z0); - break; - case EInterp::InterpQuintic: - xs = InterpQuinticFunc(x - (float)x0); - ys = InterpQuinticFunc(y - (float)y0); - zs = InterpQuinticFunc(z - (float)z0); - break; - default: - xs = 0.0f; - ys = 0.0f; - zs = 0.0f; - } - - float xd0 = x - (float)x0; - float yd0 = y - (float)y0; - float zd0 = z - (float)z0; - float xd1 = xd0 - 1.0f; - float yd1 = yd0 - 1.0f; - float zd1 = zd0 - 1.0f; - - float xf00 = Lerp(GradCoord3D(offset, x0, y0, z0, xd0, yd0, zd0), GradCoord3D(offset, x1, y0, z0, xd1, yd0, zd0), xs); - float xf10 = Lerp(GradCoord3D(offset, x0, y1, z0, xd0, yd1, zd0), GradCoord3D(offset, x1, y1, z0, xd1, yd1, zd0), xs); - float xf01 = Lerp(GradCoord3D(offset, x0, y0, z1, xd0, yd0, zd1), GradCoord3D(offset, x1, y0, z1, xd1, yd0, zd1), xs); - float xf11 = Lerp(GradCoord3D(offset, x0, y1, z1, xd0, yd1, zd1), GradCoord3D(offset, x1, y1, z1, xd1, yd1, zd1), xs); - - float yf0 = Lerp(xf00, xf10, ys); - float yf1 = Lerp(xf01, xf11, ys); - - return Lerp(yf0, yf1, zs); -} - -float PolygonalMapGenNoise::GetGradientFractal(float x, float y) -{ - x *= m_frequency; - y *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleGradientFractalFBM(x, y); - case EFractalType::Billow: - return SingleGradientFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleGradientFractalRigidMulti(x, y); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleGradientFractalFBM(float x, float y) -{ - float sum = SingleGradient(m_perm[0], x, y); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleGradient(m_perm[i], x, y) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleGradientFractalBillow(float x, float y) -{ - float sum = FastAbs(SingleGradient(m_perm[0], x, y)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleGradient(m_perm[i], x, y)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleGradientFractalRigidMulti(float x, float y) -{ - float sum = 1.0f - FastAbs(SingleGradient(m_perm[0], x, y)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleGradient(m_perm[i], x, y))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetGradient(float x, float y) -{ - return SingleGradient(0, x * m_frequency, y * m_frequency); -} - -float PolygonalMapGenNoise::SingleGradient(unsigned char offset, float x, float y) -{ - int x0 = FastFloor(x); - int y0 = FastFloor(y); - int x1 = x0 + 1; - int y1 = y0 + 1; - - float xs, ys; - switch (m_interp) - { - case EInterp::InterpLinear: - xs = x - (float)x0; - ys = y - (float)y0; - break; - case EInterp::InterpHermite: - xs = InterpHermiteFunc(x - (float)x0); - ys = InterpHermiteFunc(y - (float)y0); - break; - case EInterp::InterpQuintic: - xs = InterpQuinticFunc(x - (float)x0); - ys = InterpQuinticFunc(y - (float)y0); - break; - default: - xs = 0.0f; - ys = 0.0f; - break; - } - - float xd0 = x - (float)x0; - float yd0 = y - (float)y0; - float xd1 = xd0 - 1.0f; - float yd1 = yd0 - 1.0f; - - float xf0 = Lerp(GradCoord2D(offset, x0, y0, xd0, yd0), GradCoord2D(offset, x1, y0, xd1, yd0), xs); - float xf1 = Lerp(GradCoord2D(offset, x0, y1, xd0, yd1), GradCoord2D(offset, x1, y1, xd1, yd1), xs); - - float noiseAmount = Lerp(xf0, xf1, ys); - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -// Simplex Noise - -float PolygonalMapGenNoise::GetSimplexFractal(float x, float y, float z) -{ - x *= m_frequency; - y *= m_frequency; - z *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleSimplexFractalFBM(x, y, z); - case EFractalType::Billow: - return SingleSimplexFractalBillow(x, y, z); - case EFractalType::RigidMulti: - return SingleSimplexFractalRigidMulti(x, y, z); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleSimplexFractalFBM(float x, float y, float z) -{ - float sum = SingleSimplex(m_perm[0], x, y, z); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleSimplex(m_perm[i], x, y, z) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleSimplexFractalBillow(float x, float y, float z) -{ - float sum = FastAbs(SingleSimplex(m_perm[0], x, y, z)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleSimplex(m_perm[i], x, y, z)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleSimplexFractalRigidMulti(float x, float y, float z) -{ - float sum = 1.0f - FastAbs(SingleSimplex(m_perm[0], x, y, z)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - z *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleSimplex(m_perm[i], x, y, z))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetSimplex(float x, float y, float z) -{ - return SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency); -} - -static const float F3 = 1.0f / 3.0f; -static const float G3 = 1.0f / 6.0f; - -float PolygonalMapGenNoise::SingleSimplex(unsigned char offset, float x, float y, float z) -{ - float t = (x + y + z) * F3; - int i = FastFloor(x + t); - int j = FastFloor(y + t); - int k = FastFloor(z + t); - - t = (i + j + k) * G3; - float X0 = i - t; - float Y0 = j - t; - float Z0 = k - t; - - float x0 = x - X0; - float y0 = y - Y0; - float z0 = z - Z0; - - int i1, j1, k1; - int i2, j2, k2; - - if (x0 >= y0) - { - if (y0 >= z0) - { - i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; - } - else if (x0 >= z0) - { - i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; - } - else // x0 < z0 - { - i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; - } - } - else // x0 < y0 - { - if (y0 < z0) - { - i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; - } - else if (x0 < z0) - { - i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; - } - else // x0 >= z0 - { - i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; - } - } - - float x1 = x0 - i1 + G3; - float y1 = y0 - j1 + G3; - float z1 = z0 - k1 + G3; - float x2 = x0 - i2 + 2.0f*G3; - float y2 = y0 - j2 + 2.0f*G3; - float z2 = z0 - k2 + 2.0f*G3; - float x3 = x0 - 1.0f + 3.0f*G3; - float y3 = y0 - 1.0f + 3.0f*G3; - float z3 = z0 - 1.0f + 3.0f*G3; - - float n0, n1, n2, n3; - - t = 0.6f - x0*x0 - y0*y0 - z0*z0; - if (t < 0.0f) n0 = 0.0f; - else - { - t *= t; - n0 = t*t*GradCoord3D(offset, i, j, k, x0, y0, z0); - } - - t = 0.6f - x1*x1 - y1*y1 - z1*z1; - if (t < 0.0f) n1 = 0.0f; - else - { - t *= t; - n1 = t*t*GradCoord3D(offset, i + i1, j + j1, k + k1, x1, y1, z1); - } - - t = 0.6f - x2*x2 - y2*y2 - z2*z2; - if (t < 0.0f) n2 = 0.0f; - else - { - t *= t; - n2 = t*t*GradCoord3D(offset, i + i2, j + j2, k + k2, x2, y2, z2); - } - - t = 0.6f - x3*x3 - y3*y3 - z3*z3; - if (t < 0.0f) n3 = 0.0f; - else - { - t *= t; - n3 = t*t*GradCoord3D(offset, i + 1, j + 1, k + 1, x3, y3, z3); - } - - float noiseAmount = 32.0f * (n0 + n1 + n2 + n3); - - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -float PolygonalMapGenNoise::GetSimplexFractal(float x, float y) -{ - x *= m_frequency; - y *= m_frequency; - - switch (m_fractalType) - { - case EFractalType::FBM: - return SingleSimplexFractalFBM(x, y); - case EFractalType::Billow: - return SingleSimplexFractalBillow(x, y); - case EFractalType::RigidMulti: - return SingleSimplexFractalRigidMulti(x, y); - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleSimplexFractalFBM(float x, float y) -{ - float sum = SingleSimplex(m_perm[0], x, y); - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += SingleSimplex(m_perm[i], x, y) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleSimplexFractalBillow(float x, float y) -{ - float sum = FastAbs(SingleSimplex(m_perm[0], x, y)) * 2.0f - 1.0f; - float max = 1.0f; - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - max += amp; - sum += (FastAbs(SingleSimplex(m_perm[i], x, y)) * 2.0f - 1.0f) * amp; - } - - return sum / max; -} - -float PolygonalMapGenNoise::SingleSimplexFractalRigidMulti(float x, float y) -{ - float sum = 1.0f - FastAbs(SingleSimplex(m_perm[0], x, y)); - float amp = 1.0f; - unsigned int i = 0; - - while (++i < m_octaves) - { - x *= m_lacunarity; - y *= m_lacunarity; - - amp *= m_gain; - sum -= (1.0f - FastAbs(SingleSimplex(m_perm[i], x, y))) * amp; - } - - return sum; -} - -float PolygonalMapGenNoise::GetSimplex(float x, float y) -{ - return SingleSimplex(0, x * m_frequency, y * m_frequency); -} - -static const float F2 = 1.f / 2.f; -static const float G2 = 1.f / 4.f; - -float PolygonalMapGenNoise::SingleSimplex(unsigned char offset, float x, float y) -{ - float t = (x + y) * F2; - int i = FastFloor(x + t); - int j = FastFloor(y + t); - - t = (i + j) * G2; - float X0 = i - t; - float Y0 = j - t; - - float x0 = x - X0; - float y0 = y - Y0; - - int i1, j1; - if (x0 > y0) - { - i1 = 1; j1 = 0; - } - else - { - i1 = 0; j1 = 1; - } - - float x1 = x0 - (float)i1 + G2; - float y1 = y0 - (float)j1 + G2; - float x2 = x0 - 1.0f + 2.0f*G2; - float y2 = y0 - 1.0f + 2.0f*G2; - - float n0, n1, n2; - - t = 0.5f - x0*x0 - y0*y0; - if (t < 0) n0 = 0; - else - { - t *= t; - n0 = t * t * GradCoord2D(offset, i, j, x0, y0); - } - - t = 0.5f - x1*x1 - y1*y1; - if (t < 0) n1 = 0; - else - { - t *= t; - n1 = t*t*GradCoord2D(offset, i + i1, j + j1, x1, y1); - } - - t = 0.5f - x2*x2 - y2*y2; - if (t < 0) n2 = 0; - else - { - t *= t; - n2 = t*t*GradCoord2D(offset, i + 1, j + 1, x2, y2); - } - - float noiseAmount = 50.0f * (n0 + n1 + n2); - noiseAmount += 1.0f; - noiseAmount /= 2.0f; - float noiseDiff = (m_noiseRange.Y - m_noiseRange.X); - noiseAmount *= noiseDiff; - return noiseAmount + m_noiseRange.X; -} - -float PolygonalMapGenNoise::GetSimplex(float x, float y, float z, float w) -{ - return SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency, w * m_frequency); -} - -static const int SIMPLEX_4D[] = -{ - 0,1,2,3,0,1,3,2,0,0,0,0,0,2,3,1,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,0, - 0,2,1,3,0,0,0,0,0,3,1,2,0,3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,1,3,2,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,2,0,3,0,0,0,0,1,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,2,3,0,1,2,3,1,0, - 1,0,2,3,1,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,2,0,3,1,0,0,0,0,2,1,3,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 2,0,1,3,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,2,3,0,2,1,0,0,0,0,3,1,2,0, - 2,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,3,1,0,2,0,0,0,0,3,2,0,1,3,2,1,0 -}; - -static const float F4 = (sqrtf(5.0f) - 1.0f) / 4.0f; -static const float G4 = (5.0f - sqrtf(5.0f)) / 20.0f; - -float PolygonalMapGenNoise::SingleSimplex(unsigned char offset, float x, float y, float z, float w) -{ - float n0, n1, n2, n3, n4; - float t = (x + y + z + w) * F4; - int i = FastFloor(x + t); - int j = FastFloor(y + t); - int k = FastFloor(z + t); - int l = FastFloor(w + t); - t = (i + j + k + l) * G4; - float X0 = i - t; - float Y0 = j - t; - float Z0 = k - t; - float W0 = l - t; - float x0 = x - X0; - float y0 = y - Y0; - float z0 = z - Z0; - float w0 = w - W0; - - int c = (x0 > y0) ? 32 : 0; - c += (x0 > z0) ? 16 : 0; - c += (y0 > z0) ? 8 : 0; - c += (x0 > w0) ? 4 : 0; - c += (y0 > w0) ? 2 : 0; - c += (z0 > w0) ? 1 : 0; - c <<= 2; - - int i1 = SIMPLEX_4D[c] >= 3 ? 1 : 0; - int i2 = SIMPLEX_4D[c] >= 2 ? 1 : 0; - int i3 = SIMPLEX_4D[c++] >= 1 ? 1 : 0; - int j1 = SIMPLEX_4D[c] >= 3 ? 1 : 0; - int j2 = SIMPLEX_4D[c] >= 2 ? 1 : 0; - int j3 = SIMPLEX_4D[c++] >= 1 ? 1 : 0; - int k1 = SIMPLEX_4D[c] >= 3 ? 1 : 0; - int k2 = SIMPLEX_4D[c] >= 2 ? 1 : 0; - int k3 = SIMPLEX_4D[c++] >= 1 ? 1 : 0; - int l1 = SIMPLEX_4D[c] >= 3 ? 1 : 0; - int l2 = SIMPLEX_4D[c] >= 2 ? 1 : 0; - int l3 = SIMPLEX_4D[c] >= 1 ? 1 : 0; - - float x1 = x0 - i1 + G4; - float y1 = y0 - j1 + G4; - float z1 = z0 - k1 + G4; - float w1 = w0 - l1 + G4; - float x2 = x0 - i2 + 2.0f*G4; - float y2 = y0 - j2 + 2.0f*G4; - float z2 = z0 - k2 + 2.0f*G4; - float w2 = w0 - l2 + 2.0f*G4; - float x3 = x0 - i3 + 3.0f*G4; - float y3 = y0 - j3 + 3.0f*G4; - float z3 = z0 - k3 + 3.0f*G4; - float w3 = w0 - l3 + 3.0f*G4; - float x4 = x0 - 1.0f + 4.0f*G4; - float y4 = y0 - 1.0f + 4.0f*G4; - float z4 = z0 - 1.0f + 4.0f*G4; - float w4 = w0 - 1.0f + 4.0f*G4; - - t = 0.6f - x0*x0 - y0*y0 - z0*z0 - w0*w0; - if (t < 0.f) n0 = 0.0f; - else { - t *= t; - n0 = t * t * GradCoord4D(offset, i, j, k, l, x0, y0, z0, w0); - } - t = 0.6f - x1*x1 - y1*y1 - z1*z1 - w1*w1; - if (t < 0.f) n1 = 0.0f; - else { - t *= t; - n1 = t * t * GradCoord4D(offset, i + i1, j + j1, k + k1, l + l1, x1, y1, z1, w1); - } - t = 0.6f - x2*x2 - y2*y2 - z2*z2 - w2*w2; - if (t < 0.f) n2 = 0.0f; - else { - t *= t; - n2 = t * t * GradCoord4D(offset, i + i2, j + j2, k + k2, l + l2, x2, y2, z2, w2); - } - t = 0.6f - x3*x3 - y3*y3 - z3*z3 - w3*w3; - if (t < 0.f) n3 = 0.0f; - else { - t *= t; - n3 = t * t * GradCoord4D(offset, i + i3, j + j3, k + k3, l + l3, x3, y3, z3, w3); - } - t = 0.6f - x4*x4 - y4*y4 - z4*z4 - w4*w4; - if (t < 0.f) n4 = 0.0f; - else { - t *= t; - n4 = t * t * GradCoord4D(offset, i + 1, j + 1, k + 1, l + 1, x4, y4, z4, w4); - } - - return 27.0f * (n0 + n1 + n2 + n3 + n4); -} - -// Cellular Noise -float PolygonalMapGenNoise::GetCellular(float x, float y, float z) -{ - x *= m_frequency; - y *= m_frequency; - z *= m_frequency; - - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - case ECellularReturnType::NoiseLookup: - case ECellularReturnType::Distance: - return SingleCellular(x, y, z); - default: - return SingleCellular2Edge(x, y, z); - } -} - -float PolygonalMapGenNoise::SingleCellular(float x, float y, float z) -{ - int xr = FastRound(x); - int yr = FastRound(y); - int zr = FastRound(z); - - float distance = 999999.f; - int xc = 0; - int yc = 0; - int zc = 0; - - switch (m_cellularDistanceFunction) - { - case ECellularDistanceFunction::Euclidean: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - } - } - } - break; - case ECellularDistanceFunction::Manhattan: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ); - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - } - } - } - break; - case ECellularDistanceFunction::Natural: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = (FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ); - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - } - } - } - break; - default: - break; - } - - unsigned char lutPos; - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - return ValCoord3D(0, xc, yc, zc); - - case ECellularReturnType::NoiseLookup: - assert(m_cellularNoiseLookup); - - lutPos = Index3D_256(0, xc, yc, zc); - return m_cellularNoiseLookup->GetNoise(xc + CELL_3D_X[lutPos], yc + CELL_3D_Y[lutPos], zc + CELL_3D_Z[lutPos]); - - case ECellularReturnType::Distance: - return distance - 1.0f; - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleCellular2Edge(float x, float y, float z) -{ - int xr = FastRound(x); - int yr = FastRound(y); - int zr = FastRound(z); - - float distance = 999999.f; - float distance2 = 999999.f; - int xc = 0, yc = 0, zc = 0; - - switch (m_cellularDistanceFunction) - { - case ECellularDistanceFunction::Euclidean: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - } - break; - case ECellularDistanceFunction::Manhattan: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ); - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - } - break; - case ECellularDistanceFunction::Natural: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - for (int zi = zr - 1; zi <= zr + 1; zi++) - { - unsigned char lutPos = Index3D_256(0, xi, yi, zi); - - float vecX = xi - x + CELL_3D_X[lutPos]; - float vecY = yi - y + CELL_3D_Y[lutPos]; - float vecZ = zi - z + CELL_3D_Z[lutPos]; - - float newDistance = (FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ); - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - zc = zi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - } - break; - default: - break; - } - - switch (m_cellularReturnType) - { - case ECellularReturnType::Distance2: - return distance2 - 1.0f; - case ECellularReturnType::Distance2Add: - return distance2 + distance - 1.0f; - case ECellularReturnType::Distance2Sub: - return distance2 - distance - 1.0f; - case ECellularReturnType::Distance2Mul: - return distance2 * distance - 1.0f; - case ECellularReturnType::Distance2Div: - return distance / distance2 - 1.0f; - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::GetCellular(float x, float y) -{ - x *= m_frequency; - y *= m_frequency; - - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - case ECellularReturnType::NoiseLookup: - case ECellularReturnType::Distance: - return SingleCellular(x, y); - default: - return SingleCellular2Edge(x, y); - } -} - -float PolygonalMapGenNoise::SingleCellular(float x, float y) -{ - int xr = FastRound(x); - int yr = FastRound(y); - - float distance = 999999.f; - int xc = 0; - int yc = 0; - - switch (m_cellularDistanceFunction) - { - default: - case ECellularDistanceFunction::Euclidean: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = vecX * vecX + vecY * vecY; - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - } - } - } - break; - case ECellularDistanceFunction::Manhattan: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = (FastAbs(vecX) + FastAbs(vecY)); - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - } - } - } - break; - - case ECellularDistanceFunction::Natural: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = (FastAbs(vecX) + FastAbs(vecY)) + (vecX * vecX + vecY * vecY); - - if (newDistance < distance) - { - distance = newDistance; - xc = xi; - yc = yi; - } - } - } - break; - } - - unsigned char lutPos; - switch (m_cellularReturnType) - { - case ECellularReturnType::CellValue: - return ValCoord2D(0, xc, yc); - - case ECellularReturnType::NoiseLookup: - assert(m_cellularNoiseLookup); - - lutPos = Index2D_256(0, xc, yc); - return m_cellularNoiseLookup->GetNoise(xc + CELL_2D_X[lutPos], yc + CELL_2D_Y[lutPos]); - - case ECellularReturnType::Distance: - return distance - 1.0f; - default: - return 0.0f; - } -} - -float PolygonalMapGenNoise::SingleCellular2Edge(float x, float y) -{ - int xr = FastRound(x); - int yr = FastRound(y); - - float distance = 999999.f; - float distance2 = 999999.f; - int xc = 0, yc = 0; - - switch (m_cellularDistanceFunction) - { - default: - case ECellularDistanceFunction::Euclidean: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = vecX * vecX + vecY * vecY; - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - break; - case ECellularDistanceFunction::Manhattan: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = FastAbs(vecX) + FastAbs(vecY); - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - break; - case ECellularDistanceFunction::Natural: - for (int xi = xr - 1; xi <= xr + 1; xi++) - { - for (int yi = yr - 1; yi <= yr + 1; yi++) - { - unsigned char lutPos = Index2D_256(0, xi, yi); - - float vecX = xi - x + CELL_2D_X[lutPos]; - float vecY = yi - y + CELL_2D_Y[lutPos]; - - float newDistance = (FastAbs(vecX) + FastAbs(vecY)) + (vecX * vecX + vecY * vecY); - - if (newDistance < distance) - { - distance2 = distance; - - distance = newDistance; - xc = xi; - yc = yi; - } - else if (newDistance < distance2) - { - distance2 = newDistance; - } - } - } - break; - } - - switch (m_cellularReturnType) - { - case ECellularReturnType::Distance2: - return distance2 - 1.0f; - case ECellularReturnType::Distance2Add: - return distance2 + distance - 1.0f; - case ECellularReturnType::Distance2Sub: - return distance2 - distance - 1.0f; - case ECellularReturnType::Distance2Mul: - return distance2 * distance - 1.0f; - case ECellularReturnType::Distance2Div: - return distance / distance2 - 1.0f; - default: - return 0.0f; - } -} \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Private/PolygonalMapGenerator.cpp b/Source/PolygonalMapGenerator/Private/PolygonalMapGenerator.cpp index df093a2..f2a817f 100644 --- a/Source/PolygonalMapGenerator/Private/PolygonalMapGenerator.cpp +++ b/Source/PolygonalMapGenerator/Private/PolygonalMapGenerator.cpp @@ -1,9 +1,11 @@ // Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. -#include "PolygonalMapGeneratorPrivatePCH.h" +#include "PolygonalMapGenerator.h" #define LOCTEXT_NAMESPACE "FPolygonalMapGeneratorModule" +DEFINE_LOG_CATEGORY(LogMapGen); + void FPolygonalMapGeneratorModule::StartupModule() { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module diff --git a/Source/PolygonalMapGenerator/Private/PolygonalMapGeneratorPrivatePCH.h b/Source/PolygonalMapGenerator/Private/PolygonalMapGeneratorPrivatePCH.h deleted file mode 100644 index 03e7fa3..0000000 --- a/Source/PolygonalMapGenerator/Private/PolygonalMapGeneratorPrivatePCH.h +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. - -#include "PolygonalMapGenerator.h" - -// You should place include statements to your module's private header files here. You only need to -// add includes for headers that are used in most of your module's source files though. - -#include "CoreMinimal.h" -#include "Containers/Queue.h" \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/IO/MapTextureRenderer.h b/Source/PolygonalMapGenerator/Public/IO/MapTextureRenderer.h deleted file mode 100644 index 7145550..0000000 --- a/Source/PolygonalMapGenerator/Public/IO/MapTextureRenderer.h +++ /dev/null @@ -1,32 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Maps/Elevations/PolygonalMapHeightmap.h" -#include "Engine/TextureRenderTarget2D.h" -#include "Kismet/BlueprintFunctionLibrary.h" -#include "MapTextureRenderer.generated.h" - -/** - * - */ -UCLASS() -class POLYGONALMAPGENERATOR_API UMapTextureRenderer : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - - //UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - //static bool SaveTextureFromHeightmap(UPolygonalMapHeightmap* MapHeightmap, FString Filename); - - /*UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - static void CreateTextureFromHeightmap(UPolygonalMapHeightmap* MapHeightmap, UTextureRenderTarget2D* IslandRenderTarget, UMaterialInstanceDynamic* IslandMaterialInstanceDynamic); - - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - static void CreateTexture(UTexture2D* TargetTexture, TArray Colors); - - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - static bool SaveTextureToDisk(UTexture2D* Texture, FString Filename); - - static void UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData);*/ -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/Biomes/BiomeManager.h b/Source/PolygonalMapGenerator/Public/Maps/Biomes/BiomeManager.h deleted file mode 100644 index f3320be..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Biomes/BiomeManager.h +++ /dev/null @@ -1,77 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Components/ActorComponent.h" -#include "PolygonMap.h" -#include "GameplayTagContainer.h" -#include "BiomeManager.generated.h" - -USTRUCT(BlueprintType) -struct FBiome -{ - GENERATED_BODY() -public: - // The GameplayTag associated with this biome. - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Map Biome", meta = (Categories = "MapData.Biome")) - FGameplayTag BiomeTag; - - // The minimum elevation for this biome - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Elevation", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MinElevation; - // The maximum elevation for this biome - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Elevation", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MaxElevation; - // The minimum amount of moisture for this biome - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Moisture", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MinMoisture; - // The maxmimum amount of moisture for this biome - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Moisture", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MaxMoisture; - - // Any required tags that need to be on the FMapData struct for this biome to be selected - UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Map Biome", meta = (Categories = "MapData.MetaData")) - FGameplayTagContainer RequiredTags; - - FBiome() - { - MinElevation = 0.0f; - MaxElevation = 1.0f; - - MinMoisture = 0.0f; - MaxMoisture = 1.0f; - } -}; - -UCLASS(Blueprintable, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) -class POLYGONALMAPGENERATOR_API UBiomeManager : public UActorComponent -{ - GENERATED_BODY() -protected: - // Our implementation for determining the biome of a point - virtual FGameplayTag DetermineBiome_Implementation(const FMapData& MapData); - -public: - // Sets default values for this component's properties - UBiomeManager(); - - static const FName BIOME_OceanTag; - static const FName BIOME_CoastTag; - - // A list of all valid biomes in this BiomeManager. - // Users should add any biomes they'd like to iterate over and choose from to this list. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Biome") - TArray Biomes; - - // Whether this biome manager should allow biomes with snow. - // Games taking place in tropical climates may not need to have snow. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Biome") - bool bAllowSnow = true; - - // This determines the biome that the MapData should be in. - // It can be overridden by the user if they would like to make their own implementation. - // By default, it will iterate over the Biomes array and return the first biome that fulfills all requirements. - // If none can be found, a warning is printed to the log and an empty tag is returned. - UFUNCTION(BlueprintNativeEvent, Category="Biome") - FGameplayTag DetermineBiome(const FMapData& MapData); -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/Biomes/WhittakerBiomeManager.h b/Source/PolygonalMapGenerator/Public/Maps/Biomes/WhittakerBiomeManager.h deleted file mode 100644 index a9fcdb4..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Biomes/WhittakerBiomeManager.h +++ /dev/null @@ -1,101 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2017 Jay M Stevens -#pragma once - -#include "Maps/Biomes/BiomeManager.h" -#include "Maps/PolygonMap.h" -#include "WhittakerBiomeManager.generated.h" - -/** -* An enum representing the different Whittaker biomes. -* There are 18 biomes total. -*/ -UENUM(BlueprintType) -enum class EWhittakerBiome : uint8 -{ - Ocean UMETA(DisplayName = "Ocean"), - Ice UMETA(DisplayName = "Ice"), - Marsh UMETA(DisplayName = "Marsh"), - Lake UMETA(DisplayName = "Lake"), - Coast UMETA(DisplayName = "Coast"), - Snow UMETA(DisplayName = "Snow"), - Tundra UMETA(DisplayName = "Tundra"), - Bare UMETA(DisplayName = "Bare"), - Scorched UMETA(DisplayName = "Scorched"), - Taiga UMETA(DisplayName = "Taiga"), - Shrubland UMETA(DisplayName = "Shrubland"), - TemperateDesert UMETA(DisplayName = "Temperate Desert"), - TemperateRainForest UMETA(DisplayName = "Temperate Rain Forest"), - TemperateDeciduousForest UMETA(DisplayName = "Temperate Deciduous Forest"), - Grassland UMETA(DisplayName = "Grassland"), - TropicalRainForest UMETA(DisplayName = "Tropical Rain Forest"), - TropicalSeasonalForest UMETA(DisplayName = "Tropical Seasonal Forest"), - SubtropicalDesert UMETA(DisplayName = "Subtropical Desert") -}; - -/** - * An implementation of `BiomeManager` which uses the Whittaker diagram for its biomes. - * Total list of biomes: - * - OCEAN: Has tag "Ocean" - * - ICE: Has tag "Water", Elevation > 0.75, allow snow - * - MARSH: Has tag "Water", Elevation < 0.25 - * - LAKE: Has tag "Water"; does NOT have tags "Ocean", "Ice", or "Marsh" - * - COAST: Has tag "Coast" - * - SNOW: Elevation > 0.75 and Moisture > 0.5, allow snow - * - TUNDRA: Elevation > 0.75 and 0.5 > Moisture > 0.33, allow snow - * - BARE: Elevation > 0.75 and 0.33 > Moisture > 0.16 - * - SCORCHED: Elevation > 0.75 and Moisture < 0.16 - * - TAIGA: 0.75 > Elevation > 0.5 and Moisture > 0.66, allow snow - * - SHRUBLAND: 0.75 > Elevation > 0.5 and 0.66 > Moisture > 0.33 - * - TEMPERATE DESERT: 0.75 > Elevation > 0.5 and Moisture < 0.33 OR 0.5 > Elevation > 0.25 and Moisture < 0.16 - * - TEMPERATE RAIN FOREST: 0.5 > Elevation > 0.25 and Moisture > 0.83 - * - TEMPERATE DECIDUOUS FOREST: 0.5 > Elevation > 0.25 and 0.83 > Moisture > 0.5 - * - GRASSLAND: 0.5 > Elevation > 0.25 and 0.5 > Moisture > 0.16 OR Elevation < 0.25 and 0.33 > Moisture > 0.16 - * - TROPICAL RAIN FOREST: Elevation < 0.25 and Moisture > 0.66 - * - TROPICAL SEASONAL FOREST: Elevation < 0.25 and 0.66 > Moisture > 0.33 - * - SUBTROPICAL DESERT: Elevation < 0.25 and Moisture < 0.16 - */ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UWhittakerBiomeManager : public UBiomeManager -{ - GENERATED_BODY() -protected: - static const FName BIOME_IceTag; - static const FName BIOME_MarshTag; - static const FName BIOME_LakeTag; - static const FName BIOME_SnowTag; - static const FName BIOME_TundraTag; - static const FName BIOME_BareTag; - static const FName BIOME_ScorchedTag; - static const FName BIOME_TaigaTag; - static const FName BIOME_ShrublandTag; - static const FName BIOME_TemperateDesertTag; - static const FName BIOME_TemperateRainForestTag; - static const FName BIOME_TemperateDeciduousForestTag; - static const FName BIOME_GrasslandTag; - static const FName BIOME_TropicalRainForestTag; - static const FName BIOME_TropicalSeasonalForestTag; - static const FName BIOME_SubtropicalDesertTag; - - //virtual FGameplayTag DetermineBiome_Implementation(const FMapData& MapData) override; -public: - UWhittakerBiomeManager(); - - // Converts a biome's FName into an enum representation. - // Will return EWhittakerBiome::Ocean if there are no matches in this biome. - // The enum returned can be used in a switch statement or converted into a uint8 (for example, for use as a material ID). - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Biome") - EWhittakerBiome ConvertToWhittakerBiomeEnum(const FGameplayTag& BiomeName); - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Biome") - EWhittakerBiome LookupWhittakerBiome(const FMapData& MapData); - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Biome") - EWhittakerBiome WhittakerBiomeFromWorldPoint(UPolygonMap* MapGraph, const FVector& WorldPoint); - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Biome") - EWhittakerBiome WhittakerBiomeFromGraphPoint(UPolygonMap* MapGraph, const FVector2D& GraphPoint); - -protected: - TMap BiomeEnumMap; - TMap LocationLookup; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/Elevations/ElevationDistributor.h b/Source/PolygonalMapGenerator/Public/Maps/Elevations/ElevationDistributor.h deleted file mode 100644 index e121b8b..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Elevations/ElevationDistributor.h +++ /dev/null @@ -1,53 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Components/ActorComponent.h" -#include "PolygonMap.h" -#include "ElevationDistributor.generated.h" - -/** -* The ElevationDistributor class is a class which takes a collection -* of graph nodes on the XY plane and gives the nodes Z values. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UElevationDistributor : public UActorComponent -{ - GENERATED_BODY() - -public: - // Change the polygon graph for this ElevationDistributor. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void SetGraph(UPolygonMap* graph); - - // Determine the elevations and water at Voronoi corners. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void AssignCornerElevations(UIslandShape* islandShape, bool bneedsMoreRandomness, FRandomStream& randomGenerator); - - // Calculate downslope pointers. At every point, we point to the - // point downstream from it, or to itself. This is used for - // generating rivers and watersheds. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void CalculateDownslopes(); - - // Rescale elevations so that the highest is 1.0, and they're - // distributed well. We want lower elevations to be more common - // than higher elevations, in proportions approximately matching - // concentric rings. That is, the lowest elevation is the - // largest ring around the island, and therefore should more - // land area than the highest elevation, which is the very - // center of a perfectly circular island. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void RedistributeElevations(TArray landCorners); - - // Flatten areas which are considered ocean corners - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void FlattenWaterElevations(); - - // Assign polygon elevations as the average of their corners - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void AssignPolygonElevations(); - -protected: - UPolygonMap* MapGraph; -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/Maps/Elevations/PolygonalMapHeightmap.h b/Source/PolygonalMapGenerator/Public/Maps/Elevations/PolygonalMapHeightmap.h deleted file mode 100644 index 5b53553..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Elevations/PolygonalMapHeightmap.h +++ /dev/null @@ -1,74 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Object.h" -#include "PolygonMap.h" -#include "PolygonalMapHeightmap.generated.h" - -class UMoistureDistributor; - -/** - * A class which creates a "heightmap" of FMapData objects from a UPolygonMap object. - * This heightmap can be iterated over and its values used to create a voxel-based 3D representation in - * the game world, as a 2D grayscale image, or whatever else you can think of. - * `CreateHeightmap()` should be called after the UPolygonMap is finished being modified, as it does not - * update "live" with the UPolygonMap. - * Once the heightmap has been created, you can access its data safely using `GetMapPoint()`, or you can - * access the raw FMapData array with `GetMapData()`. - */ -UCLASS(BlueprintType) -class POLYGONALMAPGENERATOR_API UPolygonalMapHeightmap : public UObject -{ - GENERATED_BODY() - -private: - // The raw array of FMapData structs which represent each "pixel" in the heightmap. - // Once populated, this is a 2D array of `HeightmapSize` by `HeightmapSize`, represented in a 1D array. - UPROPERTY() - TArray HeightmapData; - UPROPERTY() - UMoistureDistributor* MoistureDistributor; - - UPROPERTY() - float CreateHeightmapTimer; - - FIslandGeneratorDelegate OnGenerationComplete; - - UFUNCTION() - void CheckMapPointsDone(); -public: - // The number of "pixels" in the heightmap. - // Larger values create a higher-resolution heightmap, but also mean increased processing time. - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Heightmap") - int32 HeightmapSize; - // How many of the nearest points are used when creating a heightmap from a UPolygonMap. - // As each pixel is iterated, this sets how many of the nearest UPolygonMap points we should interpolate between. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Heightmap") - int32 NumberOfPointsToAverage = 4; - - // Initializes the UPolyognalMapHeightmap object and populates the HeightmapData array. - // This should be called first, before attempting to load any data from the heightmap. - // This will create an array of FMapData objects with dimensions specified by the Size passed to this function. - // A larger value for Size will create a higher-resolution map, but will also mean increased processing time. - // Each FMapData object will be created by being interpolated from the nearest points in the UPolygonMap supplied to this function. - // The number of nearest points to consider is governed by the value of the NumberOfPointsToAverage in the UPolygonalMapHeightmap class. - // Each "pixel" in the heightmap will be supplied with its own biome, which is determined by the UBiomeManager passed to this function. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Heightmap") - void CreateHeightmap(UPolygonMap* PolygonMap, UBiomeManager* BiomeManager, UMoistureDistributor* MoistureDist, const int32 Size, const FIslandGeneratorDelegate onComplete); - - // Returns a COPY of this object's raw heightmap. - // This can be iterated over easily, but keep in mind that any changes you make won't be made to the actual heightmap object (i.e., this). - // Also keep in mind that the array is actually a 1D representation of a 2D array of HeightmapSize x HeightmapSize. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Heightmap") - TArray GetMapData(); - // Returns the FMapData that corresponds with the given (X, Y) position on the heightmap. - // If the position is out of bounds of the heightmap or the heightmap is not initialized, it will return a blank FMapData object. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Heightmap") - FMapData GetMapPoint(int32 x, int32 y); - - // Sets the map point at the given (X, Y) position on the heightmap. - // If the point is out of bounds, a warning is generated and nothing happens. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Heightmap") - void SetMapPoint(int32 X, int32 Y, FMapData MapData); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/Maps/Elevations/SimplexNoiseElevationDistributor.h b/Source/PolygonalMapGenerator/Public/Maps/Elevations/SimplexNoiseElevationDistributor.h deleted file mode 100644 index d11edda..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Elevations/SimplexNoiseElevationDistributor.h +++ /dev/null @@ -1,47 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "Maps/Elevations/ElevationDistributor.h" -#include "Noise/PolygonalMapGenNoise.h" -#include "SimplexNoiseElevationDistributor.generated.h" - -/** - * - */ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API USimplexNoiseElevationDistributor : public UElevationDistributor -{ - GENERATED_BODY() -public: - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Noise") - FNoiseSettings NoiseSettings; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Noise") - float NoiseScale = 0.0033f; - - // The elevation below which a point is considered to be water. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map") - float OceanThreshold = 0.05f; - - // How many times the gradient is applied. - // More iterations smooths out the edges of the map and accentuates the center. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Map") - int32 GradientIterations = 1; - - USimplexNoiseElevationDistributor(); - - // Determine the elevations and water at Voronoi corners. - virtual void AssignCornerElevations(UIslandShape* islandShape, bool bneedsMoreRandomness, FRandomStream& randomGenerator) override; - - //UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - //virtual void AssignOceanCoastAndLand(float lakeThreshold) override; - - virtual void RedistributeElevations(TArray landCorners) override; - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map") - virtual float GetGradient(float XCoord, float YCoord, int32 IslandSize) const; - - // Flatten areas which are considered ocean corners - //UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - //virtual void FlattenWaterElevations() override; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/IslandMapGenerator.h b/Source/PolygonalMapGenerator/Public/Maps/IslandMapGenerator.h deleted file mode 100644 index 1787a18..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/IslandMapGenerator.h +++ /dev/null @@ -1,342 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "GameFramework/Actor.h" -#include "PolygonMap.h" -#include "Maps/Elevations/ElevationDistributor.h" -#include "Maps/PointGenerators/PointGenerator.h" -#include "Maps/Biomes/BiomeManager.h" -#include "Maps/Moisture/MoistureDistributor.h" -#include "PolygonalMapHeightmap.h" -#include "Maps/IslandShapes/RadialIsland.h" -#include "Components/StaticMeshComponent.h" -#include "Materials/MaterialInstanceDynamic.h" -#include "IslandMapGenerator.generated.h" - -/* -* The IslandData struct manages all the attributes used to generate an island. -*/ -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FIslandData -{ - GENERATED_BODY() - - // The type of island to make. - // Different generators will make differently-shaped islands. - // By default, all points will be considered water. - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - TSubclassOf IslandType; - - // What IslandPointGenerator to use. - // By default, all points will be at 0,0. - // Generators can do things like make random points, for a "natural"-looking map, make square points for a grid-shaped map, etc. - UPROPERTY(Category = "Points", BlueprintReadWrite, EditAnywhere) - TSubclassOf IslandPointSelector; - - // What BiomeManager to use. - // By default, only MapData objects with the ocean or coast properties will get biomes. - // Users should create their own class to determine which biomes they want in their game. - UPROPERTY(Category = "Biomes", BlueprintReadWrite, EditAnywhere) - TSubclassOf BiomeManager; - - // What ElevationDistributor to use. - // By default, this will create an island with the elevation mostly focused in the middle. - // This will create landmasses with a giant mountain in the center. - UPROPERTY(Category = "Biomes", BlueprintReadWrite, EditAnywhere) - TSubclassOf ElevationDistributor; - - // What ElevationDistributor to use. - UPROPERTY(Category = "Biomes", BlueprintReadWrite, EditAnywhere) - TSubclassOf MoistureDistributor; - // This is the table of all possible river names. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Biomes") - UDataTable* RiverNameTable; - - // The random seed to use for the island. - // The same seed will produce the same island. - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - int32 Seed; - - // The size of the actual island, in meters. - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - int32 Size; - - // The number of points to generate. - // Higher values creates a higher-quality island, but can dramatically slow down generation time - UPROPERTY(Category = "Points", BlueprintReadWrite, EditAnywhere) - int32 NumberOfPoints; - - // These are the settings for converting the points we generate into Unreal world space. - UPROPERTY(Category = "Map", BlueprintReadWrite, EditAnywhere) - FWorldSpaceMapData PolygonMapSettings; - - //Constructor - FIslandData() - { - Size = 1024; - NumberOfPoints = 1500; - - IslandType = URadialIsland::StaticClass(); - IslandPointSelector = UPointGenerator::StaticClass(); - BiomeManager = UBiomeManager::StaticClass(); - ElevationDistributor = UElevationDistributor::StaticClass(); - MoistureDistributor = UMoistureDistributor::StaticClass(); - } -}; - -/** -* The IslandMapGenerator creates a graph and then assigns -* elevation and moisture based on various rules set in -* IslandData, using subclasses. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API AIslandMapGenerator : public AActor -{ - GENERATED_BODY() -public: - - AIslandMapGenerator(); - ~AIslandMapGenerator() {}; - - virtual void Tick(float deltaSeconds) override; - // Sets the IslandData that will be used for Island Generation. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void SetData(FIslandData islandData); - - // Resets the map back to its default state. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void ResetMap(); - - // Adds all the necessary steps for Island Generation, then - // generates an island. - // It will call the passed delegate when the generation is done. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void CreateMap(const FIslandGeneratorDelegate onComplete); - - // Returns a MapCenter at the given index. - // If the index is invalid, an empty MapCenter will be returned. - // This empty MapCenter will have an index of -1. - // Make sure to use the function UpdateCenter() to update the graph - // after the MapCenter has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCenter GetCenter(const int32 index) const; - // Returns a MapCorner at the given index. - // If the index is invalid, an empty MapCorner will be returned. - // This empty MapCorner will have an index of -1. - // Make sure to use the function UpdateCorner() to update the graph - // after the MapCorner has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCorner GetCorner(const int32 index) const; - // Returns a MapEdge at the given index. - // If the index is invalid, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge GetEdge(const int32 index) const; - - // Returns the MapEdge defined by two adjacent MapCenters. - // If the edge doesn't exist, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge FindEdgeFromCenters(const FMapCenter& v0, const FMapCenter& v1) const; - // Returns the MapEdge defined by two adjacent MapCorners. - // If the edge doesn't exist, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge FindEdgeFromCorners(const FMapCorner& v0, const FMapCorner& v1) const; - - // Returns the number of MapCenters in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetCenterNum() const; - // Returns the number of MapCorners in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetCornerNum() const; - // Returns the number of MapEdges in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetEdgeNum() const; - - // Returns our Graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - UPolygonMap* GetGraph() const; - // Returns the heightmap associated with this island. - // This heightmap will be blank until CreateHeightmap() completes. - // Be sure to call CreateHeightmap() and wait for delegate completion before calling this function. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - UPolygonalMapHeightmap* GetHeightmap() const; - - // Update a MapCenter in the graph after it has been modified. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateCenter(const FMapCenter& center); - - // Update a MapCorner in the graph after it has been modified. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateCorner(const FMapCorner& corner); - - // Update a MapEdge in the graph after it has been modified. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateEdge(const FMapEdge& edge); - - // This adds a new generation step to the list of island generation steps. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void AddGenerationStep(const FIslandGeneratorDelegate step); - - // This clears all generation steps from the island generator. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void ClearAllGenerationSteps(); - - // This creates a 2D heightmap representation of the current island. - // It will take a few seconds to complete, particularly for larger values of HeightmapSize. - // This work is multi-threaded, so the game thread will not lock up while this process completes. - // When the function is done, it will call the OnComplete delegate. - // The heightmap can be accessed through the GetHeightmap() function. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void CreateHeightmap(const int32 HeightmapSize, const FIslandGeneratorDelegate OnComplete); - - // This draws a debug voronoi representation of the island, using the values specified in - // the IslandData's PolygonMapSettings struct. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - void DrawVoronoiGraph(); - - // This draws a debug delaunay representation of the island, using the values specified in - // the IslandData's PolygonMapSettings struct. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - void DrawDelaunayGraph(); - - // Draws this map's heightmap in Unreal world space, using the values specified in the - // IslandData's PolygonMapSettings struct. - // Be sure to call CreateHeightmap() and wait for the delegate to complete before calling - // this function, otherwise there may not be any data in the heightmap array. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - void DrawHeightmap(float PixelSize = 100.0f); - - // Different settings that make up our island. - // Changing these settings will produce different-looking islands. - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - FIslandData IslandData; - -protected: - // Adds a list of steps that we need to generate our island. - // Users using Blueprint should override this and NOT call the - // parent function. They have to add steps in the Event Graph - // due to the way Blueprint works with delegates ("Events"). - UFUNCTION(BlueprintNativeEvent, Category = "World Generation|Island Generation") - void AddMapSteps(); - virtual void AddMapSteps_Implementation(); - - // Generates a new map from our IslandData. - // This iterates over each step in the IslandGeneratorSteps queue - // and executes the event. Players using Blueprint can add their - // own steps to the queue or create a new queue altogether in the - // Blueprint Event Graph. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation") - void ExecuteNextMapStep(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void ResetMapEvent(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void InitializeMapEvent(); - // Initializes the IslandShape and PointSelector classes - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void InitializeMapClasses(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void BuildGraphEvent(); - // Creates the initial points that our map will work on - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void BuildGraph(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void AssignElevationEvent(); - // Determines graph elevation - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void AssignElevation(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void AssignMoistureEvent(); - // Determines downslopes and moisture - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void AssignMoisture(); - - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void DoPointPostProcess(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void NormalizePointsEvent(); - // Normalizes all points in their acceptable range (elevation/moisture between 0 and 1, for example). - // Should be called when you are done playing with height/moisture. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void NormalizePoints(); - - UFUNCTION(BlueprintImplementableEvent, Category = "World Generation|Island Generation|Map") - void DetermineBiomesEvent(); - // Determines the biomes for all corners and centers. - // Should be called after the bulk of map generation is complete. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void DetermineBiomes(); - - // Called when the heightmap is done generating. - // Stops keeping track of the time the heightmap has been running and calls our OnHeightmapComplete delegate. - UFUNCTION() - void OnHeightmapFinished(); -private: - // The map's heightmap, generated after map generation is finished. - UPROPERTY() - UPolygonalMapHeightmap* MapHeightmap; - - // The random generator to use when generating the map. - UPROPERTY() - FRandomStream RandomGenerator; - // What time the map started being generated. - UPROPERTY() - float MapStartGenerationTime; - // What time this current step started. - UPROPERTY() - float CurrentGenerationTime; - - // Is the current map generation step done? - UPROPERTY() - bool bCurrentStepIsDone; - // Have we generated a heightmap yet? - UPROPERTY() - bool bHasGeneratedHeightmap; - - // A list of all the heightmap steps we need to take. - TQueue IslandGeneratorSteps; - - // A delegate called when initial map generation is done. - FIslandGeneratorDelegate OnGenerationComplete; - // A delegate called when heightmap generation is done. - FIslandGeneratorDelegate OnHeightmapComplete; -public: - // The graph containing all our map's polygons. - // This is the "main" representation of our map, and the source of all our raw data. - UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Island Generation") - UPolygonMap* MapGraph; - // The instance of our IslandShape object. - // IslandShapes determine the shape of the island. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Island Generation") - UIslandShape* IslandShape; - // The instance of our PointGenerator object. - // The PointGenerator determines the manner in which our points are selected. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Island Generation") - UPointGenerator* PointSelector; - // The instance of our ElevationDistributor object. - // This controls how elevation is distributed. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Island Generation") - UElevationDistributor* ElevationDistributor; - // The instance of our MoistureDistributor object. - // This controls how moisture is distributed. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Island Generation") - UMoistureDistributor* MoistureDistributor; - // The instance of our BiomeManager object. - // This controls what biomes get assigned to points. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Island Generation") - UBiomeManager* BiomeManager; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/IslandShape.h b/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/IslandShape.h deleted file mode 100644 index 97c44d1..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/IslandShape.h +++ /dev/null @@ -1,51 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Components/ActorComponent.h" -#include "IslandShape.generated.h" - -// This fixes issues with UPROPERTY in Visual Studio's Intellisense with VAssistX -using namespace UP; - -/** -* The IslandShape class is a class which takes a 2D point and -* returns a value indicating whether the point is land or water. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UIslandShape : public UActorComponent -{ - GENERATED_BODY() -public: - UIslandShape() {}; - ~UIslandShape() {}; - - // Sets the seed and the size of the island. - // Will be called before any IsPointLand calls. - UFUNCTION(BlueprintNativeEvent, Category = "Island Generation|Graph|Points") - void SetSeed(int32 seed, int32 size); - - // Whether the given point is land or not. - // By default, all points will be considered water. - UFUNCTION(BlueprintNativeEvent, Category = "Island Generation|Graph|Points") - bool IsPointLand(FVector2D point); - - // 1.0 means no small islands; 2.0 leads to a lot - UPROPERTY(Category = "Island Size", BlueprintReadWrite, EditAnywhere) - float IslandFactor = 1.07f; - - // The size of our island. - UPROPERTY(Category = "Island Size", BlueprintReadWrite, EditAnywhere) - int32 Size; - -protected: - // C++ version of SetSeed - virtual void SetSeed_Implementation(int32 seed, int32 size); - // C++ version of IsPointLand - virtual bool IsPointLand_Implementation(FVector2D point); - - // The RandomStream that has been initialized with our seed. - // Will be used if any RNG is needed. - UPROPERTY(Category = "Island Randomness", BlueprintReadWrite, EditAnywhere) - FRandomStream StreamRNG; -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/RadialIsland.h b/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/RadialIsland.h deleted file mode 100644 index 8d94516..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/RadialIsland.h +++ /dev/null @@ -1,54 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "IslandShape.h" -#include "RadialIsland.generated.h" -/** -* The Radial Island is a circular island using overlapping sine waves. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API URadialIsland : public UIslandShape -{ - GENERATED_BODY() - -public: - // The minimum number of sine wave "bumps" along the island. - UPROPERTY(Category = "Bumps", BlueprintReadWrite, EditAnywhere) - int32 BumpsMin = 1; - // The maximum number of sine wave "bumps" along the island. - UPROPERTY(Category = "Bumps", BlueprintReadWrite, EditAnywhere) - int32 BumpsMax = 6; - - // The minimum start angle for the sin function, in radians. - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float StartAngleMin = 0.0f; - // The maximum start angle for the sin function, in radians. - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float StartAngleMax = 2.0f; - - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float AngleOffsetMin = 0.0f; - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float AngleOffsetMax = 2.0f; - - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float MinAngleMin = 0.2f; - UPROPERTY(Category = "Angle", BlueprintReadWrite, EditAnywhere) - float MinAngleMax = 0.7f; - -protected: - virtual void SetSeed_Implementation(int32 seed, int32 size) override; - virtual bool IsPointLand_Implementation(FVector2D point) override; - - // The number of sine waves which form bumps along the island. - UPROPERTY(Category = "Bumps", BlueprintReadWrite, VisibleAnywhere) - int32 Bumps; - // The start angle for the sin function, in radians. - UPROPERTY(Category = "Angle", BlueprintReadWrite, VisibleAnywhere) - float StartAngle; - UPROPERTY(Category = "Angle", BlueprintReadWrite, VisibleAnywhere) - float AngleOffset; - UPROPERTY(Category = "Angle", BlueprintReadWrite, VisibleAnywhere) - float MinAngle; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/SquareIsland.h b/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/SquareIsland.h deleted file mode 100644 index 20e394f..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/IslandShapes/SquareIsland.h +++ /dev/null @@ -1,20 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "IslandShape.h" -#include "SquareIsland.generated.h" - -/** -* The Square Island is an island where all points are land. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API USquareIsland : public UIslandShape -{ - GENERATED_BODY() - -protected: - // Whether the given point is land or not. - // By default, all points will be considered land. - virtual bool IsPointLand_Implementation(FVector2D point) override; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/MapDataHelper.h b/Source/PolygonalMapGenerator/Public/Maps/MapDataHelper.h deleted file mode 100644 index 6bd15a1..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/MapDataHelper.h +++ /dev/null @@ -1,78 +0,0 @@ -// Work Copyright (c) 2017 Jay M Stevens - -#pragma once - -#include "Kismet/BlueprintFunctionLibrary.h" -#include "PolygonMap.h" -#include "MapDataHelper.generated.h" - -/** - * A helper class for FMapData objects. - * Mostly used to control tags and such. - */ -UCLASS(BlueprintType) -class POLYGONALMAPGENERATOR_API UMapDataHelper : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - // Returns whether a MapData object has a particular tag. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool HasTag(const FMapData& MapData, const FGameplayTag& Tag); - // Returns true if the supplied MapData object is tagged with "Border". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsBorder(const FMapData& MapData); - // Returns true if the supplied MapData object is tagged with "Freshwater". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsFreshwater(const FMapData& MapData); - // Returns true if the supplied MapData object is tagged with "Water". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsWater(const FMapData& MapData); - // Returns true if the supplied MapData object is tagged with "Saltwater". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsOcean(const FMapData& MapData); - // Returns true if the supplied MapData object is tagged with "Coast". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsCoast(const FMapData& MapData); - // Returns true if the supplied MapData object is tagged with "River". - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Map Data|Tags") - static bool IsRiver(const FMapData& MapData); - - // Gives a MapData object a tag, provided it doesn't have it already. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetMapTag(FMapData& MapData, const FGameplayTag& Tag); - // Gives a MapData object the tag "Border". - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetBorder(FMapData& MapData); - // Gives a MapData object the tag "Water". - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetFreshwater(FMapData& MapData); - // Gives a MapData object the tag "Ocean". - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetOcean(FMapData& MapData); - // Gives a MapData object the tag "Coast". - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetCoast(FMapData& MapData); - // Gives a MapData object the tag "River". - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData SetRiver(FMapData& MapData); - - // Removes a tag from a MapData object, if it has one. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveMapTag(FMapData& MapData, const FGameplayTag& Tag); - // Removes the tag "Border" from a MapData object. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveBorder(FMapData& MapData); - // Removes the tag "Freshwater" from a MapData object. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveFreshwater(FMapData& MapData); - // Removes the tag "Saltwater" from a MapData object. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveOcean(FMapData& MapData); - // Removes the tag "Coast" from a MapData object. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveCoast(FMapData& MapData); - // Removes the tag "River" from a MapData object. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map Data|Tags") - static FMapData RemoveRiver(FMapData& MapData); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/Maps/MapDebugVisualizer.h b/Source/PolygonalMapGenerator/Public/Maps/MapDebugVisualizer.h deleted file mode 100644 index 2cf9554..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/MapDebugVisualizer.h +++ /dev/null @@ -1,55 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "Kismet/BlueprintFunctionLibrary.h" -#include "PolygonMap.h" -#include "Moisture/River.h" -#include "MapDebugVisualizer.generated.h" - -/** - * A helper class for visualizing our map. - * Intended to be used for debugging purposes. - */ -UCLASS(BlueprintType) -class POLYGONALMAPGENERATOR_API UMapDebugVisualizer : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() -public: - // Draws a debug grid showing the position and height of each FMapData "pixel" in this heightmap. - // Keep in mind that larger values of HeightmapSize will have a SEVERE performance impact. - // Try to only use this with a limited number of pixels in the heightmap. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawDebugPixelGrid(AActor* Actor, const FWorldSpaceMapData& MapData, const TArray& HeightmapData, int32 HeightmapSize, float PixelSize); - - // Same as DrawDebugPixelGrid(), but only draws the parts of the debug grid which contain a river. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawDebugPixelRivers(AActor* Actor, const FWorldSpaceMapData& MapData, const TArray& HeightmapData, int32 HeightmapSize, float PixelSize); - - // Draws a 3D version of the underlying Delaunay graph in world space. - // This graph is a collection of all the map's centers and the - // Delaunay edges which connect them. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawDebugVoronoiGrid(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* PolygonMap); - - // Draws a 3D version of the underlying Voronoi graph in world space. - // This graph is a collection of all the map's corners and the - // Voronoi edges which connect them. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawDebugDelaunayGrid(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* PolygonMap); - - // Draws a triangle using the 3 given points. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawTriangle(AActor* Actor, FVector PointA, FVector PointB, FVector PointC); - - // Draws all the rivers in our map, as smooth lines. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawRivers(AActor* Actor, const FWorldSpaceMapData& MapData, UPolygonMap* MapGraph, const TArray& Rivers); - // Draws a smooth curve in world space. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Debug") - static void DrawBeizerCurve(AActor* Actor, const FWorldSpaceMapData& WorldData, FVector2D v0, FVector2D control0, FVector2D v1, FVector2D control1, FColor color, int32 MapSize); - -private: - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Debug") - static FVector2D CalculateBezierPoint(float t, FVector2D p0, FVector2D p1, FVector2D p2, FVector2D p3); -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/Moisture/MoistureDistributor.h b/Source/PolygonalMapGenerator/Public/Maps/Moisture/MoistureDistributor.h deleted file mode 100644 index de1dc74..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Moisture/MoistureDistributor.h +++ /dev/null @@ -1,99 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "Components/ActorComponent.h" -#include "PolygonMap.h" -#include "Engine/DataTable.h" -#include "River.h" -#include "MoistureDistributor.generated.h" - -/** - * The MoistureDistributor class distributes moisture across a map. - * It is also in charge of calculating stream flow direction, rivers, and watersheds. - */ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UMoistureDistributor : public UActorComponent -{ - GENERATED_BODY() -public: - // This adds a "base" level of moisture to every point in the map. - // If you want to simulate a wetter climate, this is what you would set. - // If you want to simulate a drier climate, you would set this to a negative number. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Biome", meta = (ClampMin = "-1.0", ClampMax = "1.0")) - float ExtraMoisture = 0.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Lakes", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float LakeThreshold = 0.9f; - // The maximum number of rivers in this map. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers") - int32 RiverCount = 50; - // The minimum height a river will begin at. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MinRiverStartElevation = 0.1f; - // The maximum height a river will begin at. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float MaxRiverStartElevation = 0.9f; - // The bias a river has towards running downstream. - // The higher the number, the more likely the river will go downstream. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float RiverDownstreamBias = 0.5f; - // The bias a river has for wandering into somewhere with standing water (like a lake). - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float StandingWaterBias = 0.75f; - // How much more likely a river is to join another river if there is one. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float RiverJoinBias = 0.825f; - // The chance that rivers bordering each other will combine to create a lake. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers", meta = (ClampMin = "0.0", ClampMax = "1.0")) - float RiverLakeConversionFactor = 0.85f; - // The minimum number of points needed for a river to be valid - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers") - uint8 MinRiverSectionCount = 5; - // How wide a river is by default. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers") - uint8 StartingRiverSize = 1; - // The maximum width a river can grow to. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rivers") - uint8 MaxRiverSize = 4; - // This is the table of all possible river names. - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Rivers") - UDataTable* RiverNameTable; - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Rivers") - TArray Rivers; - - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void SetGraph(UPolygonMap* Graph, int32 Size); - - - // Determine polygon and corner type: ocean, coast, land. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - virtual void AssignOceanCoastAndLand(); - - // Calculate the watershed of every land point. The watershed is - // the last downstream land point in the downslope graph. TODO: - // watersheds are currently calculated on corners, but it'd be - // more useful to compute them on polygon centers so that every - // polygon can be marked as being in one watershed. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void CalculateWatersheds(); - // Create rivers along edges. Pick a random corner point, then - // move downslope. Mark the edges and corners as rivers. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void CreateRivers(FRandomStream& RandomGenerator); - // Calculate moisture. Freshwater sources spread moisture: rivers - // and lakes (not oceans). Saltwater sources have moisture but do - // not spread it (we set it at the end, after propagation). - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void AssignCornerMoisture(); - // Redistribute moisture to cover the entire range evenly - // from 0.0 to 1.0. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void RedistributeMoisture(TArray LandCorners); - // Assign polygon moisture as the average of the corner moisture. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Map") - void AssignPolygonMoisture(); - -protected: - UPolygonMap* MapGraph; - int32 MapSize; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/Moisture/River.h b/Source/PolygonalMapGenerator/Public/Maps/Moisture/River.h deleted file mode 100644 index 28ae44c..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/Moisture/River.h +++ /dev/null @@ -1,124 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "UObject/NoExportTypes.h" -#include "PolygonMap.h" -#include "Engine/DataTable.h" -#include "RandomStream.h" -#include "PolygonalMapHeightmap.h" -#include "River.generated.h" - -class URiver; - -/* -* Where the river feeds into. -* Provides access to the URiver pointer that this river feeds into as well -* as the index in the URiver corners array showing where the river feeds. -*/ -USTRUCT(BlueprintType) -struct FRiverFeedLocation -{ - GENERATED_BODY() -public: - // The river this river feeds into, or NULL if it doesn't feed into anything. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - URiver* Key; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - int32 Value; -}; - -/** - * - */ -UCLASS(BlueprintType) -class POLYGONALMAPGENERATOR_API URiver : public UObject -{ - GENERATED_BODY() -public: - ~URiver(); - - /*UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - FString RiverName;*/ - // A list of all corners making up this River object. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - TArray RiverCorners; - // The name of this River - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "River") - FString RiverName; - // The MapGraph that serves as the source for all data regarding this river. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Graph") - UPolygonMap* MapGraph; - //UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - //TMap FeederRivers; - // A reference to the river that this river feeds into, if it exists. - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "River") - FRiverFeedLocation FeedsInto; - - // Whether the river is a tributary. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River") - bool IsTributary() const; - // Does this river terminate properly? - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River") - bool Terminates() const; - // Returns a copy of the FMapCorner at the given index. - // Be sure to call UpdateCorner() on the UPolygonMap if the corner gets modified at all. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River|Graph") - FMapCorner GetCorner(const int32 Index) const; - // Returns the 2D location of the FMapCorner at the given index. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River|Graph") - FVector2D GetPointAtIndex(const int32 Index) const; - // Returns the point representing the "center" of the river. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River|Graph") - FVector2D GetCenter() const; - // Gets the edge downstream from the given index. - // Be sure to call UpdateEdge() on the UPolygonMap if the edge gets modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|River|Graph") - FMapEdge GetDownstreamEdge(const int32 Index) const; - - // Sets the River's name and adds it to the global river lookup - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - void InitializeRiver(UDataTable* NameDataTable, FRandomStream& RandomGenerator); - - // Adds a corner to the river. - // All points downstream get increased by the IncreaseRiverAmount. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - FMapCorner AddCorner(FMapCorner Corner, const int32 IncreaseRiverAmount = 1); - // Joins the feeder river to this river. - // Also sets the FeedsInto data for the feeder river. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - bool JoinRiver(URiver* FeederRiver, FMapCorner JoinLocation, bool bIncreaseRiverVolume = true); - - // Makes this river into a tributary. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - void MakeTributary(); - // Clears the river entirely. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - void Clear(); - // Clears the cache used to look up rivers. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - static void ClearRiverLookupCache(); - - // "Draw" this river on the given heightmap. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|River") - void MoveRiverToHeightmap(UPolygonalMapHeightmap* MapHeightmap); - - FORCEINLINE bool operator==(const URiver& Other) const - { - return Other.RiverName.ToLower() == RiverName.ToLower(); - } - -private: - //int32 Size; - int32 FeederRiverCount; - bool bIsTributary; - - static TMap RiverLookup; - - UFUNCTION() - void DrawBeizerCurve(UPolygonalMapHeightmap* MapHeightmap, FVector2D v0, FVector2D control0, FVector2D v1, FVector2D control1); - UFUNCTION() - FVector2D CalculateBezierPoint(float t, FVector2D p0, FVector2D p1, FVector2D p2, FVector2D p3); - UFUNCTION() - void DrawLineOnHeightmap(UPolygonalMapHeightmap* MapHeightmap, const FVector2D& point1, const FVector2D& point2); -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/PointGenerator.h b/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/PointGenerator.h deleted file mode 100644 index 0475c51..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/PointGenerator.h +++ /dev/null @@ -1,57 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Components/ActorComponent.h" -#include "PointGenerator.generated.h" -// This fixes issues with UPROPERTY in Visual Studio's Intellisense with VAssistX -using namespace UP; - -/** -* The PointSelector class generates the points that the rest of the map is based around. -* More uniform points (such as a Hexagonal Selector or a Square Selector) will create more uniform maps. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UPointGenerator : public UActorComponent -{ - GENERATED_BODY() - -public: - UPointGenerator() {}; - ~UPointGenerator() {}; - - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph|Points") - void InitializeSelector(int32 mapSize, int32 seed, int32 border = 10); - - // Generates the given number of points with the given seed. - // By default, all points will be at 0,0. - UFUNCTION(BlueprintNativeEvent, Category = "World Generation|Island Generation|Graph|Points") - TArray GeneratePoints(int32 numberOfPoints); - // As the Hexagon and Square points don't have any inherent randomness, the randomness must come from elsewhere. - // This function is shorthand for detecting if this generator is a Hexagon or Square generator. - // If this is true, more randomness will be added in the actual map generation. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph|Points") - bool NeedsMoreRandomness(); - - // The lowest possible value our points can reach - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph|Points") - virtual int32 MinPoint(); - // The highest possible value our points can reach - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph|Points") - virtual int32 MaxPoint(); - - // Will return true if the given point is on or beyond our border. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph|Points") - bool PointIsOnBorder(FVector2D point); -protected: - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - int32 MapSize; - UPROPERTY(Category = "Island", BlueprintReadWrite, EditAnywhere) - FRandomStream RandomGenerator; - UPROPERTY(Category = "Points", BlueprintReadWrite, EditAnywhere) - int32 Border; - UPROPERTY(Category = "Points", BlueprintReadWrite, EditAnywhere) - bool bNeedsMoreRandomness; - - virtual TArray GeneratePoints_Implementation(int32 numberOfPoints); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/RandomPointGenerator.h b/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/RandomPointGenerator.h deleted file mode 100644 index cacc983..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/RandomPointGenerator.h +++ /dev/null @@ -1,22 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "PointGenerator.h" -#include "RandomPointGenerator.generated.h" - -/** -* The Random Point Selector will create an array of completely random points. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API URandomPointGenerator : public UPointGenerator -{ - GENERATED_BODY() - -public: - URandomPointGenerator() { bNeedsMoreRandomness = false; }; - ~URandomPointGenerator() {}; - -protected: - virtual TArray GeneratePoints_Implementation(int32 numberOfPoints) override; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/SquarePointGenerator.h b/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/SquarePointGenerator.h deleted file mode 100644 index 8393b87..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/PointGenerators/SquarePointGenerator.h +++ /dev/null @@ -1,21 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "PointGenerator.h" -#include "SquarePointGenerator.generated.h" -/** -* The SquarePointGenerator generates points in a grid pattern. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API USquarePointGenerator : public UPointGenerator -{ - GENERATED_BODY() - -public: - USquarePointGenerator() { bNeedsMoreRandomness = true; }; - ~USquarePointGenerator() {}; - -protected: - virtual TArray GeneratePoints_Implementation(int32 numberOfPoints) override; -}; diff --git a/Source/PolygonalMapGenerator/Public/Maps/PolygonMap.h b/Source/PolygonalMapGenerator/Public/Maps/PolygonMap.h deleted file mode 100644 index e041689..0000000 --- a/Source/PolygonalMapGenerator/Public/Maps/PolygonMap.h +++ /dev/null @@ -1,506 +0,0 @@ -// Original Work Copyright (c) 2010 Amit J Patel, Modified Work Copyright (c) 2016 Jay M Stevens - -#pragma once - -#include "Components/ActorComponent.h" -#include "Engine/World.h" -#include "GameplayTagContainer.h" -#include "PolygonMap.generated.h" - -DECLARE_LOG_CATEGORY_EXTERN(LogWorldGen, Log, All); -DECLARE_DYNAMIC_DELEGATE(FIslandGeneratorDelegate); - -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FMapData -{ - GENERATED_BODY() - - // Location in the map itself - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, EditAnywhere) - FVector2D Point; - - // The height of this MapData (0.0 - 1.0) - UPROPERTY(Category = "Map Biome", BlueprintReadWrite, EditAnywhere) - float Elevation; - // How much moisture this MapData receives (0.0 - 1.0) - UPROPERTY(Category = "Map Biome", BlueprintReadWrite, EditAnywhere) - float Moisture; - - // The Biome this MapData resides in. - // Biomes are determined by the BiomeManager class. - // Users can override the BiomeManager class if they would like to implement a different biome distribution. - UPROPERTY(Category = "Map Biome", BlueprintReadWrite, EditAnywhere, meta = (Categories = "MapData.Biome")) - FGameplayTag Biome; - - // Any special tags associated with the MapData object. - // This can be used to tag this with things such as "volcano", "water", "player start", etc. - // Later steps in world generation can then look at the tags and give this point special behavior based on them. - UPROPERTY(Category = "Map Biome", BlueprintReadWrite, EditAnywhere, meta = (Categories = "MapData.MetaData")) - FGameplayTagContainer Tags; - - FMapData() - { - Point = FVector2D::ZeroVector; - - Tags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Border"))); - Tags.AddTagFast(FGameplayTag::RequestGameplayTag(TEXT("MapData.MetaData.Water.Saltwater"))); - - Elevation = 0.0f; - Moisture = 0.0f; - } -}; - -struct FMapCorner; -struct FMapEdge; -class URiver; - -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FMapCenter -{ - GENERATED_BODY() - // The index of this Center. - // This can be used to look up the "main" reference of this Center in the - // main UPolygonMap class. - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, VisibleAnywhere) - int32 Index; - - // All metadata related to this FMapCenter object. - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, EditAnywhere) - FMapData CenterData; - - // The index of all neighboring Centers - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Neighbors; - // The index of all Edges that make up our borders - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Borders; - // The index of all Corners of our polygon - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Corners; - - FMapCenter() - { - Index = -1; - } - - FORCEINLINE bool operator==(const FMapCenter& Other) const - { - return Other.Index == Index; - } -}; - -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FMapCorner -{ - GENERATED_BODY() - // The index of this Corner. - // This can be used to look up the "main" reference of this Corner in the - // main UPolygonMap class. - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, VisibleAnywhere) - int32 Index; - - // All metadata related to this FMapCorner object. - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, EditAnywhere) - FMapData CornerData; - - // The index of all Centers that touch this Corner - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Touches; - // The index of all Edges that have one end terminating at this Corner - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Protrudes; - // The index of all Corners adjacent to this Corner - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - TArray Adjacent; - - // Pointer to adjacent Corner most downhill from us, or -1 - UPROPERTY(Category = "Watershed", BlueprintReadWrite, EditAnywhere) - int32 Downslope; - // Pointer to coastal Corner, or -1 for null - UPROPERTY(Category = "Watershed", BlueprintReadWrite, EditAnywhere) - int32 Watershed; - // The size of the watershed - UPROPERTY(Category = "Watershed", BlueprintReadWrite, EditAnywhere) - int32 WatershedSize; - // The size of the river flowing through this corner. - // If there is no river, this is 0. - UPROPERTY(Category = "River", BlueprintReadWrite, EditAnywhere) - int32 RiverSize; - // This index refers to where in the river this point resides. - // It refers to an array of FMapCorners in the URiver object. - // If there is no river, this is -1. - UPROPERTY(Category = "River", BlueprintReadWrite, EditAnywhere) - int32 RiverIndex; - // A pointer to any River which flows through this corner. - UPROPERTY(Category = "River", BlueprintReadWrite, EditAnywhere) - URiver* River; - - FMapCorner() - { - Index = -1; - RiverSize = 0; - Downslope = -1; - Watershed = -1; - RiverIndex = -1; - WatershedSize = 0; - River = NULL; - } - - FORCEINLINE bool operator <(const FMapCorner& c) const - { - return CornerData.Elevation < c.CornerData.Elevation; - } - - FORCEINLINE bool operator==(const FMapCorner& Other) const - { - return Other.Index == Index; - } -}; - -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FMapEdge -{ - GENERATED_BODY() - // The index of this Edge - UPROPERTY(Category = "Map Graph", BlueprintReadWrite, VisibleAnywhere) - int32 Index; - - // The Delaunay Edge points to a center. - // Right now, this is just an index of that center, rather than an actual reference to it. - // I'm not happy with this implementation, so it may be changed in the future. - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - int32 DelaunayEdge0; - // The Delaunay Edge points to a center. - // Right now, this is just an index of that center, rather than an actual reference to it. - // I'm not happy with this implementation, so it may be changed in the future. - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - int32 DelaunayEdge1; - - // The Voronoi Edge points to a corner. - // Right now, this is just an index of that corner, rather than an actual reference to it. - // I'm not happy with this implementation, so it may be changed in the future. - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - int32 VoronoiEdge0; - // The Voronoi Edge points to a corner. - // Right now, this is just an index of that corner, rather than an actual reference to it. - // I'm not happy with this implementation, so it may be changed in the future. - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - int32 VoronoiEdge1; - - // The midway point between our two voronoi edges - UPROPERTY(Category = "Map Graph", BlueprintReadOnly, VisibleAnywhere) - FVector2D Midpoint; - - // The volume of the river flowing through this edge, or 0 - UPROPERTY(Category = "Map Biome", BlueprintReadWrite, EditAnywhere) - int32 RiverVolume; - - //Constructor - FMapEdge() - { - Index = -1; - DelaunayEdge0 = -1; - DelaunayEdge1 = -1; - VoronoiEdge0 = -1; - VoronoiEdge1 = -1; - - RiverVolume = 0; - } - - FORCEINLINE bool operator==(const FMapEdge& Other) const - { - return Other.Index == Index; - } -}; - -/** -* This class governs how the 2D FMapData objects act in "world space". -* This is used showing map debug, as well as converting from "Polygon Map" space to 3D Unreal world space. -*/ -USTRUCT(BlueprintType) -struct POLYGONALMAPGENERATOR_API FWorldSpaceMapData -{ - GENERATED_BODY() - - // The size each debug point is rendered - UPROPERTY(Category = "Map", BlueprintReadWrite, EditAnywhere) - int32 PointSize; - // The Z offset of the bottom of the ocean -- what's the lowest - // point on the entire map? - UPROPERTY(Category = "Map", BlueprintReadWrite, EditAnywhere) - float ElevationOffset; - // How much to scale the map on the XY scale. - UPROPERTY(Category = "Map", BlueprintReadWrite, EditAnywhere) - float XYScaleFactor; - // How tall the map should be -- how much higher is the highest - // point in the map from the lowest point? - UPROPERTY(Category = "Map", BlueprintReadWrite, EditAnywhere) - float ElevationScale; - - FWorldSpaceMapData() - { - PointSize = 16; - ElevationOffset = 0.0f; - XYScaleFactor = 100.0f; - ElevationScale = 2560.0f; - } -}; - -/** -* The PolygonMap is a class which uses a Voronoi diagram to collect data about a graph of -* points on the XY plane. -* These points are separated into map 'centers' (the points of the Delaunay 'dual graph'), -* map 'corners' (the points of the Voronoi graph), and map 'edges' (which make up the -* connections between Voronoi graphs and Delaunay graphs). -* Map centers and map corners both have metadata associated with them in the form of a -* 'MapData' class, which is used in the actual MapGenerator. -*/ -UCLASS(Blueprintable) -class POLYGONALMAPGENERATOR_API UPolygonMap : public UActorComponent -{ - GENERATED_BODY() - friend class AIslandMapGenerator; - -public: - // A conversion from local space to world space - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "World Space Conversion") - FWorldSpaceMapData WorldData; - - // Creates the graph's initial points - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void CreatePoints(UPointGenerator* PointSelector, const int32& numberOfPoints); - - // Build graph data structure in 'edges', 'centers', 'corners', - // based on information in the Voronoi results: point.neighbors - // will be a list of neighboring points of the same type (corner - // or center); point.edges will be a list of edges that include - // that point. Each edge connects to four points: the Voronoi edge - // edge.{voronoiEdge0,voronoiEdge1} and its dual Delaunay triangle - // edge edge.{delaunayEdge0,delaunayEdge1}.0 For boundary - // polygons, the Delaunay edge will have one null point, and the - // Voronoi edge may be null. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void BuildGraph(const int32& mapSize, const FWorldSpaceMapData& data); - - // Creates an FMapCenter from the given point. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - FMapCenter MakeCenter(const FVector2D& point); - // Creates an FMapCorner from the given point. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - FMapCorner MakeCorner(const FVector2D& point); - - // Although Lloyd relaxation improves the uniformity of polygon - // sizes, it doesn't help with the edge lengths. Short edges can - // be bad for some games, and lead to weird artifacts on - // rivers. We can easily lengthen short edges by moving the - // corners, but **we lose the Voronoi property**. The corners are - // moved to the average of the polygon centers around them. Short - // edges become longer. Long edges tend to become shorter. The - // polygons tend to be more uniform after this step. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void ImproveCorners(); - - // Returns a MapCenter at the given index. - // If the index is invalid, an empty MapCenter will be returned. - // This empty MapCenter will have an index of -1. - // Make sure to use the function UpdateCenter() to update the graph - // after the MapCenter has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCenter GetCenter(const int32& index) const; - // Returns a MapCorner at the given index. - // If the index is invalid, an empty MapCorner will be returned. - // This empty MapCorner will have an index of -1. - // Make sure to use the function UpdateCorner() to update the graph - // after the MapCorner has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCorner GetCorner(const int32& index) const; - // Returns a MapEdge at the given index. - // If the index is invalid, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge GetEdge(const int32& index) const; - - // Update a MapCenter in the graph after it has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateCenter(const FMapCenter& center); - // Update a MapCorner in the graph after it has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateCorner(const FMapCorner& corner); - // Update a MapEdge in the graph after it has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void UpdateEdge(const FMapEdge& edge); - - // Returns the number of MapCenters in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetCenterNum() const; - // Returns the number of MapCorners in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetCornerNum() const; - // Returns the number of MapEdges in our graph. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetEdgeNum() const; - - // Returns the size of one side of our graph. - // The full graph is a square with each side of this length. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - int32 GetGraphSize() const; - - - // Returns ALL MapData points in our graph. - // This is like returning a collection of all MapCenters and MapCorners. - // Note that you cannot determine from a MapData object alone whether it - // came from a MapCenter or a MapCorner, and that because of this, the - // MapData object's "Index" property now means nothing. 2 different - // MapData objects may share the same indicies. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|MapData") - TArray& GetAllMapData(); - - // This returns a copy of the FMapCorner array. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - TArray GetCopyOfMapCornerArray(); - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - TArray GetCopyOfMapEdgeArray(); - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - TArray GetCopyOfMapCenterArray(); - - // Gets a list of all MapCorners which are not marked as ocean. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - TArray FindLandCorners() const; - - // Returns the MapEdge defined by two adjacent MapCenters. - // If the edge doesn't exist, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge FindEdgeFromCenters(const FMapCenter& v0, const FMapCenter& v1) const; - - // Returns the MapEdge defined by two adjacent MapCorners. - // If the edge doesn't exist, an empty MapEdge will be returned. - // This empty MapEdge will have an index of -1. - // Make sure to use the function UpdateEdge() to update the graph - // after the MapEdge has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapEdge FindEdgeFromCorners(const FMapCorner& v0, const FMapCorner& v1) const; - - // Returns the MapCenter defined by two adjacent MapCorners. - // If the center polygon doesn't exist, an empty MapCenter will be returned. - // This empty MapCenter will have an index of -1. - // Make sure to use the function UpdateCenter() to update the graph - // after the MapCenter has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCenter FindCenterFromCorners(FMapCorner CornerA, FMapCorner CornerB) const; - - // Compiles all map data into the CachedMapData array. - // This is used by the PixelMap to create pixels. - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Graph") - void CompileMapData(); - - // Converts a MapData object into the point it represents in 3D world space. - // This can be used to mark where rivers are, to place props, etc. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FVector ConvertGraphPointToWorldSpace(const FMapData& MapPointData); - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FVector2D ConvertWorldPointToGraphSpace(const FVector WorldPoint); - - // This takes a 2D point and returns a copy of the polygon encompassing that point. - // If no polygon can be found, an empty MapCenter will be returned. - // This empty MapCenter will have an index of -1. - // Make sure to use the function UpdateCenter() to update the graph - // after the MapCenter has been modified. - // Due to the way Unreal handles TArrays, we can only return - // a copy of an element, not the element itself. - // I don't like this implementation, and it may be changed in the future. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCenter FindMapCenterForCoordinate(const FVector2D& Point); - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - FMapCorner FindMapCornerForCoordinate(const FVector2D& Point); - - // Checks if a given MapCenter polygon contains a 2D point. - // If it does, this function returns true. Otherwise, it returns false. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - bool CenterContainsPoint(const FVector2D& Point, const FMapCenter& Center) const; - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - bool CornerContainsPoint(const FVector2D& Point, const FMapCorner& Corner) const; - - // Returns the Z position of a 2D map coordinate. - // The MapCorner reference will be populated with data from the triangle that the point is in. - // If the MapCorner's index is below 0, the point lies outside of the generated map. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - float CalculateZPosition(FVector2D MapLocation, FMapCorner& OutMapCorner); - - // Calculates the interpolated Z position of a 2D point between 3 MapCenters. - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - float CalculateZPositionBetweenCenters(FMapCenter CenterA, FMapCenter CenterB, FMapCenter CenterC, FVector2D MapLocation) const; - - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - float CalculateMoistureAtPoint(FVector2D MapLocation, FMapCorner& OutMapCorner); - UFUNCTION(BlueprintPure, Category = "World Generation|Island Generation|Graph") - float InterpolateMapDataMoisture(FMapData PointA, FMapData PointB, FMapData PointC, FVector2D MapLocation) const; -private: - /// Graph Data - // The points in our graph - // I don't like this implementation, and it may be changed in the future. - UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Graph", meta = (AllowPrivateAccess = "true")) - TArray Points; - // The Centers in our graph - // I don't like this implementation, and it may be changed in the future. - UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Graph", meta = (AllowPrivateAccess = "true")) - TArray Centers; - // The Corners in our graph - // I don't like this implementation, and it may be changed in the future. - UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Graph", meta = (AllowPrivateAccess = "true")) - TArray Corners; - // The Edges of our graph - // I don't like this implementation, and it may be changed in the future. - UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = "Graph", meta = (AllowPrivateAccess = "true")) - TArray Edges; - - // This variable generates our initial points - UPROPERTY() - UPointGenerator* PointSelector; - // The size of an edge in the 2D map - UPROPERTY() - int32 MapSize; - - // ALL MapData from both MapCenters and MapCorners. - // Must be compiled first. - UPROPERTY() - TArray CachedMapData; - // A map of centers connected to their location - UPROPERTY() - TMap CenterLookup; - // A map of corners connected to their location - UPROPERTY() - TMap CornerLookup; - - UPROPERTY() - int32 MinPointLocation; - UPROPERTY() - int32 MaxPointLocation; - - // Returns true if 2 segments are intersecting, otherwise returns false. - UFUNCTION() - bool SegementsIntersect(const FMapEdge& Edge, const FVector2D& StartPoint, const FVector2D& EndPoint) const; -}; diff --git a/Source/PolygonalMapGenerator/Public/Naming/ProceduralNameGenerator.h b/Source/PolygonalMapGenerator/Public/Naming/ProceduralNameGenerator.h deleted file mode 100644 index b94aae0..0000000 --- a/Source/PolygonalMapGenerator/Public/Naming/ProceduralNameGenerator.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2015 Dave Carlile -Modifications made in 2017 Jay Stevens - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#pragma once - -#include "Kismet/BlueprintFunctionLibrary.h" -#include "Engine/DataTable.h" -#include "ProceduralNameGenerator.generated.h" - -USTRUCT(BlueprintType) -struct FMarkovData : public FTableRowBase -{ - GENERATED_BODY() -public: - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Markov") - FText MarkovText; -}; - -USTRUCT(BlueprintType) -struct FMarkovCharacter -{ - GENERATED_BODY() -public: - //UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Markov") - TCHAR Letter; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Markov") - uint8 Instances; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Markov") - float Probability; - - FORCEINLINE bool operator <(const FMarkovCharacter& c) const - { - return Probability < c.Probability; - } - FORCEINLINE bool operator >(const FMarkovCharacter& c) const - { - return Probability < c.Probability; - } -}; - -/** - * - */ -UCLASS() -class POLYGONALMAPGENERATOR_API UProceduralNameGenerator : public UBlueprintFunctionLibrary -{ - GENERATED_BODY() - -public: - //UFUNCTION(BlueprintCallable, Category = "Procedural|Markov Chain") - //static TArray ConvertRiverDataToTextArray() - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Utilities|Markov Chain") - static FString GenerateRandomWord(TArray Words, FRandomStream RandomGenerator, uint8 WordOrder = 2, uint8 MinLength = 3, uint8 MaxLength = 16, bool bConvertToTitleCase = true, bool bMatchWordPattern = false); - UFUNCTION(BlueprintCallable, Category = "World Generation|Island Generation|Utilities|Markov Chain") - static FString UppercaseWords(FString value); - -private: - static uint8 Order; - static TMap> Chains; - static TSet WordPatterns; - - static bool IsVowel(TCHAR ch); - static FString GetWordPattern(FString word); - static void IdentifyWordPattern(FString word); - static void AddCharacter(FString key, TCHAR ch); - static void ProcessWord(FString word); - static void AnalyzeWord(FString word); - static void CalculateProbability(); - static void AnalyzeWords(TArray words, uint8 order); - static FMarkovCharacter* GetCharacterByProbability(FString key, float probability); - static FString GenerateRandomWord(uint8 minLength, uint8 maxLength, FRandomStream& RandomGenerator, bool bConvertToTitleCase); -}; \ No newline at end of file diff --git a/Source/PolygonalMapGenerator/Public/PolygonalMapGenerator.h b/Source/PolygonalMapGenerator/Public/PolygonalMapGenerator.h index 71f85a4..18e51ac 100644 --- a/Source/PolygonalMapGenerator/Public/PolygonalMapGenerator.h +++ b/Source/PolygonalMapGenerator/Public/PolygonalMapGenerator.h @@ -2,8 +2,11 @@ #pragma once +#include "CoreMinimal.h" #include "ModuleManager.h" +DECLARE_LOG_CATEGORY_EXTERN(LogMapGen, Log, All); + class FPolygonalMapGeneratorModule : public IModuleInterface { public: