2014-12-28 04:10:54 +00:00
|
|
|
package net.minecraftforge.client.model.b3d;
|
|
|
|
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.HashSet;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
import javax.vecmath.Matrix4f;
|
2015-06-28 22:19:10 +00:00
|
|
|
import javax.vecmath.Vector3f;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
import net.minecraft.block.state.IBlockState;
|
|
|
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
|
|
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
2015-06-22 22:03:16 +00:00
|
|
|
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
|
|
import net.minecraft.client.renderer.vertex.VertexFormat;
|
|
|
|
import net.minecraft.client.resources.IResource;
|
|
|
|
import net.minecraft.client.resources.IResourceManager;
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
import net.minecraft.util.EnumFacing;
|
2015-11-16 03:50:54 +00:00
|
|
|
import net.minecraft.util.MathHelper;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraft.util.ResourceLocation;
|
|
|
|
import net.minecraftforge.client.model.ICustomModelLoader;
|
|
|
|
import net.minecraftforge.client.model.IFlexibleBakedModel;
|
|
|
|
import net.minecraftforge.client.model.IModel;
|
2015-06-04 15:49:57 +00:00
|
|
|
import net.minecraftforge.client.model.IModelCustomData;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.client.model.IModelPart;
|
|
|
|
import net.minecraftforge.client.model.IModelState;
|
2015-06-22 22:03:16 +00:00
|
|
|
import net.minecraftforge.client.model.IPerspectiveAwareModel;
|
2015-06-04 15:49:57 +00:00
|
|
|
import net.minecraftforge.client.model.IRetexturableModel;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.client.model.ISmartBlockModel;
|
|
|
|
import net.minecraftforge.client.model.ISmartItemModel;
|
2015-02-17 00:36:08 +00:00
|
|
|
import net.minecraftforge.client.model.ModelLoader;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
|
|
|
import net.minecraftforge.client.model.TRSRTransformation;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Animation;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Face;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.IKind;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Key;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Mesh;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Node;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Texture;
|
|
|
|
import net.minecraftforge.client.model.b3d.B3DModel.Vertex;
|
2015-06-28 22:19:10 +00:00
|
|
|
import net.minecraftforge.client.model.pipeline.LightUtil;
|
|
|
|
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
|
2014-12-28 04:10:54 +00:00
|
|
|
import net.minecraftforge.common.property.IExtendedBlockState;
|
|
|
|
import net.minecraftforge.common.property.IUnlistedProperty;
|
|
|
|
import net.minecraftforge.fml.common.FMLLog;
|
|
|
|
|
|
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
|
|
import org.apache.commons.lang3.tuple.Triple;
|
|
|
|
|
|
|
|
import com.google.common.base.Function;
|
2015-12-03 19:38:08 +00:00
|
|
|
import com.google.common.base.Objects;
|
|
|
|
import com.google.common.base.Optional;
|
2015-06-04 15:49:57 +00:00
|
|
|
import com.google.common.base.Predicate;
|
2014-12-28 04:10:54 +00:00
|
|
|
import com.google.common.cache.CacheBuilder;
|
|
|
|
import com.google.common.cache.CacheLoader;
|
|
|
|
import com.google.common.cache.LoadingCache;
|
2015-06-04 15:49:57 +00:00
|
|
|
import com.google.common.collect.Collections2;
|
2014-12-28 04:10:54 +00:00
|
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
2015-11-16 03:50:54 +00:00
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
|
|
import com.google.gson.JsonElement;
|
|
|
|
import com.google.gson.JsonParser;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Loader for Blitz3D models.
|
|
|
|
* To enable for your mod call instance.addDomain(modid).
|
|
|
|
* If you need more control over accepted resources - extend the class, and register a new instance with ModelLoaderRegistry.
|
|
|
|
*/
|
2015-11-27 03:38:21 +00:00
|
|
|
@SuppressWarnings("deprecation")
|
2014-12-28 04:10:54 +00:00
|
|
|
public class B3DLoader implements ICustomModelLoader
|
|
|
|
{
|
|
|
|
public static final B3DLoader instance = new B3DLoader();
|
|
|
|
|
|
|
|
private IResourceManager manager;
|
|
|
|
|
|
|
|
private final Set<String> enabledDomains = new HashSet<String>();
|
|
|
|
private final Map<ResourceLocation, B3DModel> cache = new HashMap<ResourceLocation, B3DModel>();
|
|
|
|
|
|
|
|
public void addDomain(String domain)
|
|
|
|
{
|
|
|
|
enabledDomains.add(domain.toLowerCase());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void onResourceManagerReload(IResourceManager manager)
|
|
|
|
{
|
|
|
|
this.manager = manager;
|
|
|
|
cache.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean accepts(ResourceLocation modelLocation)
|
|
|
|
{
|
|
|
|
return enabledDomains.contains(modelLocation.getResourceDomain()) && modelLocation.getResourcePath().endsWith(".b3d");
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
2015-06-16 23:03:10 +00:00
|
|
|
public IModel loadModel(ResourceLocation modelLocation) throws IOException
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
|
|
|
|
if(!cache.containsKey(file))
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
IResource resource = null;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
resource = manager.getResource(file);
|
|
|
|
}
|
|
|
|
catch(FileNotFoundException e)
|
|
|
|
{
|
|
|
|
if(modelLocation.getResourcePath().startsWith("models/block/"))
|
|
|
|
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
|
|
|
|
else if(modelLocation.getResourcePath().startsWith("models/item/"))
|
|
|
|
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
|
|
|
|
else throw e;
|
|
|
|
}
|
|
|
|
B3DModel.Parser parser = new B3DModel.Parser(resource.getInputStream());
|
|
|
|
B3DModel model = parser.parse();
|
2015-06-14 20:34:59 +00:00
|
|
|
cache.put(file, model);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
catch(IOException e)
|
|
|
|
{
|
2015-06-16 23:03:10 +00:00
|
|
|
//FMLLog.log(Level.ERROR, e, "Exception loading model %s with B3D loader, skipping", modelLocation);
|
2015-06-14 20:34:59 +00:00
|
|
|
cache.put(file, null);
|
2015-06-16 23:03:10 +00:00
|
|
|
throw e;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
B3DModel model = cache.get(file);
|
|
|
|
if(model == null) return ModelLoaderRegistry.getMissingModel();
|
|
|
|
if(modelLocation instanceof B3DMeshLocation)
|
|
|
|
{
|
|
|
|
String mesh = ((B3DMeshLocation)modelLocation).getMesh();
|
|
|
|
if(!model.getMeshes().containsKey(mesh))
|
|
|
|
{
|
|
|
|
FMLLog.severe("No mesh named %s in model %s, skipping", mesh, modelLocation);
|
|
|
|
return ModelLoaderRegistry.getMissingModel();
|
|
|
|
}
|
2015-11-16 03:50:54 +00:00
|
|
|
return new ModelWrapper(modelLocation, model, ImmutableSet.of(mesh), 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
if(!(model.getRoot().getKind() instanceof Mesh))
|
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
return new ModelWrapper(modelLocation, model, ImmutableSet.<String>of(), 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-11-16 03:50:54 +00:00
|
|
|
return new ModelWrapper(modelLocation, model, ImmutableSet.of(((Node<Mesh>)model.getRoot()).getName()), 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-11-16 03:50:54 +00:00
|
|
|
/**
|
|
|
|
* @deprecated Use json or IModelCustomData.process
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2014-12-28 04:10:54 +00:00
|
|
|
public static class B3DMeshLocation extends ResourceLocation
|
|
|
|
{
|
|
|
|
public final String mesh;
|
|
|
|
|
|
|
|
public B3DMeshLocation(String domain, String path, String mesh)
|
|
|
|
{
|
|
|
|
super(domain, path);
|
|
|
|
this.mesh = mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getMesh()
|
|
|
|
{
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode()
|
|
|
|
{
|
|
|
|
final int prime = 31;
|
|
|
|
int result = super.hashCode();
|
|
|
|
result = prime * result + ((mesh == null) ? 0 : mesh.hashCode());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj)
|
|
|
|
{
|
|
|
|
if (this == obj) return true;
|
|
|
|
if (!super.equals(obj)) return false;
|
|
|
|
if (getClass() != obj.getClass()) return false;
|
|
|
|
B3DMeshLocation other = (B3DMeshLocation) obj;
|
|
|
|
if (mesh == null)
|
|
|
|
{
|
|
|
|
if (other.mesh != null) return false;
|
|
|
|
}
|
|
|
|
else if (!mesh.equals(other.mesh)) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class B3DState implements IModelState
|
|
|
|
{
|
|
|
|
private final Animation animation;
|
|
|
|
private final int frame;
|
2015-11-16 03:50:54 +00:00
|
|
|
private final int nextFrame;
|
|
|
|
private final float progress;
|
2015-06-22 22:03:16 +00:00
|
|
|
private final IModelState parent;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
public B3DState(Animation animation, int frame)
|
2015-06-22 22:03:16 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
this(animation, frame, frame, 0);
|
2015-06-22 22:03:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public B3DState(Animation animation, int frame, IModelState parent)
|
2015-11-16 03:50:54 +00:00
|
|
|
{
|
|
|
|
this(animation, frame, frame, 0, parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
public B3DState(Animation animation, int frame, int nextFrame, float progress)
|
|
|
|
{
|
|
|
|
this(animation, frame, nextFrame, progress, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public B3DState(Animation animation, int frame, int nextFrame, float progress, IModelState parent)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
this.animation = animation;
|
|
|
|
this.frame = frame;
|
2015-11-16 03:50:54 +00:00
|
|
|
this.nextFrame = nextFrame;
|
|
|
|
this.progress = MathHelper.clamp_float(progress, 0, 1);
|
2015-06-22 22:03:16 +00:00
|
|
|
this.parent = getParent(parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
private IModelState getParent(IModelState parent)
|
|
|
|
{
|
|
|
|
if (parent == null) return null;
|
|
|
|
else if (parent instanceof B3DState) return ((B3DState)parent).parent;
|
|
|
|
return parent;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Animation getAnimation()
|
|
|
|
{
|
|
|
|
return animation;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getFrame()
|
|
|
|
{
|
|
|
|
return frame;
|
|
|
|
}
|
|
|
|
|
2015-11-16 03:50:54 +00:00
|
|
|
public int getNextFrame()
|
|
|
|
{
|
|
|
|
return nextFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float getProgress()
|
|
|
|
{
|
|
|
|
return progress;
|
|
|
|
}
|
|
|
|
|
|
|
|
public IModelState getParent()
|
|
|
|
{
|
|
|
|
return parent;
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
public Optional<TRSRTransformation> apply(Optional<? extends IModelPart> part)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
// TODO optionify better
|
|
|
|
if(!part.isPresent()) return parent.apply(part);
|
|
|
|
if(!(part.get() instanceof NodeJoint))
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
return Optional.absent();
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
Node<?> node = ((NodeJoint)part.get()).getNode();
|
2015-11-16 03:50:54 +00:00
|
|
|
TRSRTransformation nodeTransform;
|
|
|
|
if(progress < 1e-5 || frame == nextFrame)
|
|
|
|
{
|
|
|
|
nodeTransform = getNodeMatrix(node, frame);
|
|
|
|
}
|
|
|
|
else if(progress > 1 - 1e-5)
|
|
|
|
{
|
|
|
|
nodeTransform = getNodeMatrix(node, nextFrame);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nodeTransform = getNodeMatrix(node, frame);
|
|
|
|
nodeTransform = nodeTransform.slerp(getNodeMatrix(node, nextFrame), progress);
|
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
if(parent != null && node.getParent() == null)
|
2015-06-22 22:03:16 +00:00
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
return Optional.of(parent.apply(part).or(TRSRTransformation.identity()).compose(nodeTransform));
|
2015-06-22 22:03:16 +00:00
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
return Optional.of(nodeTransform);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static LoadingCache<Triple<Animation, Node<?>, Integer>, TRSRTransformation> cache = CacheBuilder.newBuilder()
|
|
|
|
.maximumSize(16384)
|
|
|
|
.expireAfterAccess(2, TimeUnit.MINUTES)
|
|
|
|
.build(new CacheLoader<Triple<Animation, Node<?>, Integer>, TRSRTransformation>()
|
|
|
|
{
|
|
|
|
public TRSRTransformation load(Triple<Animation, Node<?>, Integer> key) throws Exception
|
|
|
|
{
|
|
|
|
return getNodeMatrix(key.getLeft(), key.getMiddle(), key.getRight());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
public TRSRTransformation getNodeMatrix(Node<?> node)
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
return getNodeMatrix(node, frame);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-11-16 03:50:54 +00:00
|
|
|
public TRSRTransformation getNodeMatrix(Node<?> node, int frame)
|
|
|
|
{
|
|
|
|
return cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node, frame));
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
public static TRSRTransformation getNodeMatrix(Animation animation, Node<?> node, int frame)
|
|
|
|
{
|
|
|
|
TRSRTransformation ret = TRSRTransformation.identity();
|
|
|
|
Key key = null;
|
|
|
|
if(animation != null) key = animation.getKeys().get(frame, node);
|
2015-11-19 20:40:44 +00:00
|
|
|
else if(node.getAnimation() != null && node.getAnimation() != animation) key = node.getAnimation().getKeys().get(frame, node);
|
2015-06-04 15:49:57 +00:00
|
|
|
if(key != null)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-04 15:49:57 +00:00
|
|
|
Node<?> parent = node.getParent();
|
|
|
|
if(parent != null)
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
// parent model-global current pose
|
2015-06-04 15:49:57 +00:00
|
|
|
TRSRTransformation pm = cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node.getParent(), frame));
|
|
|
|
ret = ret.compose(pm);
|
2015-12-03 19:38:08 +00:00
|
|
|
// joint offset in the parent coords
|
2015-06-04 15:49:57 +00:00
|
|
|
ret = ret.compose(new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null));
|
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
// current node local pose
|
2014-12-28 04:10:54 +00:00
|
|
|
ret = ret.compose(new TRSRTransformation(key.getPos(), key.getRot(), key.getScale(), null));
|
2015-12-03 19:38:08 +00:00
|
|
|
// this part moved inside the model
|
|
|
|
// inverse bind of the curent node
|
|
|
|
/*Matrix4f rm = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
|
2014-12-28 04:10:54 +00:00
|
|
|
rm.invert();
|
|
|
|
ret = ret.compose(new TRSRTransformation(rm));
|
2015-06-04 15:49:57 +00:00
|
|
|
if(parent != null)
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
// inverse bind of the parent
|
2015-06-04 15:49:57 +00:00
|
|
|
rm = new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null).getMatrix();
|
|
|
|
rm.invert();
|
|
|
|
ret = ret.compose(new TRSRTransformation(rm));
|
2015-12-03 19:38:08 +00:00
|
|
|
}*/
|
|
|
|
// TODO cache
|
|
|
|
TRSRTransformation invBind = new NodeJoint(node).getInvBindPose();
|
|
|
|
ret = ret.compose(invBind);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Node<?> parent = node.getParent();
|
|
|
|
if(parent != null)
|
|
|
|
{
|
|
|
|
// parent model-global current pose
|
|
|
|
TRSRTransformation pm = cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node.getParent(), frame));
|
|
|
|
ret = ret.compose(pm);
|
|
|
|
// joint offset in the parent coords
|
|
|
|
ret = ret.compose(new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null));
|
2015-06-04 15:49:57 +00:00
|
|
|
}
|
2015-12-03 19:38:08 +00:00
|
|
|
ret = ret.compose(new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null));
|
|
|
|
// TODO cache
|
|
|
|
TRSRTransformation invBind = new NodeJoint(node).getInvBindPose();
|
|
|
|
ret = ret.compose(invBind);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
public static class NodeJoint implements IModelPart
|
|
|
|
{
|
|
|
|
private final Node<?> node;
|
|
|
|
|
|
|
|
public NodeJoint(Node<?> node)
|
|
|
|
{
|
|
|
|
this.node = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TRSRTransformation getInvBindPose()
|
|
|
|
{
|
|
|
|
Matrix4f m = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
|
|
|
|
m.invert();
|
|
|
|
TRSRTransformation pose = new TRSRTransformation(m);
|
|
|
|
|
|
|
|
if(node.getParent() != null)
|
|
|
|
{
|
|
|
|
TRSRTransformation parent = new NodeJoint(node.getParent()).getInvBindPose();
|
|
|
|
pose = pose.compose(parent);
|
|
|
|
}
|
|
|
|
return pose;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<NodeJoint> getParent()
|
|
|
|
{
|
|
|
|
// FIXME cache?
|
|
|
|
if(node.getParent() == null) return Optional.absent();
|
|
|
|
return Optional.of(new NodeJoint(node.getParent()));
|
|
|
|
}
|
|
|
|
|
|
|
|
public Node<?> getNode()
|
|
|
|
{
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode()
|
|
|
|
{
|
|
|
|
return node.hashCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj)
|
|
|
|
{
|
|
|
|
if (this == obj) return true;
|
|
|
|
if (!super.equals(obj)) return false;
|
|
|
|
if (getClass() != obj.getClass()) return false;
|
|
|
|
NodeJoint other = (NodeJoint) obj;
|
|
|
|
return Objects.equal(node, other.node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
public static enum B3DFrameProperty implements IUnlistedProperty<B3DState>
|
|
|
|
{
|
|
|
|
instance;
|
|
|
|
public String getName()
|
|
|
|
{
|
|
|
|
return "B3DFrame";
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isValid(B3DState value)
|
|
|
|
{
|
|
|
|
return value instanceof B3DState;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Class<B3DState> getType()
|
|
|
|
{
|
|
|
|
return B3DState.class;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String valueToString(B3DState value)
|
|
|
|
{
|
|
|
|
return value.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class PartWrapper<K extends IKind<K>> implements IModelPart
|
|
|
|
{
|
|
|
|
private final Node<K> node;
|
|
|
|
|
|
|
|
public static <K extends IKind<K>> PartWrapper<K> create(Node<K> node)
|
|
|
|
{
|
|
|
|
return new PartWrapper<K>(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
public PartWrapper(Node<K> node)
|
|
|
|
{
|
|
|
|
this.node = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Node<K> getNode()
|
|
|
|
{
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-16 03:50:54 +00:00
|
|
|
/**
|
|
|
|
* @deprecated Use ModelWrapper, this will be removed in 1.9
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2015-06-04 15:49:57 +00:00
|
|
|
public static class Wrapper extends PartWrapper<Mesh> implements IRetexturableModel, IModelCustomData
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
private final ResourceLocation location;
|
2015-11-16 03:50:54 +00:00
|
|
|
private final ImmutableSet<String> meshes;
|
2014-12-28 04:10:54 +00:00
|
|
|
private final ImmutableMap<String, ResourceLocation> textures;
|
|
|
|
|
|
|
|
public Wrapper(ResourceLocation location, List<Texture> textures, B3DModel.Node<Mesh> mesh)
|
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
this(location, ImmutableSet.<String>of(), buildTextures(textures), mesh);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Wrapper(ResourceLocation location, ImmutableMap<String, ResourceLocation> textures, B3DModel.Node<Mesh> mesh)
|
2015-11-16 03:50:54 +00:00
|
|
|
{
|
|
|
|
this(location, ImmutableSet.<String>of(), textures, mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Wrapper(ResourceLocation location, ImmutableSet<String> meshes, List<Texture> textures, B3DModel.Node<Mesh> mesh)
|
|
|
|
{
|
|
|
|
this(location, meshes, buildTextures(textures), mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Wrapper(ResourceLocation location, ImmutableSet<String> meshes, ImmutableMap<String, ResourceLocation> textures, B3DModel.Node<Mesh> mesh)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
super(mesh);
|
|
|
|
this.location = location;
|
2015-11-16 03:50:54 +00:00
|
|
|
this.meshes = meshes;
|
2014-12-28 04:10:54 +00:00
|
|
|
this.textures = textures;
|
|
|
|
}
|
|
|
|
|
2015-06-04 15:49:57 +00:00
|
|
|
private static ImmutableMap<String, ResourceLocation> buildTextures(List<Texture> textures)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
|
|
|
|
|
|
|
for(Texture t : textures)
|
|
|
|
{
|
|
|
|
String path = t.getPath();
|
2015-10-03 01:42:35 +00:00
|
|
|
String location = getLocation(path);
|
|
|
|
if(!location.startsWith("#")) location = "#" + location;
|
|
|
|
builder.put(path, new ResourceLocation(location));
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
2015-06-04 15:49:57 +00:00
|
|
|
private static String getLocation(String path)
|
|
|
|
{
|
|
|
|
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2014-12-28 04:10:54 +00:00
|
|
|
public Collection<ResourceLocation> getDependencies()
|
|
|
|
{
|
|
|
|
// no dependencies for in-file models
|
|
|
|
// FIXME maybe add child meshes
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
|
|
|
public Collection<ResourceLocation> getTextures()
|
|
|
|
{
|
2015-06-04 15:49:57 +00:00
|
|
|
return Collections2.filter(textures.values(), new Predicate<ResourceLocation>()
|
|
|
|
{
|
|
|
|
public boolean apply(ResourceLocation loc)
|
|
|
|
{
|
|
|
|
return !loc.getResourcePath().startsWith("#");
|
|
|
|
}
|
|
|
|
});
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
|
2015-06-04 15:49:57 +00:00
|
|
|
TextureAtlasSprite missing = bakedTextureGetter.apply(new ResourceLocation("missingno"));
|
|
|
|
for(Map.Entry<String, ResourceLocation> e : textures.entrySet())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-04 15:49:57 +00:00
|
|
|
if(e.getValue().getResourcePath().startsWith("#"))
|
|
|
|
{
|
|
|
|
FMLLog.severe("unresolved texture '%s' for b3d model '%s'", e.getValue().getResourcePath(), location);
|
|
|
|
builder.put(e.getKey(), missing);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
builder.put(e.getKey(), bakedTextureGetter.apply(e.getValue()));
|
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-06-04 15:49:57 +00:00
|
|
|
builder.put("missingno", missing);
|
2015-11-16 03:50:54 +00:00
|
|
|
return new BakedWrapper(getNode(), state, format, meshes, builder.build());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public B3DState getDefaultState()
|
|
|
|
{
|
|
|
|
return new B3DState(getNode().getAnimation(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ResourceLocation getLocation()
|
|
|
|
{
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ImmutableMap<String, ResourceLocation> getTextureMap()
|
|
|
|
{
|
|
|
|
return textures;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode()
|
|
|
|
{
|
|
|
|
final int prime = 31;
|
|
|
|
int result = 1;
|
|
|
|
result = prime * result + ((location == null) ? 0 : location.hashCode());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object obj)
|
|
|
|
{
|
|
|
|
if (this == obj) return true;
|
|
|
|
if (obj == null) return false;
|
|
|
|
if (getClass() != obj.getClass()) return false;
|
|
|
|
Wrapper other = (Wrapper) obj;
|
|
|
|
if (location == null)
|
|
|
|
{
|
|
|
|
if (other.location != null) return false;
|
|
|
|
}
|
|
|
|
else if (!location.equals(other.location)) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2015-06-04 15:49:57 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModel retexture(ImmutableMap<String, String> textures)
|
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
|
|
|
for(Map.Entry<String, ResourceLocation> e : this.textures.entrySet())
|
|
|
|
{
|
|
|
|
String path = e.getKey();
|
|
|
|
String loc = getLocation(path);
|
|
|
|
if(textures.containsKey(loc))
|
|
|
|
{
|
|
|
|
String newLoc = textures.get(loc);
|
|
|
|
if(newLoc == null) newLoc = getLocation(path);
|
|
|
|
builder.put(e.getKey(), new ResourceLocation(newLoc));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
builder.put(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new Wrapper(location, builder.build(), getNode());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModel process(ImmutableMap<String, String> customData)
|
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public static class ModelWrapper implements IRetexturableModel, IModelCustomData
|
|
|
|
{
|
|
|
|
private final ResourceLocation modelLocation;
|
|
|
|
private final B3DModel model;
|
|
|
|
private final ImmutableSet<String> meshes;
|
|
|
|
private final ImmutableMap<String, ResourceLocation> textures;
|
|
|
|
private final int defaultKey;
|
|
|
|
|
|
|
|
public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet<String> meshes, int defaultKey)
|
|
|
|
{
|
|
|
|
this(modelLocation, model, meshes, defaultKey, buildTextures(model.getTextures()));
|
|
|
|
}
|
|
|
|
|
|
|
|
public ModelWrapper(ResourceLocation modelLocation, B3DModel model, ImmutableSet<String> meshes, int defaultKey, ImmutableMap<String, ResourceLocation> textures)
|
|
|
|
{
|
|
|
|
this.modelLocation = modelLocation;
|
|
|
|
this.model = model;
|
|
|
|
this.meshes = meshes;
|
|
|
|
this.textures = textures;
|
|
|
|
this.defaultKey = defaultKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static ImmutableMap<String, ResourceLocation> buildTextures(List<Texture> textures)
|
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
|
|
|
|
|
|
|
for(Texture t : textures)
|
|
|
|
{
|
|
|
|
String path = t.getPath();
|
|
|
|
String location = getLocation(path);
|
|
|
|
if(!location.startsWith("#")) location = "#" + location;
|
|
|
|
builder.put(path, new ResourceLocation(location));
|
|
|
|
}
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String getLocation(String path)
|
|
|
|
{
|
|
|
|
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Collection<ResourceLocation> getDependencies()
|
|
|
|
{
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Collection<ResourceLocation> getTextures()
|
|
|
|
{
|
|
|
|
return Collections2.filter(textures.values(), new Predicate<ResourceLocation>()
|
|
|
|
{
|
|
|
|
public boolean apply(ResourceLocation loc)
|
|
|
|
{
|
|
|
|
return !loc.getResourcePath().startsWith("#");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
|
|
|
|
TextureAtlasSprite missing = bakedTextureGetter.apply(new ResourceLocation("missingno"));
|
|
|
|
for(Map.Entry<String, ResourceLocation> e : textures.entrySet())
|
|
|
|
{
|
|
|
|
if(e.getValue().getResourcePath().startsWith("#"))
|
|
|
|
{
|
|
|
|
FMLLog.severe("unresolved texture '%s' for b3d model '%s'", e.getValue().getResourcePath(), modelLocation);
|
|
|
|
builder.put(e.getKey(), missing);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
builder.put(e.getKey(), bakedTextureGetter.apply(e.getValue()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
builder.put("missingno", missing);
|
|
|
|
return new BakedWrapper(model.getRoot(), state, format, meshes, builder.build());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModelState getDefaultState()
|
|
|
|
{
|
|
|
|
return new B3DState(model.getRoot().getAnimation(), defaultKey, defaultKey, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModel retexture(ImmutableMap<String, String> textures)
|
|
|
|
{
|
|
|
|
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
|
|
|
|
for(Map.Entry<String, ResourceLocation> e : this.textures.entrySet())
|
|
|
|
{
|
|
|
|
String path = e.getKey();
|
|
|
|
String loc = getLocation(path);
|
|
|
|
if(textures.containsKey(loc))
|
|
|
|
{
|
|
|
|
String newLoc = textures.get(loc);
|
|
|
|
if(newLoc == null) newLoc = getLocation(path);
|
|
|
|
builder.put(e.getKey(), new ResourceLocation(newLoc));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
builder.put(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new ModelWrapper(modelLocation, model, meshes, defaultKey, builder.build());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IModel process(ImmutableMap<String, String> data)
|
|
|
|
{
|
|
|
|
if(data.containsKey("mesh"))
|
|
|
|
{
|
|
|
|
JsonElement e = new JsonParser().parse(data.get("mesh"));
|
|
|
|
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isString())
|
|
|
|
{
|
|
|
|
return new ModelWrapper(modelLocation, model, ImmutableSet.of(e.getAsString()), defaultKey, textures);
|
|
|
|
}
|
|
|
|
else if (e.isJsonArray())
|
|
|
|
{
|
|
|
|
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
|
|
|
|
for(JsonElement s : e.getAsJsonArray())
|
|
|
|
{
|
|
|
|
if(s.isJsonPrimitive() && s.getAsJsonPrimitive().isString())
|
|
|
|
{
|
|
|
|
builder.add(s.getAsString());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FMLLog.severe("unknown mesh definition '%s' in array for b3d model '%s'", s.toString(), modelLocation);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new ModelWrapper(modelLocation, model, builder.build(), defaultKey, textures);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FMLLog.severe("unknown mesh definition '%s' for b3d model '%s'", e.toString(), modelLocation);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(data.containsKey("key"))
|
|
|
|
{
|
|
|
|
JsonElement e = new JsonParser().parse(data.get("key"));
|
|
|
|
if(e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber())
|
|
|
|
{
|
|
|
|
return new ModelWrapper(modelLocation, model, meshes, e.getAsNumber().intValue(), textures);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FMLLog.severe("unknown keyframe definition '%s' for b3d model '%s'", e.toString(), modelLocation);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
2015-06-04 15:49:57 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 22:03:16 +00:00
|
|
|
private static class BakedWrapper implements IFlexibleBakedModel, ISmartBlockModel, ISmartItemModel, IPerspectiveAwareModel
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
private final Node<?> node;
|
2014-12-28 04:10:54 +00:00
|
|
|
private final IModelState state;
|
|
|
|
private final VertexFormat format;
|
2015-11-16 03:50:54 +00:00
|
|
|
private final ImmutableSet<String> meshes;
|
2014-12-28 04:10:54 +00:00
|
|
|
private final ImmutableMap<String, TextureAtlasSprite> textures;
|
2015-11-16 03:50:54 +00:00
|
|
|
private final LoadingCache<Integer, BakedWrapper> cache;
|
2014-12-28 04:10:54 +00:00
|
|
|
|
|
|
|
private ImmutableList<BakedQuad> quads;
|
|
|
|
|
2015-11-19 20:40:44 +00:00
|
|
|
public BakedWrapper(final Node<?> node, final IModelState state, final VertexFormat format, final ImmutableSet<String> meshes, final ImmutableMap<String, TextureAtlasSprite> textures)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
this(node, state, format, meshes, textures, CacheBuilder.newBuilder()
|
|
|
|
.maximumSize(128)
|
|
|
|
.expireAfterAccess(2, TimeUnit.MINUTES)
|
2015-12-09 11:56:01 +00:00
|
|
|
.<Integer, BakedWrapper>build(new CacheLoader<Integer, BakedWrapper>()
|
2015-11-16 03:50:54 +00:00
|
|
|
{
|
|
|
|
public BakedWrapper load(Integer frame) throws Exception
|
|
|
|
{
|
|
|
|
IModelState parent = state;
|
2015-11-19 20:40:44 +00:00
|
|
|
Animation newAnimation = node.getAnimation();
|
2015-11-16 03:50:54 +00:00
|
|
|
if(parent instanceof B3DState)
|
|
|
|
{
|
|
|
|
B3DState ps = (B3DState)parent;
|
|
|
|
parent = ps.getParent();
|
|
|
|
}
|
|
|
|
return new BakedWrapper(node, new B3DState(newAnimation, frame, frame, 0, parent), format, meshes, textures);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
public BakedWrapper(Node<?> node, IModelState state, VertexFormat format, ImmutableSet<String> meshes, ImmutableMap<String, TextureAtlasSprite> textures, LoadingCache<Integer, BakedWrapper> cache)
|
|
|
|
{
|
|
|
|
this.node = node;
|
2014-12-28 04:10:54 +00:00
|
|
|
this.state = state;
|
|
|
|
this.format = format;
|
2015-11-16 03:50:54 +00:00
|
|
|
this.meshes = meshes;
|
2014-12-28 04:10:54 +00:00
|
|
|
this.textures = textures;
|
2015-11-16 03:50:54 +00:00
|
|
|
this.cache = cache;
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<BakedQuad> getFaceQuads(EnumFacing side)
|
|
|
|
{
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<BakedQuad> getGeneralQuads()
|
|
|
|
{
|
|
|
|
if(quads == null)
|
|
|
|
{
|
|
|
|
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
2015-11-16 03:50:54 +00:00
|
|
|
for(Node<?> child : node.getNodes().values())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
builder.addAll(new BakedWrapper(child, state, format, meshes, textures).getGeneralQuads());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
2015-11-16 03:50:54 +00:00
|
|
|
if(node.getKind() instanceof Mesh && meshes.contains(node.getName()))
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
Mesh mesh = (Mesh)node.getKind();
|
|
|
|
Collection<Face> faces = mesh.bake(new Function<Node<?>, Matrix4f>()
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
private final TRSRTransformation global = state.apply(Optional.<IModelPart>absent()).or(TRSRTransformation.identity());
|
2015-11-16 03:50:54 +00:00
|
|
|
public Matrix4f apply(Node<?> node)
|
|
|
|
{
|
2015-12-03 19:38:08 +00:00
|
|
|
return global.compose(state.apply(Optional.of(new NodeJoint(node))).or(TRSRTransformation.identity())).getMatrix();
|
2015-11-16 03:50:54 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
for(Face f : faces)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
UnpackedBakedQuad.Builder quadBuilder = new UnpackedBakedQuad.Builder(format);
|
|
|
|
quadBuilder.setQuadOrientation(EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z));
|
|
|
|
quadBuilder.setQuadColored();
|
|
|
|
List<Texture> textures = null;
|
|
|
|
if(f.getBrush() != null) textures = f.getBrush().getTextures();
|
|
|
|
TextureAtlasSprite sprite;
|
|
|
|
if(textures == null || textures.isEmpty()) sprite = this.textures.get("missingno");
|
|
|
|
else if(textures.get(0) == B3DModel.Texture.White) sprite = ModelLoader.White.instance;
|
|
|
|
else sprite = this.textures.get(textures.get(0).getPath());
|
|
|
|
putVertexData(quadBuilder, f.getV1(), f.getNormal(), sprite);
|
|
|
|
putVertexData(quadBuilder, f.getV2(), f.getNormal(), sprite);
|
|
|
|
putVertexData(quadBuilder, f.getV3(), f.getNormal(), sprite);
|
|
|
|
putVertexData(quadBuilder, f.getV3(), f.getNormal(), sprite);
|
|
|
|
builder.add(quadBuilder.build());
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
quads = builder.build();
|
|
|
|
}
|
|
|
|
return quads;
|
|
|
|
}
|
|
|
|
|
2015-06-28 22:19:10 +00:00
|
|
|
private final void putVertexData(UnpackedBakedQuad.Builder builder, Vertex v, Vector3f faceNormal, TextureAtlasSprite sprite)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
// TODO handle everything not handled (texture transformations, bones, transformations, normals, e.t.c)
|
2015-06-28 22:19:10 +00:00
|
|
|
for(int e = 0; e < format.getElementCount(); e++)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
switch(format.getElement(e).getUsage())
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
|
|
|
case POSITION:
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e, v.getPos().x, v.getPos().y, v.getPos().z, 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
break;
|
|
|
|
case COLOR:
|
2015-06-28 22:19:10 +00:00
|
|
|
float d = LightUtil.diffuseLight(faceNormal.x, faceNormal.y, faceNormal.z);
|
2014-12-28 04:10:54 +00:00
|
|
|
if(v.getColor() != null)
|
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e, d * v.getColor().x, d * v.getColor().y, d * v.getColor().z, v.getColor().w);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e, d, d, d, 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UV:
|
|
|
|
// TODO handle more brushes
|
2015-06-28 22:19:10 +00:00
|
|
|
if(format.getElement(e).getIndex() < v.getTexCoords().length)
|
2014-12-28 04:10:54 +00:00
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e,
|
2014-12-28 04:10:54 +00:00
|
|
|
sprite.getInterpolatedU(v.getTexCoords()[0].x * 16),
|
|
|
|
sprite.getInterpolatedV(v.getTexCoords()[0].y * 16),
|
2015-06-28 22:19:10 +00:00
|
|
|
0,
|
|
|
|
1
|
2014-12-28 04:10:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e, 0, 0, 0, 1);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NORMAL:
|
2015-06-28 22:19:10 +00:00
|
|
|
if(v.getNormal() != null)
|
|
|
|
{
|
2015-10-29 19:50:45 +00:00
|
|
|
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 0);
|
2015-06-28 22:19:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-10-29 19:50:45 +00:00
|
|
|
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 0);
|
2015-06-28 22:19:10 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
break;
|
|
|
|
default:
|
2015-06-28 22:19:10 +00:00
|
|
|
builder.put(e);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isAmbientOcclusion()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isGui3d()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isBuiltInRenderer()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public TextureAtlasSprite getTexture()
|
|
|
|
{
|
|
|
|
// FIXME somehow specify particle texture in the model
|
|
|
|
return textures.values().asList().get(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ItemCameraTransforms getItemCameraTransforms()
|
|
|
|
{
|
|
|
|
return ItemCameraTransforms.DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public BakedWrapper handleBlockState(IBlockState state)
|
|
|
|
{
|
|
|
|
if(state instanceof IExtendedBlockState)
|
|
|
|
{
|
|
|
|
IExtendedBlockState exState = (IExtendedBlockState)state;
|
|
|
|
if(exState.getUnlistedNames().contains(B3DFrameProperty.instance))
|
|
|
|
{
|
2015-07-28 21:23:34 +00:00
|
|
|
B3DState s = exState.getValue(B3DFrameProperty.instance);
|
2014-12-28 04:10:54 +00:00
|
|
|
if(s != null)
|
|
|
|
{
|
2015-11-16 03:50:54 +00:00
|
|
|
//return getCachedModel(s.getFrame());
|
|
|
|
IModelState parent = this.state;
|
|
|
|
Animation newAnimation = s.getAnimation();
|
|
|
|
if(parent instanceof B3DState)
|
|
|
|
{
|
|
|
|
B3DState ps = (B3DState)parent;
|
|
|
|
parent = ps.getParent();
|
|
|
|
}
|
|
|
|
if(newAnimation == null)
|
|
|
|
{
|
|
|
|
newAnimation = node.getAnimation();
|
|
|
|
}
|
|
|
|
if(s.getFrame() == s.getNextFrame())
|
|
|
|
{
|
|
|
|
return cache.getUnchecked(s.getFrame());
|
|
|
|
}
|
|
|
|
B3DState newState = new B3DState(newAnimation, s.getFrame(), s.getNextFrame(), s.getProgress(), parent);
|
|
|
|
return new BakedWrapper(node, newState, format, meshes, textures);
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public VertexFormat getFormat()
|
|
|
|
{
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
|
|
|
|
public BakedWrapper handleItemState(ItemStack stack)
|
|
|
|
{
|
|
|
|
// TODO specify how to get B3DState from ItemStack
|
|
|
|
return this;
|
|
|
|
}
|
2015-06-22 22:03:16 +00:00
|
|
|
|
2015-12-03 19:38:08 +00:00
|
|
|
public Pair<? extends IFlexibleBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType)
|
2015-06-22 22:03:16 +00:00
|
|
|
{
|
2015-12-15 18:49:19 +00:00
|
|
|
return IPerspectiveAwareModel.MapWrapper.handlePerspective(this, state, cameraTransformType);
|
2015-06-22 22:03:16 +00:00
|
|
|
}
|
2014-12-28 04:10:54 +00:00
|
|
|
}
|
|
|
|
}
|