Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.material;

import org.jetbrains.annotations.Nullable;

import net.minecraft.resources.ResourceLocation;

public interface Material {
Expand Down Expand Up @@ -52,4 +54,49 @@ public interface Material {
* @return The cardinal lighting mode.
*/
CardinalLightingMode cardinalLightingMode();

/**
* Whether this material should receive ambient occlusion from nearby chunk geometry.
*
* @return {@code true} if this material should receive ambient occlusion.
*/
default boolean ambientOcclusion() {
return true;
}

/**
* Check for field-wise equality between this Material and another.
*
* @param other The nullable material to check equality against.
* @return True if the materials represent the same configuration.
*/
default boolean equals(@Nullable Material other) {
if (this == other) {
return true;
}

if (other == null) {
return false;
}

// @formatter:off
return this.blur() == other.blur()
&& this.mipmap() == other.mipmap()
&& this.backfaceCulling() == other.backfaceCulling()
&& this.polygonOffset() == other.polygonOffset()
&& this.depthTest() == other.depthTest()
&& this.transparency() == other.transparency()
&& this.writeMask() == other.writeMask()
&& this.useOverlay() == other.useOverlay()
&& this.useLight() == other.useLight()
&& this.cardinalLightingMode() == other.cardinalLightingMode()
&& this.ambientOcclusion() == other.ambientOcclusion()
&& this.shaders().fragmentSource().equals(other.shaders().fragmentSource())
&& this.shaders().vertexSource().equals(other.shaders().vertexSource())
&& this.fog().source().equals(other.fog().source())
&& this.cutout().source().equals(other.cutout().source())
&& this.light().source().equals(other.light().source())
&& this.texture().equals(other.texture());
// @formatter:on
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public final class MaterialEncoder {
private static final int USE_OVERLAY_LENGTH = 1;
private static final int USE_LIGHT_LENGTH = 1;
private static final int CARDINAL_LIGHTING_MODE_LENGTH = Mth.ceillog2(CardinalLightingMode.values().length);
private static final int AMBIENT_OCCLUSION_LENGTH = 1;

// The bit offset of each property
private static final int BLUR_OFFSET = 0;
Expand All @@ -33,6 +34,7 @@ public final class MaterialEncoder {
private static final int USE_OVERLAY_OFFSET = WRITE_MASK_OFFSET + WRITE_MASK_LENGTH;
private static final int USE_LIGHT_OFFSET = USE_OVERLAY_OFFSET + USE_OVERLAY_LENGTH;
private static final int CARDINAL_LIGHTING_MODE_OFFSET = USE_LIGHT_OFFSET + USE_LIGHT_LENGTH;
private static final int AMBIENT_OCCLUSION_OFFSET = CARDINAL_LIGHTING_MODE_OFFSET + CARDINAL_LIGHTING_MODE_LENGTH;

// The bit mask for each property
private static final int BLUR_MASK = bitMask(BLUR_LENGTH, BLUR_OFFSET);
Expand All @@ -45,6 +47,7 @@ public final class MaterialEncoder {
private static final int USE_OVERLAY_MASK = bitMask(USE_OVERLAY_LENGTH, USE_OVERLAY_OFFSET);
private static final int USE_LIGHT_MASK = bitMask(USE_LIGHT_LENGTH, USE_LIGHT_OFFSET);
private static final int CARDINAL_LIGHTING_MODE_MASK = bitMask(CARDINAL_LIGHTING_MODE_LENGTH, CARDINAL_LIGHTING_MODE_OFFSET);
private static final int AMBIENT_OCCLUSION_MASK = bitMask(AMBIENT_OCCLUSION_LENGTH, AMBIENT_OCCLUSION_OFFSET);

private MaterialEncoder() {
}
Expand All @@ -60,7 +63,7 @@ public static int packUberShader(Material material) {
}

// Packed format:
// cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
// ambientOcclusion[1] | cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
public static int packProperties(Material material) {
int bits = 0;

Expand All @@ -75,6 +78,7 @@ public static int packProperties(Material material) {
if (material.useLight()) bits |= USE_LIGHT_MASK;
bits |= (material.cardinalLightingMode()
.ordinal() << CARDINAL_LIGHTING_MODE_OFFSET) & CARDINAL_LIGHTING_MODE_MASK;
if (material.ambientOcclusion()) bits |= AMBIENT_OCCLUSION_MASK;

return bits;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public static boolean materialEquals(Material lhs, Material rhs) {
return true;
}

// Not here because ubershader: useLight, useOverlay, diffuse, fog shader
// Not here because ubershader: useLight, useOverlay, diffuse, fog shader, ambient occlusion
// Everything in the comparator should be here.
// @formatter:off
return lhs.blur() == rhs.blur()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ struct FlwMaterial {
bool useOverlay;
bool useLight;
uint cardinalLightingMode;
bool ambientOcclusion;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const uint _FLW_WRITE_MASK_LENGTH = 2u;
const uint _FLW_USE_OVERLAY_LENGTH = 1u;
const uint _FLW_USE_LIGHT_LENGTH = 1u;
const uint _FLW_CARDINAL_LIGHTING_MODE_LENGTH = 2u;
const uint _FLW_AMBIENT_OCCLUSION_LENGTH = 1u;

// The bit offset of each property
const uint _FLW_BLUR_OFFSET = 0u;
Expand All @@ -21,6 +22,7 @@ const uint _FLW_WRITE_MASK_OFFSET = _FLW_TRANSPARENCY_OFFSET + _FLW_TRANSPARENCY
const uint _FLW_USE_OVERLAY_OFFSET = _FLW_WRITE_MASK_OFFSET + _FLW_WRITE_MASK_LENGTH;
const uint _FLW_USE_LIGHT_OFFSET = _FLW_USE_OVERLAY_OFFSET + _FLW_USE_OVERLAY_LENGTH;
const uint _FLW_CARDINAL_LIGHTING_MODE_OFFSET = _FLW_USE_LIGHT_OFFSET + _FLW_USE_LIGHT_LENGTH;
const uint _FLW_AMBIENT_OCCLUSION_OFFSET = _FLW_CARDINAL_LIGHTING_MODE_OFFSET + _FLW_CARDINAL_LIGHTING_MODE_LENGTH;

// The bit mask for each property
const uint _FLW_BLUR_MASK = ((1u << _FLW_BLUR_LENGTH) - 1u) << _FLW_BLUR_OFFSET;
Expand All @@ -33,9 +35,10 @@ const uint _FLW_WRITE_MASK_MASK = ((1u << _FLW_WRITE_MASK_LENGTH) - 1u) << _FLW_
const uint _FLW_USE_OVERLAY_MASK = ((1u << _FLW_USE_OVERLAY_LENGTH) - 1u) << _FLW_USE_OVERLAY_OFFSET;
const uint _FLW_USE_LIGHT_MASK = ((1u << _FLW_USE_LIGHT_LENGTH) - 1u) << _FLW_USE_LIGHT_OFFSET;
const uint _FLW_CARDINAL_LIGHTING_MODE_MASK = ((1u << _FLW_CARDINAL_LIGHTING_MODE_LENGTH) - 1u) << _FLW_CARDINAL_LIGHTING_MODE_OFFSET;
const uint _FLW_AMBIENT_OCCLUSION_MASK = ((1u << _FLW_AMBIENT_OCCLUSION_LENGTH) - 1u) << _FLW_AMBIENT_OCCLUSION_OFFSET;

// Packed format:
// cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
// ambientOcclusion[1] | cardinalLightingMode[2] | useLight[1] | useOverlay[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
m.blur = (p & _FLW_BLUR_MASK) != 0u;
m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u;
Expand All @@ -47,6 +50,7 @@ void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
m.useOverlay = (p & _FLW_USE_OVERLAY_MASK) != 0u;
m.useLight = (p & _FLW_USE_LIGHT_MASK) != 0u;
m.cardinalLightingMode = (p & _FLW_CARDINAL_LIGHTING_MODE_MASK) >> _FLW_CARDINAL_LIGHTING_MODE_OFFSET;
m.ambientOcclusion = (p & _FLW_AMBIENT_OCCLUSION_MASK) != 0;
}

void _flw_unpackUint2x16(uint s, out uint hi, out uint lo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,37 @@
public final class Materials {
public static final Material SOLID_BLOCK = SimpleMaterial.builder()
.build();
public static final Material SOLID_UNSHADED_BLOCK = SimpleMaterial.builder()
public static final Material SOLID_UNSHADED_BLOCK = SimpleMaterial.builderOf(SOLID_BLOCK)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();

public static final Material CUTOUT_MIPPED_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.HALF)
.build();
public static final Material CUTOUT_MIPPED_UNSHADED_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.HALF)
public static final Material CUTOUT_MIPPED_UNSHADED_BLOCK = SimpleMaterial.builderOf(CUTOUT_MIPPED_BLOCK)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();

public static final Material CUTOUT_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.mipmap(false)
.build();
public static final Material CUTOUT_UNSHADED_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.mipmap(false)
public static final Material CUTOUT_UNSHADED_BLOCK = SimpleMaterial.builderOf(CUTOUT_BLOCK)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();

public static final Material TRANSLUCENT_BLOCK = SimpleMaterial.builder()
.transparency(Transparency.ORDER_INDEPENDENT)
.build();
public static final Material TRANSLUCENT_UNSHADED_BLOCK = SimpleMaterial.builder()
.transparency(Transparency.ORDER_INDEPENDENT)
public static final Material TRANSLUCENT_UNSHADED_BLOCK = SimpleMaterial.builderOf(TRANSLUCENT_BLOCK)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();

public static final Material TRIPWIRE_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.transparency(Transparency.ORDER_INDEPENDENT)
.build();
public static final Material TRIPWIRE_UNSHADED_BLOCK = SimpleMaterial.builder()
.cutout(CutoutShaders.ONE_TENTH)
.transparency(Transparency.ORDER_INDEPENDENT)
public static final Material TRIPWIRE_UNSHADED_BLOCK = SimpleMaterial.builderOf(TRIPWIRE_BLOCK)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class SimpleMaterial implements Material {
protected final boolean useLight;
protected final CardinalLightingMode cardinalLightingMode;

protected final boolean ambientOcclusion;

protected SimpleMaterial(Builder builder) {
shaders = builder.shaders();
fog = builder.fog();
Expand All @@ -48,6 +50,7 @@ protected SimpleMaterial(Builder builder) {
useOverlay = builder.useOverlay();
useLight = builder.useLight();
cardinalLightingMode = builder.cardinalLightingMode();
ambientOcclusion = builder.ambientOcclusion();
}

public static Builder builder() {
Expand Down Expand Up @@ -133,6 +136,11 @@ public CardinalLightingMode cardinalLightingMode() {
return cardinalLightingMode;
}

@Override
public boolean ambientOcclusion() {
return ambientOcclusion;
}

public static class Builder implements Material {
protected MaterialShaders shaders;
protected FogShader fog;
Expand All @@ -153,6 +161,8 @@ public static class Builder implements Material {
protected boolean useLight;
protected CardinalLightingMode cardinalLightingMode;

protected boolean ambientOcclusion;

public Builder() {
shaders = StandardMaterialShaders.DEFAULT;
fog = FogShaders.LINEAR;
Expand All @@ -169,6 +179,7 @@ public Builder() {
useOverlay = true;
useLight = true;
cardinalLightingMode = CardinalLightingMode.ENTITY;
ambientOcclusion = true;
}

public Builder(Material material) {
Expand All @@ -191,6 +202,7 @@ public Builder copyFrom(Material material) {
useOverlay = material.useOverlay();
useLight = material.useLight();
cardinalLightingMode = material.cardinalLightingMode();
ambientOcclusion = material.ambientOcclusion();
return this;
}

Expand Down Expand Up @@ -277,6 +289,11 @@ public Builder cardinalLightingMode(CardinalLightingMode value) {
return this;
}

public Builder ambientOcclusion(boolean ambientOcclusion) {
this.ambientOcclusion = ambientOcclusion;
return this;
}

@Override
public MaterialShaders shaders() {
return shaders;
Expand Down Expand Up @@ -352,6 +369,11 @@ public CardinalLightingMode cardinalLightingMode() {
return cardinalLightingMode;
}

@Override
public boolean ambientOcclusion() {
return ambientOcclusion;
}

public SimpleMaterial build() {
return new SimpleMaterial(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import org.joml.Vector3f;
import org.joml.Vector4f;

import dev.engine_room.flywheel.api.material.CardinalLightingMode;
import dev.engine_room.flywheel.api.material.Material;
import dev.engine_room.flywheel.api.model.Mesh;
import dev.engine_room.flywheel.api.model.Model;
import dev.engine_room.flywheel.api.vertex.VertexList;
import dev.engine_room.flywheel.lib.material.Materials;
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
import dev.engine_room.flywheel.lib.vertex.PosVertexView;
import net.minecraft.client.renderer.RenderType;
Expand All @@ -19,32 +21,62 @@
public final class ModelUtil {
private static final float BOUNDING_SPHERE_EPSILON = 1e-4f;

private static final RenderType[] CHUNK_LAYERS = new RenderType[]{RenderType.solid(), RenderType.cutoutMipped(), RenderType.cutout(), RenderType.translucent(), RenderType.tripwire()};

// Array of chunk materials to make lookups easier.
// Index by (renderTypeIdx * 4 + shaded * 2 + ambientOcclusion).
private static final Material[] CHUNK_MATERIALS = new Material[20];

static {
Material[] baseChunkMaterials = new Material[]{Materials.SOLID_BLOCK, Materials.CUTOUT_MIPPED_BLOCK, Materials.CUTOUT_BLOCK, Materials.TRANSLUCENT_BLOCK, Materials.TRIPWIRE_BLOCK,};
for (int chunkLayerIdx = 0; chunkLayerIdx < CHUNK_LAYERS.length; chunkLayerIdx++) {
int baseMaterialIdx = chunkLayerIdx * 4;
Material baseChunkMaterial = baseChunkMaterials[chunkLayerIdx];

// shaded: false, ambientOcclusion: false
CHUNK_MATERIALS[baseMaterialIdx] = SimpleMaterial.builderOf(baseChunkMaterial)
.cardinalLightingMode(CardinalLightingMode.OFF)
.ambientOcclusion(false)
.build();
// shaded: false, ambientOcclusion: true
CHUNK_MATERIALS[baseMaterialIdx + 1] = SimpleMaterial.builderOf(baseChunkMaterial)
.cardinalLightingMode(CardinalLightingMode.OFF)
.build();
// shaded: true, ambientOcclusion: false
CHUNK_MATERIALS[baseMaterialIdx + 2] = SimpleMaterial.builderOf(baseChunkMaterial)
.ambientOcclusion(false)
.build();
// shaded: true, ambientOcclusion: true
CHUNK_MATERIALS[baseMaterialIdx + 3] = baseChunkMaterial;
}
}

private ModelUtil() {
}

@Nullable
public static Material getMaterial(RenderType chunkRenderType, boolean shaded) {
if (chunkRenderType == RenderType.solid()) {
return shaded ? Materials.SOLID_BLOCK : Materials.SOLID_UNSHADED_BLOCK;
}
if (chunkRenderType == RenderType.cutoutMipped()) {
return shaded ? Materials.CUTOUT_MIPPED_BLOCK : Materials.CUTOUT_MIPPED_UNSHADED_BLOCK;
}
if (chunkRenderType == RenderType.cutout()) {
return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK;
}
if (chunkRenderType == RenderType.translucent()) {
return shaded ? Materials.TRANSLUCENT_BLOCK : Materials.TRANSLUCENT_UNSHADED_BLOCK;
}
if (chunkRenderType == RenderType.tripwire()) {
return shaded ? Materials.TRIPWIRE_BLOCK : Materials.TRIPWIRE_UNSHADED_BLOCK;
return getMaterial(chunkRenderType, shaded, true);
}

@Nullable
public static Material getMaterial(RenderType chunkRenderType, boolean shaded, boolean ambientOcclusion) {
for (int chunkLayerIdx = 0; chunkLayerIdx < CHUNK_LAYERS.length; ++chunkLayerIdx) {
if (chunkRenderType == CHUNK_LAYERS[chunkLayerIdx]) {
int shadedIdx = shaded ? 1 : 0;
int ambientOcclusionIdx = ambientOcclusion ? 1 : 0;

int materialIdx = chunkLayerIdx * 4 + shadedIdx * 2 + ambientOcclusionIdx;

return CHUNK_MATERIALS[materialIdx];
}
}
return null;
}

@Nullable
public static Material getItemMaterial(RenderType renderType) {
var chunkMaterial = getMaterial(renderType, true);
var chunkMaterial = getMaterial(renderType, true, false);

if (chunkMaterial != null) {
return chunkMaterial;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public abstract class BakedModelBuilder {
@Nullable
PoseStack poseStack;
@Nullable
BiFunction<RenderType, Boolean, Material> materialFunc;
BlockMaterialFunction materialFunc;

BakedModelBuilder(BakedModel bakedModel) {
this.bakedModel = bakedModel;
Expand All @@ -50,7 +50,17 @@ public BakedModelBuilder poseStack(@Nullable PoseStack poseStack) {
return this;
}

public BakedModelBuilder materialFunc(@Nullable BiFunction<RenderType, Boolean, Material> materialFunc) {
@Deprecated(forRemoval = true)
public BakedModelBuilder materialFunc(@Nullable BiFunction<RenderType, Boolean, @Nullable Material> materialFunc) {
if (materialFunc != null) {
this.materialFunc = (chunkRenderType, shaded, ambientOcclusion) -> materialFunc.apply(chunkRenderType, shaded);
} else {
this.materialFunc = null;
}
return this;
}

public BakedModelBuilder materialFunc(@Nullable BlockMaterialFunction materialFunc) {
this.materialFunc = materialFunc;
return this;
}
Expand Down
Loading