diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSimple.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSimple.java
new file mode 100644
index 0000000..3d34549
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSimple.java
@@ -0,0 +1,99 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.client.world.cro;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.Consumer;
+
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.client.graphics.backend.Usage;
+import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.client.graphics.model.Shape;
+import ru.windcorp.progressia.client.graphics.model.ShapePart;
+import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
+import ru.windcorp.progressia.client.world.block.BlockRender;
+import ru.windcorp.progressia.client.world.tile.TileRender;
+import ru.windcorp.progressia.common.world.DefaultChunkData;
+import ru.windcorp.progressia.common.world.rels.RelFace;
+
+public class ChunkRenderOptimizerSimple extends ChunkRenderOptimizer {
+
+ public interface BlockOptimizedSimple {
+
+ void getShapeParts(
+ DefaultChunkData chunk,
+ Vec3i relBlockInChunk,
+ Consumer output
+ );
+
+ }
+
+ public interface TileOptimizedCustom {
+
+ void getShapeParts(
+ DefaultChunkData chunk,
+ Vec3i relBlockInChunk,
+ RelFace blockFace,
+ Consumer output
+ );
+
+ }
+
+ private final Collection parts = new ArrayList<>();
+ private final Consumer partAdder = parts::add;
+
+ public ChunkRenderOptimizerSimple(String id) {
+ super(id);
+ }
+
+ @Override
+ public void startRender() {
+ parts.clear();
+ }
+
+ @Override
+ public void addBlock(BlockRender block, Vec3i relBlockInChunk) {
+ if (block instanceof BlockOptimizedSimple) {
+ ((BlockOptimizedSimple) block).getShapeParts(chunk.getData(), relBlockInChunk, partAdder);
+ }
+ }
+
+ @Override
+ public void addTile(TileRender tile, Vec3i relBlockInChunk, RelFace blockFace) {
+ if (tile instanceof TileOptimizedCustom) {
+ ((TileOptimizedCustom) tile).getShapeParts(chunk.getData(), relBlockInChunk, blockFace, partAdder);
+ }
+ }
+
+ @Override
+ public Renderable endRender() {
+
+ if (parts.isEmpty()) {
+ return null;
+ }
+
+ return new Shape(
+ Usage.STATIC,
+ WorldRenderProgram.getDefault(),
+ parts.toArray(new ShapePart[parts.size()])
+ );
+
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderCross.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderCross.java
new file mode 100644
index 0000000..01af8f6
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderCross.java
@@ -0,0 +1,170 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.client.world.tile;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.Consumer;
+
+import glm.mat._3.Mat3;
+import glm.mat._4.Mat4;
+import glm.vec._3.Vec3;
+import glm.vec._3.i.Vec3i;
+import glm.vec._4.Vec4;
+import ru.windcorp.progressia.client.graphics.Colors;
+import ru.windcorp.progressia.client.graphics.backend.Usage;
+import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.client.graphics.model.Shape;
+import ru.windcorp.progressia.client.graphics.model.ShapePart;
+import ru.windcorp.progressia.client.graphics.model.ShapeParts;
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
+import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple.TileOptimizedCustom;
+import ru.windcorp.progressia.common.util.Matrices;
+import ru.windcorp.progressia.common.util.VectorUtil;
+import ru.windcorp.progressia.common.util.Vectors;
+import ru.windcorp.progressia.common.world.DefaultChunkData;
+import ru.windcorp.progressia.common.world.rels.AbsFace;
+import ru.windcorp.progressia.common.world.rels.AxisRotations;
+import ru.windcorp.progressia.common.world.rels.RelFace;
+
+public class TileRenderCross extends TileRender implements TileOptimizedCustom {
+
+ private static final float SQRT_2_OVER_2 = (float) Math.sqrt(2) / 2;
+ private static final float[] ONE_AND_NEGATIVE_ONE = new float[] { 1, -1 };
+
+ private final Texture texture;
+ private final float width;
+
+ public TileRenderCross(String id, Texture texture, boolean allowStretching) {
+ super(id);
+ this.texture = texture;
+ this.width = allowStretching ? 1 : SQRT_2_OVER_2;
+ }
+
+ public Texture getTexture(RelFace blockFace) {
+ return texture;
+ }
+
+ public Vec4 getColorMultiplier(RelFace blockFace) {
+ return Colors.WHITE;
+ }
+
+ @Override
+ public void getShapeParts(
+ DefaultChunkData chunk,
+ Vec3i bic,
+ RelFace blockFace,
+ Consumer output
+ ) {
+ Mat4 transform = Matrices.grab4();
+ Vec3 origin = Vectors.grab3();
+ Vec3 width = Vectors.grab3();
+ Vec3 height = Vectors.grab3();
+
+ Mat3 resolutionMatrix = AxisRotations.getResolutionMatrix3(blockFace.resolve(AbsFace.POS_Z));
+
+ Vec4 color = getColorMultiplier(blockFace);
+ Texture texture = getTexture(blockFace);
+ float originOffset = (1 - this.width) / 2;
+
+ WorldRenderProgram program = WorldRenderProgram.getDefault();
+
+ for (int i = 0; getTransform(chunk, bic, blockFace, i, transform); i++) {
+
+ for (float flip : ONE_AND_NEGATIVE_ONE) {
+ origin.set(flip * (originOffset - 0.5f), originOffset - 0.5f, 0);
+ width.set(flip * this.width, this.width, 0);
+ height.set(0, 0, 1);
+
+ VectorUtil.applyMat4(origin, transform);
+ VectorUtil.rotateOnly(width, transform);
+ VectorUtil.rotateOnly(height, transform);
+
+ origin.z += 1 - 0.5f;
+
+ if (blockFace != RelFace.UP) {
+ resolutionMatrix.mul(origin);
+ resolutionMatrix.mul(width);
+ resolutionMatrix.mul(height);
+ }
+
+ origin.add(bic.x, bic.y, bic.z);
+
+ output.accept(
+ ShapeParts.createRectangle(
+ program,
+ texture,
+ color,
+ origin,
+ width,
+ height,
+ false
+ )
+ );
+ output.accept(
+ ShapeParts.createRectangle(
+ program,
+ texture,
+ color,
+ origin,
+ width,
+ height,
+ true
+ )
+ );
+ }
+
+ }
+
+ Matrices.release(transform);
+ Vectors.release(origin);
+ Vectors.release(width);
+ Vectors.release(height);
+ }
+
+ protected boolean getTransform(
+ DefaultChunkData chunk,
+ Vec3i relBlockInChunk,
+ RelFace blockFace,
+ int count,
+ Mat4 output
+ ) {
+ output.identity();
+ return count == 0;
+ }
+
+ @Override
+ public Renderable createRenderable(DefaultChunkData chunk, Vec3i blockInChunk, RelFace blockFace) {
+ Collection parts = new ArrayList<>(4);
+
+ getShapeParts(chunk, blockInChunk, blockFace, parts::add);
+
+ return new Shape(
+ Usage.STATIC,
+ WorldRenderProgram.getDefault(),
+ parts.toArray(new ShapePart[parts.size()])
+ );
+ }
+
+ @Override
+ public boolean needsOwnRenderable() {
+ return false;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java
index f25368f..3f33e50 100644
--- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java
+++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java
@@ -180,6 +180,25 @@ public class VectorUtil {
return applyMat4(inOut, mat, inOut);
}
+ public static Vec3 rotateOnly(Vec3 in, Mat4 mat, Vec3 out) {
+ if (out == null) {
+ out = new Vec3();
+ }
+
+ Mat3 mat3 = Matrices.grab3();
+ mat3.set(mat);
+
+ mat3.mul(in, out);
+
+ Matrices.release(mat3);
+
+ return out;
+ }
+
+ public static Vec3 rotateOnly(Vec3 inOut, Mat4 mat) {
+ return rotateOnly(inOut, mat, inOut);
+ }
+
public static Vec3 rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) {
if (out == null) {
out = new Vec3();
diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java
index b4dfedc..09e4ff1 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/DefaultServerContextImpl.java
@@ -405,7 +405,7 @@ class DefaultServerContextImpl extends DefaultServerContext
@Override
public int getTileCount(Vec3i location, RelFace face) {
- assert requireContextRole(Role.TILE_STACK);
+ assert requireContextRole(Role.WORLD);
TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z));
if (stack == null)
return 0;
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java
index 6050c49..2ec6636 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/context/SurfaceContextImpl.java
@@ -20,7 +20,9 @@ package ru.windcorp.progressia.server.world.generation.surface.context;
import java.util.Random;
import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.common.world.generic.TileGenericStackRO;
import ru.windcorp.progressia.common.world.rels.RelFace;
+import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.server.world.context.ServerTileContext;
import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext;
import ru.windcorp.progressia.server.world.generation.surface.Surface;
@@ -110,5 +112,12 @@ public class SurfaceContextImpl extends RotatingServerContext implements Surface
super.push(location, face, layer);
return this;
}
+
+ @Override
+ public void addTile(Vec3i userLocation, RelFace userFace, TileData tile) {
+ if (getTileCount(userLocation, userFace) < TileGenericStackRO.TILES_PER_FACE) {
+ super.addTile(userLocation, userFace, tile);
+ }
+ }
}
diff --git a/src/main/java/ru/windcorp/progressia/test/Rocks.java b/src/main/java/ru/windcorp/progressia/test/Rocks.java
index ebf31fe..d137376 100644
--- a/src/main/java/ru/windcorp/progressia/test/Rocks.java
+++ b/src/main/java/ru/windcorp/progressia/test/Rocks.java
@@ -82,6 +82,10 @@ public class Rocks {
public BlockData getBlock(RockVariant variant) {
return blocks.get(variant);
}
+
+ public Collection getBlocks() {
+ return blocks.values();
+ }
private void register() {
for (RockVariant variant : RockVariant.values()) {
diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java
index 1244560..3be2c7e 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestContent.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java
@@ -38,6 +38,7 @@ import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
import ru.windcorp.progressia.client.graphics.world.Selection;
import ru.windcorp.progressia.client.world.block.*;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
+import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSimple;
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSurface;
import ru.windcorp.progressia.client.world.entity.*;
import ru.windcorp.progressia.client.world.tile.*;
@@ -174,9 +175,20 @@ public class TestContent {
register(new TileRenderTransparentSurface("Test:Stones", getTileTexture("Stones")));
register(new HangingTileLogic("Test:Stones"));
- register(new TileData("Test:YellowFlowers"));
- register(new TileRenderTransparentSurface("Test:YellowFlowers", getTileTexture("YellowFlowers")));
- register(new HangingTileLogic("Test:YellowFlowers"));
+ for (String color : new String[] {
+ "Yellow",
+ "White",
+ "Purple",
+ "Blue"
+ }) {
+
+ String fullName = color + "Flowers";
+ String id = "Test:" + fullName;
+
+ register(new TileData(id));
+ register(new TileRenderTransparentSurface(id, getTileTexture(fullName)));
+ register(new HangingTileLogic(id));
+ }
register(new TileData("Test:Sand"));
register(new TileRenderTransparentSurface("Test:Sand", getTileTexture("Sand")));
@@ -241,6 +253,32 @@ public class TestContent {
register(new TileData("Test:TilesSmall"));
register(new TileRenderOpaqueSurface("Test:TilesSmall", getTileTexture("TilesSmall")));
register(new HangingTileLogic("Test:TilesSmall"));
+
+ for (String variant : new String[] {
+ "Low", "Medium", "Tall"
+ }) {
+ String fullName = variant + "Grass";
+ String id = "Test:" + fullName;
+
+ register(new TileData(id));
+ register(new TileRenderHerb(id, getTileTexture(fullName), 6));
+ register(new HangingTileLogic(id));
+ }
+
+ for (String variant : new String[] {
+ "Dandelion", "Lavander"
+ }) {
+ String fullName = "Tiny" + variant + "Flowers";
+ String id = "Test:" + fullName;
+
+ register(new TileData(id));
+ register(new TileRenderTinyFlower(id, getTileTexture(fullName), 8, 0.5f));
+ register(new HangingTileLogic(id));
+ }
+
+ register(new TileData("Test:Bush"));
+ register(new TileRenderHerb("Test:Bush", getTileTexture("Bush"), 1));
+ register(new HangingTileLogic("Test:Bush"));
TileDataRegistry.getInstance().values().forEach(PLACEABLE_TILES::add);
PLACEABLE_TILES.removeIf(b -> placeableBlacklist.contains(b.getId()));
@@ -285,6 +323,7 @@ public class TestContent {
i -> isAnythingSelected() && TestPlayerControls.getInstance().isBlockSelected()
)
);
+
logic.register(ControlLogic.of("Test:PlaceBlock", TestContent::onBlockPlaceReceived));
data.register("Test:PlaceTile", ControlPlaceTileData::new);
@@ -442,7 +481,10 @@ public class TestContent {
private static void registerMisc() {
ChunkIO.registerCodec(new TestChunkCodec());
+
ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new);
+ ChunkRenderOptimizerRegistry.getInstance().register("Core:SimpleOptimizer", ChunkRenderOptimizerSimple::new);
+
GravityModelRegistry.getInstance().register("Test:TheGravityModel", TestGravityModel::new);
GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", PlanetGravityModel::new);
}
diff --git a/src/main/java/ru/windcorp/progressia/test/TileRenderHerb.java b/src/main/java/ru/windcorp/progressia/test/TileRenderHerb.java
new file mode 100644
index 0000000..866d803
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/TileRenderHerb.java
@@ -0,0 +1,89 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.test;
+
+import glm.mat._4.Mat4;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.client.world.tile.TileRenderCross;
+import ru.windcorp.progressia.common.world.DefaultChunkData;
+import ru.windcorp.progressia.common.world.rels.RelFace;
+
+public class TileRenderHerb extends TileRenderCross {
+
+ /*
+ * Stolen from OpenJDK's Random implementation
+ * *evil cackling*
+ */
+ private static final long MULTIPLIER = 0x5DEECE66DL;
+ private static final long ADDEND = 0xBL;
+ private static final long MASK = (1L << 48) - 1;
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+ private static long permute(long seed) {
+ return (seed * MULTIPLIER + ADDEND) & MASK;
+ }
+
+ private static double getDouble(long seed) {
+ final int mask26bits = (1 << 26) - 1;
+ final int mask27bits = (1 << 27) - 1;
+
+ int randomBitsX26 = (int) (seed & 0xFFFFFFFF);
+ int randomBitsX27 = (int) ((seed >>> Integer.SIZE) & 0xFFFFFFFF);
+
+ randomBitsX26 = randomBitsX26 & mask26bits;
+ randomBitsX27 = randomBitsX27 & mask27bits;
+
+ return (((long) (randomBitsX26) << 27) + randomBitsX27) * DOUBLE_UNIT;
+ }
+
+ private final int maxCount;
+
+ public TileRenderHerb(String id, Texture texture, int maxCount) {
+ super(id, texture, true);
+ this.maxCount = maxCount;
+ }
+
+ @Override
+ protected boolean getTransform(
+ DefaultChunkData chunk,
+ Vec3i relBlockInChunk,
+ RelFace blockFace,
+ int count,
+ Mat4 output
+ ) {
+
+ long seed = permute(count ^ getId().hashCode());
+ seed = permute(seed + relBlockInChunk.x);
+ seed = permute(seed + relBlockInChunk.y);
+ seed = permute(seed + relBlockInChunk.z);
+ seed = permute(seed + blockFace.getId());
+
+ float x = (float) getDouble(seed) * 0.8f - 0.4f;
+ seed = permute(seed);
+ float y = (float) getDouble(seed) * 0.8f - 0.4f;
+ seed = permute(seed);
+ float size = (float) getDouble(seed) * 0.5f + 0.5f;
+ seed = permute(seed);
+ double rotation = getDouble(seed) * Math.PI / 8;
+
+ output.identity().translate(x, y, 0).scale(size).rotateZ(rotation);
+ return (count == 0) || ((count < maxCount) && (seed % 3 != 0));
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/TileRenderTinyFlower.java b/src/main/java/ru/windcorp/progressia/test/TileRenderTinyFlower.java
new file mode 100644
index 0000000..28985b9
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/TileRenderTinyFlower.java
@@ -0,0 +1,48 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.test;
+
+import glm.mat._4.Mat4;
+import glm.vec._3.i.Vec3i;
+import ru.windcorp.progressia.client.graphics.texture.Texture;
+import ru.windcorp.progressia.common.world.DefaultChunkData;
+import ru.windcorp.progressia.common.world.rels.RelFace;
+
+public class TileRenderTinyFlower extends TileRenderHerb {
+
+ private final float size;
+
+ public TileRenderTinyFlower(String id, Texture texture, int maxCount, float size) {
+ super(id, texture, maxCount);
+ this.size = size;
+ }
+
+ @Override
+ protected boolean getTransform(
+ DefaultChunkData chunk,
+ Vec3i relBlockInChunk,
+ RelFace blockFace,
+ int count,
+ Mat4 output
+ ) {
+ boolean result = super.getTransform(chunk, relBlockInChunk, blockFace, count, output);
+ output.scale(size);
+ return result;
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/Fields.java b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java
index 86741df..26ccdca 100644
--- a/src/main/java/ru/windcorp/progressia/test/gen/Fields.java
+++ b/src/main/java/ru/windcorp/progressia/test/gen/Fields.java
@@ -214,6 +214,10 @@ public class Fields {
public static Field bias(Field f, double bias) {
return tweak(f, 1, 1, bias);
}
+
+ public static Field anti(Field f) {
+ return tweak(f, 1, -1, 1);
+ }
public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) {
return (x, y) -> {
@@ -221,14 +225,16 @@ public class Fields {
double scale = 1;
double amplitude = 1;
+ double cumulativeAmplitude = 0;
for (int i = 0; i < octaves; ++i) {
result += f.compute(x * scale, y * scale) * amplitude;
+ cumulativeAmplitude += amplitude;
scale *= scaleFactor;
amplitude /= amplitudeFactor;
}
- return result;
+ return result / cumulativeAmplitude;
};
}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestFlowerFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestFlowerFeature.java
new file mode 100644
index 0000000..33460a1
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/gen/TestFlowerFeature.java
@@ -0,0 +1,95 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.test.gen;
+
+import java.util.Set;
+import java.util.function.Function;
+
+import com.google.common.collect.ImmutableSet;
+
+import ru.windcorp.progressia.common.world.rels.RelFace;
+import ru.windcorp.progressia.common.world.tile.TileData;
+import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
+import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
+import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature;
+import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
+import ru.windcorp.progressia.test.TestContent;
+
+public class TestFlowerFeature extends SurfaceTopLayerFeature {
+
+ private static class FlowerGenerator {
+ private final TileData tile;
+ private final SurfaceFloatField floweriness;
+
+ public FlowerGenerator(TileData tile, Function flowerinessGenerator) {
+ this.tile = tile;
+ this.floweriness = flowerinessGenerator.apply(tile.getName());
+ }
+
+ public void generate(SurfaceBlockContext context) {
+ if (context.getRandom().nextDouble() < floweriness.get(context)) {
+ context.addTile(RelFace.UP, tile);
+ }
+ }
+ }
+
+ private final Set soilWhitelist;
+ {
+ ImmutableSet.Builder b = ImmutableSet.builder();
+ b.add("Test:Dirt", "Test:Stone");
+ TestContent.ROCKS.getRocks().forEach(rock -> rock.getBlocks().forEach(block -> b.add(block.getId())));
+ soilWhitelist = b.build();
+ }
+
+ private final FlowerGenerator[] flowers;
+
+ public TestFlowerFeature(String id, Function flowerinessGenerator) {
+ super(id);
+
+ this.flowers = TileDataRegistry.getInstance().values().stream()
+ .filter(tile -> tile.getName().endsWith("Flowers"))
+ .map(tile -> new FlowerGenerator(tile, flowerinessGenerator))
+ .toArray(FlowerGenerator[]::new);
+ }
+
+ @Override
+ protected void processTopBlock(SurfaceBlockContext context) {
+ if (context.getLocation().z < 0) {
+ return;
+ }
+ if (!soilWhitelist.contains(context.getBlock().getId())) {
+ return;
+ }
+
+ if (!context.pushRelative(RelFace.UP).logic().getBlock().isTransparent()) {
+ context.pop();
+ return;
+ }
+ context.pop();
+
+ for (FlowerGenerator flower : flowers) {
+ flower.generate(context);
+ }
+ }
+
+ @Override
+ protected boolean isSolid(SurfaceBlockContext context) {
+ return context.logic().getBlock().isSolid(RelFace.UP);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
index cc1ff8b..9837831 100644
--- a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
+++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
@@ -76,7 +76,7 @@ public class TestGenerationConfig {
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
- SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector");
+ SurfaceFloatField cliffs = FIELDS.get("Test:Cliff");
WorleyProceduralNoise.Builder builder = WorleyProceduralNoise.builder();
TestContent.ROCKS.getRocks().forEach(rock -> {
@@ -108,21 +108,32 @@ public class TestGenerationConfig {
private static void registerFeatures(List features) {
SurfaceFloatField forestiness = FIELDS.register(
- "Test:Forestiness",
+ "Test:Forest",
() -> squash(scale(FIELDS.primitive(), 200), 5)
);
-
- SurfaceFloatField floweriness = FIELDS.register(
- "Test:Floweriness",
+
+ SurfaceFloatField grassiness = FIELDS.register(
+ "Test:Grass",
f -> multiply(
- scale(octaves(FIELDS.primitive(), 2, 2), 40),
- tweak(FIELDS.get("Test:Forestiness", f), 1, -1, 1.1)
+ tweak(octaves(FIELDS.primitive(), 2, 2), 40, 0.5, 1.2),
+ squash(tweak(FIELDS.get("Test:Forest", f), 1, -0.7, 1), 10),
+ anti(squash(FIELDS.get("Test:Cliff", f), 10))
+ )
+ );
+
+ Function floweriness = flowerName -> FIELDS.register(
+ "Test:Flower" + flowerName,
+ f -> multiply(
+ selectPositive(squash(scale(octaves(FIELDS.primitive(), 2, 3), 100), 2), 1, 0.5),
+ tweak(FIELDS.get("Test:Forest", f), 1, -1, 1.1),
+ anti(squash(FIELDS.get("Test:Cliff", f), 10))
)
);
features.add(new TestBushFeature("Test:BushFeature", forestiness));
features.add(new TestTreeFeature("Test:TreeFeature", forestiness));
- features.add(new TestGrassFeature("Test:GrassFeature", FIELDS.get("Test:CliffSelector"), floweriness));
+ features.add(new TestGrassFeature("Test:GrassFeature", grassiness));
+ features.add(new TestFlowerFeature("Test:FlowerFeature", floweriness));
}
}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java
index d1d73e5..ca36cee 100644
--- a/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java
+++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGrassFeature.java
@@ -23,40 +23,47 @@ import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import ru.windcorp.progressia.common.util.ArrayFloatRangeMap;
+import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
+import ru.windcorp.progressia.test.TestContent;
public class TestGrassFeature extends SurfaceTopLayerFeature {
-
- private static final Set WHITELIST = ImmutableSet.of(
- "Test:Dirt",
- "Test:Stone",
- "Test:GraniteMonolith",
- "Test:GraniteCracked",
- "Test:GraniteGravel"
- );
-
+
+ private final Set soilWhitelist;
+ {
+ ImmutableSet.Builder b = ImmutableSet.builder();
+ b.add("Test:Dirt", "Test:Stone");
+ TestContent.ROCKS.getRocks().forEach(rock -> rock.getBlocks().forEach(block -> b.add(block.getId())));
+ soilWhitelist = b.build();
+ }
+
private final SurfaceFloatField grassiness;
- private final SurfaceFloatField floweriness;
- private final double scatterDensity = 1.0 / (3*3);
-
+ private final double scatterDensity = 1.0 / (3 * 3);
+
private final TileData grass = TileDataRegistry.getInstance().get("Test:Grass");
- private final List flowers = ImmutableList.of(
- TileDataRegistry.getInstance().get("Test:YellowFlowers")
- );
+
+ private final FloatRangeMap grasses = new ArrayFloatRangeMap<>();
+ {
+ grasses.put(0.6f, 1, TileDataRegistry.getInstance().get("Test:TallGrass"));
+ grasses.put(0.4f, 0.6f, TileDataRegistry.getInstance().get("Test:MediumGrass"));
+ grasses.put(0.1f, 0.4f, TileDataRegistry.getInstance().get("Test:LowGrass"));
+ }
+
private final List scatter = ImmutableList.of(
TileDataRegistry.getInstance().get("Test:Stones"),
- TileDataRegistry.getInstance().get("Test:Sand")
+ TileDataRegistry.getInstance().get("Test:Sand"),
+ TileDataRegistry.getInstance().get("Test:Bush")
);
- public TestGrassFeature(String id, SurfaceFloatField grassiness, SurfaceFloatField floweriness) {
+ public TestGrassFeature(String id, SurfaceFloatField grassiness) {
super(id);
this.grassiness = grassiness;
- this.floweriness = floweriness;
}
@Override
@@ -64,26 +71,22 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
if (context.getLocation().z < 0) {
return;
}
- if (!WHITELIST.contains(context.getBlock().getId())) {
+ if (!soilWhitelist.contains(context.getBlock().getId())) {
return;
}
-
+
if (!context.pushRelative(RelFace.UP).logic().getBlock().isTransparent()) {
context.pop();
return;
}
context.pop();
-
+
double grassiness = this.grassiness.get(context);
- if (grassiness < 0.2) {
- growGrass(context);
+ if (grassiness > 0.1) {
+ growGrass(context, grassiness);
}
-
+
placeScatter(context);
-
- if (grassiness < 0.2) {
- growFlowers(context);
- }
}
private void placeScatter(SurfaceBlockContext context) {
@@ -93,24 +96,25 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
}
}
- private void growGrass(SurfaceBlockContext context) {
+ private void growGrass(SurfaceBlockContext context, double grassiness) {
for (RelFace face : RelFace.getFaces()) {
- if (face == RelFace.DOWN) continue;
-
+ if (face == RelFace.DOWN)
+ continue;
+
if (context.pushRelative(face).logic().getBlock().isTransparent()) {
context.pop();
context.addTile(face, grass);
} else {
context.pop();
}
-
- }
- }
- private void growFlowers(SurfaceBlockContext context) {
- if (context.getRandom().nextDouble() < floweriness.get(context)) {
- TileData tile = pickRandom(context, flowers);
- context.addTile(RelFace.UP, tile);
+ }
+
+ if (context.getRandom().nextDouble() < grassiness) {
+ TileData herbGrass = grasses.get((float) grassiness);
+ if (herbGrass != null) {
+ context.addTile(RelFace.UP, herbGrass);
+ }
}
}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java
index c09aec1..24a0e5c 100644
--- a/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java
+++ b/src/main/java/ru/windcorp/progressia/test/gen/TestHeightMap.java
@@ -54,9 +54,9 @@ public class TestHeightMap implements SurfaceFloatField {
tweak(octaves(fields.primitive(), 2, 3), 50, 0.2)
);
- fields.register("Test:CliffSelector", face, multiply(
+ fields.register("Test:Cliff", face, multiply(
shoreCliffSelector,
- bias(select(shoreCliffs, 0, 0.07), 0)
+ select(shoreCliffs, 0, 0.07)
));
fields.register("Test:Height", face, cutoff(add(
diff --git a/src/main/resources/assets/textures/blocks/LogSide.png b/src/main/resources/assets/textures/blocks/LogSide.png
index e176519..c4d7ca1 100644
Binary files a/src/main/resources/assets/textures/blocks/LogSide.png and b/src/main/resources/assets/textures/blocks/LogSide.png differ
diff --git a/src/main/resources/assets/textures/blocks/LogTop.png b/src/main/resources/assets/textures/blocks/LogTop.png
index 44d89fb..fb61de5 100644
Binary files a/src/main/resources/assets/textures/blocks/LogTop.png and b/src/main/resources/assets/textures/blocks/LogTop.png differ
diff --git a/src/main/resources/assets/textures/tiles/BlueFlowers.png b/src/main/resources/assets/textures/tiles/BlueFlowers.png
new file mode 100644
index 0000000..82c5047
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/BlueFlowers.png differ
diff --git a/src/main/resources/assets/textures/tiles/Bush.png b/src/main/resources/assets/textures/tiles/Bush.png
new file mode 100644
index 0000000..0922df3
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/Bush.png differ
diff --git a/src/main/resources/assets/textures/tiles/GrassSide.png b/src/main/resources/assets/textures/tiles/GrassSide.png
index 7c0a724..7a128f6 100644
Binary files a/src/main/resources/assets/textures/tiles/GrassSide.png and b/src/main/resources/assets/textures/tiles/GrassSide.png differ
diff --git a/src/main/resources/assets/textures/tiles/GrassTop.png b/src/main/resources/assets/textures/tiles/GrassTop.png
index edab970..ae6039d 100644
Binary files a/src/main/resources/assets/textures/tiles/GrassTop.png and b/src/main/resources/assets/textures/tiles/GrassTop.png differ
diff --git a/src/main/resources/assets/textures/tiles/LowGrass.png b/src/main/resources/assets/textures/tiles/LowGrass.png
new file mode 100644
index 0000000..2f3726f
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/LowGrass.png differ
diff --git a/src/main/resources/assets/textures/tiles/MediumGrass.png b/src/main/resources/assets/textures/tiles/MediumGrass.png
new file mode 100644
index 0000000..7115d2f
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/MediumGrass.png differ
diff --git a/src/main/resources/assets/textures/tiles/PurpleFlowers.png b/src/main/resources/assets/textures/tiles/PurpleFlowers.png
new file mode 100644
index 0000000..e118fdd
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/PurpleFlowers.png differ
diff --git a/src/main/resources/assets/textures/tiles/TallGrass.png b/src/main/resources/assets/textures/tiles/TallGrass.png
new file mode 100644
index 0000000..ce41bcf
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/TallGrass.png differ
diff --git a/src/main/resources/assets/textures/tiles/TinyDandelionFlowers.png b/src/main/resources/assets/textures/tiles/TinyDandelionFlowers.png
new file mode 100644
index 0000000..35f651c
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/TinyDandelionFlowers.png differ
diff --git a/src/main/resources/assets/textures/tiles/TinyLavanderFlowers.png b/src/main/resources/assets/textures/tiles/TinyLavanderFlowers.png
new file mode 100644
index 0000000..ab2542d
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/TinyLavanderFlowers.png differ
diff --git a/src/main/resources/assets/textures/tiles/WhiteFlowers.png b/src/main/resources/assets/textures/tiles/WhiteFlowers.png
new file mode 100644
index 0000000..84a987a
Binary files /dev/null and b/src/main/resources/assets/textures/tiles/WhiteFlowers.png differ