diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/NoiseAddon.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/NoiseAddon.java index 86743f2cc..1c226711a 100644 --- a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/NoiseAddon.java +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/NoiseAddon.java @@ -30,6 +30,7 @@ import com.dfsek.terra.addons.noise.config.templates.noise.fractal.BrownianMotio import com.dfsek.terra.addons.noise.config.templates.noise.fractal.PingPongTemplate; import com.dfsek.terra.addons.noise.config.templates.noise.fractal.RidgedFractalTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.ClampNormalizerTemplate; +import com.dfsek.terra.addons.noise.config.templates.normalizer.ExpressionNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.NormalNormalizerTemplate; import com.dfsek.terra.addons.noise.config.templates.normalizer.PosterizationNormalizerTemplate; @@ -134,7 +135,7 @@ public class NoiseAddon implements AddonInitializer { Map packSamplers = new LinkedHashMap<>(); Map packFunctions = new LinkedHashMap<>(); noiseRegistry.register(addon.key("EXPRESSION"), () -> new ExpressionFunctionTemplate(packSamplers, packFunctions)); - + noiseRegistry.register(addon.key("EXPRESSION_NORMALIZER"), () -> new ExpressionNormalizerTemplate(packSamplers, packFunctions)); NoiseConfigPackTemplate template = event.loadTemplate(new NoiseConfigPackTemplate()); packSamplers.putAll(template.getSamplers()); diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/noise/ExpressionFunctionTemplate.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/noise/ExpressionFunctionTemplate.java index a15cc8e61..e401aa0cf 100644 --- a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/noise/ExpressionFunctionTemplate.java +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/noise/ExpressionFunctionTemplate.java @@ -8,7 +8,6 @@ package com.dfsek.terra.addons.noise.config.templates.noise; import com.dfsek.paralithic.eval.tokenizer.ParseException; -import com.dfsek.paralithic.functions.Function; import com.dfsek.tectonic.api.config.template.annotations.Default; import com.dfsek.tectonic.api.config.template.annotations.Value; @@ -19,17 +18,16 @@ import java.util.Map; import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler; import com.dfsek.terra.addons.noise.config.templates.FunctionTemplate; import com.dfsek.terra.addons.noise.config.templates.SamplerTemplate; -import com.dfsek.terra.addons.noise.paralithic.defined.UserDefinedFunction; -import com.dfsek.terra.addons.noise.paralithic.noise.NoiseFunction2; -import com.dfsek.terra.addons.noise.paralithic.noise.NoiseFunction3; import com.dfsek.terra.addons.noise.samplers.noise.ExpressionFunction; import com.dfsek.terra.api.config.meta.Meta; import com.dfsek.terra.api.noise.NoiseSampler; +import static com.dfsek.terra.addons.noise.paralithic.FunctionUtil.convertFunctionsAndSamplers; + @SuppressWarnings({ "FieldMayBeFinal", "unused" }) public class ExpressionFunctionTemplate extends SamplerTemplate { - private final Map otherFunctions; + private final Map globalSamplers; private final Map globalFunctions; @Value("variables") @Default @@ -43,44 +41,19 @@ public class ExpressionFunctionTemplate extends SamplerTemplate functions = new LinkedHashMap<>(); - public ExpressionFunctionTemplate(Map otherFunctions, Map samplers) { - this.otherFunctions = otherFunctions; - this.globalFunctions = samplers; + public ExpressionFunctionTemplate(Map globalSamplers, Map globalFunctions) { + this.globalSamplers = globalSamplers; + this.globalFunctions = globalFunctions; } @Override public NoiseSampler get() { + var mergedFunctions = new HashMap<>(globalFunctions); mergedFunctions.putAll(functions); + var mergedSamplers = new HashMap<>(globalSamplers); mergedSamplers.putAll(samplers); try { - Map noiseFunctionMap = generateFunctions(); - return new ExpressionFunction(noiseFunctionMap, expression, vars); + return new ExpressionFunction(convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars); } catch(ParseException e) { throw new RuntimeException("Failed to parse expression.", e); } } - - private Map generateFunctions() throws ParseException { - Map noiseFunctionMap = new HashMap<>(); - - for(Map.Entry entry : globalFunctions.entrySet()) { - noiseFunctionMap.put(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue())); - } - - for(Map.Entry entry : functions.entrySet()) { - noiseFunctionMap.put(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue())); - } - - otherFunctions.forEach((id, function) -> { - if(function.getDimensions() == 2) { - noiseFunctionMap.put(id, new NoiseFunction2(function.getSampler())); - } else noiseFunctionMap.put(id, new NoiseFunction3(function.getSampler())); - }); - - samplers.forEach((id, function) -> { - if(function.getDimensions() == 2) { - noiseFunctionMap.put(id, new NoiseFunction2(function.getSampler())); - } else noiseFunctionMap.put(id, new NoiseFunction3(function.getSampler())); - }); - - return noiseFunctionMap; - } } diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/normalizer/ExpressionNormalizerTemplate.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/normalizer/ExpressionNormalizerTemplate.java new file mode 100644 index 000000000..97318d388 --- /dev/null +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/config/templates/normalizer/ExpressionNormalizerTemplate.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.noise.config.templates.normalizer; + +import com.dfsek.paralithic.eval.tokenizer.ParseException; +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; + +import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler; +import com.dfsek.terra.addons.noise.config.templates.FunctionTemplate; +import com.dfsek.terra.addons.noise.normalizer.ExpressionNormalizer; +import com.dfsek.terra.api.config.meta.Meta; +import com.dfsek.terra.api.noise.NoiseSampler; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import static com.dfsek.terra.addons.noise.paralithic.FunctionUtil.convertFunctionsAndSamplers; + + +@SuppressWarnings({ "unused", "FieldMayBeFinal" }) +public class ExpressionNormalizerTemplate extends NormalizerTemplate { + + private final Map globalSamplers; + private final Map globalFunctions; + + @Value("expression") + private @Meta String expression; + + @Value("variables") + @Default + private @Meta Map vars = new HashMap<>(); + + @Value("samplers") + @Default + private @Meta LinkedHashMap samplers = new LinkedHashMap<>(); + + @Value("functions") + @Default + private @Meta LinkedHashMap functions = new LinkedHashMap<>(); + + public ExpressionNormalizerTemplate(Map globalSamplers, Map globalFunctions) { + this.globalSamplers = globalSamplers; + this.globalFunctions = globalFunctions; + } + + @Override + public NoiseSampler get() { + var mergedFunctions = new HashMap<>(globalFunctions); mergedFunctions.putAll(functions); + var mergedSamplers = new HashMap<>(globalSamplers); mergedSamplers.putAll(samplers); + try { + return new ExpressionNormalizer(function, convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars); + } catch(ParseException e) { + throw new RuntimeException("Failed to parse expression.", e); + } + } +} diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/normalizer/ExpressionNormalizer.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/normalizer/ExpressionNormalizer.java new file mode 100644 index 000000000..95c607f76 --- /dev/null +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/normalizer/ExpressionNormalizer.java @@ -0,0 +1,33 @@ +package com.dfsek.terra.addons.noise.normalizer; + +import com.dfsek.paralithic.Expression; +import com.dfsek.paralithic.eval.parser.Parser; +import com.dfsek.paralithic.eval.parser.Scope; +import com.dfsek.paralithic.eval.tokenizer.ParseException; +import com.dfsek.paralithic.functions.Function; + +import com.dfsek.terra.api.noise.NoiseSampler; + +import java.util.Map; + + +public class ExpressionNormalizer extends Normalizer { + + private final Expression expression; + + public ExpressionNormalizer(NoiseSampler sampler, Map functions, String eq, Map vars) + throws ParseException { + super(sampler); + Parser p = new Parser(); + Scope scope = new Scope(); + scope.addInvocationVariable("in"); + vars.forEach(scope::create); + functions.forEach(p::registerFunction); + expression = p.parse(eq, scope); + } + + @Override + public double normalize(double in) { + return expression.evaluate(in); + } +} diff --git a/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/FunctionUtil.java b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/FunctionUtil.java new file mode 100644 index 000000000..f968f5bad --- /dev/null +++ b/common/addons/config-noise-function/src/main/java/com/dfsek/terra/addons/noise/paralithic/FunctionUtil.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.addons.noise.paralithic; + +import com.dfsek.paralithic.eval.tokenizer.ParseException; +import com.dfsek.paralithic.functions.Function; + +import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler; +import com.dfsek.terra.addons.noise.config.templates.FunctionTemplate; +import com.dfsek.terra.addons.noise.paralithic.defined.UserDefinedFunction; +import com.dfsek.terra.addons.noise.paralithic.noise.NoiseFunction2; +import com.dfsek.terra.addons.noise.paralithic.noise.NoiseFunction3; + +import java.util.HashMap; +import java.util.Map; + + +public class FunctionUtil { + private FunctionUtil() {} + + public static Map convertFunctionsAndSamplers(Map functions, + Map samplers) throws ParseException { + Map functionMap = new HashMap<>(); + for(Map.Entry entry : functions.entrySet()) { + functionMap.put(entry.getKey(), UserDefinedFunction.newInstance(entry.getValue())); + } + samplers.forEach((id, sampler) -> functionMap.put(id, + sampler.getDimensions() == 2 ? + new NoiseFunction2(sampler.getSampler()) : + new NoiseFunction3(sampler.getSampler()))); + return functionMap; + } +}