diff --git a/data/file_list.yml b/data/file_list.yml index 65d72b94..d11a8b82 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -260640,11 +260640,11 @@ Library/Math/MathUtil.o: - offset: 0x9312b8 size: 100 label: _ZN2al11calcFractalEffjfffb - status: NotDecompiled + status: Matching - offset: 0x93131c size: 116 label: _ZN2al16calcMultiFractalEfffjfffb - status: NotDecompiled + status: Matching - offset: 0x931390 size: 112 label: _ZN2al22calcNormalDistributionEfff @@ -294004,35 +294004,35 @@ Project/Math/FractalGenerator.o: label: - _ZN2al16FractalGeneratorC1Ejfff - _ZN2al16FractalGeneratorC2Ejfff - status: NotDecompiled + status: Matching - offset: 0xa6a884 size: 20 label: _ZN2al16FractalGenerator8setParamEjfff - status: NotDecompiled + status: Matching - offset: 0xa6a898 size: 220 label: _ZN2al16FractalGenerator11calcFractalEffb - status: NotDecompiled + status: Matching - offset: 0xa6a974 size: 228 label: _ZN2al16FractalGenerator21makeSmoothPerlinNoiseEff - status: NotDecompiled + status: Matching - offset: 0xa6aa58 size: 340 label: _ZN2al16FractalGenerator15makePerlinNoiseEff - status: NotDecompiled + status: Matching - offset: 0xa6abac size: 232 label: _ZN2al16FractalGenerator16calcMultiFractalEfffb - status: NotDecompiled + status: Matching - offset: 0xa6ac94 size: 84 label: _ZN2al16FractalGenerator10makeRandomEii - status: NotDecompiled + status: Matching - offset: 0xa6ace8 size: 452 label: _ZN2al16FractalGenerator16makeSmoothRandomEii - status: NotDecompiled + status: Matching Project/Memory/MemorySystem.o: '.text': - offset: 0xa6aeac diff --git a/lib/al/Library/Math/FractalGenerator.cpp b/lib/al/Library/Math/FractalGenerator.cpp new file mode 100644 index 00000000..ffffa209 --- /dev/null +++ b/lib/al/Library/Math/FractalGenerator.cpp @@ -0,0 +1,122 @@ +#include "Library/Math/FractalGenerator.h" + +#include "Library/Math/MathUtil.h" + +namespace al { +FractalGenerator::FractalGenerator(u32 permutations, f32 amplitude, f32 scale, + f32 nextOrderAmplitude) + : mPermutations(permutations), mAmplitude(amplitude), mScale(scale), + mNextOrderAmplitude(nextOrderAmplitude) {} + +void FractalGenerator::setParam(u32 permutations, f32 amplitude, f32 scale, + f32 nextOrderAmplitude) { + mPermutations = permutations; + mAmplitude = amplitude; + mScale = scale; + mNextOrderAmplitude = nextOrderAmplitude; +} + +f32 FractalGenerator::calcFractal(f32 x, f32 y, bool useSmoothPerlingNoise) { + f32 value = 0.0f; + + f32 amplitude = mAmplitude; + f32 scale = mScale; + for (s32 i = 0; i < (s32)(mPermutations - 1); i++) { + if (useSmoothPerlingNoise) + value += makeSmoothPerlinNoise(scale * x, scale * y) * amplitude; + else + value += makePerlinNoise(scale * x, scale * y) * amplitude; + + scale *= 2; + amplitude *= mNextOrderAmplitude; + } + + return value; +} + +f32 FractalGenerator::makeSmoothPerlinNoise(f32 x, f32 y) { + s32 gridX = (s32)x; + s32 gridY = (s32)y; + f32 fracX = x - gridX; + f32 fracY = y - gridY; + + // NOTE: ASM is using an undef call for subsequent calls. This is not a bug since + // makeSmoothRandom doesn't make use of any class members. This is probably a compiler + // optimization error + FractalGenerator* gen; + f32 r00 = makeSmoothRandom(gridX, gridY); + f32 r10 = gen->makeSmoothRandom(gridX + 1, gridY); + f32 r01 = gen->makeSmoothRandom(gridX, gridY + 1); + f32 r11 = gen->makeSmoothRandom(gridX + 1, gridY + 1); + + return lerpValue(lerpValue(r00, r10, easeInOut(fracX)), lerpValue(r01, r11, easeInOut(fracX)), + easeInOut(fracY)); +} + +f32 FractalGenerator::makePerlinNoise(f32 x, f32 y) { + s32 gridX = (s32)x; + s32 gridY = (s32)y; + f32 fracX = x - gridX; + f32 fracY = y - gridY; + + f32 r00 = makeRandom(gridX, gridY); + f32 r10 = makeRandom(gridX + 1, gridY); + f32 r01 = makeRandom(gridX, gridY + 1); + f32 r11 = makeRandom(gridX + 1, gridY + 1); + + return lerpValue(lerpValue(r00, r10, easeInOut(fracX)), lerpValue(r01, r11, easeInOut(fracX)), + easeInOut(fracY)); +} + +f32 FractalGenerator::calcMultiFractal(f32 x, f32 y, f32 baseAmplitude, + bool useSmoothPerlingNoise) { + f32 value = 1.0f; + + f32 amplitude = mAmplitude; + f32 scale = mScale; + for (s32 i = 0; i < (s32)(mPermutations - 1); i++) { + if (useSmoothPerlingNoise) + value *= baseAmplitude * makeSmoothPerlinNoise(scale * x, scale * y) * amplitude; + else + value *= baseAmplitude * makePerlinNoise(scale * x, scale * y) * amplitude; + + scale *= 2; + amplitude *= mNextOrderAmplitude; + } + + return value; +} + +inline s32 makeSeed(s32 x, s32 y) { + s32 seed = x + y * 57; + seed ^= seed << 13; + return seed; +} + +inline f32 makeNoise(s32 seed) { + // NOTE: The only true random are all these magic values + s32 hash = (seed * seed * 0x4bd9 + 0x2e59b) * seed + 0x4bcb4b; + return static_cast(hash & 0x4b746f) / -3354521.0f; +} + +f32 FractalGenerator::makeRandom(s32 x, s32 y) { + return makeNoise(makeSeed(x, y)) + 1.0f; +} + +f32 FractalGenerator::makeSmoothRandom(s32 x, s32 y) { + constexpr f32 weight_corners = 0.25f; + constexpr f32 weight_sides = 0.5f; + constexpr f32 weight_center = 0.25f; + + f32 corners = (makeRandom(x - 1, y - 1) + makeRandom(x + 1, y - 1) + makeRandom(x - 1, y + 1) + + makeRandom(x + 1, y + 1)) * + ((1.0f / 4.0f) * weight_corners); + f32 sides = (makeRandom(x - 1, y) + makeRandom(x + 1, y) + makeRandom(x, y - 1) + + makeRandom(x, y + 1)) * + ((1.0f / 4.0f) * weight_sides); + ; + f32 center = makeRandom(x, y) * weight_center; + return corners + sides + center; +} + +} // namespace al diff --git a/lib/al/Library/Math/FractalGenerator.h b/lib/al/Library/Math/FractalGenerator.h new file mode 100644 index 00000000..c0f34293 --- /dev/null +++ b/lib/al/Library/Math/FractalGenerator.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace al { + +class FractalGenerator { +public: + FractalGenerator(u32 permutations, f32 amplitude, f32 scale, f32 nextOrderAmplitude); + + void setParam(u32 permutations, f32 amplitude, f32 scale, f32 nextOrderAmplitude); + f32 calcFractal(f32 x, f32 y, bool useSmoothPerlingNoise); + f32 makeSmoothPerlinNoise(f32 x, f32 y); + f32 makePerlinNoise(f32 x, f32 y); + f32 calcMultiFractal(f32 x, f32 y, f32 baseAmplitude, bool useSmoothPerlingNoise); + f32 makeRandom(s32 x, s32 y); + f32 makeSmoothRandom(s32 x, s32 y); + +private: + u32 mPermutations; + f32 mAmplitude; + f32 mScale; + f32 mNextOrderAmplitude; +}; + +} // namespace al diff --git a/lib/al/Library/Math/MathUtil.cpp b/lib/al/Library/Math/MathUtil.cpp index cbfa64cd..1e2ac131 100644 --- a/lib/al/Library/Math/MathUtil.cpp +++ b/lib/al/Library/Math/MathUtil.cpp @@ -7,6 +7,7 @@ #include #include "Library/Base/HashCodeUtil.h" +#include "Library/Math/FractalGenerator.h" #include "Library/Matrix/MatrixUtil.h" namespace al { @@ -1742,6 +1743,18 @@ f32 convertSpringEnergyToSpeed(f32 a, f32 b, f32 c) { return sead::Mathf::sqrt(a * c * a + b * b); } +f32 calcFractal(f32 x, f32 y, u32 permutations, f32 amplitude, f32 scale, f32 nextOrderAmplitude, + bool useSmoothPerlingNoise) { + FractalGenerator generator(permutations, amplitude, scale, nextOrderAmplitude); + return generator.calcFractal(x, y, useSmoothPerlingNoise); +} + +f32 calcMultiFractal(f32 x, f32 y, f32 baseAmplitude, u32 permutations, f32 amplitude, f32 scale, + f32 nextOrderAmplitude, bool useSmoothPerlingNoise) { + FractalGenerator generator(permutations, amplitude, scale, nextOrderAmplitude); + return generator.calcMultiFractal(x, y, baseAmplitude, useSmoothPerlingNoise); +} + const char* axisIndexToString(s32 axisIndex) { switch (axisIndex) { case 0: diff --git a/lib/al/Library/Math/MathUtil.h b/lib/al/Library/Math/MathUtil.h index 86ff5a5f..aaefe18f 100644 --- a/lib/al/Library/Math/MathUtil.h +++ b/lib/al/Library/Math/MathUtil.h @@ -494,8 +494,10 @@ void visitCellsOverlapped(const sead::Vector3f&, const sead::Vector3f&, f32, const VisitCellCallBack&); f32 calcMultValueToDestination(u32, f32, f32); f32 getHaltonSequence(u32, u32); -f32 calcFractal(f32, f32, u32, f32, f32, f32, bool); -f32 calcMultiFractal(f32, f32, f32, u32, f32, f32, f32, bool); +f32 calcFractal(f32 x, f32 y, u32 permutations, f32 amplitude, f32 scale, f32 nextOrderAmplitude, + bool useSmoothPerlingNoise); +f32 calcMultiFractal(f32 x, f32 y, f32 baseAmplitude, u32 permutations, f32 amplitude, f32 scale, + f32 nextOrderAmplitude, bool useSmoothPerlingNoise); f32 calcNormalDistribution(f32, f32, f32); bool calcVecViewInput(sead::Vector3f*, const sead::Vector2f&, const sead::Vector3f&, const sead::Matrix34f*);