Fixed perspective transformations for item models.
This commit is contained in:
parent
d7c4a06ce8
commit
510b5523d5
6 changed files with 154 additions and 13 deletions
|
@ -1,8 +1,12 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.vecmath.Vector4f;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumType;
|
||||
|
@ -104,4 +108,33 @@ public class Attributes
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BakedQuad transform(TRSRTransformation transform, BakedQuad quad, VertexFormat format)
|
||||
{
|
||||
for (VertexFormatElement e : (List<VertexFormatElement>)format.getElements())
|
||||
{
|
||||
if (e.getUsage() == VertexFormatElement.EnumUsage.POSITION)
|
||||
{
|
||||
if (e.getType() != VertexFormatElement.EnumType.FLOAT)
|
||||
{
|
||||
throw new IllegalArgumentException("can only transform float position");
|
||||
}
|
||||
int[] data = Arrays.copyOf(quad.getVertexData(), quad.getVertexData().length);
|
||||
float[] pos = new float[] { 0f, 0f, 0f, 1f };
|
||||
for (int i = 0; i < Math.min(4, e.getElementCount()); i++)
|
||||
{
|
||||
pos[i] = Float.intBitsToFloat(data[e.getOffset() / 4 + i]);
|
||||
}
|
||||
Vector4f vec = new Vector4f(pos);
|
||||
transform.getMatrix().transform(vec);
|
||||
vec.get(pos);
|
||||
for (int i = 0; i < Math.min(4, e.getElementCount()); i++)
|
||||
{
|
||||
data[e.getOffset() / 4 + i] = Float.floatToRawIntBits(pos[i]);
|
||||
}
|
||||
return new BakedQuad(data, quad.getTintIndex(), quad.getFace());
|
||||
}
|
||||
}
|
||||
return quad;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,12 +2,11 @@ package net.minecraftforge.client.model;
|
|||
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
/*
|
||||
* Model that changes based on the rendering perspective
|
||||
* (first-person, GUI, e.t.c - see TransformType)
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package net.minecraftforge.client.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* IModelState that can change depending on the perspective.
|
||||
*/
|
||||
public interface IPerspectiveState extends IModelState
|
||||
{
|
||||
/**
|
||||
* @return the additional state that needs to be applied for each part when in given perspective type.
|
||||
*/
|
||||
public IModelState forPerspective(TransformType type);
|
||||
|
||||
public static class Impl implements IPerspectiveState
|
||||
{
|
||||
private final IModelState parent;
|
||||
private final ImmutableMap<TransformType, IModelState> states;
|
||||
|
||||
public Impl(IModelState parent, ImmutableMap<TransformType, IModelState> states)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.states = states;
|
||||
}
|
||||
|
||||
public Impl(IModelState parent, ItemCameraTransforms transforms)
|
||||
{
|
||||
this(parent, getMap(transforms));
|
||||
}
|
||||
|
||||
private static ImmutableMap<TransformType, IModelState> getMap(ItemCameraTransforms transforms)
|
||||
{
|
||||
Map<TransformType, IModelState> map = Maps.newHashMap();
|
||||
map.put(TransformType.NONE, TRSRTransformation.identity());
|
||||
map.put(TransformType.THIRD_PERSON, transforms.thirdPerson);
|
||||
map.put(TransformType.FIRST_PERSON, transforms.firstPerson);
|
||||
map.put(TransformType.GUI, transforms.gui);
|
||||
map.put(TransformType.HEAD, transforms.head);
|
||||
return Maps.immutableEnumMap(map);
|
||||
}
|
||||
|
||||
public TRSRTransformation apply(IModelPart part)
|
||||
{
|
||||
return parent.apply(part);
|
||||
}
|
||||
|
||||
public IModelState forPerspective(TransformType type)
|
||||
{
|
||||
return states.getOrDefault(type, TRSRTransformation.identity());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,27 +4,35 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ModelBlock;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormatElement;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.model.IBakedModel;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class ItemLayerModel implements IRetexturableModel {
|
||||
|
||||
public static final ItemLayerModel instance = new ItemLayerModel(ImmutableList.<ResourceLocation>of());
|
||||
|
||||
private final ImmutableList<ResourceLocation> textures;
|
||||
|
||||
public ItemLayerModel(ImmutableList<ResourceLocation> textures)
|
||||
|
@ -75,29 +83,53 @@ public class ItemLayerModel implements IRetexturableModel {
|
|||
return new ItemLayerModel(builder.build());
|
||||
}
|
||||
|
||||
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
public IFlexibleBakedModel bake(IModelState state, final VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
final TRSRTransformation transform = state.apply(this);
|
||||
for(int i = 0; i < textures.size(); i++)
|
||||
{
|
||||
TextureAtlasSprite sprite = bakedTextureGetter.apply(textures.get(i));
|
||||
builder.addAll(getQuadsForSprite(i, sprite, format));
|
||||
builder.addAll(Iterables.transform(getQuadsForSprite(i, sprite, format), new Function<BakedQuad, BakedQuad>()
|
||||
{
|
||||
public BakedQuad apply(BakedQuad input)
|
||||
{
|
||||
return Attributes.transform(transform, input, format);
|
||||
}
|
||||
}));
|
||||
}
|
||||
TextureAtlasSprite particle = bakedTextureGetter.apply(textures.isEmpty() ? new ResourceLocation("missingno") : textures.get(0));
|
||||
if(state instanceof IPerspectiveState)
|
||||
{
|
||||
IPerspectiveState ps = (IPerspectiveState)state;
|
||||
Map<TransformType, TRSRTransformation> map = Maps.newHashMap();
|
||||
for(TransformType type : TransformType.values())
|
||||
{
|
||||
map.put(type, ps.forPerspective(type).apply(this));
|
||||
}
|
||||
return new BakedModel(builder.build(), particle, format, Maps.immutableEnumMap(map));
|
||||
}
|
||||
return new BakedModel(builder.build(), particle, format);
|
||||
}
|
||||
|
||||
public static class BakedModel implements IFlexibleBakedModel
|
||||
public static class BakedModel implements IFlexibleBakedModel, IPerspectiveAwareModel
|
||||
{
|
||||
private final ImmutableList<BakedQuad> quads;
|
||||
private final TextureAtlasSprite particle;
|
||||
private final VertexFormat format;
|
||||
private final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
|
||||
public BakedModel(ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format)
|
||||
{
|
||||
this(quads, particle, format, ImmutableMap.<TransformType, TRSRTransformation>of());
|
||||
}
|
||||
|
||||
public BakedModel(ImmutableList<BakedQuad> quads, TextureAtlasSprite particle, VertexFormat format, ImmutableMap<TransformType, TRSRTransformation> transforms)
|
||||
{
|
||||
this.quads = quads;
|
||||
this.particle = particle;
|
||||
this.format = format;
|
||||
this.transforms = transforms;
|
||||
}
|
||||
|
||||
public boolean isAmbientOcclusion() { return true; }
|
||||
|
@ -108,9 +140,17 @@ public class ItemLayerModel implements IRetexturableModel {
|
|||
public List<BakedQuad> getFaceQuads(EnumFacing side) { return ImmutableList.of(); }
|
||||
public List<BakedQuad> getGeneralQuads() { return quads; }
|
||||
public VertexFormat getFormat() { return format; }
|
||||
|
||||
@Override
|
||||
public Pair<IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
||||
{
|
||||
TRSRTransformation tr = transforms.getOrDefault(cameraTransformType, TRSRTransformation.identity());
|
||||
Matrix4f mat = tr == TRSRTransformation.identity() ? null : tr.getMatrix();
|
||||
return Pair.of((IBakedModel)this, mat);
|
||||
}
|
||||
}
|
||||
|
||||
public static final ImmutableList<BakedQuad> getQuadsForSprite(int tint, TextureAtlasSprite sprite, VertexFormat format)
|
||||
public ImmutableList<BakedQuad> getQuadsForSprite(int tint, TextureAtlasSprite sprite, VertexFormat format)
|
||||
{
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
|
@ -131,7 +171,7 @@ public class ItemLayerModel implements IRetexturableModel {
|
|||
ptu = true;
|
||||
for(int u = 0; u < uMax; u++)
|
||||
{
|
||||
boolean t = (pixels[u + (vMax - 1 - v) * uMax] >> 24 & 0xFF) == 0;
|
||||
boolean t = isTransparent(pixels, uMax, vMax, u, v);
|
||||
if(ptu && !t) // left - transparent, right - opaque
|
||||
{
|
||||
builder.add(buildSideQuad(buf, format, EnumFacing.WEST, tint, sprite, u, v));
|
||||
|
@ -182,6 +222,11 @@ public class ItemLayerModel implements IRetexturableModel {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
protected boolean isTransparent(int[] pixels, int uMax, int vMax, int u, int v)
|
||||
{
|
||||
return (pixels[u + (vMax - 1 - v) * uMax] >> 24 & 0xFF) == 0;
|
||||
}
|
||||
|
||||
private static BakedQuad buildSideQuad(ByteBuffer buf, VertexFormat format, EnumFacing side, int tint, TextureAtlasSprite sprite, int u, int v)
|
||||
{
|
||||
float x0 = (float)u / sprite.getIconWidth();
|
||||
|
|
|
@ -320,10 +320,11 @@ public class ModelLoader extends ModelBakery
|
|||
throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format);
|
||||
}
|
||||
ModelBlock model = this.model;
|
||||
if(hasItemModel(model)) return new ItemLayerModel(model).bake(state, format, bakedTextureGetter);//model = makeItemModel(model);
|
||||
if(model == null) return getMissingModel().bake(state, format, bakedTextureGetter);
|
||||
if(isCustomRenderer(model)) return new IFlexibleBakedModel.Wrapper(new BuiltInModel(new ItemCameraTransforms(model.getThirdPersonTransform(), model.getFirstPersonTransform(), model.getHeadTransform(), model.getInGuiTransform())), Attributes.DEFAULT_BAKED_FORMAT);
|
||||
return new IFlexibleBakedModel.Wrapper(bakeModel(model, state.apply(this), state instanceof UVLock), Attributes.DEFAULT_BAKED_FORMAT);
|
||||
ItemCameraTransforms transforms = new ItemCameraTransforms(model.getThirdPersonTransform(), model.getFirstPersonTransform(), model.getHeadTransform(), model.getInGuiTransform());
|
||||
if(hasItemModel(model)) return new ItemLayerModel(model).bake(new IPerspectiveState.Impl(state, transforms), format, bakedTextureGetter);
|
||||
if(isCustomRenderer(model)) return new IFlexibleBakedModel.Wrapper(new BuiltInModel(transforms), format);
|
||||
return new IFlexibleBakedModel.Wrapper(bakeModel(model, state.apply(this), state instanceof UVLock), format);
|
||||
}
|
||||
|
||||
public IModelState getDefaultState()
|
||||
|
|
|
@ -53,7 +53,7 @@ public class TRSRTransformation implements IModelState, ITransformation
|
|||
|
||||
public TRSRTransformation(ItemTransformVec3f transform)
|
||||
{
|
||||
this(transform.translation, quatFromYXZ(transform.rotation), transform.scale, null);
|
||||
this(transform.translation, quatFromYXZDegrees(transform.rotation), transform.scale, null);
|
||||
}
|
||||
|
||||
public TRSRTransformation(ModelRotation rotation)
|
||||
|
@ -97,6 +97,11 @@ public class TRSRTransformation implements IModelState, ITransformation
|
|||
}
|
||||
}
|
||||
|
||||
public static Quat4f quatFromYXZDegrees(Vector3f yxz)
|
||||
{
|
||||
return quatFromYXZ((float)Math.toRadians(yxz.y), (float)Math.toRadians(yxz.x), (float)Math.toRadians(yxz.z));
|
||||
}
|
||||
|
||||
public static Quat4f quatFromYXZ(Vector3f yxz)
|
||||
{
|
||||
return quatFromYXZ(yxz.y, yxz.x, yxz.z);
|
||||
|
|
Loading…
Reference in a new issue