Created
June 29, 2015 15:32
-
-
Save StillManic/ace8963c06c76c7758da to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"forge_marker": 1, | |
"defaults": { | |
"textures": {}, | |
"model": "forgedebugmodelloaderregistry:eye.obj" | |
}, | |
"variants": { | |
"normal": [{}], | |
"inventory": [{ | |
"transform": "forge:default-block" | |
}], | |
"facing=down": { "model": "forgedebugmodelloaderregistry:eye.obj", "x": 90 }, | |
"facing=up": { "model": "forgedebugmodelloaderregistry:eye.obj", "x": 270 }, | |
"facing=north": { "model": "forgedebugmodelloaderregistry:eye.obj" }, | |
"facing=south": { "model": "forgedebugmodelloaderregistry:eye.obj", "y": 180 }, | |
"facing=west": { "model": "forgedebugmodelloaderregistry:eye.obj", "y": 270 }, | |
"facing=east": { "model": "forgedebugmodelloaderregistry:eye.obj", "y": 90 } | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Mod(modid = ModelLoaderRegistryDebug.MODID, version = ModelLoaderRegistryDebug.VERSION) | |
public class ModelLoaderRegistryDebug | |
{ | |
public static final String MODID = "ForgeDebugModelLoaderRegistry"; | |
public static final String VERSION = "1.0"; | |
@EventHandler | |
public void preInit(FMLPreInitializationEvent event) | |
{ | |
GameRegistry.registerBlock(CustomModelBlock.instance, CustomModelBlock.name); | |
GameRegistry.registerBlock(CustomModelBlock2.instance, CustomModelBlock2.name); | |
GameRegistry.registerBlock(CustomModelBlock3.instance, CustomModelBlock3.name); | |
GameRegistry.registerBlock(CustomModelBlock4.instance, CustomModelBlock4.name); | |
GameRegistry.registerTileEntity(CustomTileEntity2.class, CustomModelBlock2.name); | |
if (event.getSide() == Side.CLIENT) | |
clientPreInit(); | |
} | |
private void clientPreInit() | |
{ | |
B3DLoader.instance.addDomain(MODID.toLowerCase()); | |
Item item = Item.getItemFromBlock(CustomModelBlock.instance); | |
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(MODID.toLowerCase() + ":" + CustomModelBlock.name, "inventory")); | |
OBJLoader.instance.addDomain(MODID.toLowerCase()); | |
Item item2 = Item.getItemFromBlock(CustomModelBlock2.instance); | |
ModelLoader.setCustomModelResourceLocation(item2, 0, new ModelResourceLocation(MODID.toLowerCase() + ":" + CustomModelBlock2.name, "inventory")); | |
Item item3 = Item.getItemFromBlock(CustomModelBlock3.instance); | |
ModelLoader.setCustomModelResourceLocation(item3, 0, new ModelResourceLocation(MODID.toLowerCase() + ":" + CustomModelBlock3.name, "inventory")); | |
Item item4 = Item.getItemFromBlock(CustomModelBlock4.instance); | |
ModelLoader.setCustomModelResourceLocation(item4, 0, new ModelResourceLocation(MODID.toLowerCase() + ":" + CustomModelBlock4.name, "inventory")); | |
} | |
public static class CustomModelBlock extends Block | |
{ | |
public static final CustomModelBlock instance = new CustomModelBlock(); | |
public static final String name = "CustomModelBlock"; | |
private int counter = 1; | |
private ExtendedBlockState state = new ExtendedBlockState(this, new IProperty[0], new IUnlistedProperty[]{ B3DLoader.B3DFrameProperty.instance }); | |
private CustomModelBlock() | |
{ | |
super(Material.iron); | |
setCreativeTab(CreativeTabs.tabBlock); | |
setUnlocalizedName(MODID + ":" + name); | |
} | |
@Override | |
public boolean isOpaqueCube() { return false; } | |
@Override | |
public boolean isFullCube() { return false; } | |
@Override | |
public boolean isVisuallyOpaque() { return false; } | |
@Override | |
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) | |
{ | |
B3DLoader.B3DState newState = new B3DLoader.B3DState(null, counter); | |
return ((IExtendedBlockState)this.state.getBaseState()).withProperty(B3DLoader.B3DFrameProperty.instance, newState); | |
} | |
@Override | |
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ) | |
{ | |
if(world.isRemote) | |
{ | |
System.out.println("click " + counter); | |
if(player.isSneaking()) counter--; | |
else counter++; | |
//if(counter >= model.getNode().getKeys().size()) counter = 0; | |
world.markBlockRangeForRenderUpdate(pos, pos); | |
} | |
return false; | |
} | |
} | |
public static class CustomModelBlock2 extends Block implements ITileEntityProvider | |
{ | |
public static final CustomModelBlock2 instance = new CustomModelBlock2(); | |
public static final String name = "CustomModelBlock2"; | |
private ExtendedBlockState state = new ExtendedBlockState(this, new IProperty[0], new IUnlistedProperty[]{OBJModel.OBJProperty.instance}); | |
private CustomModelBlock2() | |
{ | |
super(Material.iron); | |
setCreativeTab(CreativeTabs.tabBlock); | |
setUnlocalizedName(MODID + ":" + name); | |
} | |
@Override | |
public TileEntity createNewTileEntity(World worldIn, int meta) | |
{ | |
return new CustomTileEntity2(); | |
} | |
@Override | |
public boolean isOpaqueCube() { return false; } | |
@Override | |
public boolean isFullCube() { return false; } | |
@Override | |
public boolean isVisuallyOpaque() { return false; } | |
@Override | |
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) | |
{ | |
try | |
{ | |
CustomTileEntity2 tileEntity = (CustomTileEntity2) world.getTileEntity(pos); | |
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase(), "block/tesseract.obj")); | |
ChatComponentText text = new ChatComponentText(""); | |
if (tileEntity != null) text = new ChatComponentText("" + tileEntity.getCounter()); | |
else text = new ChatComponentText("tile entity null"); | |
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(text); | |
List<String> elements = new ArrayList<String>(); | |
elements.addAll(((OBJModel) model).getMatLib().getElements().keySet()); | |
List<String> visible = new ArrayList<String>(); | |
// List<OBJModel.Element> elements = Lists.newArrayList(((OBJModel) model).getMatLib().getElements().values()); | |
// for (OBJModel.Element e : elements) | |
// { | |
// e.setVisible(false); | |
// } | |
// if (tileEntity != null) | |
// { | |
// for (int i = tileEntity.getCounter(); i >= 0; i--) | |
// { | |
// elements.get(i).setVisible(true); | |
// } | |
// } | |
// Map<IModelPart, TRSRTransformation> map = new HashMap<IModelPart, TRSRTransformation>(); | |
// for (OBJModel.Element e : ((OBJModel) model).getMatLib().getVisibleElements().values()) | |
// { | |
// map.put(e, e.getTransform()); | |
// } | |
// OBJModel.OBJState retState = new OBJModel.OBJState(map, (OBJModel) model); | |
OBJModel.OBJState retState = new OBJModel.OBJState(visible, (OBJModel) model); | |
return ((IExtendedBlockState) this.state.getBaseState()).withProperty(OBJModel.OBJProperty.instance, retState); | |
} | |
catch (IOException e) | |
{ | |
return state; | |
} | |
} | |
@Override | |
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ) | |
{ | |
if (world.getTileEntity(pos) == null) world.setTileEntity(pos, new CustomTileEntity2()); | |
IModel model = ModelLoaderRegistry.getMissingModel(); | |
CustomTileEntity2 tileEntity = (CustomTileEntity2) world.getTileEntity(pos); | |
try | |
{ | |
model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase() + ":" + "block/tesseract.obj")); | |
} | |
catch (IOException e) | |
{ | |
model = ModelLoaderRegistry.getMissingModel(); | |
} | |
if (player.isSneaking()) | |
{ | |
tileEntity.decrement(); | |
} | |
else | |
{ | |
if (model != ModelLoaderRegistry.getMissingModel()) | |
{ | |
tileEntity.setMax(((OBJModel) model).getMatLib().getElements().keySet().size() - 1); | |
tileEntity.increment(); | |
} | |
} | |
world.markBlockRangeForRenderUpdate(pos, pos); | |
return false; | |
} | |
@Override | |
public boolean hasTileEntity(IBlockState state) | |
{ | |
return true; | |
} | |
} | |
public static class CustomTileEntity2 extends TileEntity | |
{ | |
private int counter = 0; | |
private int max = 1; | |
public CustomTileEntity2() {} | |
public int getCounter() | |
{ | |
return this.counter; | |
} | |
public int getMax() | |
{ | |
return this.max; | |
} | |
public void increment() | |
{ | |
if (this.counter == max) this.counter = -1; | |
this.counter++; | |
} | |
public void decrement() | |
{ | |
if (this.counter == 0) this.counter = max + 1; | |
this.counter--; | |
} | |
public void reset() | |
{ | |
this.counter = 0; | |
this.max = 1; | |
} | |
public void setMax(int max) | |
{ | |
this.max = max; | |
} | |
public void setToMax() | |
{ | |
this.counter = this.max; | |
} | |
} | |
public static class CustomModelBlock3 extends Block | |
{ | |
public static final CustomModelBlock3 instance = new CustomModelBlock3(); | |
public static final String name = "CustomModelBlock3"; | |
private CustomModelBlock3() | |
{ | |
super(Material.iron); | |
setCreativeTab(CreativeTabs.tabBlock); | |
setUnlocalizedName(name); | |
} | |
@Override | |
public boolean isOpaqueCube() { return false; } | |
@Override | |
public boolean isFullCube() { return false; } | |
@Override | |
public boolean isVisuallyOpaque() { return false; } | |
} | |
public static class CustomModelBlock4 extends Block | |
{ | |
// public static EnumFacing facing = EnumFacing.NORTH; | |
public static final PropertyDirection FACING = PropertyDirection.create("facing"); | |
public static final CustomModelBlock4 instance = new CustomModelBlock4(); | |
public static final String name = "CustomModelBlock4"; | |
private ExtendedBlockState state = new ExtendedBlockState(this, new IProperty[] {FACING}, new IUnlistedProperty[]{OBJModel.OBJProperty.instance}); | |
// private ExtendedBlockState state = new ExtendedBlockState(this, new IProperty[] {FACING}, new IUnlistedProperty[0]); | |
// private BlockState state = new BlockState(this, new IProperty[] {FACING}); | |
private CustomModelBlock4() | |
{ | |
super(Material.iron); | |
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH)); | |
setCreativeTab(CreativeTabs.tabBlock); | |
setUnlocalizedName(name); | |
} | |
@Override | |
public IBlockState onBlockPlaced(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer) | |
{ | |
return this.getDefaultState().withProperty(FACING, getFacingFromEntity(world, pos, placer)); | |
} | |
@Override | |
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) | |
{ | |
world.setBlockState(pos, state.withProperty(FACING, getFacingFromEntity(world, pos, placer)), 2); | |
} | |
public static EnumFacing getFacing(int meta) | |
{ | |
return EnumFacing.getFront(meta & 7); | |
} | |
@Override | |
@SideOnly(Side.CLIENT) | |
public IBlockState getStateForEntityRender(IBlockState state) | |
{ | |
return this.getDefaultState().withProperty(FACING, EnumFacing.SOUTH); | |
} | |
@Override | |
public IBlockState getStateFromMeta(int meta) | |
{ | |
return this.getDefaultState().withProperty(FACING, getFacing(meta)); | |
} | |
@Override | |
public int getMetaFromState(IBlockState state) | |
{ | |
return ((EnumFacing) state.getValue(FACING)).getIndex(); | |
} | |
@Override | |
public BlockState createBlockState() | |
{ | |
this.state = new ExtendedBlockState(this, new IProperty[] {FACING}, new IUnlistedProperty[] {OBJModel.OBJProperty.instance}); | |
return state; | |
} | |
@Override | |
public boolean isOpaqueCube() { return false; } | |
@Override | |
public boolean isFullCube() { return false; } | |
@Override | |
public boolean isVisuallyOpaque() { return false; } | |
@Override | |
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos) | |
{ | |
try | |
{ | |
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase() + ":" + "block/eye.obj")); | |
if (((OBJModel) model).getModelState() != null && ((OBJModel) model).getModelState() instanceof OBJModel.OBJState) | |
{ | |
FMLLog.info("CustomModelBlock4: Model state passed", new Object[0]); | |
OBJModel.OBJState retState = new OBJModel.OBJState(null, (OBJModel) model); | |
return ((IExtendedBlockState) this.state.getBaseState()).withProperty(OBJModel.OBJProperty.instance, retState).withProperty(FACING, state.getValue(FACING)); | |
} | |
} | |
catch (IOException e) | |
{ | |
FMLLog.info("CustomModelBlock4: failed to load block/eye.obj", new Object[0]); | |
} | |
return state; | |
} | |
private void setElementTransforms(TRSRTransformation input) | |
{ | |
try | |
{ | |
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase(), "block/tesseract.obj")); | |
TRSRTransformation transform = input == null ? TRSRTransformation.identity() : input; | |
for (Map.Entry<String, OBJModel.Element> e : ((OBJModel) model).getMatLib().getElements().entrySet()) | |
{ | |
OBJModel.Element element = e.getValue(); | |
element.setTransform(transform); | |
} | |
} | |
catch (IOException e) | |
{ | |
FMLLog.info("CustomModelBlock4: failed to find build/tesseract.obj", new Object[0]); | |
} | |
} | |
public static EnumFacing getFacingFromEntity(World worldIn, BlockPos clickedBlock, EntityLivingBase entityIn) | |
{ | |
if (MathHelper.abs((float)entityIn.posX - (float)clickedBlock.getX()) < 2.0F && MathHelper.abs((float)entityIn.posZ - (float)clickedBlock.getZ()) < 2.0F) | |
{ | |
double d0 = entityIn.posY + (double)entityIn.getEyeHeight(); | |
if (d0 - (double)clickedBlock.getY() > 2.0D) | |
{ | |
return EnumFacing.UP; | |
} | |
if ((double)clickedBlock.getY() - d0 > 0.0D) | |
{ | |
return EnumFacing.DOWN; | |
} | |
} | |
return entityIn.getHorizontalFacing().getOpposite(); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class OBJModel implements IRetexturableModel, IModelCustomData | |
{ | |
private MaterialLibrary matLib; | |
private IModelState state; | |
private final ResourceLocation location; | |
private float minU = 0f; | |
private float maxU = 1f; | |
private float minV = 0f; | |
private float maxV = 1f; | |
public OBJModel(MaterialLibrary matLib, ResourceLocation location) | |
{ | |
this.matLib = matLib; | |
this.location = location; | |
} | |
public IModelState getModelState() | |
{ | |
return this.state; | |
} | |
private void setModelState(IModelState state) | |
{ | |
this.state = state; | |
} | |
public float getMinU() | |
{ | |
return this.minU; | |
} | |
public float getMaxU() | |
{ | |
return this.maxU; | |
} | |
public float getMinV() | |
{ | |
return this.minV; | |
} | |
public float getMaxV() | |
{ | |
return this.maxV; | |
} | |
public void setUVBounds(float minU, float maxU, float minV, float maxV) | |
{ | |
this.minU = minU; | |
this.maxU = maxU; | |
this.minV = minV; | |
this.maxV = maxV; | |
} | |
@Override | |
public Collection<ResourceLocation> getDependencies() | |
{ | |
return Collections.emptyList(); | |
} | |
@Override | |
public Collection<ResourceLocation> getTextures() | |
{ | |
Iterator<Material> materialIterator = this.matLib.materials.values().iterator(); | |
List<ResourceLocation> textures = new ArrayList<ResourceLocation>(); | |
while (materialIterator.hasNext()) | |
{ | |
Material mat = materialIterator.next(); | |
ResourceLocation textureLoc = new ResourceLocation(mat.getTexture().getPath()); | |
if (!textures.contains(textureLoc)) | |
textures.add(textureLoc); | |
} | |
return textures; | |
} | |
@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, Material> e : matLib.materials.entrySet()) | |
{ | |
if (e.getValue().getTexture().getTextureLocation().getResourcePath().startsWith("#")) | |
{ | |
FMLLog.severe("unresolved texture '%s' for obj model '%s'", e.getValue().getTexture().getTextureLocation().getResourcePath(), location); | |
builder.put(e.getKey(), missing); | |
} | |
else | |
{ | |
// TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().registerSprite(e.getValue().getTexture().getTextureLocation()); | |
builder.put(e.getKey(), bakedTextureGetter.apply(e.getValue().getTexture().getTextureLocation())); | |
// builder.put(e.getKey(), sprite); | |
} | |
} | |
builder.put("missingno", missing); | |
return new OBJBakedModel(this, state, format, builder.build()); | |
} | |
public OBJState getDefaultState() | |
{ | |
return new OBJState(null, this); | |
} | |
public MaterialLibrary getMatLib() | |
{ | |
return this.matLib; | |
} | |
@Override | |
public IModel process(ImmutableMap<String, String> customData) | |
{ | |
// TODO: use for defining different visibility configurations? | |
return null; | |
} | |
private static String getLocation(String path) | |
{ | |
if (path.endsWith(".png")) | |
path = path.substring(0, path.length() - ".png".length()); | |
return path; | |
} | |
@Override | |
public IModel retexture(ImmutableMap<String, String> textures) | |
{ | |
MaterialLibrary lib = this.matLib; | |
for (Map.Entry<String, String> e : textures.entrySet()) | |
{ | |
FMLLog.info("OBJModel: Retexturing: %s with %s", e.getKey(), e.getValue()); | |
String name = e.getKey(); | |
String loc = e.getValue(); | |
if (name.equalsIgnoreCase("all")) | |
{ | |
for (Map.Entry<String, Material> m : lib.materials.entrySet()) | |
{ | |
if (!m.getKey().equals(Material.WHITE_NAME)) | |
{ | |
m.getValue().getTexture().setPath(loc); | |
} | |
} | |
} | |
else if (lib.materials.containsKey(name)) | |
{ | |
lib.materials.get(name).getTexture().setPath(loc); | |
} | |
} | |
return new OBJModel(lib, location); | |
} | |
public static class Parser | |
{ | |
private static Set<String> unknownObjectCommands = new HashSet<String>(); | |
public MaterialLibrary materialLibrary = new OBJModel(null, null).new MaterialLibrary(); | |
private IResourceManager manager; | |
private InputStreamReader objStream; | |
private BufferedReader objReader; | |
private ResourceLocation objFrom; | |
private List<String> elementList = new ArrayList<String>(); | |
private List<Vertex> vertices = new ArrayList<Vertex>(); | |
private List<Normal> normals = new ArrayList<Normal>(); | |
private List<TextureCoordinate> texCoords = new ArrayList<TextureCoordinate>(); | |
private float minU = 0f; | |
private float maxU = 1f; | |
private float minV = 0f; | |
private float maxV = 1f; | |
public Parser(IResource from, IResourceManager manager) throws IOException | |
{ | |
this.manager = manager; | |
this.objFrom = from.getResourceLocation(); | |
this.objStream = new InputStreamReader(from.getInputStream(), Charsets.UTF_8); | |
this.objReader = new BufferedReader(objStream); | |
} | |
public List<String> getElements() | |
{ | |
return this.elementList; | |
} | |
public OBJModel parse() throws IOException | |
{ | |
String currentLine = ""; | |
Material material = new Material(); | |
for (;;) | |
{ | |
currentLine = objReader.readLine(); | |
if (currentLine == null) break; | |
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue; | |
String[] fields = currentLine.split(" ", 2); | |
String key = fields[0]; | |
String data = fields[1]; | |
if (key.equalsIgnoreCase("mtllib")) | |
materialLibrary.parseMaterials(manager, data, objFrom); | |
else if (key.equalsIgnoreCase("usemtl")) | |
material = materialLibrary.materials.get(data); | |
else if (key.equalsIgnoreCase("v")) | |
{ | |
String[] splitData = data.split(" "); | |
float[] floatSplitData = new float[splitData.length]; | |
for (int i = 0; i < splitData.length; i++) | |
floatSplitData[i] = Float.parseFloat(splitData[i]); | |
Vector4f pos = new Vector4f(floatSplitData[0], floatSplitData[1], floatSplitData[2], floatSplitData.length == 4 ? floatSplitData[3] : 1); | |
Vector4f color = new Vector4f(1f, 1f, 1f, 1f); | |
if (material.isWhite()) color = material.getColor(); | |
Vertex vertex = new Vertex(pos, color); | |
this.vertices.add(vertex); | |
} | |
else if (key.equalsIgnoreCase("vn")) | |
{ | |
String[] splitData = data.split(" "); | |
float[] floatSplitData = new float[splitData.length]; | |
for (int i = 0; i < splitData.length; i++) | |
floatSplitData[i] = Float.parseFloat(splitData[i]); | |
Normal normal = new Normal(new Vector3f(floatSplitData[0], floatSplitData[1], floatSplitData[2])); | |
this.normals.add(normal); | |
} | |
else if (key.equalsIgnoreCase("vt")) | |
{ | |
String[] splitData = data.split(" "); | |
float[] floatSplitData = new float[splitData.length]; | |
for (int i = 0; i < splitData.length; i++) | |
floatSplitData[i] = Float.parseFloat(splitData[i]); | |
TextureCoordinate texCoord = new TextureCoordinate(new Vector3f(floatSplitData[0], floatSplitData[1], | |
floatSplitData.length == 3 ? floatSplitData[2] : 1)); | |
if (floatSplitData[0] < this.minU) | |
{ | |
this.minU = floatSplitData[0]; | |
} | |
else if (floatSplitData[0] > this.maxU) | |
{ | |
this.maxU = floatSplitData[0]; | |
} | |
if (floatSplitData[1] < this.minV) | |
{ | |
this.minV = floatSplitData[1]; | |
} | |
else if (floatSplitData[1] > this.maxV) | |
{ | |
this.maxV = floatSplitData[1]; | |
} | |
this.texCoords.add(texCoord); | |
} | |
else if (key.equalsIgnoreCase("f")) | |
{ | |
String[] splitSpace = data.split(" "); | |
String[][] splitSlash = new String[splitSpace.length][]; | |
int vert = 0; | |
int texCoord = 0; | |
int norm = 0; | |
List<Vertex> v = new ArrayList<Vertex>(splitSpace.length); | |
List<TextureCoordinate> t = new ArrayList<TextureCoordinate>(splitSpace.length); | |
List<Normal> n = new ArrayList<Normal>(splitSpace.length); | |
for (int i = 0; i < splitSpace.length; i++) | |
{ | |
if (splitSpace[i].contains("//")) | |
{ | |
splitSlash[i] = splitSpace[i].split("//"); | |
vert = Integer.parseInt(splitSlash[i][0]); | |
vert = vert < 0 ? this.vertices.size() - 1 : vert - 1; | |
norm = Integer.parseInt(splitSlash[i][1]); | |
norm = norm < 0 ? this.normals.size() - 1 : norm - 1; | |
v.add(this.vertices.get(vert)); | |
n.add(this.normals.get(norm)); | |
} | |
else if (splitSpace[i].contains("/")) | |
{ | |
splitSlash[i] = splitSpace[i].split("/"); | |
vert = Integer.parseInt(splitSlash[i][0]); | |
vert = vert < 0 ? this.vertices.size() - 1 : vert - 1; | |
texCoord = Integer.parseInt(splitSlash[i][1]); | |
texCoord = texCoord < 0 ? this.texCoords.size() - 1 : texCoord - 1; | |
if (splitSlash[i].length > 2) | |
{ | |
norm = Integer.parseInt(splitSlash[i][2]); | |
norm = norm < 0 ? this.normals.size() - 1 : norm - 1; | |
} | |
v.add(this.vertices.get(vert)); | |
t.add(this.texCoords.get(texCoord)); | |
if (splitSlash[i].length > 2) n.add(this.normals.get(norm)); | |
} | |
else | |
{ | |
splitSlash[i] = splitSpace[i].split(""); | |
vert = Integer.parseInt(splitSlash[i][0]); | |
vert = vert < 0 ? this.vertices.size() - 1 : vert - 1; | |
v.add(this.vertices.get(vert)); | |
} | |
} | |
Vertex[] va = new Vertex[v.size()]; | |
v.toArray(va); | |
TextureCoordinate[] ta = new TextureCoordinate[t.size()]; | |
t.toArray(ta); | |
Normal[] na = new Normal[n.size()]; | |
n.toArray(na); | |
Face face = new Face(va, ta, na); | |
if (material.getTexture() == null || material.getTexture().equals(Texture.White)) | |
{ | |
this.materialLibrary.library.put(face, this.materialLibrary.materials.get(Material.WHITE_NAME)); | |
} | |
else | |
{ | |
this.materialLibrary.library.put(face, material); | |
} | |
if (elementList.isEmpty()) | |
{ | |
if (this.materialLibrary.getElements().containsKey(Element.DEFAULT_NAME)) | |
{ | |
this.materialLibrary.getElements().get(Element.DEFAULT_NAME).addFace(face); | |
} | |
else | |
{ | |
Element def = new Element(Element.DEFAULT_NAME, null); | |
def.addFace(face); | |
this.materialLibrary.getElements().put(Element.DEFAULT_NAME, def); | |
} | |
} | |
else | |
{ | |
for (String s : elementList) | |
{ | |
if (this.materialLibrary.getElements().containsKey(s)) | |
{ | |
this.materialLibrary.getElements().get(s).addFace(face); | |
} | |
else | |
{ | |
Element e = new Element(s, null); | |
e.addFace(face); | |
this.materialLibrary.getElements().put(s, e); | |
} | |
} | |
} | |
} | |
else if (key.equalsIgnoreCase("g") || key.equalsIgnoreCase("o")) | |
{ | |
elementList.clear(); | |
if (key.equalsIgnoreCase("g")) | |
{ | |
String[] splitSpace = data.split(" "); | |
for (String s : splitSpace) | |
elementList.add(s); | |
} | |
else | |
{ | |
elementList.add(data); | |
} | |
} | |
else | |
{ | |
if (!unknownObjectCommands.contains(key)) | |
{ | |
unknownObjectCommands.add(key); | |
FMLLog.info("OBJLoader.Parser: command '%s' (model: '%s') is not currently supported, skipping", key, objFrom); | |
} | |
} | |
} | |
OBJModel model = new OBJModel(this.materialLibrary, this.objFrom); | |
model.setUVBounds(minU, maxU, minV, maxV); | |
return model; | |
} | |
} | |
public class MaterialLibrary | |
{ | |
private Set<String> unknownMaterialCommands = new HashSet<String>(); | |
private Map<String, Material> materials = new HashMap<String, Material>(); | |
private Map<Face, Material> library = new HashMap<Face, Material>(); | |
private Map<String, Element> elements = new HashMap<String, Element>(); | |
private InputStreamReader mtlStream; | |
private BufferedReader mtlReader; | |
public MaterialLibrary() | |
{ | |
this.elements.put(Element.DEFAULT_NAME, new Element(Element.DEFAULT_NAME, null)); | |
} | |
public void parseMaterials(IResourceManager manager, String path, ResourceLocation from) throws IOException | |
{ | |
boolean hasSetTexture = false; | |
boolean hasSetColor = false; | |
String domain = from.getResourceDomain(); | |
mtlStream = new InputStreamReader(manager.getResource(new ResourceLocation(domain, path)).getInputStream(), Charsets.UTF_8); | |
mtlReader = new BufferedReader(mtlStream); | |
String currentLine = ""; | |
Material material = new Material(); | |
material.setName(Material.WHITE_NAME); | |
material.setTexture(Texture.White); | |
this.materials.put(Material.WHITE_NAME, material); | |
for (;;) | |
{ | |
currentLine = mtlReader.readLine(); | |
if (currentLine == null) break; | |
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue; | |
String[] fields = currentLine.split(" ", 2); | |
String key = fields[0]; | |
String data = fields[1]; | |
if (key.equalsIgnoreCase("newmtl")) | |
{ | |
hasSetColor = false; | |
hasSetTexture = false; | |
material = new Material(); | |
material.setName(data); | |
this.materials.put(data, material); | |
} | |
else if (key.equalsIgnoreCase("Ka") || key.equalsIgnoreCase("Kd") || key.equalsIgnoreCase("Ks")) | |
{ | |
if (!hasSetColor) | |
{ | |
String[] rgbStrings = data.split(" ", 3); | |
Vector4f color = new Vector4f(Float.parseFloat(rgbStrings[0]), Float.parseFloat(rgbStrings[1]), Float.parseFloat(rgbStrings[2]), 1.0f); | |
hasSetColor = true; | |
material.setColor(color); | |
} | |
else | |
{ | |
FMLLog.info("OBJModel: A color has already been defined for material '%s' in '%s'. The color defined by key '%s' will not be applied!", material.getName(), new ResourceLocation(domain, path).toString(), key); | |
} | |
} | |
else if (key.equalsIgnoreCase("map_Ka") || key.equalsIgnoreCase("map_Kd") || key.equalsIgnoreCase("map_Ks")) | |
{ | |
if (!hasSetTexture) | |
{ | |
if (data.contains(" ")) | |
{ | |
String[] mapStrings = data.split(" "); | |
String texturePath = mapStrings[mapStrings.length - 1]; | |
Texture texture = new Texture(texturePath); | |
hasSetTexture = true; | |
material.setTexture(texture); | |
} | |
else | |
{ | |
Texture texture = new Texture(data); | |
hasSetTexture = true; | |
material.setTexture(texture); | |
} | |
} | |
else | |
{ | |
FMLLog.info("OBJModel: A texture has already been defined for material '%s' in '%s'. The texture defined by key '%s' will not be applied!", material.getName(), new ResourceLocation(domain, path).toString(), key); | |
} | |
} | |
else | |
{ | |
if (!unknownMaterialCommands.contains(key)) | |
{ | |
unknownMaterialCommands.add(key); | |
FMLLog.info("OBJLoader.MaterialLibrary: command '%s' (model: '%s') is not currently supported, skipping", key, new ResourceLocation( | |
domain, path)); | |
} | |
} | |
} | |
} | |
public Map<String, Element> getElements() | |
{ | |
return this.elements; | |
} | |
public Map<String, Element> getVisibleElements() | |
{ | |
Map<String, Element> ret = new HashMap<String, Element>(); | |
for (Map.Entry<String, Element> e : this.elements.entrySet()) | |
{ | |
if (e.getValue().isVisible()) | |
ret.put(e.getKey(), e.getValue()); | |
} | |
return ret; | |
} | |
} | |
public static class Material | |
{ | |
public static final String WHITE_NAME = "OBJModel.White.Texture.Name"; | |
public static final String DEFAULT_NAME = "OBJModel.Default.Texture.Name"; | |
private Vector4f color; | |
private Texture texture = Texture.White; | |
private String name = DEFAULT_NAME; | |
public Material() | |
{ | |
this(new Vector4f(1f, 1f, 1f, 1f)); | |
} | |
public Material(Vector4f color) | |
{ | |
this(color, Texture.White, WHITE_NAME); | |
} | |
public Material(Texture texture) | |
{ | |
this(new Vector4f(1, 1, 1, 1), texture, DEFAULT_NAME); | |
} | |
public Material(Vector4f color, Texture texture, String name) | |
{ | |
this.color = color; | |
this.texture = texture; | |
this.name = name != null ? name : DEFAULT_NAME; | |
} | |
public void setName(String name) | |
{ | |
this.name = name != null ? name : DEFAULT_NAME; | |
} | |
public String getName() | |
{ | |
return this.name; | |
} | |
public void setColor(Vector4f color) | |
{ | |
this.color = color; | |
} | |
public Vector4f getColor() | |
{ | |
return this.color; | |
} | |
public void setTexture(Texture texture) | |
{ | |
this.texture = texture; | |
} | |
public Texture getTexture() | |
{ | |
return this.texture; | |
} | |
public boolean isWhite() | |
{ | |
return this.texture.equals(Texture.White); | |
} | |
} | |
public static class Texture | |
{ | |
public static Texture White = new Texture("builtin/white", new Vector2f(0, 0), new Vector2f(1, 1), 0); | |
private String path; | |
private Vector2f position; | |
private Vector2f scale; | |
private float rotation; | |
public Texture(String path) | |
{ | |
this(path, new Vector2f(0, 0), new Vector2f(1, 1), 0); | |
} | |
public Texture(String path, Vector2f position, Vector2f scale, float rotation) | |
{ | |
this.path = path; | |
this.position = position; | |
this.scale = scale; | |
this.rotation = rotation; | |
} | |
public ResourceLocation getTextureLocation() | |
{ | |
ResourceLocation loc = new ResourceLocation(this.path); | |
return loc; | |
} | |
public void setPath(String path) | |
{ | |
this.path = path; | |
} | |
public String getPath() | |
{ | |
return this.path; | |
} | |
public void setPosition(Vector2f position) | |
{ | |
this.position = position; | |
} | |
public Vector2f getPosition() | |
{ | |
return this.position; | |
} | |
public void setScale(Vector2f scale) | |
{ | |
this.scale = scale; | |
} | |
public Vector2f getScale() | |
{ | |
return this.scale; | |
} | |
public void setRotation(float rotation) | |
{ | |
this.rotation = rotation; | |
} | |
public float getRotation() | |
{ | |
return this.rotation; | |
} | |
} | |
public static class Face | |
{ | |
private Vertex[] verts = new Vertex[4]; | |
private Normal[] norms = new Normal[4]; | |
private TextureCoordinate[] texCoords = new TextureCoordinate[4]; | |
public Face(Vertex[] verts) | |
{ | |
this(verts, null, null); | |
} | |
public Face(Vertex[] verts, Normal[] norms) | |
{ | |
this(verts, null, norms); | |
} | |
public Face(Vertex[] verts, TextureCoordinate[] texCoords) | |
{ | |
this(verts, texCoords, null); | |
} | |
public Face(Vertex[] verts, TextureCoordinate[] texCoords, Normal[] norms) | |
{ | |
this.verts = verts; | |
this.verts = this.verts.length > 0 ? this.verts : null; | |
this.norms = norms; | |
this.norms = this.norms.length > 0 ? this.norms : null; | |
this.texCoords = texCoords; | |
this.texCoords = this.texCoords.length > 0 ? this.texCoords : null; | |
ensureQuads(); | |
} | |
private void ensureQuads() | |
{ | |
if (this.verts != null && this.verts.length == 3) | |
{ | |
this.verts = new Vertex[]{this.verts[0], this.verts[1], this.verts[2], this.verts[2]}; | |
} | |
if (this.norms != null && this.norms.length == 3) | |
{ | |
this.norms = new Normal[]{this.norms[0], this.norms[1], this.norms[2], this.norms[2]}; | |
} | |
if (this.texCoords != null && this.texCoords.length == 3) | |
{ | |
this.texCoords = new TextureCoordinate[]{this.texCoords[0], this.texCoords[1], this.texCoords[2], this.texCoords[2]}; | |
} | |
} | |
public void setVertices(Vertex[] verts) | |
{ | |
this.verts = verts; | |
} | |
public Vertex[] getVertices() | |
{ | |
return this.verts; | |
} | |
public void setNormals(Normal[] norms) | |
{ | |
this.norms = norms; | |
} | |
public Normal[] getNormals() | |
{ | |
return this.norms; | |
} | |
public void setTextureCoordinates(TextureCoordinate[] texCoords) | |
{ | |
this.texCoords = texCoords; | |
} | |
public TextureCoordinate[] getTextureCoordinates() | |
{ | |
return this.texCoords; | |
} | |
public boolean areUVsNormalized() | |
{ | |
for (TextureCoordinate t : this.texCoords) | |
{ | |
if (!(t.getPosition().getX() > 0.0f && t.getPosition().getX() < 1.0f && t.getPosition().getY() > 0.0f && t.getPosition().getY() < 1.0f)) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
public Normal getNormal() | |
{ | |
if (norms == null) | |
{ // use vertices to calculate normal | |
Vector3f v1 = new Vector3f(this.verts[0].getPosition().x, this.verts[0].getPosition().y, this.verts[0].getPosition().z); | |
Vector3f v2 = new Vector3f(this.verts[1].getPosition().x, this.verts[1].getPosition().y, this.verts[1].getPosition().z); | |
Vector3f v3 = new Vector3f(this.verts[2].getPosition().x, this.verts[2].getPosition().y, this.verts[2].getPosition().z); | |
Vector3f v4 = this.verts.length > 3 ? new Vector3f(this.verts[3].getPosition().x, this.verts[3].getPosition().y, this.verts[3].getPosition().z) | |
: null; | |
if (v4 == null) | |
{ | |
Vector3f v2c = new Vector3f(v2.x, v2.y, v2.z); | |
Vector3f v1c = new Vector3f(v1.x, v1.y, v1.z); | |
v1c.sub(v2c); | |
Vector3f v3c = new Vector3f(v3.x, v3.y, v3.z); | |
v3c.sub(v2c); | |
Vector3f c = new Vector3f(); | |
c.cross(v1c, v3c); | |
c.normalize(); | |
Normal normal = new Normal(c); | |
return normal; | |
} | |
else | |
{ | |
Vector3f v2c = new Vector3f(v2.x, v2.y, v2.z); | |
Vector3f v1c = new Vector3f(v1.x, v1.y, v1.z); | |
v1c.sub(v2c); | |
Vector3f v3c = new Vector3f(v3.x, v3.y, v3.z); | |
v3c.sub(v2c); | |
Vector3f c = new Vector3f(); | |
c.cross(v1c, v3c); | |
c.normalize(); | |
v1c = new Vector3f(v1.x, v1.y, v1.z); | |
v3c = new Vector3f(v3.x, v3.y, v3.z); | |
Vector3f v4c = new Vector3f(v4.x, v4.y, v4.z); | |
v1c.sub(v4c); | |
v3c.sub(v4c); | |
Vector3f d = new Vector3f(); | |
d.cross(v1c, v3c); | |
d.normalize(); | |
Vector3f avg = new Vector3f(); | |
avg.x = (c.x + d.x) * 0.5f; | |
avg.y = (c.y + d.y) * 0.5f; | |
avg.z = (c.z + d.z) * 0.5f; | |
avg.normalize(); | |
Normal normal = new Normal(avg); | |
return normal; | |
} | |
} | |
else | |
{ // use normals to calculate normal | |
Vector3f n1 = this.norms[0].getNormal(); | |
Vector3f n2 = this.norms[1].getNormal(); | |
Vector3f n3 = this.norms[2].getNormal(); | |
Vector3f n4 = this.norms.length > 3 ? this.norms[3].getNormal() : null; | |
if (n4 == null) | |
{ | |
Vector3f n2c = new Vector3f(n2.x, n2.y, n2.z); | |
Vector3f n1c = new Vector3f(n1.x, n1.y, n1.z); | |
n1c.sub(n2c); | |
Vector3f n3c = new Vector3f(n3.x, n3.y, n3.z); | |
n3c.sub(n2c); | |
Vector3f c = new Vector3f(); | |
c.cross(n1c, n3c); | |
c.normalize(); | |
Normal normal = new Normal(c); | |
return normal; | |
} | |
else | |
{ | |
Vector3f n2c = new Vector3f(n2.x, n2.y, n2.z); | |
Vector3f n1c = new Vector3f(n1.x, n1.y, n1.z); | |
n1c.sub(n2c); | |
Vector3f n3c = new Vector3f(n3.x, n3.y, n3.z); | |
n3c.sub(n2c); | |
Vector3f c = new Vector3f(); | |
c.cross(n1c, n3c); | |
c.normalize(); | |
n1c = new Vector3f(n1.x, n1.y, n1.z); | |
n3c = new Vector3f(n3.x, n3.y, n3.z); | |
Vector3f n4c = new Vector3f(n4.x, n4.y, n4.z); | |
n1c.sub(n4c); | |
n3c.sub(n4c); | |
Vector3f d = new Vector3f(); | |
d.cross(n1c, n3c); | |
d.normalize(); | |
Vector3f avg = new Vector3f(); | |
avg.x = (c.x + d.x) * 0.5f; | |
avg.y = (c.y + d.y) * 0.5f; | |
avg.z = (c.z + d.z) * 0.5f; | |
avg.normalize(); | |
Normal normal = new Normal(avg); | |
return normal; | |
} | |
} | |
} | |
} | |
public static class Vertex | |
{ | |
private Vector4f position; | |
private Vector4f color; | |
public Vertex(Vector4f position, Vector4f color) | |
{ | |
this.position = position; | |
this.color = color; | |
} | |
public void setPos(Vector4f position) | |
{ | |
this.position = position; | |
} | |
public Vector4f getPosition() | |
{ | |
return this.position; | |
} | |
public void setColor(Vector4f color) | |
{ | |
this.color = color; | |
} | |
public Vector4f getColor() | |
{ | |
return this.color; | |
} | |
@Override | |
public String toString() | |
{ | |
StringBuilder builder = new StringBuilder(); | |
builder.append(String.format("v:%n")); | |
builder.append(String.format(" position: %s %s %s%n", position.x, position.y, position.z)); | |
builder.append(String.format(" color: %s %s %s %s%n", color.x, color.y, color.z, color.w)); | |
return builder.toString(); | |
} | |
} | |
public static class Normal | |
{ | |
private Vector3f normal; | |
public Normal(Vector3f normal) | |
{ | |
this.normal = normal; | |
} | |
public void setNormal(Vector3f normal) | |
{ | |
this.normal = normal; | |
} | |
public Vector3f getNormal() | |
{ | |
return this.normal; | |
} | |
} | |
public static class TextureCoordinate | |
{ | |
private Vector3f position; | |
public TextureCoordinate(Vector3f position) | |
{ | |
this.position = position; | |
} | |
public void setPosition(Vector3f position) | |
{ | |
this.position = position; | |
} | |
public Vector3f getPosition() | |
{ | |
return this.position; | |
} | |
} | |
public static class OBJState implements IModelState | |
{ | |
private OBJModel model; | |
private List<String> visibleElements = new ArrayList<String>(); | |
public OBJState(List<String> visibleElements, OBJModel model) | |
{ | |
if (visibleElements == null || visibleElements.isEmpty()) | |
this.visibleElements.add("all"); | |
else | |
this.visibleElements = visibleElements; | |
this.model = model; | |
setVisibleElements(this.visibleElements); | |
} | |
public void setVisibleElements(List<String> visibleElements) | |
{ | |
String s = visibleElements.get(0); | |
if (s.equalsIgnoreCase("all")) | |
{ | |
showAllElements(); | |
} | |
else if (s.equalsIgnoreCase("none")) | |
{ | |
hideAllElements(); | |
} | |
else if (s.equalsIgnoreCase("all except")) | |
{ | |
showAllElements(); | |
for (int i = 1; i < visibleElements.size(); i++) | |
{ | |
if (this.model.getMatLib().getElements().containsKey(visibleElements.get(i))) | |
{ | |
this.model.getMatLib().getElements().get(visibleElements.get(i)).setVisible(false); | |
} | |
else | |
{ | |
FMLLog.severe("OBJState: could not find element of name '%s' whilst setting element visibility, skipping", visibleElements.get(i)); | |
} | |
} | |
} | |
else | |
{ | |
hideAllElements(); | |
for (String v : visibleElements) | |
{ | |
if (!this.model.getMatLib().getElements().containsKey(v)) | |
{ | |
FMLLog.severe("OBJState: could not find element of name '%s' whilst setting element visibility, skipping", v); | |
} | |
else | |
{ | |
this.model.getMatLib().getElements().get(v).setVisible(true); | |
} | |
} | |
} | |
} | |
private void showAllElements() | |
{ | |
for (Element e : this.model.getMatLib().getElements().values()) | |
{ | |
e.setVisible(true); | |
} | |
} | |
private void hideAllElements() | |
{ | |
for (Element e : this.model.getMatLib().getElements().values()) | |
{ | |
e.setVisible(false); | |
} | |
} | |
public List<String> getVisibleElements() | |
{ | |
List<String> visible = new ArrayList<String>(); | |
for (Map.Entry<String, Element> e : this.model.getMatLib().getElements().entrySet()) | |
{ | |
if (e.getValue().isVisible()) | |
{ | |
visible.add(e.getKey()); | |
} | |
} | |
return visible; | |
} | |
public TRSRTransformation apply(IModelPart part) | |
{ | |
TRSRTransformation ret = TRSRTransformation.identity(); | |
// TRSRTransformation ret = super.apply(part); | |
if (part instanceof Element) | |
{ | |
Element element = (Element) part; | |
ret = ret.compose(element.getTransform()); | |
// ret = ret.compose(new TRSRTransformation(element.getPos(), element.getRot(), element.getScale(), null)); | |
Matrix4f matrix = ret.getMatrix(); | |
matrix.invert(); | |
ret = ret.compose(new TRSRTransformation(matrix)); | |
} | |
return ret; | |
} | |
} | |
public enum OBJProperty implements IUnlistedProperty<OBJState> | |
{ | |
instance; | |
public String getName() | |
{ | |
return "OBJPropery"; | |
} | |
@Override | |
public boolean isValid(OBJState value) | |
{ | |
return value instanceof OBJState; | |
} | |
@Override | |
public Class<OBJState> getType() | |
{ | |
return OBJState.class; | |
} | |
@Override | |
public String valueToString(OBJState value) | |
{ | |
return value.toString(); | |
} | |
} | |
public static class Element implements IModelPart | |
{ | |
public static final String DEFAULT_NAME = "OBJModel.Default.Element.Name"; | |
private String name = DEFAULT_NAME; | |
private TRSRTransformation transform = TRSRTransformation.identity(); | |
private LinkedHashSet<Face> faces = new LinkedHashSet<Face>(); | |
private boolean visible = true; | |
public Element(String name, LinkedHashSet<Face> faces) | |
{ | |
this(name, TRSRTransformation.identity(), faces); | |
} | |
public Element(String name, TRSRTransformation transform, LinkedHashSet<Face> faces) | |
{ | |
this.name = name != null ? name : DEFAULT_NAME; | |
this.transform = transform; | |
if (faces == null) | |
this.faces = new LinkedHashSet<Face>(); | |
else | |
this.faces = faces; | |
} | |
public ImmutableList<Face> bake() | |
{ | |
ImmutableList.Builder<Face> builder = ImmutableList.builder(); | |
for (Face f : faces) | |
{ | |
builder.add(f); | |
} | |
return builder.build(); | |
} | |
public String getName() | |
{ | |
return this.name; | |
} | |
public void setTransform(TRSRTransformation transform) | |
{ | |
if (transform == null) | |
this.transform = TRSRTransformation.identity(); | |
else | |
this.transform = transform; | |
} | |
public TRSRTransformation getTransform() | |
{ | |
return this.transform; | |
} | |
// public void setName(String name) | |
// { | |
// this.name = name; | |
// } | |
// | |
// public Vector3f getPos() | |
// { | |
// return this.pos; | |
// } | |
// | |
// public void setPos(Vector3f pos) | |
// { | |
// this.pos = pos; | |
// } | |
// | |
// public Vector3f getScale() | |
// { | |
// return this.scale; | |
// } | |
// | |
// public void setScale(Vector3f scale) | |
// { | |
// this.scale = scale; | |
// } | |
// | |
// public Quat4f getRot() | |
// { | |
// return this.rot; | |
// } | |
// | |
// public void setRot(Quat4f rot) | |
// { | |
// this.rot = rot; | |
// } | |
public LinkedHashSet<Face> getFaces() | |
{ | |
return this.faces; | |
} | |
public void setFaces(LinkedHashSet<Face> faces) | |
{ | |
this.faces = faces; | |
} | |
public void addFace(Face face) | |
{ | |
this.faces.add(face); | |
} | |
public void addFaces(List<Face> faces) | |
{ | |
this.faces.addAll(faces); | |
} | |
public boolean isVisible() | |
{ | |
return this.visible; | |
} | |
public void setVisible(boolean visible) | |
{ | |
this.visible = visible; | |
} | |
} | |
private class OBJBakedModel implements IFlexibleBakedModel, ISmartBlockModel, ISmartItemModel, IPerspectiveAwareModel | |
{ | |
private final OBJModel model; | |
private final IModelState state; | |
private final VertexFormat format; | |
private final ByteBuffer buffer; | |
private LinkedHashSet<BakedQuad> quads; | |
private static final int BYTES_IN_INT = Integer.SIZE / Byte.SIZE; | |
private static final int VERTICES_IN_QUAD = 4; | |
private Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter; | |
private ImmutableMap<String, TextureAtlasSprite> textures; | |
private EnumFacing facing = EnumFacing.SOUTH; | |
public OBJBakedModel(OBJModel model, IModelState state, VertexFormat format, ImmutableMap<String, TextureAtlasSprite> textures) | |
{ | |
this.model = model; | |
this.state = state; | |
this.format = format; | |
this.textures = textures; | |
buffer = BufferUtils.createByteBuffer(VERTICES_IN_QUAD * format.getNextOffset()); | |
model.setModelState(state); | |
} | |
@Override | |
public List<BakedQuad> getFaceQuads(EnumFacing side) | |
{ | |
return Collections.emptyList(); | |
} | |
@Override | |
public List<BakedQuad> getGeneralQuads() | |
{ | |
if (quads == null) | |
{ | |
quads = new LinkedHashSet<BakedQuad>(); | |
LinkedHashSet<Face> faces = new LinkedHashSet<Face>(); | |
Iterator<Element> elementIterator = this.model.getMatLib().getElements().values().iterator(); | |
while (elementIterator.hasNext()) | |
{ | |
Element e = elementIterator.next(); | |
if (e.isVisible()) faces.addAll(e.getFaces()); | |
} | |
for (Face f : faces) | |
{ | |
buffer.clear(); | |
String texture = this.model.getMatLib().library.get(f).getName(); | |
TextureAtlasSprite sprite = this.textures.get("missingno"); | |
if (this.model.getMatLib().materials.get(texture).isWhite()) | |
sprite = ModelLoader.White.instance; | |
else | |
sprite = this.textures.get(texture); | |
if (f.texCoords != null && !f.areUVsNormalized()) | |
{ | |
float minU = 0.0f; | |
float maxU = 1.0f; | |
float minV = 0.0f; | |
float maxV = 1.0f; | |
for (TextureCoordinate t : f.texCoords) | |
{ | |
minU = t.getPosition().getX() < minU ? t.getPosition().getX() : minU; | |
maxU = t.getPosition().getX() > maxU ? t.getPosition().getX() : maxU; | |
minV = t.getPosition().getY() < minV ? t.getPosition().getY() : minV; | |
maxV = t.getPosition().getY() > maxV ? t.getPosition().getY() : maxV; | |
} | |
for (int i = 0; i < f.texCoords.length; i++) | |
{ | |
TextureCoordinate t = f.texCoords[i]; | |
float U = (t.getPosition().getX() - minU) / (maxU - minU); | |
float V = (t.getPosition().getY() - minV) / (maxV - minV); | |
Vector3f normPos = new Vector3f(U, V, t.getPosition().getZ()); | |
f.texCoords[i] = new TextureCoordinate(normPos); | |
} | |
} | |
putVertexData(f.verts[0], f.texCoords != null ? f.texCoords[0] : null, f.norms != null ? f.norms[0] : f.getNormal(), sprite, false); | |
putVertexData(f.verts[1], f.texCoords != null ? f.texCoords[1] : null, f.norms != null ? f.norms[1] : f.getNormal(), sprite, false); | |
putVertexData(f.verts[2], f.texCoords != null ? f.texCoords[2] : null, f.norms != null ? f.norms[2] : f.getNormal(), sprite, false); | |
putVertexData(f.verts[3], f.texCoords != null ? f.texCoords[3] : null, f.norms != null ? f.norms[3] : f.getNormal(), sprite, false); | |
buffer.flip(); | |
int[] data = new int[VERTICES_IN_QUAD * format.getNextOffset() / BYTES_IN_INT]; | |
buffer.asIntBuffer().get(data); | |
quads.add(new ColoredBakedQuad(data, -1, EnumFacing.getFacingFromVector(f.getNormal().normal.x, f.getNormal().normal.y, f.getNormal().normal.z))); | |
} | |
} | |
List<BakedQuad> quadList = new ArrayList<BakedQuad>(); | |
quadList.addAll(quads); | |
return quadList; | |
} | |
private void put(ByteBuffer buffer, VertexFormatElement e, Float... fs) | |
{ | |
Attributes.put(buffer, e, true, 0f, fs); | |
} | |
@SuppressWarnings("unchecked") | |
private final void putVertexData(Vertex v, TextureCoordinate t, Normal n, TextureAtlasSprite sprite, boolean isTriangle) | |
{ | |
int oldPos = buffer.position(); | |
Number[] ns = new Number[16]; | |
for (int i = 0; i < ns.length; i++) | |
ns[i] = 0f; | |
for (VertexFormatElement e : (List<VertexFormatElement>) format.getElements()) | |
{ | |
switch (e.getUsage()) | |
{ | |
case POSITION: | |
put(buffer, e, v.position.x, v.position.y, v.position.z, 1f); | |
break; | |
case COLOR: | |
if (v.color != null) | |
put(buffer, e, v.color.x, v.color.y, v.color.z, v.color.w); | |
else | |
put(buffer, e, 1f, 1f, 1f, 1f); | |
break; | |
case UV: | |
if (t != null) | |
{ | |
put(buffer, e, sprite.getInterpolatedU(t.getPosition().x * 16), sprite.getInterpolatedV(t.getPosition().y * 16), 0f, 1f); | |
} | |
else | |
put(buffer, e, 0f, 0f, 0f, 1f); | |
break; | |
case NORMAL: | |
put(buffer, e, n.normal.x, n.normal.y, n.normal.z, 1f); | |
break; | |
case GENERIC: | |
put(buffer, e, 0f, 0f, 0f, 0f); | |
break; | |
default: | |
break; | |
} | |
} | |
buffer.position(oldPos + format.getNextOffset()); | |
} | |
@Override | |
public boolean isAmbientOcclusion() | |
{ | |
return true; | |
} | |
@Override | |
public boolean isGui3d() | |
{ | |
return true; | |
} | |
@Override | |
public boolean isBuiltInRenderer() | |
{ | |
return false; | |
} | |
@Override | |
public TextureAtlasSprite getTexture() | |
{ | |
return this.textures.get(0); | |
} | |
@Override | |
public ItemCameraTransforms getItemCameraTransforms() | |
{ | |
return ItemCameraTransforms.DEFAULT; | |
} | |
@Override | |
public VertexFormat getFormat() | |
{ | |
return format; | |
} | |
@Override | |
public IBakedModel handleItemState(ItemStack stack) | |
{ | |
return this; | |
} | |
@Override | |
public OBJBakedModel handleBlockState(IBlockState state) | |
{ | |
// OBJBakedModel ret = this; | |
// if (state instanceof IExtendedBlockState) | |
// { | |
// IExtendedBlockState exState = (IExtendedBlockState) state; | |
// if (exState.getUnlistedNames().contains(OBJProperty.instance)) | |
// { | |
// OBJState s = (OBJState) exState.getValue(OBJProperty.instance); | |
// if (s != null) ret = getModel(s.getVisibleElements()); | |
// } | |
// | |
// if (exState.getPropertyNames().contains(PropertyDirection.create("facing"))) | |
// { | |
// EnumFacing f = (EnumFacing) exState.getValue(PropertyDirection.create("facing")); | |
// if (f != null) ret = ret.getRotatedModel(f); | |
// } | |
// } | |
if (state instanceof IExtendedBlockState) | |
{ | |
IExtendedBlockState exState = (IExtendedBlockState) state; | |
if (exState.getUnlistedNames().contains(OBJProperty.instance)) | |
{ | |
OBJState s = (OBJState) exState.getValue(OBJProperty.instance); | |
if (s != null) return getModel(s.getVisibleElements()); | |
} | |
} | |
return this; | |
} | |
public OBJBakedModel getModel(List<String> visibleElements) | |
{ | |
return new OBJBakedModel(model, new OBJState(visibleElements, this.model), format, this.textures); | |
} | |
public OBJBakedModel getRotatedModel(EnumFacing facing) | |
{ | |
return this; | |
} | |
@Override | |
public Pair<IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType) | |
{ | |
if (state instanceof IPerspectiveState) | |
{ | |
return Pair.of((IBakedModel) this, ((IPerspectiveState) state).forPerspective(cameraTransformType).apply(model).getMatrix()); | |
} | |
return Pair.of((IBakedModel) this, null); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment