diff --git a/src/main/java/grondag/canvas/apiimpl/material/AbstractMeshMaterial.java b/src/main/java/grondag/canvas/apiimpl/material/AbstractMeshMaterial.java index 7722d8237..c738a77b9 100644 --- a/src/main/java/grondag/canvas/apiimpl/material/AbstractMeshMaterial.java +++ b/src/main/java/grondag/canvas/apiimpl/material/AbstractMeshMaterial.java @@ -23,6 +23,40 @@ import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; public abstract class AbstractMeshMaterial { + protected long bits; + + AbstractMeshMaterial(long bits) { + this.bits = bits; + } + + public BlendMode blendMode() { + return BLEND_MODE.getValue(bits); + } + + public boolean disableColorIndex() { + return DISABLE_COLOR.getValue(bits); + } + + public boolean emissive() { + return EMISSIVE.getValue(bits); + } + + public boolean disableDiffuse() { + return DISABLE_DIFFUSE.getValue(bits); + } + + public boolean disableAo() { + return DISABLE_AO.getValue(bits); + } + + public MaterialShaderImpl shader() { + return MaterialShaderManager.INSTANCE.get(SHADER.getValue(bits)); + } + + public MaterialConditionImpl condition() { + return MaterialConditionImpl.fromIndex(CONDITION.getValue(bits)); + } + public static final int SHADER_FLAGS_DISABLE_AO; static final BlendMode[] LAYERS = new BlendMode[4]; private static final BitPacker64 BITPACKER_0 = new BitPacker64<>(null, null); @@ -58,38 +92,4 @@ public abstract class AbstractMeshMaterial { DEFAULT_BITS = defaultBits; SHADER_FLAGS_DISABLE_AO = (int) DISABLE_AO.setValue(true, 0); } - - protected long bits; - - AbstractMeshMaterial(long bits) { - this.bits = bits; - } - - public BlendMode blendMode() { - return BLEND_MODE.getValue(bits); - } - - public boolean disableColorIndex() { - return DISABLE_COLOR.getValue(bits); - } - - public boolean emissive() { - return EMISSIVE.getValue(bits); - } - - public boolean disableDiffuse() { - return DISABLE_DIFFUSE.getValue(bits); - } - - public boolean disableAo() { - return DISABLE_AO.getValue(bits); - } - - public MaterialShaderImpl shader() { - return MaterialShaderManager.INSTANCE.get(SHADER.getValue(bits)); - } - - public MaterialConditionImpl condition() { - return MaterialConditionImpl.fromIndex(CONDITION.getValue(bits)); - } } diff --git a/src/main/java/grondag/canvas/apiimpl/material/MeshMaterial.java b/src/main/java/grondag/canvas/apiimpl/material/MeshMaterial.java index 924d99998..e44423747 100644 --- a/src/main/java/grondag/canvas/apiimpl/material/MeshMaterial.java +++ b/src/main/java/grondag/canvas/apiimpl/material/MeshMaterial.java @@ -90,7 +90,7 @@ public MaterialConditionImpl condition() { static final ObjectArrayList LIST = new ObjectArrayList<>(); static final Long2ObjectOpenHashMap MAP = new Long2ObjectOpenHashMap<>(); - public static MeshMaterial byIndex(int index) { + public static MeshMaterial fromIndex(int index) { assert index < LIST.size(); assert index >= 0; diff --git a/src/main/java/grondag/canvas/apiimpl/mesh/MutableQuadViewImpl.java b/src/main/java/grondag/canvas/apiimpl/mesh/MutableQuadViewImpl.java index 605f07e60..64391f9f4 100644 --- a/src/main/java/grondag/canvas/apiimpl/mesh/MutableQuadViewImpl.java +++ b/src/main/java/grondag/canvas/apiimpl/mesh/MutableQuadViewImpl.java @@ -94,7 +94,7 @@ public final MutableQuadViewImpl material(RenderMaterial material) { data[baseIndex + HEADER_MATERIAL] = ((MeshMaterial) material).index; - assert MeshMaterial.byIndex(data[baseIndex + HEADER_MATERIAL]) == material; + assert MeshMaterial.fromIndex(data[baseIndex + HEADER_MATERIAL]) == material; return this; } diff --git a/src/main/java/grondag/canvas/apiimpl/mesh/QuadViewImpl.java b/src/main/java/grondag/canvas/apiimpl/mesh/QuadViewImpl.java index 62fd911ac..496a2bcb5 100644 --- a/src/main/java/grondag/canvas/apiimpl/mesh/QuadViewImpl.java +++ b/src/main/java/grondag/canvas/apiimpl/mesh/QuadViewImpl.java @@ -178,7 +178,7 @@ public final void toVanilla(int[] target, int targetIndex) { @Override public final MeshMaterial material() { - return MeshMaterial.byIndex(data[baseIndex + HEADER_MATERIAL]); + return MeshMaterial.fromIndex(data[baseIndex + HEADER_MATERIAL]); } @Override diff --git a/src/main/java/grondag/canvas/mixin/MixinMultiPhase.java b/src/main/java/grondag/canvas/mixin/MixinMultiPhase.java index 534405ca4..65fa3bd2c 100644 --- a/src/main/java/grondag/canvas/mixin/MixinMultiPhase.java +++ b/src/main/java/grondag/canvas/mixin/MixinMultiPhase.java @@ -19,8 +19,8 @@ import java.util.Optional; import grondag.canvas.mixinterface.MultiPhaseExt; -import grondag.canvas.wip.state.WipRenderState; -import grondag.canvas.wip.state.WipVertexState; +import grondag.canvas.wip.state.WipRenderMaterial; +import grondag.canvas.wip.state.WipRenderMaterialFinder; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -37,8 +37,7 @@ abstract class MixinMultiPhase extends RenderLayer implements MultiPhaseExt { @Shadow private RenderLayer.MultiPhaseParameters phases; - private @Nullable WipRenderState renderState; - private int vertexState; + private @Nullable WipRenderMaterial materialState; private MixinMultiPhase(String name, VertexFormat vertexFormat, int drawMode, int expectedBufferSize, boolean hasCrumbling, boolean translucent, Runnable startAction, Runnable endAction) { super(name, vertexFormat, drawMode, expectedBufferSize, hasCrumbling, translucent, startAction, endAction); @@ -65,23 +64,17 @@ public AccessMultiPhaseParameters canvas_phases() { } @Override - public WipRenderState canvas_renderState() { - WipRenderState result = renderState; + public WipRenderMaterial canvas_materialState() { + WipRenderMaterial result = materialState; if (result == null) { - result = WipRenderState.finder().copyFromLayer(this); - renderState = result; - vertexState = WipVertexState.finder().copyFromLayer(this).find(); + result = WipRenderMaterialFinder.threadLocal().copyFromLayer(this); + materialState = result; } return result; } - @Override - public int canvas_vertexState() { - return vertexState; - } - @Override public void canvas_startDrawing() { super.startDrawing(); diff --git a/src/main/java/grondag/canvas/mixinterface/MultiPhaseExt.java b/src/main/java/grondag/canvas/mixinterface/MultiPhaseExt.java index 94ec5ba55..899c60b42 100644 --- a/src/main/java/grondag/canvas/mixinterface/MultiPhaseExt.java +++ b/src/main/java/grondag/canvas/mixinterface/MultiPhaseExt.java @@ -19,12 +19,11 @@ import java.util.Optional; import grondag.canvas.mixin.AccessMultiPhaseParameters; -import grondag.canvas.wip.state.WipRenderState; +import grondag.canvas.wip.state.WipRenderMaterial; import net.minecraft.client.render.RenderLayer; public interface MultiPhaseExt { - Optional canvas_affectedOutline(); boolean canvas_outline(); @@ -35,12 +34,7 @@ public interface MultiPhaseExt { AccessMultiPhaseParameters canvas_phases(); - WipRenderState canvas_renderState(); - - /** - * Must be called after {@link #canvas_renderState()} - */ - int canvas_vertexState(); + WipRenderMaterial canvas_materialState(); String canvas_name(); } diff --git a/src/main/java/grondag/canvas/render/CanvasParticleRenderer.java b/src/main/java/grondag/canvas/render/CanvasParticleRenderer.java index 8551d89fb..c5359969f 100644 --- a/src/main/java/grondag/canvas/render/CanvasParticleRenderer.java +++ b/src/main/java/grondag/canvas/render/CanvasParticleRenderer.java @@ -25,8 +25,8 @@ import grondag.canvas.mixinterface.ParticleManagerExt; import grondag.canvas.wip.encoding.WipVertexCollectorImpl; import grondag.canvas.wip.state.RenderContextState; -import grondag.canvas.wip.state.WipRenderState; -import grondag.canvas.wip.state.WipVertexState; +import grondag.canvas.wip.state.WipRenderMaterial; +import grondag.canvas.wip.state.WipRenderMaterialFinder; import grondag.canvas.wip.state.property.WipDecal; import grondag.canvas.wip.state.property.WipDepthTest; import grondag.canvas.wip.state.property.WipFog; @@ -60,6 +60,8 @@ public class CanvasParticleRenderer { private LightmapTextureManager lightmapTextureManager; private ParticleManagerExt ext; private Runnable drawHandler = Runnables.doNothing(); + private WipRenderMaterial baseMat; + private WipRenderMaterial emissiveMat; CanvasParticleRenderer(RenderContextState contextState) { collector = new WipVertexCollectorImpl(contextState); @@ -87,7 +89,6 @@ public void renderParticles(ParticleManager pm, MatrixStack matrixStack, VertexC if (!particles.hasNext()) continue; - // FEAT: material maps for particles final VertexConsumer consumer = beginSheet(particleTextureSheet); @@ -95,8 +96,9 @@ public void renderParticles(ParticleManager pm, MatrixStack matrixStack, VertexC final Particle particle = particles.next(); try { + // FEAT: enhanced material maps for particles - shaders for animation in particular final RenderMaterial mat = (RenderMaterial) MaterialMap.getForParticle(((ParticleExt) particle).canvas_particleType()).getMapped(null); - collector.vertexState(mat == null || !mat.emissive() ? PARTICLE_VERTEX_STATE : PARTICLE_EMISSIVE_VERTEX_STATE); + collector.vertexState(mat == null || !mat.emissive() ? baseMat : emissiveMat); particle.buildGeometry(consumer, camera, tickDelta); } catch (final Throwable exception) { final CrashReport crashReport = CrashReport.create(exception, "Rendering Particle"); @@ -137,18 +139,21 @@ private VertexConsumer beginSheet(ParticleTextureSheet particleTextureSheet) { // PERF: consolidate these draws if (Configurator.enableExperimentalPipeline) { if (particleTextureSheet == ParticleTextureSheet.TERRAIN_SHEET) { - collector.prepare(RENDER_STATE_TERRAIN); - collector.vertexState(PARTICLE_VERTEX_STATE); + baseMat = RENDER_STATE_TERRAIN; + emissiveMat = RENDER_STATE_TERRAIN_EMISSIVE; + collector.prepare(baseMat); drawHandler = () -> collector.drawAndClear(); return collector; } else if (particleTextureSheet == ParticleTextureSheet.PARTICLE_SHEET_LIT || particleTextureSheet == ParticleTextureSheet.PARTICLE_SHEET_OPAQUE) { - collector.prepare(RENDER_STATE_OPAQUE_OR_LIT); - collector.vertexState(PARTICLE_VERTEX_STATE); + baseMat = RENDER_STATE_OPAQUE_OR_LIT; + emissiveMat = RENDER_STATE_OPAQUE_OR_LIT_EMISSIVE; + collector.prepare(baseMat); drawHandler = () -> collector.drawAndClear(); return collector; } else if (particleTextureSheet == ParticleTextureSheet.PARTICLE_SHEET_TRANSLUCENT) { - collector.prepare(RENDER_STATE_TRANSLUCENT); - collector.vertexState(PARTICLE_VERTEX_STATE); + baseMat = RENDER_STATE_TRANSLUCENT; + emissiveMat = RENDER_STATE_TRANSLUCENT_EMISSIVE; + collector.prepare(baseMat); drawHandler = () -> collector.drawAndClear(); return collector; } @@ -160,8 +165,8 @@ private VertexConsumer beginSheet(ParticleTextureSheet particleTextureSheet) { return bufferBuilder; } - private static WipRenderState.Finder baseFinder() { - return WipRenderState.finder() + private static WipRenderMaterialFinder baseFinder() { + return WipRenderMaterialFinder.threadLocal() .primitive(GL11.GL_QUADS) .depthTest(WipDepthTest.LEQUAL) .cull(false) @@ -170,26 +175,38 @@ private static WipRenderState.Finder baseFinder() { .decal(WipDecal.NONE) .target(WipTarget.PARTICLES) .lines(false) + .disableAo(true) + .disableDiffuse(true) + .cutout(true) + .translucentCutout(true) .fog(WipFog.BLACK_FOG); } - private static final WipRenderState RENDER_STATE_TERRAIN = baseFinder() + private static final WipRenderMaterial RENDER_STATE_TERRAIN = baseFinder() .texture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) .transparency(WipTransparency.DEFAULT) .find(); + private static final WipRenderMaterial RENDER_STATE_TERRAIN_EMISSIVE = baseFinder().copyFrom(RENDER_STATE_TERRAIN) + .emissive(true) + .find(); + // MC has two but they are functionally identical - private static final WipRenderState RENDER_STATE_OPAQUE_OR_LIT = baseFinder() + private static final WipRenderMaterial RENDER_STATE_OPAQUE_OR_LIT = baseFinder() .transparency(WipTransparency.NONE) .texture(SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE) .find(); - private static final WipRenderState RENDER_STATE_TRANSLUCENT = baseFinder() + private static final WipRenderMaterial RENDER_STATE_OPAQUE_OR_LIT_EMISSIVE = baseFinder().copyFrom(RENDER_STATE_OPAQUE_OR_LIT) + .emissive(true) + .find(); + + private static final WipRenderMaterial RENDER_STATE_TRANSLUCENT = baseFinder() .transparency(WipTransparency.TRANSLUCENT) .texture(SpriteAtlasTexture.PARTICLE_ATLAS_TEXTURE) .find(); - // Doesn't strictly match vanilla - which uses 10% threshold vs the 0.03xxx value here. - private static final int PARTICLE_VERTEX_STATE = WipVertexState.finder().disableAo(true).disableDiffuse(true).cutout(true).translucentCutout(true).find(); - private static final int PARTICLE_EMISSIVE_VERTEX_STATE = WipVertexState.finder().disableAo(true).disableDiffuse(true).cutout(true).translucentCutout(true).emissive(true).find(); + private static final WipRenderMaterial RENDER_STATE_TRANSLUCENT_EMISSIVE = baseFinder().copyFrom(RENDER_STATE_TRANSLUCENT) + .emissive(true) + .find(); } diff --git a/src/main/java/grondag/canvas/wip/encoding/WipAbstractVertexCollector.java b/src/main/java/grondag/canvas/wip/encoding/WipAbstractVertexCollector.java index 09d59ce17..8f8fe7a5b 100644 --- a/src/main/java/grondag/canvas/wip/encoding/WipAbstractVertexCollector.java +++ b/src/main/java/grondag/canvas/wip/encoding/WipAbstractVertexCollector.java @@ -20,8 +20,8 @@ import grondag.canvas.apiimpl.util.NormalHelper; import grondag.canvas.mixinterface.SpriteExt; import grondag.canvas.wip.state.RenderContextState; -import grondag.canvas.wip.state.WipRenderState; -import grondag.canvas.wip.state.WipVertexState; +import grondag.canvas.wip.state.RenderStateData; +import grondag.canvas.wip.state.WipRenderMaterial; import static grondag.canvas.material.MaterialVertexFormats.MATERIAL_COLOR_INDEX; import static grondag.canvas.material.MaterialVertexFormats.MATERIAL_LIGHT_INDEX; @@ -36,7 +36,7 @@ public abstract class WipAbstractVertexCollector implements WipVertexCollector { private static final int LAST_VERTEX_BASE_INDEX = MATERIAL_QUAD_STRIDE - MATERIAL_VERTEX_STRIDE; - protected WipRenderState materialState; + protected WipRenderMaterial materialState; protected final RenderContextState contextState; protected final int[] vertexData = new int[MATERIAL_QUAD_STRIDE]; @@ -63,9 +63,9 @@ public WipVertexCollector texture(float u, float v) { public WipVertexCollector overlay(int u, int v) { if (v == 3) { // NB: these are pre-shifted to msb - overlayFlags = WipVertexState.HURT_OVERLAY_FLAG; + overlayFlags = RenderStateData.HURT_OVERLAY_FLAG; } else if (v == 10) { - overlayFlags = u > 7 ? WipVertexState.FLASH_OVERLAY_FLAG : 0; + overlayFlags = u > 7 ? RenderStateData.FLASH_OVERLAY_FLAG : 0; } else { overlayFlags = 0; } @@ -87,9 +87,10 @@ public WipVertexCollector packedLightWithAo(int packedLight, int ao) { } @Override - public WipVertexCollector vertexState(int vertexState) { - normalBase = (WipVertexState.shaderFlags(vertexState) << 24); - conditionActive = WipVertexState.condition(vertexState).compute(); + public WipVertexCollector vertexState(WipRenderMaterial material) { + // WIP2: should assert collector key doesn't change here but not currently visible + normalBase = (material.shaderFlags << 24); + conditionActive = material.condition().compute(); return this; } diff --git a/src/main/java/grondag/canvas/wip/encoding/WipImmediate.java b/src/main/java/grondag/canvas/wip/encoding/WipImmediate.java index c804ea081..cb5c11afd 100644 --- a/src/main/java/grondag/canvas/wip/encoding/WipImmediate.java +++ b/src/main/java/grondag/canvas/wip/encoding/WipImmediate.java @@ -28,14 +28,14 @@ public WipImmediate(BufferBuilder fallbackBuffer, Map drawList for (int i = 0; i < limit; ++i) { final WipVertexCollectorImpl collector = drawList.get(i); final int vertexCount = collector.vertexCount(); - collector.materialState.enable(); + collector.materialState.renderState.enable(); GlStateManager.drawArrays(collector.materialState.primitive, startIndex, vertexCount); startIndex += vertexCount; collector.clear(); diff --git a/src/main/java/grondag/canvas/wip/encoding/WipVertexCollectorList.java b/src/main/java/grondag/canvas/wip/encoding/WipVertexCollectorList.java index 0a375c7e0..ddc4c7179 100644 --- a/src/main/java/grondag/canvas/wip/encoding/WipVertexCollectorList.java +++ b/src/main/java/grondag/canvas/wip/encoding/WipVertexCollectorList.java @@ -20,6 +20,7 @@ import grondag.canvas.material.MaterialState; import grondag.canvas.wip.state.RenderContextState; +import grondag.canvas.wip.state.WipRenderMaterial; import grondag.canvas.wip.state.WipRenderState; import it.unimi.dsi.fastutil.objects.ObjectArrayList; @@ -51,16 +52,16 @@ public void clear() { size = 0; } - public final WipVertexCollectorImpl getIfExists(WipRenderState materialState) { - return materialState == WipRenderState.MISSING ? null : collectors[materialState.index]; + public final WipVertexCollectorImpl getIfExists(WipRenderMaterial materialState) { + return materialState == WipRenderMaterial.MISSING ? null : collectors[materialState.collectorIndex]; } - public final WipVertexCollectorImpl get(WipRenderState materialState) { - if (materialState == WipRenderState.MISSING) { + public final WipVertexCollectorImpl get(WipRenderMaterial materialState) { + if (materialState == WipRenderMaterial.MISSING) { return null; } - final int index = materialState.index; + final int index = materialState.collectorIndex; WipVertexCollectorImpl[] collectors = this.collectors; WipVertexCollectorImpl result; @@ -76,7 +77,7 @@ public final WipVertexCollectorImpl get(WipRenderState materialState) { } if (result == null) { - assert materialState.index != MaterialState.TRANSLUCENT_INDEX; + assert materialState.collectorIndex != MaterialState.TRANSLUCENT_INDEX; result = emptyCollector().prepare(materialState); collectors[index] = result; } diff --git a/src/main/java/grondag/canvas/wip/state/AbstractRenderState.java b/src/main/java/grondag/canvas/wip/state/AbstractRenderState.java index 5605adfa5..134917dd0 100644 --- a/src/main/java/grondag/canvas/wip/state/AbstractRenderState.java +++ b/src/main/java/grondag/canvas/wip/state/AbstractRenderState.java @@ -26,12 +26,8 @@ import grondag.canvas.wip.state.property.WipTextureState; import grondag.canvas.wip.state.property.WipTransparency; import grondag.canvas.wip.state.property.WipWriteMask; -import grondag.fermion.bits.BitPacker64; - -@SuppressWarnings("rawtypes") -abstract class AbstractRenderState { - protected final long bits; +abstract class AbstractRenderState extends AbstractRenderStateView { public final int index; /** @@ -46,7 +42,9 @@ abstract class AbstractRenderState { */ public final int primitive; + // WIP: remove - doesn't change public final int vertexStrideInts; + public final WipTextureState texture; public final boolean bilinear; public final WipTransparency translucency; @@ -68,45 +66,22 @@ abstract class AbstractRenderState { public final boolean isTranslucentTerrain; protected AbstractRenderState(int index, long bits) { - this.bits = bits; + super(bits); this.index = index; - primitive = PRIMITIVE.getValue(bits); - texture = WipTextureState.fromIndex(TEXTURE.getValue(bits)); - bilinear = BILINEAR.getValue(bits); - depthTest = DEPTH_TEST.getValue(bits); - cull = CULL.getValue(bits); - writeMask = WRITE_MASK.getValue(bits); - enableLightmap = ENABLE_LIGHTMAP.getValue(bits); - decal = DECAL.getValue(bits); - target = TARGET.getValue(bits); - lines = LINES.getValue(bits); - fog = FOG.getValue(bits); + primitive = primitive(); + texture = texture(); + bilinear = bilinear(); + depthTest = depthTest(); + cull = cull(); + writeMask = writeMask(); + enableLightmap = enableLightmap(); + decal = decal(); + target = target(); + lines = lines(); + fog = fog(); vertexStrideInts = MaterialVertexFormats.POSITION_COLOR_TEXTURE_MATERIAL_LIGHT_NORMAL.vertexStrideInts; translucency = TRANSPARENCY.getValue(bits); - shader = WipMaterialShaderManager.INSTANCE.find(VERTEX_SHADER.getValue(bits), FRAGMENT_SHADER.getValue(bits), translucency == WipTransparency.TRANSLUCENT ? WipProgramType.MATERIAL_VERTEX_LOGIC : WipProgramType.MATERIAL_UNIFORM_LOGIC); + shader = WipMaterialShaderManager.INSTANCE.get(SHADER.getValue(bits)); isTranslucentTerrain = (target == WipTarget.MAIN || target == WipTarget.TRANSLUCENT) && translucency == WipTransparency.TRANSLUCENT; } - - - static final BitPacker64 PACKER = new BitPacker64<> (null, null); - - // GL State comes first for sorting - static final BitPacker64.IntElement TEXTURE = PACKER.createIntElement(WipTextureState.MAX_TEXTURE_STATES); - static final BitPacker64.BooleanElement BILINEAR = PACKER.createBooleanElement(); - - static final BitPacker64.EnumElement TRANSPARENCY = PACKER.createEnumElement(WipTransparency.class); - static final BitPacker64.EnumElement DEPTH_TEST = PACKER.createEnumElement(WipDepthTest.class); - static final BitPacker64.BooleanElement CULL = PACKER.createBooleanElement(); - static final BitPacker64.EnumElement WRITE_MASK = PACKER.createEnumElement(WipWriteMask.class); - static final BitPacker64.BooleanElement ENABLE_LIGHTMAP = PACKER.createBooleanElement(); - static final BitPacker64.EnumElement DECAL = PACKER.createEnumElement(WipDecal.class); - static final BitPacker64.EnumElement TARGET = PACKER.createEnumElement(WipTarget.class); - static final BitPacker64.BooleanElement LINES = PACKER.createBooleanElement(); - static final BitPacker64.EnumElement FOG = PACKER.createEnumElement(WipFog.class); - - // These don't affect GL state but do affect encoding - must be buffered separately - static final BitPacker64.IntElement PRIMITIVE = PACKER.createIntElement(8); - - static final BitPacker64.IntElement VERTEX_SHADER = PACKER.createIntElement(4096); - static final BitPacker64.IntElement FRAGMENT_SHADER = PACKER.createIntElement(4096); } diff --git a/src/main/java/grondag/canvas/wip/state/AbstractRenderStateView.java b/src/main/java/grondag/canvas/wip/state/AbstractRenderStateView.java new file mode 100644 index 000000000..c6d8215f0 --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/AbstractRenderStateView.java @@ -0,0 +1,211 @@ +/* + * Copyright 2019, 2020 grondag + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package grondag.canvas.wip.state; + +import grondag.canvas.apiimpl.MaterialConditionImpl; +import grondag.canvas.wip.shader.WipMaterialShaderImpl; +import grondag.canvas.wip.shader.WipMaterialShaderManager; +import grondag.canvas.wip.state.property.WipDecal; +import grondag.canvas.wip.state.property.WipDepthTest; +import grondag.canvas.wip.state.property.WipFog; +import grondag.canvas.wip.state.property.WipTarget; +import grondag.canvas.wip.state.property.WipTextureState; +import grondag.canvas.wip.state.property.WipTransparency; +import grondag.canvas.wip.state.property.WipWriteMask; +import grondag.fermion.bits.BitPacker64; +import grondag.frex.api.material.MaterialCondition; + +import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; + +@SuppressWarnings("rawtypes") +abstract class AbstractRenderStateView { + protected long bits; + + protected AbstractRenderStateView(long bits) { + this.bits = bits; + } + + public long collectorKey() { + return bits & COLLECTOR_KEY_MASK; + } + + public WipMaterialShaderImpl shader() { + return WipMaterialShaderManager.INSTANCE.get(SHADER.getValue(bits)); + } + + public MaterialCondition condition() { + return MaterialConditionImpl.fromIndex(CONDITION.getValue(bits)); + } + + public int conditionIndex() { + return CONDITION.getValue(bits); + } + + public boolean emissive() { + return EMISSIVE.getValue(bits); + } + + public boolean disableDiffuse() { + return DISABLE_DIFFUSE.getValue(bits); + } + + public boolean disableAo() { + return DISABLE_AO.getValue(bits); + } + + public int primitive() { + return PRIMITIVE.getValue(bits); + } + + public WipTextureState texture() { + return WipTextureState.fromIndex(TEXTURE.getValue(bits)); + } + + public boolean bilinear() { + return BILINEAR.getValue(bits); + } + + public WipTransparency translucency() { + return TRANSPARENCY.getValue(bits); + } + + public WipDepthTest depthTest() { + return DEPTH_TEST.getValue(bits); + } + + public boolean cull() { + return CULL.getValue(bits); + } + + public WipWriteMask writeMask() { + return WRITE_MASK.getValue(bits); + } + + public boolean enableLightmap() { + return ENABLE_LIGHTMAP.getValue(bits); + } + + public WipDecal decal() { + return DECAL.getValue(bits); + } + + public WipTarget target() { + return TARGET.getValue(bits); + } + + public boolean lines() { + return LINES.getValue(bits); + } + + public WipFog fog() { + return FOG.getValue(bits); + } + + /** derived and may not match input for non-block layers */ + @Deprecated + public BlendMode blendMode() { + if (DEFAULT_BLEND_MODE.getValue(bits)) { + return BlendMode.DEFAULT; + } + + if (translucency() != WipTransparency.NONE) { + return BlendMode.TRANSLUCENT; + } else if (cutout()) { + return unmipped() ? BlendMode.CUTOUT : BlendMode.CUTOUT_MIPPED; + } else { + return BlendMode.SOLID; + } + } + + public boolean disableColorIndex() { + return DISABLE_COLOR_INDEX.getValue(bits); + } + + public boolean cutout() { + return CUTOUT.getValue(bits); + } + + public boolean unmipped() { + return UNMIPPED.getValue(bits); + } + + public boolean translucentCutout() { + return TRANSLUCENT_CUTOUT.getValue(bits); + } + + public boolean hurtOverlay() { + return HURT_OVERLAY.getValue(bits); + } + + public boolean flashOverlay() { + return FLASH_OVERLAY.getValue(bits); + } + + public int shaderFlags() { + return (int) (bits >>> FLAG_SHIFT) & 0xFF; + } + + static final BitPacker64 PACKER = new BitPacker64<> (null, null); + + // GL State comes first for sorting + static final BitPacker64.IntElement TEXTURE = PACKER.createIntElement(WipTextureState.MAX_TEXTURE_STATES); + static final BitPacker64.BooleanElement BILINEAR = PACKER.createBooleanElement(); + + static final BitPacker64.EnumElement TRANSPARENCY = PACKER.createEnumElement(WipTransparency.class); + static final BitPacker64.EnumElement DEPTH_TEST = PACKER.createEnumElement(WipDepthTest.class); + static final BitPacker64.BooleanElement CULL = PACKER.createBooleanElement(); + static final BitPacker64.EnumElement WRITE_MASK = PACKER.createEnumElement(WipWriteMask.class); + static final BitPacker64.BooleanElement ENABLE_LIGHTMAP = PACKER.createBooleanElement(); + static final BitPacker64.EnumElement DECAL = PACKER.createEnumElement(WipDecal.class); + static final BitPacker64.EnumElement TARGET = PACKER.createEnumElement(WipTarget.class); + static final BitPacker64.BooleanElement LINES = PACKER.createBooleanElement(); + static final BitPacker64.EnumElement FOG = PACKER.createEnumElement(WipFog.class); + static final BitPacker64.IntElement SHADER = PACKER.createIntElement(4096); + + public static final long RENDER_STATE_MASK = PACKER.bitMask(); + + // These don't affect GL state but must be buffered separately + // Should always be zero in render state, only used in buffer key and material + static final BitPacker64.IntElement PRIMITIVE = PACKER.createIntElement(8); + static final BitPacker64.IntElement CONDITION = PACKER.createIntElement(MaterialConditionImpl.MAX_CONDITIONS); + + public static final long COLLECTOR_KEY_MASK = PACKER.bitMask(); + + // here and below only used in material - holds vertex state - does not affect buffering or gl State + static final BitPacker64.BooleanElement DISABLE_COLOR_INDEX = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement DEFAULT_BLEND_MODE = PACKER.createBooleanElement(); + + static final int FLAG_SHIFT = PACKER.bitLength(); + + // last 8 bits correspond to shader flag bits + static final BitPacker64.BooleanElement EMISSIVE = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement DISABLE_DIFFUSE = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement DISABLE_AO = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement CUTOUT = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement UNMIPPED = PACKER.createBooleanElement(); + // true = 10%, false = 50% + static final BitPacker64.BooleanElement TRANSLUCENT_CUTOUT = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement HURT_OVERLAY = PACKER.createBooleanElement(); + static final BitPacker64.BooleanElement FLASH_OVERLAY = PACKER.createBooleanElement(); + + public static final long HURT_OVERLAY_FLAG = HURT_OVERLAY.comparisonMask() >>> FLAG_SHIFT; + public static final long FLASH_OVERLAY_FLAG = FLASH_OVERLAY.comparisonMask() >>> FLAG_SHIFT; + + static { + assert PACKER.bitLength() <= 64; + } +} diff --git a/src/main/java/grondag/canvas/wip/state/AbstractStateFinder.java b/src/main/java/grondag/canvas/wip/state/AbstractStateFinder.java index b73607bcd..6532f2851 100644 --- a/src/main/java/grondag/canvas/wip/state/AbstractStateFinder.java +++ b/src/main/java/grondag/canvas/wip/state/AbstractStateFinder.java @@ -34,21 +34,27 @@ import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; -import static grondag.canvas.wip.state.AbstractRenderState.BILINEAR; -import static grondag.canvas.wip.state.AbstractRenderState.CULL; -import static grondag.canvas.wip.state.AbstractRenderState.DECAL; -import static grondag.canvas.wip.state.AbstractRenderState.DEPTH_TEST; -import static grondag.canvas.wip.state.AbstractRenderState.ENABLE_LIGHTMAP; -import static grondag.canvas.wip.state.AbstractRenderState.FOG; -import static grondag.canvas.wip.state.AbstractRenderState.FRAGMENT_SHADER; -import static grondag.canvas.wip.state.AbstractRenderState.LINES; -import static grondag.canvas.wip.state.AbstractRenderState.PACKER; -import static grondag.canvas.wip.state.AbstractRenderState.PRIMITIVE; -import static grondag.canvas.wip.state.AbstractRenderState.TARGET; -import static grondag.canvas.wip.state.AbstractRenderState.TEXTURE; -import static grondag.canvas.wip.state.AbstractRenderState.TRANSPARENCY; -import static grondag.canvas.wip.state.AbstractRenderState.VERTEX_SHADER; -import static grondag.canvas.wip.state.AbstractRenderState.WRITE_MASK; +import static grondag.canvas.wip.state.AbstractRenderStateView.BILINEAR; +import static grondag.canvas.wip.state.AbstractRenderStateView.CULL; +import static grondag.canvas.wip.state.AbstractRenderStateView.CUTOUT; +import static grondag.canvas.wip.state.AbstractRenderStateView.DECAL; +import static grondag.canvas.wip.state.AbstractRenderStateView.DEPTH_TEST; +import static grondag.canvas.wip.state.AbstractRenderStateView.DISABLE_AO; +import static grondag.canvas.wip.state.AbstractRenderStateView.DISABLE_DIFFUSE; +import static grondag.canvas.wip.state.AbstractRenderStateView.EMISSIVE; +import static grondag.canvas.wip.state.AbstractRenderStateView.ENABLE_LIGHTMAP; +import static grondag.canvas.wip.state.AbstractRenderStateView.FLASH_OVERLAY; +import static grondag.canvas.wip.state.AbstractRenderStateView.FOG; +import static grondag.canvas.wip.state.AbstractRenderStateView.HURT_OVERLAY; +import static grondag.canvas.wip.state.AbstractRenderStateView.LINES; +import static grondag.canvas.wip.state.AbstractRenderStateView.PRIMITIVE; +import static grondag.canvas.wip.state.AbstractRenderStateView.SHADER; +import static grondag.canvas.wip.state.AbstractRenderStateView.TARGET; +import static grondag.canvas.wip.state.AbstractRenderStateView.TEXTURE; +import static grondag.canvas.wip.state.AbstractRenderStateView.TRANSLUCENT_CUTOUT; +import static grondag.canvas.wip.state.AbstractRenderStateView.TRANSPARENCY; +import static grondag.canvas.wip.state.AbstractRenderStateView.UNMIPPED; +import static grondag.canvas.wip.state.AbstractRenderStateView.WRITE_MASK; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.RenderLayer; @@ -60,6 +66,9 @@ public abstract class AbstractStateFinder, V extends AbstractRenderState> { protected long bits; + protected int vertexShaderIndex; + protected int fragmentShaderIndex; + public T reset() { bits = 0; vertexShader(WipShaderData.DEFAULT_VERTEX_SOURCE); @@ -138,18 +147,77 @@ public T fog(WipFog fog) { } public T vertexShader(Identifier vertexSource) { - bits = VERTEX_SHADER.setValue(WipMaterialShaderManager.vertexIndex.toHandle(vertexSource), bits); + vertexShaderIndex = WipMaterialShaderManager.vertexIndex.toHandle(vertexSource); return (T) this; } public T fragmentShader(Identifier fragmentSource) { - bits = FRAGMENT_SHADER.setValue(WipMaterialShaderManager.fragmentIndex.toHandle(fragmentSource), bits); + fragmentShaderIndex = WipMaterialShaderManager.fragmentIndex.toHandle(fragmentSource); + return (T) this; + } + + public T emissive(boolean emissive) { + bits = EMISSIVE.setValue(emissive, bits); + return (T) this; + } + + public T disableDiffuse(boolean disableDiffuse) { + bits = DISABLE_DIFFUSE.setValue(disableDiffuse, bits); + return (T) this; + } + + public T disableAo(boolean disableAo) { + bits = DISABLE_AO.setValue(disableAo, bits); + return (T) this; + } + + public T cutout(boolean cutout) { + bits = CUTOUT.setValue(cutout, bits); + return (T) this; + } + + public T unmipped(boolean unmipped) { + bits = UNMIPPED.setValue(unmipped, bits); + return (T) this; + } + + /** + * Sets cutout threshold to low value vs default of 50% + */ + public T translucentCutout(boolean translucentCutout) { + bits = TRANSLUCENT_CUTOUT.setValue(translucentCutout, bits); + return (T) this; + } + + /** + * Used in lieu of overlay texture. Displays red blended overlay color. + */ + public T hurtOverlay(boolean hurtOverlay) { + bits = HURT_OVERLAY.setValue(hurtOverlay, bits); + return (T) this; + } + + /** + * Used in lieu of overlay texture. Displays white blended overlay color. + */ + public T flashOverlay(boolean flashOverlay) { + bits = FLASH_OVERLAY.setValue(flashOverlay, bits); return (T) this; } protected abstract V missing(); - protected abstract V find(); + public V find() { + bits = SHADER.setValue(WipMaterialShaderManager.INSTANCE.find(vertexShaderIndex,fragmentShaderIndex, TRANSPARENCY.getValue(bits) == WipTransparency.TRANSLUCENT ? WipProgramType.MATERIAL_VERTEX_LOGIC : WipProgramType.MATERIAL_UNIFORM_LOGIC).index, bits); + return findInner(); + } + + public V fromBits(long bits) { + this.bits = bits; + return findInner(); + } + + protected abstract V findInner(); public V copyFromLayer(RenderLayer layer) { if (AbstractStateFinder.isExcluded(layer)) { @@ -170,15 +238,27 @@ public V copyFromLayer(RenderLayer layer) { target(WipTarget.fromPhase(params.getTarget())); lines(params.getLineWidth() != RenderPhase.FULL_LINE_WIDTH); fog(WipFog.fromPhase(params.getFog())); + unmipped(!tex.getMipmap()); + disableDiffuse(params.getDiffuseLighting() == RenderPhase.DISABLE_DIFFUSE_LIGHTING); + cutout(params.getAlpha() != RenderPhase.ZERO_ALPHA); + translucentCutout(params.getAlpha() == RenderPhase.ONE_TENTH_ALPHA); + disableAo(true); + + // WIP2: put in proper material map hooks + final String name = ((MultiPhaseExt) layer).canvas_name(); + emissive(name.equals("eyes") || name.equals("beacon_beam")); return find(); } + public T copyFrom(V template) { + this.bits = template.bits; + return (T) this; + } + private static final ReferenceOpenHashSet EXCLUSIONS = new ReferenceOpenHashSet<>(64, Hash.VERY_FAST_LOAD_FACTOR); static { - assert PACKER.bitLength() <= 56; // high eight bits saved for RenderMaterial aggregate - // entity shadows aren't worth EXCLUSIONS.add(((EntityRenderDispatcherExt) MinecraftClient.getInstance().getEntityRenderDispatcher()).canvas_shadowLayer()); diff --git a/src/main/java/grondag/canvas/wip/state/CollectorIndexMap.java b/src/main/java/grondag/canvas/wip/state/CollectorIndexMap.java new file mode 100644 index 000000000..16b0a5c50 --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/CollectorIndexMap.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019, 2020 grondag + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package grondag.canvas.wip.state; + +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.longs.Long2IntFunction; +import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; + +public class CollectorIndexMap { + public static final int MAX_COLLECTOR_COUNT = 4096; + static int nextIndex = 0; + + private static final long[] KEYS_BY_INDEX = new long[MAX_COLLECTOR_COUNT]; + private static final WipRenderState[] RENDER_STATES = new WipRenderState[MAX_COLLECTOR_COUNT]; + static final Long2IntOpenHashMap MAP = new Long2IntOpenHashMap(256, Hash.VERY_FAST_LOAD_FACTOR); + + private static final Long2IntFunction FUNC = key -> { + final int result = nextIndex++; + RENDER_STATES[result] = WipRenderStateFinder.threadLocal().fromBits(key); + KEYS_BY_INDEX[result] = key; + return result; + }; + + public static synchronized int indexFromKey(long collectorKey) { + return MAP.computeIfAbsent(collectorKey, FUNC); + } + + public static long keyFromIndex(int index) { + return KEYS_BY_INDEX[index]; + } + + public static WipRenderState renderStateForIndex(int index) { + return RENDER_STATES[index]; + } +} diff --git a/src/main/java/grondag/canvas/wip/state/RenderStateData.java b/src/main/java/grondag/canvas/wip/state/RenderStateData.java new file mode 100644 index 000000000..ff6892f5b --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/RenderStateData.java @@ -0,0 +1,24 @@ +/* + * Copyright 2019, 2020 grondag + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package grondag.canvas.wip.state; + +public class RenderStateData { + private RenderStateData() {} + + public static final int HURT_OVERLAY_FLAG = (int) (AbstractRenderStateView.HURT_OVERLAY_FLAG << 24); + public static final int FLASH_OVERLAY_FLAG = (int) (AbstractRenderStateView.FLASH_OVERLAY_FLAG << 24); +} diff --git a/src/main/java/grondag/canvas/wip/state/WipRenderMaterial.java b/src/main/java/grondag/canvas/wip/state/WipRenderMaterial.java new file mode 100644 index 000000000..113b85980 --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/WipRenderMaterial.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019, 2020 grondag + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package grondag.canvas.wip.state; + +import grondag.frex.api.material.RenderMaterial; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; + + +public final class WipRenderMaterial extends AbstractRenderState implements RenderMaterial { + public final int collectorIndex; + public final WipRenderState renderState; + public final int shaderFlags; + + WipRenderMaterial(long bits) { + super(nextIndex++, bits); + collectorIndex = CollectorIndexMap.indexFromKey(collectorKey()); + renderState = CollectorIndexMap.renderStateForIndex(collectorIndex); + shaderFlags = shaderFlags(); + } + + private static ThreadLocal FINDER = ThreadLocal.withInitial(WipRenderMaterialFinder::new); + + public static WipRenderMaterialFinder finder() { + final WipRenderMaterialFinder result = FINDER.get(); + result.reset(); + return result; + } + + static int nextIndex = 0; + static final ObjectArrayList LIST = new ObjectArrayList<>(); + static final Long2ObjectOpenHashMap MAP = new Long2ObjectOpenHashMap<>(4096, Hash.VERY_FAST_LOAD_FACTOR); + + public static final WipRenderMaterial MISSING = new WipRenderMaterial(0); + + static { + LIST.add(MISSING); + } + + public static WipRenderMaterial fromIndex(int index) { + return LIST.get(index); + } +} diff --git a/src/main/java/grondag/canvas/wip/state/WipRenderMaterialFinder.java b/src/main/java/grondag/canvas/wip/state/WipRenderMaterialFinder.java new file mode 100644 index 000000000..cb14c8dbb --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/WipRenderMaterialFinder.java @@ -0,0 +1,32 @@ +package grondag.canvas.wip.state; + + +public class WipRenderMaterialFinder extends AbstractStateFinder { + @Override + protected synchronized WipRenderMaterial findInner() { + WipRenderMaterial result = WipRenderMaterial.MAP.get(bits); + + if (result == null) { + result = new WipRenderMaterial(bits); + WipRenderMaterial.MAP.put(bits, result); + WipRenderMaterial.LIST.add(result); + } + + return result; + } + + @Override + protected WipRenderMaterial missing() { + return WipRenderMaterial.MISSING; + } + + private static ThreadLocal FINDER = ThreadLocal.withInitial(WipRenderMaterialFinder::new); + + public static WipRenderMaterialFinder threadLocal() { + final WipRenderMaterialFinder result = FINDER.get(); + result.reset(); + return result; + } + + +} \ No newline at end of file diff --git a/src/main/java/grondag/canvas/wip/state/WipRenderState.java b/src/main/java/grondag/canvas/wip/state/WipRenderState.java index 504206845..0269667a2 100644 --- a/src/main/java/grondag/canvas/wip/state/WipRenderState.java +++ b/src/main/java/grondag/canvas/wip/state/WipRenderState.java @@ -119,7 +119,7 @@ public static void disable() { public static final int MAX_COUNT = 4096; static int nextIndex = 0; static final WipRenderState[] STATES = new WipRenderState[MAX_COUNT]; - private static final Long2ObjectOpenHashMap MAP = new Long2ObjectOpenHashMap<>(4096, Hash.VERY_FAST_LOAD_FACTOR); + static final Long2ObjectOpenHashMap MAP = new Long2ObjectOpenHashMap<>(4096, Hash.VERY_FAST_LOAD_FACTOR); public static final WipRenderState MISSING = new WipRenderState(0); @@ -130,32 +130,4 @@ public static void disable() { public static WipRenderState fromIndex(int index) { return STATES[index]; } - - private static ThreadLocal FINDER = ThreadLocal.withInitial(Finder::new); - - public static Finder finder() { - final Finder result = FINDER.get(); - result.reset(); - return result; - } - - public static class Finder extends AbstractStateFinder{ - @Override - public synchronized WipRenderState find() { - WipRenderState result = MAP.get(bits); - - if (result == null) { - result = new WipRenderState(bits); - MAP.put(bits, result); - STATES[result.index] = result; - } - - return result; - } - - @Override - protected WipRenderState missing() { - return MISSING; - } - } } diff --git a/src/main/java/grondag/canvas/wip/state/WipRenderStateFinder.java b/src/main/java/grondag/canvas/wip/state/WipRenderStateFinder.java new file mode 100644 index 000000000..29cfdcd32 --- /dev/null +++ b/src/main/java/grondag/canvas/wip/state/WipRenderStateFinder.java @@ -0,0 +1,30 @@ +package grondag.canvas.wip.state; + + +public class WipRenderStateFinder extends AbstractStateFinder{ + @Override + public synchronized WipRenderState findInner() { + WipRenderState result = WipRenderState.MAP.get(bits); + + if (result == null) { + result = new WipRenderState(bits); + WipRenderState.MAP.put(bits, result); + WipRenderState.STATES[result.index] = result; + } + + return result; + } + + @Override + protected WipRenderState missing() { + return WipRenderState.MISSING; + } + + private static ThreadLocal FINDER = ThreadLocal.withInitial(WipRenderStateFinder::new); + + public static WipRenderStateFinder threadLocal() { + final WipRenderStateFinder result = FINDER.get(); + result.reset(); + return result; + } +} \ No newline at end of file diff --git a/src/main/java/grondag/canvas/wip/state/WipVertexState.java b/src/main/java/grondag/canvas/wip/state/WipVertexState.java deleted file mode 100644 index 0f2054c81..000000000 --- a/src/main/java/grondag/canvas/wip/state/WipVertexState.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2019, 2020 grondag - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package grondag.canvas.wip.state; - -import grondag.canvas.apiimpl.MaterialConditionImpl; -import grondag.canvas.mixin.AccessMultiPhaseParameters; -import grondag.canvas.mixin.AccessTexture; -import grondag.canvas.mixinterface.MultiPhaseExt; -import grondag.fermion.bits.BitPacker32; -import grondag.fermion.bits.BitPacker32.BooleanElement; -import grondag.fermion.bits.BitPacker32.IntElement; - -import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.render.RenderPhase; - -/** - * Encapsulates material state conveyed via vertex attributes. - */ -@SuppressWarnings("rawtypes") -public class WipVertexState { - private WipVertexState() { } - - private static final BitPacker32 PACKER = new BitPacker32<>(null, null); - public static final int STATE_COUNT = 1 << PACKER.bitLength(); - // first 16 bits correspond to shader flag bits - private static final BooleanElement EMISSIVE = PACKER.createBooleanElement(); - private static final BooleanElement DISABLE_DIFFUSE = PACKER.createBooleanElement(); - private static final BooleanElement DISABLE_AO = PACKER.createBooleanElement(); - private static final BooleanElement CUTOUT = PACKER.createBooleanElement(); - private static final BooleanElement UNMIPPED = PACKER.createBooleanElement(); - - // true = 10%, false = 50% - private static final BooleanElement TRANSLUCENT_CUTOUT = PACKER.createBooleanElement(); - private static final BooleanElement HURT_OVERLAY = PACKER.createBooleanElement(); - private static final BooleanElement FLASH_OVERLAY = PACKER.createBooleanElement(); - - public static final int HURT_OVERLAY_FLAG = HURT_OVERLAY.comparisonMask() << 24; - public static final int FLASH_OVERLAY_FLAG = FLASH_OVERLAY.comparisonMask() << 24; - - private static final IntElement CONDITION = PACKER.createIntElement(MaterialConditionImpl.MAX_CONDITIONS); - - static { - assert MaterialConditionImpl.ALWAYS.index == 0; - } - - public static boolean emissive(int vertexState) { - return EMISSIVE.getValue(vertexState); - } - - public static boolean disableDiffuse(int vertexState) { - return DISABLE_DIFFUSE.getValue(vertexState); - } - - public static boolean disableAo(int vertexState) { - return DISABLE_AO.getValue(vertexState); - } - - public static boolean cutout(int vertexState) { - return CUTOUT.getValue(vertexState); - } - - public static boolean unmipped(int vertexState) { - return UNMIPPED.getValue(vertexState); - } - - public static boolean translucentCutout(int vertexState) { - return TRANSLUCENT_CUTOUT.getValue(vertexState); - } - - public static boolean hurtOverlay(int vertexState) { - return HURT_OVERLAY.getValue(vertexState); - } - - public static boolean flashOverlay(int vertexState) { - return FLASH_OVERLAY.getValue(vertexState); - } - - public static MaterialConditionImpl condition(int vertexState) { - return MaterialConditionImpl.fromIndex(CONDITION.getValue(vertexState)); - } - - public static int conditionIndex(int vertexState) { - return CONDITION.getValue(vertexState); - } - - public static int shaderFlags(int vertexState) { - return vertexState & 0xFF; - } - - public static class Finder { - private int vertexState = 0; - - public Finder() { - reset(); - } - - public Finder reset() { - vertexState = 0; - return this; - } - - /** - * Note sets Ao disabled by default - non-terrain layers can't/won't use it. - */ - public Finder copyFromLayer(RenderLayer layer) { - final MultiPhaseExt ext = (MultiPhaseExt) layer; - - final String name = ext.canvas_name(); - final AccessMultiPhaseParameters params = ext.canvas_phases(); - final AccessTexture tex = (AccessTexture) params.getTexture(); - unmipped(!tex.getMipmap()); - disableDiffuse(params.getDiffuseLighting() == RenderPhase.DISABLE_DIFFUSE_LIGHTING); - cutout(params.getAlpha() != RenderPhase.ZERO_ALPHA); - translucentCutout(params.getAlpha() == RenderPhase.ONE_TENTH_ALPHA); - disableAo(true); - - // WIP2: put in proper material map hooks - emissive(name.equals("eyes") || name.equals("beacon_beam")); - return this; - } - - public Finder emissive(boolean emissive) { - vertexState = EMISSIVE.setValue(emissive, vertexState); - return this; - } - - public Finder disableDiffuse(boolean disableDiffuse) { - vertexState = DISABLE_DIFFUSE.setValue(disableDiffuse, vertexState); - return this; - } - - public Finder disableAo(boolean disableAo) { - vertexState = DISABLE_AO.setValue(disableAo, vertexState); - return this; - } - - public Finder cutout(boolean cutout) { - vertexState = CUTOUT.setValue(cutout, vertexState); - return this; - } - - public Finder unmipped(boolean unmipped) { - vertexState = UNMIPPED.setValue(unmipped, vertexState); - return this; - } - - /** - * Sets cutout threshold to low value vs default of 50% - */ - public Finder translucentCutout(boolean translucentCutout) { - vertexState = TRANSLUCENT_CUTOUT.setValue(translucentCutout, vertexState); - return this; - } - - /** - * Used in lieu of overlay texture. Displays red blended overlay color. - */ - public Finder hurtOverlay(boolean hurtOverlay) { - vertexState = HURT_OVERLAY.setValue(hurtOverlay, vertexState); - return this; - } - - /** - * Used in lieu of overlay texture. Displays white blended overlay color. - */ - public Finder flashOverlay(boolean flashOverlay) { - vertexState = FLASH_OVERLAY.setValue(flashOverlay, vertexState); - return this; - } - - public int find() { - return vertexState; - } - - public Finder condition(MaterialConditionImpl condition) { - vertexState = CONDITION.setValue(condition.index, vertexState); - return this; - } - } - - private static ThreadLocal FINDER = ThreadLocal.withInitial(Finder::new); - - public static Finder finder() { - final Finder result = FINDER.get(); - return result.reset(); - } -}