blusunrize.immersiveengineering.client.models.IESmartObjModel.java Source code

Java tutorial

Introduction

Here is the source code for blusunrize.immersiveengineering.client.models.IESmartObjModel.java

Source

/*
 * BluSunrize
 * Copyright (c) 2017
 *
 * This code is licensed under "Blu's License of Common Sense"
 * Details can be found in the license file in the root folder of this project
 */

package blusunrize.immersiveengineering.client.models;

import blusunrize.immersiveengineering.api.ApiUtils;
import blusunrize.immersiveengineering.api.ComparableItemStack;
import blusunrize.immersiveengineering.api.IEProperties;
import blusunrize.immersiveengineering.api.shader.CapabilityShader;
import blusunrize.immersiveengineering.api.shader.CapabilityShader.ShaderWrapper;
import blusunrize.immersiveengineering.api.shader.IShaderItem;
import blusunrize.immersiveengineering.api.shader.ShaderCase;
import blusunrize.immersiveengineering.api.shader.ShaderCase.ShaderLayer;
import blusunrize.immersiveengineering.client.ClientUtils;
import blusunrize.immersiveengineering.client.models.smart.ConnModelReal.ExtBlockstateAdapter;
import blusunrize.immersiveengineering.common.util.chickenbones.Matrix4;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.block.model.ItemOverrideList;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.obj.OBJModel;
import net.minecraftforge.client.model.obj.OBJModel.*;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.LightUtil;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad.Builder;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;

import javax.vecmath.Matrix4f;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@SuppressWarnings("deprecation")
public class IESmartObjModel extends OBJBakedModel {
    public static Cache<ComparableItemStack, IBakedModel> cachedBakedItemModels = CacheBuilder.newBuilder()
            .maximumSize(100).expireAfterAccess(60, TimeUnit.SECONDS).build();
    public static HashMap<ExtBlockstateAdapter, List<BakedQuad>> modelCache = new HashMap<>();
    IBakedModel baseModel;
    HashMap<TransformType, Matrix4> transformationMap = new HashMap<TransformType, Matrix4>();
    ImmutableList<BakedQuad> bakedQuads;
    ItemStack tempStack = ItemStack.EMPTY;
    IBlockState tempState;
    public EntityLivingBase tempEntity;
    public static EntityLivingBase tempEntityStatic;
    VertexFormat format;
    Map<String, String> texReplace = null;
    public TransformType lastCameraTransform = TransformType.FIXED;
    boolean isDynamic;

    public IESmartObjModel(IBakedModel baseModel, OBJModel model, IModelState state, VertexFormat format,
            ImmutableMap<String, TextureAtlasSprite> textures, HashMap<TransformType, Matrix4> transformationMap,
            boolean isDynamic) {
        model.super(model, state, format, textures);
        this.baseModel = baseModel;
        this.transformationMap = transformationMap;
        this.format = format;
        this.isDynamic = isDynamic;
    }

    @Override
    public Pair<? extends IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType) {
        this.lastCameraTransform = cameraTransformType;
        if (transformationMap == null || transformationMap.isEmpty())
            return super.handlePerspective(cameraTransformType);
        Matrix4 matrix = transformationMap.containsKey(cameraTransformType)
                ? transformationMap.get(cameraTransformType).copy()
                : new Matrix4();

        if (!this.tempStack.isEmpty() && this.tempStack.getItem() instanceof IOBJModelCallback)
            matrix = ((IOBJModelCallback) this.tempStack.getItem()).handlePerspective(this.tempStack,
                    cameraTransformType, matrix, tempEntity);

        //matrix = new Matrix4(); //Assign Matrixes here manually in debug mode, then move them to the actual registration method
        //Dynamic stuff to use when figurign out positioning for new items!
        //if(cameraTransformType==TransformType.FIRST_PERSON_RIGHT_HAND)//FP_R
        //   matrix =  new Matrix4().scale(.375, .4375, .375).translate(-.25, 1, .5).rotate(Math.PI*.5, 0, 1, 0);
        //else if(cameraTransformType==TransformType.FIRST_PERSON_LEFT_HAND)//FP_L
        //   matrix = new Matrix4().scale(-.375, .4375, .375).translate(.25, 1, .5).rotate(-Math.PI*.5, 0, 1, 0);
        //else if(cameraTransformType==TransformType.THIRD_PERSON_RIGHT_HAND) //TP_R
        //   matrix = new Matrix4().translate(0, .5, .1);
        //else if(cameraTransformType==TransformType.THIRD_PERSON_LEFT_HAND) //TP_L
        //   matrix = new Matrix4().translate(0, .5, .1);
        //else if(cameraTransformType==TransformType.FIXED) //FIXED
        //   matrix = new Matrix4();
        //else if(cameraTransformType==TransformType.GUI) //INV
        //   matrix = new Matrix4().rotate(-Math.PI/4, 0, 0, 1).rotate(Math.PI/8, 0, 1, 0);
        //if (cameraTransformType==TransformType.GROUND)//GROUND
        //   matrix = new Matrix4().scale(.5, .5, .5).translate(0, .5, 0);

        return Pair.of(this, matrix.toMatrix4f());
    }

    VertexFormat getFormat() {
        return this.format;
    }

    @Override
    public boolean isBuiltInRenderer() {
        return isDynamic;
    }

    @Override
    public ItemOverrideList getOverrides() {
        return overrideList;
    }

    ItemOverrideList overrideList = new ItemOverrideList(new ArrayList<>()) {
        @Override
        public IBakedModel handleItemState(IBakedModel originalModel, ItemStack stack, World world,
                EntityLivingBase entity) {
            tempEntityStatic = entity;
            ComparableItemStack comp = ApiUtils.createComparableItemStack(stack, false, true);
            if (comp == null)
                return originalModel;
            IBakedModel model = cachedBakedItemModels.getIfPresent(comp);
            if (model == null) {
                if (originalModel instanceof IESmartObjModel) {
                    IESmartObjModel newModel = (IESmartObjModel) originalModel;

                    ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
                    builder.put(ModelLoader.White.LOCATION.toString(), ModelLoader.White.INSTANCE);
                    TextureAtlasSprite missing = Minecraft.getMinecraft().getTextureMapBlocks()
                            .getAtlasSprite(new ResourceLocation("missingno").toString());

                    for (String s : newModel.getModel().getMatLib().getMaterialNames()) {
                        TextureAtlasSprite sprite = null;
                        if (stack.hasCapability(CapabilityShader.SHADER_CAPABILITY, null)) {
                            ShaderWrapper wrapper = stack.getCapability(CapabilityShader.SHADER_CAPABILITY, null);
                            ItemStack shader = wrapper.getShaderItem();
                            if (!shader.isEmpty() && shader.getItem() instanceof IShaderItem) {
                                ShaderCase sCase = ((IShaderItem) shader.getItem()).getShaderCase(shader, stack,
                                        wrapper.getShaderType());
                                if (sCase != null) {
                                    ResourceLocation rl = sCase.getReplacementSprite(shader, stack, s, 0);
                                    sprite = ClientUtils.getSprite(rl);
                                }
                            }
                        }
                        if (sprite == null && stack.getItem() instanceof IOBJModelCallback)
                            sprite = ((IOBJModelCallback) stack.getItem()).getTextureReplacement(stack, s);
                        if (sprite == null)
                            sprite = Minecraft.getMinecraft().getTextureMapBlocks()
                                    .getAtlasSprite(newModel.getModel().getMatLib().getMaterial(s).getTexture()
                                            .getTextureLocation().toString());
                        if (sprite == null)
                            sprite = missing;
                        builder.put(s, sprite);
                    }
                    builder.put("missingno", missing);
                    IESmartObjModel bakedModel = new IESmartObjModel(newModel.baseModel, newModel.getModel(),
                            newModel.getState(), newModel.getFormat(), builder.build(), transformationMap,
                            isDynamic);
                    bakedModel.tempStack = stack;
                    bakedModel.tempEntity = entity;
                    model = bakedModel;
                } else
                    model = originalModel;
                comp.copy();
                cachedBakedItemModels.put(comp, model);
            }
            if (model instanceof IESmartObjModel) {
                ((IESmartObjModel) model).tempStack = stack;
                ((IESmartObjModel) model).tempEntity = entity;
            }
            return model;
        }
    };

    @Override
    public List<BakedQuad> getQuads(IBlockState blockState, EnumFacing side, long rand) {
        if (side != null)
            return ImmutableList.of();
        OBJState objState = null;
        Map<String, String> tex = null;
        if (blockState instanceof IExtendedBlockState) {
            IExtendedBlockState ext = (IExtendedBlockState) blockState;
            if (ext.getUnlistedNames().contains(Properties.AnimationProperty)) {
                IModelState modState = ext.getValue(Properties.AnimationProperty);
                if (modState instanceof OBJState)
                    objState = (OBJState) modState;
            }
            if (ext.getUnlistedNames().contains(IEProperties.OBJ_TEXTURE_REMAP))
                tex = ext.getValue(IEProperties.OBJ_TEXTURE_REMAP);
        }
        return getQuads(blockState, side, rand, objState, tex, false);
    }

    public List<BakedQuad> getQuads(IBlockState blockState, EnumFacing side, long rand, OBJState objstate,
            Map<String, String> tex, boolean addAnimationAndTex) {
        texReplace = tex;
        this.tempState = blockState;
        if (blockState instanceof IExtendedBlockState) {
            IExtendedBlockState exState = (IExtendedBlockState) blockState;
            ExtBlockstateAdapter adapter;
            if (objstate != null) {
                if (objstate.parent == null || objstate.parent == TRSRTransformation.identity())
                    objstate.parent = this.getState();
                if (objstate.getVisibilityMap().containsKey(Group.ALL)
                        || objstate.getVisibilityMap().containsKey(Group.ALL_EXCEPT))
                    this.updateStateVisibilityMap(objstate);
            }
            if (addAnimationAndTex)
                adapter = new ExtBlockstateAdapter(exState, MinecraftForgeClient.getRenderLayer(),
                        ExtBlockstateAdapter.CONNS_OBJ_CALLBACK, new Object[] { objstate, tex });
            else
                adapter = new ExtBlockstateAdapter(exState, MinecraftForgeClient.getRenderLayer(),
                        ExtBlockstateAdapter.CONNS_OBJ_CALLBACK);
            List<BakedQuad> quads = modelCache.get(adapter);
            if (quads == null) {
                IESmartObjModel model = null;
                if (objstate != null)
                    model = new IESmartObjModel(baseModel, getModel(), objstate, getFormat(), getTextures(),
                            transformationMap, isDynamic);
                if (model == null)
                    model = new IESmartObjModel(baseModel, getModel(), this.getState(), getFormat(), getTextures(),
                            transformationMap, isDynamic);
                model.tempState = blockState;
                model.texReplace = tex;
                quads = model.buildQuads();
                modelCache.put(adapter, quads);
            }
            return Collections.synchronizedList(Lists.newArrayList(quads));
        }
        if (bakedQuads == null)
            bakedQuads = buildQuads();
        List<BakedQuad> quadList = Lists.newArrayList(bakedQuads);
        return Collections.synchronizedList(quadList);
    }

    private ImmutableList<BakedQuad> buildQuads() {
        List<BakedQuad> quads = Lists.newArrayList();
        ItemStack shader = ItemStack.EMPTY;
        ShaderCase sCase = null;
        IOBJModelCallback callback = null;
        Object callbackObject = null;
        if (!this.tempStack.isEmpty() && tempStack.hasCapability(CapabilityShader.SHADER_CAPABILITY, null)) {
            ShaderWrapper wrapper = tempStack.getCapability(CapabilityShader.SHADER_CAPABILITY, null);
            if (wrapper != null) {
                shader = wrapper.getShaderItem();
                if (!shader.isEmpty() && shader.getItem() instanceof IShaderItem)
                    sCase = ((IShaderItem) shader.getItem()).getShaderCase(shader, tempStack,
                            wrapper.getShaderType());
            }
        } else if (this.tempState != null && this.tempState instanceof IExtendedBlockState
                && ((IExtendedBlockState) this.tempState).getUnlistedNames()
                        .contains(CapabilityShader.BLOCKSTATE_PROPERTY)) {
            ShaderWrapper wrapper = ((IExtendedBlockState) this.tempState)
                    .getValue(CapabilityShader.BLOCKSTATE_PROPERTY);
            if (wrapper != null) {
                shader = wrapper.getShaderItem();
                if (!shader.isEmpty() && shader.getItem() instanceof IShaderItem)
                    sCase = ((IShaderItem) shader.getItem()).getShaderCase(shader, null, wrapper.getShaderType());
            }
        }

        if (!this.tempStack.isEmpty() && tempStack.getItem() instanceof IOBJModelCallback) {
            callback = (IOBJModelCallback) tempStack.getItem();
            callbackObject = this.tempStack;
        } else if (this.tempState != null && this.tempState instanceof IExtendedBlockState
                && ((IExtendedBlockState) this.tempState).getUnlistedNames().contains(IOBJModelCallback.PROPERTY)) {
            callback = ((IExtendedBlockState) this.tempState).getValue(IOBJModelCallback.PROPERTY);
            callbackObject = this.tempState;
        }
        for (String groupName : getModel().getMatLib().getGroups().keySet()) {
            List<Pair<BakedQuad, ShaderLayer>> temp = addQuadsForGroup(callback, callbackObject, groupName, sCase,
                    shader);
            quads.addAll(temp.stream().filter(Objects::nonNull).map(Pair::getKey).collect(Collectors.toList()));
        }

        if (callback != null)
            quads = callback.modifyQuads(callbackObject, quads);
        return ImmutableList.copyOf(quads);
    }

    public <T> List<Pair<BakedQuad, ShaderLayer>> addQuadsForGroup(IOBJModelCallback<T> callback, T callbackObject,
            String groupName, ShaderCase sCase, ItemStack shader) {
        int maxPasses = 1;
        if (sCase != null)
            maxPasses = sCase.getLayers().length;
        Group g = getModel().getMatLib().getGroups().get(groupName);
        List<Face> faces = new ArrayList<>();
        Optional<TRSRTransformation> transform = Optional.empty();
        if (this.getState() instanceof OBJState) {
            OBJState state = (OBJState) this.getState();
            if (state.parent != null)
                transform = state.parent.apply(Optional.empty());
            if (callback != null)
                transform = callback.applyTransformations(callbackObject, groupName, transform);
            if (state.getGroupsWithVisibility(true).contains(groupName))
                faces.addAll(g.applyTransform(transform));
        } else {
            transform = getState().apply(Optional.empty());
            if (callback != null)
                transform = callback.applyTransformations(callbackObject, groupName, transform);
            faces.addAll(g.applyTransform(transform));
        }
        List<Pair<BakedQuad, ShaderLayer>> quads = new ArrayList<>(faces.size());
        for (int pass = 0; pass < maxPasses; pass++) {
            ShaderLayer shaderLayer = sCase != null ? sCase.getLayers()[pass] : null;
            if (callback != null)
                if (!callback.shouldRenderGroup(callbackObject, groupName))
                    continue;
            if (sCase != null)
                if (!sCase.renderModelPartForPass(shader, tempStack, groupName, pass))
                    continue;

            int argb = 0xffffffff;
            if (sCase != null)
                argb = sCase.getARGBColourModifier(shader, tempStack, groupName, pass);
            else if (callback != null)
                argb = callback.getRenderColour(callbackObject, groupName);

            boolean dynQuad = false;

            float[] colour = { (argb >> 16 & 255) / 255f, (argb >> 8 & 255) / 255f, (argb & 255) / 255f,
                    (argb >> 24 & 255) / 255f };

            for (int faceId = 0; faceId < faces.size(); faceId++) {
                Face f = faces.get(faceId);
                TextureAtlasSprite tempSprite = null;
                if (this.getModel().getMatLib().getMaterial(f.getMaterialName()).isWhite()
                        && !"null".equals(f.getMaterialName())) {
                    for (Vertex v : f.getVertices())
                        if (!v.getMaterial()
                                .equals(this.getModel().getMatLib().getMaterial(v.getMaterial().getName())))
                            v.setMaterial(this.getModel().getMatLib().getMaterial(v.getMaterial().getName()));
                    tempSprite = ModelLoader.White.INSTANCE;
                } else {
                    if (sCase != null) {
                        ResourceLocation rl = sCase.getReplacementSprite(shader, tempStack, groupName, pass);
                        if (rl != null)
                            tempSprite = ClientUtils.getSprite(rl);
                    }
                    if (tempSprite == null && callback != null)
                        tempSprite = callback.getTextureReplacement(callbackObject, f.getMaterialName());
                    if (tempSprite == null && tempState != null && texReplace != null) {
                        String s = texReplace.get(groupName);
                        if (s != null)
                            tempSprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(s);
                    }
                    if (tempSprite == null && !"null".equals(f.getMaterialName()))
                        tempSprite = Minecraft.getMinecraft().getTextureMapBlocks()
                                .getAtlasSprite(this.getModel().getMatLib().getMaterial(f.getMaterialName())
                                        .getTexture().getTextureLocation().toString());
                }
                if (tempSprite == null)
                    tempSprite = Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite();
                if (tempSprite != null) {
                    Builder builder = new Builder(getFormat());
                    builder.setQuadOrientation(
                            EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z));
                    builder.setTexture(tempSprite);
                    builder.setQuadTint(pass);
                    Normal faceNormal = f.getNormal();
                    TextureCoordinate[] uvs = new TextureCoordinate[4];
                    boolean renderFace = true;
                    for (int i = 0; i < 4; i++) {
                        Vertex vertex = f.getVertices()[i];
                        //V-Flip is processed here already, rather than in the later method, since it's needed for easy UV comparissons on the Shader Layers
                        uvs[i] = vertex.hasTextureCoordinate()
                                ? new TextureCoordinate(vertex.getTextureCoordinate().u,
                                        1 - vertex.getTextureCoordinate().v, vertex.getTextureCoordinate().w)
                                : TextureCoordinate.getDefaultUVs()[i];

                        if (shaderLayer != null) {
                            double[] texBounds = shaderLayer.getTextureBounds();
                            if (texBounds != null) {
                                if (texBounds[0] > uvs[i].u || uvs[i].u > texBounds[2] || texBounds[1] > uvs[i].v
                                        || uvs[i].v > texBounds[3])//if any uvs are outside the layers bounds
                                {
                                    renderFace = false;
                                    break;
                                }
                                double dU = texBounds[2] - texBounds[0];
                                double dV = texBounds[3] - texBounds[1];
                                //Rescaling to the partial bounds that the texture represents
                                uvs[i].u = (float) ((uvs[i].u - texBounds[0]) / dU);
                                uvs[i].v = (float) ((uvs[i].v - texBounds[1]) / dV);
                            }
                            //Rescaling to the selective area of the texture that is used
                            double[] cutBounds = shaderLayer.getCutoutBounds();
                            if (cutBounds != null) {
                                double dU = cutBounds[2] - cutBounds[0];
                                double dV = cutBounds[3] - cutBounds[1];
                                uvs[i].u = (float) (cutBounds[0] + dU * uvs[i].u);
                                uvs[i].v = (float) (cutBounds[1] + dV * uvs[i].v);
                            }
                        }
                    }
                    if (renderFace) {
                        for (int i = 0; i < 4; i++)
                            putVertexData(builder, f.getVertices()[i], faceNormal, uvs[i], tempSprite, colour);
                        quads.add(new ImmutablePair<>(builder.build(),
                                shaderLayer != null && shaderLayer.isDynamicLayer() ? shaderLayer : null));
                    }
                }
            }
        }
        return quads;
    }

    protected final void putVertexData(IVertexConsumer builder, Vertex v, Normal faceNormal,
            TextureCoordinate texCoord, TextureAtlasSprite sprite, float[] colour) {
        for (int e = 0; e < getFormat().getElementCount(); e++) {
            switch (getFormat().getElement(e).getUsage()) {
            case POSITION:
                builder.put(e, v.getPos().x, v.getPos().y, v.getPos().z, v.getPos().w);
                break;
            case COLOR:
                float d;
                if (v.hasNormal())
                    d = LightUtil.diffuseLight(v.getNormal().x, v.getNormal().y, v.getNormal().z);
                else
                    d = LightUtil.diffuseLight(faceNormal.x, faceNormal.y, faceNormal.z);
                if (v.getMaterial() != null)
                    builder.put(e, d * v.getMaterial().getColor().x * colour[0],
                            d * v.getMaterial().getColor().y * colour[1],
                            d * v.getMaterial().getColor().z * colour[2], v.getMaterial().getColor().w * colour[3]);
                else
                    builder.put(e, d * colour[0], d * colour[1], d * colour[2], 1 * colour[3]);
                break;
            case UV:
                if (sprite == null)//Double Safety. I have no idea how it even happens, but it somehow did .-.
                    sprite = Minecraft.getMinecraft().getTextureMapBlocks().getMissingSprite();
                builder.put(e, sprite.getInterpolatedU(texCoord.u * 16), sprite.getInterpolatedV((texCoord.v) * 16), //v-flip used to be processed here but was moved because of shader layers
                        0, 1);
                break;
            case NORMAL:
                if (!v.hasNormal())
                    builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 0);
                else
                    builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 0);
                break;
            default:
                builder.put(e);
            }
        }
    }

    static int getExtendedStateHash(IExtendedBlockState state) {
        return state.hashCode() * 31 + state.getUnlistedProperties().hashCode();
    }

    //   private final LoadingCache<Integer, IESmartObjModel> ieobjcache = CacheBuilder.newBuilder().maximumSize(20).build(new CacheLoader<Integer, IESmartObjModel>()
    //   {
    //      public IESmartObjModel load(IModelState state) throws Exception
    //      {
    //         return new IESmartObjModel(baseModel, getModel(), state, getFormat(), getTextures(), transformationMap);
    //      }
    //   });

    protected void updateStateVisibilityMap(OBJState state) {
        if (state.getVisibilityMap().containsKey(Group.ALL)) {
            boolean operation = state.getVisibilityMap().get(Group.ALL);
            state.getVisibilityMap().clear();
            for (String s : this.getModel().getMatLib().getGroups().keySet()) {
                state.getVisibilityMap().put(s, OBJState.Operation.SET_TRUE.performOperation(operation));
            }
        } else if (state.getVisibilityMap().containsKey(Group.ALL_EXCEPT)) {
            List<String> exceptList = state.getGroupNamesFromMap().subList(1, state.getGroupNamesFromMap().size());
            state.getVisibilityMap().remove(Group.ALL_EXCEPT);
            for (String s : this.getModel().getMatLib().getGroups().keySet()) {
                if (!exceptList.contains(s)) {
                    state.getVisibilityMap().put(s,
                            OBJState.Operation.SET_TRUE.performOperation(state.getVisibilityMap().get(s)));
                }
            }
        } else {
            for (String s : state.getVisibilityMap().keySet()) {
                state.getVisibilityMap().put(s,
                        OBJState.Operation.SET_TRUE.performOperation(state.getVisibilityMap().get(s)));
            }
        }
    }

    static Field f_textures;

    public static ImmutableMap<String, TextureAtlasSprite> getTexturesForOBJModel(IBakedModel model) {
        try {
            if (f_textures == null) {
                f_textures = OBJBakedModel.class.getDeclaredField("textures");
                f_textures.setAccessible(true);
            }
            return (ImmutableMap<String, TextureAtlasSprite>) f_textures.get(model);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public ImmutableMap<String, TextureAtlasSprite> getTextures() {
        try {
            if (f_textures == null) {
                f_textures = OBJBakedModel.class.getDeclaredField("textures");
                f_textures.setAccessible(true);
            }
            return (ImmutableMap<String, TextureAtlasSprite>) f_textures.get(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}