Add first iteration of custom block-renderers (#561)

This commit is contained in:
Lukas Rieger (Blue) 2024-11-01 22:30:05 +01:00
parent b26b908992
commit c2fa00db5b
No known key found for this signature in database
GPG Key ID: AA33883B1BBA03E6
15 changed files with 239 additions and 89 deletions

View File

@ -27,7 +27,7 @@
import com.flowpowered.math.vector.Vector3i; import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.TileMetaConsumer; import de.bluecolored.bluemap.core.map.TileMetaConsumer;
import de.bluecolored.bluemap.core.map.hires.blockmodel.BlockStateModelFactory; import de.bluecolored.bluemap.core.map.hires.blockmodel.BlockStateModelRenderer;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.util.math.Color; import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.world.Chunk; import de.bluecolored.bluemap.core.world.Chunk;
@ -39,31 +39,31 @@ public class HiresModelRenderer {
private final ResourcePack resourcePack; private final ResourcePack resourcePack;
private final RenderSettings renderSettings; private final RenderSettings renderSettings;
private final ThreadLocal<BlockStateModelFactory> threadLocalModelFactory; private final ThreadLocal<BlockStateModelRenderer> threadLocalBlockRenderer;
public HiresModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) { public HiresModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack; this.resourcePack = resourcePack;
this.renderSettings = renderSettings; this.renderSettings = renderSettings;
this.threadLocalModelFactory = ThreadLocal.withInitial(() -> new BlockStateModelFactory(resourcePack, textureGallery, renderSettings)); this.threadLocalBlockRenderer = ThreadLocal.withInitial(() -> new BlockStateModelRenderer(resourcePack, textureGallery, renderSettings));
} }
public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel model) { public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel model) {
render(world, modelMin, modelMax, model, (x, z, c, h, l) -> {}); render(world, modelMin, modelMax, model, (x, z, c, h, l) -> {});
} }
public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel model, TileMetaConsumer tileMetaConsumer) { public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel tileModel, TileMetaConsumer tileMetaConsumer) {
Vector3i min = modelMin.max(renderSettings.getMinPos()); Vector3i min = modelMin.max(renderSettings.getMinPos());
Vector3i max = modelMax.min(renderSettings.getMaxPos()); Vector3i max = modelMax.min(renderSettings.getMaxPos());
Vector3i modelAnchor = new Vector3i(modelMin.getX(), 0, modelMin.getZ()); Vector3i modelAnchor = new Vector3i(modelMin.getX(), 0, modelMin.getZ());
BlockStateModelFactory modelFactory = threadLocalModelFactory.get(); BlockStateModelRenderer blockRenderer = threadLocalBlockRenderer.get();
int maxHeight, minY, maxY; int maxHeight, minY, maxY;
double topBlockLight; double topBlockLight;
Color columnColor = new Color(), blockColor = new Color(); Color columnColor = new Color(), blockColor = new Color();
BlockNeighborhood<?> block = new BlockNeighborhood<>(resourcePack, renderSettings, world, 0, 0, 0); BlockNeighborhood<?> block = new BlockNeighborhood<>(resourcePack, renderSettings, world, 0, 0, 0);
BlockModelView blockModel = new BlockModelView(model); TileModelView blockModel = new TileModelView(tileModel);
int x, y, z; int x, y, z;
for (x = modelMin.getX(); x <= modelMax.getX(); x++){ for (x = modelMin.getX(); x <= modelMax.getX(); x++){
@ -85,7 +85,7 @@ public void render(World world, Vector3i modelMin, Vector3i modelMax, TileModel
blockModel.initialize(); blockModel.initialize();
modelFactory.render(block, blockModel, blockColor); blockRenderer.render(block, blockModel, blockColor);
//update topBlockLight //update topBlockLight
topBlockLight = Math.max(topBlockLight, block.getBlockLightLevel() * (1 - columnColor.a)); topBlockLight = Math.max(topBlockLight, block.getBlockLightLevel() * (1 - columnColor.a));

View File

@ -27,90 +27,90 @@
import de.bluecolored.bluemap.core.util.math.MatrixM3f; import de.bluecolored.bluemap.core.util.math.MatrixM3f;
import de.bluecolored.bluemap.core.util.math.MatrixM4f; import de.bluecolored.bluemap.core.util.math.MatrixM4f;
public class BlockModelView { public class TileModelView {
private TileModel hiresTile; private TileModel tileModel;
private int start, size; private int start, size;
public BlockModelView(TileModel hiresTile) { public TileModelView(TileModel tileModel) {
initialize(hiresTile); initialize(tileModel);
} }
public BlockModelView initialize(TileModel hiresTile, int start) { public TileModelView initialize(TileModel hiresTile, int start) {
this.hiresTile = hiresTile; this.tileModel = hiresTile;
this.start = start; this.start = start;
this.size = hiresTile.size() - start; this.size = hiresTile.size() - start;
return this; return this;
} }
public BlockModelView initialize(TileModel hiresTile) { public TileModelView initialize(TileModel hiresTile) {
this.hiresTile = hiresTile; this.tileModel = hiresTile;
this.start = hiresTile.size(); this.start = hiresTile.size();
this.size = 0; this.size = 0;
return this; return this;
} }
public BlockModelView initialize(int start) { public TileModelView initialize(int start) {
this.start = start; this.start = start;
this.size = hiresTile.size() - start; this.size = tileModel.size() - start;
return this; return this;
} }
public BlockModelView initialize() { public TileModelView initialize() {
this.start = hiresTile.size(); this.start = tileModel.size();
this.size = 0; this.size = 0;
return this; return this;
} }
public BlockModelView reset() { public TileModelView reset() {
hiresTile.reset(this.start); tileModel.reset(this.start);
this.size = 0; this.size = 0;
return this; return this;
} }
public int add(int count) { public int add(int count) {
int s = hiresTile.add(count); int s = tileModel.add(count);
if (s != start + size) throw new IllegalStateException("Size of HiresTileModel had external changes since view-initialisation!"); if (s != start + size) throw new IllegalStateException("Size of HiresTileModel had external changes since view-initialisation!");
this.size += count; this.size += count;
return s; return s;
} }
public BlockModelView rotate(float angle, float axisX, float axisY, float axisZ) { public TileModelView rotate(float angle, float axisX, float axisY, float axisZ) {
hiresTile.rotate(start, size, angle, axisX, axisY, axisZ); tileModel.rotate(start, size, angle, axisX, axisY, axisZ);
return this; return this;
} }
public BlockModelView rotate(float pitch, float yaw, float roll) { public TileModelView rotate(float pitch, float yaw, float roll) {
hiresTile.rotate(start, size, pitch, yaw, roll); tileModel.rotate(start, size, pitch, yaw, roll);
return this; return this;
} }
public BlockModelView scale(float sx, float sy, float sz) { public TileModelView scale(float sx, float sy, float sz) {
hiresTile.scale(start, size, sx, sy, sz); tileModel.scale(start, size, sx, sy, sz);
return this; return this;
} }
public BlockModelView translate(float dx, float dy, float dz) { public TileModelView translate(float dx, float dy, float dz) {
hiresTile.translate(start, size, dx, dy, dz); tileModel.translate(start, size, dx, dy, dz);
return this; return this;
} }
public BlockModelView transform(MatrixM3f t) { public TileModelView transform(MatrixM3f t) {
hiresTile.transform(start, size, t); tileModel.transform(start, size, t);
return this; return this;
} }
public BlockModelView transform( public TileModelView transform(
float m00, float m01, float m02, float m00, float m01, float m02,
float m10, float m11, float m12, float m10, float m11, float m12,
float m20, float m21, float m22 float m20, float m21, float m22
) { ) {
hiresTile.transform(start, size, tileModel.transform(start, size,
m00, m01, m02, m00, m01, m02,
m10, m11, m12, m10, m11, m12,
m20, m21, m22 m20, m21, m22
@ -118,18 +118,18 @@ public BlockModelView transform(
return this; return this;
} }
public BlockModelView transform(MatrixM4f t) { public TileModelView transform(MatrixM4f t) {
hiresTile.transform(start, size, t); tileModel.transform(start, size, t);
return this; return this;
} }
public BlockModelView transform( public TileModelView transform(
float m00, float m01, float m02, float m03, float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13, float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23, float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33 float m30, float m31, float m32, float m33
) { ) {
hiresTile.transform(start, size, tileModel.transform(start, size,
m00, m01, m02, m03, m00, m01, m02, m03,
m10, m11, m12, m13, m10, m11, m12, m13,
m20, m21, m22, m23, m20, m21, m22, m23,
@ -138,8 +138,8 @@ public BlockModelView transform(
return this; return this;
} }
public TileModel getHiresTile() { public TileModel getTileModel() {
return hiresTile; return tileModel;
} }
public int getStart() { public int getStart() {

View File

@ -0,0 +1,27 @@
package de.bluecolored.bluemap.core.map.hires.blockmodel;
import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
public interface BlockRenderer {
/**
* Renders the given blocks (block-state-)variant into the given blockModel, and sets the given blockColor to the
* color that represents the rendered block.
* <p>
* <b>Implementation Note:</b><br>
* This method is guaranteed to be called only on <b>one thread per BlockRenderer instance</b>, so you can use this
* for optimizations.<br>
* Keep in mind this method will be called once for every block that is being rendered, so be very careful
* about performance and instance-creations.
* </p>
* @param block The block information that should be rendered.
* @param variant The block-state variant that should be rendered.
* @param blockModel The model(-view) where the block should be rendered to.
* @param blockColor The color that should be set to the color that represents the rendered block.
*/
void render(BlockNeighborhood<?> block, Variant variant, TileModelView blockModel, Color blockColor);
}

View File

@ -0,0 +1,11 @@
package de.bluecolored.bluemap.core.map.hires.blockmodel;
import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
public interface BlockRendererFactory {
BlockRenderer create(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings);
}

View File

@ -0,0 +1,56 @@
package de.bluecolored.bluemap.core.map.hires.blockmodel;
import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.util.Key;
import de.bluecolored.bluemap.core.util.Keyed;
import de.bluecolored.bluemap.core.util.Registry;
import de.bluecolored.bluemap.core.world.BlockState;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
public interface BlockRendererType extends Keyed, BlockRendererFactory {
BlockRendererType DEFAULT = new Impl(Key.bluemap("default"), ResourceModelRenderer::new);
BlockRendererType LIQUID = new Impl(Key.bluemap("liquid"), LiquidModelRenderer::new);
BlockRendererType MISSING = new Impl(Key.bluemap("missing"), MissingModelRenderer::new);
Registry<BlockRendererType> REGISTRY = new Registry<>(
DEFAULT,
LIQUID,
MISSING
);
/**
* If the loaded resourcepack does not have any resources for this blockState, this method will be called.
* If this method returns true, this renderer will be used to render the block instead of rendering the default
* black-purple "missing block" model.
* When rendering, the provided "variant" will always be bluemaps default "missing-block" resource.
*
* <p>
* This can (and should only then) be used to provide a way of rendering blocks that are completely dynamically
* created by a mod, and there is no way to provide static block-state resources that point at the correct renderer.
* </p>
*
* @param blockState The {@link BlockState} that was not found in the loaded resources.
* @return true if this renderer-type can render the provided {@link BlockState} despite missing resources.
*/
default boolean isFallbackFor(BlockState blockState) {
return false;
}
@RequiredArgsConstructor
class Impl implements BlockRendererType {
@Getter private final Key key;
private final BlockRendererFactory rendererFactory;
@Override
public BlockRenderer create(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
return rendererFactory.create(resourcePack, textureGallery, renderSettings);
}
}
}

View File

@ -24,8 +24,10 @@
*/ */
package de.bluecolored.bluemap.core.map.hires.blockmodel; package de.bluecolored.bluemap.core.map.hires.blockmodel;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.BlockModelView; import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.map.hires.RenderSettings; import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel; import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.BlockModel;
@ -37,27 +39,25 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class BlockStateModelFactory { public class BlockStateModelRenderer {
private final ResourcePack resourcePack; private final ResourcePack resourcePack;
private final ResourceModelBuilder resourceModelBuilder; private final LoadingCache<BlockRendererType, BlockRenderer> blockRenderers;
private final LiquidModelBuilder liquidModelBuilder;
private final List<Variant> variants = new ArrayList<>(); private final List<Variant> variants = new ArrayList<>();
public BlockStateModelFactory(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) { public BlockStateModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack; this.resourcePack = resourcePack;
this.blockRenderers = Caffeine.newBuilder()
this.resourceModelBuilder = new ResourceModelBuilder(resourcePack, textureGallery, renderSettings); .build(type -> type.create(resourcePack, textureGallery, renderSettings));
this.liquidModelBuilder = new LiquidModelBuilder(resourcePack, textureGallery, renderSettings);
} }
public void render(BlockNeighborhood<?> block, BlockModelView blockModel, Color blockColor) { public void render(BlockNeighborhood<?> block, TileModelView blockModel, Color blockColor) {
render(block, block.getBlockState(), blockModel, blockColor); render(block, block.getBlockState(), blockModel, blockColor);
} }
private final Color waterloggedColor = new Color(); private final Color waterloggedColor = new Color();
public void render(BlockNeighborhood<?> block, BlockState blockState, BlockModelView blockModel, Color blockColor) { public void render(BlockNeighborhood<?> block, BlockState blockState, TileModelView blockModel, Color blockColor) {
blockColor.set(0, 0, 0, 0, true); blockColor.set(0, 0, 0, 0, true);
//shortcut for air //shortcut for air
@ -79,7 +79,7 @@ public void render(BlockNeighborhood<?> block, BlockState blockState, BlockModel
} }
private final Color variantColor = new Color(); private final Color variantColor = new Color();
private void renderModel(BlockNeighborhood<?> block, BlockState blockState, BlockModelView blockModel, Color blockColor) { private void renderModel(BlockNeighborhood<?> block, BlockState blockState, TileModelView blockModel, Color blockColor) {
int modelStart = blockModel.getStart(); int modelStart = blockModel.getStart();
var stateResource = resourcePack.getBlockState(blockState); var stateResource = resourcePack.getBlockState(blockState);
@ -98,11 +98,8 @@ private void renderModel(BlockNeighborhood<?> block, BlockState blockState, Bloc
variantColor.set(0f, 0f, 0f, 0f, true); variantColor.set(0f, 0f, 0f, 0f, true);
if (modelResource.isLiquid()) { blockRenderers.get(modelResource.getRenderer())
liquidModelBuilder.build(block, blockState, variant, blockModel.initialize(), variantColor); .render(block, variant, blockModel.initialize(), blockColor);
} else {
resourceModelBuilder.build(block, variant, blockModel.initialize(), variantColor);
}
if (variantColor.a > blockColorOpacity) if (variantColor.a > blockColorOpacity)
blockColorOpacity = variantColor.a; blockColorOpacity = variantColor.a;

View File

@ -27,7 +27,7 @@
import com.flowpowered.math.TrigMath; import com.flowpowered.math.TrigMath;
import com.flowpowered.math.vector.Vector3i; import com.flowpowered.math.vector.Vector3i;
import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.BlockModelView; import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.map.hires.TileModel; import de.bluecolored.bluemap.core.map.hires.TileModel;
import de.bluecolored.bluemap.core.map.hires.RenderSettings; import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory; import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
@ -50,7 +50,7 @@
* A model builder for all liquid blocks * A model builder for all liquid blocks
*/ */
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public class LiquidModelBuilder { public class LiquidModelRenderer implements BlockRenderer {
private static final float BLOCK_SCALE = 1f / 16f; private static final float BLOCK_SCALE = 1f / 16f;
private static final MatrixM3f FLOWING_UV_SCALE = new MatrixM3f() private static final MatrixM3f FLOWING_UV_SCALE = new MatrixM3f()
.identity() .identity()
@ -68,11 +68,12 @@ public class LiquidModelBuilder {
private BlockNeighborhood<?> block; private BlockNeighborhood<?> block;
private BlockState blockState; private BlockState blockState;
private boolean isWaterlogged, isWaterLike;
private BlockModel modelResource; private BlockModel modelResource;
private BlockModelView blockModel; private TileModelView blockModel;
private Color blockColor; private Color blockColor;
public LiquidModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) { public LiquidModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack; this.resourcePack = resourcePack;
this.textureGallery = textureGallery; this.textureGallery = textureGallery;
this.renderSettings = renderSettings; this.renderSettings = renderSettings;
@ -92,9 +93,11 @@ public LiquidModelBuilder(ResourcePack resourcePack, TextureGallery textureGalle
for (int i = 0; i < uvs.length; i++) uvs[i] = new VectorM2f(0, 0); for (int i = 0; i < uvs.length; i++) uvs[i] = new VectorM2f(0, 0);
} }
public void build(BlockNeighborhood<?> block, BlockState blockState, Variant variant, BlockModelView blockModel, Color color) { public void render(BlockNeighborhood<?> block, Variant variant, TileModelView blockModel, Color color) {
this.block = block; this.block = block;
this.blockState = blockState; this.blockState = block.getBlockState();
this.isWaterlogged = blockState.isWaterlogged() || block.getProperties().isAlwaysWaterlogged();
this.isWaterLike = blockState.isWater() || isWaterlogged;
this.modelResource = variant.getModel().getResource(); this.modelResource = variant.getModel().getResource();
this.blockModel = blockModel; this.blockModel = blockModel;
this.blockColor = color; this.blockColor = color;
@ -137,9 +140,7 @@ private void build() {
int flowTextureId = textureGallery.get(flowTexturePath); int flowTextureId = textureGallery.get(flowTexturePath);
tintcolor.set(1f, 1f, 1f, 1f, true); tintcolor.set(1f, 1f, 1f, 1f, true);
if (blockState.isWater()) { if (isWaterLike) blockColorCalculator.getBlendedWaterColor(block, tintcolor);
blockColorCalculator.getBlendedWaterColor(block, tintcolor);
}
int modelStart = blockModel.getStart(); int modelStart = blockModel.getStart();
@ -223,8 +224,15 @@ private boolean isLiquidBlockingBlock(BlockState blockState){
@SuppressWarnings("StringEquality") @SuppressWarnings("StringEquality")
private boolean isSameLiquid(ExtendedBlock<?> block){ private boolean isSameLiquid(ExtendedBlock<?> block){
if (block.getBlockState().getFormatted() == this.blockState.getFormatted()) return true; BlockState blockState = block.getBlockState();
return this.blockState.isWater() && (block.getBlockState().isWaterlogged() || block.getProperties().isAlwaysWaterlogged());
if (this.isWaterlogged)
return blockState.isWater() || blockState.isWaterlogged() || block.getProperties().isAlwaysWaterlogged();
if (blockState.getFormatted() == this.blockState.getFormatted())
return true;
return this.isWaterLike && (blockState.isWaterlogged() || block.getProperties().isAlwaysWaterlogged());
} }
private float getLiquidBaseHeight(BlockState block){ private float getLiquidBaseHeight(BlockState block){
@ -249,7 +257,7 @@ private boolean createElementFace(Direction faceDir, VectorM3f c0, VectorM3f c1,
blockModel.initialize(); blockModel.initialize();
blockModel.add(2); blockModel.add(2);
TileModel tileModel = blockModel.getHiresTile(); TileModel tileModel = blockModel.getTileModel();
int face1 = blockModel.getStart(); int face1 = blockModel.getStart();
int face2 = face1 + 1; int face2 = face1 + 1;

View File

@ -0,0 +1,37 @@
package de.bluecolored.bluemap.core.map.hires.blockmodel;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockstate.Variant;
import de.bluecolored.bluemap.core.util.math.Color;
import de.bluecolored.bluemap.core.world.BlockState;
import de.bluecolored.bluemap.core.world.block.BlockNeighborhood;
public class MissingModelRenderer implements BlockRenderer {
private static final LoadingCache<BlockState, BlockRendererType> BLOCK_RENDERER_TYPES = Caffeine.newBuilder()
.maximumSize(1000)
.build(blockState -> {
for (BlockRendererType type : BlockRendererType.REGISTRY.values())
if (type.isFallbackFor(blockState)) return type;
return BlockRendererType.DEFAULT;
});
private final LoadingCache<BlockRendererType, BlockRenderer> blockRenderers;
public MissingModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.blockRenderers = Caffeine.newBuilder()
.build(type -> type.create(resourcePack, textureGallery, renderSettings));
}
@Override
public void render(BlockNeighborhood<?> block, Variant variant, TileModelView blockModel, Color blockColor) {
blockRenderers.get(BLOCK_RENDERER_TYPES.get(block.getBlockState()))
.render(block, variant, blockModel, blockColor);
}
}

View File

@ -29,7 +29,7 @@
import com.flowpowered.math.vector.Vector3i; import com.flowpowered.math.vector.Vector3i;
import com.flowpowered.math.vector.Vector4f; import com.flowpowered.math.vector.Vector4f;
import de.bluecolored.bluemap.core.map.TextureGallery; import de.bluecolored.bluemap.core.map.TextureGallery;
import de.bluecolored.bluemap.core.map.hires.BlockModelView; import de.bluecolored.bluemap.core.map.hires.TileModelView;
import de.bluecolored.bluemap.core.map.hires.TileModel; import de.bluecolored.bluemap.core.map.hires.TileModel;
import de.bluecolored.bluemap.core.map.hires.RenderSettings; import de.bluecolored.bluemap.core.map.hires.RenderSettings;
import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory; import de.bluecolored.bluemap.core.resources.BlockColorCalculatorFactory;
@ -54,7 +54,7 @@
* This model builder creates a BlockStateModel using the information from parsed resource-pack json files. * This model builder creates a BlockStateModel using the information from parsed resource-pack json files.
*/ */
@SuppressWarnings("DuplicatedCode") @SuppressWarnings("DuplicatedCode")
public class ResourceModelBuilder { public class ResourceModelRenderer implements BlockRenderer {
private static final float BLOCK_SCALE = 1f / 16f; private static final float BLOCK_SCALE = 1f / 16f;
private final ResourcePack resourcePack; private final ResourcePack resourcePack;
@ -71,11 +71,11 @@ public class ResourceModelBuilder {
private BlockNeighborhood<?> block; private BlockNeighborhood<?> block;
private Variant variant; private Variant variant;
private BlockModel modelResource; private BlockModel modelResource;
private BlockModelView blockModel; private TileModelView blockModel;
private Color blockColor; private Color blockColor;
private float blockColorOpacity; private float blockColorOpacity;
public ResourceModelBuilder(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) { public ResourceModelRenderer(ResourcePack resourcePack, TextureGallery textureGallery, RenderSettings renderSettings) {
this.resourcePack = resourcePack; this.resourcePack = resourcePack;
this.textureGallery = textureGallery; this.textureGallery = textureGallery;
this.renderSettings = renderSettings; this.renderSettings = renderSettings;
@ -86,7 +86,7 @@ public ResourceModelBuilder(ResourcePack resourcePack, TextureGallery textureGal
} }
private final MatrixM4f modelTransform = new MatrixM4f(); private final MatrixM4f modelTransform = new MatrixM4f();
public void build(BlockNeighborhood<?> block, Variant variant, BlockModelView blockModel, Color color) { public void render(BlockNeighborhood<?> block, Variant variant, TileModelView blockModel, Color color) {
this.block = block; this.block = block;
this.blockModel = blockModel; this.blockModel = blockModel;
this.blockColor = color; this.blockColor = color;
@ -132,7 +132,7 @@ public void build(BlockNeighborhood<?> block, Variant variant, BlockModelView bl
} }
private final MatrixM4f modelElementTransform = new MatrixM4f(); private final MatrixM4f modelElementTransform = new MatrixM4f();
private void buildModelElementResource(Element element, BlockModelView blockModel) { private void buildModelElementResource(Element element, TileModelView blockModel) {
//create faces //create faces
Vector3f from = element.getFrom(); Vector3f from = element.getFrom();
@ -215,7 +215,7 @@ private void createElementFace(Element element, Direction faceDir, VectorM3f c0,
blockModel.initialize(); blockModel.initialize();
blockModel.add(2); blockModel.add(2);
TileModel tileModel = blockModel.getHiresTile(); TileModel tileModel = blockModel.getTileModel();
int face1 = blockModel.getStart(); int face1 = blockModel.getStart();
int face2 = face1 + 1; int face2 = face1 + 1;

View File

@ -29,6 +29,7 @@
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import de.bluecolored.bluemap.core.map.hires.blockmodel.BlockRendererType;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face; import de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel.Face;
import de.bluecolored.bluemap.core.util.Direction; import de.bluecolored.bluemap.core.util.Direction;
import de.bluecolored.bluemap.core.util.Key; import de.bluecolored.bluemap.core.util.Key;
@ -64,6 +65,11 @@ public static GsonBuilder addAdapter(GsonBuilder builder) {
GrassColorModifier.REGISTRY, GrassColorModifier.REGISTRY,
Key.MINECRAFT_NAMESPACE, Key.MINECRAFT_NAMESPACE,
GrassColorModifier.NONE GrassColorModifier.NONE
))
.registerTypeAdapter(BlockRendererType.class, new RegistryAdapter<>(
BlockRendererType.REGISTRY,
Key.BLUEMAP_NAMESPACE,
BlockRendererType.DEFAULT
)); ));
} }

View File

@ -24,28 +24,35 @@
*/ */
package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel; package de.bluecolored.bluemap.core.resources.pack.resourcepack.blockmodel;
import de.bluecolored.bluemap.core.map.hires.blockmodel.BlockRendererType;
import de.bluecolored.bluemap.core.resources.ResourcePath; import de.bluecolored.bluemap.core.resources.ResourcePath;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack; import de.bluecolored.bluemap.core.resources.pack.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture; import de.bluecolored.bluemap.core.resources.pack.resourcepack.texture.Texture;
import de.bluecolored.bluemap.core.util.Direction; import de.bluecolored.bluemap.core.util.Direction;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.HashMap;
import java.util.Map;
@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
public class BlockModel { public class BlockModel {
private BlockRendererType renderer = BlockRendererType.DEFAULT;
private ResourcePath<BlockModel> parent; private ResourcePath<BlockModel> parent;
private Map<String, TextureVariable> textures = new HashMap<>(); private Map<String, TextureVariable> textures = new HashMap<>();
private Element[] elements; private Element[] elements;
private boolean ambientocclusion = true; private boolean ambientocclusion = true;
private transient boolean liquid = false;
private transient boolean culling = false; private transient boolean culling = false;
private transient boolean occluding = false; private transient boolean occluding = false;
private BlockModel(){} private BlockModel(){}
public BlockRendererType getRenderer() {
return renderer;
}
@Nullable @Nullable
public ResourcePath<BlockModel> getParent() { public ResourcePath<BlockModel> getParent() {
return parent; return parent;
@ -64,10 +71,6 @@ public boolean isAmbientocclusion() {
return ambientocclusion; return ambientocclusion;
} }
public boolean isLiquid() {
return liquid;
}
public boolean isCulling() { public boolean isCulling() {
return culling; return culling;
} }
@ -95,11 +98,6 @@ public synchronized void applyParent(ResourcePack resourcePack) {
ResourcePath<BlockModel> parentPath = this.parent; ResourcePath<BlockModel> parentPath = this.parent;
this.parent = null; this.parent = null;
if (parentPath.getFormatted().equals("bluemap:builtin/liquid")) {
this.liquid = true;
return;
}
BlockModel parent = parentPath.getResource(resourcePack::getBlockModel); BlockModel parent = parentPath.getResource(resourcePack::getBlockModel);
if (parent != null) { if (parent != null) {
parent.applyParent(resourcePack); parent.applyParent(resourcePack);

View File

@ -40,6 +40,9 @@ public class Block<T extends Block<T>> {
private final LightData lightData = new LightData(-1, -1); private final LightData lightData = new LightData(-1, -1);
private @Nullable Biome biome; private @Nullable Biome biome;
private boolean isBlockEntitySet;
private @Nullable BlockEntity blockEntity;
public Block(World world, int x, int y, int z) { public Block(World world, int x, int y, int z) {
set(world, x, y, z); set(world, x, y, z);
} }
@ -81,6 +84,8 @@ protected void reset() {
this.blockState = null; this.blockState = null;
this.lightData.set(-1, -1); this.lightData.set(-1, -1);
this.biome = null; this.biome = null;
this.isBlockEntitySet = false;
this.blockEntity = null;
} }
public T add(int dx, int dy, int dz) { public T add(int dx, int dy, int dz) {
@ -148,7 +153,11 @@ public int getBlockLightLevel() {
} }
public @Nullable BlockEntity getBlockEntity() { public @Nullable BlockEntity getBlockEntity() {
return getChunk().getBlockEntity(x, y, z); if (!isBlockEntitySet) {
blockEntity = getChunk().getBlockEntity(x, y, z);
isBlockEntitySet = true;
}
return blockEntity;
} }
@Override @Override

View File

@ -1,4 +1,5 @@
{ {
"renderer": "bluemap:missing",
"parent": "block/cube_all", "parent": "block/cube_all",
"textures": { "textures": {
"all": "bluemap:block/missing" "all": "bluemap:block/missing"

View File

@ -1,5 +1,5 @@
{ {
"parent": "bluemap:builtin/liquid", "renderer": "bluemap:liquid",
"textures": { "textures": {
"particle": "block/lava_still", "particle": "block/lava_still",
"still": "block/lava_still", "still": "block/lava_still",

View File

@ -1,5 +1,5 @@
{ {
"parent": "bluemap:builtin/liquid", "renderer": "bluemap:liquid",
"textures": { "textures": {
"particle": "block/water_still", "particle": "block/water_still",
"still": "block/water_still", "still": "block/water_still",