2018-03-06 05:20:54 +08:00
|
|
|
#include "generator.h"
|
|
|
|
#include "layers.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2022-12-30 20:20:29 +08:00
|
|
|
#include <math.h>
|
2018-03-06 05:20:54 +08:00
|
|
|
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
int mapOceanMixMod(const Layer * l, int * out, int x, int z, int w, int h)
|
|
|
|
{
|
|
|
|
int *otyp;
|
2023-05-20 21:57:06 +08:00
|
|
|
int64_t i, j;
|
2021-11-19 06:13:44 +08:00
|
|
|
l->p2->getMap(l->p2, out, x, z, w, h);
|
|
|
|
|
|
|
|
otyp = (int *) malloc(w*h*sizeof(int));
|
|
|
|
memcpy(otyp, out, w*h*sizeof(int));
|
|
|
|
|
|
|
|
l->p->getMap(l->p, out, x, z, w, h);
|
|
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
{
|
|
|
|
int landID, oceanID;
|
|
|
|
|
2023-05-20 21:57:06 +08:00
|
|
|
landID = out[j*w + i];
|
2021-11-19 06:13:44 +08:00
|
|
|
|
|
|
|
if (!isOceanic(landID))
|
|
|
|
continue;
|
|
|
|
|
2023-05-20 21:57:06 +08:00
|
|
|
oceanID = otyp[j*w + i];
|
2021-11-19 06:13:44 +08:00
|
|
|
|
|
|
|
if (landID == deep_ocean)
|
|
|
|
{
|
|
|
|
switch (oceanID)
|
|
|
|
{
|
|
|
|
case lukewarm_ocean:
|
|
|
|
oceanID = deep_lukewarm_ocean;
|
|
|
|
break;
|
|
|
|
case ocean:
|
|
|
|
oceanID = deep_ocean;
|
|
|
|
break;
|
|
|
|
case cold_ocean:
|
|
|
|
oceanID = deep_cold_ocean;
|
|
|
|
break;
|
|
|
|
case frozen_ocean:
|
|
|
|
oceanID = deep_frozen_ocean;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-20 21:57:06 +08:00
|
|
|
out[j*w + i] = oceanID;
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(otyp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setupGenerator(Generator *g, int mc, uint32_t flags)
|
|
|
|
{
|
|
|
|
g->mc = mc;
|
2022-08-15 00:00:23 +08:00
|
|
|
g->dim = DIM_UNDEF;
|
2021-11-19 06:13:44 +08:00
|
|
|
g->flags = flags;
|
|
|
|
g->seed = 0;
|
|
|
|
g->sha = 0;
|
|
|
|
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
if (mc >= MC_B1_8 && mc <= MC_1_17)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
|
|
|
setupLayerStack(&g->ls, mc, flags & LARGE_BIOMES);
|
|
|
|
g->entry = NULL;
|
|
|
|
if (flags & FORCE_OCEAN_VARIANTS && mc >= MC_1_13)
|
|
|
|
{
|
|
|
|
g->ls.entry_16 = setupLayer(
|
|
|
|
g->xlayer+2, &mapOceanMixMod, mc, 1, 0, 0,
|
|
|
|
g->ls.entry_16, &g->ls.layers[L_ZOOM_16_OCEAN]);
|
|
|
|
|
|
|
|
g->ls.entry_64 = setupLayer(
|
|
|
|
g->xlayer+3, &mapOceanMixMod, mc, 1, 0, 0,
|
|
|
|
g->ls.entry_64, &g->ls.layers[L_ZOOM_64_OCEAN]);
|
|
|
|
|
|
|
|
g->ls.entry_256 = setupLayer(
|
|
|
|
g->xlayer+4, &mapOceanMixMod, mc, 1, 0, 0,
|
|
|
|
g->ls.entry_256, &g->ls.layers[L_OCEAN_TEMP_256]);
|
|
|
|
}
|
|
|
|
}
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
else if (mc >= MC_1_18)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
|
|
|
initBiomeNoise(&g->bn, mc);
|
|
|
|
}
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
g->bnb.mc = mc;
|
|
|
|
}
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void applySeed(Generator *g, int dim, uint64_t seed)
|
|
|
|
{
|
|
|
|
g->dim = dim;
|
|
|
|
g->seed = seed;
|
|
|
|
g->sha = 0;
|
|
|
|
|
2022-08-15 00:00:23 +08:00
|
|
|
if (dim == DIM_OVERWORLD)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
2023-02-08 05:02:46 +08:00
|
|
|
if (g->mc <= MC_B1_7)
|
|
|
|
{
|
|
|
|
setBetaBiomeSeed(&g->bnb, seed);
|
|
|
|
//initSurfaceNoiseBeta(&g->snb, g->seed);
|
|
|
|
}
|
|
|
|
else if (g->mc <= MC_1_17)
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
setLayerSeed(g->entry ? g->entry : g->ls.entry_1, seed);
|
2023-02-08 05:02:46 +08:00
|
|
|
}
|
|
|
|
else // if (g->mc >= MC_1_18)
|
|
|
|
{
|
2021-11-20 22:46:52 +08:00
|
|
|
setBiomeSeed(&g->bn, seed, g->flags & LARGE_BIOMES);
|
2023-02-08 05:02:46 +08:00
|
|
|
}
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
2023-01-17 03:47:12 +08:00
|
|
|
else if (dim == DIM_NETHER && g->mc >= MC_1_16_1)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
2021-11-20 22:46:52 +08:00
|
|
|
setNetherSeed(&g->nn, seed);
|
|
|
|
}
|
2022-08-15 00:00:23 +08:00
|
|
|
else if (dim == DIM_END && g->mc >= MC_1_9)
|
2021-11-20 22:46:52 +08:00
|
|
|
{
|
2022-09-05 04:40:19 +08:00
|
|
|
setEndSeed(&g->en, g->mc, seed);
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
|
|
|
if (g->mc >= MC_1_15)
|
|
|
|
{
|
2022-08-15 00:00:23 +08:00
|
|
|
if (g->mc <= MC_1_17 && dim == DIM_OVERWORLD && !g->entry)
|
2021-11-19 06:13:44 +08:00
|
|
|
g->sha = g->ls.entry_1->startSalt;
|
|
|
|
else
|
|
|
|
g->sha = getVoronoiSHA(seed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size_t getMinCacheSize(const Generator *g, int scale, int sx, int sy, int sz)
|
|
|
|
{
|
|
|
|
if (sy == 0)
|
|
|
|
sy = 1;
|
|
|
|
size_t len = (size_t)sx * sz * sy;
|
2023-02-18 18:27:49 +08:00
|
|
|
if (g->mc <= MC_B1_7 && scale <= 4 && !(g->flags & NO_BETA_OCEAN))
|
Added ocean detection for Beta 1.7
(generator.c)
- getMinCacheSize(): Allocate extra cache for Beta ocean column noise buffer
(noise.c)
- samplePerlin(): Reverted previous change, as the attempted optimization had
unintended side-effects for 1.18+ generation and had no measurable
performance improvement.
(layers.h)
- Renamed two OctaveNoise members of struct SurfaceNoiseBeta
- Added new struct SeaLevelColumnNoiseBeta
- Added headers for four new functions defined in layers.c
(layers.c)
- initSurfaceNoiseBeta(): Reflect changes to names in layers.h
- sampleBiomeNoiseBeta(): When nptype == 1, returned humidity value is now
multiplied by temperature to reflect the behavior seen in biome gen
- Added new function genColumnNoise():
Generates values used to calculate terrain noise columns and places
them in a SeaLevelColumnNoiseBeta struct pointed to by the provided
pointer.
- Added new function processColumnNoise():
Generates a partial noise column for finding the block at sea level
using data pointed to by the provided SeaLevelColumnNoiseBeta pointer
- Added new function sampleBlocks():
Using adjacent noise columns, determine whether the blocks at y=64 are
solid and place results in array pointed to by provided pointer
- Added new function sampleBetaBiomeOneBlock():
Generates new noise columns for each sampled block and skips the
diagonal traversal with cache buffer, as no noise columns data can be
re-used when scale >= 8.
- genBetaBiomeNoiseScaled():
Previous "no ocean" code is now locked behind (noOcean || scale >= 8)
condition. Calls sampleBiomeNoiseBeta() when noOcean is true, and calls
sampleBetaBiomeOneBlock() otherwise.
Else, the generated region is traversed in 4x4 block sections
corresponding to terrain noise columns. Columns are saved for re-use in
future passes in order to minimize unnecessary Perlin generation, and
region traversal is done in diagonal stripes in order to minimize extra
cache size needed (on average) for the saved noise sample buffer.
My original plan for the diagonal traversal was to store SeaLevelColumnNoise
*pointers* in the extra cache space, which would be dynamically allocated
when generated, but since extra cache space will only exceed the original
cache space when the generated area is so small that memory concerns are
trivial, this plan was abandoned in favor of storing the structs directly in
the cache. This approach also eliminates the risk of memory leaks.
Currently, with oceans, this code takes about 20 seconds to generate the
biomes for a 4096 x 4096 block region. Since this approach to ocean-finding
deals in 4x4 noise columns, scales 2-4 are still quite slow for the same
scaled region -- about 13 seconds at 1:4 scale. At higher scales, the
diagonal approach is abandoned and four new noise columns are generated for
every midpoint block that is sampled.
I made a quick test build of Cubiomes Viewer, and while the ocean-finding
code works, the regions are very slow to show up in the view window, and
changing the zoom level can cause regions to reset when zooming in both
directions. Perhaps some optimizations can be made in Cubiomes Viewer in
terms of handling cache and displaying generated biomes at different scales,
but I'm not familiar enough with that project to suggest anything specific.
I tried to cut out as much unnecessary processing as possible in my
implementation of the inherently cpu-intensive ocean-finding algorithm, but
it's certainly possible optimizations can be made in the generation code
itself.
2023-02-02 08:00:03 +08:00
|
|
|
{
|
2023-02-18 18:27:49 +08:00
|
|
|
int cellwidth = scale >> 1;
|
|
|
|
int smin = (sx < sz ? sx : sz);
|
2023-05-20 21:57:06 +08:00
|
|
|
int slen = ((smin >> (2 >> cellwidth)) + 1) * 2 + 1;
|
2023-02-18 18:27:49 +08:00
|
|
|
len += slen * sizeof(SeaLevelColumnNoiseBeta);
|
Added ocean detection for Beta 1.7
(generator.c)
- getMinCacheSize(): Allocate extra cache for Beta ocean column noise buffer
(noise.c)
- samplePerlin(): Reverted previous change, as the attempted optimization had
unintended side-effects for 1.18+ generation and had no measurable
performance improvement.
(layers.h)
- Renamed two OctaveNoise members of struct SurfaceNoiseBeta
- Added new struct SeaLevelColumnNoiseBeta
- Added headers for four new functions defined in layers.c
(layers.c)
- initSurfaceNoiseBeta(): Reflect changes to names in layers.h
- sampleBiomeNoiseBeta(): When nptype == 1, returned humidity value is now
multiplied by temperature to reflect the behavior seen in biome gen
- Added new function genColumnNoise():
Generates values used to calculate terrain noise columns and places
them in a SeaLevelColumnNoiseBeta struct pointed to by the provided
pointer.
- Added new function processColumnNoise():
Generates a partial noise column for finding the block at sea level
using data pointed to by the provided SeaLevelColumnNoiseBeta pointer
- Added new function sampleBlocks():
Using adjacent noise columns, determine whether the blocks at y=64 are
solid and place results in array pointed to by provided pointer
- Added new function sampleBetaBiomeOneBlock():
Generates new noise columns for each sampled block and skips the
diagonal traversal with cache buffer, as no noise columns data can be
re-used when scale >= 8.
- genBetaBiomeNoiseScaled():
Previous "no ocean" code is now locked behind (noOcean || scale >= 8)
condition. Calls sampleBiomeNoiseBeta() when noOcean is true, and calls
sampleBetaBiomeOneBlock() otherwise.
Else, the generated region is traversed in 4x4 block sections
corresponding to terrain noise columns. Columns are saved for re-use in
future passes in order to minimize unnecessary Perlin generation, and
region traversal is done in diagonal stripes in order to minimize extra
cache size needed (on average) for the saved noise sample buffer.
My original plan for the diagonal traversal was to store SeaLevelColumnNoise
*pointers* in the extra cache space, which would be dynamically allocated
when generated, but since extra cache space will only exceed the original
cache space when the generated area is so small that memory concerns are
trivial, this plan was abandoned in favor of storing the structs directly in
the cache. This approach also eliminates the risk of memory leaks.
Currently, with oceans, this code takes about 20 seconds to generate the
biomes for a 4096 x 4096 block region. Since this approach to ocean-finding
deals in 4x4 noise columns, scales 2-4 are still quite slow for the same
scaled region -- about 13 seconds at 1:4 scale. At higher scales, the
diagonal approach is abandoned and four new noise columns are generated for
every midpoint block that is sampled.
I made a quick test build of Cubiomes Viewer, and while the ocean-finding
code works, the regions are very slow to show up in the view window, and
changing the zoom level can cause regions to reset when zooming in both
directions. Perhaps some optimizations can be made in Cubiomes Viewer in
terms of handling cache and displaying generated biomes at different scales,
but I'm not familiar enough with that project to suggest anything specific.
I tried to cut out as much unnecessary processing as possible in my
implementation of the inherently cpu-intensive ocean-finding algorithm, but
it's certainly possible optimizations can be made in the generation code
itself.
2023-02-02 08:00:03 +08:00
|
|
|
}
|
2023-02-18 18:27:49 +08:00
|
|
|
else if (g->mc >= MC_B1_8 && g->mc <= MC_1_17 && g->dim == DIM_OVERWORLD)
|
2021-11-19 06:13:44 +08:00
|
|
|
{ // recursively check the layer stack for the max buffer
|
|
|
|
const Layer *entry = getLayerForScale(g, scale);
|
|
|
|
if (!entry) {
|
|
|
|
printf("getMinCacheSize(): failed to determine scaled entry\n");
|
2024-10-07 19:20:00 +08:00
|
|
|
return 0;
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
|
|
|
size_t len2d = getMinLayerCacheSize(entry, sx, sz);
|
|
|
|
len += len2d - sx*sz;
|
|
|
|
}
|
2023-02-18 18:27:49 +08:00
|
|
|
else if ((g->mc >= MC_1_18 || g->dim != DIM_OVERWORLD) && scale <= 1)
|
2021-11-19 06:13:44 +08:00
|
|
|
{ // allocate space for temporary copy of voronoi source
|
|
|
|
sx = ((sx+3) >> 2) + 2;
|
|
|
|
sy = ((sy+3) >> 2) + 2;
|
|
|
|
sz = ((sz+3) >> 2) + 2;
|
|
|
|
len += sx * sy * sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
int *allocCache(const Generator *g, Range r)
|
|
|
|
{
|
|
|
|
size_t len = getMinCacheSize(g, r.scale, r.sx, r.sy, r.sz);
|
2024-10-07 19:20:00 +08:00
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
2021-11-19 06:13:44 +08:00
|
|
|
return (int*) calloc(len, sizeof(int));
|
|
|
|
}
|
|
|
|
|
|
|
|
int genBiomes(const Generator *g, int *cache, Range r)
|
|
|
|
{
|
|
|
|
int err = 1;
|
2023-05-20 21:57:06 +08:00
|
|
|
int64_t i, k;
|
2021-11-19 06:13:44 +08:00
|
|
|
|
2022-08-15 00:00:23 +08:00
|
|
|
if (g->dim == DIM_OVERWORLD)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
if (g->mc >= MC_B1_8 && g->mc <= MC_1_17)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
|
|
|
const Layer *entry = getLayerForScale(g, r.scale);
|
|
|
|
if (!entry) return -1;
|
|
|
|
err = genArea(entry, cache, r.x, r.z, r.sx, r.sz);
|
|
|
|
if (err) return err;
|
|
|
|
for (k = 1; k < r.sy; k++)
|
|
|
|
{ // overworld has no vertical noise: expanding 2D into 3D
|
|
|
|
for (i = 0; i < r.sx*r.sz; i++)
|
|
|
|
cache[k*r.sx*r.sz + i] = cache[i];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
else if (g->mc >= MC_1_18)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
2023-02-08 05:02:46 +08:00
|
|
|
return genBiomeNoiseScaled(&g->bn, cache, r, g->sha);
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
else // g->mc <= MC_B1_7
|
|
|
|
{
|
2023-02-08 05:02:46 +08:00
|
|
|
if (g->flags & NO_BETA_OCEAN)
|
|
|
|
{
|
|
|
|
err = genBiomeNoiseBetaScaled(&g->bnb, NULL, cache, r);
|
|
|
|
}
|
|
|
|
else
|
Added noise generation functions for Beta 1.7 terrain
(biome_tree.c)
- Moved a curly brace to maintain style consistent with repo
(generator.h)
- Removed SurfaceNoiseBeta struct from Generator
(generator.c)
- applySeed(): Removed initSurfaceNoiseBeta() call
- genBiomes():
Now declares and initializes SurfaceNoiseBeta when mc <= MC_B1_7
Returns err when g->dim == DIM_END and mc < MC_1_0
(layers.c)
- biomeExists(): Added new checks for mc <= B1_7
- initSurfaceNoiseBeta(): Implemented
- New comment added to sampleBiomeNoiseBeta()
(noise.h)
- Added headers for four new functions defined in noise.c
(noise.c)
- samplePerlin(): Placed all lerps used for 3D noise but not used for 2D noise
behind a (d2 != 0) condition. I'm anticipating needing every bit of
optimization I can find to make ocean-finding practically efficient.
- added new samplePerlinOldBetaTerrain3D() function:
used to generate the octmin, octmax, and octmain noise near sea level
for the given noise column x and z. The necessity for this function will
be explained more in-depth below.
- added new initOctaveOldBetaTerrain() function:
Used to initialize the five Perlin OctaveNoise structs in
SurfaceNoiseBeta. Unlike climate noise, these are Perlin noise maps
instead of Simplex, but the existing octaveInit() cannot be used because
the starting lacunarity values are not integer powers of 2.
- added new sampleOctave2D() function:
Nearly identical to sampleOctave(), except that ay is set to -(p->b),
forcing samplePerlin()'s d2 variable to be 0, resulting in a 2D noise
sample.
- added new sampleOctaveOldBetaTerrain3D() function:
Used to sample the three 3D noisemaps in SurfaceNoiseBeta. The function
is passed a 2-element array of doubles, which is passed to
samplePerlinOldBetaTerrain3D() where the different octaves' values are
added. The only samples made are the ones necessary to determine the
blocks at sea level.
samplePerlinOldBetaTerrain3D() is necessary because when generating these
versions' overworld octmin, octmax, and octmain noise, lower levels affect
higher levels based on whether the lower 8 bits of i2 are equal to the lower
8 bits of i2 from the previous iteration. Each level is only affected by the
immediately previous level where (i2 & 255 !- previ2), so I was able to make an
optimization -- the first several y-level iterations are split into a separate
for loop that only looks at i2, and finds the highest y-level that affects the
final output at sea level. In my Java test program using Minecraft's code, this
optimization brough the time needed to produce an image of a 4096 x 4096 region
down to 1/3 of what it was before the optimization.
The yLacFlag argument determines whether or not lacunarity is cut in half for
the y dimension -- octmain uses lacunarity values for y that are half of the
x/z lacunarity value.
In a future commit, I may extend samplePerlinOldBetaTerrain3D() and
sampleOctaveOldBetaTerrain3D() to generate partial noise columns between ymin
and ymax bounds, in order to eventually implement 4x4 surface height finding.
2023-01-28 09:17:38 +08:00
|
|
|
{
|
|
|
|
SurfaceNoiseBeta snb;
|
|
|
|
initSurfaceNoiseBeta(&snb, g->seed);
|
2023-02-08 05:02:46 +08:00
|
|
|
err = genBiomeNoiseBetaScaled(&g->bnb, &snb, cache, r);
|
Added noise generation functions for Beta 1.7 terrain
(biome_tree.c)
- Moved a curly brace to maintain style consistent with repo
(generator.h)
- Removed SurfaceNoiseBeta struct from Generator
(generator.c)
- applySeed(): Removed initSurfaceNoiseBeta() call
- genBiomes():
Now declares and initializes SurfaceNoiseBeta when mc <= MC_B1_7
Returns err when g->dim == DIM_END and mc < MC_1_0
(layers.c)
- biomeExists(): Added new checks for mc <= B1_7
- initSurfaceNoiseBeta(): Implemented
- New comment added to sampleBiomeNoiseBeta()
(noise.h)
- Added headers for four new functions defined in noise.c
(noise.c)
- samplePerlin(): Placed all lerps used for 3D noise but not used for 2D noise
behind a (d2 != 0) condition. I'm anticipating needing every bit of
optimization I can find to make ocean-finding practically efficient.
- added new samplePerlinOldBetaTerrain3D() function:
used to generate the octmin, octmax, and octmain noise near sea level
for the given noise column x and z. The necessity for this function will
be explained more in-depth below.
- added new initOctaveOldBetaTerrain() function:
Used to initialize the five Perlin OctaveNoise structs in
SurfaceNoiseBeta. Unlike climate noise, these are Perlin noise maps
instead of Simplex, but the existing octaveInit() cannot be used because
the starting lacunarity values are not integer powers of 2.
- added new sampleOctave2D() function:
Nearly identical to sampleOctave(), except that ay is set to -(p->b),
forcing samplePerlin()'s d2 variable to be 0, resulting in a 2D noise
sample.
- added new sampleOctaveOldBetaTerrain3D() function:
Used to sample the three 3D noisemaps in SurfaceNoiseBeta. The function
is passed a 2-element array of doubles, which is passed to
samplePerlinOldBetaTerrain3D() where the different octaves' values are
added. The only samples made are the ones necessary to determine the
blocks at sea level.
samplePerlinOldBetaTerrain3D() is necessary because when generating these
versions' overworld octmin, octmax, and octmain noise, lower levels affect
higher levels based on whether the lower 8 bits of i2 are equal to the lower
8 bits of i2 from the previous iteration. Each level is only affected by the
immediately previous level where (i2 & 255 !- previ2), so I was able to make an
optimization -- the first several y-level iterations are split into a separate
for loop that only looks at i2, and finds the highest y-level that affects the
final output at sea level. In my Java test program using Minecraft's code, this
optimization brough the time needed to produce an image of a 4096 x 4096 region
down to 1/3 of what it was before the optimization.
The yLacFlag argument determines whether or not lacunarity is cut in half for
the y dimension -- octmain uses lacunarity values for y that are half of the
x/z lacunarity value.
In a future commit, I may extend samplePerlinOldBetaTerrain3D() and
sampleOctaveOldBetaTerrain3D() to generate partial noise columns between ymin
and ymax bounds, in order to eventually implement 4x4 surface height finding.
2023-01-28 09:17:38 +08:00
|
|
|
}
|
2023-02-06 01:38:24 +08:00
|
|
|
if (err) return err;
|
|
|
|
for (k = 1; k < r.sy; k++)
|
|
|
|
{ // overworld has no vertical noise: expanding 2D into 3D
|
|
|
|
for (i = 0; i < r.sx*r.sz; i++)
|
|
|
|
cache[k*r.sx*r.sz + i] = cache[i];
|
|
|
|
}
|
|
|
|
return 0;
|
Added Beta climate biome generation (no ocean gen yet)
(biome_tree.c)
- getOldBetaBiome: removed isWater argument.
(finders.c)
- getStructureConfig: now returns 0 for mineshafts and villages before B1.8.
(layers.h)
- Added SurfaceNoiseBeta struct:
Very similar to SurfaceNoise.
Since SurfaceNoiseBeta will only ever be used for the Overworld, the
double values saved in SurfaceNoise will be hardcoded into the
SurfaceNoiseBeta sampling function.
octSurf and octDepth in surfaceNoise are replaced with new octA and octB
OctaveNoises, used for precise terrain generation. These names are
subject to change if I come up with more meaningful names in the
future.
The oct array contains six additional PerlinNoise structs compared to
SurfaceNoise, as the 4-octave octSurf is replaced with the 10-octave
octA.
- Added BiomeNoiseBeta struct:
Mostly a cut-down version of BiomeNoise.
The climate array contains three OctaveNoise structs, corresponding to
the 4-octave temperature and humidity noise generators, as well as
an additional 2-octave generator that I'm calling "fuzz". The fuzz
noise is high-frequency and low-amplitude, and is used as a factor
applied to the raw output of both the temperature and humidity
generators before these values are used.
The PerlinNoise array oct contains 10 octaves -- 4 for temperature, 4 for
humidity, and 2 for fuzz.
nptype and mc are carried over from BiomeNoise. mc currently has no
purpose, but I've heard of a bug in some early beta versions causing
chunk biomes to generate rotated, so storing the version may
eventually prove useful.
- Added headers for 5 new functions in layers.c.
- Changed header for getOldBetaBiome (defined in biome_tree.c) to reflect new
signature.
(layers.c)
- Added initSurfaceNoiseBeta function: No-op placeholder for now.
- Added setBetaBiomeSeed function: Initializes the three climate simplex noise
generators and sets bnb->nptype to -1 by default.
- Added sampleBiomeNoiseBeta function:
sampleBiomeNoiseBeta samples climate noise at the given x and z
coordinates (1:1 scale) and returns a biome ID corresponding to the
biome at the generated temperature and humidity noise values.
The behavior of zeroing out the array np when it is passed is copied
from sampleBiomeNoise. I'm not sure about its function, so if it's
not applicable, this argument and associated behavior can be removed.
If bnb->nptype is set to NP_TEMPERATURE or NP_HUMIDITY, only that noise
value is generated and the other is ignored. The noise value is
multiplied by 10000 and returned as a signed long to match the
behavior of sampleBiomeNoise. Note that Beta climate values range from
0 to 1, not -1 to 1, so the resulting ints will all be nonnegative.
The argument nv (noise values) is a pointer to a 2-element array of
doubles. If it is present, the noise values are placed in the array
before the biome is determined.
- Added genBetaBiomeNoiseScaled function:
At 1:1 scale, every block in Range r is sampled and the return value of
sampleBiomeNoiseBeta is placed in the cache.
At higher scales, midpoints are sampled.
When ocean support is added, this function will likely behave
differently when NO_BETA_OCEAN is clear in order to maximize time
and memory efficiency.
(generator.h)
- Flags enum: Bit 1 (0x2) is now the NO_BETA_OCEAN flag.
- Generator struct: New union member for pre-B1.8: Includes BiomeNoiseBeta
and SurfaceNoiseBeta structs now defined in layers.h
(generator.c)
- setupGenearator:
New version so pre-B1.8 versions behave correctly.
For mc <= MC_B1_7, setupGenerator simply sets g->bnb.mc, as all other
setup for pre-B1.8 biome generation requires the seed to be known.
- applySeed:
When mc <= MC_B1_7, the new setBetaBiomeSeed function defined in layers.c
is called. If the NO_BETA_OCEAN flag is not set, initSurfaceNoiseBeta
is also called. initSurfaceNoiseBeta is currently just a no-op
placeholder.
- getMinCacheSize:
New version check.
Returns default size when mc <= MC_B1_7. Will likely be modified when
ocean-finding functionality is added.
- genBiomes: Calls genBetaBiomeNoiseScaled when mc <= MC_B1_7
Note: Compiling libcubiomes.a will will currently cause several warnings due to
unused parameters related to not-yet-implemented ocean finding.
2023-01-24 05:51:54 +08:00
|
|
|
}
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
2022-08-15 00:00:23 +08:00
|
|
|
else if (g->dim == DIM_NETHER)
|
2021-11-19 06:13:44 +08:00
|
|
|
{
|
2021-11-20 22:46:52 +08:00
|
|
|
return genNetherScaled(&g->nn, cache, r, g->mc, g->sha);
|
|
|
|
}
|
2022-08-15 00:00:23 +08:00
|
|
|
else if (g->dim == DIM_END)
|
2021-11-20 22:46:52 +08:00
|
|
|
{
|
2023-02-08 05:02:46 +08:00
|
|
|
return genEndScaled(&g->en, cache, r, g->mc, g->sha);
|
2021-11-19 06:13:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int getBiomeAt(const Generator *g, int scale, int x, int y, int z)
|
|
|
|
{
|
|
|
|
Range r = {scale, x, z, 1, 1, y, 1};
|
|
|
|
int *ids = allocCache(g, r);
|
|
|
|
int id = genBiomes(g, ids, r);
|
|
|
|
if (id == 0)
|
|
|
|
id = ids[0];
|
|
|
|
else
|
|
|
|
id = none;
|
|
|
|
free(ids);
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Layer *getLayerForScale(const Generator *g, int scale)
|
|
|
|
{
|
|
|
|
if (g->mc > MC_1_17)
|
|
|
|
return NULL;
|
|
|
|
switch (scale)
|
|
|
|
{
|
|
|
|
case 0: return g->entry;
|
|
|
|
case 1: return g->ls.entry_1;
|
|
|
|
case 4: return g->ls.entry_4;
|
|
|
|
case 16: return g->ls.entry_16;
|
|
|
|
case 64: return g->ls.entry_64;
|
|
|
|
case 256: return g->ls.entry_256;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Layer *setupLayer(Layer *l, mapfunc_t *map, int mc,
|
2021-07-01 05:52:21 +08:00
|
|
|
int8_t zoom, int8_t edge, uint64_t saltbase, Layer *p, Layer *p2)
|
2018-03-06 05:20:54 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
//Layer *l = g->layers + layerId;
|
2021-04-19 01:50:08 +08:00
|
|
|
l->getMap = map;
|
|
|
|
l->mc = mc;
|
|
|
|
l->zoom = zoom;
|
|
|
|
l->edge = edge;
|
|
|
|
l->scale = 0;
|
2021-07-01 05:52:21 +08:00
|
|
|
if (saltbase == 0 || saltbase == LAYER_INIT_SHA)
|
|
|
|
l->layerSalt = saltbase;
|
|
|
|
else
|
|
|
|
l->layerSalt = getLayerSalt(saltbase);
|
2020-07-24 04:42:38 +08:00
|
|
|
l->startSalt = 0;
|
|
|
|
l->startSeed = 0;
|
2021-01-26 03:01:37 +08:00
|
|
|
l->noise = NULL;
|
2020-08-10 00:52:58 +08:00
|
|
|
l->data = NULL;
|
2021-04-19 01:50:08 +08:00
|
|
|
l->p = p;
|
2018-03-06 05:20:54 +08:00
|
|
|
l->p2 = p2;
|
2021-04-19 01:50:08 +08:00
|
|
|
return l;
|
2018-03-06 05:20:54 +08:00
|
|
|
}
|
|
|
|
|
2020-05-05 18:13:43 +08:00
|
|
|
static void setupScale(Layer *l, int scale)
|
|
|
|
{
|
2021-04-21 05:13:53 +08:00
|
|
|
l->scale = scale;
|
2021-04-19 01:50:08 +08:00
|
|
|
if (l->p)
|
|
|
|
setupScale(l->p, scale * l->zoom);
|
|
|
|
if (l->p2)
|
|
|
|
setupScale(l->p2, scale * l->zoom);
|
2020-05-05 18:13:43 +08:00
|
|
|
}
|
2018-03-18 00:53:16 +08:00
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
void setupLayerStack(LayerStack *g, int mc, int largeBiomes)
|
2018-03-06 05:20:54 +08:00
|
|
|
{
|
2021-07-24 01:56:59 +08:00
|
|
|
if (mc < MC_1_3)
|
|
|
|
largeBiomes = 0;
|
|
|
|
|
2021-04-19 01:50:08 +08:00
|
|
|
memset(g, 0, sizeof(LayerStack));
|
2021-11-19 06:13:44 +08:00
|
|
|
Layer *p, *l = g->layers;
|
2023-01-17 03:47:12 +08:00
|
|
|
mapfunc_t *map_land = 0;
|
2021-11-19 06:13:44 +08:00
|
|
|
// L: layer
|
2021-04-19 01:50:08 +08:00
|
|
|
// M: mapping function
|
|
|
|
// V: minecraft version
|
|
|
|
// Z: zoom
|
|
|
|
// E: edge
|
|
|
|
// S: salt base
|
|
|
|
// P1: parent 1
|
|
|
|
// P2: parent 2
|
|
|
|
|
2023-01-09 07:42:42 +08:00
|
|
|
if (mc == MC_B1_8)
|
|
|
|
{ // L M V Z E S P1 P2
|
|
|
|
// NOTE: reusing slot for continent:4096, but scale is 1:8192
|
2023-01-17 03:47:12 +08:00
|
|
|
map_land = mapLandB18;
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_CONTINENT_4096, mapContinent, mc, 1, 0, 1, 0, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4096, mapZoomFuzzy, mc, 2, 3, 2000, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_4096, map_land, mc, 1, 2, 1, p, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_2048, mapZoom, mc, 2, 3, 2001, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_2048, map_land, mc, 1, 2, 2, p, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_1024, mapZoom, mc, 2, 3, 2002, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_1024_A, map_land, mc, 1, 2, 3, p, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_512, mapZoom, mc, 2, 3, 2003, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_512, map_land, mc, 1, 2, 3, p, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_256, mapZoom, mc, 2, 3, 2004, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_256, map_land, mc, 1, 2, 3, p, 0);
|
|
|
|
p = setupLayer(l+L_BIOME_256, mapBiome, mc, 1, 0, 200, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_128, mapZoom, mc, 2, 3, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
// river noise layer chain, also used to determine where hills generate
|
|
|
|
p = setupLayer(l+L_NOISE_256, mapNoise, mc, 1, 0, 100,
|
|
|
|
l+L_LAND_256, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
}
|
2023-01-17 03:47:12 +08:00
|
|
|
else if (mc <= MC_1_6)
|
2023-01-09 07:42:42 +08:00
|
|
|
{ // L M V Z E S P1 P2
|
2023-01-17 03:47:12 +08:00
|
|
|
map_land = mapLand16;
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_CONTINENT_4096, mapContinent, mc, 1, 0, 1, 0, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_2048, mapZoomFuzzy, mc, 2, 3, 2000, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_2048, map_land, mc, 1, 2, 1, p, 0);
|
2023-01-09 07:42:42 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_1024, mapZoom, mc, 2, 3, 2001, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_1024_A, map_land, mc, 1, 2, 2, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SNOW_1024, mapSnow16, mc, 1, 2, 2, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_512, mapZoom, mc, 2, 3, 2002, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_512, map_land, mc, 1, 2, 3, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_256, mapZoom, mc, 2, 3, 2003, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_256, map_land, mc, 1, 2, 4, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_MUSHROOM_256, mapMushroom, mc, 1, 2, 5, p, 0);
|
|
|
|
p = setupLayer(l+L_BIOME_256, mapBiome, mc, 1, 0, 200, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_128, mapZoom, mc, 2, 3, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64, mapZoom, mc, 2, 3, 1001, p, 0);
|
2021-04-21 05:13:53 +08:00
|
|
|
// river noise layer chain, also used to determine where hills generate
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_NOISE_256, mapNoise, mc, 1, 0, 100,
|
2023-01-17 03:47:12 +08:00
|
|
|
l+L_MUSHROOM_256, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
|
|
|
else
|
2021-11-19 06:13:44 +08:00
|
|
|
{ // L M V Z E S P1 P2
|
2023-01-17 03:47:12 +08:00
|
|
|
map_land = mapLand;
|
|
|
|
p = setupLayer(l+L_CONTINENT_4096, mapContinent, mc, 1, 0, 1, 0, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_2048, mapZoomFuzzy, mc, 2, 3, 2000, p, 0);
|
|
|
|
p = setupLayer(l+L_LAND_2048, map_land, mc, 1, 2, 1, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_1024, mapZoom, mc, 2, 3, 2001, p, 0);
|
|
|
|
p = setupLayer(l+L_LAND_1024_A, map_land, mc, 1, 2, 2, p, 0);
|
|
|
|
p = setupLayer(l+L_LAND_1024_B, map_land, mc, 1, 2, 50, p, 0);
|
|
|
|
p = setupLayer(l+L_LAND_1024_C, map_land, mc, 1, 2, 70, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ISLAND_1024, mapIsland, mc, 1, 2, 2, p, 0);
|
|
|
|
p = setupLayer(l+L_SNOW_1024, mapSnow, mc, 1, 2, 2, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_1024_D, map_land, mc, 1, 2, 3, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_COOL_1024, mapCool, mc, 1, 2, 2, p, 0);
|
|
|
|
p = setupLayer(l+L_HEAT_1024, mapHeat, mc, 1, 2, 2, p, 0);
|
|
|
|
p = setupLayer(l+L_SPECIAL_1024, mapSpecial, mc, 1, 2, 3, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_512, mapZoom, mc, 2, 3, 2002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_256, mapZoom, mc, 2, 3, 2003, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_256, map_land, mc, 1, 2, 4, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_MUSHROOM_256, mapMushroom, mc, 1, 2, 5, p, 0);
|
|
|
|
p = setupLayer(l+L_DEEP_OCEAN_256, mapDeepOcean, mc, 1, 2, 4, p, 0);
|
|
|
|
p = setupLayer(l+L_BIOME_256, mapBiome, mc, 1, 0, 200, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
if (mc >= MC_1_14)
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_BAMBOO_256, mapBamboo, mc, 1, 0, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_128, mapZoom, mc, 2, 3, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_BIOME_EDGE_64, mapBiomeEdge, mc, 1, 2, 1000, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
// river noise layer chain, also used to determine where hills generate
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_RIVER_INIT_256, mapNoise, mc, 1, 0, 100,
|
|
|
|
l+L_DEEP_OCEAN_256, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
|
|
|
|
2023-01-17 03:47:12 +08:00
|
|
|
if (mc <= MC_1_0) {}
|
|
|
|
else if (mc <= MC_1_12)
|
2021-07-24 01:56:59 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_HILLS, mapZoom, mc, 2, 3, 0, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_HILLS, mapZoom, mc, 2, 3, 0, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
2023-01-17 03:47:12 +08:00
|
|
|
else // if (mc >= MC_1_13)
|
2021-07-24 01:56:59 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_HILLS, mapZoom, mc, 2, 3, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_HILLS, mapZoom, mc, 2, 3, 1001, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mc <= MC_1_0)
|
2021-11-19 06:13:44 +08:00
|
|
|
{ // L M V Z E S P1 P2
|
|
|
|
p = setupLayer(l+L_ZOOM_32, mapZoom, mc, 2, 3, 1000,
|
|
|
|
l+L_ZOOM_64, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_32, map_land, mc, 1, 2, 3, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
// NOTE: reusing slot for shore:16, but scale is 1:32
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SHORE_16, mapShore, mc, 1, 2, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_16, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4, mapZoom, mc, 2, 3, 1003, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SMOOTH_4, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
|
|
|
|
// river layer chain
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_RIVER, mapZoom, mc, 2, 3, 1000,
|
|
|
|
l+L_NOISE_256, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_RIVER, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_32_RIVER, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_16_RIVER, mapZoom, mc, 2, 3, 1003, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8_RIVER, mapZoom, mc, 2, 3, 1004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4_RIVER, mapZoom, mc, 2, 3, 1005, p, 0);
|
|
|
|
|
|
|
|
p = setupLayer(l+L_RIVER_4, mapRiver, mc, 1, 2, 1, p, 0);
|
|
|
|
p = setupLayer(l+L_SMOOTH_4_RIVER, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
|
|
|
else if (mc <= MC_1_6)
|
2023-01-17 03:47:12 +08:00
|
|
|
{ // L M V Z E S P1 P2
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_HILLS_64, mapHills, mc, 1, 2, 1000,
|
|
|
|
l+L_ZOOM_64, l+L_ZOOM_64_HILLS);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_32, mapZoom, mc, 2, 3, 1000, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_32, map_land, mc, 1, 2, 3, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_16, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_SHORE_16, mapShore, mc, 1, 2, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_SWAMP_RIVER_16, mapSwampRiver, mc, 1, 0, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4, mapZoom, mc, 2, 3, 1003, p, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
2021-07-20 00:11:36 +08:00
|
|
|
if (largeBiomes)
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_LARGE_A, mapZoom, mc, 2, 3, 1004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_LARGE_B, mapZoom, mc, 2, 3, 1005, p, 0);
|
2021-07-20 00:11:36 +08:00
|
|
|
}
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SMOOTH_4, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
|
|
|
// river layer chain
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_RIVER, mapZoom, mc, 2, 3, 1000,
|
|
|
|
l+L_NOISE_256, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_RIVER, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_32_RIVER, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_16_RIVER, mapZoom, mc, 2, 3, 1003, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8_RIVER, mapZoom, mc, 2, 3, 1004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4_RIVER, mapZoom, mc, 2, 3, 1005, p, 0);
|
2021-07-20 00:11:36 +08:00
|
|
|
|
|
|
|
if (largeBiomes)
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_L_RIVER_A, mapZoom, mc, 2, 3, 1006, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_L_RIVER_B, mapZoom, mc, 2, 3, 1007, p, 0);
|
2021-07-20 00:11:36 +08:00
|
|
|
}
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_RIVER_4, mapRiver, mc, 1, 2, 1, p, 0);
|
|
|
|
p = setupLayer(l+L_SMOOTH_4_RIVER, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2018-03-06 05:20:54 +08:00
|
|
|
}
|
2023-01-17 03:47:12 +08:00
|
|
|
else // if (mc >= MC_1_7)
|
|
|
|
{ // L M V Z E S P1 P2
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_HILLS_64, mapHills, mc, 1, 2, 1000,
|
|
|
|
l+L_BIOME_EDGE_64, l+L_ZOOM_64_HILLS);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SUNFLOWER_64, mapSunflower, mc, 1, 0, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_32, mapZoom, mc, 2, 3, 1000, p, 0);
|
2023-01-17 03:47:12 +08:00
|
|
|
p = setupLayer(l+L_LAND_32, map_land, mc, 1, 2, 3, p, 0);
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_16, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_SHORE_16, mapShore, mc, 1, 2, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4, mapZoom, mc, 2, 3, 1003, p, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
|
|
|
if (largeBiomes)
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_LARGE_A, mapZoom, mc, 2, 3, 1004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_LARGE_B, mapZoom, mc, 2, 3, 1005, p, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
}
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_SMOOTH_4, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
|
|
|
// river layer chain
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_RIVER, mapZoom, mc, 2, 3, 1000,
|
|
|
|
l+L_RIVER_INIT_256, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_RIVER, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_32_RIVER, mapZoom, mc, 2, 3, 1000, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_16_RIVER, mapZoom, mc, 2, 3, 1001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8_RIVER, mapZoom, mc, 2, 3, 1002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4_RIVER, mapZoom, mc, 2, 3, 1003, p, 0);
|
2021-07-18 17:48:54 +08:00
|
|
|
|
2021-07-20 00:11:36 +08:00
|
|
|
if (largeBiomes && mc == MC_1_7)
|
2021-07-18 17:48:54 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_L_RIVER_A, mapZoom, mc, 2, 3, 1004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_L_RIVER_B, mapZoom, mc, 2, 3, 1005, p, 0);
|
2021-07-18 17:48:54 +08:00
|
|
|
}
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_RIVER_4, mapRiver, mc, 1, 2, 1, p, 0);
|
|
|
|
p = setupLayer(l+L_SMOOTH_4_RIVER, mapSmooth, mc, 1, 2, 1000, p, 0);
|
2020-05-05 17:32:35 +08:00
|
|
|
}
|
2018-03-11 05:45:57 +08:00
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_RIVER_MIX_4, mapRiverMix, mc, 1, 0, 100,
|
|
|
|
l+L_SMOOTH_4, l+L_SMOOTH_4_RIVER);
|
2019-05-07 05:14:25 +08:00
|
|
|
|
|
|
|
|
2021-04-19 01:50:08 +08:00
|
|
|
if (mc <= MC_1_12)
|
2018-11-29 12:32:12 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_VORONOI_1, mapVoronoi114, mc, 4, 3, 10, p, 0);
|
2019-05-07 05:14:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ocean variants
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_OCEAN_TEMP_256, mapOceanTemp, mc, 1, 0, 2, 0, 0);
|
2021-04-19 01:50:08 +08:00
|
|
|
p->noise = &g->oceanRnd;
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_ZOOM_128_OCEAN, mapZoom, mc, 2, 3, 2001, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_64_OCEAN, mapZoom, mc, 2, 3, 2002, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_32_OCEAN, mapZoom, mc, 2, 3, 2003, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_16_OCEAN, mapZoom, mc, 2, 3, 2004, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_8_OCEAN, mapZoom, mc, 2, 3, 2005, p, 0);
|
|
|
|
p = setupLayer(l+L_ZOOM_4_OCEAN, mapZoom, mc, 2, 3, 2006, p, 0);
|
|
|
|
p = setupLayer(l+L_OCEAN_MIX_4, mapOceanMix, mc, 1, 17, 100,
|
|
|
|
l+L_RIVER_MIX_4, l+L_ZOOM_4_OCEAN);
|
2021-04-19 01:50:08 +08:00
|
|
|
|
|
|
|
if (mc <= MC_1_14)
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_VORONOI_1, mapVoronoi114, mc, 4, 3, 10, p, 0);
|
2021-03-06 23:20:24 +08:00
|
|
|
else
|
2021-11-19 06:13:44 +08:00
|
|
|
p = setupLayer(l+L_VORONOI_1, mapVoronoi, mc, 4, 3, LAYER_INIT_SHA, p, 0);
|
2018-11-29 12:32:12 +08:00
|
|
|
}
|
|
|
|
|
2021-04-19 01:50:08 +08:00
|
|
|
g->entry_1 = p;
|
2021-11-19 06:13:44 +08:00
|
|
|
g->entry_4 = l + (mc <= MC_1_12 ? L_RIVER_MIX_4 : L_OCEAN_MIX_4);
|
2021-07-18 17:48:54 +08:00
|
|
|
if (largeBiomes)
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
g->entry_16 = l + L_ZOOM_4;
|
|
|
|
g->entry_64 = l + (mc <= MC_1_6 ? L_SWAMP_RIVER_16 : L_SHORE_16);
|
2022-09-05 04:40:19 +08:00
|
|
|
g->entry_256 = l + (mc <= MC_1_6 ? L_HILLS_64 : L_SUNFLOWER_64);
|
2021-07-18 17:48:54 +08:00
|
|
|
}
|
2021-07-24 01:56:59 +08:00
|
|
|
else if (mc >= MC_1_1)
|
2021-07-18 17:48:54 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
g->entry_16 = l + (mc <= MC_1_6 ? L_SWAMP_RIVER_16 : L_SHORE_16);
|
2022-09-05 04:40:19 +08:00
|
|
|
g->entry_64 = l + (mc <= MC_1_6 ? L_HILLS_64 : L_SUNFLOWER_64);
|
2021-11-19 06:13:44 +08:00
|
|
|
g->entry_256 = l + (mc <= MC_1_14 ? L_BIOME_256 : L_BAMBOO_256);
|
2021-07-18 17:48:54 +08:00
|
|
|
}
|
2021-07-24 01:56:59 +08:00
|
|
|
else
|
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
g->entry_16 = l + L_ZOOM_16;
|
|
|
|
g->entry_64 = l + L_ZOOM_64;
|
|
|
|
g->entry_256 = l + L_BIOME_256;
|
2021-07-24 01:56:59 +08:00
|
|
|
}
|
2021-04-19 01:50:08 +08:00
|
|
|
setupScale(g->entry_1, 1);
|
2018-11-29 12:32:12 +08:00
|
|
|
}
|
|
|
|
|
2020-05-05 18:49:06 +08:00
|
|
|
|
2018-07-28 22:36:41 +08:00
|
|
|
/* Recursively calculates the minimum buffer size required to generate an area
|
|
|
|
* of the specified size from the current layer onwards.
|
|
|
|
*/
|
2021-09-04 16:35:09 +08:00
|
|
|
static void getMaxArea(
|
|
|
|
const Layer *layer, int areaX, int areaZ, int *maxX, int *maxZ, size_t *siz)
|
2018-03-06 05:20:54 +08:00
|
|
|
{
|
2018-07-28 22:36:41 +08:00
|
|
|
if (layer == NULL)
|
2018-03-11 05:45:57 +08:00
|
|
|
return;
|
2018-03-06 05:20:54 +08:00
|
|
|
|
2021-09-04 16:35:09 +08:00
|
|
|
areaX += layer->edge;
|
|
|
|
areaZ += layer->edge;
|
|
|
|
|
2022-05-22 19:39:33 +08:00
|
|
|
// multi-layers and zoom-layers use a temporary copy of their parent area
|
|
|
|
if (layer->p2 || layer->zoom != 1)
|
|
|
|
*siz += areaX * areaZ;
|
|
|
|
|
2021-09-04 16:35:09 +08:00
|
|
|
if (areaX > *maxX) *maxX = areaX;
|
|
|
|
if (areaZ > *maxZ) *maxZ = areaZ;
|
|
|
|
|
2021-04-19 01:50:08 +08:00
|
|
|
if (layer->zoom == 2)
|
2018-03-06 05:20:54 +08:00
|
|
|
{
|
2020-08-10 00:52:58 +08:00
|
|
|
areaX >>= 1;
|
|
|
|
areaZ >>= 1;
|
2018-03-11 05:45:57 +08:00
|
|
|
}
|
2021-04-19 01:50:08 +08:00
|
|
|
else if (layer->zoom == 4)
|
2018-03-11 05:45:57 +08:00
|
|
|
{
|
2020-08-10 00:52:58 +08:00
|
|
|
areaX >>= 2;
|
|
|
|
areaZ >>= 2;
|
2018-03-06 05:20:54 +08:00
|
|
|
}
|
|
|
|
|
2021-09-04 16:35:09 +08:00
|
|
|
getMaxArea(layer->p, areaX, areaZ, maxX, maxZ, siz);
|
|
|
|
if (layer->p2)
|
|
|
|
getMaxArea(layer->p2, areaX, areaZ, maxX, maxZ, siz);
|
2018-03-11 05:45:57 +08:00
|
|
|
}
|
|
|
|
|
2021-11-19 06:13:44 +08:00
|
|
|
size_t getMinLayerCacheSize(const Layer *layer, int sizeX, int sizeZ)
|
2018-03-11 05:45:57 +08:00
|
|
|
{
|
2021-11-19 06:13:44 +08:00
|
|
|
int maxX = sizeX, maxZ = sizeZ;
|
2021-09-04 16:35:09 +08:00
|
|
|
size_t bufsiz = 0;
|
2021-11-19 06:13:44 +08:00
|
|
|
getMaxArea(layer, sizeX, sizeZ, &maxX, &maxZ, &bufsiz);
|
2021-09-04 16:35:09 +08:00
|
|
|
return bufsiz + maxX * (size_t)maxZ;
|
2018-03-06 05:20:54 +08:00
|
|
|
}
|
|
|
|
|
2020-08-10 00:52:58 +08:00
|
|
|
int genArea(const Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight)
|
2018-03-06 05:20:54 +08:00
|
|
|
{
|
2023-05-20 21:57:06 +08:00
|
|
|
memset(out, 0, sizeof(*out)*areaWidth*areaHeight);
|
2020-08-10 00:52:58 +08:00
|
|
|
return layer->getMap(layer, out, areaX, areaZ, areaWidth, areaHeight);
|
2018-03-06 05:20:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-16 02:44:14 +08:00
|
|
|
int mapApproxHeight(float *y, int *ids, const Generator *g, const SurfaceNoise *sn,
|
2022-12-30 20:20:29 +08:00
|
|
|
int x, int z, int w, int h)
|
|
|
|
{
|
2024-06-03 04:12:34 +08:00
|
|
|
if (g->dim == DIM_NETHER)
|
|
|
|
return 127;
|
|
|
|
|
|
|
|
if (g->dim == DIM_END)
|
|
|
|
{
|
|
|
|
if (g->mc <= MC_1_8)
|
|
|
|
return 1;
|
2024-10-07 19:20:00 +08:00
|
|
|
return mapEndSurfaceHeight(y, &g->en, sn, x, z, w, h, 4, 0);
|
2024-06-03 04:12:34 +08:00
|
|
|
}
|
2022-12-30 20:20:29 +08:00
|
|
|
|
2023-01-05 18:02:02 +08:00
|
|
|
if (g->mc >= MC_1_18)
|
|
|
|
{
|
|
|
|
if (g->bn.nptype != -1 && g->bn.nptype != NP_DEPTH)
|
|
|
|
return 1;
|
2023-05-20 21:57:06 +08:00
|
|
|
int64_t i, j;
|
2023-01-05 18:02:02 +08:00
|
|
|
for (j = 0; j < h; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
{
|
2023-01-16 02:44:14 +08:00
|
|
|
int flags = 0;//SAMPLE_NO_SHIFT;
|
2023-01-05 18:02:02 +08:00
|
|
|
int64_t np[6];
|
|
|
|
int id = sampleBiomeNoise(&g->bn, np, x+i, 0, z+j, 0, flags);
|
|
|
|
if (ids)
|
|
|
|
ids[j*w+i] = id;
|
2023-01-16 02:44:14 +08:00
|
|
|
y[j*w+i] = np[NP_DEPTH] / 76.0;
|
2023-01-05 18:02:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2023-02-18 18:27:49 +08:00
|
|
|
else if (g->mc <= MC_B1_7)
|
|
|
|
{
|
|
|
|
SurfaceNoiseBeta snb; // TODO: merge SurfaceNoise and SurfaceNoiseBeta?
|
|
|
|
initSurfaceNoiseBeta(&snb, g->seed);
|
2023-05-20 21:57:06 +08:00
|
|
|
int64_t i, j;
|
2023-02-18 18:27:49 +08:00
|
|
|
for (j = 0; j < h; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
{
|
2023-05-20 21:57:06 +08:00
|
|
|
int samplex = (x + i) * 4 + 2;
|
|
|
|
int samplez = (z + j) * 4 + 2;
|
2023-02-18 18:27:49 +08:00
|
|
|
// TODO: properly implement beta surface finder
|
|
|
|
y[j*w+i] = approxSurfaceBeta(&g->bnb, &snb, samplex, samplez);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2023-01-05 18:02:02 +08:00
|
|
|
|
2022-12-30 20:20:29 +08:00
|
|
|
const float biome_kernel[25] = { // with 10 / (sqrt(i**2 + j**2) + 0.2)
|
|
|
|
3.302044127, 4.104975761, 4.545454545, 4.104975761, 3.302044127,
|
|
|
|
4.104975761, 6.194967155, 8.333333333, 6.194967155, 4.104975761,
|
|
|
|
4.545454545, 8.333333333, 50.00000000, 8.333333333, 4.545454545,
|
|
|
|
4.104975761, 6.194967155, 8.333333333, 6.194967155, 4.104975761,
|
|
|
|
3.302044127, 4.104975761, 4.545454545, 4.104975761, 3.302044127,
|
|
|
|
};
|
|
|
|
|
2023-05-20 21:57:06 +08:00
|
|
|
double *depth = (double*) malloc(sizeof(double) * 2 * w * h);
|
2022-12-30 20:20:29 +08:00
|
|
|
double *scale = depth + w * h;
|
2023-05-20 21:57:06 +08:00
|
|
|
int64_t i, j;
|
|
|
|
int ii, jj;
|
2022-12-30 20:20:29 +08:00
|
|
|
|
|
|
|
Range r = {4, x-2, z-2, w+5, h+5, 0, 1};
|
|
|
|
int *cache = allocCache(g, r);
|
|
|
|
genBiomes(g, cache, r);
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
{
|
|
|
|
double d0, s0;
|
|
|
|
double wt = 0, ws = 0, wd = 0;
|
|
|
|
int id0 = cache[(j+2)*r.sx + (i+2)];
|
|
|
|
getBiomeDepthAndScale(id0, &d0, &s0, 0);
|
|
|
|
|
|
|
|
for (jj = 0; jj < 5; jj++)
|
|
|
|
{
|
|
|
|
for (ii = 0; ii < 5; ii++)
|
|
|
|
{
|
|
|
|
double d, s;
|
|
|
|
int id = cache[(j+jj)*r.sx + (i+ii)];
|
|
|
|
getBiomeDepthAndScale(id, &d, &s, 0);
|
|
|
|
float weight = biome_kernel[jj*5+ii] / (d + 2);
|
|
|
|
if (d > d0)
|
|
|
|
weight *= 0.5;
|
|
|
|
ws += s * weight;
|
|
|
|
wd += d * weight;
|
|
|
|
wt += weight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ws /= wt;
|
|
|
|
wd /= wt;
|
|
|
|
ws = ws * 0.9 + 0.1;
|
|
|
|
wd = (wd * 4.0 - 1) / 8;
|
|
|
|
ws = 96 / ws;
|
|
|
|
wd = wd * 17./64;
|
|
|
|
depth[j*w+i] = wd;
|
|
|
|
scale[j*w+i] = ws;
|
|
|
|
if (ids)
|
|
|
|
ids[j*w+i] = id0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(cache);
|
|
|
|
|
|
|
|
for (j = 0; j < h; j++)
|
|
|
|
{
|
|
|
|
for (i = 0; i < w; i++)
|
|
|
|
{
|
|
|
|
int px = x+i, pz = z+j;
|
|
|
|
double off = sampleOctaveAmp(&sn->octdepth, px*200, 10, pz*200, 1, 0, 1);
|
|
|
|
off *= 65535./8000;
|
|
|
|
if (off < 0) off = -0.3 * off;
|
|
|
|
off = off * 3 - 2;
|
|
|
|
if (off > 1) off = 1;
|
|
|
|
off *= 17./64;
|
|
|
|
if (off < 0) off *= 1./28;
|
|
|
|
else off *= 1./40;
|
|
|
|
|
|
|
|
double vmin = 0, vmax = 0;
|
|
|
|
int ytest = 8, ymin = 0, ymax = 32;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
double v[2];
|
|
|
|
int k;
|
|
|
|
for (k = 0; k < 2; k++)
|
|
|
|
{
|
|
|
|
int py = ytest + k;
|
|
|
|
double n0 = sampleSurfaceNoise(sn, px, py, pz);
|
|
|
|
double fall = 1 - 2 * py / 32.0 + off - 0.46875;
|
|
|
|
fall = scale[j*w+i] * (fall + depth[j*w+i]);
|
|
|
|
n0 += (fall > 0 ? 4*fall : fall);
|
|
|
|
v[k] = n0;
|
|
|
|
if (n0 >= 0 && py > ymin)
|
|
|
|
{
|
|
|
|
ymin = py;
|
|
|
|
vmin = n0;
|
|
|
|
}
|
|
|
|
if (n0 < 0 && py < ymax)
|
|
|
|
{
|
|
|
|
ymax = py;
|
|
|
|
vmax = n0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
double dy = v[0] / (v[0] - v[1]);
|
|
|
|
dy = (dy <= 0 ? floor(dy) : ceil(dy)); // round away from zero
|
|
|
|
ytest += (int) dy;
|
|
|
|
if (ytest <= ymin) ytest = ymin+1;
|
|
|
|
if (ytest >= ymax) ytest = ymax-1;
|
|
|
|
}
|
|
|
|
while (ymax - ymin > 1);
|
|
|
|
|
2023-01-16 02:44:14 +08:00
|
|
|
y[j*w+i] = 8 * (vmin / (double)(vmin - vmax) + ymin);
|
2022-12-30 20:20:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
free(depth);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-03-06 05:20:54 +08:00
|
|
|
|
2021-06-06 23:00:35 +08:00
|
|
|
|
|
|
|
|