Rendering refactors

- Fix fluid rendering in JEI scenes
- Add more separate options to SuperByteBuffer
- Fix copper backtank diffuse when worn
- Fix enchantment glint on custom rendered items; Closes #1846
This commit is contained in:
PepperBell 2021-07-03 01:03:37 -07:00
parent ccbb57f518
commit b5c0684dd6
7 changed files with 204 additions and 142 deletions

View file

@ -15,6 +15,7 @@ import net.minecraft.block.BlockState;
import net.minecraft.client.MainWindow; import net.minecraft.client.MainWindow;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.entity.player.ClientPlayerEntity;
import net.minecraft.client.renderer.Atlases;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.IRenderTypeBuffer.Impl; import net.minecraft.client.renderer.IRenderTypeBuffer.Impl;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
@ -60,7 +61,7 @@ public class CopperBacktankArmorLayer<T extends LivingEntity, M extends EntityMo
BipedModel<?> model = (BipedModel<?>) entityModel; BipedModel<?> model = (BipedModel<?>) entityModel;
BlockState renderedState = AllBlocks.COPPER_BACKTANK.getDefaultState() BlockState renderedState = AllBlocks.COPPER_BACKTANK.getDefaultState()
.with(CopperBacktankBlock.HORIZONTAL_FACING, Direction.SOUTH); .with(CopperBacktankBlock.HORIZONTAL_FACING, Direction.SOUTH);
RenderType renderType = RenderType.getCutout(); RenderType renderType = Atlases.getEntityCutout();
SuperByteBuffer backtank = CreateClient.BUFFER_CACHE.renderBlock(renderedState); SuperByteBuffer backtank = CreateClient.BUFFER_CACHE.renderBlock(renderedState);
SuperByteBuffer cogs = SuperByteBuffer cogs =
@ -69,8 +70,9 @@ public class CopperBacktankArmorLayer<T extends LivingEntity, M extends EntityMo
model.bipedBody.rotate(ms); model.bipedBody.rotate(ms);
ms.translate(-1 / 2f, 10 / 16f, 1f); ms.translate(-1 / 2f, 10 / 16f, 1f);
ms.scale(1, -1, -1); ms.scale(1, -1, -1);
backtank.light(light) backtank.forEntityRender()
.renderInto(ms, buffer.getBuffer(renderType)); .light(light)
.renderInto(ms, buffer.getBuffer(renderType));
cogs.matrixStacker() cogs.matrixStacker()
.centre() .centre()
@ -80,13 +82,11 @@ public class CopperBacktankArmorLayer<T extends LivingEntity, M extends EntityMo
.rotate(Direction.EAST, AngleHelper.rad(2 * AnimationTickHolder.getRenderTime(entity.world) % 360)) .rotate(Direction.EAST, AngleHelper.rad(2 * AnimationTickHolder.getRenderTime(entity.world) % 360))
.translate(0, -6.5f / 16, -11f / 16); .translate(0, -6.5f / 16, -11f / 16);
cogs.light(light) cogs.forEntityRender()
.light(light)
.renderInto(ms, buffer.getBuffer(renderType)); .renderInto(ms, buffer.getBuffer(renderType));
if (buffer instanceof Impl)
((Impl) buffer).draw(renderType);
ms.pop(); ms.pop();
} }
public static void register() { public static void register() {

View file

@ -11,14 +11,12 @@ import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Atlases;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -26,17 +24,16 @@ import net.minecraft.util.math.vector.Matrix3f;
public class BlueprintRenderer extends EntityRenderer<BlueprintEntity> { public class BlueprintRenderer extends EntityRenderer<BlueprintEntity> {
public BlueprintRenderer(EntityRendererManager p_i46179_1_) { public BlueprintRenderer(EntityRendererManager manager) {
super(p_i46179_1_); super(manager);
} }
@Override @Override
public void render(BlueprintEntity entity, float yaw, float pt, MatrixStack ms, IRenderTypeBuffer buffer, public void render(BlueprintEntity entity, float yaw, float pt, MatrixStack ms, IRenderTypeBuffer buffer,
int overlay) { int light) {
PartialModel partialModel = entity.size == 3 ? AllBlockPartials.CRAFTING_BLUEPRINT_3x3 PartialModel partialModel = entity.size == 3 ? AllBlockPartials.CRAFTING_BLUEPRINT_3x3
: entity.size == 2 ? AllBlockPartials.CRAFTING_BLUEPRINT_2x2 : AllBlockPartials.CRAFTING_BLUEPRINT_1x1; : entity.size == 2 ? AllBlockPartials.CRAFTING_BLUEPRINT_2x2 : AllBlockPartials.CRAFTING_BLUEPRINT_1x1;
SuperByteBuffer sbb = PartialBufferer.get(partialModel, Blocks.AIR.getDefaultState()); SuperByteBuffer sbb = PartialBufferer.get(partialModel, Blocks.AIR.getDefaultState());
int light = WorldRenderer.getLightmapCoordinates(entity.world, entity.getBlockPos());
sbb.matrixStacker() sbb.matrixStacker()
.rotateY(-yaw) .rotateY(-yaw)
.rotateX(90.0F + entity.rotationPitch) .rotateX(90.0F + entity.rotationPitch)
@ -44,10 +41,9 @@ public class BlueprintRenderer extends EntityRenderer<BlueprintEntity> {
if (entity.size == 2) if (entity.size == 2)
sbb.translate(.5, 0, -.5); sbb.translate(.5, 0, -.5);
RenderType entitySolid = RenderType.getEntitySolid(PlayerContainer.BLOCK_ATLAS_TEXTURE); sbb.forEntityRender()
sbb.asEntityModel()
.light(light) .light(light)
.renderInto(ms, buffer.getBuffer(entitySolid)); .renderInto(ms, buffer.getBuffer(Atlases.getEntitySolid()));
super.render(entity, yaw, pt, ms, buffer, light); super.render(entity, yaw, pt, ms, buffer, light);
ms.push(); ms.push();

View file

@ -2,20 +2,18 @@ package com.simibubi.create.foundation.fluid;
import java.util.function.Function; import java.util.function.Function;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.matrix.MatrixStack.Entry; import com.mojang.blaze3d.matrix.MatrixStack.Entry;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.renderState.RenderTypes;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.ColorHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.inventory.container.PlayerContainer;
@ -28,42 +26,23 @@ import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i; import net.minecraft.util.math.vector.Vector3i;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fluids.FluidAttributes; import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.Mod;
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
@Mod.EventBusSubscriber(Dist.CLIENT)
public class FluidRenderer { public class FluidRenderer {
// If we draw to BufferBuilder that minecraft provides for RenderType.getTranslucent(), minecraft draws the contents public static IVertexBuilder getFluidBuilder(IRenderTypeBuffer buffer) {
// to the wrong framebuffer. If we tried to inject a custom RenderType into RenderTypeBuffers, we'd have the same return buffer.getBuffer(RenderTypes.getFluid());
// issue. This is because minecraft calls IRenderTypeBuffer.Impl::draw just before clearing the transparency
// framebuffer, so anything we put into the normal RenderTypeBuffers will never be seen. By using our own
// BufferBuilder, we can avoid getting our contents wiped. Then, using Flywheel's renderLayer hook, we can draw our
// buffer at the same time the transparent world layer is drawn.
private static final BufferBuilder _builder = new BufferBuilder(RenderType.getTranslucent().getExpectedBufferSize());
private static BufferBuilder getBuilder() {
if (!_builder.isBuilding()) {
RenderType type = RenderType.getTranslucent();
_builder.begin(type.getDrawMode(), type.getVertexFormat());
}
return _builder;
}
@SubscribeEvent
public static void renderLayer(RenderLayerEvent event) {
if (event.type == RenderType.getTranslucent()) {
event.type.draw(_builder, 0, 0, 0);
}
} }
public static void renderFluidStream(FluidStack fluidStack, Direction direction, float radius, float progress, public static void renderFluidStream(FluidStack fluidStack, Direction direction, float radius, float progress,
boolean inbound, IRenderTypeBuffer buffer, MatrixStack ms, int light) { boolean inbound, IRenderTypeBuffer buffer, MatrixStack ms, int light) {
renderFluidStream(fluidStack, direction, radius, progress, inbound, getFluidBuilder(buffer), ms, light);
}
public static void renderFluidStream(FluidStack fluidStack, Direction direction, float radius, float progress,
boolean inbound, IVertexBuilder builder, MatrixStack ms, int light) {
Fluid fluid = fluidStack.getFluid(); Fluid fluid = fluidStack.getFluid();
FluidAttributes fluidAttributes = fluid.getAttributes(); FluidAttributes fluidAttributes = fluid.getAttributes();
Function<ResourceLocation, TextureAtlasSprite> spriteAtlas = Minecraft.getInstance() Function<ResourceLocation, TextureAtlasSprite> spriteAtlas = Minecraft.getInstance()
@ -72,18 +51,14 @@ public class FluidRenderer {
TextureAtlasSprite stillTexture = spriteAtlas.apply(fluidAttributes.getStillTexture(fluidStack)); TextureAtlasSprite stillTexture = spriteAtlas.apply(fluidAttributes.getStillTexture(fluidStack));
int color = fluidAttributes.getColor(fluidStack); int color = fluidAttributes.getColor(fluidStack);
IVertexBuilder builder = getBuilder(); int blockLightIn = (light >> 4) & 0xF;
if (buffer instanceof SuperRenderTypeBuffer)
builder = ((SuperRenderTypeBuffer) buffer).getLateBuffer(RenderType.getTranslucent());
MatrixStacker msr = MatrixStacker.of(ms);
int blockLightIn = (light >> 4) & 0xf;
int luminosity = Math.max(blockLightIn, fluidAttributes.getLuminosity(fluidStack)); int luminosity = Math.max(blockLightIn, fluidAttributes.getLuminosity(fluidStack));
light = (light & 0xf00000) | luminosity << 4; light = (light & 0xF00000) | luminosity << 4;
if (inbound) if (inbound)
direction = direction.getOpposite(); direction = direction.getOpposite();
MatrixStacker msr = MatrixStacker.of(ms);
ms.push(); ms.push();
msr.centre() msr.centre()
.rotateY(AngleHelper.horizontalAngle(direction)) .rotateY(AngleHelper.horizontalAngle(direction))
@ -111,11 +86,15 @@ public class FluidRenderer {
stillTexture); stillTexture);
ms.pop(); ms.pop();
} }
public static void renderTiledFluidBB(FluidStack fluidStack, float xMin, float yMin, float zMin, float xMax, public static void renderTiledFluidBB(FluidStack fluidStack, float xMin, float yMin, float zMin, float xMax,
float yMax, float zMax, IRenderTypeBuffer buffer, MatrixStack ms, int light, boolean renderBottom) { float yMax, float zMax, IRenderTypeBuffer buffer, MatrixStack ms, int light, boolean renderBottom) {
renderTiledFluidBB(fluidStack, xMin, yMin, zMin, xMax, yMax, zMax, getFluidBuilder(buffer), ms, light, renderBottom);
}
public static void renderTiledFluidBB(FluidStack fluidStack, float xMin, float yMin, float zMin, float xMax,
float yMax, float zMax, IVertexBuilder builder, MatrixStack ms, int light, boolean renderBottom) {
Fluid fluid = fluidStack.getFluid(); Fluid fluid = fluidStack.getFluid();
FluidAttributes fluidAttributes = fluid.getAttributes(); FluidAttributes fluidAttributes = fluid.getAttributes();
TextureAtlasSprite fluidTexture = Minecraft.getInstance() TextureAtlasSprite fluidTexture = Minecraft.getInstance()
@ -123,16 +102,12 @@ public class FluidRenderer {
.apply(fluidAttributes.getStillTexture(fluidStack)); .apply(fluidAttributes.getStillTexture(fluidStack));
int color = fluidAttributes.getColor(fluidStack); int color = fluidAttributes.getColor(fluidStack);
IVertexBuilder builder = getBuilder(); int blockLightIn = (light >> 4) & 0xF;
if (buffer instanceof SuperRenderTypeBuffer)
builder = ((SuperRenderTypeBuffer) buffer).getLateBuffer(RenderType.getTranslucent());
MatrixStacker msr = MatrixStacker.of(ms);
Vector3d center = new Vector3d(xMin + (xMax - xMin) / 2, yMin + (yMax - yMin) / 2, zMin + (zMax - zMin) / 2);
int blockLightIn = (light >> 4) & 0xf;
int luminosity = Math.max(blockLightIn, fluidAttributes.getLuminosity(fluidStack)); int luminosity = Math.max(blockLightIn, fluidAttributes.getLuminosity(fluidStack));
light = (light & 0xf00000) | luminosity << 4; light = (light & 0xF00000) | luminosity << 4;
Vector3d center = new Vector3d(xMin + (xMax - xMin) / 2, yMin + (yMax - yMin) / 2, zMin + (zMax - zMin) / 2);
MatrixStacker msr = MatrixStacker.of(ms);
ms.push(); ms.push();
if (fluidStack.getFluid() if (fluidStack.getFluid()
.getAttributes() .getAttributes()
@ -245,6 +220,7 @@ public class FluidRenderer {
builder.vertex(peek.getModel(), x, y, z) builder.vertex(peek.getModel(), x, y, z)
.color(r, g, b, a) .color(r, g, b, a)
.texture(u, v) .texture(u, v)
.overlay(OverlayTexture.DEFAULT_UV)
.light(light) .light(light)
.normal(n.getX(), n.getY(), n.getZ()) .normal(n.getX(), n.getY(), n.getZ())
.endVertex(); .endVertex();

View file

@ -158,12 +158,12 @@ public class GuiGameElement {
private static class GuiBlockModelRenderBuilder extends GuiRenderBuilder { private static class GuiBlockModelRenderBuilder extends GuiRenderBuilder {
protected IBakedModel blockmodel; protected IBakedModel blockModel;
protected BlockState blockState; protected BlockState blockState;
public GuiBlockModelRenderBuilder(IBakedModel blockmodel, @Nullable BlockState blockState) { public GuiBlockModelRenderBuilder(IBakedModel blockmodel, @Nullable BlockState blockState) {
this.blockState = blockState == null ? Blocks.AIR.getDefaultState() : blockState; this.blockState = blockState == null ? Blocks.AIR.getDefaultState() : blockState;
this.blockmodel = blockmodel; this.blockModel = blockmodel;
} }
@Override @Override
@ -194,7 +194,7 @@ public class GuiGameElement {
.getColor(blockState, null, null, 0); .getColor(blockState, null, null, 0);
Vector3d rgb = ColorHelper.getRGB(color == -1 ? this.color : color); Vector3d rgb = ColorHelper.getRGB(color == -1 ? this.color : color);
blockRenderer.getBlockModelRenderer() blockRenderer.getBlockModelRenderer()
.renderModel(ms.peek(), vb, blockState, blockmodel, (float) rgb.x, (float) rgb.y, (float) rgb.z, .renderModel(ms.peek(), vb, blockState, blockModel, (float) rgb.x, (float) rgb.y, (float) rgb.z,
0xF000F0, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE); 0xF000F0, OverlayTexture.DEFAULT_UV, VirtualEmptyModelData.INSTANCE);
buffer.draw(); buffer.draw();
} }
@ -227,13 +227,9 @@ public class GuiGameElement {
.isEmpty()) .isEmpty())
return; return;
ms.push();
RenderHelper.disableStandardItemLighting();
FluidRenderer.renderTiledFluidBB(new FluidStack(blockState.getFluidState() FluidRenderer.renderTiledFluidBB(new FluidStack(blockState.getFluidState()
.getFluid(), 1000), 0, 0, 0, 1.0001f, 1.0001f, 1.0001f, buffer, ms, 0xF000F0, true); .getFluid(), 1000), 0, 0, 0, 1.0001f, 1.0001f, 1.0001f, buffer, ms, 0xF000F0, false);
buffer.draw(RenderType.getTranslucent()); buffer.draw();
RenderHelper.enable();
ms.pop();
} }
} }

View file

@ -70,7 +70,7 @@ public class PartialItemModelRenderer {
if (!model.isBuiltInRenderer()) if (!model.isBuiltInRenderer())
renderBakedItemModel(model, light, ms, renderBakedItemModel(model, light, ms,
ItemRenderer.getArmorVertexConsumer(buffer, type, true, stack.hasEffect())); ItemRenderer.getDirectGlintVertexConsumer(buffer, type, true, stack.hasEffect()));
else else
stack.getItem() stack.getItem()
.getItemStackTileEntityRenderer() .getItemStackTileEntityRenderer()

View file

@ -16,6 +16,7 @@ import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix3f; import net.minecraft.util.math.vector.Matrix3f;
import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Quaternion; import net.minecraft.util.math.vector.Quaternion;
@ -32,13 +33,18 @@ public class SuperByteBuffer {
// Vertex Position // Vertex Position
private MatrixStack transforms; private MatrixStack transforms;
// Vertex Texture Coords
private SpriteShiftFunc spriteShiftFunc;
private boolean isEntityModel;
// Vertex Coloring // Vertex Coloring
private boolean shouldColor; private boolean shouldColor;
private int r, g, b, a; private int r, g, b, a;
private boolean disableDiffuseDiv;
private boolean disableDiffuseMult;
// Vertex Texture Coords
private SpriteShiftFunc spriteShiftFunc;
// Vertex Overlay Color
private boolean hasOverlay;
private int overlay = OverlayTexture.DEFAULT_UV;;
// Vertex Lighting // Vertex Lighting
private boolean useWorldLight; private boolean useWorldLight;
@ -46,6 +52,15 @@ public class SuperByteBuffer {
private int packedLightCoords; private int packedLightCoords;
private Matrix4f lightTransform; private Matrix4f lightTransform;
// Vertex Normals
private boolean fullNormalTransform;
// Temporary
private static final Long2IntMap WORLD_LIGHT_CACHE = new Long2IntOpenHashMap();
private final Vector4f pos = new Vector4f();
private final Vector3f normal = new Vector3f();
private final Vector4f lightPos = new Vector4f();
public SuperByteBuffer(BufferBuilder buf) { public SuperByteBuffer(BufferBuilder buf) {
template = new BufferBuilderReader(buf); template = new BufferBuilderReader(buf);
transforms = new MatrixStack(); transforms = new MatrixStack();
@ -61,27 +76,26 @@ public class SuperByteBuffer {
return (v - sprite.getMinV()) / f * 16.0F; return (v - sprite.getMinV()) / f * 16.0F;
} }
private static final Long2IntMap WORLD_LIGHT_CACHE = new Long2IntOpenHashMap();
Vector4f pos = new Vector4f();
Vector3f normal = new Vector3f();
Vector4f lightPos = new Vector4f();
public void renderInto(MatrixStack input, IVertexBuilder builder) { public void renderInto(MatrixStack input, IVertexBuilder builder) {
if (isEmpty()) if (isEmpty())
return; return;
Matrix3f normalMat = transforms.peek()
.getNormal()
.copy();
Matrix4f modelMat = input.peek() Matrix4f modelMat = input.peek()
.getModel() .getModel()
.copy(); .copy();
Matrix4f localTransforms = transforms.peek() Matrix4f localTransforms = transforms.peek()
.getModel(); .getModel();
modelMat.multiply(localTransforms); modelMat.multiply(localTransforms);
Matrix3f normalMat;
if (fullNormalTransform) {
normalMat = input.peek().getNormal().copy();
Matrix3f localNormalTransforms = transforms.peek().getNormal();
normalMat.multiply(localNormalTransforms);
} else {
normalMat = transforms.peek().getNormal().copy();
}
if (useWorldLight) { if (useWorldLight) {
WORLD_LIGHT_CACHE.clear(); WORLD_LIGHT_CACHE.clear();
} }
@ -101,43 +115,58 @@ public class SuperByteBuffer {
float normalY = template.getNY(i) / 127f; float normalY = template.getNY(i) / 127f;
float normalZ = template.getNZ(i) / 127f; float normalZ = template.getNZ(i) / 127f;
float staticDiffuse = LightUtil.diffuseLight(normalX, normalY, normalZ);
normal.set(normalX, normalY, normalZ); normal.set(normalX, normalY, normalZ);
normal.transform(normalMat); normal.transform(normalMat);
float nx = normal.getX(); float nx = normal.getX();
float ny = normal.getY(); float ny = normal.getY();
float nz = normal.getZ(); float nz = normal.getZ();
float staticDiffuse = LightUtil.diffuseLight(normalX, normalY, normalZ);
float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz); float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz);
pos.set(x, y, z, 1F); pos.set(x, y, z, 1F);
pos.transform(modelMat); pos.transform(modelMat);
builder.vertex(pos.getX(), pos.getY(), pos.getZ()); builder.vertex(pos.getX(), pos.getY(), pos.getZ());
if (isEntityModel) { if (shouldColor) {
builder.color(255, 255, 255, 255); if (disableDiffuseMult) {
} else if (shouldColor) { builder.color(this.r, this.g, this.b, this.a);
int colorR = Math.min(255, (int) (((float) this.r) * instanceDiffuse)); } else {
int colorG = Math.min(255, (int) (((float) this.g) * instanceDiffuse)); int colorR = transformColor(this.r, instanceDiffuse);
int colorB = Math.min(255, (int) (((float) this.b) * instanceDiffuse)); int colorG = transformColor(this.g, instanceDiffuse);
builder.color(colorR, colorG, colorB, this.a); int colorB = transformColor(this.b, instanceDiffuse);
builder.color(colorR, colorG, colorB, this.a);
}
} else { } else {
float diffuseMult = instanceDiffuse / staticDiffuse; if (disableDiffuseDiv && disableDiffuseMult) {
int colorR = Math.min(255, (int) (((float) Byte.toUnsignedInt(r)) * diffuseMult)); builder.color(r, g, b, a);
int colorG = Math.min(255, (int) (((float) Byte.toUnsignedInt(g)) * diffuseMult)); } else {
int colorB = Math.min(255, (int) (((float) Byte.toUnsignedInt(b)) * diffuseMult)); float diffuseMult;
builder.color(colorR, colorG, colorB, a); if (disableDiffuseDiv) {
diffuseMult = instanceDiffuse;
} else if (disableDiffuseMult) {
diffuseMult = 1 / staticDiffuse;
} else {
diffuseMult = instanceDiffuse / staticDiffuse;
}
int colorR = transformColor(r, diffuseMult);
int colorG = transformColor(g, diffuseMult);
int colorB = transformColor(b, diffuseMult);
builder.color(colorR, colorG, colorB, a);
}
} }
float u = template.getU(i); float u = template.getU(i);
float v = template.getV(i); float v = template.getV(i);
if (spriteShiftFunc != null) { if (spriteShiftFunc != null) {
spriteShiftFunc.shift(builder, u, v); spriteShiftFunc.shift(builder, u, v);
} else } else {
builder.texture(u, v); builder.texture(u, v);
}
if (isEntityModel) if (hasOverlay) {
builder.overlay(OverlayTexture.DEFAULT_UV); builder.overlay(overlay);
}
int light; int light;
if (useWorldLight) { if (useWorldLight) {
@ -163,10 +192,8 @@ public class SuperByteBuffer {
builder.light(light); builder.light(light);
} }
if (isEntityModel) builder.normal(nx, ny, nz);
builder.normal(input.peek().getNormal(), nx, ny, nz);
else
builder.normal(nx, ny, nz);
builder.endVertex(); builder.endVertex();
} }
@ -175,17 +202,21 @@ public class SuperByteBuffer {
public SuperByteBuffer reset() { public SuperByteBuffer reset() {
transforms = new MatrixStack(); transforms = new MatrixStack();
spriteShiftFunc = null;
shouldColor = false; shouldColor = false;
isEntityModel = false;
r = 0; r = 0;
g = 0; g = 0;
b = 0; b = 0;
a = 0; a = 0;
disableDiffuseDiv = false;
disableDiffuseMult = false;
spriteShiftFunc = null;
hasOverlay = false;
overlay = OverlayTexture.DEFAULT_UV;
useWorldLight = false; useWorldLight = false;
hybridLight = false; hybridLight = false;
packedLightCoords = 0; packedLightCoords = 0;
lightTransform = null; lightTransform = null;
fullNormalTransform = false;
return this; return this;
} }
@ -241,6 +272,15 @@ public class SuperByteBuffer {
.translate(-.5f, -.5f, -.5f); .translate(-.5f, -.5f, -.5f);
} }
public SuperByteBuffer color(int r, int g, int b, int a) {
shouldColor = true;
this.r = r;
this.g = g;
this.b = b;
this.a = a;
return this;
}
public SuperByteBuffer color(int color) { public SuperByteBuffer color(int color) {
shouldColor = true; shouldColor = true;
r = ((color >> 16) & 0xFF); r = ((color >> 16) & 0xFF);
@ -250,6 +290,25 @@ public class SuperByteBuffer {
return this; return this;
} }
/**
* Prevents vertex colors from being divided by the diffuse value calculated from the raw untransformed normal vector.
* Useful when passed vertex colors do not have diffuse baked in.
* Disabled when custom color is used.
*/
public SuperByteBuffer disableDiffuseDiv() {
disableDiffuseDiv = true;
return this;
}
/**
* Prevents vertex colors from being multiplied by the diffuse value calculated from the final transformed normal vector.
* Useful for entity rendering, when diffuse is applied automatically later.
*/
public SuperByteBuffer disableDiffuseMult() {
disableDiffuseMult = true;
return this;
}
public SuperByteBuffer shiftUV(SpriteShiftEntry entry) { public SuperByteBuffer shiftUV(SpriteShiftEntry entry) {
this.spriteShiftFunc = (builder, u, v) -> { this.spriteShiftFunc = (builder, u, v) -> {
float targetU = entry.getTarget() float targetU = entry.getTarget()
@ -286,6 +345,17 @@ public class SuperByteBuffer {
return this; return this;
} }
public SuperByteBuffer overlay() {
hasOverlay = true;
return this;
}
public SuperByteBuffer overlay(int overlay) {
hasOverlay = true;
this.overlay = overlay;
return this;
}
public SuperByteBuffer light() { public SuperByteBuffer light() {
useWorldLight = true; useWorldLight = true;
return this; return this;
@ -309,16 +379,38 @@ public class SuperByteBuffer {
return this; return this;
} }
/**
* Uses max light from calculated light (world light or custom light) and vertex light for the final light value.
* Ineffective if any other light method was not called.
*/
public SuperByteBuffer hybridLight() { public SuperByteBuffer hybridLight() {
hybridLight = true; hybridLight = true;
return this; return this;
} }
public SuperByteBuffer asEntityModel() { /**
isEntityModel = true; * Transforms normals not only by the local matrix stack, but also by the passed matrix stack.
*/
public SuperByteBuffer fullNormalTransform() {
fullNormalTransform = true;
return this; return this;
} }
public SuperByteBuffer forEntityRender() {
disableDiffuseMult();
overlay();
fullNormalTransform();
return this;
}
public static int transformColor(byte component, float scale) {
return MathHelper.clamp((int) (Byte.toUnsignedInt(component) * scale), 0, 255);
}
public static int transformColor(int component, float scale) {
return MathHelper.clamp((int) (component * scale), 0, 255);
}
public static int maxLight(int packedLight1, int packedLight2) { public static int maxLight(int packedLight1, int packedLight2) {
int blockLight1 = LightTexture.getBlockLightCoordinates(packedLight1); int blockLight1 = LightTexture.getBlockLightCoordinates(packedLight1);
int skyLight1 = LightTexture.getSkyLightCoordinates(packedLight1); int skyLight1 = LightTexture.getSkyLightCoordinates(packedLight1);

View file

@ -1,7 +1,9 @@
package com.simibubi.create.foundation.renderState; package com.simibubi.create.foundation.renderState;
import com.mojang.blaze3d.systems.RenderSystem; import org.lwjgl.opengl.GL11;
import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.Create;
import net.minecraft.client.renderer.RenderState; import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
@ -11,8 +13,6 @@ import net.minecraft.util.ResourceLocation;
public class RenderTypes extends RenderState { public class RenderTypes extends RenderState {
protected static final RenderState.CullState DISABLE_CULLING = new NoCullState();
public static RenderType getOutlineTranslucent(ResourceLocation texture, boolean cull) { public static RenderType getOutlineTranslucent(ResourceLocation texture, boolean cull) {
RenderType.State rendertype$state = RenderType.State.builder() RenderType.State rendertype$state = RenderType.State.builder()
.texture(new RenderState.TextureState(texture, false, false)) .texture(new RenderState.TextureState(texture, false, false))
@ -23,15 +23,14 @@ public class RenderTypes extends RenderState {
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
.build(true); .build(true);
return RenderType.of("outline_translucent" + (cull ? "_cull" : ""), return RenderType.of(createLayerName("outline_translucent" + (cull ? "_cull" : "")),
DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, rendertype$state); DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256, true, true, rendertype$state);
} }
private static final RenderType OUTLINE_SOLID = private static final RenderType OUTLINE_SOLID =
RenderType.of("outline_solid", DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, RenderType.of(createLayerName("outline_solid"), DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256, true,
false, RenderType.State.builder() false, RenderType.State.builder()
.texture(new RenderState.TextureState(AllSpecialTextures.BLANK.getLocation(), false, false)) .texture(new RenderState.TextureState(AllSpecialTextures.BLANK.getLocation(), false, false))
.transparency(NO_TRANSPARENCY)
.diffuseLighting(ENABLE_DIFFUSE_LIGHTING) .diffuseLighting(ENABLE_DIFFUSE_LIGHTING)
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
@ -40,12 +39,10 @@ public class RenderTypes extends RenderState {
public static RenderType getGlowingSolid(ResourceLocation texture) { public static RenderType getGlowingSolid(ResourceLocation texture) {
RenderType.State rendertype$state = RenderType.State.builder() RenderType.State rendertype$state = RenderType.State.builder()
.texture(new RenderState.TextureState(texture, false, false)) .texture(new RenderState.TextureState(texture, false, false))
.transparency(NO_TRANSPARENCY)
.diffuseLighting(DISABLE_DIFFUSE_LIGHTING)
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
.build(true); .build(true);
return RenderType.of("glowing_solid", DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, return RenderType.of(createLayerName("glowing_solid"), DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256,
true, false, rendertype$state); true, false, rendertype$state);
} }
@ -53,41 +50,52 @@ public class RenderTypes extends RenderState {
RenderType.State rendertype$state = RenderType.State.builder() RenderType.State rendertype$state = RenderType.State.builder()
.texture(new RenderState.TextureState(texture, false, false)) .texture(new RenderState.TextureState(texture, false, false))
.transparency(TRANSLUCENT_TRANSPARENCY) .transparency(TRANSLUCENT_TRANSPARENCY)
.diffuseLighting(DISABLE_DIFFUSE_LIGHTING)
.alpha(ONE_TENTH_ALPHA) .alpha(ONE_TENTH_ALPHA)
.cull(DISABLE_CULLING) .cull(DISABLE_CULLING)
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
.build(true); .build(true);
return RenderType.of("glowing_translucent", DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, return RenderType.of(createLayerName("glowing_translucent"), DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS,
256, true, true, rendertype$state); 256, true, true, rendertype$state);
} }
private static final RenderType GLOWING_SOLID = RenderTypes.getGlowingSolid(PlayerContainer.BLOCK_ATLAS_TEXTURE); private static final RenderType GLOWING_SOLID = getGlowingSolid(PlayerContainer.BLOCK_ATLAS_TEXTURE);
private static final RenderType GLOWING_TRANSLUCENT = private static final RenderType GLOWING_TRANSLUCENT = getGlowingTranslucent(PlayerContainer.BLOCK_ATLAS_TEXTURE);
RenderTypes.getGlowingTranslucent(PlayerContainer.BLOCK_ATLAS_TEXTURE);
private static final RenderType ITEM_PARTIAL_SOLID = private static final RenderType ITEM_PARTIAL_SOLID =
RenderType.of("item_solid", DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, RenderType.of(createLayerName("item_solid"), DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256, true,
false, RenderType.State.builder() false, RenderType.State.builder()
.texture(new RenderState.TextureState(PlayerContainer.BLOCK_ATLAS_TEXTURE, false, false)) .texture(BLOCK_ATLAS_TEXTURE)
.transparency(NO_TRANSPARENCY) .transparency(NO_TRANSPARENCY)
.diffuseLighting(ENABLE_DIFFUSE_LIGHTING) .diffuseLighting(ENABLE_DIFFUSE_LIGHTING)
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
.build(true)); .build(true));
private static final RenderType ITEM_PARTIAL_TRANSLUCENT = RenderType.of("entity_translucent", private static final RenderType ITEM_PARTIAL_TRANSLUCENT = RenderType.of(createLayerName("item_translucent"),
DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, 7, 256, true, true, RenderType.State.builder() DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256, true, true, RenderType.State.builder()
.texture(new RenderState.TextureState(PlayerContainer.BLOCK_ATLAS_TEXTURE, false, false)) .texture(BLOCK_ATLAS_TEXTURE)
.transparency(TRANSLUCENT_TRANSPARENCY) .transparency(TRANSLUCENT_TRANSPARENCY)
.diffuseLighting(ENABLE_DIFFUSE_LIGHTING) .diffuseLighting(ENABLE_DIFFUSE_LIGHTING)
.alpha(ONE_TENTH_ALPHA) .alpha(ONE_TENTH_ALPHA)
.cull(ENABLE_CULLING)
.lightmap(ENABLE_LIGHTMAP) .lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR) .overlay(ENABLE_OVERLAY_COLOR)
.build(true)); .build(true));
private static final RenderType FLUID = RenderType.of(createLayerName("fluid"),
DefaultVertexFormats.POSITION_COLOR_TEXTURE_OVERLAY_LIGHT_NORMAL, GL11.GL_QUADS, 256, true, true, RenderType.State.builder()
.texture(MIPMAP_BLOCK_ATLAS_TEXTURE)
.transparency(TRANSLUCENT_TRANSPARENCY)
.shadeModel(SMOOTH_SHADE_MODEL)
.alpha(ONE_TENTH_ALPHA)
.lightmap(ENABLE_LIGHTMAP)
.overlay(ENABLE_OVERLAY_COLOR)
.build(true));
private static String createLayerName(String name) {
return Create.ID + ":" + name;
}
public static RenderType getItemPartialSolid() { public static RenderType getItemPartialSolid() {
return ITEM_PARTIAL_SOLID; return ITEM_PARTIAL_SOLID;
} }
@ -108,19 +116,13 @@ public class RenderTypes extends RenderState {
return GLOWING_TRANSLUCENT; return GLOWING_TRANSLUCENT;
} }
protected static class NoCullState extends RenderState.CullState { public static RenderType getFluid() {
public NoCullState() { return FLUID;
super(false);
}
@Override
public void startDrawing() {
RenderSystem.disableCull();
}
} }
// Mmm gimme those protected fields // Mmm gimme those protected fields
public RenderTypes() { public RenderTypes() {
super(null, null, null); super(null, null, null);
} }
} }