From 846b14cf7c77761134f7db72f5c0e9f664cabcb8 Mon Sep 17 00:00:00 2001 From: paulevsGitch Date: Mon, 12 Oct 2020 00:24:26 +0300 Subject: [PATCH] Structures, texture changes --- .../betterend/registry/FeatureRegistry.java | 2 + .../java/ru/betterend/util/SplineHelper.java | 10 ++ .../util/sdf/operator/SDFRotation.java | 4 + .../world/biome/BiomeChorusForest.java | 3 +- .../world/features/ChorusTreeFeature.java | 96 ++++++++++++++++++ .../betterend/blockstates/chorus_log.json | 24 ++--- .../materialmaps/block/chorus_bark.json | 3 + .../materialmaps/block/chorus_log.json | 14 +++ .../betterend/materials/glow_20_half.json | 10 ++ .../betterend/models/block/chorus_log.json | 38 +++++-- .../betterend/models/block/chorus_log_2.json | 34 +++++++ .../shaders/material/glow_20_half.frag | 8 ++ .../textures/block/chorus_log_side.png | Bin 0 -> 591 bytes .../textures/block/chorus_log_side.png.mcmeta | 14 +++ .../textures/block/chorus_log_side_1.png | Bin 0 -> 2508 bytes .../textures/block/chorus_log_side_2.png | Bin 0 -> 2552 bytes .../textures/block/chorus_log_side_glow_1.png | Bin 0 -> 3044 bytes .../block/chorus_log_side_glow_1.png.mcmeta | 12 +++ .../textures/block/chorus_log_side_glow_2.png | Bin 0 -> 4772 bytes .../block/chorus_log_side_glow_2.png.mcmeta | 12 +++ .../textures/block/chorus_log_top.png | Bin 0 -> 2136 bytes 21 files changed, 262 insertions(+), 22 deletions(-) create mode 100644 src/main/java/ru/betterend/world/features/ChorusTreeFeature.java create mode 100644 src/main/resources/assets/betterend/materialmaps/block/chorus_bark.json create mode 100644 src/main/resources/assets/betterend/materialmaps/block/chorus_log.json create mode 100644 src/main/resources/assets/betterend/materials/glow_20_half.json create mode 100644 src/main/resources/assets/betterend/models/block/chorus_log_2.json create mode 100644 src/main/resources/assets/betterend/shaders/material/glow_20_half.frag create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side.png create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side.png.mcmeta create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_1.png create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_2.png create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_glow_1.png create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_glow_1.png.mcmeta create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_glow_2.png create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_side_glow_2.png.mcmeta create mode 100644 src/main/resources/assets/betterend/textures/block/chorus_log_top.png diff --git a/src/main/java/ru/betterend/registry/FeatureRegistry.java b/src/main/java/ru/betterend/registry/FeatureRegistry.java index 60a2d3f6..4d075a2b 100644 --- a/src/main/java/ru/betterend/registry/FeatureRegistry.java +++ b/src/main/java/ru/betterend/registry/FeatureRegistry.java @@ -1,6 +1,7 @@ package ru.betterend.registry; import ru.betterend.world.features.BlueVineFeature; +import ru.betterend.world.features.ChorusTreeFeature; import ru.betterend.world.features.DoublePlantFeature; import ru.betterend.world.features.EndFeature; import ru.betterend.world.features.EndLakeFeature; @@ -11,6 +12,7 @@ import ru.betterend.world.features.VineFeature; public class FeatureRegistry { // Trees // public static final EndFeature MOSSY_GLOWSHROOM = new EndFeature("mossy_glowshroom", new MossyGlowshroomFeature(), 3); + public static final EndFeature CHORUS_TREE = new EndFeature("chorus_tree", new ChorusTreeFeature(), 1); // Plants // public static final EndFeature UMBRELLA_MOSS = new EndFeature("umbrella_moss", new DoublePlantFeature(BlockRegistry.UMBRELLA_MOSS, BlockRegistry.UMBRELLA_MOSS_TALL, 5), 5); diff --git a/src/main/java/ru/betterend/util/SplineHelper.java b/src/main/java/ru/betterend/util/SplineHelper.java index d9bec0ff..fce13b66 100644 --- a/src/main/java/ru/betterend/util/SplineHelper.java +++ b/src/main/java/ru/betterend/util/SplineHelper.java @@ -41,6 +41,16 @@ public class SplineHelper { } } + public static void parableOffset(List spline, float distance) { + int count = spline.size(); + for (int i = 1; i < count; i++) { + Vector3f pos = spline.get(i); + float x = (float) i / (float) (count + 1); + float y = pos.getY() + x * x * distance; + pos.set(pos.getX(), y, pos.getZ()); + } + } + public static SDF buildSDF(List spline, float radius1, float radius2, Function placerFunction) { int count = spline.size(); float max = count - 2; diff --git a/src/main/java/ru/betterend/util/sdf/operator/SDFRotation.java b/src/main/java/ru/betterend/util/sdf/operator/SDFRotation.java index 8f0494de..8bc580ab 100644 --- a/src/main/java/ru/betterend/util/sdf/operator/SDFRotation.java +++ b/src/main/java/ru/betterend/util/sdf/operator/SDFRotation.java @@ -7,6 +7,10 @@ public class SDFRotation extends SDFUnary { private static final Vector3f POS = new Vector3f(); private Quaternion rotation; + public SDFRotation setRotation() { + return this; + } + @Override public float getDistance(float x, float y, float z) { POS.set(x, y, z); diff --git a/src/main/java/ru/betterend/world/biome/BiomeChorusForest.java b/src/main/java/ru/betterend/world/biome/BiomeChorusForest.java index 53129b27..7e96aff8 100644 --- a/src/main/java/ru/betterend/world/biome/BiomeChorusForest.java +++ b/src/main/java/ru/betterend/world/biome/BiomeChorusForest.java @@ -4,7 +4,6 @@ import net.minecraft.entity.EntityType; import ru.betterend.registry.BlockRegistry; import ru.betterend.registry.EntityRegistry; import ru.betterend.registry.FeatureRegistry; -import ru.betterend.registry.StructureRegistry; public class BiomeChorusForest extends EndBiome { public BiomeChorusForest() { @@ -15,9 +14,9 @@ public class BiomeChorusForest extends EndBiome { //.setParticles(ParticleRegistry.GLOWING_SPHERE, 0.001F) //.setLoop(SoundRegistry.AMBIENT_FOGGY_MUSHROOMLAND) //.setMusic(SoundRegistry.MUSIC_FOGGY_MUSHROOMLAND) - .addStructureFeature(StructureRegistry.GIANT_MOSSY_GLOWSHROOM) .addFeature(FeatureRegistry.ENDER_ORE) .addFeature(FeatureRegistry.RARE_END_LAKE) + .addFeature(FeatureRegistry.CHORUS_TREE) .addFeature(FeatureRegistry.CHORUS_GRASS) .addMobSpawn(EntityRegistry.END_SLIME, 5, 1, 2) .addMobSpawn(EntityType.ENDERMAN, 50, 1, 4)); diff --git a/src/main/java/ru/betterend/world/features/ChorusTreeFeature.java b/src/main/java/ru/betterend/world/features/ChorusTreeFeature.java new file mode 100644 index 00000000..611a540e --- /dev/null +++ b/src/main/java/ru/betterend/world/features/ChorusTreeFeature.java @@ -0,0 +1,96 @@ +package ru.betterend.world.features; + +import java.util.List; +import java.util.Random; +import java.util.function.Function; + +import com.google.common.collect.Lists; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Material; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import ru.betterend.registry.BlockRegistry; +import ru.betterend.registry.BlockTagRegistry; +import ru.betterend.util.MHelper; +import ru.betterend.util.SplineHelper; +import ru.betterend.util.sdf.SDF; +import ru.betterend.util.sdf.operator.SDFScale; +import ru.betterend.util.sdf.operator.SDFUnion; + +public class ChorusTreeFeature extends DefaultFeature { + private static final Function REPLACE; + + @Override + public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { + if (world.getBlockState(pos.down()).getBlock() != BlockRegistry.CHORUS_NYLIUM) return false; + + float size = MHelper.randRange(10, 20, random); + List> splines = Lists.newArrayList(); + List spline = SplineHelper.makeSpline(0, 0, 0, 0, size, 0, 4); + SplineHelper.offsetParts(spline, random, 0.7F, 0, 0.7F); + Vector3f last = spline.get(spline.size() - 1); + branch(splines, last.getX(), last.getY(), last.getZ(), size * 0.6F, MHelper.randRange(0, MHelper.PI2, random), random, MHelper.floor(Math.log(size) * 1.5F)); + + SDF function = SplineHelper.buildSDF(spline, 1.4F, 0.8F, (bpos) -> { + return BlockRegistry.CHORUS.bark.getDefaultState(); + }); + + for (List sp: splines) { + float width = 0.8F - (sp.get(0).getY() - size) / 40; + if (size > 0F) { + SDF funcSp = SplineHelper.buildSDF(sp, width, width, (bpos) -> { + return BlockRegistry.CHORUS.bark.getDefaultState(); + }); + function = new SDFUnion().setSourceA(function).setSourceB(funcSp); + } + } + function = new SDFScale().setScale(MHelper.randRange(1F, 2F, random)).setSource(function); + function.setReplaceFunction(REPLACE); + function.fillRecursive(world, pos); + + return true; + } + + private void branch(List> splines, float x, float y, float z, float size, float angle, Random random, int depth) { + if (depth == 0) return; + + float dx = (float) Math.cos(angle) * size * 0.3F; + float dz = (float) Math.sin(angle) * size * 0.3F; + + float x1 = x + dx; + float z1 = z + dz; + float x2 = x - dx; + float z2 = z - dz; + + List spline = SplineHelper.makeSpline(x, y, z, x1, y, z1, 5); + SplineHelper.parableOffset(spline, size); + SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); + splines.add(spline); + Vector3f pos1 = spline.get(spline.size() - 1); + + spline = SplineHelper.makeSpline(x, y, z, x2, y, z2, 5); + SplineHelper.parableOffset(spline, size); + SplineHelper.offsetParts(spline, random, 0.3F, 0, 0.3F); + splines.add(spline); + Vector3f pos2 = spline.get(spline.size() - 1); + + branch(splines, pos1.getX(), pos1.getY(), pos1.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); + branch(splines, pos2.getX(), pos2.getY(), pos2.getZ(), size * 0.8F, angle + (float) Math.PI * 0.5F, random, depth - 1); + } + + static { + REPLACE = (state) -> { + if (state.isIn(BlockTagRegistry.END_GROUND)) { + return true; + } + if (state.getMaterial().equals(Material.PLANT)) { + return true; + } + return state.getMaterial().isReplaceable(); + }; + } +} diff --git a/src/main/resources/assets/betterend/blockstates/chorus_log.json b/src/main/resources/assets/betterend/blockstates/chorus_log.json index 4c74bf8e..4ecb922a 100644 --- a/src/main/resources/assets/betterend/blockstates/chorus_log.json +++ b/src/main/resources/assets/betterend/blockstates/chorus_log.json @@ -1,16 +1,16 @@ { "variants": { - "axis=x": { - "model": "betterend:block/chorus_log", - "x": 90, - "y": 90 - }, - "axis=y": { - "model": "betterend:block/chorus_log" - }, - "axis=z": { - "model": "betterend:block/chorus_log", - "x": 90 - } + "axis=x": [ + { "model": "betterend:block/chorus_log", "x": 90, "y": 90 }, + { "model": "betterend:block/chorus_log_2", "x": 90, "y": 90 } + ], + "axis=y": [ + { "model": "betterend:block/chorus_log" }, + { "model": "betterend:block/chorus_log_2" } + ], + "axis=z": [ + { "model": "betterend:block/chorus_log", "x": 90 }, + { "model": "betterend:block/chorus_log_2", "x": 90 } + ] } } diff --git a/src/main/resources/assets/betterend/materialmaps/block/chorus_bark.json b/src/main/resources/assets/betterend/materialmaps/block/chorus_bark.json new file mode 100644 index 00000000..225e95be --- /dev/null +++ b/src/main/resources/assets/betterend/materialmaps/block/chorus_bark.json @@ -0,0 +1,3 @@ +{ + "defaultMaterial": "betterend:glow_20_half" +} diff --git a/src/main/resources/assets/betterend/materialmaps/block/chorus_log.json b/src/main/resources/assets/betterend/materialmaps/block/chorus_log.json new file mode 100644 index 00000000..45ff06f2 --- /dev/null +++ b/src/main/resources/assets/betterend/materialmaps/block/chorus_log.json @@ -0,0 +1,14 @@ +{ + "defaultMap": { + "spriteMap": [ + { + "sprite": "betterend:block/chorus_log_side_glow_1", + "material": "betterend:glow_all_half" + }, + { + "sprite": "betterend:block/chorus_log_side_glow_2", + "material": "betterend:glow_all_half" + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/betterend/materials/glow_20_half.json b/src/main/resources/assets/betterend/materials/glow_20_half.json new file mode 100644 index 00000000..3ed9bf23 --- /dev/null +++ b/src/main/resources/assets/betterend/materials/glow_20_half.json @@ -0,0 +1,10 @@ +{ + "layers": [ + { + "vertexSource": "canvas:shaders/material/default.vert", + "fragmentSource": "betterend:shaders/material/glow_20_half.frag", + "disableAo": true, + "disableDiffuse": true + } + ] +} diff --git a/src/main/resources/assets/betterend/models/block/chorus_log.json b/src/main/resources/assets/betterend/models/block/chorus_log.json index 6e78f0dc..4226edf9 100644 --- a/src/main/resources/assets/betterend/models/block/chorus_log.json +++ b/src/main/resources/assets/betterend/models/block/chorus_log.json @@ -1,12 +1,34 @@ { "parent": "block/cube", "textures": { - "down": "betterend:block/chorus_log_top", - "east": "betterend:block/chorus_log_side", - "north": "betterend:block/chorus_log_side", - "particle": "betterend:block/chorus_log_side", - "south": "betterend:block/chorus_log_side", - "up": "betterend:block/chorus_log_top", - "west": "betterend:block/chorus_log_side" - } + "top": "betterend:block/chorus_log_top", + "side": "betterend:block/chorus_log_side_1", + "glow": "betterend:block/chorus_log_side_glow_1", + "particle": "#side" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "shade": false, + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "east" } + } + } + ] } diff --git a/src/main/resources/assets/betterend/models/block/chorus_log_2.json b/src/main/resources/assets/betterend/models/block/chorus_log_2.json new file mode 100644 index 00000000..5842dea2 --- /dev/null +++ b/src/main/resources/assets/betterend/models/block/chorus_log_2.json @@ -0,0 +1,34 @@ +{ + "parent": "block/cube", + "textures": { + "top": "betterend:block/chorus_log_top", + "side": "betterend:block/chorus_log_side_2", + "glow": "betterend:block/chorus_log_side_glow_2", + "particle": "#side" + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "down" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "shade": false, + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#glow", "cullface": "east" } + } + } + ] +} diff --git a/src/main/resources/assets/betterend/shaders/material/glow_20_half.frag b/src/main/resources/assets/betterend/shaders/material/glow_20_half.frag new file mode 100644 index 00000000..9efc319b --- /dev/null +++ b/src/main/resources/assets/betterend/shaders/material/glow_20_half.frag @@ -0,0 +1,8 @@ +#include frex:shaders/api/fragment.glsl +#include frex:shaders/lib/math.glsl + +void frx_startFragment(inout frx_FragmentData fragData) { + float glow = frx_luminance(fragData.spriteColor.rgb) - 0.2; + glow = clamp(glow * 3, 0, 0.5); + fragData.emissivity = glow; +} diff --git a/src/main/resources/assets/betterend/textures/block/chorus_log_side.png b/src/main/resources/assets/betterend/textures/block/chorus_log_side.png new file mode 100644 index 0000000000000000000000000000000000000000..d7256a2f7909a92662bd9221bdc23a72a2cfc5b4 GIT binary patch literal 591 zcmV-V0Kv&B^;uB(&^p+UfPX)IA`O}LO!k)sGldPG!x2n896U}h*bm0D(m z)C$3CWeGwdKH~fk%81()Z#_~V=ny>C*ihmjHg#6&@x@v_B6<&@F2VbSau6Y`W;BQP z9XI4&lSj)uTIL~{$6Dm!na5Kos66rT|9GHMUpzXQMEQ$Huk3aS*e*~63^!BOv3Yb> zdhi&ZB@fFyEc1}eLpBd5?1RUBEQ}VFhZ@+x=IQ+7B$jQUDUj`2xwhzDPa`tR)@@Sa{@ri97LLPndaN3H^^@10E zw?BDofqro=Gdt!7o9oB?@H{^(&ksvHVkkX%w9G>?5AoA4<0ucmge~RpOT;c7%P+oo z48LR^!!KtNBcETHP2Jc^YohsSjg=cKX@R5o!vZO(+L0M ddHOl#=^wIc5t~0A{9XV6002ovPDHLkV1f$801p5F literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/betterend/textures/block/chorus_log_side.png.mcmeta b/src/main/resources/assets/betterend/textures/block/chorus_log_side.png.mcmeta new file mode 100644 index 00000000..65970fdc --- /dev/null +++ b/src/main/resources/assets/betterend/textures/block/chorus_log_side.png.mcmeta @@ -0,0 +1,14 @@ +{ + "animation": { + "interpolate": false, + "frametime": 2, + "frames": [ + 0, + 1, + 2, + 3, + 4, + 5 + ] + } +} diff --git a/src/main/resources/assets/betterend/textures/block/chorus_log_side_1.png b/src/main/resources/assets/betterend/textures/block/chorus_log_side_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2e4ef658e7bbeed0f304155c4c641e06377f2af3 GIT binary patch literal 2508 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 literal 0 HcmV?d00001