Added grasses and flowers
- Added CROSimple to optimize simple non-Surface textures - Added TileRenderCross - Added Low, Medium and Tall grass - Added Blue, Purple and White flat flowers - Added Bushes - Added tiny Dandelions and tiny Lavanders - Improved grass and log textures
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<ShapePart> output
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TileOptimizedCustom {
|
||||||
|
|
||||||
|
void getShapeParts(
|
||||||
|
DefaultChunkData chunk,
|
||||||
|
Vec3i relBlockInChunk,
|
||||||
|
RelFace blockFace,
|
||||||
|
Consumer<ShapePart> output
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Collection<ShapePart> parts = new ArrayList<>();
|
||||||
|
private final Consumer<ShapePart> 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()])
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<ShapePart> 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<ShapePart> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -180,6 +180,25 @@ public class VectorUtil {
|
|||||||
return applyMat4(inOut, mat, inOut);
|
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) {
|
public static Vec3 rotate(Vec3 in, Vec3 axis, float angle, Vec3 out) {
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
out = new Vec3();
|
out = new Vec3();
|
||||||
|
@ -405,7 +405,7 @@ class DefaultServerContextImpl extends DefaultServerContext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTileCount(Vec3i location, RelFace face) {
|
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));
|
TileDataStack stack = world.getTilesOrNull(location, face.resolve(AbsFace.POS_Z));
|
||||||
if (stack == null)
|
if (stack == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -20,7 +20,9 @@ package ru.windcorp.progressia.server.world.generation.surface.context;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import glm.vec._3.i.Vec3i;
|
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.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.ServerTileContext;
|
||||||
import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext;
|
import ru.windcorp.progressia.server.world.context.impl.RotatingServerContext;
|
||||||
import ru.windcorp.progressia.server.world.generation.surface.Surface;
|
import ru.windcorp.progressia.server.world.generation.surface.Surface;
|
||||||
@ -111,4 +113,11 @@ public class SurfaceContextImpl extends RotatingServerContext implements Surface
|
|||||||
return this;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,10 @@ public class Rocks {
|
|||||||
return blocks.get(variant);
|
return blocks.get(variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<BlockData> getBlocks() {
|
||||||
|
return blocks.values();
|
||||||
|
}
|
||||||
|
|
||||||
private void register() {
|
private void register() {
|
||||||
for (RockVariant variant : RockVariant.values()) {
|
for (RockVariant variant : RockVariant.values()) {
|
||||||
|
|
||||||
|
@ -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.graphics.world.Selection;
|
||||||
import ru.windcorp.progressia.client.world.block.*;
|
import ru.windcorp.progressia.client.world.block.*;
|
||||||
import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerRegistry;
|
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.cro.ChunkRenderOptimizerSurface;
|
||||||
import ru.windcorp.progressia.client.world.entity.*;
|
import ru.windcorp.progressia.client.world.entity.*;
|
||||||
import ru.windcorp.progressia.client.world.tile.*;
|
import ru.windcorp.progressia.client.world.tile.*;
|
||||||
@ -174,9 +175,20 @@ public class TestContent {
|
|||||||
register(new TileRenderTransparentSurface("Test:Stones", getTileTexture("Stones")));
|
register(new TileRenderTransparentSurface("Test:Stones", getTileTexture("Stones")));
|
||||||
register(new HangingTileLogic("Test:Stones"));
|
register(new HangingTileLogic("Test:Stones"));
|
||||||
|
|
||||||
register(new TileData("Test:YellowFlowers"));
|
for (String color : new String[] {
|
||||||
register(new TileRenderTransparentSurface("Test:YellowFlowers", getTileTexture("YellowFlowers")));
|
"Yellow",
|
||||||
register(new HangingTileLogic("Test:YellowFlowers"));
|
"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 TileData("Test:Sand"));
|
||||||
register(new TileRenderTransparentSurface("Test:Sand", getTileTexture("Sand")));
|
register(new TileRenderTransparentSurface("Test:Sand", getTileTexture("Sand")));
|
||||||
@ -242,6 +254,32 @@ public class TestContent {
|
|||||||
register(new TileRenderOpaqueSurface("Test:TilesSmall", getTileTexture("TilesSmall")));
|
register(new TileRenderOpaqueSurface("Test:TilesSmall", getTileTexture("TilesSmall")));
|
||||||
register(new HangingTileLogic("Test: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);
|
TileDataRegistry.getInstance().values().forEach(PLACEABLE_TILES::add);
|
||||||
PLACEABLE_TILES.removeIf(b -> placeableBlacklist.contains(b.getId()));
|
PLACEABLE_TILES.removeIf(b -> placeableBlacklist.contains(b.getId()));
|
||||||
PLACEABLE_TILES.sort(Comparator.comparing(TileData::getId));
|
PLACEABLE_TILES.sort(Comparator.comparing(TileData::getId));
|
||||||
@ -285,6 +323,7 @@ public class TestContent {
|
|||||||
i -> isAnythingSelected() && TestPlayerControls.getInstance().isBlockSelected()
|
i -> isAnythingSelected() && TestPlayerControls.getInstance().isBlockSelected()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
logic.register(ControlLogic.of("Test:PlaceBlock", TestContent::onBlockPlaceReceived));
|
logic.register(ControlLogic.of("Test:PlaceBlock", TestContent::onBlockPlaceReceived));
|
||||||
|
|
||||||
data.register("Test:PlaceTile", ControlPlaceTileData::new);
|
data.register("Test:PlaceTile", ControlPlaceTileData::new);
|
||||||
@ -442,7 +481,10 @@ public class TestContent {
|
|||||||
|
|
||||||
private static void registerMisc() {
|
private static void registerMisc() {
|
||||||
ChunkIO.registerCodec(new TestChunkCodec());
|
ChunkIO.registerCodec(new TestChunkCodec());
|
||||||
|
|
||||||
ChunkRenderOptimizerRegistry.getInstance().register("Core:SurfaceOptimizer", ChunkRenderOptimizerSurface::new);
|
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:TheGravityModel", TestGravityModel::new);
|
||||||
GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", PlanetGravityModel::new);
|
GravityModelRegistry.getInstance().register("Test:PlanetGravityModel", PlanetGravityModel::new);
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -215,20 +215,26 @@ public class Fields {
|
|||||||
return tweak(f, 1, 1, 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) {
|
public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) {
|
||||||
return (x, y) -> {
|
return (x, y) -> {
|
||||||
double result = 0;
|
double result = 0;
|
||||||
|
|
||||||
double scale = 1;
|
double scale = 1;
|
||||||
double amplitude = 1;
|
double amplitude = 1;
|
||||||
|
double cumulativeAmplitude = 0;
|
||||||
|
|
||||||
for (int i = 0; i < octaves; ++i) {
|
for (int i = 0; i < octaves; ++i) {
|
||||||
result += f.compute(x * scale, y * scale) * amplitude;
|
result += f.compute(x * scale, y * scale) * amplitude;
|
||||||
|
cumulativeAmplitude += amplitude;
|
||||||
scale *= scaleFactor;
|
scale *= scaleFactor;
|
||||||
amplitude /= amplitudeFactor;
|
amplitude /= amplitudeFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result / cumulativeAmplitude;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
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<String, SurfaceFloatField> 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<String> soilWhitelist;
|
||||||
|
{
|
||||||
|
ImmutableSet.Builder<String> 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<String, SurfaceFloatField> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -76,7 +76,7 @@ public class TestGenerationConfig {
|
|||||||
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
|
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
|
||||||
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
|
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
|
||||||
|
|
||||||
SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector");
|
SurfaceFloatField cliffs = FIELDS.get("Test:Cliff");
|
||||||
|
|
||||||
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
|
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
|
||||||
TestContent.ROCKS.getRocks().forEach(rock -> {
|
TestContent.ROCKS.getRocks().forEach(rock -> {
|
||||||
@ -108,21 +108,32 @@ public class TestGenerationConfig {
|
|||||||
private static void registerFeatures(List<SurfaceFeature> features) {
|
private static void registerFeatures(List<SurfaceFeature> features) {
|
||||||
|
|
||||||
SurfaceFloatField forestiness = FIELDS.register(
|
SurfaceFloatField forestiness = FIELDS.register(
|
||||||
"Test:Forestiness",
|
"Test:Forest",
|
||||||
() -> squash(scale(FIELDS.primitive(), 200), 5)
|
() -> squash(scale(FIELDS.primitive(), 200), 5)
|
||||||
);
|
);
|
||||||
|
|
||||||
SurfaceFloatField floweriness = FIELDS.register(
|
SurfaceFloatField grassiness = FIELDS.register(
|
||||||
"Test:Floweriness",
|
"Test:Grass",
|
||||||
f -> multiply(
|
f -> multiply(
|
||||||
scale(octaves(FIELDS.primitive(), 2, 2), 40),
|
tweak(octaves(FIELDS.primitive(), 2, 2), 40, 0.5, 1.2),
|
||||||
tweak(FIELDS.get("Test:Forestiness", f), 1, -1, 1.1)
|
squash(tweak(FIELDS.get("Test:Forest", f), 1, -0.7, 1), 10),
|
||||||
|
anti(squash(FIELDS.get("Test:Cliff", f), 10))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Function<String, SurfaceFloatField> 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 TestBushFeature("Test:BushFeature", forestiness));
|
||||||
features.add(new TestTreeFeature("Test:TreeFeature", 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,40 +23,47 @@ import java.util.Set;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
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.rels.RelFace;
|
||||||
import ru.windcorp.progressia.common.world.tile.TileData;
|
import ru.windcorp.progressia.common.world.tile.TileData;
|
||||||
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
|
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.SurfaceFloatField;
|
||||||
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature;
|
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature;
|
||||||
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
|
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
|
||||||
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
|
|
||||||
public class TestGrassFeature extends SurfaceTopLayerFeature {
|
public class TestGrassFeature extends SurfaceTopLayerFeature {
|
||||||
|
|
||||||
private static final Set<String> WHITELIST = ImmutableSet.of(
|
private final Set<String> soilWhitelist;
|
||||||
"Test:Dirt",
|
{
|
||||||
"Test:Stone",
|
ImmutableSet.Builder<String> b = ImmutableSet.builder();
|
||||||
"Test:GraniteMonolith",
|
b.add("Test:Dirt", "Test:Stone");
|
||||||
"Test:GraniteCracked",
|
TestContent.ROCKS.getRocks().forEach(rock -> rock.getBlocks().forEach(block -> b.add(block.getId())));
|
||||||
"Test:GraniteGravel"
|
soilWhitelist = b.build();
|
||||||
);
|
}
|
||||||
|
|
||||||
private final SurfaceFloatField grassiness;
|
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 TileData grass = TileDataRegistry.getInstance().get("Test:Grass");
|
||||||
private final List<TileData> flowers = ImmutableList.of(
|
|
||||||
TileDataRegistry.getInstance().get("Test:YellowFlowers")
|
private final FloatRangeMap<TileData> 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<TileData> scatter = ImmutableList.of(
|
private final List<TileData> scatter = ImmutableList.of(
|
||||||
TileDataRegistry.getInstance().get("Test:Stones"),
|
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);
|
super(id);
|
||||||
this.grassiness = grassiness;
|
this.grassiness = grassiness;
|
||||||
this.floweriness = floweriness;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -64,7 +71,7 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
|
|||||||
if (context.getLocation().z < 0) {
|
if (context.getLocation().z < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!WHITELIST.contains(context.getBlock().getId())) {
|
if (!soilWhitelist.contains(context.getBlock().getId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,15 +82,11 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
|
|||||||
context.pop();
|
context.pop();
|
||||||
|
|
||||||
double grassiness = this.grassiness.get(context);
|
double grassiness = this.grassiness.get(context);
|
||||||
if (grassiness < 0.2) {
|
if (grassiness > 0.1) {
|
||||||
growGrass(context);
|
growGrass(context, grassiness);
|
||||||
}
|
}
|
||||||
|
|
||||||
placeScatter(context);
|
placeScatter(context);
|
||||||
|
|
||||||
if (grassiness < 0.2) {
|
|
||||||
growFlowers(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeScatter(SurfaceBlockContext context) {
|
private void placeScatter(SurfaceBlockContext context) {
|
||||||
@ -93,9 +96,10 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void growGrass(SurfaceBlockContext context) {
|
private void growGrass(SurfaceBlockContext context, double grassiness) {
|
||||||
for (RelFace face : RelFace.getFaces()) {
|
for (RelFace face : RelFace.getFaces()) {
|
||||||
if (face == RelFace.DOWN) continue;
|
if (face == RelFace.DOWN)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (context.pushRelative(face).logic().getBlock().isTransparent()) {
|
if (context.pushRelative(face).logic().getBlock().isTransparent()) {
|
||||||
context.pop();
|
context.pop();
|
||||||
@ -105,12 +109,12 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void growFlowers(SurfaceBlockContext context) {
|
if (context.getRandom().nextDouble() < grassiness) {
|
||||||
if (context.getRandom().nextDouble() < floweriness.get(context)) {
|
TileData herbGrass = grasses.get((float) grassiness);
|
||||||
TileData tile = pickRandom(context, flowers);
|
if (herbGrass != null) {
|
||||||
context.addTile(RelFace.UP, tile);
|
context.addTile(RelFace.UP, herbGrass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ public class TestHeightMap implements SurfaceFloatField {
|
|||||||
tweak(octaves(fields.primitive(), 2, 3), 50, 0.2)
|
tweak(octaves(fields.primitive(), 2, 3), 50, 0.2)
|
||||||
);
|
);
|
||||||
|
|
||||||
fields.register("Test:CliffSelector", face, multiply(
|
fields.register("Test:Cliff", face, multiply(
|
||||||
shoreCliffSelector,
|
shoreCliffSelector,
|
||||||
bias(select(shoreCliffs, 0, 0.07), 0)
|
select(shoreCliffs, 0, 0.07)
|
||||||
));
|
));
|
||||||
|
|
||||||
fields.register("Test:Height", face, cutoff(add(
|
fields.register("Test:Height", face, cutoff(add(
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 8.1 KiB |
BIN
src/main/resources/assets/textures/tiles/BlueFlowers.png
Normal file
After Width: | Height: | Size: 481 B |
BIN
src/main/resources/assets/textures/tiles/Bush.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 6.9 KiB |
BIN
src/main/resources/assets/textures/tiles/LowGrass.png
Normal file
After Width: | Height: | Size: 448 B |
BIN
src/main/resources/assets/textures/tiles/MediumGrass.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
src/main/resources/assets/textures/tiles/PurpleFlowers.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
src/main/resources/assets/textures/tiles/TallGrass.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 4.3 KiB |
BIN
src/main/resources/assets/textures/tiles/TinyLavanderFlowers.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
src/main/resources/assets/textures/tiles/WhiteFlowers.png
Normal file
After Width: | Height: | Size: 586 B |