Fixed perspective transformations for item models.

This commit is contained in:
RainWarrior 2015-06-23 15:55:58 +03:00
parent d7c4a06ce8
commit 510b5523d5
6 changed files with 154 additions and 13 deletions

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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());
}
}
}

View file

@ -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();

View file

@ -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()

View file

@ -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);