diff --git a/CMakeLists.txt b/CMakeLists.txt index cae041d32..7f60058b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,3 +75,4 @@ add_subdirectory(igor) add_subdirectory(mihail) add_subdirectory(xbrzscale) add_subdirectory(fantasyname) +add_subdirectory(FastNoise) diff --git a/FastNoise/CMakeLists.txt b/FastNoise/CMakeLists.txt new file mode 100644 index 000000000..6d8d0faa2 --- /dev/null +++ b/FastNoise/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB FASTNOISE_SOURCES FastNoise.cpp FastNoise.h) + +set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") + +if(HAVE_CXX14) + add_definitions(-DHAVE_CXX14) +endif() + +add_library(fastnoise ${FASTNOISE_SOURCES}) diff --git a/FastNoise/FastNoise.cpp b/FastNoise/FastNoise.cpp new file mode 100644 index 000000000..9f6b8cc7c --- /dev/null +++ b/FastNoise/FastNoise.cpp @@ -0,0 +1,2359 @@ +// FastNoise.cpp +// +// MIT License +// +// Copyright(c) 2017 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 "FastNoise.h" + +#include +#include + +#include +#include + +const FN_DECIMAL GRAD_X[] = +{ + 1, -1, 1, -1, + 1, -1, 1, -1, + 0, 0, 0, 0 +}; +const FN_DECIMAL GRAD_Y[] = +{ + 1, 1, -1, -1, + 0, 0, 0, 0, + 1, -1, 1, -1 +}; +const FN_DECIMAL GRAD_Z[] = +{ + 0, 0, 0, 0, + 1, 1, -1, -1, + 1, 1, -1, -1 +}; + +const FN_DECIMAL 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 FN_DECIMAL VAL_LUT[] = +{ + FN_DECIMAL(0.3490196078), FN_DECIMAL(0.4352941176), FN_DECIMAL(-0.4509803922), FN_DECIMAL(0.6392156863), FN_DECIMAL(0.5843137255), FN_DECIMAL(-0.1215686275), FN_DECIMAL(0.7176470588), FN_DECIMAL(-0.1058823529), FN_DECIMAL(0.3960784314), FN_DECIMAL(0.0431372549), FN_DECIMAL(-0.03529411765), FN_DECIMAL(0.3176470588), FN_DECIMAL(0.7254901961), FN_DECIMAL(0.137254902), FN_DECIMAL(0.8588235294), FN_DECIMAL(-0.8196078431), + FN_DECIMAL(-0.7960784314), FN_DECIMAL(-0.3333333333), FN_DECIMAL(-0.6705882353), FN_DECIMAL(-0.3882352941), FN_DECIMAL(0.262745098), FN_DECIMAL(0.3254901961), FN_DECIMAL(-0.6470588235), FN_DECIMAL(-0.9215686275), FN_DECIMAL(-0.5294117647), FN_DECIMAL(0.5294117647), FN_DECIMAL(-0.4666666667), FN_DECIMAL(0.8117647059), FN_DECIMAL(0.3803921569), FN_DECIMAL(0.662745098), FN_DECIMAL(0.03529411765), FN_DECIMAL(-0.6156862745), + FN_DECIMAL(-0.01960784314), FN_DECIMAL(-0.3568627451), FN_DECIMAL(-0.09019607843), FN_DECIMAL(0.7490196078), FN_DECIMAL(0.8352941176), FN_DECIMAL(-0.4039215686), FN_DECIMAL(-0.7490196078), FN_DECIMAL(0.9529411765), FN_DECIMAL(-0.0431372549), FN_DECIMAL(-0.9294117647), FN_DECIMAL(-0.6549019608), FN_DECIMAL(0.9215686275), FN_DECIMAL(-0.06666666667), FN_DECIMAL(-0.4431372549), FN_DECIMAL(0.4117647059), FN_DECIMAL(-0.4196078431), + FN_DECIMAL(-0.7176470588), FN_DECIMAL(-0.8117647059), FN_DECIMAL(-0.2549019608), FN_DECIMAL(0.4901960784), FN_DECIMAL(0.9137254902), FN_DECIMAL(0.7882352941), FN_DECIMAL(-1.0), FN_DECIMAL(-0.4745098039), FN_DECIMAL(0.7960784314), FN_DECIMAL(0.8509803922), FN_DECIMAL(-0.6784313725), FN_DECIMAL(0.4588235294), FN_DECIMAL(1.0), FN_DECIMAL(-0.1843137255), FN_DECIMAL(0.4509803922), FN_DECIMAL(0.1450980392), + FN_DECIMAL(-0.231372549), FN_DECIMAL(-0.968627451), FN_DECIMAL(-0.8588235294), FN_DECIMAL(0.4274509804), FN_DECIMAL(0.003921568627), FN_DECIMAL(-0.003921568627), FN_DECIMAL(0.2156862745), FN_DECIMAL(0.5058823529), FN_DECIMAL(0.7647058824), FN_DECIMAL(0.2078431373), FN_DECIMAL(-0.5921568627), FN_DECIMAL(0.5764705882), FN_DECIMAL(-0.1921568627), FN_DECIMAL(-0.937254902), FN_DECIMAL(0.08235294118), FN_DECIMAL(-0.08235294118), + FN_DECIMAL(0.9058823529), FN_DECIMAL(0.8274509804), FN_DECIMAL(0.02745098039), FN_DECIMAL(-0.168627451), FN_DECIMAL(-0.7803921569), FN_DECIMAL(0.1137254902), FN_DECIMAL(-0.9450980392), FN_DECIMAL(0.2), FN_DECIMAL(0.01960784314), FN_DECIMAL(0.5607843137), FN_DECIMAL(0.2705882353), FN_DECIMAL(0.4431372549), FN_DECIMAL(-0.9607843137), FN_DECIMAL(0.6156862745), FN_DECIMAL(0.9294117647), FN_DECIMAL(-0.07450980392), + FN_DECIMAL(0.3098039216), FN_DECIMAL(0.9921568627), FN_DECIMAL(-0.9137254902), FN_DECIMAL(-0.2941176471), FN_DECIMAL(-0.3411764706), FN_DECIMAL(-0.6235294118), FN_DECIMAL(-0.7647058824), FN_DECIMAL(-0.8901960784), FN_DECIMAL(0.05882352941), FN_DECIMAL(0.2392156863), FN_DECIMAL(0.7333333333), FN_DECIMAL(0.6549019608), FN_DECIMAL(0.2470588235), FN_DECIMAL(0.231372549), FN_DECIMAL(-0.3960784314), FN_DECIMAL(-0.05098039216), + FN_DECIMAL(-0.2235294118), FN_DECIMAL(-0.3725490196), FN_DECIMAL(0.6235294118), FN_DECIMAL(0.7019607843), FN_DECIMAL(-0.8274509804), FN_DECIMAL(0.4196078431), FN_DECIMAL(0.07450980392), FN_DECIMAL(0.8666666667), FN_DECIMAL(-0.537254902), FN_DECIMAL(-0.5058823529), FN_DECIMAL(-0.8039215686), FN_DECIMAL(0.09019607843), FN_DECIMAL(-0.4823529412), FN_DECIMAL(0.6705882353), FN_DECIMAL(-0.7882352941), FN_DECIMAL(0.09803921569), + FN_DECIMAL(-0.6078431373), FN_DECIMAL(0.8039215686), FN_DECIMAL(-0.6), FN_DECIMAL(-0.3254901961), FN_DECIMAL(-0.4117647059), FN_DECIMAL(-0.01176470588), FN_DECIMAL(0.4823529412), FN_DECIMAL(0.168627451), FN_DECIMAL(0.8745098039), FN_DECIMAL(-0.3647058824), FN_DECIMAL(-0.1607843137), FN_DECIMAL(0.568627451), FN_DECIMAL(-0.9921568627), FN_DECIMAL(0.9450980392), FN_DECIMAL(0.5137254902), FN_DECIMAL(0.01176470588), + FN_DECIMAL(-0.1450980392), FN_DECIMAL(-0.5529411765), FN_DECIMAL(-0.5764705882), FN_DECIMAL(-0.1137254902), FN_DECIMAL(0.5215686275), FN_DECIMAL(0.1607843137), FN_DECIMAL(0.3725490196), FN_DECIMAL(-0.2), FN_DECIMAL(-0.7254901961), FN_DECIMAL(0.631372549), FN_DECIMAL(0.7098039216), FN_DECIMAL(-0.568627451), FN_DECIMAL(0.1294117647), FN_DECIMAL(-0.3098039216), FN_DECIMAL(0.7411764706), FN_DECIMAL(-0.8509803922), + FN_DECIMAL(0.2549019608), FN_DECIMAL(-0.6392156863), FN_DECIMAL(-0.5607843137), FN_DECIMAL(-0.3176470588), FN_DECIMAL(0.937254902), FN_DECIMAL(0.9843137255), FN_DECIMAL(0.5921568627), FN_DECIMAL(0.6941176471), FN_DECIMAL(0.2862745098), FN_DECIMAL(-0.5215686275), FN_DECIMAL(0.1764705882), FN_DECIMAL(0.537254902), FN_DECIMAL(-0.4901960784), FN_DECIMAL(-0.4588235294), FN_DECIMAL(-0.2078431373), FN_DECIMAL(-0.2156862745), + FN_DECIMAL(0.7725490196), FN_DECIMAL(0.3647058824), FN_DECIMAL(-0.2392156863), FN_DECIMAL(0.2784313725), FN_DECIMAL(-0.8823529412), FN_DECIMAL(0.8980392157), FN_DECIMAL(0.1215686275), FN_DECIMAL(0.1058823529), FN_DECIMAL(-0.8745098039), FN_DECIMAL(-0.9843137255), FN_DECIMAL(-0.7019607843), FN_DECIMAL(0.9607843137), FN_DECIMAL(0.2941176471), FN_DECIMAL(0.3411764706), FN_DECIMAL(0.1529411765), FN_DECIMAL(0.06666666667), + FN_DECIMAL(-0.9764705882), FN_DECIMAL(0.3019607843), FN_DECIMAL(0.6470588235), FN_DECIMAL(-0.5843137255), FN_DECIMAL(0.05098039216), FN_DECIMAL(-0.5137254902), FN_DECIMAL(-0.137254902), FN_DECIMAL(0.3882352941), FN_DECIMAL(-0.262745098), FN_DECIMAL(-0.3019607843), FN_DECIMAL(-0.1764705882), FN_DECIMAL(-0.7568627451), FN_DECIMAL(0.1843137255), FN_DECIMAL(-0.5450980392), FN_DECIMAL(-0.4980392157), FN_DECIMAL(-0.2784313725), + FN_DECIMAL(-0.9529411765), FN_DECIMAL(-0.09803921569), FN_DECIMAL(0.8901960784), FN_DECIMAL(-0.2862745098), FN_DECIMAL(-0.3803921569), FN_DECIMAL(0.5529411765), FN_DECIMAL(0.7803921569), FN_DECIMAL(-0.8352941176), FN_DECIMAL(0.6862745098), FN_DECIMAL(0.7568627451), FN_DECIMAL(0.4980392157), FN_DECIMAL(-0.6862745098), FN_DECIMAL(-0.8980392157), FN_DECIMAL(-0.7725490196), FN_DECIMAL(-0.7098039216), FN_DECIMAL(-0.2470588235), + FN_DECIMAL(-0.9058823529), FN_DECIMAL(0.9764705882), FN_DECIMAL(0.1921568627), FN_DECIMAL(0.8431372549), FN_DECIMAL(-0.05882352941), FN_DECIMAL(0.3568627451), FN_DECIMAL(0.6078431373), FN_DECIMAL(0.5450980392), FN_DECIMAL(0.4039215686), FN_DECIMAL(-0.7333333333), FN_DECIMAL(-0.4274509804), FN_DECIMAL(0.6), FN_DECIMAL(0.6784313725), FN_DECIMAL(-0.631372549), FN_DECIMAL(-0.02745098039), FN_DECIMAL(-0.1294117647), + FN_DECIMAL(0.3333333333), FN_DECIMAL(-0.8431372549), FN_DECIMAL(0.2235294118), FN_DECIMAL(-0.3490196078), FN_DECIMAL(-0.6941176471), FN_DECIMAL(0.8823529412), FN_DECIMAL(0.4745098039), FN_DECIMAL(0.4666666667), FN_DECIMAL(-0.7411764706), FN_DECIMAL(-0.2705882353), FN_DECIMAL(0.968627451), FN_DECIMAL(0.8196078431), FN_DECIMAL(-0.662745098), FN_DECIMAL(-0.4352941176), FN_DECIMAL(-0.8666666667), FN_DECIMAL(-0.1529411765), +}; + +const FN_DECIMAL CELL_2D_X[] = +{ + FN_DECIMAL(-0.6440658039), FN_DECIMAL(-0.08028078721), FN_DECIMAL(0.9983546168), FN_DECIMAL(0.9869492062), FN_DECIMAL(0.9284746418), FN_DECIMAL(0.6051097552), FN_DECIMAL(-0.794167404), FN_DECIMAL(-0.3488667991), FN_DECIMAL(-0.943136526), FN_DECIMAL(-0.9968171318), FN_DECIMAL(0.8740961579), FN_DECIMAL(0.1421139764), FN_DECIMAL(0.4282553608), FN_DECIMAL(-0.9986665833), FN_DECIMAL(0.9996760121), FN_DECIMAL(-0.06248383632), + FN_DECIMAL(0.7120139305), FN_DECIMAL(0.8917660409), FN_DECIMAL(0.1094842955), FN_DECIMAL(-0.8730880804), FN_DECIMAL(0.2594811489), FN_DECIMAL(-0.6690063346), FN_DECIMAL(-0.9996834972), FN_DECIMAL(-0.8803608671), FN_DECIMAL(-0.8166554937), FN_DECIMAL(0.8955599676), FN_DECIMAL(-0.9398321388), FN_DECIMAL(0.07615451399), FN_DECIMAL(-0.7147270565), FN_DECIMAL(0.8707354457), FN_DECIMAL(-0.9580008579), FN_DECIMAL(0.4905965632), + FN_DECIMAL(0.786775944), FN_DECIMAL(0.1079711577), FN_DECIMAL(0.2686638979), FN_DECIMAL(0.6113487322), FN_DECIMAL(-0.530770584), FN_DECIMAL(-0.7837268286), FN_DECIMAL(-0.8558691039), FN_DECIMAL(-0.5726093896), FN_DECIMAL(-0.9830740914), FN_DECIMAL(0.7087766359), FN_DECIMAL(0.6807027153), FN_DECIMAL(-0.08864708788), FN_DECIMAL(0.6704485923), FN_DECIMAL(-0.1350735482), FN_DECIMAL(-0.9381333003), FN_DECIMAL(0.9756655376), + FN_DECIMAL(0.4231433671), FN_DECIMAL(-0.4959787385), FN_DECIMAL(0.1005554325), FN_DECIMAL(-0.7645857281), FN_DECIMAL(-0.5859053796), FN_DECIMAL(-0.9751154306), FN_DECIMAL(-0.6972258572), FN_DECIMAL(0.7907012002), FN_DECIMAL(-0.9109899213), FN_DECIMAL(-0.9584307894), FN_DECIMAL(-0.8269529333), FN_DECIMAL(0.2608264719), FN_DECIMAL(-0.7773760119), FN_DECIMAL(0.7606456974), FN_DECIMAL(-0.8961083758), FN_DECIMAL(-0.9838134719), + FN_DECIMAL(0.7338893576), FN_DECIMAL(0.2161226729), FN_DECIMAL(0.673509891), FN_DECIMAL(-0.5512056873), FN_DECIMAL(0.6899744332), FN_DECIMAL(0.868004831), FN_DECIMAL(0.5897430311), FN_DECIMAL(-0.8950444221), FN_DECIMAL(-0.3595752773), FN_DECIMAL(0.8209486981), FN_DECIMAL(-0.2912360132), FN_DECIMAL(-0.9965011374), FN_DECIMAL(0.9766994634), FN_DECIMAL(0.738790822), FN_DECIMAL(-0.4730947722), FN_DECIMAL(0.8946479441), + FN_DECIMAL(-0.6943628971), FN_DECIMAL(-0.6620468182), FN_DECIMAL(-0.0887255502), FN_DECIMAL(-0.7512250855), FN_DECIMAL(-0.5322986898), FN_DECIMAL(0.5226295385), FN_DECIMAL(0.2296318375), FN_DECIMAL(0.7915307344), FN_DECIMAL(-0.2756485999), FN_DECIMAL(-0.6900234522), FN_DECIMAL(0.07090588086), FN_DECIMAL(0.5981278485), FN_DECIMAL(0.3033429312), FN_DECIMAL(-0.7253142797), FN_DECIMAL(-0.9855874307), FN_DECIMAL(-0.1761843396), + FN_DECIMAL(-0.6438468325), FN_DECIMAL(-0.9956136595), FN_DECIMAL(0.8541580762), FN_DECIMAL(-0.9999807666), FN_DECIMAL(-0.02152416253), FN_DECIMAL(-0.8705983095), FN_DECIMAL(-0.1197138014), FN_DECIMAL(-0.992107781), FN_DECIMAL(-0.9091181546), FN_DECIMAL(0.788610536), FN_DECIMAL(-0.994636402), FN_DECIMAL(0.4211256853), FN_DECIMAL(0.3110430857), FN_DECIMAL(-0.4031127839), FN_DECIMAL(0.7610684239), FN_DECIMAL(0.7685674467), + FN_DECIMAL(0.152271555), FN_DECIMAL(-0.9364648723), FN_DECIMAL(0.1681333739), FN_DECIMAL(-0.3567427907), FN_DECIMAL(-0.418445483), FN_DECIMAL(-0.98774778), FN_DECIMAL(0.8705250765), FN_DECIMAL(-0.8911701067), FN_DECIMAL(-0.7315350966), FN_DECIMAL(0.6030885658), FN_DECIMAL(-0.4149130821), FN_DECIMAL(0.7585339481), FN_DECIMAL(0.6963196535), FN_DECIMAL(0.8332685012), FN_DECIMAL(-0.8086815232), FN_DECIMAL(0.7518116724), + FN_DECIMAL(-0.3490535894), FN_DECIMAL(0.6972110903), FN_DECIMAL(-0.8795676928), FN_DECIMAL(-0.6442331882), FN_DECIMAL(0.6610236811), FN_DECIMAL(-0.9853565782), FN_DECIMAL(-0.590338458), FN_DECIMAL(0.09843602117), FN_DECIMAL(0.5646534882), FN_DECIMAL(-0.6023259233), FN_DECIMAL(-0.3539248861), FN_DECIMAL(0.5132728656), FN_DECIMAL(0.9380385118), FN_DECIMAL(-0.7599270056), FN_DECIMAL(-0.7425936564), FN_DECIMAL(-0.6679610562), + FN_DECIMAL(-0.3018497816), FN_DECIMAL(0.814478266), FN_DECIMAL(0.03777430269), FN_DECIMAL(-0.7514235086), FN_DECIMAL(0.9662556939), FN_DECIMAL(-0.4720194901), FN_DECIMAL(-0.435054126), FN_DECIMAL(0.7091901235), FN_DECIMAL(0.929379209), FN_DECIMAL(0.9997434357), FN_DECIMAL(0.8306320299), FN_DECIMAL(-0.9434019629), FN_DECIMAL(-0.133133759), FN_DECIMAL(0.5048413216), FN_DECIMAL(0.3711995273), FN_DECIMAL(0.98552091), + FN_DECIMAL(0.7401857005), FN_DECIMAL(-0.9999981398), FN_DECIMAL(-0.2144033253), FN_DECIMAL(0.4808624681), FN_DECIMAL(-0.413835885), FN_DECIMAL(0.644229305), FN_DECIMAL(0.9626648696), FN_DECIMAL(0.1833665934), FN_DECIMAL(0.5794129), FN_DECIMAL(0.01404446873), FN_DECIMAL(0.4388494993), FN_DECIMAL(0.5213612322), FN_DECIMAL(-0.5281609948), FN_DECIMAL(-0.9745306846), FN_DECIMAL(-0.9904373013), FN_DECIMAL(0.9100232252), + FN_DECIMAL(-0.9914057719), FN_DECIMAL(0.7892627765), FN_DECIMAL(0.3364421659), FN_DECIMAL(-0.9416099764), FN_DECIMAL(0.7802732656), FN_DECIMAL(0.886302871), FN_DECIMAL(0.6524471291), FN_DECIMAL(0.5762186726), FN_DECIMAL(-0.08987644664), FN_DECIMAL(-0.2177026782), FN_DECIMAL(-0.9720345052), FN_DECIMAL(-0.05722538858), FN_DECIMAL(0.8105983127), FN_DECIMAL(0.3410261032), FN_DECIMAL(0.6452309645), FN_DECIMAL(-0.7810612152), + FN_DECIMAL(0.9989395718), FN_DECIMAL(-0.808247815), FN_DECIMAL(0.6370177929), FN_DECIMAL(0.5844658772), FN_DECIMAL(0.2054070861), FN_DECIMAL(0.055960522), FN_DECIMAL(-0.995827561), FN_DECIMAL(0.893409165), FN_DECIMAL(-0.931516824), FN_DECIMAL(0.328969469), FN_DECIMAL(-0.3193837488), FN_DECIMAL(0.7314755657), FN_DECIMAL(-0.7913517714), FN_DECIMAL(-0.2204109786), FN_DECIMAL(0.9955900414), FN_DECIMAL(-0.7112353139), + FN_DECIMAL(-0.7935008741), FN_DECIMAL(-0.9961918204), FN_DECIMAL(-0.9714163995), FN_DECIMAL(-0.9566188669), FN_DECIMAL(0.2748495632), FN_DECIMAL(-0.4681743221), FN_DECIMAL(-0.9614449642), FN_DECIMAL(0.585194072), FN_DECIMAL(0.4532946061), FN_DECIMAL(-0.9916113176), FN_DECIMAL(0.942479587), FN_DECIMAL(-0.9813704753), FN_DECIMAL(-0.6538429571), FN_DECIMAL(0.2923335053), FN_DECIMAL(-0.2246660704), FN_DECIMAL(-0.1800781949), + FN_DECIMAL(-0.9581216256), FN_DECIMAL(0.552215082), FN_DECIMAL(-0.9296791922), FN_DECIMAL(0.643183699), FN_DECIMAL(0.9997325981), FN_DECIMAL(-0.4606920354), FN_DECIMAL(-0.2148721265), FN_DECIMAL(0.3482070809), FN_DECIMAL(0.3075517813), FN_DECIMAL(0.6274756393), FN_DECIMAL(0.8910881765), FN_DECIMAL(-0.6397771309), FN_DECIMAL(-0.4479080125), FN_DECIMAL(-0.5247665011), FN_DECIMAL(-0.8386507094), FN_DECIMAL(0.3901291416), + FN_DECIMAL(0.1458336921), FN_DECIMAL(0.01624613149), FN_DECIMAL(-0.8273199879), FN_DECIMAL(0.5611100679), FN_DECIMAL(-0.8380219841), FN_DECIMAL(-0.9856122234), FN_DECIMAL(-0.861398618), FN_DECIMAL(0.6398413916), FN_DECIMAL(0.2694510795), FN_DECIMAL(0.4327334514), FN_DECIMAL(-0.9960265354), FN_DECIMAL(-0.939570655), FN_DECIMAL(-0.8846996446), FN_DECIMAL(0.7642113189), FN_DECIMAL(-0.7002080528), FN_DECIMAL(0.664508256), +}; +const FN_DECIMAL CELL_2D_Y[] = +{ + FN_DECIMAL(0.7649700911), FN_DECIMAL(0.9967722885), FN_DECIMAL(0.05734160033), FN_DECIMAL(-0.1610318741), FN_DECIMAL(0.371395799), FN_DECIMAL(-0.7961420628), FN_DECIMAL(0.6076990492), FN_DECIMAL(-0.9371723195), FN_DECIMAL(0.3324056156), FN_DECIMAL(0.07972205329), FN_DECIMAL(-0.4857529277), FN_DECIMAL(-0.9898503007), FN_DECIMAL(0.9036577593), FN_DECIMAL(0.05162417479), FN_DECIMAL(-0.02545330525), FN_DECIMAL(-0.998045976), + FN_DECIMAL(-0.7021653386), FN_DECIMAL(-0.4524967717), FN_DECIMAL(-0.9939885256), FN_DECIMAL(-0.4875625128), FN_DECIMAL(-0.9657481729), FN_DECIMAL(-0.7432567015), FN_DECIMAL(0.02515761212), FN_DECIMAL(0.4743044842), FN_DECIMAL(0.5771254669), FN_DECIMAL(0.4449408324), FN_DECIMAL(0.3416365773), FN_DECIMAL(0.9970960285), FN_DECIMAL(0.6994034849), FN_DECIMAL(0.4917517499), FN_DECIMAL(0.286765333), FN_DECIMAL(0.8713868327), + FN_DECIMAL(0.6172387009), FN_DECIMAL(0.9941540269), FN_DECIMAL(0.9632339851), FN_DECIMAL(-0.7913613129), FN_DECIMAL(0.847515538), FN_DECIMAL(0.6211056739), FN_DECIMAL(0.5171924952), FN_DECIMAL(-0.8198283277), FN_DECIMAL(-0.1832084353), FN_DECIMAL(0.7054329737), FN_DECIMAL(0.7325597678), FN_DECIMAL(0.9960630973), FN_DECIMAL(0.7419559859), FN_DECIMAL(0.9908355749), FN_DECIMAL(-0.346274329), FN_DECIMAL(0.2192641299), + FN_DECIMAL(-0.9060627411), FN_DECIMAL(-0.8683346653), FN_DECIMAL(0.9949314574), FN_DECIMAL(-0.6445220433), FN_DECIMAL(-0.8103794704), FN_DECIMAL(-0.2216977607), FN_DECIMAL(0.7168515217), FN_DECIMAL(0.612202264), FN_DECIMAL(-0.412428616), FN_DECIMAL(0.285325116), FN_DECIMAL(0.56227115), FN_DECIMAL(-0.9653857009), FN_DECIMAL(-0.6290361962), FN_DECIMAL(0.6491672535), FN_DECIMAL(0.443835306), FN_DECIMAL(-0.1791955706), + FN_DECIMAL(-0.6792690269), FN_DECIMAL(-0.9763662173), FN_DECIMAL(0.7391782104), FN_DECIMAL(0.8343693968), FN_DECIMAL(0.7238337389), FN_DECIMAL(0.4965557504), FN_DECIMAL(0.8075909592), FN_DECIMAL(-0.4459769977), FN_DECIMAL(-0.9331160806), FN_DECIMAL(-0.5710019572), FN_DECIMAL(0.9566512346), FN_DECIMAL(-0.08357920318), FN_DECIMAL(0.2146116448), FN_DECIMAL(-0.6739348049), FN_DECIMAL(0.8810115417), FN_DECIMAL(0.4467718167), + FN_DECIMAL(-0.7196250184), FN_DECIMAL(-0.749462481), FN_DECIMAL(0.9960561112), FN_DECIMAL(0.6600461127), FN_DECIMAL(-0.8465566164), FN_DECIMAL(-0.8525598897), FN_DECIMAL(-0.9732775654), FN_DECIMAL(0.6111293616), FN_DECIMAL(-0.9612584717), FN_DECIMAL(-0.7237870097), FN_DECIMAL(-0.9974830104), FN_DECIMAL(-0.8014006968), FN_DECIMAL(0.9528814544), FN_DECIMAL(-0.6884178931), FN_DECIMAL(-0.1691668301), FN_DECIMAL(0.9843571905), + FN_DECIMAL(0.7651544003), FN_DECIMAL(-0.09355982605), FN_DECIMAL(-0.5200134429), FN_DECIMAL(-0.006202125807), FN_DECIMAL(-0.9997683284), FN_DECIMAL(0.4919944954), FN_DECIMAL(-0.9928084436), FN_DECIMAL(-0.1253880012), FN_DECIMAL(-0.4165383308), FN_DECIMAL(-0.6148930171), FN_DECIMAL(-0.1034332049), FN_DECIMAL(-0.9070022917), FN_DECIMAL(-0.9503958117), FN_DECIMAL(0.9151503065), FN_DECIMAL(-0.6486716073), FN_DECIMAL(0.6397687707), + FN_DECIMAL(-0.9883386937), FN_DECIMAL(0.3507613761), FN_DECIMAL(0.9857642561), FN_DECIMAL(-0.9342026446), FN_DECIMAL(-0.9082419159), FN_DECIMAL(0.1560587169), FN_DECIMAL(0.4921240607), FN_DECIMAL(-0.453669308), FN_DECIMAL(0.6818037859), FN_DECIMAL(0.7976742329), FN_DECIMAL(0.9098610522), FN_DECIMAL(0.651633524), FN_DECIMAL(0.7177318024), FN_DECIMAL(-0.5528685241), FN_DECIMAL(0.5882467118), FN_DECIMAL(0.6593778956), + FN_DECIMAL(0.9371027648), FN_DECIMAL(-0.7168658839), FN_DECIMAL(-0.4757737632), FN_DECIMAL(0.7648291307), FN_DECIMAL(0.7503650398), FN_DECIMAL(0.1705063456), FN_DECIMAL(-0.8071558121), FN_DECIMAL(-0.9951433815), FN_DECIMAL(-0.8253280792), FN_DECIMAL(-0.7982502628), FN_DECIMAL(0.9352738503), FN_DECIMAL(0.8582254747), FN_DECIMAL(-0.3465310238), FN_DECIMAL(0.65000842), FN_DECIMAL(-0.6697422351), FN_DECIMAL(0.7441962291), + FN_DECIMAL(-0.9533555), FN_DECIMAL(0.5801940659), FN_DECIMAL(-0.9992862963), FN_DECIMAL(-0.659820211), FN_DECIMAL(0.2575848092), FN_DECIMAL(0.881588113), FN_DECIMAL(-0.9004043022), FN_DECIMAL(-0.7050172826), FN_DECIMAL(0.369126382), FN_DECIMAL(-0.02265088836), FN_DECIMAL(0.5568217228), FN_DECIMAL(-0.3316515286), FN_DECIMAL(0.991098079), FN_DECIMAL(-0.863212164), FN_DECIMAL(-0.9285531277), FN_DECIMAL(0.1695539323), + FN_DECIMAL(-0.672402505), FN_DECIMAL(-0.001928841934), FN_DECIMAL(0.9767452145), FN_DECIMAL(-0.8767960349), FN_DECIMAL(0.9103515037), FN_DECIMAL(-0.7648324016), FN_DECIMAL(0.2706960452), FN_DECIMAL(-0.9830446035), FN_DECIMAL(0.8150341657), FN_DECIMAL(-0.9999013716), FN_DECIMAL(-0.8985605806), FN_DECIMAL(0.8533360801), FN_DECIMAL(0.8491442537), FN_DECIMAL(-0.2242541966), FN_DECIMAL(-0.1379635899), FN_DECIMAL(-0.4145572694), + FN_DECIMAL(0.1308227633), FN_DECIMAL(0.6140555916), FN_DECIMAL(0.9417041303), FN_DECIMAL(-0.336705587), FN_DECIMAL(-0.6254387508), FN_DECIMAL(0.4631060578), FN_DECIMAL(-0.7578342456), FN_DECIMAL(-0.8172955655), FN_DECIMAL(-0.9959529228), FN_DECIMAL(-0.9760151351), FN_DECIMAL(0.2348380732), FN_DECIMAL(-0.9983612848), FN_DECIMAL(0.5856025746), FN_DECIMAL(-0.9400538266), FN_DECIMAL(-0.7639875669), FN_DECIMAL(0.6244544645), + FN_DECIMAL(0.04604054566), FN_DECIMAL(0.5888424828), FN_DECIMAL(0.7708490978), FN_DECIMAL(-0.8114182882), FN_DECIMAL(0.9786766212), FN_DECIMAL(-0.9984329822), FN_DECIMAL(0.09125496582), FN_DECIMAL(-0.4492438803), FN_DECIMAL(-0.3636982357), FN_DECIMAL(0.9443405575), FN_DECIMAL(-0.9476254645), FN_DECIMAL(-0.6818676535), FN_DECIMAL(-0.6113610831), FN_DECIMAL(0.9754070948), FN_DECIMAL(-0.0938108173), FN_DECIMAL(-0.7029540015), + FN_DECIMAL(-0.6085691109), FN_DECIMAL(-0.08718862881), FN_DECIMAL(-0.237381926), FN_DECIMAL(0.2913423132), FN_DECIMAL(0.9614872426), FN_DECIMAL(0.8836361266), FN_DECIMAL(-0.2749974196), FN_DECIMAL(-0.8108932717), FN_DECIMAL(-0.8913607575), FN_DECIMAL(0.129255541), FN_DECIMAL(-0.3342637104), FN_DECIMAL(-0.1921249337), FN_DECIMAL(-0.7566302845), FN_DECIMAL(-0.9563164339), FN_DECIMAL(-0.9744358146), FN_DECIMAL(0.9836522982), + FN_DECIMAL(-0.2863615732), FN_DECIMAL(0.8337016872), FN_DECIMAL(0.3683701937), FN_DECIMAL(0.7657119102), FN_DECIMAL(-0.02312427772), FN_DECIMAL(0.8875600535), FN_DECIMAL(0.976642191), FN_DECIMAL(0.9374176384), FN_DECIMAL(0.9515313457), FN_DECIMAL(-0.7786361937), FN_DECIMAL(-0.4538302125), FN_DECIMAL(-0.7685604874), FN_DECIMAL(-0.8940796454), FN_DECIMAL(-0.8512462154), FN_DECIMAL(0.5446696133), FN_DECIMAL(0.9207601495), + FN_DECIMAL(-0.9893091197), FN_DECIMAL(-0.9998680229), FN_DECIMAL(0.5617309299), FN_DECIMAL(-0.8277411985), FN_DECIMAL(0.545636467), FN_DECIMAL(0.1690223212), FN_DECIMAL(-0.5079295433), FN_DECIMAL(0.7685069899), FN_DECIMAL(-0.9630140787), FN_DECIMAL(0.9015219132), FN_DECIMAL(0.08905695279), FN_DECIMAL(-0.3423550559), FN_DECIMAL(-0.4661614943), FN_DECIMAL(-0.6449659371), FN_DECIMAL(0.7139388509), FN_DECIMAL(0.7472809229), +}; +const FN_DECIMAL CELL_3D_X[] = +{ + FN_DECIMAL(0.3752498686), FN_DECIMAL(0.687188096), FN_DECIMAL(0.2248135212), FN_DECIMAL(0.6692006647), FN_DECIMAL(-0.4376476931), FN_DECIMAL(0.6139972552), FN_DECIMAL(0.9494563929), FN_DECIMAL(0.8065108882), FN_DECIMAL(-0.2218812853), FN_DECIMAL(0.8484661167), FN_DECIMAL(0.5551817596), FN_DECIMAL(0.2133903499), FN_DECIMAL(0.5195126593), FN_DECIMAL(-0.6440141975), FN_DECIMAL(-0.5192897331), FN_DECIMAL(-0.3697654077), + FN_DECIMAL(-0.07927779647), FN_DECIMAL(0.4187757321), FN_DECIMAL(-0.750078731), FN_DECIMAL(0.6579554632), FN_DECIMAL(-0.6859803838), FN_DECIMAL(-0.6878407087), FN_DECIMAL(0.9490848347), FN_DECIMAL(0.5795829433), FN_DECIMAL(-0.5325976529), FN_DECIMAL(-0.1363699466), FN_DECIMAL(0.417665879), FN_DECIMAL(-0.9108236468), FN_DECIMAL(0.4438605427), FN_DECIMAL(0.819294887), FN_DECIMAL(-0.4033873915), FN_DECIMAL(-0.2817317705), + FN_DECIMAL(0.3969665622), FN_DECIMAL(0.5323450134), FN_DECIMAL(-0.6833017297), FN_DECIMAL(0.3881436661), FN_DECIMAL(-0.7119144767), FN_DECIMAL(-0.2306979838), FN_DECIMAL(-0.9398873022), FN_DECIMAL(0.1701906676), FN_DECIMAL(-0.4261839496), FN_DECIMAL(-0.003712295499), FN_DECIMAL(-0.734675004), FN_DECIMAL(-0.3195046015), FN_DECIMAL(0.7345307424), FN_DECIMAL(0.9766246496), FN_DECIMAL(-0.02003735175), FN_DECIMAL(-0.4824156342), + FN_DECIMAL(0.4245892007), FN_DECIMAL(0.9072427669), FN_DECIMAL(0.593346808), FN_DECIMAL(-0.8911762541), FN_DECIMAL(-0.7657571834), FN_DECIMAL(-0.5268198896), FN_DECIMAL(-0.8801903279), FN_DECIMAL(-0.6296409617), FN_DECIMAL(-0.09492481344), FN_DECIMAL(-0.4920470525), FN_DECIMAL(0.7307666154), FN_DECIMAL(-0.2514540636), FN_DECIMAL(-0.3356210347), FN_DECIMAL(-0.3522787894), FN_DECIMAL(0.87847885), FN_DECIMAL(-0.7424096346), + FN_DECIMAL(0.5757585274), FN_DECIMAL(0.4519299338), FN_DECIMAL(0.6420368628), FN_DECIMAL(-0.1128478447), FN_DECIMAL(0.499874883), FN_DECIMAL(0.5291681739), FN_DECIMAL(-0.5098837195), FN_DECIMAL(0.5639583502), FN_DECIMAL(-0.8456386526), FN_DECIMAL(-0.9657134875), FN_DECIMAL(-0.576437342), FN_DECIMAL(-0.5666013014), FN_DECIMAL(0.5667702405), FN_DECIMAL(-0.481316582), FN_DECIMAL(0.7313389916), FN_DECIMAL(-0.3805628566), + FN_DECIMAL(-0.6512675909), FN_DECIMAL(-0.2787156951), FN_DECIMAL(0.8648059114), FN_DECIMAL(-0.9730216276), FN_DECIMAL(-0.8335820906), FN_DECIMAL(0.2673159641), FN_DECIMAL(0.231150148), FN_DECIMAL(0.01286214638), FN_DECIMAL(0.6774953261), FN_DECIMAL(0.6542885718), FN_DECIMAL(-0.02545450161), FN_DECIMAL(0.2101238586), FN_DECIMAL(-0.5572105885), FN_DECIMAL(0.813705672), FN_DECIMAL(-0.7546026951), FN_DECIMAL(-0.2502500006), + FN_DECIMAL(-0.9979289381), FN_DECIMAL(0.7024037039), FN_DECIMAL(0.08990874624), FN_DECIMAL(0.8170812432), FN_DECIMAL(0.4226980265), FN_DECIMAL(-0.2442153475), FN_DECIMAL(-0.9183326731), FN_DECIMAL(0.6068222411), FN_DECIMAL(0.818676691), FN_DECIMAL(-0.7236735282), FN_DECIMAL(-0.5383903295), FN_DECIMAL(-0.6269337242), FN_DECIMAL(-0.0939331121), FN_DECIMAL(0.9203878539), FN_DECIMAL(-0.7256396824), FN_DECIMAL(0.6292431149), + FN_DECIMAL(0.4234156978), FN_DECIMAL(0.006685688024), FN_DECIMAL(-0.2598694113), FN_DECIMAL(0.6408036421), FN_DECIMAL(0.05899871622), FN_DECIMAL(0.7090281418), FN_DECIMAL(-0.5905222072), FN_DECIMAL(0.3128214264), FN_DECIMAL(-0.691925826), FN_DECIMAL(0.3634019349), FN_DECIMAL(-0.6772511147), FN_DECIMAL(-0.3204583896), FN_DECIMAL(-0.3906740409), FN_DECIMAL(-0.3342190395), FN_DECIMAL(-0.517779592), FN_DECIMAL(-0.6817711267), + FN_DECIMAL(0.6422383105), FN_DECIMAL(0.4388482478), FN_DECIMAL(0.2968562611), FN_DECIMAL(-0.2019778353), FN_DECIMAL(0.6014865048), FN_DECIMAL(0.9519280722), FN_DECIMAL(0.3398889569), FN_DECIMAL(0.8179709354), FN_DECIMAL(0.2365522154), FN_DECIMAL(0.3262175096), FN_DECIMAL(-0.8060715954), FN_DECIMAL(-0.2068642503), FN_DECIMAL(0.6208057279), FN_DECIMAL(-0.5274282502), FN_DECIMAL(-0.3722334928), FN_DECIMAL(-0.8923412971), + FN_DECIMAL(0.5341834201), FN_DECIMAL(-0.3663701513), FN_DECIMAL(-0.6114600319), FN_DECIMAL(0.5026307556), FN_DECIMAL(0.8396151729), FN_DECIMAL(0.9245042467), FN_DECIMAL(-0.7994843957), FN_DECIMAL(-0.5357200589), FN_DECIMAL(-0.6283359739), FN_DECIMAL(-0.61351886), FN_DECIMAL(-0.875632008), FN_DECIMAL(-0.5278879423), FN_DECIMAL(0.9087491985), FN_DECIMAL(-0.03500215466), FN_DECIMAL(-0.261365798), FN_DECIMAL(-0.579523541), + FN_DECIMAL(-0.3765052689), FN_DECIMAL(-0.74398252), FN_DECIMAL(0.4257318052), FN_DECIMAL(-0.1214508921), FN_DECIMAL(0.8561809753), FN_DECIMAL(0.6802835104), FN_DECIMAL(-0.5452131039), FN_DECIMAL(-0.1997156478), FN_DECIMAL(0.4562348357), FN_DECIMAL(-0.811704301), FN_DECIMAL(0.67793962), FN_DECIMAL(-0.9237819106), FN_DECIMAL(0.6973511259), FN_DECIMAL(-0.5189506), FN_DECIMAL(0.5517320032), FN_DECIMAL(-0.396710831), + FN_DECIMAL(0.5493762815), FN_DECIMAL(-0.2507853002), FN_DECIMAL(0.4788634005), FN_DECIMAL(0.387333516), FN_DECIMAL(-0.2176515694), FN_DECIMAL(0.6749832419), FN_DECIMAL(0.2148283022), FN_DECIMAL(-0.7521815872), FN_DECIMAL(0.4697000159), FN_DECIMAL(0.7890593699), FN_DECIMAL(-0.7606162952), FN_DECIMAL(0.01083397843), FN_DECIMAL(0.5254091908), FN_DECIMAL(-0.6748025877), FN_DECIMAL(0.751091524), FN_DECIMAL(0.05259056135), + FN_DECIMAL(0.01889481232), FN_DECIMAL(-0.6037423727), FN_DECIMAL(-0.6542965129), FN_DECIMAL(0.08873301081), FN_DECIMAL(-0.6191345671), FN_DECIMAL(0.4331858488), FN_DECIMAL(-0.3858351946), FN_DECIMAL(-0.1429059747), FN_DECIMAL(0.4118221036), FN_DECIMAL(-0.6247153214), FN_DECIMAL(-0.611423014), FN_DECIMAL(0.5542939606), FN_DECIMAL(-0.9432768808), FN_DECIMAL(-0.4567870451), FN_DECIMAL(-0.7349133547), FN_DECIMAL(0.399304489), + FN_DECIMAL(-0.7474927672), FN_DECIMAL(0.02589419753), FN_DECIMAL(0.783915821), FN_DECIMAL(0.6138668752), FN_DECIMAL(0.4276376047), FN_DECIMAL(-0.4347886353), FN_DECIMAL(0.02947841302), FN_DECIMAL(-0.833742746), FN_DECIMAL(0.3817221742), FN_DECIMAL(-0.8743368359), FN_DECIMAL(-0.3823443796), FN_DECIMAL(-0.6829243811), FN_DECIMAL(-0.3681903049), FN_DECIMAL(-0.367626833), FN_DECIMAL(-0.434583373), FN_DECIMAL(0.235891995), + FN_DECIMAL(-0.6874880269), FN_DECIMAL(-0.5115661773), FN_DECIMAL(-0.5534962601), FN_DECIMAL(0.5632777056), FN_DECIMAL(0.686191532), FN_DECIMAL(-0.05095871588), FN_DECIMAL(-0.06865785057), FN_DECIMAL(-0.5975288531), FN_DECIMAL(-0.6429790056), FN_DECIMAL(-0.3729361548), FN_DECIMAL(0.2237917666), FN_DECIMAL(0.6046773225), FN_DECIMAL(-0.5041542295), FN_DECIMAL(-0.03972191174), FN_DECIMAL(0.7028828406), FN_DECIMAL(-0.5560856498), + FN_DECIMAL(0.5898328456), FN_DECIMAL(-0.9308076766), FN_DECIMAL(0.4617069864), FN_DECIMAL(0.3190983137), FN_DECIMAL(0.9116567753), FN_DECIMAL(-0.45029554), FN_DECIMAL(0.3346334459), FN_DECIMAL(0.8525005645), FN_DECIMAL(0.2528483381), FN_DECIMAL(-0.8306630147), FN_DECIMAL(-0.6880390622), FN_DECIMAL(0.7448684026), FN_DECIMAL(-0.1963355843), FN_DECIMAL(-0.5900257974), FN_DECIMAL(0.9097057294), FN_DECIMAL(-0.2509196808), +}; +const FN_DECIMAL CELL_3D_Y[] = +{ + FN_DECIMAL(-0.6760585049), FN_DECIMAL(-0.09136176499), FN_DECIMAL(0.1681325679), FN_DECIMAL(-0.6688468686), FN_DECIMAL(-0.4822753902), FN_DECIMAL(-0.7891068824), FN_DECIMAL(-0.1877509944), FN_DECIMAL(0.548470914), FN_DECIMAL(-0.463339443), FN_DECIMAL(-0.4050542082), FN_DECIMAL(0.3218158513), FN_DECIMAL(0.2546493823), FN_DECIMAL(-0.3753271935), FN_DECIMAL(0.4745384887), FN_DECIMAL(0.481254652), FN_DECIMAL(-0.8934416489), + FN_DECIMAL(-0.6737085076), FN_DECIMAL(0.7469917228), FN_DECIMAL(0.3826230411), FN_DECIMAL(0.6751013678), FN_DECIMAL(-0.7248119515), FN_DECIMAL(-0.3224276742), FN_DECIMAL(-0.02076190936), FN_DECIMAL(-0.6404268166), FN_DECIMAL(-0.5292028444), FN_DECIMAL(0.7151414636), FN_DECIMAL(-0.6144655059), FN_DECIMAL(-0.369912124), FN_DECIMAL(0.6942067212), FN_DECIMAL(-0.4481558248), FN_DECIMAL(-0.6366894559), FN_DECIMAL(0.5956568471), + FN_DECIMAL(0.564274539), FN_DECIMAL(0.7145584688), FN_DECIMAL(0.6871918316), FN_DECIMAL(0.5657918509), FN_DECIMAL(-0.6275978114), FN_DECIMAL(0.4146983062), FN_DECIMAL(0.2638993789), FN_DECIMAL(-0.792633138), FN_DECIMAL(0.5706133514), FN_DECIMAL(0.8606546462), FN_DECIMAL(0.6490900316), FN_DECIMAL(-0.8242699196), FN_DECIMAL(0.6765819124), FN_DECIMAL(0.1959534069), FN_DECIMAL(-0.8426769757), FN_DECIMAL(-0.5917672797), + FN_DECIMAL(0.7517364266), FN_DECIMAL(0.03252559226), FN_DECIMAL(0.0883617105), FN_DECIMAL(0.4475064813), FN_DECIMAL(-0.1418643552), FN_DECIMAL(0.7343428473), FN_DECIMAL(0.3870192548), FN_DECIMAL(-0.7716703522), FN_DECIMAL(0.4839898327), FN_DECIMAL(0.7437439055), FN_DECIMAL(-0.5989573348), FN_DECIMAL(-0.8357068955), FN_DECIMAL(0.6086049038), FN_DECIMAL(0.9194627258), FN_DECIMAL(0.4718297238), FN_DECIMAL(-0.2650335884), + FN_DECIMAL(-0.6470352599), FN_DECIMAL(-0.5555181303), FN_DECIMAL(0.1222351235), FN_DECIMAL(0.7802044684), FN_DECIMAL(-0.8636947022), FN_DECIMAL(-0.2341352163), FN_DECIMAL(0.683030874), FN_DECIMAL(-0.5005858287), FN_DECIMAL(0.2334616211), FN_DECIMAL(0.2576877608), FN_DECIMAL(0.6666816727), FN_DECIMAL(-0.7663996863), FN_DECIMAL(0.794201982), FN_DECIMAL(0.6189308788), FN_DECIMAL(0.6071033261), FN_DECIMAL(-0.4206058253), + FN_DECIMAL(-0.3957336915), FN_DECIMAL(-0.8170257484), FN_DECIMAL(-0.1043240417), FN_DECIMAL(0.0002167596213), FN_DECIMAL(0.1816339018), FN_DECIMAL(-0.6838094939), FN_DECIMAL(-0.2495341969), FN_DECIMAL(-0.7116756954), FN_DECIMAL(-0.03361673621), FN_DECIMAL(-0.3350836431), FN_DECIMAL(0.2137186039), FN_DECIMAL(0.2557996786), FN_DECIMAL(0.7490117093), FN_DECIMAL(0.4942936549), FN_DECIMAL(-0.352686853), FN_DECIMAL(-0.3952445435), + FN_DECIMAL(-0.0459964767), FN_DECIMAL(-0.7115787471), FN_DECIMAL(0.08022899756), FN_DECIMAL(0.5362268157), FN_DECIMAL(-0.8258613686), FN_DECIMAL(0.1114171723), FN_DECIMAL(0.3882823051), FN_DECIMAL(-0.7915404457), FN_DECIMAL(0.3250957662), FN_DECIMAL(0.6401346464), FN_DECIMAL(-0.2662724517), FN_DECIMAL(-0.6727907114), FN_DECIMAL(-0.994730818), FN_DECIMAL(-0.3596358977), FN_DECIMAL(0.2344610069), FN_DECIMAL(-0.6645215546), + FN_DECIMAL(-0.7107590611), FN_DECIMAL(-0.4646617327), FN_DECIMAL(0.6717191355), FN_DECIMAL(0.5101893498), FN_DECIMAL(0.1185768238), FN_DECIMAL(0.236005093), FN_DECIMAL(-0.7811024061), FN_DECIMAL(0.5089325193), FN_DECIMAL(0.6073187658), FN_DECIMAL(-0.7930732557), FN_DECIMAL(-0.6822767155), FN_DECIMAL(0.3201532885), FN_DECIMAL(0.7545302807), FN_DECIMAL(0.1072664448), FN_DECIMAL(0.6784033173), FN_DECIMAL(-0.6595924967), + FN_DECIMAL(0.7276509498), FN_DECIMAL(0.5586689436), FN_DECIMAL(-0.6498636788), FN_DECIMAL(0.6789333174), FN_DECIMAL(0.7105966551), FN_DECIMAL(-0.2872214155), FN_DECIMAL(0.496746217), FN_DECIMAL(-0.3880337977), FN_DECIMAL(0.7324070604), FN_DECIMAL(-0.9326634749), FN_DECIMAL(-0.5867839255), FN_DECIMAL(0.8003043651), FN_DECIMAL(-0.1631882481), FN_DECIMAL(-0.6796374681), FN_DECIMAL(-0.8066678503), FN_DECIMAL(0.4238177418), + FN_DECIMAL(0.7715863549), FN_DECIMAL(0.5455367347), FN_DECIMAL(-0.03205115397), FN_DECIMAL(-0.6005545066), FN_DECIMAL(-0.5423640002), FN_DECIMAL(0.3569205906), FN_DECIMAL(-0.582071752), FN_DECIMAL(0.6407354361), FN_DECIMAL(0.7777142984), FN_DECIMAL(-0.09956428618), FN_DECIMAL(0.1100002681), FN_DECIMAL(0.8136349123), FN_DECIMAL(0.2923431904), FN_DECIMAL(0.9735794425), FN_DECIMAL(0.8324974864), FN_DECIMAL(-0.6179617717), + FN_DECIMAL(-0.9248386523), FN_DECIMAL(-0.6448780771), FN_DECIMAL(-0.5274402761), FN_DECIMAL(-0.7862170565), FN_DECIMAL(0.2682099744), FN_DECIMAL(-0.5848777694), FN_DECIMAL(-0.6364561467), FN_DECIMAL(-0.7167402514), FN_DECIMAL(-0.8677012494), FN_DECIMAL(0.4205286707), FN_DECIMAL(-0.7007832749), FN_DECIMAL(0.243272451), FN_DECIMAL(-0.1899846085), FN_DECIMAL(-0.6146124977), FN_DECIMAL(-0.8093357692), FN_DECIMAL(-0.03545096987), + FN_DECIMAL(-0.7191590868), FN_DECIMAL(0.7478645848), FN_DECIMAL(0.3623517328), FN_DECIMAL(0.8436992512), FN_DECIMAL(-0.2445711729), FN_DECIMAL(0.6897356637), FN_DECIMAL(-0.1708070787), FN_DECIMAL(0.4639272368), FN_DECIMAL(-0.7917186656), FN_DECIMAL(0.02980025428), FN_DECIMAL(0.6334156172), FN_DECIMAL(-0.9815544807), FN_DECIMAL(-0.2307217304), FN_DECIMAL(0.1080823318), FN_DECIMAL(0.5167601798), FN_DECIMAL(-0.845120016), + FN_DECIMAL(0.441572562), FN_DECIMAL(0.5876789172), FN_DECIMAL(-0.6365908737), FN_DECIMAL(0.68350166), FN_DECIMAL(0.5849723959), FN_DECIMAL(0.1164114357), FN_DECIMAL(-0.7379813884), FN_DECIMAL(-0.9613237178), FN_DECIMAL(-0.9071943084), FN_DECIMAL(-0.7682111105), FN_DECIMAL(0.639074459), FN_DECIMAL(-0.619358298), FN_DECIMAL(0.2807257131), FN_DECIMAL(-0.01800868791), FN_DECIMAL(0.3776607289), FN_DECIMAL(0.7207567823), + FN_DECIMAL(0.5536661486), FN_DECIMAL(-0.9974053117), FN_DECIMAL(-0.02047200006), FN_DECIMAL(-0.6739453804), FN_DECIMAL(-0.5607471297), FN_DECIMAL(0.8815553192), FN_DECIMAL(0.8275977415), FN_DECIMAL(0.3928902456), FN_DECIMAL(0.550991396), FN_DECIMAL(0.4247623676), FN_DECIMAL(-0.3436948871), FN_DECIMAL(-0.3653537677), FN_DECIMAL(0.3181702902), FN_DECIMAL(-0.6067173171), FN_DECIMAL(-0.8984128477), FN_DECIMAL(0.4220839766), + FN_DECIMAL(0.7238407199), FN_DECIMAL(-0.7766913695), FN_DECIMAL(0.6460037842), FN_DECIMAL(0.2544775664), FN_DECIMAL(0.6488840578), FN_DECIMAL(0.805016833), FN_DECIMAL(-0.9183807036), FN_DECIMAL(0.4144046357), FN_DECIMAL(0.270587208), FN_DECIMAL(-0.8813684494), FN_DECIMAL(0.6985971877), FN_DECIMAL(-0.7795603017), FN_DECIMAL(-0.8624480731), FN_DECIMAL(0.5532697017), FN_DECIMAL(0.711179521), FN_DECIMAL(-0.7798160574), + FN_DECIMAL(0.5225859041), FN_DECIMAL(0.1261859368), FN_DECIMAL(0.3398033582), FN_DECIMAL(-0.7472173667), FN_DECIMAL(-0.4032647119), FN_DECIMAL(-0.4246578154), FN_DECIMAL(0.8481212377), FN_DECIMAL(-0.2144838537), FN_DECIMAL(0.3431714491), FN_DECIMAL(0.5310188231), FN_DECIMAL(0.6682978632), FN_DECIMAL(0.3110433206), FN_DECIMAL(0.9263293599), FN_DECIMAL(-0.6155600569), FN_DECIMAL(0.07169784399), FN_DECIMAL(0.8985888773), +}; +const FN_DECIMAL CELL_3D_Z[] = +{ + FN_DECIMAL(-0.6341391283), FN_DECIMAL(-0.7207118346), FN_DECIMAL(0.9597866014), FN_DECIMAL(0.3237504235), FN_DECIMAL(-0.7588642466), FN_DECIMAL(-0.01782410481), FN_DECIMAL(0.2515593809), FN_DECIMAL(0.2207257205), FN_DECIMAL(-0.8579541106), FN_DECIMAL(0.3406410681), FN_DECIMAL(0.7669470462), FN_DECIMAL(-0.9431957648), FN_DECIMAL(0.7676171537), FN_DECIMAL(-0.6000491115), FN_DECIMAL(-0.7062096948), FN_DECIMAL(0.2550207115), + FN_DECIMAL(0.7347325213), FN_DECIMAL(0.5163625202), FN_DECIMAL(-0.5394270162), FN_DECIMAL(0.3336656285), FN_DECIMAL(-0.0638635111), FN_DECIMAL(-0.6503195787), FN_DECIMAL(0.3143356798), FN_DECIMAL(-0.5039217245), FN_DECIMAL(0.6605180464), FN_DECIMAL(-0.6855479011), FN_DECIMAL(-0.6693185756), FN_DECIMAL(0.1832083647), FN_DECIMAL(-0.5666258437), FN_DECIMAL(0.3576482138), FN_DECIMAL(-0.6571949095), FN_DECIMAL(-0.7522101635), + FN_DECIMAL(-0.7238865886), FN_DECIMAL(0.4538887323), FN_DECIMAL(0.2467106257), FN_DECIMAL(0.7274778869), FN_DECIMAL(0.3151170655), FN_DECIMAL(-0.8802293764), FN_DECIMAL(-0.2167232729), FN_DECIMAL(0.5854637865), FN_DECIMAL(0.7019741052), FN_DECIMAL(0.5091756071), FN_DECIMAL(0.1973189533), FN_DECIMAL(0.46743546), FN_DECIMAL(0.05197599597), FN_DECIMAL(0.088354718), FN_DECIMAL(0.5380464843), FN_DECIMAL(-0.6458224544), + FN_DECIMAL(-0.5045952393), FN_DECIMAL(0.419347884), FN_DECIMAL(0.8000823542), FN_DECIMAL(-0.07445020656), FN_DECIMAL(-0.6272881641), FN_DECIMAL(-0.428020311), FN_DECIMAL(-0.2747382083), FN_DECIMAL(-0.08987283726), FN_DECIMAL(0.8699098354), FN_DECIMAL(0.4524761885), FN_DECIMAL(-0.3274603257), FN_DECIMAL(0.4882262167), FN_DECIMAL(-0.7189983256), FN_DECIMAL(0.1746079907), FN_DECIMAL(0.0751772698), FN_DECIMAL(-0.6152927202), + FN_DECIMAL(0.4998474673), FN_DECIMAL(-0.6979677227), FN_DECIMAL(0.7568667263), FN_DECIMAL(-0.6152612058), FN_DECIMAL(0.06447140991), FN_DECIMAL(-0.8155744872), FN_DECIMAL(-0.5229602449), FN_DECIMAL(0.6567836838), FN_DECIMAL(-0.4799905631), FN_DECIMAL(0.03153534591), FN_DECIMAL(0.4724992466), FN_DECIMAL(-0.3026458097), FN_DECIMAL(-0.2191225827), FN_DECIMAL(-0.620692287), FN_DECIMAL(0.3107552588), FN_DECIMAL(0.8235670294), + FN_DECIMAL(0.6474915988), FN_DECIMAL(-0.5047637941), FN_DECIMAL(0.4911488878), FN_DECIMAL(-0.2307138167), FN_DECIMAL(-0.5216800015), FN_DECIMAL(0.6789305939), FN_DECIMAL(0.9403734863), FN_DECIMAL(0.702390397), FN_DECIMAL(0.7347584625), FN_DECIMAL(0.6779567958), FN_DECIMAL(0.9765635805), FN_DECIMAL(-0.9436177661), FN_DECIMAL(-0.358465925), FN_DECIMAL(-0.3058706624), FN_DECIMAL(0.5533414464), FN_DECIMAL(-0.8838306897), + FN_DECIMAL(0.04496841812), FN_DECIMAL(0.01687374963), FN_DECIMAL(-0.9927133148), FN_DECIMAL(-0.211752318), FN_DECIMAL(0.3732015249), FN_DECIMAL(0.9632990593), FN_DECIMAL(-0.07682417004), FN_DECIMAL(-0.07232213047), FN_DECIMAL(0.4733721775), FN_DECIMAL(0.2579229713), FN_DECIMAL(0.7995216286), FN_DECIMAL(0.3928189967), FN_DECIMAL(0.04107517667), FN_DECIMAL(0.1534542912), FN_DECIMAL(0.6468965045), FN_DECIMAL(0.4030684878), + FN_DECIMAL(-0.5617300988), FN_DECIMAL(-0.885463029), FN_DECIMAL(0.693729985), FN_DECIMAL(-0.5736527866), FN_DECIMAL(-0.9911905409), FN_DECIMAL(-0.66451538), FN_DECIMAL(0.2028855685), FN_DECIMAL(0.8019541421), FN_DECIMAL(-0.3903877149), FN_DECIMAL(-0.4888495114), FN_DECIMAL(-0.2753714057), FN_DECIMAL(-0.8915202143), FN_DECIMAL(0.5273119089), FN_DECIMAL(0.9363714773), FN_DECIMAL(-0.5212228249), FN_DECIMAL(-0.31642672), + FN_DECIMAL(0.2409440761), FN_DECIMAL(-0.703776404), FN_DECIMAL(-0.6996810411), FN_DECIMAL(-0.7058714505), FN_DECIMAL(-0.3650566783), FN_DECIMAL(0.1064744278), FN_DECIMAL(0.7985729102), FN_DECIMAL(0.424680257), FN_DECIMAL(-0.6384535592), FN_DECIMAL(0.1540161646), FN_DECIMAL(-0.07702731943), FN_DECIMAL(-0.5627789132), FN_DECIMAL(-0.7667919169), FN_DECIMAL(-0.509815999), FN_DECIMAL(0.4590525092), FN_DECIMAL(0.1552595611), + FN_DECIMAL(0.345402042), FN_DECIMAL(0.7537656024), FN_DECIMAL(0.7906259247), FN_DECIMAL(-0.6218493452), FN_DECIMAL(0.02979350071), FN_DECIMAL(-0.1337893489), FN_DECIMAL(-0.1483818606), FN_DECIMAL(0.549965562), FN_DECIMAL(0.01882482408), FN_DECIMAL(-0.7833783002), FN_DECIMAL(0.4702855809), FN_DECIMAL(0.2435827372), FN_DECIMAL(0.2978428332), FN_DECIMAL(0.2256499906), FN_DECIMAL(0.4885036897), FN_DECIMAL(0.5312962584), + FN_DECIMAL(0.05401156992), FN_DECIMAL(0.1749922158), FN_DECIMAL(-0.7352273018), FN_DECIMAL(0.6058980284), FN_DECIMAL(0.4416079111), FN_DECIMAL(0.4417378638), FN_DECIMAL(0.5455879807), FN_DECIMAL(-0.6681295324), FN_DECIMAL(0.1973431441), FN_DECIMAL(0.4053292055), FN_DECIMAL(0.2220375492), FN_DECIMAL(0.2957118467), FN_DECIMAL(0.6910913512), FN_DECIMAL(0.5940890106), FN_DECIMAL(-0.2014135283), FN_DECIMAL(-0.9172588213), + FN_DECIMAL(-0.4254361401), FN_DECIMAL(-0.6146586825), FN_DECIMAL(-0.7996193253), FN_DECIMAL(-0.3716777111), FN_DECIMAL(-0.9448876842), FN_DECIMAL(-0.2620349924), FN_DECIMAL(0.9615995749), FN_DECIMAL(-0.4679683524), FN_DECIMAL(0.3905937144), FN_DECIMAL(0.613593722), FN_DECIMAL(0.1422937358), FN_DECIMAL(0.1908754211), FN_DECIMAL(0.8189704912), FN_DECIMAL(-0.7300408736), FN_DECIMAL(-0.4108776451), FN_DECIMAL(-0.5319834504), + FN_DECIMAL(-0.8970265651), FN_DECIMAL(-0.5386359045), FN_DECIMAL(0.4082255906), FN_DECIMAL(0.7245356676), FN_DECIMAL(0.5239080873), FN_DECIMAL(-0.8937552226), FN_DECIMAL(-0.553637673), FN_DECIMAL(0.2354455182), FN_DECIMAL(-0.0860293075), FN_DECIMAL(-0.1399373318), FN_DECIMAL(-0.4666323327), FN_DECIMAL(0.5560157407), FN_DECIMAL(0.1772619533), FN_DECIMAL(-0.8893937725), FN_DECIMAL(-0.5632714576), FN_DECIMAL(-0.5666264959), + FN_DECIMAL(-0.3670263736), FN_DECIMAL(-0.06717242579), FN_DECIMAL(0.6205295181), FN_DECIMAL(-0.4110536264), FN_DECIMAL(0.7090054553), FN_DECIMAL(0.183899597), FN_DECIMAL(-0.5605470555), FN_DECIMAL(0.3879565548), FN_DECIMAL(0.7420893903), FN_DECIMAL(-0.2347595118), FN_DECIMAL(-0.8577217497), FN_DECIMAL(0.6325590203), FN_DECIMAL(-0.8736152276), FN_DECIMAL(0.7048011129), FN_DECIMAL(-0.06317948268), FN_DECIMAL(0.8753285574), + FN_DECIMAL(-0.05843650473), FN_DECIMAL(-0.3674922622), FN_DECIMAL(-0.5256624401), FN_DECIMAL(0.7861039337), FN_DECIMAL(0.3287714416), FN_DECIMAL(0.5910593099), FN_DECIMAL(-0.3896960134), FN_DECIMAL(0.6864605361), FN_DECIMAL(0.7164918431), FN_DECIMAL(-0.290014277), FN_DECIMAL(-0.6796169617), FN_DECIMAL(0.1632515592), FN_DECIMAL(0.04485347486), FN_DECIMAL(0.8320545697), FN_DECIMAL(0.01339408056), FN_DECIMAL(-0.2874989857), + FN_DECIMAL(0.615630723), FN_DECIMAL(0.3430367014), FN_DECIMAL(0.8193658136), FN_DECIMAL(-0.5829600957), FN_DECIMAL(0.07911697781), FN_DECIMAL(0.7854296063), FN_DECIMAL(-0.4107442306), FN_DECIMAL(0.4766964066), FN_DECIMAL(-0.9045999527), FN_DECIMAL(-0.1673856787), FN_DECIMAL(0.2828077348), FN_DECIMAL(-0.5902737632), FN_DECIMAL(-0.321506229), FN_DECIMAL(-0.5224513133), FN_DECIMAL(-0.4090169985), FN_DECIMAL(-0.3599685311), +}; + +static int FastFloor(FN_DECIMAL f) { return (f >= 0 ? (int)f : (int)f - 1); } +static int FastRound(FN_DECIMAL f) { return (f >= 0) ? (int)(f + FN_DECIMAL(0.5)) : (int)(f - FN_DECIMAL(0.5)); } +static int FastAbs(int i) { return abs(i); } +static FN_DECIMAL FastAbs(FN_DECIMAL f) { return fabs(f); } +static FN_DECIMAL Lerp(FN_DECIMAL a, FN_DECIMAL b, FN_DECIMAL t) { return a + t * (b - a); } +static FN_DECIMAL InterpHermiteFunc(FN_DECIMAL t) { return t*t*(3 - 2 * t); } +static FN_DECIMAL InterpQuinticFunc(FN_DECIMAL t) { return t*t*t*(t*(t * 6 - 15) + 10); } +static FN_DECIMAL CubicLerp(FN_DECIMAL a, FN_DECIMAL b, FN_DECIMAL c, FN_DECIMAL d, FN_DECIMAL t) +{ + FN_DECIMAL p = (d - c) - (a - b); + return t * t * t * p + t * t * ((a - b) - p) + t * (c - a) + b; +} + +void FastNoise::SetSeed(int seed) +{ + m_seed = seed; + + std::mt19937_64 gen(seed); + + for (int i = 0; i < 256; i++) + m_perm[i] = i; + + for (int j = 0; j < 256; j++) + { + int rng = (int)(gen() % (256 - j)); + int k = rng + 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; + } +} + +void FastNoise::CalculateFractalBounding() +{ + FN_DECIMAL amp = m_gain; + FN_DECIMAL ampFractal = 1.0f; + for (int i = 1; i < m_octaves; i++) + { + ampFractal += amp; + amp *= m_gain; + } + m_fractalBounding = 1.0f / ampFractal; +} + +void FastNoise::SetCellularDistance2Indices(int cellularDistanceIndex0, int cellularDistanceIndex1) +{ + m_cellularDistanceIndex0 = std::min(cellularDistanceIndex0, cellularDistanceIndex1); + m_cellularDistanceIndex1 = std::max(cellularDistanceIndex0, cellularDistanceIndex1); + + m_cellularDistanceIndex0 = std::min(std::max(m_cellularDistanceIndex0, 0), FN_CELLULAR_INDEX_MAX); + m_cellularDistanceIndex1 = std::min(std::max(m_cellularDistanceIndex1, 0), FN_CELLULAR_INDEX_MAX); +} + +void FastNoise::GetCellularDistance2Indices(int& cellularDistanceIndex0, int& cellularDistanceIndex1) const +{ + cellularDistanceIndex0 = m_cellularDistanceIndex0; + cellularDistanceIndex1 = m_cellularDistanceIndex1; +} + +unsigned char FastNoise::Index2D_12(unsigned char offset, int x, int y) const +{ + return m_perm12[(x & 0xff) + m_perm[(y & 0xff) + offset]]; +} +unsigned char FastNoise::Index3D_12(unsigned char offset, int x, int y, int z) const +{ + return m_perm12[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + offset]]]; +} +unsigned char FastNoise::Index4D_32(unsigned char offset, int x, int y, int z, int w) const +{ + return m_perm[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + m_perm[(w & 0xff) + offset]]]] & 31; +} +unsigned char FastNoise::Index2D_256(unsigned char offset, int x, int y) const +{ + return m_perm[(x & 0xff) + m_perm[(y & 0xff) + offset]]; +} +unsigned char FastNoise::Index3D_256(unsigned char offset, int x, int y, int z) const +{ + return m_perm[(x & 0xff) + m_perm[(y & 0xff) + m_perm[(z & 0xff) + offset]]]; +} +unsigned char FastNoise::Index4D_256(unsigned char offset, int x, int y, int z, int w) const +{ + 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 FN_DECIMAL ValCoord2D(int seed, int x, int y) +{ + int n = seed; + n ^= X_PRIME * x; + n ^= Y_PRIME * y; + + return (n * n * n * 60493) / FN_DECIMAL(2147483648); +} +static FN_DECIMAL ValCoord3D(int seed, int x, int y, int z) +{ + int n = seed; + n ^= X_PRIME * x; + n ^= Y_PRIME * y; + n ^= Z_PRIME * z; + + return (n * n * n * 60493) / FN_DECIMAL(2147483648); +} +static FN_DECIMAL ValCoord4D(int seed, int x, int y, int z, int w) +{ + int n = seed; + n ^= X_PRIME * x; + n ^= Y_PRIME * y; + n ^= Z_PRIME * z; + n ^= W_PRIME * w; + + return (n * n * n * 60493) / FN_DECIMAL(2147483648); +} + +FN_DECIMAL FastNoise::ValCoord2DFast(unsigned char offset, int x, int y) const +{ + return VAL_LUT[Index2D_256(offset, x, y)]; +} +FN_DECIMAL FastNoise::ValCoord3DFast(unsigned char offset, int x, int y, int z) const +{ + return VAL_LUT[Index3D_256(offset, x, y, z)]; +} + +FN_DECIMAL FastNoise::GradCoord2D(unsigned char offset, int x, int y, FN_DECIMAL xd, FN_DECIMAL yd) const +{ + unsigned char lutPos = Index2D_12(offset, x, y); + + return xd*GRAD_X[lutPos] + yd*GRAD_Y[lutPos]; +} +FN_DECIMAL FastNoise::GradCoord3D(unsigned char offset, int x, int y, int z, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd) const +{ + unsigned char lutPos = Index3D_12(offset, x, y, z); + + return xd*GRAD_X[lutPos] + yd*GRAD_Y[lutPos] + zd*GRAD_Z[lutPos]; +} +FN_DECIMAL FastNoise::GradCoord4D(unsigned char offset, int x, int y, int z, int w, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd, FN_DECIMAL wd) const +{ + unsigned char lutPos = Index4D_32(offset, x, y, z, w) << 2; + + return xd*GRAD_4D[lutPos] + yd*GRAD_4D[lutPos + 1] + zd*GRAD_4D[lutPos + 2] + wd*GRAD_4D[lutPos + 3]; +} + +FN_DECIMAL FastNoise::GetNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + // for now, simplex is only useful 4d fractal noise, so just use that + + switch (m_noiseType) + { + case Simplex: + return SingleSimplex(0, x, y, z, w); + case SimplexFractal: + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y, z, w); + case Billow: + return SingleSimplexFractalBillow(x, y, z, w); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y, z, w); + default: + return 0; + } + default: + return 0; + } +} + +FN_DECIMAL FastNoise::GetNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_noiseType) + { + case Value: + return SingleValue(0, x, y, z); + case ValueFractal: + switch (m_fractalType) + { + case FBM: + return SingleValueFractalFBM(x, y, z); + case Billow: + return SingleValueFractalBillow(x, y, z); + case RigidMulti: + return SingleValueFractalRigidMulti(x, y, z); + default: + return 0; + } + case Perlin: + return SinglePerlin(0, x, y, z); + case PerlinFractal: + switch (m_fractalType) + { + case FBM: + return SinglePerlinFractalFBM(x, y, z); + case Billow: + return SinglePerlinFractalBillow(x, y, z); + case RigidMulti: + return SinglePerlinFractalRigidMulti(x, y, z); + default: + return 0; + } + case Simplex: + return SingleSimplex(0, x, y, z); + case SimplexFractal: + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y, z); + case Billow: + return SingleSimplexFractalBillow(x, y, z); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y, z); + default: + return 0; + } + case Cellular: + switch (m_cellularReturnType) + { + case CellValue: + case NoiseLookup: + case Distance: + return SingleCellular(x, y, z); + default: + return SingleCellular2Edge(x, y, z); + } + case WhiteNoise: + return GetWhiteNoise(x, y, z); + case Cubic: + return SingleCubic(0, x, y, z); + case CubicFractal: + switch (m_fractalType) + { + case FBM: + return SingleCubicFractalFBM(x, y, z); + case Billow: + return SingleCubicFractalBillow(x, y, z); + case RigidMulti: + return SingleCubicFractalRigidMulti(x, y, z); + } + default: + return 0; + } +} + +FN_DECIMAL FastNoise::GetNoise(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_noiseType) + { + case Value: + return SingleValue(0, x, y); + case ValueFractal: + switch (m_fractalType) + { + case FBM: + return SingleValueFractalFBM(x, y); + case Billow: + return SingleValueFractalBillow(x, y); + case RigidMulti: + return SingleValueFractalRigidMulti(x, y); + } + case Perlin: + return SinglePerlin(0, x, y); + case PerlinFractal: + switch (m_fractalType) + { + case FBM: + return SinglePerlinFractalFBM(x, y); + case Billow: + return SinglePerlinFractalBillow(x, y); + case RigidMulti: + return SinglePerlinFractalRigidMulti(x, y); + } + case Simplex: + return SingleSimplex(0, x, y); + case SimplexFractal: + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y); + case Billow: + return SingleSimplexFractalBillow(x, y); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y); + } + case Cellular: + switch (m_cellularReturnType) + { + case CellValue: + case NoiseLookup: + case Distance: + return SingleCellular(x, y); + default: + return SingleCellular2Edge(x, y); + } + case WhiteNoise: + return GetWhiteNoise(x, y); + case Cubic: + return SingleCubic(0, x, y); + case CubicFractal: + switch (m_fractalType) + { + case FBM: + return SingleCubicFractalFBM(x, y); + case Billow: + return SingleCubicFractalBillow(x, y); + case RigidMulti: + return SingleCubicFractalRigidMulti(x, y); + } + } + return 0; +} + +// White Noise +FN_DECIMAL FastNoise::GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + return 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)); +} + +FN_DECIMAL FastNoise::GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + return ValCoord3D(m_seed, + *reinterpret_cast(&x) ^ (*reinterpret_cast(&x) >> 16), + *reinterpret_cast(&y) ^ (*reinterpret_cast(&y) >> 16), + *reinterpret_cast(&z) ^ (*reinterpret_cast(&z) >> 16)); +} + +FN_DECIMAL FastNoise::GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y) const +{ + return ValCoord2D(m_seed, + *reinterpret_cast(&x) ^ (*reinterpret_cast(&x) >> 16), + *reinterpret_cast(&y) ^ (*reinterpret_cast(&y) >> 16)); +} + +FN_DECIMAL FastNoise::GetWhiteNoiseInt(int x, int y, int z, int w) const +{ + return ValCoord4D(m_seed, x, y, z, w); +} + +FN_DECIMAL FastNoise::GetWhiteNoiseInt(int x, int y, int z) const +{ + return ValCoord3D(m_seed, x, y, z); +} + +FN_DECIMAL FastNoise::GetWhiteNoiseInt(int x, int y) const +{ + return ValCoord2D(m_seed, x, y); +} + +// Value Noise +FN_DECIMAL FastNoise::GetValueFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleValueFractalFBM(x, y, z); + case Billow: + return SingleValueFractalBillow(x, y, z); + case RigidMulti: + return SingleValueFractalRigidMulti(x, y, z); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = SingleValue(m_perm[0], x, y, z); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += SingleValue(m_perm[i], x, y, z) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = FastAbs(SingleValue(m_perm[0], x, y, z)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleValue(m_perm[i], x, y, z)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleValue(m_perm[0], x, y, z)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleValue(m_perm[i], x, y, z))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetValue(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + return SingleValue(0, x * m_frequency, y * m_frequency, z * m_frequency); +} + +FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + int x0 = FastFloor(x); + int y0 = FastFloor(y); + int z0 = FastFloor(z); + int x1 = x0 + 1; + int y1 = y0 + 1; + int z1 = z0 + 1; + + FN_DECIMAL xs, ys, zs; + switch (m_interp) + { + case Linear: + xs = x - (FN_DECIMAL)x0; + ys = y - (FN_DECIMAL)y0; + zs = z - (FN_DECIMAL)z0; + break; + case Hermite: + xs = InterpHermiteFunc(x - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(y - (FN_DECIMAL)y0); + zs = InterpHermiteFunc(z - (FN_DECIMAL)z0); + break; + case Quintic: + xs = InterpQuinticFunc(x - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(y - (FN_DECIMAL)y0); + zs = InterpQuinticFunc(z - (FN_DECIMAL)z0); + break; + } + + FN_DECIMAL xf00 = Lerp(ValCoord3DFast(offset, x0, y0, z0), ValCoord3DFast(offset, x1, y0, z0), xs); + FN_DECIMAL xf10 = Lerp(ValCoord3DFast(offset, x0, y1, z0), ValCoord3DFast(offset, x1, y1, z0), xs); + FN_DECIMAL xf01 = Lerp(ValCoord3DFast(offset, x0, y0, z1), ValCoord3DFast(offset, x1, y0, z1), xs); + FN_DECIMAL xf11 = Lerp(ValCoord3DFast(offset, x0, y1, z1), ValCoord3DFast(offset, x1, y1, z1), xs); + + FN_DECIMAL yf0 = Lerp(xf00, xf10, ys); + FN_DECIMAL yf1 = Lerp(xf01, xf11, ys); + + return Lerp(yf0, yf1, zs); +} + +FN_DECIMAL FastNoise::GetValueFractal(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleValueFractalFBM(x, y); + case Billow: + return SingleValueFractalBillow(x, y); + case RigidMulti: + return SingleValueFractalRigidMulti(x, y); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = SingleValue(m_perm[0], x, y); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += SingleValue(m_perm[i], x, y) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = FastAbs(SingleValue(m_perm[0], x, y)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + amp *= m_gain; + sum += (FastAbs(SingleValue(m_perm[i], x, y)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleValue(m_perm[0], x, y)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleValue(m_perm[i], x, y))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetValue(FN_DECIMAL x, FN_DECIMAL y) const +{ + return SingleValue(0, x * m_frequency, y * m_frequency); +} + +FN_DECIMAL FastNoise::SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const +{ + int x0 = FastFloor(x); + int y0 = FastFloor(y); + int x1 = x0 + 1; + int y1 = y0 + 1; + + FN_DECIMAL xs, ys; + switch (m_interp) + { + case Linear: + xs = x - (FN_DECIMAL)x0; + ys = y - (FN_DECIMAL)y0; + break; + case Hermite: + xs = InterpHermiteFunc(x - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(y - (FN_DECIMAL)y0); + break; + case Quintic: + xs = InterpQuinticFunc(x - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(y - (FN_DECIMAL)y0); + break; + } + + FN_DECIMAL xf0 = Lerp(ValCoord2DFast(offset, x0, y0), ValCoord2DFast(offset, x1, y0), xs); + FN_DECIMAL xf1 = Lerp(ValCoord2DFast(offset, x0, y1), ValCoord2DFast(offset, x1, y1), xs); + + return Lerp(xf0, xf1, ys); +} + +// Perlin Noise +FN_DECIMAL FastNoise::GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SinglePerlinFractalFBM(x, y, z); + case Billow: + return SinglePerlinFractalBillow(x, y, z); + case RigidMulti: + return SinglePerlinFractalRigidMulti(x, y, z); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = SinglePerlin(m_perm[0], x, y, z); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += SinglePerlin(m_perm[i], x, y, z) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = FastAbs(SinglePerlin(m_perm[0], x, y, z)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SinglePerlin(m_perm[i], x, y, z)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = 1 - FastAbs(SinglePerlin(m_perm[0], x, y, z)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SinglePerlin(m_perm[i], x, y, z))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetPerlin(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + return SinglePerlin(0, x * m_frequency, y * m_frequency, z * m_frequency); +} + +FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + int x0 = FastFloor(x); + int y0 = FastFloor(y); + int z0 = FastFloor(z); + int x1 = x0 + 1; + int y1 = y0 + 1; + int z1 = z0 + 1; + + FN_DECIMAL xs, ys, zs; + switch (m_interp) + { + case Linear: + xs = x - (FN_DECIMAL)x0; + ys = y - (FN_DECIMAL)y0; + zs = z - (FN_DECIMAL)z0; + break; + case Hermite: + xs = InterpHermiteFunc(x - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(y - (FN_DECIMAL)y0); + zs = InterpHermiteFunc(z - (FN_DECIMAL)z0); + break; + case Quintic: + xs = InterpQuinticFunc(x - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(y - (FN_DECIMAL)y0); + zs = InterpQuinticFunc(z - (FN_DECIMAL)z0); + break; + } + + FN_DECIMAL xd0 = x - (FN_DECIMAL)x0; + FN_DECIMAL yd0 = y - (FN_DECIMAL)y0; + FN_DECIMAL zd0 = z - (FN_DECIMAL)z0; + FN_DECIMAL xd1 = xd0 - 1; + FN_DECIMAL yd1 = yd0 - 1; + FN_DECIMAL zd1 = zd0 - 1; + + FN_DECIMAL xf00 = Lerp(GradCoord3D(offset, x0, y0, z0, xd0, yd0, zd0), GradCoord3D(offset, x1, y0, z0, xd1, yd0, zd0), xs); + FN_DECIMAL xf10 = Lerp(GradCoord3D(offset, x0, y1, z0, xd0, yd1, zd0), GradCoord3D(offset, x1, y1, z0, xd1, yd1, zd0), xs); + FN_DECIMAL xf01 = Lerp(GradCoord3D(offset, x0, y0, z1, xd0, yd0, zd1), GradCoord3D(offset, x1, y0, z1, xd1, yd0, zd1), xs); + FN_DECIMAL xf11 = Lerp(GradCoord3D(offset, x0, y1, z1, xd0, yd1, zd1), GradCoord3D(offset, x1, y1, z1, xd1, yd1, zd1), xs); + + FN_DECIMAL yf0 = Lerp(xf00, xf10, ys); + FN_DECIMAL yf1 = Lerp(xf01, xf11, ys); + + return Lerp(yf0, yf1, zs); +} + +FN_DECIMAL FastNoise::GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SinglePerlinFractalFBM(x, y); + case Billow: + return SinglePerlinFractalBillow(x, y); + case RigidMulti: + return SinglePerlinFractalRigidMulti(x, y); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = SinglePerlin(m_perm[0], x, y); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += SinglePerlin(m_perm[i], x, y) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = FastAbs(SinglePerlin(m_perm[0], x, y)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SinglePerlin(m_perm[i], x, y)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = 1 - FastAbs(SinglePerlin(m_perm[0], x, y)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SinglePerlin(m_perm[i], x, y))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetPerlin(FN_DECIMAL x, FN_DECIMAL y) const +{ + return SinglePerlin(0, x * m_frequency, y * m_frequency); +} + +FN_DECIMAL FastNoise::SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const +{ + int x0 = FastFloor(x); + int y0 = FastFloor(y); + int x1 = x0 + 1; + int y1 = y0 + 1; + + FN_DECIMAL xs, ys; + switch (m_interp) + { + case Linear: + xs = x - (FN_DECIMAL)x0; + ys = y - (FN_DECIMAL)y0; + break; + case Hermite: + xs = InterpHermiteFunc(x - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(y - (FN_DECIMAL)y0); + break; + case Quintic: + xs = InterpQuinticFunc(x - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(y - (FN_DECIMAL)y0); + break; + } + + FN_DECIMAL xd0 = x - (FN_DECIMAL)x0; + FN_DECIMAL yd0 = y - (FN_DECIMAL)y0; + FN_DECIMAL xd1 = xd0 - 1; + FN_DECIMAL yd1 = yd0 - 1; + + FN_DECIMAL xf0 = Lerp(GradCoord2D(offset, x0, y0, xd0, yd0), GradCoord2D(offset, x1, y0, xd1, yd0), xs); + FN_DECIMAL xf1 = Lerp(GradCoord2D(offset, x0, y1, xd0, yd1), GradCoord2D(offset, x1, y1, xd1, yd1), xs); + + return Lerp(xf0, xf1, ys); +} + +// Simplex Noise + +FN_DECIMAL FastNoise::GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + w *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y, z, w); + case Billow: + return SingleSimplexFractalBillow(x, y, z, w); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y, z, w); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y, z); + case Billow: + return SingleSimplexFractalBillow(x, y, z); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y, z); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + FN_DECIMAL sum = SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency, w * m_frequency); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + w *= m_lacunarity; + + amp *= m_gain; + sum += SingleSimplex(m_perm[i], x, y, z, w) * amp; + } + + return sum * m_fractalBounding; +} + + +FN_DECIMAL FastNoise::SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + FN_DECIMAL sum = FastAbs(SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency, w * m_frequency)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + w *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleSimplex(m_perm[i], x, y, z, w)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleSimplex(0, x, y, z, w)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + w *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleSimplex(m_perm[i], x, y, z, w))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = SingleSimplex(m_perm[0], x, y, z); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += SingleSimplex(m_perm[i], x, y, z) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = FastAbs(SingleSimplex(m_perm[0], x, y, z)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleSimplex(m_perm[i], x, y, z)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleSimplex(m_perm[0], x, y, z)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleSimplex(m_perm[i], x, y, z))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + return SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency); +} + +static const FN_DECIMAL F3 = 1 / FN_DECIMAL(3); +static const FN_DECIMAL G3 = 1 / FN_DECIMAL(6); + +FN_DECIMAL FastNoise::SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL 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; + FN_DECIMAL X0 = i - t; + FN_DECIMAL Y0 = j - t; + FN_DECIMAL Z0 = k - t; + + FN_DECIMAL x0 = x - X0; + FN_DECIMAL y0 = y - Y0; + FN_DECIMAL 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; + } + } + + FN_DECIMAL x1 = x0 - i1 + G3; + FN_DECIMAL y1 = y0 - j1 + G3; + FN_DECIMAL z1 = z0 - k1 + G3; + FN_DECIMAL x2 = x0 - i2 + 2*G3; + FN_DECIMAL y2 = y0 - j2 + 2*G3; + FN_DECIMAL z2 = z0 - k2 + 2*G3; + FN_DECIMAL x3 = x0 - 1 + 3*G3; + FN_DECIMAL y3 = y0 - 1 + 3*G3; + FN_DECIMAL z3 = z0 - 1 + 3*G3; + + FN_DECIMAL n0, n1, n2, n3; + + t = FN_DECIMAL(0.6) - x0*x0 - y0*y0 - z0*z0; + if (t < 0) n0 = 0; + else + { + t *= t; + n0 = t*t*GradCoord3D(offset, i, j, k, x0, y0, z0); + } + + t = FN_DECIMAL(0.6) - x1*x1 - y1*y1 - z1*z1; + if (t < 0) n1 = 0; + else + { + t *= t; + n1 = t*t*GradCoord3D(offset, i + i1, j + j1, k + k1, x1, y1, z1); + } + + t = FN_DECIMAL(0.6) - x2*x2 - y2*y2 - z2*z2; + if (t < 0) n2 = 0; + else + { + t *= t; + n2 = t*t*GradCoord3D(offset, i + i2, j + j2, k + k2, x2, y2, z2); + } + + t = FN_DECIMAL(0.6) - x3*x3 - y3*y3 - z3*z3; + if (t < 0) n3 = 0; + else + { + t *= t; + n3 = t*t*GradCoord3D(offset, i + 1, j + 1, k + 1, x3, y3, z3); + } + + return 32 * (n0 + n1 + n2 + n3); +} + +FN_DECIMAL FastNoise::GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleSimplexFractalFBM(x, y); + case Billow: + return SingleSimplexFractalBillow(x, y); + case RigidMulti: + return SingleSimplexFractalRigidMulti(x, y); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = SingleSimplex(m_perm[0], x, y); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += SingleSimplex(m_perm[i], x, y) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = FastAbs(SingleSimplex(m_perm[0], x, y)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleSimplex(m_perm[i], x, y)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleSimplex(m_perm[0], x, y)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleSimplex(m_perm[i], x, y))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::SingleSimplexFractalBlend(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = SingleSimplex(m_perm[0], x, y); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum *= SingleSimplex(m_perm[i], x, y) * amp + 1; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::GetSimplex(FN_DECIMAL x, FN_DECIMAL y) const +{ + return SingleSimplex(0, x * m_frequency, y * m_frequency); +} + +//static const FN_DECIMAL F2 = 1 / FN_DECIMAL(2); +//static const FN_DECIMAL G2 = 1 / FN_DECIMAL(4); + +static const FN_DECIMAL SQRT3 = FN_DECIMAL(1.7320508075688772935274463415059); +static const FN_DECIMAL F2 = FN_DECIMAL(0.5) * (SQRT3 - FN_DECIMAL(1.0)); +static const FN_DECIMAL G2 = (FN_DECIMAL(3.0) - SQRT3) / FN_DECIMAL(6.0); + +FN_DECIMAL FastNoise::SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL t = (x + y) * F2; + int i = FastFloor(x + t); + int j = FastFloor(y + t); + + t = (i + j) * G2; + FN_DECIMAL X0 = i - t; + FN_DECIMAL Y0 = j - t; + + FN_DECIMAL x0 = x - X0; + FN_DECIMAL y0 = y - Y0; + + int i1, j1; + if (x0 > y0) + { + i1 = 1; j1 = 0; + } + else + { + i1 = 0; j1 = 1; + } + + FN_DECIMAL x1 = x0 - (FN_DECIMAL)i1 + G2; + FN_DECIMAL y1 = y0 - (FN_DECIMAL)j1 + G2; + FN_DECIMAL x2 = x0 - 1 + 2*G2; + FN_DECIMAL y2 = y0 - 1 + 2*G2; + + FN_DECIMAL n0, n1, n2; + + t = FN_DECIMAL(0.5) - x0*x0 - y0*y0; + if (t < 0) n0 = 0; + else + { + t *= t; + n0 = t * t * GradCoord2D(offset, i, j, x0, y0); + } + + t = FN_DECIMAL(0.5) - x1*x1 - y1*y1; + if (t < 0) n1 = 0; + else + { + t *= t; + n1 = t*t*GradCoord2D(offset, i + i1, j + j1, x1, y1); + } + + t = FN_DECIMAL(0.5) - x2*x2 - y2*y2; + if (t < 0) n2 = 0; + else + { + t *= t; + n2 = t*t*GradCoord2D(offset, i + 1, j + 1, x2, y2); + } + + return 70 * (n0 + n1 + n2); +} + +FN_DECIMAL FastNoise::GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + return SingleSimplex(0, x * m_frequency, y * m_frequency, z * m_frequency, w * m_frequency); +} + +static const FN_DECIMAL F4 = (sqrt(FN_DECIMAL(5)) - 1) / 4; +static const FN_DECIMAL G4 = (5 - sqrt(FN_DECIMAL(5))) / 20; + +FN_DECIMAL FastNoise::SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const +{ + FN_DECIMAL n0, n1, n2, n3, n4; + FN_DECIMAL 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; + FN_DECIMAL X0 = i - t; + FN_DECIMAL Y0 = j - t; + FN_DECIMAL Z0 = k - t; + FN_DECIMAL W0 = l - t; + FN_DECIMAL x0 = x - X0; + FN_DECIMAL y0 = y - Y0; + FN_DECIMAL z0 = z - Z0; + FN_DECIMAL w0 = w - W0; + + int rankx = 0; + int ranky = 0; + int rankz = 0; + int rankw = 0; + + if (x0 > y0) rankx++; else ranky++; + if (x0 > z0) rankx++; else rankz++; + if (x0 > w0) rankx++; else rankw++; + if (y0 > z0) ranky++; else rankz++; + if (y0 > w0) ranky++; else rankw++; + if (z0 > w0) rankz++; else rankw++; + + int i1 = rankx >= 3 ? 1 : 0; + int j1 = ranky >= 3 ? 1 : 0; + int k1 = rankz >= 3 ? 1 : 0; + int l1 = rankw >= 3 ? 1 : 0; + + int i2 = rankx >= 2 ? 1 : 0; + int j2 = ranky >= 2 ? 1 : 0; + int k2 = rankz >= 2 ? 1 : 0; + int l2 = rankw >= 2 ? 1 : 0; + + int i3 = rankx >= 1 ? 1 : 0; + int j3 = ranky >= 1 ? 1 : 0; + int k3 = rankz >= 1 ? 1 : 0; + int l3 = rankw >= 1 ? 1 : 0; + + FN_DECIMAL x1 = x0 - i1 + G4; + FN_DECIMAL y1 = y0 - j1 + G4; + FN_DECIMAL z1 = z0 - k1 + G4; + FN_DECIMAL w1 = w0 - l1 + G4; + FN_DECIMAL x2 = x0 - i2 + 2*G4; + FN_DECIMAL y2 = y0 - j2 + 2*G4; + FN_DECIMAL z2 = z0 - k2 + 2*G4; + FN_DECIMAL w2 = w0 - l2 + 2*G4; + FN_DECIMAL x3 = x0 - i3 + 3*G4; + FN_DECIMAL y3 = y0 - j3 + 3*G4; + FN_DECIMAL z3 = z0 - k3 + 3*G4; + FN_DECIMAL w3 = w0 - l3 + 3*G4; + FN_DECIMAL x4 = x0 - 1 + 4*G4; + FN_DECIMAL y4 = y0 - 1 + 4*G4; + FN_DECIMAL z4 = z0 - 1 + 4*G4; + FN_DECIMAL w4 = w0 - 1 + 4*G4; + + t = FN_DECIMAL(0.6) - x0*x0 - y0*y0 - z0*z0 - w0*w0; + if (t < 0) n0 = 0; + else { + t *= t; + n0 = t * t * GradCoord4D(offset, i, j, k, l, x0, y0, z0, w0); + } + t = FN_DECIMAL(0.6) - x1*x1 - y1*y1 - z1*z1 - w1*w1; + if (t < 0) n1 = 0; + else { + t *= t; + n1 = t * t * GradCoord4D(offset, i + i1, j + j1, k + k1, l + l1, x1, y1, z1, w1); + } + t = FN_DECIMAL(0.6) - x2*x2 - y2*y2 - z2*z2 - w2*w2; + if (t < 0) n2 = 0; + else { + t *= t; + n2 = t * t * GradCoord4D(offset, i + i2, j + j2, k + k2, l + l2, x2, y2, z2, w2); + } + t = FN_DECIMAL(0.6) - x3*x3 - y3*y3 - z3*z3 - w3*w3; + if (t < 0) n3 = 0; + else { + t *= t; + n3 = t * t * GradCoord4D(offset, i + i3, j + j3, k + k3, l + l3, x3, y3, z3, w3); + } + t = FN_DECIMAL(0.6) - x4*x4 - y4*y4 - z4*z4 - w4*w4; + if (t < 0) n4 = 0; + else { + t *= t; + n4 = t * t * GradCoord4D(offset, i + 1, j + 1, k + 1, l + 1, x4, y4, z4, w4); + } + + return 27 * (n0 + n1 + n2 + n3 + n4); +} + +// Cubic Noise +FN_DECIMAL FastNoise::GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleCubicFractalFBM(x, y, z); + case Billow: + return SingleCubicFractalBillow(x, y, z); + case RigidMulti: + return SingleCubicFractalRigidMulti(x, y, z); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = SingleCubic(m_perm[0], x, y, z); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += SingleCubic(m_perm[i], x, y, z) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = FastAbs(SingleCubic(m_perm[0], x, y, z)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleCubic(m_perm[i], x, y, z)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleCubic(m_perm[0], x, y, z)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleCubic(m_perm[i], x, y, z))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetCubic(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + return SingleCubic(0, x * m_frequency, y * m_frequency, z * m_frequency); +} + +const FN_DECIMAL CUBIC_3D_BOUNDING = 1 / (FN_DECIMAL(1.5) * FN_DECIMAL(1.5) * FN_DECIMAL(1.5)); + +FN_DECIMAL FastNoise::SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + int x1 = FastFloor(x); + int y1 = FastFloor(y); + int z1 = FastFloor(z); + + int x0 = x1 - 1; + int y0 = y1 - 1; + int z0 = z1 - 1; + int x2 = x1 + 1; + int y2 = y1 + 1; + int z2 = z1 + 1; + int x3 = x1 + 2; + int y3 = y1 + 2; + int z3 = z1 + 2; + + FN_DECIMAL xs = x - (FN_DECIMAL)x1; + FN_DECIMAL ys = y - (FN_DECIMAL)y1; + FN_DECIMAL zs = z - (FN_DECIMAL)z1; + + return CubicLerp( + CubicLerp( + CubicLerp(ValCoord3DFast(offset, x0, y0, z0), ValCoord3DFast(offset, x1, y0, z0), ValCoord3DFast(offset, x2, y0, z0), ValCoord3DFast(offset, x3, y0, z0), xs), + CubicLerp(ValCoord3DFast(offset, x0, y1, z0), ValCoord3DFast(offset, x1, y1, z0), ValCoord3DFast(offset, x2, y1, z0), ValCoord3DFast(offset, x3, y1, z0), xs), + CubicLerp(ValCoord3DFast(offset, x0, y2, z0), ValCoord3DFast(offset, x1, y2, z0), ValCoord3DFast(offset, x2, y2, z0), ValCoord3DFast(offset, x3, y2, z0), xs), + CubicLerp(ValCoord3DFast(offset, x0, y3, z0), ValCoord3DFast(offset, x1, y3, z0), ValCoord3DFast(offset, x2, y3, z0), ValCoord3DFast(offset, x3, y3, z0), xs), + ys), + CubicLerp( + CubicLerp(ValCoord3DFast(offset, x0, y0, z1), ValCoord3DFast(offset, x1, y0, z1), ValCoord3DFast(offset, x2, y0, z1), ValCoord3DFast(offset, x3, y0, z1), xs), + CubicLerp(ValCoord3DFast(offset, x0, y1, z1), ValCoord3DFast(offset, x1, y1, z1), ValCoord3DFast(offset, x2, y1, z1), ValCoord3DFast(offset, x3, y1, z1), xs), + CubicLerp(ValCoord3DFast(offset, x0, y2, z1), ValCoord3DFast(offset, x1, y2, z1), ValCoord3DFast(offset, x2, y2, z1), ValCoord3DFast(offset, x3, y2, z1), xs), + CubicLerp(ValCoord3DFast(offset, x0, y3, z1), ValCoord3DFast(offset, x1, y3, z1), ValCoord3DFast(offset, x2, y3, z1), ValCoord3DFast(offset, x3, y3, z1), xs), + ys), + CubicLerp( + CubicLerp(ValCoord3DFast(offset, x0, y0, z2), ValCoord3DFast(offset, x1, y0, z2), ValCoord3DFast(offset, x2, y0, z2), ValCoord3DFast(offset, x3, y0, z2), xs), + CubicLerp(ValCoord3DFast(offset, x0, y1, z2), ValCoord3DFast(offset, x1, y1, z2), ValCoord3DFast(offset, x2, y1, z2), ValCoord3DFast(offset, x3, y1, z2), xs), + CubicLerp(ValCoord3DFast(offset, x0, y2, z2), ValCoord3DFast(offset, x1, y2, z2), ValCoord3DFast(offset, x2, y2, z2), ValCoord3DFast(offset, x3, y2, z2), xs), + CubicLerp(ValCoord3DFast(offset, x0, y3, z2), ValCoord3DFast(offset, x1, y3, z2), ValCoord3DFast(offset, x2, y3, z2), ValCoord3DFast(offset, x3, y3, z2), xs), + ys), + CubicLerp( + CubicLerp(ValCoord3DFast(offset, x0, y0, z3), ValCoord3DFast(offset, x1, y0, z3), ValCoord3DFast(offset, x2, y0, z3), ValCoord3DFast(offset, x3, y0, z3), xs), + CubicLerp(ValCoord3DFast(offset, x0, y1, z3), ValCoord3DFast(offset, x1, y1, z3), ValCoord3DFast(offset, x2, y1, z3), ValCoord3DFast(offset, x3, y1, z3), xs), + CubicLerp(ValCoord3DFast(offset, x0, y2, z3), ValCoord3DFast(offset, x1, y2, z3), ValCoord3DFast(offset, x2, y2, z3), ValCoord3DFast(offset, x3, y2, z3), xs), + CubicLerp(ValCoord3DFast(offset, x0, y3, z3), ValCoord3DFast(offset, x1, y3, z3), ValCoord3DFast(offset, x2, y3, z3), ValCoord3DFast(offset, x3, y3, z3), xs), + ys), + zs) * CUBIC_3D_BOUNDING; +} + + +FN_DECIMAL FastNoise::GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_fractalType) + { + case FBM: + return SingleCubicFractalFBM(x, y); + case Billow: + return SingleCubicFractalBillow(x, y); + case RigidMulti: + return SingleCubicFractalRigidMulti(x, y); + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = SingleCubic(m_perm[0], x, y); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += SingleCubic(m_perm[i], x, y) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = FastAbs(SingleCubic(m_perm[0], x, y)) * 2 - 1; + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum += (FastAbs(SingleCubic(m_perm[i], x, y)) * 2 - 1) * amp; + } + + return sum * m_fractalBounding; +} + +FN_DECIMAL FastNoise::SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const +{ + FN_DECIMAL sum = 1 - FastAbs(SingleCubic(m_perm[0], x, y)); + FN_DECIMAL amp = 1; + int i = 0; + + while (++i < m_octaves) + { + x *= m_lacunarity; + y *= m_lacunarity; + + amp *= m_gain; + sum -= (1 - FastAbs(SingleCubic(m_perm[i], x, y))) * amp; + } + + return sum; +} + +FN_DECIMAL FastNoise::GetCubic(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + return SingleCubic(0, x, y); +} + +const FN_DECIMAL CUBIC_2D_BOUNDING = 1 / (FN_DECIMAL(1.5) * FN_DECIMAL(1.5)); + +FN_DECIMAL FastNoise::SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const +{ + int x1 = FastFloor(x); + int y1 = FastFloor(y); + + int x0 = x1 - 1; + int y0 = y1 - 1; + int x2 = x1 + 1; + int y2 = y1 + 1; + int x3 = x1 + 2; + int y3 = y1 + 2; + + FN_DECIMAL xs = x - (FN_DECIMAL)x1; + FN_DECIMAL ys = y - (FN_DECIMAL)y1; + + return CubicLerp( + CubicLerp(ValCoord2DFast(offset, x0, y0), ValCoord2DFast(offset, x1, y0), ValCoord2DFast(offset, x2, y0), ValCoord2DFast(offset, x3, y0), xs), + CubicLerp(ValCoord2DFast(offset, x0, y1), ValCoord2DFast(offset, x1, y1), ValCoord2DFast(offset, x2, y1), ValCoord2DFast(offset, x3, y1), xs), + CubicLerp(ValCoord2DFast(offset, x0, y2), ValCoord2DFast(offset, x1, y2), ValCoord2DFast(offset, x2, y2), ValCoord2DFast(offset, x3, y2), xs), + CubicLerp(ValCoord2DFast(offset, x0, y3), ValCoord2DFast(offset, x1, y3), ValCoord2DFast(offset, x2, y3), ValCoord2DFast(offset, x3, y3), xs), + ys) * CUBIC_2D_BOUNDING; +} + +// Cellular Noise +FN_DECIMAL FastNoise::GetCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + switch (m_cellularReturnType) + { + case CellValue: + case NoiseLookup: + case Distance: + return SingleCellular(x, y, z); + default: + return SingleCellular2Edge(x, y, z); + } +} + +FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + int xr = FastRound(x); + int yr = FastRound(y); + int zr = FastRound(z); + + FN_DECIMAL distance = 999999; + int xc, yc, zc; + + switch (m_cellularDistanceFunction) + { + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; + + if (newDistance < distance) + { + distance = newDistance; + xc = xi; + yc = yi; + zc = zi; + } + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ); + + if (newDistance < distance) + { + distance = newDistance; + xc = xi; + yc = yi; + zc = zi; + } + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL 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 CellValue: + return ValCoord3D(m_seed, xc, yc, zc); + + case NoiseLookup: + assert(m_cellularNoiseLookup); + + lutPos = Index3D_256(0, xc, yc, zc); + return m_cellularNoiseLookup->GetNoise(xc + CELL_3D_X[lutPos] * m_cellularJitter, yc + CELL_3D_Y[lutPos] * m_cellularJitter, zc + CELL_3D_Z[lutPos] * m_cellularJitter); + + case Distance: + return distance; + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const +{ + int xr = FastRound(x); + int yr = FastRound(y); + int zr = FastRound(z); + + FN_DECIMAL distance[FN_CELLULAR_INDEX_MAX+1] = { 999999,999999,999999,999999 }; + + switch (m_cellularDistanceFunction) + { + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ; + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ); + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_3D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_3D_Y[lutPos] * m_cellularJitter; + FN_DECIMAL vecZ = zi - z + CELL_3D_Z[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = (FastAbs(vecX) + FastAbs(vecY) + FastAbs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ); + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + } + break; + default: + break; + } + + switch (m_cellularReturnType) + { + case Distance2: + return distance[m_cellularDistanceIndex1]; + case Distance2Add: + return distance[m_cellularDistanceIndex1] + distance[m_cellularDistanceIndex0]; + case Distance2Sub: + return distance[m_cellularDistanceIndex1] - distance[m_cellularDistanceIndex0]; + case Distance2Mul: + return distance[m_cellularDistanceIndex1] * distance[m_cellularDistanceIndex0]; + case Distance2Div: + return distance[m_cellularDistanceIndex0] / distance[m_cellularDistanceIndex1]; + default: + return 0; + } +} + +FN_DECIMAL FastNoise::GetCellular(FN_DECIMAL x, FN_DECIMAL y) const +{ + x *= m_frequency; + y *= m_frequency; + + switch (m_cellularReturnType) + { + case CellValue: + case NoiseLookup: + case Distance: + return SingleCellular(x, y); + default: + return SingleCellular2Edge(x, y); + } +} + +FN_DECIMAL FastNoise::SingleCellular(FN_DECIMAL x, FN_DECIMAL y) const +{ + int xr = FastRound(x); + int yr = FastRound(y); + + FN_DECIMAL distance = 999999; + int xc, yc; + + switch (m_cellularDistanceFunction) + { + default: + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = vecX * vecX + vecY * vecY; + + if (newDistance < distance) + { + distance = newDistance; + xc = xi; + yc = yi; + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = (FastAbs(vecX) + FastAbs(vecY)); + + if (newDistance < distance) + { + distance = newDistance; + xc = xi; + yc = yi; + } + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL 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 CellValue: + return ValCoord2D(m_seed, xc, yc); + + case NoiseLookup: + assert(m_cellularNoiseLookup); + + lutPos = Index2D_256(0, xc, yc); + return m_cellularNoiseLookup->GetNoise(xc + CELL_2D_X[lutPos] * m_cellularJitter, yc + CELL_2D_Y[lutPos] * m_cellularJitter); + + case Distance: + return distance; + default: + return 0; + } +} + +FN_DECIMAL FastNoise::SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y) const +{ + int xr = FastRound(x); + int yr = FastRound(y); + + FN_DECIMAL distance[FN_CELLULAR_INDEX_MAX + 1] = { 999999,999999,999999,999999 }; + + switch (m_cellularDistanceFunction) + { + default: + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = vecX * vecX + vecY * vecY; + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = FastAbs(vecX) + FastAbs(vecY); + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + break; + case 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); + + FN_DECIMAL vecX = xi - x + CELL_2D_X[lutPos] * m_cellularJitter; + FN_DECIMAL vecY = yi - y + CELL_2D_Y[lutPos] * m_cellularJitter; + + FN_DECIMAL newDistance = (FastAbs(vecX) + FastAbs(vecY)) + (vecX * vecX + vecY * vecY); + + for (int i = m_cellularDistanceIndex1; i > 0; i--) + distance[i] = fmax(fmin(distance[i], newDistance), distance[i - 1]); + distance[0] = fmin(distance[0], newDistance); + } + } + break; + } + + switch (m_cellularReturnType) + { + case Distance2: + return distance[m_cellularDistanceIndex1]; + case Distance2Add: + return distance[m_cellularDistanceIndex1] + distance[m_cellularDistanceIndex0]; + case Distance2Sub: + return distance[m_cellularDistanceIndex1] - distance[m_cellularDistanceIndex0]; + case Distance2Mul: + return distance[m_cellularDistanceIndex1] * distance[m_cellularDistanceIndex0]; + case Distance2Div: + return distance[m_cellularDistanceIndex0] / distance[m_cellularDistanceIndex1]; + default: + return 0; + } +} + +void FastNoise::GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const +{ + SingleGradientPerturb(0, m_gradientPerturbAmp, m_frequency, x, y, z); +} + +void FastNoise::GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const +{ + FN_DECIMAL amp = m_gradientPerturbAmp * m_fractalBounding; + FN_DECIMAL freq = m_frequency; + int i = 0; + + SingleGradientPerturb(m_perm[0], amp, m_frequency, x, y, z); + + while (++i < m_octaves) + { + freq *= m_lacunarity; + amp *= m_gain; + SingleGradientPerturb(m_perm[i], amp, freq, x, y, z); + } +} + +void FastNoise::SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const +{ + FN_DECIMAL xf = x * frequency; + FN_DECIMAL yf = y * frequency; + FN_DECIMAL zf = z * frequency; + + int x0 = FastFloor(xf); + int y0 = FastFloor(yf); + int z0 = FastFloor(zf); + int x1 = x0 + 1; + int y1 = y0 + 1; + int z1 = z0 + 1; + + FN_DECIMAL xs, ys, zs; + switch (m_interp) + { + default: + case Linear: + xs = xf - (FN_DECIMAL)x0; + ys = yf - (FN_DECIMAL)y0; + zs = zf - (FN_DECIMAL)z0; + break; + case Hermite: + xs = InterpHermiteFunc(xf - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(yf - (FN_DECIMAL)y0); + zs = InterpHermiteFunc(zf - (FN_DECIMAL)z0); + break; + case Quintic: + xs = InterpQuinticFunc(xf - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(yf - (FN_DECIMAL)y0); + zs = InterpQuinticFunc(zf - (FN_DECIMAL)z0); + break; + } + + int lutPos0 = Index3D_256(offset, x0, y0, z0); + int lutPos1 = Index3D_256(offset, x1, y0, z0); + + FN_DECIMAL lx0x = Lerp(CELL_3D_X[lutPos0], CELL_3D_X[lutPos1], xs); + FN_DECIMAL ly0x = Lerp(CELL_3D_Y[lutPos0], CELL_3D_Y[lutPos1], xs); + FN_DECIMAL lz0x = Lerp(CELL_3D_Z[lutPos0], CELL_3D_Z[lutPos1], xs); + + lutPos0 = Index3D_256(offset, x0, y1, z0); + lutPos1 = Index3D_256(offset, x1, y1, z0); + + FN_DECIMAL lx1x = Lerp(CELL_3D_X[lutPos0], CELL_3D_X[lutPos1], xs); + FN_DECIMAL ly1x = Lerp(CELL_3D_Y[lutPos0], CELL_3D_Y[lutPos1], xs); + FN_DECIMAL lz1x = Lerp(CELL_3D_Z[lutPos0], CELL_3D_Z[lutPos1], xs); + + FN_DECIMAL lx0y = Lerp(lx0x, lx1x, ys); + FN_DECIMAL ly0y = Lerp(ly0x, ly1x, ys); + FN_DECIMAL lz0y = Lerp(lz0x, lz1x, ys); + + lutPos0 = Index3D_256(offset, x0, y0, z1); + lutPos1 = Index3D_256(offset, x1, y0, z1); + + lx0x = Lerp(CELL_3D_X[lutPos0], CELL_3D_X[lutPos1], xs); + ly0x = Lerp(CELL_3D_Y[lutPos0], CELL_3D_Y[lutPos1], xs); + lz0x = Lerp(CELL_3D_Z[lutPos0], CELL_3D_Z[lutPos1], xs); + + lutPos0 = Index3D_256(offset, x0, y1, z1); + lutPos1 = Index3D_256(offset, x1, y1, z1); + + lx1x = Lerp(CELL_3D_X[lutPos0], CELL_3D_X[lutPos1], xs); + ly1x = Lerp(CELL_3D_Y[lutPos0], CELL_3D_Y[lutPos1], xs); + lz1x = Lerp(CELL_3D_Z[lutPos0], CELL_3D_Z[lutPos1], xs); + + x += Lerp(lx0y, Lerp(lx0x, lx1x, ys), zs) * warpAmp; + y += Lerp(ly0y, Lerp(ly0x, ly1x, ys), zs) * warpAmp; + z += Lerp(lz0y, Lerp(lz0x, lz1x, ys), zs) * warpAmp; +} + +void FastNoise::GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y) const +{ + SingleGradientPerturb(0, m_gradientPerturbAmp, m_frequency, x, y); +} + +void FastNoise::GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y) const +{ + FN_DECIMAL amp = m_gradientPerturbAmp * m_fractalBounding; + FN_DECIMAL freq = m_frequency; + int i = 0; + + SingleGradientPerturb(m_perm[0], amp, m_frequency, x, y); + + while (++i < m_octaves) + { + freq *= m_lacunarity; + amp *= m_gain; + SingleGradientPerturb(m_perm[i], amp, freq, x, y); + } +} + +void FastNoise::SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y) const +{ + FN_DECIMAL xf = x * frequency; + FN_DECIMAL yf = y * frequency; + + int x0 = FastFloor(xf); + int y0 = FastFloor(yf); + int x1 = x0 + 1; + int y1 = y0 + 1; + + FN_DECIMAL xs, ys; + switch (m_interp) + { + default: + case Linear: + xs = xf - (FN_DECIMAL)x0; + ys = yf - (FN_DECIMAL)y0; + break; + case Hermite: + xs = InterpHermiteFunc(xf - (FN_DECIMAL)x0); + ys = InterpHermiteFunc(yf - (FN_DECIMAL)y0); + break; + case Quintic: + xs = InterpQuinticFunc(xf - (FN_DECIMAL)x0); + ys = InterpQuinticFunc(yf - (FN_DECIMAL)y0); + break; + } + + int lutPos0 = Index2D_256(offset, x0, y0); + int lutPos1 = Index2D_256(offset, x1, y0); + + FN_DECIMAL lx0x = Lerp(CELL_2D_X[lutPos0], CELL_2D_X[lutPos1], xs); + FN_DECIMAL ly0x = Lerp(CELL_2D_Y[lutPos0], CELL_2D_Y[lutPos1], xs); + + lutPos0 = Index2D_256(offset, x0, y1); + lutPos1 = Index2D_256(offset, x1, y1); + + FN_DECIMAL lx1x = Lerp(CELL_2D_X[lutPos0], CELL_2D_X[lutPos1], xs); + FN_DECIMAL ly1x = Lerp(CELL_2D_Y[lutPos0], CELL_2D_Y[lutPos1], xs); + + x += Lerp(lx0x, lx1x, ys) * warpAmp; + y += Lerp(ly0x, ly1x, ys) * warpAmp; +} diff --git a/FastNoise/FastNoise.h b/FastNoise/FastNoise.h new file mode 100644 index 000000000..00410a0cf --- /dev/null +++ b/FastNoise/FastNoise.h @@ -0,0 +1,317 @@ +// FastNoise.h +// +// MIT License +// +// Copyright(c) 2017 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'.) +// + +// VERSION: 0.4.1 + +#ifndef FASTNOISE_H +#define FASTNOISE_H + +// Uncomment the line below to use doubles throughout FastNoise instead of floats +//#define FN_USE_DOUBLES + +#define FN_CELLULAR_INDEX_MAX 3 + +#ifdef FN_USE_DOUBLES +typedef double FN_DECIMAL; +#else +typedef float FN_DECIMAL; +#endif + +class FastNoise +{ +public: + explicit FastNoise(int seed = 1337) { SetSeed(seed); CalculateFractalBounding(); } + + enum NoiseType { Value, ValueFractal, Perlin, PerlinFractal, Simplex, SimplexFractal, Cellular, WhiteNoise, Cubic, CubicFractal }; + enum Interp { Linear, Hermite, Quintic }; + enum FractalType { FBM, Billow, RigidMulti }; + enum CellularDistanceFunction { Euclidean, Manhattan, Natural }; + enum CellularReturnType { CellValue, NoiseLookup, Distance, Distance2, Distance2Add, Distance2Sub, Distance2Mul, Distance2Div }; + + // Sets seed used for all noise types + // Default: 1337 + void SetSeed(int seed); + + // Returns seed used for all noise types + int GetSeed() const { return m_seed; } + + // Sets frequency for all noise types + // Default: 0.01 + void SetFrequency(FN_DECIMAL frequency) { m_frequency = frequency; } + + // Returns frequency used for all noise types + FN_DECIMAL GetFrequency() const { return m_frequency; } + + // Changes the interpolation method used to smooth between noise values + // Possible interpolation methods (lowest to highest quality) : + // - Linear + // - Hermite + // - Quintic + // Used in Value, Perlin Noise and Position Warping + // Default: Quintic + void SetInterp(Interp interp) { m_interp = interp; } + + // Returns interpolation method used for supported noise types + Interp GetInterp() const { return m_interp; } + + // Sets noise return type of GetNoise(...) + // Default: Simplex + void SetNoiseType(NoiseType noiseType) { m_noiseType = noiseType; } + + // Returns the noise type used by GetNoise + NoiseType GetNoiseType() const { return m_noiseType; } + + // Sets octave count for all fractal noise types + // Default: 3 + void SetFractalOctaves(int octaves) { m_octaves = octaves; CalculateFractalBounding(); } + + // Returns octave count for all fractal noise types + int GetFractalOctaves() const { return m_octaves; } + + // Sets octave lacunarity for all fractal noise types + // Default: 2.0 + void SetFractalLacunarity(FN_DECIMAL lacunarity) { m_lacunarity = lacunarity; } + + // Returns octave lacunarity for all fractal noise types + FN_DECIMAL GetFractalLacunarity() const { return m_lacunarity; } + + // Sets octave gain for all fractal noise types + // Default: 0.5 + void SetFractalGain(FN_DECIMAL gain) { m_gain = gain; CalculateFractalBounding(); } + + // Returns octave gain for all fractal noise types + FN_DECIMAL GetFractalGain() const { return m_gain; } + + // Sets method for combining octaves in all fractal noise types + // Default: FBM + void SetFractalType(FractalType fractalType) { m_fractalType = fractalType; } + + // Returns method for combining octaves in all fractal noise types + FractalType GetFractalType() const { return m_fractalType; } + + + // Sets distance function used in cellular noise calculations + // Default: Euclidean + void SetCellularDistanceFunction(CellularDistanceFunction cellularDistanceFunction) { m_cellularDistanceFunction = cellularDistanceFunction; } + + // Returns the distance function used in cellular noise calculations + CellularDistanceFunction GetCellularDistanceFunction() const { return m_cellularDistanceFunction; } + + // Sets return type from cellular noise calculations + // Note: NoiseLookup requires another FastNoise object be set with SetCellularNoiseLookup() to function + // Default: CellValue + void SetCellularReturnType(CellularReturnType cellularReturnType) { m_cellularReturnType = cellularReturnType; } + + // Returns the return type from cellular noise calculations + CellularReturnType GetCellularReturnType() const { return m_cellularReturnType; } + + // Noise used to calculate a cell value if cellular return type is NoiseLookup + // The lookup value is acquired through GetNoise() so ensure you SetNoiseType() on the noise lookup, value, Perlin or simplex is recommended + void SetCellularNoiseLookup(FastNoise* noise) { m_cellularNoiseLookup = noise; } + + // Returns the noise used to calculate a cell value if the cellular return type is NoiseLookup + FastNoise* GetCellularNoiseLookup() const { return m_cellularNoiseLookup; } + + // Sets the 2 distance indices used for distance2 return types + // Default: 0, 1 + // Note: index0 should be lower than index1 + // Both indices must be >= 0, index1 must be < 4 + void SetCellularDistance2Indices(int cellularDistanceIndex0, int cellularDistanceIndex1); + + // Returns the 2 distance indices used for distance2 return types + void GetCellularDistance2Indices(int& cellularDistanceIndex0, int& cellularDistanceIndex1) const; + + // Sets the maximum distance a cellular point can move from its grid position + // Setting this high will make artifacts more common + // Default: 0.45 + void SetCellularJitter(FN_DECIMAL cellularJitter) { m_cellularJitter = cellularJitter; } + + // Returns the maximum distance a cellular point can move from its grid position + FN_DECIMAL GetCellularJitter() const { return m_cellularJitter; } + + // Sets the maximum warp distance from original location when using GradientPerturb{Fractal}(...) + // Default: 1.0 + void SetGradientPerturbAmp(FN_DECIMAL gradientPerturbAmp) { m_gradientPerturbAmp = gradientPerturbAmp; } + + // Returns the maximum warp distance from original location when using GradientPerturb{Fractal}(...) + FN_DECIMAL GetGradientPerturbAmp() const { return m_gradientPerturbAmp; } + + //2D + FN_DECIMAL GetValue(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL GetValueFractal(FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL GetPerlin(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL GetCellular(FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL GetWhiteNoiseInt(int x, int y) const; + + FN_DECIMAL GetCubic(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL GetNoise(FN_DECIMAL x, FN_DECIMAL y) const; + + void GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y) const; + void GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y) const; + + //3D + FN_DECIMAL GetValue(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL GetValueFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL GetPerlin(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL GetPerlinFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL GetCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL GetWhiteNoiseInt(int x, int y, int z) const; + + FN_DECIMAL GetCubic(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL GetCubicFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL GetNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + void GradientPerturb(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const; + void GradientPerturbFractal(FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const; + + //4D + FN_DECIMAL GetSimplex(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; +FN_DECIMAL GetSimplexFractal(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + + FN_DECIMAL GetWhiteNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + FN_DECIMAL GetWhiteNoiseInt(int x, int y, int z, int w) const; + + FN_DECIMAL GetNoise(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + +private: + unsigned char m_perm[512]; + unsigned char m_perm12[512]; + + int m_seed = 1337; + FN_DECIMAL m_frequency = FN_DECIMAL(0.01); + Interp m_interp = Quintic; + NoiseType m_noiseType = Simplex; + + int m_octaves = 3; + FN_DECIMAL m_lacunarity = FN_DECIMAL(2); + FN_DECIMAL m_gain = FN_DECIMAL(0.5); + FractalType m_fractalType = FBM; + FN_DECIMAL m_fractalBounding; + + CellularDistanceFunction m_cellularDistanceFunction = Euclidean; + CellularReturnType m_cellularReturnType = CellValue; + FastNoise* m_cellularNoiseLookup = nullptr; + int m_cellularDistanceIndex0 = 0; + int m_cellularDistanceIndex1 = 1; + FN_DECIMAL m_cellularJitter = FN_DECIMAL(0.45); + + FN_DECIMAL m_gradientPerturbAmp = FN_DECIMAL(1); + + void CalculateFractalBounding(); + + //2D + FN_DECIMAL SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleSimplexFractalBlend(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y) const; + + FN_DECIMAL SingleCellular(FN_DECIMAL x, FN_DECIMAL y) const; + FN_DECIMAL SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y) const; + + void SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y) const; + + //3D + FN_DECIMAL SingleValueFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleValueFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleValueFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleValue(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL SinglePerlinFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SinglePerlinFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SinglePerlinFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SinglePerlin(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL SingleCubicFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleCubicFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleCubicFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleCubic(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + FN_DECIMAL SingleCellular(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + FN_DECIMAL SingleCellular2Edge(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z) const; + + void SingleGradientPerturb(unsigned char offset, FN_DECIMAL warpAmp, FN_DECIMAL frequency, FN_DECIMAL& x, FN_DECIMAL& y, FN_DECIMAL& z) const; + + //4D + FN_DECIMAL SingleSimplexFractalFBM(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + FN_DECIMAL SingleSimplexFractalBillow(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + FN_DECIMAL SingleSimplexFractalRigidMulti(FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + FN_DECIMAL SingleSimplex(unsigned char offset, FN_DECIMAL x, FN_DECIMAL y, FN_DECIMAL z, FN_DECIMAL w) const; + + inline unsigned char Index2D_12(unsigned char offset, int x, int y) const; + inline unsigned char Index3D_12(unsigned char offset, int x, int y, int z) const; + inline unsigned char Index4D_32(unsigned char offset, int x, int y, int z, int w) const; + inline unsigned char Index2D_256(unsigned char offset, int x, int y) const; + inline unsigned char Index3D_256(unsigned char offset, int x, int y, int z) const; + inline unsigned char Index4D_256(unsigned char offset, int x, int y, int z, int w) const; + + inline FN_DECIMAL ValCoord2DFast(unsigned char offset, int x, int y) const; + inline FN_DECIMAL ValCoord3DFast(unsigned char offset, int x, int y, int z) const; + inline FN_DECIMAL GradCoord2D(unsigned char offset, int x, int y, FN_DECIMAL xd, FN_DECIMAL yd) const; + inline FN_DECIMAL GradCoord3D(unsigned char offset, int x, int y, int z, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd) const; + inline FN_DECIMAL GradCoord4D(unsigned char offset, int x, int y, int z, int w, FN_DECIMAL xd, FN_DECIMAL yd, FN_DECIMAL zd, FN_DECIMAL wd) const; +}; +#endif diff --git a/Main/CMakeLists.txt b/Main/CMakeLists.txt index 7bd570658..193e505ee 100644 --- a/Main/CMakeLists.txt +++ b/Main/CMakeLists.txt @@ -33,8 +33,8 @@ set_source_files_properties( PROPERTIES HEADER_FILE_ONLY TRUE) add_executable(ivan ${IVAN_SOURCES} Resource/Ivan.rc) -target_include_directories(ivan PUBLIC Include ../Felib/Include ../audio ../fantasyname ${PCRE_INCLUDE_DIRS} ${SDL2_mixer_INCLUDE_DIR}) -target_link_libraries(ivan FeLib FeAudio xbrzscale fantasyname ${PCRE_LIBRARIES} ${SDL2_mixer_LIBRARY}) +target_include_directories(ivan PUBLIC Include ../Felib/Include ../audio ../fantasyname ../FastNoise ${PCRE_INCLUDE_DIRS} ${SDL2_mixer_INCLUDE_DIR}) +target_link_libraries(ivan FeLib FeAudio xbrzscale fantasyname fastnoise ${PCRE_LIBRARIES} ${SDL2_mixer_LIBRARY}) if(MSVC AND _VCPKG_INSTALLED_DIR) # Gum solution. Manually copy pcre.dll to where ivan.exe will end up. diff --git a/Main/Include/char.h b/Main/Include/char.h index 3c143cce2..fe7140009 100644 --- a/Main/Include/char.h +++ b/Main/Include/char.h @@ -418,6 +418,7 @@ class character : public entity, public id festring GetPersonalPronoun(truth = true) const; festring GetPossessivePronoun(truth = true) const; festring GetObjectPronoun(truth = true) const; + festring GetWorldShapeDescription() const; virtual truth BodyPartCanBeSevered(int) const; virtual void AddName(festring&, int) const; void ReceiveHeal(long); diff --git a/Main/Include/command.h b/Main/Include/command.h index 642db2957..3fe8e080c 100644 --- a/Main/Include/command.h +++ b/Main/Include/command.h @@ -100,6 +100,7 @@ class commandsystem static truth AssignName(character*); static truth Search(character*); static truth Consume(character*, cchar*, cchar*, sorter, truth = false); + static truth ShowWorldSeed(character*); #ifdef WIZARD static truth WizardMode(character*); static truth AutoPlay(character* Char); diff --git a/Main/Include/game.h b/Main/Include/game.h index c7369e00a..b497cd938 100644 --- a/Main/Include/game.h +++ b/Main/Include/game.h @@ -510,6 +510,8 @@ class game static truth ValidateCustomCmdKey(int iNewKey, int iIgnoreIndex, bool bMoveKeys); static festring GetMoveKeyDesc(int i); static void LoadCustomCommandKeys(); + static int GetWorldShape() { return WorldShape; } + static void SetWorldShape(int What) { WorldShape = What; } private: static void UpdateCameraCoordinate(int&, int, int, int); static cchar* const Alignment[]; @@ -632,6 +634,7 @@ class game const static int iListWidth = 652; static std::vector vDbgDrawOverlayFunctions; static int iCurrentDungeonTurn; + static int WorldShape; }; inline void game::CombineLights(col24& L1, col24 L2) diff --git a/Main/Include/iconf.h b/Main/Include/iconf.h index f89d02c71..47e387514 100644 --- a/Main/Include/iconf.h +++ b/Main/Include/iconf.h @@ -78,6 +78,11 @@ class ivanconfig static long GetSfxVolume() { return SfxVolume.Value; } static long GetMIDIOutputDevice() { return MIDIOutputDevice.Value; } static truth GetExtraMenuGraphics(){ return UseExtraMenuGraphics.Value; } + static v2 GetWorldSizeConfig(); + static int GetLandTypeConfig() { return LandTypeConfig.Value; } + static int GetWorldShapeConfig() { return WorldShapeConfig.Value; } + static int GetWorldSeedConfig() { return WorldSeedConfig.Value; } + static int GetWorldSizeNumber() { return WorldSizeConfig.Value; } #ifndef __DJGPP__ static int GetGraphicsScale() { return GraphicsScale.Value; } @@ -151,6 +156,12 @@ class ivanconfig static void AltSilhouetteDisplayer(const cycleoption* O, festring& Entry); static void AllowMouseOnFelistChanger(truthoption*, truth); static void UseExtraMenuGraphicsChanger(truthoption*, truth); + static void WorldSizeConfigDisplayer(const cycleoption* O, festring& Entry); + static void LandTypeConfigDisplayer(const cycleoption* O, festring& Entry); + static void WorldShapeConfigDisplayer(const cycleoption* O, festring& Entry); + static void WorldSeedConfigDisplayer(const numberoption* O, festring& Entry); + static truth WorldSeedConfigChangeInterface(numberoption* O); + static void WorldSeedConfigChanger(numberoption* O, long What); #ifndef __DJGPP__ static void GraphicsScaleDisplayer(const cycleoption*, festring&); @@ -251,6 +262,11 @@ class ivanconfig static scrollbaroption Volume; static scrollbaroption SfxVolume; static cycleoption MIDIOutputDevice; + + static cycleoption WorldSizeConfig; + static cycleoption LandTypeConfig; + static cycleoption WorldShapeConfig; + static numberoption WorldSeedConfig; #ifndef __DJGPP__ static cycleoption GraphicsScale; diff --git a/Main/Include/ivandef.h b/Main/Include/ivandef.h index c62780d9f..4fedf0080 100644 --- a/Main/Include/ivandef.h +++ b/Main/Include/ivandef.h @@ -743,6 +743,14 @@ cv2 SILHOUETTE_SIZE(48, 64); // it is TILE_SIZE*3,TILE_SIZE*4 tho.. #define TUNDRA 6 #define GLACIER 7 +#define HUGE_WORLD 0 +#define LARGE_WORLD 1 +#define MEDIUM_WORLD 2 +#define SMALL_WORLD 3 +#define TINY_WORLD 4 +#define ONE_SCREEN_WORLD 5 +#define FOUR_SCREEN_WORLD 6 + #define NO_MOVE 0 #define WALK 1 #define SWIM 2 diff --git a/Main/Include/worldmap.h b/Main/Include/worldmap.h index 14c0b4c5a..2d23900d5 100644 --- a/Main/Include/worldmap.h +++ b/Main/Include/worldmap.h @@ -39,6 +39,8 @@ class worldmap : public area void SmoothAltitude(); void SmoothClimate(); void RandomizeAltitude(); + void PeriodicSimplexNoiseAltitude(int); + void SimplexNoiseAltitude(); continent* GetContinentUnder(v2) const; continent* GetContinent(int) const; void RemoveEmptyContinents(); @@ -58,6 +60,9 @@ class worldmap : public area void UpdateLOS(); virtual int GetTypeOfNativeGTerrainType(int) const; truth PoissonDiscSamplerCheckDistance(int, int, double, int, int, long, std::vector); + int GetWorldSeed() const { return WorldSeed; } + void InitializeShapeDescription(); + std::vector GetWasPlaced(); protected: wsquare*** Map; std::vector Continent; @@ -69,6 +74,10 @@ class worldmap : public area uchar** PossibleLocationBuffer; short** NoIslandAltitudeBuffer; charactervector PlayerGroup; + int WorldSeed; + std::vector Grid; + std::vector Queue; + std::vector WasPlaced; }; outputfile& operator<<(outputfile&, const worldmap*); diff --git a/Main/Include/wterra.h b/Main/Include/wterra.h index e850fb025..bde6c82a7 100644 --- a/Main/Include/wterra.h +++ b/Main/Include/wterra.h @@ -128,10 +128,11 @@ struct owterraindatabase : public wterraindatabase int AttachedDungeon; int AttachedArea; truth CanBeGenerated; - int NativeGTerrainType; + fearray NativeGTerrainTypes; truth RevealEnvironmentInitially; truth HideLocationInitially; truth CanBeOnAnyTerrain; + truth IsCoreLocation; }; class owterrainprototype @@ -154,6 +155,7 @@ class owterrainprototype virtual truth RevealEnvironmentInitially() const { return false; } virtual truth HideLocationInitially() const { return false; } virtual truth CanBeOnAnyTerrain() const { return false; } + virtual truth IsCoreLocation() const { return false; } private: int Index; const owterrainprototype* Base; @@ -184,10 +186,11 @@ class owterrain : public wterrain, public oterrain DATA_BASE_VALUE(int, AttachedDungeon); DATA_BASE_VALUE(int, AttachedArea); DATA_BASE_TRUTH(CanBeGenerated); - DATA_BASE_VALUE(int, NativeGTerrainType); + DATA_BASE_VALUE(const fearray&, NativeGTerrainTypes); DATA_BASE_TRUTH(RevealEnvironmentInitially); DATA_BASE_TRUTH(HideLocationInitially); DATA_BASE_TRUTH(CanBeOnAnyTerrain); + DATA_BASE_TRUTH(IsCoreLocation); protected: virtual v2 GetBitmapPos(int) const; virtual cfestring& GetNameStem() const; diff --git a/Main/Include/wterras.h b/Main/Include/wterras.h index 08e468152..cd1888b9d 100644 --- a/Main/Include/wterras.h +++ b/Main/Include/wterras.h @@ -101,132 +101,39 @@ OWTERRAIN(blackmarket, owterrain) { }; -OWTERRAIN(locationAA, owterrain) -{ -}; - -OWTERRAIN(locationAB, owterrain) -{ -}; - -OWTERRAIN(locationAC, owterrain) -{ -}; - -OWTERRAIN(locationAD, owterrain) -{ -}; - -OWTERRAIN(locationAE, owterrain) -{ -}; - -OWTERRAIN(locationAF, owterrain) -{ -}; - -OWTERRAIN(locationAG, owterrain) -{ -}; - -OWTERRAIN(locationAH, owterrain) -{ -}; - -OWTERRAIN(locationAI, owterrain) -{ -}; - -OWTERRAIN(locationAJ, owterrain) -{ -}; - - -OWTERRAIN(locationAK, owterrain) -{ -}; - -OWTERRAIN(locationAL, owterrain) -{ -}; - -OWTERRAIN(locationAM, owterrain) -{ -}; - -OWTERRAIN(locationAN, owterrain) -{ -}; - -OWTERRAIN(locationAO, owterrain) -{ -}; - -OWTERRAIN(locationAP, owterrain) -{ -}; - -OWTERRAIN(locationAQ, owterrain) -{ -}; - -OWTERRAIN(locationAR, owterrain) -{ -}; - -OWTERRAIN(locationAS, owterrain) -{ -}; - -OWTERRAIN(locationAT, owterrain) -{ -}; - -OWTERRAIN(locationAU, owterrain) -{ -}; - -OWTERRAIN(locationAV, owterrain) -{ -}; - OWTERRAIN(xinrochtomb, owterrain) { }; -OWTERRAIN(locationAX, owterrain) -{ -}; - -OWTERRAIN(locationAY, owterrain) +OWTERRAIN(locationA, owterrain) { }; -OWTERRAIN(locationAZ, owterrain) +OWTERRAIN(locationB, owterrain) { }; -OWTERRAIN(locationBA, owterrain) +OWTERRAIN(locationC, owterrain) { }; -OWTERRAIN(locationBB, owterrain) +OWTERRAIN(locationD, owterrain) { }; -OWTERRAIN(locationBC, owterrain) +OWTERRAIN(locationE, owterrain) { }; -OWTERRAIN(locationBD, owterrain) +OWTERRAIN(locationF, owterrain) { }; -OWTERRAIN(locationBE, owterrain) +OWTERRAIN(locationG, owterrain) { }; -OWTERRAIN(locationBF, owterrain) +OWTERRAIN(locationH, owterrain) { }; diff --git a/Main/Source/char.cpp b/Main/Source/char.cpp index 7f52c2460..a263c8238 100644 --- a/Main/Source/char.cpp +++ b/Main/Source/char.cpp @@ -1586,6 +1586,37 @@ truth character::TryMove(v2 MoveVector, truth Important, truth Run, truth* pbWai { /** No multitile support */ + int Shape = game::GetWorldShape(); + area* Area = game::GetCurrentArea(); + + if(Shape == 0) + { + MoveTo = MoveTo; // Flat + } + else if(Shape == 1) + { + // Cylinder + if(MoveTo.X > Area->GetXSize() - 1) + MoveTo.X = 0; + if(MoveTo.X < 0) + MoveTo.X = Area->GetXSize() - 1; + } + else if(Shape == 2) + { + // Toroidal + if(MoveTo.X > Area->GetXSize() - 1) + MoveTo.X = 0; + if(MoveTo.X < 0) + MoveTo.X = Area->GetXSize() - 1; + if(MoveTo.Y > Area->GetYSize() - 1) + MoveTo.Y = 0; + if(MoveTo.Y < 0) + MoveTo.Y = Area->GetYSize() - 1; + } + else + MoveTo = MoveTo; // Flat (default) + + if(CanMove() && GetArea()->IsValidPos(MoveTo) && (CanMoveOn(GetNearWSquare(MoveTo)) @@ -5407,6 +5438,20 @@ void character::AddName(festring& String, int Case) const } } +festring character::GetWorldShapeDescription() const +{ + int Shape = game::GetWorldShape(); + + if(Shape == 0) + return CONST_S("square pancake"); // Flat + else if(Shape == 1) + return CONST_S("square brandy snap"); // Cylinder + else if(Shape == 2) + return CONST_S("square doughnut"); // Toroidal + else + return CONST_S("square pancake"); // Default +} + int character::GetHungerState() const { if(!UsesNutrition()) @@ -8620,6 +8665,7 @@ festring& character::ProcessMessage(festring& Msg) const SEARCH_N_REPLACE(Msg, "@Sp", GetPossessivePronoun().CapitalizeCopy()); SEARCH_N_REPLACE(Msg, "@Op", GetObjectPronoun().CapitalizeCopy()); SEARCH_N_REPLACE(Msg, "@Gd", GetMasterGod()->GetName()); + SEARCH_N_REPLACE(Msg, "@ws", GetWorldShapeDescription()); return Msg; } diff --git a/Main/Source/command.cpp b/Main/Source/command.cpp index 08b3e5094..40e2fea57 100644 --- a/Main/Source/command.cpp +++ b/Main/Source/command.cpp @@ -131,6 +131,7 @@ command* commandsystem::Command[] = new command(&ToggleRunning, "toggle running", 'u', 'U', 'U', true), new command(&Kick, "kick", 'k', 'K', 'K', false), new command(&ForceVomit, "vomit", 'V', 'V', 'V', false), + new command(&ShowWorldSeed, "display the world seed", '^', '^', '^', true), #ifdef WIZARD new command(&WizardMode, "wizard mode activation (Ctrl+ for console)", '`', '`', '`', true), @@ -1932,6 +1933,17 @@ truth commandsystem::Search(character* Char) return true; } +truth commandsystem::ShowWorldSeed(character*) +{ + int Seed = game::GetWorldMap()->GetWorldSeed(); + if(!Seed) + ADD_MESSAGE("World seed is 0"); + else + ADD_MESSAGE("World seed is %d", Seed); + + return false; +} + #ifdef WIZARD truth commandsystem::WizardMode(character* Char) @@ -1945,74 +1957,27 @@ truth commandsystem::WizardMode(character* Char) if(game::IsInWilderness()) { - v2 ElpuriCavePos = game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE); - game::GetWorldMap()->GetWSquare(ElpuriCavePos)->ChangeOWTerrain(elpuricave::Spawn()); - game::GetWorldMap()->RevealEnvironment(ElpuriCavePos, 1); - - v2 XinrochTombPos = game::GetWorldMap()->GetEntryPos(0, XINROCH_TOMB); - game::GetWorldMap()->GetWSquare(XinrochTombPos)->ChangeOWTerrain(xinrochtomb::Spawn()); - game::GetWorldMap()->RevealEnvironment(XinrochTombPos, 1); - - v2 AslonaPos = game::GetWorldMap()->GetEntryPos(0, ASLONA_CASTLE); - game::GetWorldMap()->GetWSquare(AslonaPos)->ChangeOWTerrain(aslonacastle::Spawn()); - game::GetWorldMap()->RevealEnvironment(AslonaPos, 1); - - v2 RebelPos = game::GetWorldMap()->GetEntryPos(0, REBEL_CAMP); - game::GetWorldMap()->GetWSquare(RebelPos)->ChangeOWTerrain(rebelcamp::Spawn()); - game::GetWorldMap()->RevealEnvironment(RebelPos, 1); - - v2 GoblinFortPos = game::GetWorldMap()->GetEntryPos(0, GOBLIN_FORT); - game::GetWorldMap()->GetWSquare(GoblinFortPos)->ChangeOWTerrain(goblinfort::Spawn()); - game::GetWorldMap()->RevealEnvironment(GoblinFortPos, 1); - - v2 FungalCavePos = game::GetWorldMap()->GetEntryPos(0, FUNGAL_CAVE); - game::GetWorldMap()->GetWSquare(FungalCavePos)->ChangeOWTerrain(fungalcave::Spawn()); - game::GetWorldMap()->RevealEnvironment(FungalCavePos, 1); - - v2 PyramidPos = game::GetWorldMap()->GetEntryPos(0, PYRAMID); - game::GetWorldMap()->GetWSquare(PyramidPos)->ChangeOWTerrain(pyramid::Spawn()); - game::GetWorldMap()->RevealEnvironment(PyramidPos, 1); - - v2 BlackMarketPos = game::GetWorldMap()->GetEntryPos(0, BLACK_MARKET); - game::GetWorldMap()->GetWSquare(BlackMarketPos)->ChangeOWTerrain(blackmarket::Spawn()); - game::GetWorldMap()->RevealEnvironment(BlackMarketPos, 1); + for(uint j = 0; j < game::GetWorldMap()->GetWasPlaced().size(); j++) + { + owterrain* NewPlace = protocontainer::GetProto(game::GetWorldMap()->GetWasPlaced()[j].X)->Spawn(); + v2 LocationPosition = game::GetWorldMap()->GetEntryPos(0, game::GetWorldMap()->GetWasPlaced()[j].Y); + game::GetWorldMap()->GetWSquare(LocationPosition)->ChangeOWTerrain(NewPlace); + game::GetWorldMap()->RevealEnvironment(LocationPosition, 1); + } game::GetWorldMap()->SendNewDrawRequest(); } else { game::LoadWorldMap(); - v2 ElpuriCavePos = game::GetWorldMap()->GetEntryPos(0, ELPURI_CAVE); - game::GetWorldMap()->GetWSquare(ElpuriCavePos)->ChangeOWTerrain(elpuricave::Spawn()); - game::GetWorldMap()->RevealEnvironment(ElpuriCavePos, 1); - - v2 XinrochTombPos = game::GetWorldMap()->GetEntryPos(0, XINROCH_TOMB); - game::GetWorldMap()->GetWSquare(XinrochTombPos)->ChangeOWTerrain(xinrochtomb::Spawn()); - game::GetWorldMap()->RevealEnvironment(XinrochTombPos, 1); - - v2 AslonaPos = game::GetWorldMap()->GetEntryPos(0, ASLONA_CASTLE); - game::GetWorldMap()->GetWSquare(AslonaPos)->ChangeOWTerrain(aslonacastle::Spawn()); - game::GetWorldMap()->RevealEnvironment(AslonaPos, 1); - - v2 RebelPos = game::GetWorldMap()->GetEntryPos(0, REBEL_CAMP); - game::GetWorldMap()->GetWSquare(RebelPos)->ChangeOWTerrain(rebelcamp::Spawn()); - game::GetWorldMap()->RevealEnvironment(RebelPos, 1); - v2 GoblinFortPos = game::GetWorldMap()->GetEntryPos(0, GOBLIN_FORT); - game::GetWorldMap()->GetWSquare(GoblinFortPos)->ChangeOWTerrain(goblinfort::Spawn()); - game::GetWorldMap()->RevealEnvironment(GoblinFortPos, 1); - - v2 FungalCavePos = game::GetWorldMap()->GetEntryPos(0, FUNGAL_CAVE); - game::GetWorldMap()->GetWSquare(FungalCavePos)->ChangeOWTerrain(fungalcave::Spawn()); - game::GetWorldMap()->RevealEnvironment(FungalCavePos, 1); - - v2 PyramidPos = game::GetWorldMap()->GetEntryPos(0, PYRAMID); - game::GetWorldMap()->GetWSquare(PyramidPos)->ChangeOWTerrain(pyramid::Spawn()); - game::GetWorldMap()->RevealEnvironment(PyramidPos, 1); - - v2 BlackMarketPos = game::GetWorldMap()->GetEntryPos(0, BLACK_MARKET); - game::GetWorldMap()->GetWSquare(BlackMarketPos)->ChangeOWTerrain(blackmarket::Spawn()); - game::GetWorldMap()->RevealEnvironment(BlackMarketPos, 1); + for(uint j = 0; j < game::GetWorldMap()->GetWasPlaced().size(); j++) + { + owterrain* NewPlace = protocontainer::GetProto(game::GetWorldMap()->GetWasPlaced()[j].X)->Spawn(); + v2 LocationPosition = game::GetWorldMap()->GetEntryPos(0, game::GetWorldMap()->GetWasPlaced()[j].Y); + game::GetWorldMap()->GetWSquare(LocationPosition)->ChangeOWTerrain(NewPlace); + game::GetWorldMap()->RevealEnvironment(LocationPosition, 1); + } game::SaveWorldMap(); } diff --git a/Main/Source/database.cpp b/Main/Source/database.cpp index 3d49698cc..f04366509 100644 --- a/Main/Source/database.cpp +++ b/Main/Source/database.cpp @@ -707,10 +707,11 @@ template<> void databasecreator::CreateDataBaseMemberMap() ADD_MEMBER(AttachedDungeon); ADD_MEMBER(AttachedArea); ADD_MEMBER(CanBeGenerated); - ADD_MEMBER(NativeGTerrainType); + ADD_MEMBER(NativeGTerrainTypes); ADD_MEMBER(RevealEnvironmentInitially); ADD_MEMBER(HideLocationInitially); ADD_MEMBER(CanBeOnAnyTerrain); + ADD_MEMBER(IsCoreLocation); } template<> void databasecreator::CreateDataBaseMemberMap() diff --git a/Main/Source/game.cpp b/Main/Source/game.cpp index 6d877a603..4e551d084 100644 --- a/Main/Source/game.cpp +++ b/Main/Source/game.cpp @@ -239,6 +239,8 @@ int game::iCurrentDungeonTurn=-1; int CurrentSavefileVersion=-1; +int game::WorldShape = 0; + /** * IMPORTANT!!! * this is intended to be called only from Load() and NEVER on Save()! @@ -843,9 +845,11 @@ truth game::Init(cfestring& loadBaseName) InitDangerMap(); Petrus = 0; InitDungeons(); - SetCurrentArea(WorldMap = new worldmap(128, 128)); + v2 NewWorldSize = ivanconfig::GetWorldSizeConfig(); + SetCurrentArea(WorldMap = new worldmap(NewWorldSize.X, NewWorldSize.Y)); CurrentWSquareMap = WorldMap->GetMap(); WorldMap->Generate(); + GetCurrentArea()->SendNewDrawRequest(); UpdateCamera(); SendLOSUpdateRequest(); Tick = 0; @@ -3469,6 +3473,7 @@ truth game::Save(cfestring& SaveName) /* or in more readable format: time() - LastLoad + TimeAtLastLoad */ SaveFile << PlayerHasReceivedAllGodsKnownBonus; + SaveFile << WorldShape; protosystem::SaveCharacterDataBaseFlags(SaveFile); commandsystem::SaveSwapWeapons(SaveFile); DBGLN; @@ -3564,6 +3569,7 @@ int game::Load(cfestring& saveName) SaveFile >> DefaultWish >> DefaultChangeMaterial >> DefaultDetectMaterial; SaveFile >> TimePlayedBeforeLastLoad; SaveFile >> PlayerHasReceivedAllGodsKnownBonus; + SaveFile >> WorldShape; LastLoad = time(0); protosystem::LoadCharacterDataBaseFlags(SaveFile); diff --git a/Main/Source/iconf.cpp b/Main/Source/iconf.cpp index e0ba6a018..3d98f062d 100644 --- a/Main/Source/iconf.cpp +++ b/Main/Source/iconf.cpp @@ -331,6 +331,29 @@ cycleoption ivanconfig::MIDIOutputDevice( "MIDIOutputDevice", "Select an output device for the game music, or disable soundtrack.", 0, 0, // {default value, number of options to cycle through} &MIDIOutputDeviceDisplayer); +cycleoption ivanconfig::LandTypeConfig("LandTypeConfig", + "What land shapes to generate", + "Choose whether to generate continents or pangea. If Pangea is selected, the generator will make all locations reachable from the same landmass.", + 0, 2, + &LandTypeConfigDisplayer); +cycleoption ivanconfig::WorldSizeConfig("WorldSizeConfig", + "Size of the world map", + "Select a world size.", + 2, 7, + &WorldSizeConfigDisplayer); +cycleoption ivanconfig::WorldShapeConfig("WorldShapeConfig", + "Shape of the world", + "This affects the player's movement around the world. Pancake worlds are flat, and the player cannot cross the edges of the world map. Brandy snap worlds are like a cylinder, the world map wraps around the horizontal axis. Doughnut worlds are shaped like a torus, the player can wrap around the horizontal and vertical axes.", + 0, 3, + &WorldShapeConfigDisplayer); +numberoption ivanconfig::WorldSeedConfig("WorldSeedConfig", + "Select a world seed", + "0 gives a random world seed, else select a new one at your own risk. If a world cannot be generated with the given seed after a finite number of attempts, you will get a message saying the world generator encountered a bad seed, what that seed was, and a new world will be generated from a random seed instead of the one specified here.", + 0, + &WorldSeedConfigDisplayer, + &WorldSeedConfigChangeInterface, + &WorldSeedConfigChanger); + #ifndef __DJGPP__ cycleoption ivanconfig::GraphicsScale( "GraphicsScale", "Select window scaling factor", @@ -924,6 +947,89 @@ void ivanconfig::SfxVolumeChanger(numberoption* O, long What) O->Value = What; } +void ivanconfig::WorldSizeConfigDisplayer(const cycleoption* O, festring& Entry) +{ + if(O->Value == 0) + Entry << "Huge (128x128)"; + else if(O->Value == 1) + Entry << "Large (96x96)"; + else if(O->Value == 2) + Entry << "Medium (64x64)"; + else if(O->Value == 3) + Entry << "Small (49x49)"; + else if(O->Value == 4) + Entry << "Tiny (32x32)"; + else if(O->Value == 5) + Entry << "One screen (42x26)"; + else if(O->Value == 6) + Entry << "Four screens (84x52)"; + else + Entry << O->Value; +} + +void ivanconfig::LandTypeConfigDisplayer(const cycleoption* O, festring& Entry) +{ + if(O->Value == 0) + Entry << "Pangea"; + else if(O->Value == 1) + Entry << "Continents"; + else + Entry << O->Value; +} + +void ivanconfig::WorldShapeConfigDisplayer(const cycleoption* O, festring& Entry) +{ + if(O->Value == 0) + Entry << "Pancake (flat)"; + else if(O->Value == 1) + Entry << "Brandy snap (cylinder)"; + else if(O->Value == 2) + Entry << "Doughnut (torus)"; + else + Entry << O->Value; +} + +v2 ivanconfig::GetWorldSizeConfig() +{ + v2 WorldSize = v2(49, 49); + + if(WorldSizeConfig.Value == HUGE_WORLD) + WorldSize = v2(128, 128); + else if(WorldSizeConfig.Value == LARGE_WORLD) + WorldSize = v2(96, 96); + else if(WorldSizeConfig.Value == SMALL_WORLD) + WorldSize = v2(49, 49); + else if(WorldSizeConfig.Value == TINY_WORLD) + WorldSize = v2(32, 32); + else if(WorldSizeConfig.Value == ONE_SCREEN_WORLD) + WorldSize = v2(42, 26); + else if(WorldSizeConfig.Value == FOUR_SCREEN_WORLD) + WorldSize = v2(84, 52); + else + WorldSize = v2(49, 49); //SMALL_WORLD + + return WorldSize; +} + +void ivanconfig::WorldSeedConfigDisplayer(const numberoption* O, festring& Entry) +{ + Entry << O->Value << "/2147483647"; +} + +truth ivanconfig::WorldSeedConfigChangeInterface(numberoption* O) +{ + O->ChangeValue(iosystem::NumberQuestion(CONST_S("0 gives random world seed, else select new one at your own risk."), GetQuestionPos(), WHITE, !game::IsRunning())); + clearToBackgroundAfterChangeInterface(); + return false; +} + +void ivanconfig::WorldSeedConfigChanger(numberoption* O, long What) +{ + if(What < -1) + What = 0; + + O->Value = What; +} #ifndef __DJGPP__ @@ -1206,6 +1312,15 @@ void ivanconfig::Initialize() configsystem::AddOption(fsCategory,&HideWeirdHitAnimationsThatLookLikeMiss); configsystem::AddOption(fsCategory,&UseLightEmiterBasedOnVolume); + fsCategory="World Generation"; + configsystem::AddOption(fsCategory, &WorldSizeConfig); + configsystem::AddOption(fsCategory, &LandTypeConfig); + configsystem::AddOption(fsCategory, &WorldShapeConfig); + configsystem::AddOption(fsCategory, &WorldSeedConfig); + + //World shape: Flat, [Horizontal Wrap (cylinder)] + // Alt names for world shape: pancake (flat), doughnut (torus), brandy snap (cylinder). + /******************************** * LOAD AND APPLY some SETTINGS * ********************************/ diff --git a/Main/Source/worldmap.cpp b/Main/Source/worldmap.cpp index 48161397a..9bd6506cf 100644 --- a/Main/Source/worldmap.cpp +++ b/Main/Source/worldmap.cpp @@ -12,6 +12,8 @@ /* Compiled through wmapset.cpp */ +#include "FastNoise.h" + #define MAX_TEMPERATURE 27 // increase for a warmer world #define LATITUDE_EFFECT 40 // increase for more effect #define ALTITUDE_EFFECT 0.02 @@ -24,6 +26,8 @@ int DirX[8] = { -1, -1, -1, 0, 0, 1, 1, 1 }; int DirY[8] = { -1, 0, 1, -1, 1, -1, 0, 1 }; +FastNoise WorldNoise; // Create a FastNoise object + continent* worldmap::GetContinentUnder(v2 Pos) const { return Continent[ContinentBuffer[Pos.X][Pos.Y]]; } v2 worldmap::GetEntryPos(ccharacter*, int I) const @@ -32,6 +36,7 @@ continent* worldmap::GetContinent(int I) const { return Continent[I]; } int worldmap::GetAltitude(v2 Pos) { return AltitudeBuffer[Pos.X][Pos.Y]; } charactervector& worldmap::GetPlayerGroup() { return PlayerGroup; } character* worldmap::GetPlayerGroupMember(int c) { return PlayerGroup[c]; } +std::vector worldmap::GetWasPlaced() { return WasPlaced;} struct location { @@ -47,7 +52,7 @@ struct distancetoattnam { inline bool operator() (const location& loc1, const location& loc2) { - return (loc1.DistanceToAttnam < loc2.DistanceToAttnam); + return (loc1.DistanceToAttnam < loc2.DistanceToAttnam); } }; @@ -55,11 +60,12 @@ struct place { int Type; int Config; - int NativeGTerrainType; + std::vector NativeGroundTerrainTypes; truth HasBeenPlaced; truth CanBeOnAnyTerrain; + truth IsCoreLocation; - place(int t, int c, int n, truth p, truth a) : Type(t), Config(c), NativeGTerrainType(n), HasBeenPlaced(p), CanBeOnAnyTerrain(a) {} + place(int t, int c, std::vector s, truth p, truth a, truth i) : Type(t), Config(c), NativeGroundTerrainTypes(s), HasBeenPlaced(p), CanBeOnAnyTerrain(a), IsCoreLocation(i) {} }; worldmap::worldmap(int XSize, int YSize) : area(XSize, YSize) @@ -81,6 +87,8 @@ worldmap::worldmap(int XSize, int YSize) : area(XSize, YSize) continent::AltitudeBuffer = AltitudeBuffer; continent::ContinentBuffer = ContinentBuffer; continent::PossibleLocationBuffer = PossibleLocationBuffer; + + InitializeShapeDescription(); } worldmap::~worldmap() @@ -114,7 +122,7 @@ void worldmap::Save(outputfile& SaveFile) const for(ulong c = 0; c < XSizeTimesYSize; ++c) Map[0][c]->Save(SaveFile); - SaveFile << Continent << PlayerGroup; + SaveFile << Continent << PlayerGroup << WorldSeed << WasPlaced; } void worldmap::Load(inputfile& SaveFile) @@ -151,7 +159,15 @@ void worldmap::Load(inputfile& SaveFile) } CalculateNeighbourBitmapPoses(); - SaveFile >> Continent >> PlayerGroup; + SaveFile >> Continent >> PlayerGroup >> WorldSeed >> WasPlaced; +} + +void worldmap::InitializeShapeDescription() +{ + int Shape = ivanconfig::GetWorldShapeConfig(); + game::SetWorldShape(Shape); + + return; } void worldmap::Generate() @@ -160,17 +176,111 @@ void worldmap::Generate() Alloc2D(OldTypeBuffer, XSize, YSize); Alloc2D(NoIslandAltitudeBuffer, XSize, YSize); + int GeometricMeanSize = sqrt(XSize*YSize); + truth UsingPangea = !ivanconfig::GetLandTypeConfig() ? true : false; + + // Counters + int WorldAttempts = 0; + int PlacementAttempts = 0; + int ForcedWorldReGens = 0; + + // Limits + uint maxSeededWorldAttempts = 4; + uint maxForcedWorldRegenerations = 20; + uint maxDiscSamplingAttempts = 6; + + // Flags + truth ForcePlacementOnAnyTerrain = false; + truth ForceWorldReGen = false; + truth CoreLocationFailure = false; + + // World seed flags + int InitialSeed = ivanconfig::GetWorldSeedConfig(); + truth CustomSeedRequested = (!InitialSeed ? false : true); + truth InitialSeedFailed = false; + + // Determining noise distribution according to world size and shape + int WorldSize = ivanconfig::GetWorldSizeNumber(); + // A general rule-of-thumb for NoiseFrequency for the noise type and fractal type and octaves we are using here: + // NoiseFrequency = 1.0 => larger landmasses + // NoiseFrequency = 2.0 => smaller landmasses + double NoiseFrequency = 1.1; + + switch(WorldSize) + { + case HUGE_WORLD: + NoiseFrequency = (!UsingPangea ? 2.0 : 1.2); + maxSeededWorldAttempts = 4; + maxForcedWorldRegenerations = 10; + break; + case LARGE_WORLD: + NoiseFrequency = (!UsingPangea ? 2.0 : 1.2); + maxSeededWorldAttempts = 4; + maxForcedWorldRegenerations = 10; + break; + case FOUR_SCREEN_WORLD: + NoiseFrequency = (!UsingPangea ? 1.4 : 1.2); + maxSeededWorldAttempts = 4; + break; + case MEDIUM_WORLD: + NoiseFrequency = (!UsingPangea ? 1.4 : 1.3); + maxSeededWorldAttempts = 8; + break; + case SMALL_WORLD: + NoiseFrequency = (!UsingPangea ? 1.3 : 1.0); + maxSeededWorldAttempts = 8; + break; + case TINY_WORLD: + NoiseFrequency = (!UsingPangea ? 1.3 : 1.2); + maxSeededWorldAttempts = 16; + maxForcedWorldRegenerations = 40; + break; + case ONE_SCREEN_WORLD: + NoiseFrequency = (!UsingPangea ? 1.2 : 1.1); + maxSeededWorldAttempts = 16; + maxForcedWorldRegenerations = 30; + break; + default: + NoiseFrequency = 1.1; + maxSeededWorldAttempts = 4; + maxForcedWorldRegenerations = 20; + } + + WorldNoise.SetNoiseType(FastNoise::SimplexFractal); + WorldNoise.SetFrequency(NoiseFrequency); + WorldNoise.SetFractalType(FastNoise::Billow); + WorldNoise.SetFractalOctaves(4); + for(;;) { - RandomizeAltitude(); - SmoothAltitude(); + + if(CustomSeedRequested && (WorldAttempts >= maxSeededWorldAttempts) && !InitialSeedFailed) + { + InitialSeedFailed = true; + } + + if(InitialSeedFailed == true && InitialSeed != 0) + { + ADD_MESSAGE("World generator encountered bad seed: %d", InitialSeed); + InitialSeed = 0; + ForcedWorldReGens = 0; + PlacementAttempts = 0; + } + + ForceWorldReGen = false; + CoreLocationFailure = false; + + WorldAttempts++; + //RandomizeAltitude(); // Old method + PeriodicSimplexNoiseAltitude(InitialSeed); + //SmoothAltitude(); // Used to have a smoothing step here, probably not needed anymore GenerateClimate(); SmoothClimate(); CalculateContinents(); std::vector PerfectForAttnam, PerfectForNewAttnam; for(uint c = 1; c < Continent.size(); ++c) - if(Continent[c]->GetSize() > 250 && Continent[c]->GetSize() < 750 + if(Continent[c]->GetSize() > GeometricMeanSize && Continent[c]->GetSize() < (!UsingPangea ? 1024 : 16385) && Continent[c]->GetGTerrainAmount(EGForestType) && Continent[c]->GetGTerrainAmount(SnowType)) PerfectForAttnam.push_back(Continent[c]); @@ -178,9 +288,10 @@ void worldmap::Generate() if(!PerfectForAttnam.size()) continue; - v2 AttnamPos, ElpuriCavePos, NewAttnamPos, TunnelEntry, TunnelExit; + v2 NewAttnamPos, TunnelEntry, TunnelExit; truth Correct = false; continent* PetrusLikes; + truth Completed = true; // Store this before we start making islands which have no continent number. for(int x = 0; x < XSize; ++x) @@ -191,137 +302,136 @@ void worldmap::Generate() { game::BusyAnimation(); PetrusLikes = PerfectForAttnam[RAND() % PerfectForAttnam.size()]; - AttnamPos = PetrusLikes->GetRandomMember(EGForestType); - ElpuriCavePos = PetrusLikes->GetRandomMember(SnowType); + + int EGForestAmount = PetrusLikes->GetGTerrainAmount(EGForestType); + int SnowAmount = PetrusLikes->GetGTerrainAmount(SnowType); + //ADD_MESSAGE("PetrusLikes has %d EGForest and %d Snow tiles.", EGForestAmount, SnowAmount); for(int c2 = 1; c2 < 50; ++c2) { TunnelExit = PetrusLikes->GetMember(RAND() % PetrusLikes->GetSize()); - if(AttnamPos != TunnelExit && ElpuriCavePos != TunnelExit) + for(int d1 = 0; d1 < 8; ++d1) { - for(int d1 = 0; d1 < 8; ++d1) + v2 Pos = TunnelExit + game::GetMoveVector(d1); + + if(IsValidPos(Pos) && AltitudeBuffer[Pos.X][Pos.Y] <= 0) { - v2 Pos = TunnelExit + game::GetMoveVector(d1); + int Distance = 3 + (RAND() & 3); + truth Error = false; + TunnelEntry = Pos; - if(IsValidPos(Pos) && AltitudeBuffer[Pos.X][Pos.Y] <= 0) + for(int c2 = 0; c2 < Distance; ++c2) { - int Distance = 3 + (RAND() & 3); - truth Error = false; - TunnelEntry = Pos; + TunnelEntry += game::GetMoveVector(d1); - for(int c2 = 0; c2 < Distance; ++c2) + if(!IsValidPos(TunnelEntry) + || AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] > 0) { - TunnelEntry += game::GetMoveVector(d1); + Error = true; + break; + } + } + + if(Error) + continue; + + int x, y; + int Counter = 0; - if(!IsValidPos(TunnelEntry) - || AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] > 0) + for(x = TunnelEntry.X - 3; x <= TunnelEntry.X + 3; ++x) + { + for(y = TunnelEntry.Y - 3; y <= TunnelEntry.Y + 3; + ++y, ++Counter) + if(Counter != 0 && Counter != 6 + && Counter != 42 && Counter != 48 + && (!IsValidPos(x, y) + || AltitudeBuffer[x][y] > 0 + || AltitudeBuffer[x][y] < -350)) { Error = true; break; } - } if(Error) - continue; + break; + } + + if(Error) + continue; - int x, y; - int Counter = 0; + Error = true; - for(x = TunnelEntry.X - 3; x <= TunnelEntry.X + 3; ++x) + for(x = 0; x < XSize; ++x) + if(TypeBuffer[x][TunnelEntry.Y] == JungleType) { - for(y = TunnelEntry.Y - 3; y <= TunnelEntry.Y + 3; - ++y, ++Counter) - if(Counter != 0 && Counter != 6 - && Counter != 42 && Counter != 48 - && (!IsValidPos(x, y) - || AltitudeBuffer[x][y] > 0 - || AltitudeBuffer[x][y] < -350)) - { - Error = true; - break; - } - - if(Error) - break; + Error = false; + break; } - if(Error) - continue; - - Error = true; - - for(x = 0; x < XSize; ++x) - if(TypeBuffer[x][TunnelEntry.Y] == JungleType) - { - Error = false; - break; - } - - if(Error) - continue; - - Counter = 0; - - for(x = TunnelEntry.X - 2; x <= TunnelEntry.X + 2; ++x) - for(y = TunnelEntry.Y - 2; y <= TunnelEntry.Y + 2; - ++y, ++Counter) - if(Counter != 0 && Counter != 4 - && Counter != 20 && Counter != 24) - AltitudeBuffer[x][y] /= 2; - - AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] = 1 + RAND() % 50; - TypeBuffer[TunnelEntry.X][TunnelEntry.Y] = JungleType; - GetWSquare(TunnelEntry)->ChangeGWTerrain(jungle::Spawn()); - int NewAttnamIndex; - - for(NewAttnamIndex = RAND() & 7; - NewAttnamIndex == 7 - d1; - NewAttnamIndex = RAND() & 7); - - NewAttnamPos = TunnelEntry - + game::GetMoveVector(NewAttnamIndex); - static int DiagonalDir[4] = { 0, 2, 5, 7 }; - static int NotDiagonalDir[4] = { 1, 3, 4, 6 }; - static int AdjacentDir[4][2] = { { 0, 1 }, { 0, 2 }, - { 1, 3 }, { 2, 3 } }; - truth Raised[] = { false, false, false, false }; - int d2; - - for(d2 = 0; d2 < 4; ++d2) - if(NotDiagonalDir[d2] != 7 - d1 - && (NotDiagonalDir[d2] == NewAttnamIndex - || !(RAND() & 2))) - { - v2 Pos = TunnelEntry - + game::GetMoveVector(NotDiagonalDir[d2]); - AltitudeBuffer[Pos.X][Pos.Y] = 1 + RAND() % 50; - TypeBuffer[Pos.X][Pos.Y] = JungleType; - GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn()); - Raised[d2] = true; - } - - for(d2 = 0; d2 < 4; ++d2) - if(DiagonalDir[d2] != 7 - d1 - && (DiagonalDir[d2] == NewAttnamIndex - || (Raised[AdjacentDir[d2][0]] - && Raised[AdjacentDir[d2][1]] && !(RAND() & 2)))) - { - v2 Pos = TunnelEntry - + game::GetMoveVector(DiagonalDir[d2]); - AltitudeBuffer[Pos.X][Pos.Y] = 1 + RAND() % 50; - TypeBuffer[Pos.X][Pos.Y] = JungleType; - GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn()); - } + if(Error) + continue; + + Counter = 0; + + for(x = TunnelEntry.X - 2; x <= TunnelEntry.X + 2; ++x) + for(y = TunnelEntry.Y - 2; y <= TunnelEntry.Y + 2; + ++y, ++Counter) + if(Counter != 0 && Counter != 4 + && Counter != 20 && Counter != 24) + AltitudeBuffer[x][y] /= 2; + + AltitudeBuffer[TunnelEntry.X][TunnelEntry.Y] = 1 + RAND() % 50; + TypeBuffer[TunnelEntry.X][TunnelEntry.Y] = JungleType; + GetWSquare(TunnelEntry)->ChangeGWTerrain(jungle::Spawn()); + int NewAttnamIndex; + + for(NewAttnamIndex = RAND() & 7; + NewAttnamIndex == 7 - d1; + NewAttnamIndex = RAND() & 7); + + NewAttnamPos = TunnelEntry + + game::GetMoveVector(NewAttnamIndex); + static int DiagonalDir[4] = { 0, 2, 5, 7 }; + static int NotDiagonalDir[4] = { 1, 3, 4, 6 }; + static int AdjacentDir[4][2] = { { 0, 1 }, { 0, 2 }, + { 1, 3 }, { 2, 3 } }; + truth Raised[] = { false, false, false, false }; + int d2; + + for(d2 = 0; d2 < 4; ++d2) + if(NotDiagonalDir[d2] != 7 - d1 + && (NotDiagonalDir[d2] == NewAttnamIndex + || !(RAND() & 2))) + { + v2 Pos = TunnelEntry + + game::GetMoveVector(NotDiagonalDir[d2]); + AltitudeBuffer[Pos.X][Pos.Y] = 1 + RAND() % 50; + TypeBuffer[Pos.X][Pos.Y] = JungleType; + GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn()); + Raised[d2] = true; + } - Correct = true; - break; - } - } + for(d2 = 0; d2 < 4; ++d2) + if(DiagonalDir[d2] != 7 - d1 + && (DiagonalDir[d2] == NewAttnamIndex + || (Raised[AdjacentDir[d2][0]] + && Raised[AdjacentDir[d2][1]] && !(RAND() & 2)))) + { + v2 Pos = TunnelEntry + + game::GetMoveVector(DiagonalDir[d2]); + AltitudeBuffer[Pos.X][Pos.Y] = 1 + RAND() % 50; + TypeBuffer[Pos.X][Pos.Y] = JungleType; + GetWSquare(Pos)->ChangeGWTerrain(jungle::Spawn()); + } - if(Correct) + Correct = true; break; + } } + + if(Correct) + break; } if(Correct) @@ -331,133 +441,265 @@ void worldmap::Generate() if(!Correct) continue; - // Use a Poisson disc sampler to find random nicely-spaced points on the world map - // Third argument is radius. Radius = 6 produces circa 120 positions (more spaced-out), Radius = 5 produces circa 200 positions (closer together) - AllocateGlobalPossibleLocations(XSize, YSize, 6, 10); - // Create a vector of location data structures from the available locations - std::vector AvailableLocations; - - // Pick out all the locations above ground as valid candidate locations - for(int x1 = 0; x1 < XSize; ++x1) - for(int y1 = 0; y1 < YSize; ++y1) - if((PossibleLocationBuffer[x1][y1] == true) && (NoIslandAltitudeBuffer[x1][y1] > 0)) - { - AvailableLocations.push_back(location(v2(x1, y1), TypeBuffer[x1][y1], GetContinentUnder(v2(x1, y1))->GetIndex(), (AttnamPos - v2(x1, y1)).GetManhattanLength())); - } + std::vector AvailableLocations; + // Make up a vector of places from the script that need to be placed + std::vector ToBePlaced; + std::vector ShallBePlaced; + std::vector AtTheseCoordinates; - // Remove those positions that have already been taken up by core places, plus the origin. Theoretically, New Attnam and Tunnel Entry need not be checked. - std::vector ForbiddenPositions = {v2(0, 0), NewAttnamPos, TunnelEntry, TunnelExit, AttnamPos, ElpuriCavePos}; - for(uint i = 0; i < ForbiddenPositions.size(); i++) + for(int k1 = 0; k1 < maxDiscSamplingAttempts; k1++) { - AvailableLocations.erase( - std::remove_if( - AvailableLocations.begin(), - AvailableLocations.end(), - [ForbiddenPositions, i](location vec) -> truth {return vec.Position == ForbiddenPositions[i];}), - AvailableLocations.end()); - } + AvailableLocations.clear(); + ShallBePlaced.clear(); + AtTheseCoordinates.clear(); + ToBePlaced.clear(); + + // Is this appropriate here, or does it introduce a bug?? Note that reaching this point means k1 has been incremented... + if(ForceWorldReGen) + break; - // Sort the vector of global available locations according to distance to attnam. Closest places are first. - std::sort(AvailableLocations.begin(), AvailableLocations.end(), distancetoattnam()); + PlacementAttempts++; - // Make up a vector of places from the script that need to be placed - std::vector ToBePlaced; - // Pick out only the places that can be generated, and get their native ground terrain type - for(int Type = 1; Type < protocontainer::GetSize(); ++Type) - { - const owterrain::prototype* Proto = protocontainer::GetProto(Type); - const owterrain::database*const* ConfigData = Proto->GetConfigData(); - int ConfigSize = Proto->GetConfigSize(); + int PoissonRadius = 3; + // Add a check on world gen attempts here, no point using a coarse radius if ForcedWorldReGens > 3, or for tiny worlds + if((k1 <= 1) && (ForcedWorldReGens <= 2) && (WorldSize == HUGE_WORLD || WorldSize == LARGE_WORLD)) + PoissonRadius = 5; // COARSE_RADIUS + else if(k1 > 1 && k1 <= 3 && (ForcedWorldReGens <= 4) && (WorldSize != ONE_SCREEN_WORLD || WorldSize != TINY_WORLD)) + PoissonRadius = 4; // FINER_RADIUS + else + PoissonRadius = 3; // FINEST_RADIUS + + // Use a Poisson disc sampler to find random nicely-spaced points on the world map + // Third argument is radius. On a 128x128 tile map, Radius = 6 produces circa 120 positions (more spaced-out), Radius = 5 produces circa 200 positions (closer together). + AllocateGlobalPossibleLocations(XSize, YSize, PoissonRadius, 10); // default is 6 + + // Pick out all the locations above ground as valid candidate locations + for(int x1 = 0; x1 < XSize; ++x1) + for(int y1 = 0; y1 < YSize; ++y1) + if((PossibleLocationBuffer[x1][y1] == true) && (NoIslandAltitudeBuffer[x1][y1] > 0)) + { + AvailableLocations.push_back(location(v2(x1, y1), TypeBuffer[x1][y1], GetContinentUnder(v2(x1, y1))->GetIndex(), (TunnelExit - v2(x1, y1)).GetManhattanLength())); // was AttnamPos + } + + // Remove those positions that have already been taken up by core places, plus the origin. + // To get a nice boundary around the TunnelExit, we could add the neighbouring positions to the forbidden positions. Later perhaps. + std::vector ForbiddenPositions = {v2(0, 0), NewAttnamPos, TunnelEntry, TunnelExit}; + for(uint i = 0; i < ForbiddenPositions.size(); i++) + { + AvailableLocations.erase( + std::remove_if( + AvailableLocations.begin(), + AvailableLocations.end(), + [ForbiddenPositions, i](location vec) -> truth {return vec.Position == ForbiddenPositions[i];}), + AvailableLocations.end()); + } - for(int c = 0; c < ConfigSize; ++c) + // Sort the vector of global available locations according to distance to Attnam. Closest places are first. + std::sort(AvailableLocations.begin(), AvailableLocations.end(), distancetoattnam()); + + // Pick out only the places that can be generated that are not core locations, and get their native ground terrain type + for(int Type = 1; Type < protocontainer::GetSize(); ++Type) { - const owterrain::database* DataBase = ConfigData[c]; + const owterrain::prototype* Proto = protocontainer::GetProto(Type); + const owterrain::database*const* ConfigData = Proto->GetConfigData(); + int ConfigSize = Proto->GetConfigSize(); - if(!DataBase->IsAbstract && DataBase->CanBeGenerated) + for(int c = 0; c < ConfigSize; ++c) { - place ConfigID(Type, DataBase->Config, DataBase->NativeGTerrainType, false, DataBase->CanBeOnAnyTerrain); - ToBePlaced.push_back(ConfigID); + const owterrain::database* DataBase = ConfigData[c]; + + if(!DataBase->IsAbstract && DataBase->CanBeGenerated && !DataBase->IsCoreLocation) + { + const fearray &TerrainTypes = DataBase->NativeGTerrainTypes; + std::vector NativeGroundTerrainTypes; + for (uint f = 0; f < TerrainTypes.Size; ++f) + { + NativeGroundTerrainTypes.push_back(TerrainTypes[f]); + } + + place ConfigID(Type, DataBase->Config, NativeGroundTerrainTypes, false, DataBase->CanBeOnAnyTerrain, DataBase->IsCoreLocation); + ToBePlaced.push_back(ConfigID); + } } } - } - // Re-order the places so they appear in random order: - std::random_shuffle(ToBePlaced.begin(), ToBePlaced.end()); - - // Do this for as many times as there are number of continents. - for(uint c = 1; c < Continent.size(); ++c) - { - // Get the next nearest continent index by looking at the top of the available locations. - int ThisContinent = AvailableLocations[0].ContinentIndex; + // Re-order the places so they appear in random order: + std::random_shuffle(ToBePlaced.begin(), ToBePlaced.end()); - // Get each available location on the first continent. - std::vector AvailableLocationsOnThisContinent; - - // Collect all remaining available locations on this continent. - for(uint i = 0; i < AvailableLocations.size(); i++) + // Then pick out the places that are generable core locations, and get their native terrain types + for(int Type = 1; Type < protocontainer::GetSize(); ++Type) { - if(AvailableLocations[i].ContinentIndex == ThisContinent) + const owterrain::prototype* Proto = protocontainer::GetProto(Type); + const owterrain::database*const* ConfigData = Proto->GetConfigData(); + int ConfigSize = Proto->GetConfigSize(); + + for(int c = 0; c < ConfigSize; ++c) { - AvailableLocationsOnThisContinent.push_back(AvailableLocations[i]); + const owterrain::database* DataBase = ConfigData[c]; + + if(!DataBase->IsAbstract && DataBase->CanBeGenerated && DataBase->IsCoreLocation) + { + const fearray &TerrainTypes = DataBase->NativeGTerrainTypes; + std::vector NativeGroundTerrainTypes; + for (uint f = 0; f < TerrainTypes.Size; ++f) + { + NativeGroundTerrainTypes.push_back(TerrainTypes[f]); + } + + place ConfigID(Type, DataBase->Config, NativeGroundTerrainTypes, false, DataBase->CanBeOnAnyTerrain, DataBase->IsCoreLocation); + ToBePlaced.push_back(ConfigID); // Append core locations Attnam and Gloomy Caves + } } } - // Go through all the locations on the continent. These are always in order of distance to Attnam, closest at the top. - for(uint i = 0; i < AvailableLocationsOnThisContinent.size(); i++) + + // Pre-pend Attnam and Gloomy Caves to vector ToBePlaced by reversing ToBePlaced. Now Attnam and GC will be more likely to be placed first for their respective terrain type and hence appear on the same continent as the underwater tunnel exit. + std::reverse(ToBePlaced.begin(), ToBePlaced.end()); + + // Do this for as many times as there are number of continents. + for(uint c = 1; c < Continent.size(); ++c) { - // Go through all remaining places. These are always in a random order :) - for(uint j = 0; j < ToBePlaced.size(); j++) + if(UsingPangea && (c != PetrusLikes->GetIndex())) + continue; // continues to the end of loop until we are using the right continent + + // Get the next nearest continent index by looking at the top of the available locations. + int ThisContinent = AvailableLocations[0].ContinentIndex; + + // Get each available location on the first continent. + std::vector AvailableLocationsOnThisContinent; + + // Collect all remaining available locations on this continent. + for(uint i = 0; i < AvailableLocations.size(); i++) + { + if(AvailableLocations[i].ContinentIndex == ThisContinent) + { + AvailableLocationsOnThisContinent.push_back(AvailableLocations[i]); + } + } + // Go through all the locations on the continent. These are always in order of distance to Attnam, closest at the top. + for(uint i = 0; i < AvailableLocationsOnThisContinent.size(); i++) { - // If the terrain type of the available location matches that of the place, then put the place there. - if((AvailableLocationsOnThisContinent[i].GTerrainType == GetTypeOfNativeGTerrainType(ToBePlaced[j].NativeGTerrainType)) || (ToBePlaced[j].CanBeOnAnyTerrain)) + // Go through all remaining places. These are always in a random order :) + for(uint j = 0; j < ToBePlaced.size(); j++) { - owterrain* NewPlace = protocontainer::GetProto(ToBePlaced[j].Type)->Spawn(); - v2 NewPos = AvailableLocationsOnThisContinent[i].Position; + // Go through the possible terrain types for each place (NativeGTerrainTypes from owterra.dat) + for(uint j2 = 0; j2 < ToBePlaced[j].NativeGroundTerrainTypes.size(); j2++) + { + // If the terrain type of the available location matches that of the place, then put the place there. + if((AvailableLocationsOnThisContinent[i].GTerrainType == GetTypeOfNativeGTerrainType(ToBePlaced[j].NativeGroundTerrainTypes[j2])) || (ToBePlaced[j].CanBeOnAnyTerrain) || ForcePlacementOnAnyTerrain) + { + v2 NewPos = AvailableLocationsOnThisContinent[i].Position; - if(!NewPlace->HideLocationInitially()) - GetWSquare(NewPos)->ChangeOWTerrain(NewPlace); + // Check that Attnam and Gloomy Caves (core locations) appear on the same continent as PetrusLikes + if(ToBePlaced[j].IsCoreLocation && (ThisContinent != PetrusLikes->GetIndex())) + { + //ADD_MESSAGE("Failed to place core location on continent with UT exit!"); + //ADD_MESSAGE("ThisContinent: %d, PetrusLikes: %d", ThisContinent, PetrusLikes->GetIndex()); + // Just a simple flag with a break will do + CoreLocationFailure = true; + break; + } - SetEntryPos(NewPlace->GetAttachedDungeon(), NewPos); - ToBePlaced[j].HasBeenPlaced = true; + ShallBePlaced.push_back(ToBePlaced[j]); + AtTheseCoordinates.push_back(NewPos); + ToBePlaced[j].HasBeenPlaced = true; - if(NewPlace->RevealEnvironmentInitially()) - RevealEnvironment(NewPos, 1); + break; + } + //ADD_MESSAGE("There are %d places to be placed", ToBePlaced.size()); + } + if(CoreLocationFailure) + break; - break; + if(ToBePlaced[j].HasBeenPlaced == true) + break; } + if(CoreLocationFailure) + break; + + // Remove any places that have been placed, so we don't try to pick them out of our vector again. + ToBePlaced.erase( + std::remove_if( + ToBePlaced.begin(), + ToBePlaced.end(), + [](place vec) -> truth {return vec.HasBeenPlaced;}), + ToBePlaced.end()); } - // Remove any places that have been placed, so we don't try to pick them out of our vector again. - ToBePlaced.erase( + if(CoreLocationFailure) + break; + + // Remove the locations on the continent we have just examined. Whether or not they populate with places, they will not be re-visited because their terrains don't match + AvailableLocations.erase( std::remove_if( - ToBePlaced.begin(), - ToBePlaced.end(), - [](place vec) -> truth {return vec.HasBeenPlaced;}), - ToBePlaced.end()); + AvailableLocations.begin(), + AvailableLocations.end(), + [ThisContinent](location vec) -> truth {return vec.ContinentIndex == ThisContinent;}), + AvailableLocations.end()); + + AvailableLocationsOnThisContinent.clear(); + + if(ToBePlaced.empty()) + { + Completed = true; + break; // this is success and should break out to the worldgen (outer) loop. + } } - // Remove the locations on the continent we have just examined. Whether or not they populate with places, they will not be re-visited. - AvailableLocations.erase( - std::remove_if( - AvailableLocations.begin(), - AvailableLocations.end(), - [ThisContinent](location vec) -> truth {return vec.ContinentIndex == ThisContinent;}), - AvailableLocations.end()); - - AvailableLocationsOnThisContinent.clear(); - - // Two early stopping criteria. In the default case we just run out of continents to step through. - if(AvailableLocations.empty()) - break; + + // If there are still towns to be placed, or Attnam or GC not appearing on start continent, then re-roll + if(!ToBePlaced.empty() || CoreLocationFailure) + { + AvailableLocations.clear(); + ShallBePlaced.clear(); + AtTheseCoordinates.clear(); + ToBePlaced.clear(); - if(ToBePlaced.empty()) - break; + if(k1 >= maxDiscSamplingAttempts - 1) + ForceWorldReGen = true; + + if(ForcedWorldReGens >= maxForcedWorldRegenerations) + { + //ADD_MESSAGE("Forcing placement on any terrain..."); + ForcePlacementOnAnyTerrain = true; + } + + continue; // this continue statement breaks out only to the disc re-sample loop. + } + + if(Completed) + { + ForceWorldReGen = false; + break; // prevents further disc sampling + } + } //for loop for poisson disc sampling attempts + if(ForceWorldReGen) + { + ForcedWorldReGens++; + continue; + } + + if(ShallBePlaced.size() != AtTheseCoordinates.size()) + { + ABORT("Mismatched location placement!"); // In theory should never get to here } + else + { + // Actually spawn the worldmap locations in their final positions + for(uint j = 0; j < ShallBePlaced.size(); j++) + { + owterrain* NewPlace = protocontainer::GetProto(ShallBePlaced[j].Type)->Spawn(); + if(!NewPlace->HideLocationInitially()) + GetWSquare(AtTheseCoordinates[j])->ChangeOWTerrain(NewPlace); + + SetEntryPos(NewPlace->GetAttachedDungeon(), AtTheseCoordinates[j]); + if(NewPlace->RevealEnvironmentInitially()) + RevealEnvironment(AtTheseCoordinates[j], 1); - GetWSquare(AttnamPos)->ChangeOWTerrain(attnam::Spawn()); - SetEntryPos(ATTNAM, AttnamPos); - RevealEnvironment(AttnamPos, 1); + WasPlaced.emplace_back(v2(ShallBePlaced[j].Type, NewPlace->GetAttachedDungeon())); + } + } + GetWSquare(NewAttnamPos)->ChangeOWTerrain(newattnam::Spawn()); SetEntryPos(NEW_ATTNAM, NewAttnamPos); - SetEntryPos(ELPURI_CAVE, ElpuriCavePos); GetWSquare(TunnelEntry)->ChangeOWTerrain(underwatertunnel::Spawn()); SetEntryPos(UNDER_WATER_TUNNEL, TunnelEntry); GetWSquare(TunnelExit)->ChangeOWTerrain(underwatertunnelexit::Spawn()); @@ -471,17 +713,74 @@ void worldmap::Generate() delete [] OldAltitudeBuffer; delete [] OldTypeBuffer; delete [] NoIslandAltitudeBuffer; + + //ADD_MESSAGE("World generation attempts, %d", WorldAttempts); + //ADD_MESSAGE("Forced world re-generations, %d", ForcedWorldReGens); + //ADD_MESSAGE("Location placement attempts, %d", PlacementAttempts); + + // Add a message to indicate that dungeons may show up on weird terrains + if(ForcePlacementOnAnyTerrain == true) + ADD_MESSAGE("\"It's the world %s, but not as we know it...\"", ivanconfig::GetDefaultPetName().CStr()); } void worldmap::RandomizeAltitude() { game::BusyAnimation(); + + WorldSeed = 0; for(int x = 0; x < XSize; ++x) for(int y = 0; y < YSize; ++y) AltitudeBuffer[x][y] = 4000 - RAND() % 8000; } +void worldmap::PeriodicSimplexNoiseAltitude(int InitialSeed) +{ + game::BusyAnimation(); + + if((InitialSeed <= 0) || (InitialSeed >= 2147483647)) + WorldSeed = RAND() % 2147483647; + else + WorldSeed = InitialSeed; + + WorldNoise.SetSeed(WorldSeed); + + float multiplier = 1.0 / ( 2.0 * FPI ); + + for(int x = 0; x < XSize; ++x) + { + for(int y = 0; y < YSize; ++y) + { + float s = x / (float)XSize; + float t = y / (float)YSize; + + float nx = (float)cos(s * 2.0 * FPI) * multiplier; + float ny = (float)cos(t * 2.0 * FPI) * multiplier; + float nz = (float)sin(s * 2.0 * FPI) * multiplier; + float nw = (float)sin(t * 2.0 * FPI) * multiplier; + + AltitudeBuffer[x][y] = (short)(1000 * WorldNoise.GetNoise(nx, ny, nz, nw)) + 600; + // Could add frog shape in here and blend to get Valpuri-shaped continent + } + } +} + +void worldmap::SimplexNoiseAltitude() +{ + game::BusyAnimation(); + + WorldSeed = RAND() % 2147483647; + WorldNoise.SetSeed(WorldSeed); + + for (int x = 0; x < XSize; x++) + { + for (int y = 0; y < YSize; y++) + { + AltitudeBuffer[x][y] = (short)(1000 * WorldNoise.GetNoise(x, y)); + } + } +} + void worldmap::SmoothAltitude() { for(int c = 0; c < 10; ++c) @@ -922,9 +1221,10 @@ void worldmap::AllocateGlobalPossibleLocations(int XSize, int YSize, int Radius, // Allocate a grid and a queue memset(PossibleLocationBuffer[0], 0, XSizeTimesYSize * sizeof(uchar)); - std::vector Grid(GridCellWidth*GridCellHeight, v2(0, 0)); + Grid.clear(); - std::vector Queue; + for(int k = 0; k < GridCellWidth*GridCellHeight; k++) + Grid.emplace_back(v2(0, 0)); int QueueSize = 0; int SampleSize = 0; @@ -936,7 +1236,8 @@ void worldmap::AllocateGlobalPossibleLocations(int XSize, int YSize, int Radius, // Do the SetPoint function v2 Sample = v2(XPos, YPos); - Queue.push_back(Sample); + Queue.clear(); + Queue.emplace_back(Sample); // Find where (x,y) sits in the grid int XIndex = int(XPos / CellSize); int YIndex = int(YPos / CellSize); @@ -946,6 +1247,8 @@ void worldmap::AllocateGlobalPossibleLocations(int XSize, int YSize, int Radius, QueueSize += 1; SampleSize += 1; + v2 NewSample = v2(0, 0); + while(QueueSize) { int XIdx = int((RAND() % 100 / 100.0) * QueueSize); @@ -954,8 +1257,8 @@ void worldmap::AllocateGlobalPossibleLocations(int XSize, int YSize, int Radius, { double Angle = 2 * FPI * (RAND() % 100) / 100.0; double Hypotenuse = sqrt( A * (RAND() % 100) / 100.0 + RadiusSquared); - int XPos = int(Sample.X + Hypotenuse*cos(Angle)); - int YPos = int(Sample.Y + Hypotenuse*sin(Angle)); + XPos = int(Sample.X + Hypotenuse*cos(Angle)); + YPos = int(Sample.Y + Hypotenuse*sin(Angle)); if((XPos >= 0) && (XPos < XSize)) { if((YPos >= 0) && (YPos < YSize)) @@ -963,8 +1266,8 @@ void worldmap::AllocateGlobalPossibleLocations(int XSize, int YSize, int Radius, if(PoissonDiscSamplerCheckDistance(XPos, YPos, CellSize, GridCellWidth, GridCellHeight, RadiusSquared, Grid)) { // Do the SetPoint function - v2 NewSample = v2(XPos, YPos); - Queue.push_back(NewSample); + NewSample = v2(XPos, YPos); + Queue.emplace_back(NewSample); // Find where (x,y) sits in the grid XIndex = int(XPos / CellSize); YIndex = int(YPos / CellSize); diff --git a/Script/char.dat b/Script/char.dat index 05608de48..7f4ca8566 100644 --- a/Script/char.dat +++ b/Script/char.dat @@ -1502,7 +1502,7 @@ priest FriendlyReplies = { 14, - "@Dd talks to you: \"Valpurus the Great Frog is the highest of all gods. The Wise know that the world is really a square pancake which He carries on His back. This is why this Cathedral and the whole city of Attnam is dedicated to His worship.\"", + "@Dd talks to you: \"Valpurus the Great Frog is the highest of all gods. The Wise know that the world is really a @ws which He carries on His back. This is why this Cathedral and the whole city of Attnam is dedicated to His worship.\"", "\"The souls of the virtuous, the devout and the faithful bath forever in the radiant glory of Valpurus and sing praises on His greatness. The souls of sinners, heretics and unbelievers are swallowed by Mortifer and damned to relive their worst nightmares for all eternity!\"", "\"The Cathedral of Valpurus has no windows, for it is written in the Holy Book of Valpurus: 'Windows is Evil.'\"", "\"I am the Cardinal of Truth, therefore everything I say is truth.\"", diff --git a/Script/owterra.dat b/Script/owterra.dat index e0a115e28..dfa6d3fb5 100644 --- a/Script/owterra.dat +++ b/Script/owterra.dat @@ -31,10 +31,11 @@ owterrain UsesLongArticle = false; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = 0; + NativeGTerrainTypes = { 1, 0; } RevealEnvironmentInitially = false; /* Overridden by the world map generator for core locations */ HideLocationInitially = false; /* Overridden by the world map generator for core locations */ CanBeOnAnyTerrain = false; /* Overridden by the world map generator for core locations */ + IsCoreLocation = false; } attnam @@ -43,8 +44,12 @@ attnam NameStem = "mighty cathedral reaching the clouds"; UsesLongArticle = false; AttachedDungeon = ATTNAM; - CanBeGenerated = false; /* Overridden by the world map generator */ - NativeGTerrainType = EVERGREEN_FOREST; + CanBeGenerated = true; + NativeGTerrainTypes = { 1, EVERGREEN_FOREST; } + RevealEnvironmentInitially = true; + HideLocationInitially = false; + CanBeOnAnyTerrain = false; + IsCoreLocation = true; } elpuricave @@ -53,8 +58,12 @@ elpuricave NameStem = "hideous cave entrance radiating pure evil"; UsesLongArticle = false; AttachedDungeon = ELPURI_CAVE; - CanBeGenerated = false; /* Overridden by the world map generator */ - NativeGTerrainType = TUNDRA; + CanBeGenerated = true; + NativeGTerrainTypes = { 1, TUNDRA; } + RevealEnvironmentInitially = true; + HideLocationInitially = false; + CanBeOnAnyTerrain = false; + IsCoreLocation = true; } newattnam @@ -64,7 +73,8 @@ newattnam UsesLongArticle = false; AttachedDungeon = NEW_ATTNAM; CanBeGenerated = false; /* Overridden by the world map generator */ - NativeGTerrainType = JUNGLE; + NativeGTerrainTypes = { 1, JUNGLE; } + /*IsCoreLocation = true;*/ } underwatertunnel @@ -74,7 +84,8 @@ underwatertunnel UsesLongArticle = true; AttachedDungeon = UNDER_WATER_TUNNEL; CanBeGenerated = false; /* Overridden by the world map generator */ - NativeGTerrainType = JUNGLE; + NativeGTerrainTypes = { 1, JUNGLE; } + /*IsCoreLocation = true;*/ } underwatertunnelexit @@ -85,7 +96,8 @@ underwatertunnelexit AttachedDungeon = UNDER_WATER_TUNNEL; AttachedArea = 2; /*underwater tunnel level 3*/ CanBeGenerated = false; /* Overridden by the world map generator */ - NativeGTerrainType = JUNGLE; + NativeGTerrainTypes = { 1, JUNGLE; } + /*IsCoreLocation = true;*/ } aslonacastle @@ -96,7 +108,7 @@ aslonacastle AttachedDungeon = ASLONA_CASTLE; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = LEAFY_FOREST; + NativeGTerrainTypes = { 1, LEAFY_FOREST; } } rebelcamp @@ -107,7 +119,7 @@ rebelcamp AttachedDungeon = REBEL_CAMP; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = STEPPE; + NativeGTerrainTypes = { 1, STEPPE; } } goblinfort @@ -118,7 +130,7 @@ goblinfort AttachedDungeon = GOBLIN_FORT; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = EVERGREEN_FOREST; + NativeGTerrainTypes = { 1, EVERGREEN_FOREST; } } fungalcave @@ -128,7 +140,7 @@ fungalcave AttachedDungeon = FUNGAL_CAVE; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = JUNGLE; + NativeGTerrainTypes = { 1, JUNGLE; } } pyramid @@ -138,7 +150,7 @@ pyramid AttachedDungeon = PYRAMID; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = DESERT; + NativeGTerrainTypes = { 2, DESERT, JUNGLE; } } blackmarket @@ -149,248 +161,7 @@ blackmarket AttachedDungeon = BLACK_MARKET; CanBeGenerated = true; HideLocationInitially = true; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAA -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = MONDEDR; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = JUNGLE; -} - -locationAB -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = IRINOX; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = JUNGLE; -} - -locationAC -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = DARK_FOREST; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = JUNGLE; -} - -locationAD -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = JUNGLE; -} - -locationAE -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = GLACIER; -} - -locationAF -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = GLACIER; -} - -locationAG -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = GLACIER; -} - -locationAH -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = GLACIER; -} - -locationAI -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAJ -{ - BitmapPos = 0, 64; - NameStem = "a house"; - AttachedDungeon = 0; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAK -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAL -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAM -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = LEAFY_FOREST; -} - -locationAN -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = EVERGREEN_FOREST; -} - -locationAO -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = EVERGREEN_FOREST; -} - -locationAP -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = DESERT; -} - -locationAQ -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = DESERT; -} - -locationAR -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = STEPPE; -} - -locationAS -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = STEPPE; -} - -locationAT -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = STEPPE; -} - -locationAU -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = STEPPE; -} - -locationAV -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = STEPPE; + NativeGTerrainTypes = { 1, LEAFY_FOREST; } } xinrochtomb @@ -401,46 +172,45 @@ xinrochtomb AttachedDungeon = XINROCH_TOMB; AttachedArea = 0; CanBeGenerated = true; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 2, GLACIER, TUNDRA; } RevealEnvironmentInitially = false; HideLocationInitially = true; - CanBeOnAnyTerrain = true; } -locationAX +locationA { BitmapPos = 0, 64; NameStem = "empty area"; UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; + AttachedDungeon = MONDEDR; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, TUNDRA; } } -locationAY +locationB { BitmapPos = 0, 64; NameStem = "empty area"; UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; + AttachedDungeon = IRINOX; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, JUNGLE; } } -locationAZ +locationC { BitmapPos = 0, 64; NameStem = "empty area"; UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; + AttachedDungeon = DARK_FOREST; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 2, LEAFY_FOREST, EVERGREEN_FOREST; } } -locationBA +locationD { BitmapPos = 0, 64; NameStem = "empty area"; @@ -448,10 +218,10 @@ locationBA AttachedDungeon = EMPTY_AREA; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, LEAFY_FOREST; } } -locationBB +locationE { BitmapPos = 0, 64; NameStem = "empty area"; @@ -459,21 +229,21 @@ locationBB AttachedDungeon = EMPTY_AREA; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, STEPPE; } } -locationBC +locationF { BitmapPos = 0, 64; - NameStem = "empty area"; + NameStem = "Erno's House"; UsesLongArticle = true; AttachedDungeon = EMPTY_AREA; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, TUNDRA; } } -locationBD +locationG { BitmapPos = 0, 64; NameStem = "empty area"; @@ -481,10 +251,10 @@ locationBD AttachedDungeon = EMPTY_AREA; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, TUNDRA; } } -locationBE +locationH { BitmapPos = 0, 64; NameStem = "empty area"; @@ -492,16 +262,15 @@ locationBE AttachedDungeon = EMPTY_AREA; AttachedArea = 0; CanBeGenerated = false; - NativeGTerrainType = TUNDRA; + NativeGTerrainTypes = { 1, GLACIER; } } -locationBF -{ - BitmapPos = 0, 64; - NameStem = "empty area"; - UsesLongArticle = true; - AttachedDungeon = EMPTY_AREA; - AttachedArea = 0; - CanBeGenerated = false; - NativeGTerrainType = TUNDRA; -} +/* Previously, there were 31 additional locations, with the following WTerrain distributions: +JUNGLE x4 +GLACIER x4 +LEAFY_FOREST x5 +EVERGREEN_FOREST x2 +DESERT x2 +STEPPE x4 +TUNDRA x10 +*/