Added the variant name to the missing model. (#3328)

This commit is contained in:
Fry 2017-01-19 13:57:37 +04:00 committed by GitHub
parent 1e7eb6fb09
commit bbc107de96
6 changed files with 425 additions and 5 deletions

View file

@ -0,0 +1,223 @@
package net.minecraftforge.client.model;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;
import java.util.Collection;
import java.util.List;
final class FancyMissingModel implements IModel
{
private static final ResourceLocation font = new ResourceLocation("minecraft", "textures/font/ascii.png");
private static final ResourceLocation font2 = new ResourceLocation("minecraft", "font/ascii");
private static final TRSRTransformation smallTransformation = TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, null, new Vector3f(.25f, .25f, .25f), null));
private static final LoadingCache<VertexFormat, SimpleModelFontRenderer> fontCache = CacheBuilder.newBuilder().maximumSize(3).build(new CacheLoader<VertexFormat, SimpleModelFontRenderer>()
{
public SimpleModelFontRenderer load(VertexFormat format) throws Exception
{
Matrix4f m = new Matrix4f();
m.m20 = 1f / 128f;
m.m01 = m.m12 = -m.m20;
m.m33 = 1;
m.setTranslation(new Vector3f(1, 1 + 1f / 0x100, 0));
return new SimpleModelFontRenderer(
Minecraft.getMinecraft().gameSettings,
font,
Minecraft.getMinecraft().getTextureManager(),
false,
m,
format
) {
@Override
protected float renderUnicodeChar(char c, boolean italic)
{
return super.renderDefaultChar(126, italic);
}
};
}
});
private final IModel missingModel;
private final String message;
public FancyMissingModel(IModel missingModel, String message)
{
this.missingModel = missingModel;
this.message = message;
}
@Override
public Collection<ResourceLocation> getDependencies()
{
return ImmutableList.of();
}
@Override
public Collection<ResourceLocation> getTextures()
{
return ImmutableList.of(font2);
}
@Override
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
IBakedModel bigMissing = missingModel.bake(state, format, bakedTextureGetter);
IModelState smallState = new ModelStateComposition(state, smallTransformation);
IBakedModel smallMissing = missingModel.bake(smallState, format, bakedTextureGetter);
return new BakedModel(bigMissing, smallMissing, fontCache.getUnchecked(format), message, bakedTextureGetter.apply(font2));
}
@Override
public IModelState getDefaultState()
{
return TRSRTransformation.identity();
}
private static final class BakedModel implements IPerspectiveAwareModel
{
private final SimpleModelFontRenderer fontRenderer;
private final String message;
private final TextureAtlasSprite fontTexture;
private final IBakedModel missingModel;
private final IBakedModel otherModel;
private final boolean big;
private ImmutableList<BakedQuad> quads;
public BakedModel(IBakedModel bigMissing, IBakedModel smallMissing, SimpleModelFontRenderer fontRenderer, String message, TextureAtlasSprite fontTexture)
{
this.missingModel = bigMissing;
otherModel = new BakedModel(smallMissing, fontRenderer, message, fontTexture, this);
this.big = true;
this.fontRenderer = fontRenderer;
this.message = message;
this.fontTexture = fontTexture;
}
public BakedModel(IBakedModel smallMissing, SimpleModelFontRenderer fontRenderer, String message, TextureAtlasSprite fontTexture, BakedModel big)
{
this.missingModel = smallMissing;
otherModel = big;
this.big = false;
this.fontRenderer = fontRenderer;
this.message = message;
this.fontTexture = fontTexture;
}
@Override
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
{
if (side == null)
{
if (quads == null)
{
fontRenderer.setSprite(fontTexture);
fontRenderer.setFillBlanks(true);
String[] lines = message.split("\\r?\\n");
List<String> splitLines = Lists.newArrayList();
for (int y = 0; y < lines.length; y++)
{
splitLines.addAll(fontRenderer.listFormattedStringToWidth(lines[y], 0x80));
}
for (int y = 0; y < splitLines.size(); y++)
{
fontRenderer.drawString(splitLines.get(y), 0, (int)((y - splitLines.size() / 2f) * fontRenderer.FONT_HEIGHT) + 0x40, 0xFF00FFFF);
}
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
builder.addAll(missingModel.getQuads(state, side, rand));
builder.addAll(fontRenderer.build());
quads = builder.build();
}
return quads;
}
return missingModel.getQuads(state, side, rand);
}
@Override
public boolean isAmbientOcclusion() { return true; }
@Override
public boolean isGui3d() { return false; }
@Override
public boolean isBuiltInRenderer() { return false; }
@Override
public TextureAtlasSprite getParticleTexture() { return fontTexture; }
@Override
public ItemCameraTransforms getItemCameraTransforms() { return ItemCameraTransforms.DEFAULT; }
@Override
public ItemOverrideList getOverrides() { return ItemOverrideList.NONE; }
@Override
public Pair<? extends IBakedModel, Matrix4f> handlePerspective(ItemCameraTransforms.TransformType cameraTransformType)
{
TRSRTransformation transform = TRSRTransformation.identity();
boolean big = true;
switch (cameraTransformType)
{
case THIRD_PERSON_LEFT_HAND:
break;
case THIRD_PERSON_RIGHT_HAND:
break;
case FIRST_PERSON_LEFT_HAND:
transform = new TRSRTransformation(new Vector3f(-0.62f, 0.5f, -.5f), new Quat4f(1, -1, -1, 1), null, null);
big = false;
break;
case FIRST_PERSON_RIGHT_HAND:
transform = new TRSRTransformation(new Vector3f(-0.5f, 0.5f, -.5f), new Quat4f(1, 1, 1, 1), null, null);
big = false;
break;
case HEAD:
break;
case GUI:
if (ForgeModContainer.zoomInMissingModelTextInGui)
{
transform = new TRSRTransformation(null, new Quat4f(1, 1, 1, 1), new Vector3f(4, 4, 4), null);
big = false;
}
else
{
transform = new TRSRTransformation(null, new Quat4f(1, 1, 1, 1), null, null);
big = true;
}
break;
case FIXED:
transform = new TRSRTransformation(null, new Quat4f(-1, -1, 1, 1), null, null);
break;
default:
break;
}
if (big != this.big)
{
return Pair.of(otherModel, transform.getMatrix());
}
return Pair.of(this, transform.getMatrix());
}
}
}

View file

@ -262,7 +262,7 @@ public final class ModelLoader extends ModelBakery
catch(Exception e)
{
storeException(location, e);
model = getMissingModel();
model = ModelLoaderRegistry.getMissingModel(location, e);
}
stateModels.put(location, model);
}
@ -348,11 +348,12 @@ public final class ModelLoader extends ModelBakery
exception = new ItemLoadingException("Could not load item model either from the normal location " + file + " or from the blockstate", normalException, blockstateException);
}
}
stateModels.put(memory, model);
if(exception != null)
{
storeException(memory, exception);
model = ModelLoaderRegistry.getMissingModel(memory, exception);
}
stateModels.put(memory, model);
}
}
ProgressManager.pop(itemBar);

View file

@ -189,7 +189,7 @@ public class ModelLoaderRegistry
}
catch(Exception e)
{
return getMissingModel();
return getMissingModel(location, e);
}
}
@ -205,7 +205,7 @@ public class ModelLoaderRegistry
catch(Exception e)
{
FMLLog.getLogger().error(error, e);
return getMissingModel();
return getMissingModel(location, e);
}
}
@ -218,6 +218,14 @@ public class ModelLoaderRegistry
return ModelLoader.VanillaLoader.INSTANCE.getLoader().getMissingModel();
}
static IModel getMissingModel(ResourceLocation location, Throwable cause)
{
//IModel model = new FancyMissingModel(ExceptionUtils.getStackTrace(cause).replaceAll("\\t", " "));
IModel model = new FancyMissingModel(getMissingModel(), location.toString());
textures.addAll(model.getTextures());
return model;
}
public static void clearModelCache(IResourceManager manager)
{
ModelLoaderRegistry.manager = manager;

View file

@ -0,0 +1,179 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
public abstract class SimpleModelFontRenderer extends FontRenderer {
private float r, g, b, a;
private final Matrix4f matrix;
private ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
private final VertexFormat format;
private final Vector3f normal = new Vector3f(0, 0, 1);
private final EnumFacing orientation;
private boolean fillBlanks = false;
private TextureAtlasSprite sprite;
public SimpleModelFontRenderer(GameSettings settings, ResourceLocation font, TextureManager manager, boolean isUnicode, Matrix4f matrix, VertexFormat format)
{
super(settings, font, manager, isUnicode);
manager.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
this.matrix = new Matrix4f(matrix);
Matrix3f nm = new Matrix3f();
this.matrix.getRotationScale(nm);
nm.invert();
nm.transpose();
this.format = format;
nm.transform(normal);
normal.normalize();
orientation = EnumFacing.getFacingFromVector(normal.x, normal.y, normal.z);
}
public void setSprite(TextureAtlasSprite sprite)
{
this.sprite = sprite;
super.onResourceManagerReload(null);
}
public void setFillBlanks(boolean fillBlanks)
{
this.fillBlanks = fillBlanks;
}
@Override
protected float renderDefaultChar(int pos, boolean italic)
{
float x = (pos % 16) / 16f;
float y = (pos / 16) / 16f;
float sh = italic ? 1f : 0f;
float w = charWidth[pos] - 1.01f;
float h = FONT_HEIGHT - 1.01f;
float wt = w / 128f;
float ht = h / 128f;
UnpackedBakedQuad.Builder quadBuilder = new UnpackedBakedQuad.Builder(format);
quadBuilder.setQuadOrientation(orientation);
addVertex(quadBuilder, posX + sh, posY, x, y);
addVertex(quadBuilder, posX - sh, posY + h, x, y + ht);
addVertex(quadBuilder, posX + w + sh, posY + h, x + wt, y + ht);
addVertex(quadBuilder, posX + w - sh, posY, x + wt, y);
builder.add(quadBuilder.build());
if(fillBlanks)
{
float cuv = 15f / 16f;
quadBuilder = new UnpackedBakedQuad.Builder(format);
quadBuilder.setQuadOrientation(orientation);
addVertex(quadBuilder, posX + w + sh, posY, cuv, cuv);
addVertex(quadBuilder, posX + w - sh, posY + h, cuv, cuv);
addVertex(quadBuilder, posX + charWidth[pos] + sh, posY + h, cuv, cuv);
addVertex(quadBuilder, posX + charWidth[pos] - sh, posY, cuv, cuv);
builder.add(quadBuilder.build());
quadBuilder = new UnpackedBakedQuad.Builder(format);
quadBuilder.setQuadOrientation(orientation);
addVertex(quadBuilder, posX + sh, posY + h, cuv, cuv);
addVertex(quadBuilder, posX - sh, posY + FONT_HEIGHT, cuv, cuv);
addVertex(quadBuilder, posX + charWidth[pos] + sh, posY + FONT_HEIGHT, cuv, cuv);
addVertex(quadBuilder, posX + charWidth[pos] - sh, posY + h, cuv, cuv);
builder.add(quadBuilder.build());
}
return charWidth[pos];
}
private final Vector4f vec = new Vector4f();
private void addVertex(UnpackedBakedQuad.Builder quadBuilder, float x, float y, float u, float v)
{
vec.x = x;
vec.y = y;
vec.z = 0;
vec.w = 1;
matrix.transform(vec);
for(int e = 0; e < format.getElementCount(); e++)
{
switch(format.getElement(e).getUsage())
{
case POSITION:
quadBuilder.put(e, vec.x, vec.y, vec.z, vec.w);
break;
case UV:
quadBuilder.put(e, sprite.getInterpolatedU(u * 16), sprite.getInterpolatedV(v * 16), 0, 1);
break;
case COLOR:
quadBuilder.put(e, r, g, b, a);
break;
case NORMAL:
//quadBuilder.put(e, normal.x, normal.y, normal.z, 1);
quadBuilder.put(e, 0, 0, 1, 1);
break;
default:
quadBuilder.put(e);
break;
}
}
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager)
{
super.onResourceManagerReload(resourceManager);
String p = locationFontTexture.getResourcePath();
if(p.startsWith("textures/")) p = p.substring("textures/".length(), p.length());
if(p.endsWith(".png")) p = p.substring(0, p.length() - ".png".length());
String f = locationFontTexture.getResourceDomain() + ":" + p;
sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(f);
}
@Override
protected abstract float renderUnicodeChar(char c, boolean italic);
@Override
protected void doDraw(float shift)
{
posX += (int)shift;
}
@Override
protected void setColor(float r, float g, float b, float a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
@Override public void enableAlpha()
{
}
public ImmutableList<BakedQuad> build()
{
ImmutableList<BakedQuad> ret = builder.build();
builder = ImmutableList.builder();
return ret;
}
}

View file

@ -112,6 +112,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
public static boolean disableVersionCheck = false;
public static boolean forgeLightPipelineEnabled = true;
public static boolean replaceVanillaBucketModel = true;
public static boolean zoomInMissingModelTextInGui = false;
public static long java8Reminder = 0;
public static boolean disableStairSlabCulling = false; // Also known as the "DontCullStairsBecauseIUseACrappyTexturePackThatBreaksBasicBlockShapesSoICantTrustBasicBlockCulling" flag
public static boolean alwaysSetupTerrainOffThread = false; // In RenderGlobal.setupTerrain, always force the chunk render updates to be queued to the thread
@ -283,12 +284,19 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
// Client-Side only properties
propOrder = new ArrayList<String>();
prop = config.get(Configuration.CATEGORY_CLIENT, "replaceVanillaBucketModel", Boolean.FALSE,
"Replace the vanilla bucket models with Forges own dynamic bucket model. Unifies bucket visuals if a mod uses the Forge bucket model.");
prop.setLanguageKey("forge.configgui.replaceBuckets").setRequiresMcRestart(true);
replaceVanillaBucketModel = prop.getBoolean(Boolean.FALSE);
propOrder.add(prop.getName());
prop = config.get(Configuration.CATEGORY_CLIENT, "zoomInMissingModelTextInGui", Boolean.TRUE,
"Toggle off to make missing model text in the gui fit inside the slot.");
zoomInMissingModelTextInGui = prop.getBoolean(Boolean.FALSE);
prop.setLanguageKey("forge.configgui.zoomInMissingModelTextInGui");
propOrder.add(prop.getName());
prop = config.get(Configuration.CATEGORY_CLIENT, "java8Reminder", java8Reminder,
"The timestamp of the last reminder to update to Java 8 in number of milliseconds since January 1, 1970, 00:00:00 GMT. Nag will show only once every 24 hours. To disable it set this to some really high number.");
java8Reminder = prop.getLong(java8Reminder);

View file

@ -49,6 +49,7 @@ forge.configgui.replaceBuckets=Use Forge's bucket model
forge.configgui.forgeLightPipelineEnabled=Forge Light Pipeline Enabled
forge.configgui.java8Reminder=Java 8 Reminder timestamp
forge.configgui.disableStairSlabCulling=Disable Stair/Slab culling.
forge.configgui.zoomInMissingModelTextInGui=Zoom in Missing model text in the GUI
forge.configgui.disableStairSlabCulling.tooltip=Enable this if you see through blocks touching stairs/slabs with your resource pack.
forge.configgui.alwaysSetupTerrainOffThread=Force threaded chunk rendering
forge.configgui.alwaysSetupTerrainOffThread.tooltip=Enable forge to queue all chunk updates to the Chunk Update thread. May increase FPS significantly, but may also cause weird rendering lag. Not recommended for computers without a significant number of cores available.
@ -186,4 +187,4 @@ fml.button.continue=Continue
fml.button.open.mods.folder=Open Mods Folder
fml.button.open.file=Open %s
forge.container.enchant.limitedEnchantability=Limited Enchantability
forge.container.enchant.limitedEnchantability=Limited Enchantability