Implement rendering for item models with emissive quads (#5047)
This commit is contained in:
parent
1280dea111
commit
67da3182c1
4 changed files with 227 additions and 8 deletions
|
@ -16,7 +16,18 @@
|
|||
|
||||
this.field_184395_f = p_i46552_3_;
|
||||
}
|
||||
@@ -97,7 +98,7 @@
|
||||
@@ -74,6 +75,10 @@
|
||||
}
|
||||
|
||||
private void func_191967_a(IBakedModel p_191967_1_, int p_191967_2_, ItemStack p_191967_3_) {
|
||||
+ if (net.minecraftforge.common.ForgeConfig.CLIENT.allowEmissiveItems.get()) {
|
||||
+ net.minecraftforge.client.ForgeHooksClient.renderLitItem(this, p_191967_1_, p_191967_2_, p_191967_3_);
|
||||
+ return;
|
||||
+ }
|
||||
Tessellator tessellator = Tessellator.func_178181_a();
|
||||
BufferBuilder bufferbuilder = tessellator.func_178180_c();
|
||||
bufferbuilder.func_181668_a(7, DefaultVertexFormats.field_176599_b);
|
||||
@@ -97,7 +102,7 @@
|
||||
if (p_180454_2_.func_188618_c()) {
|
||||
GlStateManager.func_179131_c(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
GlStateManager.func_179091_B();
|
||||
|
@ -25,7 +36,7 @@
|
|||
} else {
|
||||
this.func_191961_a(p_180454_2_, p_180454_1_);
|
||||
if (p_180454_1_.func_77962_s()) {
|
||||
@@ -163,7 +164,7 @@
|
||||
@@ -163,7 +168,7 @@
|
||||
k = k | -16777216;
|
||||
}
|
||||
|
||||
|
@ -34,7 +45,7 @@
|
|||
}
|
||||
|
||||
}
|
||||
@@ -224,11 +225,8 @@
|
||||
@@ -224,11 +229,8 @@
|
||||
GlStateManager.func_179147_l();
|
||||
GlStateManager.func_187428_a(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
||||
GlStateManager.func_179094_E();
|
||||
|
@ -48,7 +59,7 @@
|
|||
|
||||
this.func_180454_a(p_184394_1_, p_184394_2_);
|
||||
GlStateManager.func_187407_a(GlStateManager.CullFace.BACK);
|
||||
@@ -259,7 +257,7 @@
|
||||
@@ -259,7 +261,7 @@
|
||||
GlStateManager.func_187401_a(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.func_179131_c(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
this.func_180452_a(p_191962_2_, p_191962_3_, p_191962_4_.func_177556_c());
|
||||
|
@ -57,7 +68,7 @@
|
|||
this.func_180454_a(p_191962_1_, p_191962_4_);
|
||||
GlStateManager.func_179118_c();
|
||||
GlStateManager.func_179101_C();
|
||||
@@ -298,6 +296,7 @@
|
||||
@@ -298,6 +300,7 @@
|
||||
crashreportcategory.func_189529_a("Item Type", () -> {
|
||||
return String.valueOf((Object)p_184391_2_.func_77973_b());
|
||||
});
|
||||
|
@ -65,7 +76,7 @@
|
|||
crashreportcategory.func_189529_a("Item Damage", () -> {
|
||||
return String.valueOf(p_184391_2_.func_77952_i());
|
||||
});
|
||||
@@ -329,9 +328,12 @@
|
||||
@@ -329,9 +332,12 @@
|
||||
GlStateManager.func_179147_l();
|
||||
GlStateManager.func_179145_e();
|
||||
GlStateManager.func_179126_j();
|
||||
|
@ -79,7 +90,7 @@
|
|||
GlStateManager.func_179140_f();
|
||||
GlStateManager.func_179097_i();
|
||||
GlStateManager.func_179090_x();
|
||||
@@ -339,11 +341,9 @@
|
||||
@@ -339,11 +345,9 @@
|
||||
GlStateManager.func_179084_k();
|
||||
Tessellator tessellator = Tessellator.func_178181_a();
|
||||
BufferBuilder bufferbuilder = tessellator.func_178180_c();
|
||||
|
@ -94,7 +105,7 @@
|
|||
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, 13, 2, 0, 0, 0, 255);
|
||||
this.func_181565_a(bufferbuilder, p_180453_3_ + 2, p_180453_4_ + 13, i, 1, j >> 16 & 255, j >> 8 & 255, j & 255, 255);
|
||||
GlStateManager.func_179147_l();
|
||||
@@ -382,4 +382,9 @@
|
||||
@@ -382,4 +386,9 @@
|
||||
public void func_195410_a(IResourceManager p_195410_1_) {
|
||||
this.field_175059_m.func_178085_b();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ import java.io.File;
|
|||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
@ -47,6 +49,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import org.apache.logging.log4j.core.async.ThreadNameCachingStrategy;
|
||||
import org.apache.logging.log4j.core.impl.ReusableLogEventFactory;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.GameSettings;
|
||||
|
@ -62,7 +65,10 @@ import net.minecraft.client.renderer.BufferBuilder;
|
|||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.WorldRenderer;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.model.BlockFaceUV;
|
||||
|
@ -79,6 +85,7 @@ import net.minecraft.client.renderer.entity.model.ModelBiped;
|
|||
import net.minecraft.client.renderer.texture.NativeImage;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
|
||||
|
@ -119,6 +126,7 @@ import net.minecraftforge.client.event.sound.PlaySoundEvent;
|
|||
import net.minecraftforge.client.model.ModelDynBucket;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.animation.Animation;
|
||||
import net.minecraftforge.client.model.pipeline.QuadGatheringTransformer;
|
||||
import net.minecraftforge.common.ForgeMod;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.model.IModelPart;
|
||||
|
@ -548,6 +556,197 @@ public class ForgeHooksClient
|
|||
}
|
||||
}
|
||||
|
||||
private static class LightGatheringTransformer extends QuadGatheringTransformer {
|
||||
|
||||
private static final VertexFormat FORMAT = new VertexFormat().addElement(DefaultVertexFormats.TEX_2F).addElement(DefaultVertexFormats.TEX_2S);
|
||||
|
||||
int blockLight, skyLight;
|
||||
|
||||
{ setVertexFormat(FORMAT); }
|
||||
|
||||
boolean hasLighting()
|
||||
{
|
||||
return dataLength[1] >= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processQuad()
|
||||
{
|
||||
// Reset light data
|
||||
blockLight = 0;
|
||||
skyLight = 0;
|
||||
// Compute average light for all 4 vertices
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
blockLight += (int) ((quadData[1][i][0] * 0xFFFF) / 0x20);
|
||||
skyLight += (int) ((quadData[1][i][1] * 0xFFFF) / 0x20);
|
||||
}
|
||||
// Values must be multiplied by 16, divided by 4 for average => x4
|
||||
blockLight *= 4;
|
||||
skyLight *= 4;
|
||||
}
|
||||
|
||||
// Dummy overrides
|
||||
|
||||
@Override
|
||||
public void setQuadTint(int tint) {}
|
||||
|
||||
@Override
|
||||
public void setQuadOrientation(EnumFacing orientation) {}
|
||||
|
||||
@Override
|
||||
public void setApplyDiffuseLighting(boolean diffuse) {}
|
||||
|
||||
@Override
|
||||
public void setTexture(TextureAtlasSprite texture) {}
|
||||
}
|
||||
|
||||
private static final LightGatheringTransformer lightGatherer = new LightGatheringTransformer();
|
||||
|
||||
public static void renderLitItem(ItemRenderer ri, IBakedModel model, int color, ItemStack stack)
|
||||
{
|
||||
List<BakedQuad> allquads = new ArrayList<>();
|
||||
Random random = new Random();
|
||||
long seed = 42L;
|
||||
|
||||
for (EnumFacing enumfacing : EnumFacing.values())
|
||||
{
|
||||
random.setSeed(seed);
|
||||
allquads.addAll(model.getQuads(null, enumfacing, random));
|
||||
}
|
||||
|
||||
random.setSeed(seed);
|
||||
allquads.addAll(model.getQuads(null, null, random));
|
||||
|
||||
if (allquads.isEmpty()) return;
|
||||
|
||||
// Current list of consecutive quads with the same lighting
|
||||
List<BakedQuad> segment = new ArrayList<>();
|
||||
|
||||
// Lighting of the current segment
|
||||
int segmentBlockLight = -1;
|
||||
int segmentSkyLight = -1;
|
||||
// Coloring of the current segment
|
||||
int segmentColorMultiplier = color;
|
||||
// If the current segment contains lighting data
|
||||
boolean hasLighting = false;
|
||||
|
||||
// Tint index cache to avoid unnecessary IItemColor lookups
|
||||
int prevTintIndex = -1;
|
||||
|
||||
for (int i = 0; i < allquads.size(); i++)
|
||||
{
|
||||
BakedQuad q = allquads.get(i);
|
||||
|
||||
// Lighting of the current quad
|
||||
int bl = 0;
|
||||
int sl = 0;
|
||||
|
||||
// Fail-fast on ITEM, as it cannot have light data
|
||||
if (q.getFormat() != DefaultVertexFormats.ITEM && q.getFormat().hasUv(1))
|
||||
{
|
||||
q.pipe(lightGatherer);
|
||||
if (lightGatherer.hasLighting())
|
||||
{
|
||||
bl = lightGatherer.blockLight;
|
||||
sl = lightGatherer.skyLight;
|
||||
}
|
||||
}
|
||||
|
||||
int colorMultiplier = segmentColorMultiplier;
|
||||
|
||||
// If there is no color override, and this quad is tinted, we need to apply IItemColor
|
||||
if (color == 0xFFFFFFFF && q.hasTintIndex())
|
||||
{
|
||||
int tintIndex = q.getTintIndex();
|
||||
|
||||
if (prevTintIndex != tintIndex)
|
||||
{
|
||||
colorMultiplier = getColorMultiplier(stack, tintIndex);
|
||||
}
|
||||
prevTintIndex = tintIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorMultiplier = color;
|
||||
prevTintIndex = -1;
|
||||
}
|
||||
|
||||
boolean lightingDirty = segmentBlockLight != bl || segmentSkyLight != sl;
|
||||
boolean colorDirty = hasLighting && segmentColorMultiplier != colorMultiplier;
|
||||
|
||||
// If lighting or color data has changed, draw the segment and flush it
|
||||
if (lightingDirty || colorDirty)
|
||||
{
|
||||
if (i > 0) // Make sure this isn't the first quad being processed
|
||||
{
|
||||
drawSegment(ri, color, stack, segment, segmentBlockLight, segmentSkyLight, segmentColorMultiplier, lightingDirty && (hasLighting || segment.size() < i), colorDirty);
|
||||
}
|
||||
segmentBlockLight = bl;
|
||||
segmentSkyLight = sl;
|
||||
segmentColorMultiplier = colorMultiplier;
|
||||
hasLighting = segmentBlockLight > 0 || segmentSkyLight > 0;
|
||||
}
|
||||
|
||||
segment.add(q);
|
||||
}
|
||||
|
||||
drawSegment(ri, color, stack, segment, segmentBlockLight, segmentSkyLight, segmentColorMultiplier, hasLighting || segment.size() < allquads.size(), false);
|
||||
|
||||
// Clean up render state if necessary
|
||||
if (hasLighting)
|
||||
{
|
||||
OpenGlHelper.glMultiTexCoord2f(OpenGlHelper.GL_TEXTURE1, OpenGlHelper.lastBrightnessX, OpenGlHelper.lastBrightnessY);
|
||||
GL11.glMaterialfv(GL11.GL_FRONT_AND_BACK, GL11.GL_EMISSION, RenderHelper.setColorBuffer(0, 0, 0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawSegment(ItemRenderer ri, int baseColor, ItemStack stack, List<BakedQuad> segment, int bl, int sl, int tintColor, boolean updateLighting, boolean updateColor)
|
||||
{
|
||||
BufferBuilder bufferbuilder = Tessellator.getInstance().getBuffer();
|
||||
bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
|
||||
|
||||
float lastBl = OpenGlHelper.lastBrightnessX;
|
||||
float lastSl = OpenGlHelper.lastBrightnessY;
|
||||
|
||||
if (updateLighting || updateColor)
|
||||
{
|
||||
float emissive = Math.max(bl, sl) / 240f;
|
||||
|
||||
float r = (tintColor >>> 16 & 0xff) / 255f;
|
||||
float g = (tintColor >>> 8 & 0xff) / 255f;
|
||||
float b = (tintColor & 0xff) / 255f;
|
||||
|
||||
GL11.glMaterialfv(GL11.GL_FRONT_AND_BACK, GL11.GL_EMISSION, RenderHelper.setColorBuffer(emissive * r, emissive * g, emissive * b, 1));
|
||||
|
||||
if (updateLighting)
|
||||
{
|
||||
OpenGlHelper.glMultiTexCoord2f(OpenGlHelper.GL_TEXTURE1, Math.max(bl, lastBl), Math.max(sl, lastSl));
|
||||
}
|
||||
}
|
||||
|
||||
ri.renderQuads(bufferbuilder, segment, baseColor, stack);
|
||||
Tessellator.getInstance().draw();
|
||||
|
||||
// Preserve this as it represents the "world" lighting
|
||||
OpenGlHelper.lastBrightnessX = lastBl;
|
||||
OpenGlHelper.lastBrightnessY = lastSl;
|
||||
|
||||
segment.clear();
|
||||
}
|
||||
|
||||
private static int getColorMultiplier(ItemStack stack, int tintIndex)
|
||||
{
|
||||
if (tintIndex == -1 || stack.isEmpty()) return 0xFFFFFFFF;
|
||||
|
||||
int colorMultiplier = Minecraft.getInstance().getItemColors().getColor(stack, tintIndex);
|
||||
|
||||
// Always full opacity
|
||||
colorMultiplier |= 0xff << 24; // -16777216
|
||||
|
||||
return colorMultiplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* internal, relies on fixed format of FaceBakery
|
||||
*/
|
||||
|
|
|
@ -125,6 +125,8 @@ public class ForgeConfig
|
|||
public final BooleanValue selectiveResourceReloadEnabled;
|
||||
|
||||
public final BooleanValue showLoadWarnings;
|
||||
|
||||
public final BooleanValue allowEmissiveItems;
|
||||
|
||||
Client(ForgeConfigSpec.Builder builder) {
|
||||
builder.comment("Client only settings, mostly things related to rendering")
|
||||
|
@ -166,6 +168,11 @@ public class ForgeConfig
|
|||
.comment("When enabled, forge will show any warnings that occurred during loading")
|
||||
.translation("forge.configgui.showloadwarnings")
|
||||
.define("showLoadWarnings", true);
|
||||
|
||||
allowEmissiveItems = builder
|
||||
.comment("Allow item rendering to detect emissive quads and draw them properly. This allows glowing blocks to look the same in item form, but incurs a very slight performance hit.")
|
||||
.translation("forge.configgui.allowEmissiveItems")
|
||||
.define("allowEmissiveItems", true);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@ public net.minecraft.entity.item.EntityXPOrb field_70530_e # xpValue
|
|||
public net.minecraft.world.gen.structure.StructureVillagePieces$Village
|
||||
# RenderPlayer
|
||||
#public net.minecraft.client.renderer.entity.RenderBiped field_77071_a #modelBipedMain
|
||||
# RenderItem
|
||||
public net.minecraft.client.renderer.ItemRenderer func_191970_a(Lnet/minecraft/client/renderer/BufferBuilder;Ljava/util/List;ILnet/minecraft/item/ItemStack;)V # renderQuads
|
||||
# ChunkProviderServer
|
||||
public net.minecraft.world.gen.ChunkProviderServer field_186029_c # chunkGenerator
|
||||
public net.minecraft.world.gen.ChunkProviderServer field_73244_f # loadedChunkHashMap
|
||||
|
|
Loading…
Reference in a new issue