B3D Improvements

- fixed keyframe transformation application
 - textures are now resolved the same way as in vanilla models
 - added the ability to use forge blockstate texture information
 - removed unused code from the B3D example
This commit is contained in:
RainWarrior 2015-06-04 18:49:57 +03:00
parent 581363fddd
commit d6bc936ffa
5 changed files with 96 additions and 133 deletions

View file

@ -30,8 +30,10 @@ import net.minecraftforge.client.model.IColoredBakedQuad.ColoredBakedQuad;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IFlexibleBakedModel;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.IModelCustomData;
import net.minecraftforge.client.model.IModelPart;
import net.minecraftforge.client.model.IModelState;
import net.minecraftforge.client.model.IRetexturableModel;
import net.minecraftforge.client.model.ISmartBlockModel;
import net.minecraftforge.client.model.ISmartItemModel;
import net.minecraftforge.client.model.ModelLoader;
@ -56,11 +58,14 @@ import org.apache.logging.log4j.Level;
import org.lwjgl.BufferUtils;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
/*
@ -238,24 +243,28 @@ public class B3DLoader implements ICustomModelLoader
public static TRSRTransformation getNodeMatrix(Animation animation, Node<?> node, int frame)
{
TRSRTransformation ret = TRSRTransformation.identity();
if(node.getParent() != null)
{
TRSRTransformation pm = cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node.getParent(), frame));
ret = ret.compose(pm);
}
Key key = null;
if(animation != null) key = animation.getKeys().get(frame, node);
else if(key == null && node.getAnimation() != null && node.getAnimation() != animation) key = node.getAnimation().getKeys().get(frame, node);
if(key == null)
{
FMLLog.severe("invalid key index: " + frame);
}
else
if(key != null)
{
Node<?> parent = node.getParent();
if(parent != null)
{
TRSRTransformation pm = cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node.getParent(), frame));
ret = ret.compose(pm);
ret = ret.compose(new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null));
}
ret = ret.compose(new TRSRTransformation(key.getPos(), key.getRot(), key.getScale(), null));
Matrix4f rm = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
rm.invert();
ret = ret.compose(new TRSRTransformation(rm));
if(parent != null)
{
rm = new TRSRTransformation(parent.getPos(), parent.getRot(), parent.getScale(), null).getMatrix();
rm.invert();
ret = ret.compose(new TRSRTransformation(rm));
}
}
return ret;
}
@ -305,14 +314,14 @@ public class B3DLoader implements ICustomModelLoader
}
}
public static class Wrapper extends PartWrapper<Mesh> implements IModel
public static class Wrapper extends PartWrapper<Mesh> implements IRetexturableModel, IModelCustomData
{
private final ResourceLocation location;
private final ImmutableMap<String, ResourceLocation> textures;
public Wrapper(ResourceLocation location, List<Texture> textures, B3DModel.Node<Mesh> mesh)
{
this(location, buildTextures(location, textures), mesh);
this(location, buildTextures(textures), mesh);
}
public Wrapper(ResourceLocation location, ImmutableMap<String, ResourceLocation> textures, B3DModel.Node<Mesh> mesh)
@ -322,19 +331,24 @@ public class B3DLoader implements ICustomModelLoader
this.textures = textures;
}
private static ImmutableMap<String, ResourceLocation> buildTextures(ResourceLocation location, List<Texture> textures)
private static ImmutableMap<String, ResourceLocation> buildTextures(List<Texture> textures)
{
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
for(Texture t : textures)
{
String path = t.getPath();
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
builder.put(t.getPath(), new ResourceLocation(location.getResourceDomain(), path));
builder.put(path, new ResourceLocation(getLocation(path)));
}
return builder.build();
}
private static String getLocation(String path)
{
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
return path;
}
public Collection<ResourceLocation> getDependencies()
{
// no dependencies for in-file models
@ -344,17 +358,32 @@ public class B3DLoader implements ICustomModelLoader
public Collection<ResourceLocation> getTextures()
{
return textures.values();
return Collections2.filter(textures.values(), new Predicate<ResourceLocation>()
{
public boolean apply(ResourceLocation loc)
{
return !loc.getResourcePath().startsWith("#");
}
});
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
for(String path : textures.keySet())
TextureAtlasSprite missing = bakedTextureGetter.apply(new ResourceLocation("missingno"));
for(Map.Entry<String, ResourceLocation> e : textures.entrySet())
{
builder.put(path, bakedTextureGetter.apply(textures.get(path)));
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()));
}
}
builder.put("missingno", bakedTextureGetter.apply(new ResourceLocation("missingno")));
builder.put("missingno", missing);
return new BakedWrapper(this, state, format, builder.build());
}
@ -396,6 +425,35 @@ public class B3DLoader implements ICustomModelLoader
else if (!location.equals(other.location)) return false;
return true;
}
@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)
{
// TODO keyframe
return null;
}
}
private static class BakedWrapper implements IFlexibleBakedModel, ISmartBlockModel, ISmartItemModel
@ -454,9 +512,10 @@ public class B3DLoader implements ICustomModelLoader
for(Face f : faces)
{
buf.clear();
List<Texture> textures = f.getBrush().getTextures();
List<Texture> textures = null;
if(f.getBrush() != null) textures = f.getBrush().getTextures();
TextureAtlasSprite sprite;
if(textures.isEmpty()) sprite = this.textures.get("missingno");
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(f.getV1(), sprite);

View file

@ -64,14 +64,9 @@ public class ModelLoaderRegistryDebug
private void clientPreInit()
{
//ModelLoaderRegistry.registerLoader(DummyModelLoader.instance);
B3DLoader.instance.addDomain(MODID.toLowerCase());
//ModelBakery.addVariantName(Item.getItemFromBlock(CustomModelBlock.instance), "forgedebug:dummymodel");
String modelLocation = MODID.toLowerCase() + ":untitled2.b3d";
ModelBakery.addVariantName(Item.getItemFromBlock(CustomModelBlock.instance), modelLocation);
Item item = Item.getItemFromBlock(CustomModelBlock.instance);
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(modelLocation, "inventory"));
//ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation("forgedebug:dummymodel", "inventory"));
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(MODID.toLowerCase() + ":" + CustomModelBlock.name, "inventory"));
}
public static class CustomModelBlock extends Block
@ -100,9 +95,7 @@ public class ModelLoaderRegistryDebug
@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos)
{
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase(),"block/untitled2.b3d"));
B3DLoader.B3DState defaultState = ((B3DLoader.Wrapper)model).getDefaultState();
B3DLoader.B3DState newState = new B3DLoader.B3DState(defaultState.getAnimation(), counter);
B3DLoader.B3DState newState = new B3DLoader.B3DState(null, counter);
return ((IExtendedBlockState)this.state.getBaseState()).withProperty(B3DLoader.B3DFrameProperty.instance, newState);
}
@ -120,106 +113,4 @@ public class ModelLoaderRegistryDebug
return false;
}
}
public static class DummyModelLoader implements ICustomModelLoader
{
public static final DummyModelLoader instance = new DummyModelLoader();
public static final ResourceLocation dummyTexture = new ResourceLocation("minecraft:blocks/dirt");
public boolean accepts(ResourceLocation modelLocation)
{
return modelLocation.getResourceDomain().equals("forgedebug") && modelLocation.getResourcePath().contains("dummymodel");
}
public IModel loadModel(ResourceLocation model)
{
return DummyModel.instance;
}
public static enum DummyModel implements IModel
{
instance;
public Collection<ResourceLocation> getDependencies()
{
return Collections.emptyList();
}
public Collection<ResourceLocation> getTextures()
{
return Collections.singletonList(dummyTexture);
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> textures)
{
return new DummyBakedModel(textures.apply(dummyTexture));
}
public IModelState getDefaultState()
{
return ModelRotation.X0_Y0;
}
}
public static class DummyBakedModel implements IFlexibleBakedModel
{
private final TextureAtlasSprite texture;
public DummyBakedModel(TextureAtlasSprite texture)
{
this.texture = texture;
}
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return Collections.emptyList();
}
private int[] vertexToInts(float x, float y, float z, int color, float u, float v)
{
return new int[] {
Float.floatToRawIntBits(x),
Float.floatToRawIntBits(y),
Float.floatToRawIntBits(z),
color,
Float.floatToRawIntBits(texture.getInterpolatedU(u)),
Float.floatToRawIntBits(texture.getInterpolatedV(v)),
0
};
}
public List<BakedQuad> getGeneralQuads()
{
List<BakedQuad> ret = new ArrayList<BakedQuad>();
// 1 half-way rotated quad looking UP
ret.add(new BakedQuad(Ints.concat(
vertexToInts(0, .5f, .5f, -1, 0, 0),
vertexToInts(.5f, .5f, 1, -1, 0, 16),
vertexToInts(1, .5f, .5f, -1, 16, 16),
vertexToInts(.5f, .5f, 0, -1, 16, 0)
), -1, EnumFacing.UP));
return ret;
}
public boolean isGui3d() { return true; }
public boolean isAmbientOcclusion() { return true; }
public boolean isBuiltInRenderer() { return false; }
public TextureAtlasSprite getTexture() { return this.texture; }
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
public VertexFormat getFormat()
{
return Attributes.DEFAULT_BAKED_FORMAT;
}
}
public void onResourceManagerReload(IResourceManager resourceManager) {}
}
}

View file

@ -1,5 +1,18 @@
{
"forge_marker": 1,
"defaults": {
"textures": {
"#texture": "forgedebugmodelloaderregistry:texture",
"#chest": "entity/chest/normal"
},
"model": "forgedebugmodelloaderregistry:chest.b3d"
},
"variants": {
"normal" : { "model" : "forgedebugmodelloaderregistry:untitled2.b3d" }
"normal": {
"dummy": ""
},
"inventory": {
"dummy": ""
}
}
}