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