All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.malisis.core.renderer.MalisisRenderer Maven / Gradle / Ivy

Go to download

MalisisCore is a framework dedicated to simplify many processes required during a mod development.

There is a newer version: 1.12.2-6.4.0
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Ordinastie
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package net.malisis.core.renderer;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import net.malisis.core.MalisisCore;
import net.malisis.core.asm.AsmUtils;
import net.malisis.core.renderer.element.Face;
import net.malisis.core.renderer.element.Shape;
import net.malisis.core.renderer.element.Vertex;
import net.malisis.core.renderer.element.shape.Cube;
import net.malisis.core.renderer.font.FontRenderOptions;
import net.malisis.core.renderer.font.MalisisFont;
import net.malisis.core.renderer.icon.MalisisIcon;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.client.renderer.DestroyBlockProgress;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.client.IItemRenderer;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.util.ForgeDirection;

import org.lwjgl.opengl.GL11;

import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.relauncher.ReflectionHelper;

/**
 * Base class for rendering. Handle the rendering for {@link ISimpleBlockRenderingHandler}, {@link TileEntitySpecialRenderer}, and
 * {@link IItemRenderer}. Provides easy registration of the renderer, and automatically sets up the context for the rendering.
 *
 * @author Ordinastie
 *
 */
public class MalisisRenderer extends TileEntitySpecialRenderer implements ISimpleBlockRenderingHandler, IItemRenderer, IRenderWorldLast
{
	//Reference to Minecraft.renderGlobal.damagedBlocks (lazy loaded)
	/** The damaged blocks. */
	private static Map damagedBlocks;
	/** The damaged icons. */
	protected static IIcon[] damagedIcons;
	/** Reference to Tessellator.isDrawing field **/
	private static Field isDrawingField;
	/** Whether this {@link MalisisRenderer} initialized. (initialize() already called) */
	private boolean initialized = false;
	/** Id of this {@link MalisisRenderer}. */
	protected int renderId = -1;
	/** Tessellator reference. */
	protected Tessellator t = Tessellator.instance;
	/** Current world reference (ISBRH/TESR/IRWL). */
	protected IBlockAccess world;
	/** RenderBlocks reference (ISBRH). */
	protected RenderBlocks renderBlocks;
	/** Whether render coordinates already shifted (ISBRH). */
	protected boolean isShifted = false;
	/** Block to render (ISBRH/TESR). */
	protected Block block;
	/** Metadata of the block to render (ISBRH/TESR). */
	protected int blockMetadata;
	/** Position of the block (ISBRH/TESR). */
	protected int x, y, z;
	/** TileEntity currently drawing (for TESR). */
	protected TileEntity tileEntity;
	/** Partial tick time (TESR/IRWL). */
	protected float partialTick = 0;
	/** ItemStack to render (ITEM). */
	protected ItemStack itemStack;
	/** ItemRenderType of item rendering (ITEM). */
	protected ItemRenderType itemRenderType;
	/** RenderGlobal reference (IRWL) */
	protected RenderGlobal renderGlobal;
	/** Type of rendering. */
	protected RenderType renderType;
	/** Mode of rendering (GL constant). */
	protected int drawMode;
	/** Current shape being rendered. */
	protected Shape shape = new Cube();
	/** Current face being rendered. */
	protected Face face;
	/** Current parameters for the shape being rendered. */
	protected RenderParameters rp = new RenderParameters();
	/** Current parameters for the face being rendered. */
	protected RenderParameters params;
	/** Base brightness of the block. */
	protected int baseBrightness;
	/** An override texture set by the renderer. */
	protected IIcon overrideTexture;

	/** Whether the damage for the blocks should be handled by this {@link MalisisRenderer} (for TESR). */
	protected boolean getBlockDamage = false;
	/** Current block destroy progression (for TESR). */
	protected DestroyBlockProgress destroyBlockProgress = null;

	/** Whether at least one vertex has been drawn. */
	protected boolean vertexDrawn = false;

	/**
	 * Instantiates a new {@link MalisisRenderer}.
	 */
	public MalisisRenderer()
	{
		this.renderId = RenderingRegistry.getNextAvailableRenderId();
		this.t = Tessellator.instance;
	}

	/**
	 * Gets the partialTick for this frame. Used for TESR and ITEMS
	 *
	 * @return the partial tick
	 */
	public float getPartialTick()
	{
		return partialTick;
	}

	// #region set()
	/**
	 * Resets data so this {@link MalisisRenderer} can be reused.
	 */
	public void reset()
	{
		this.renderType = RenderType.UNSET;
		this.drawMode = 0;
		this.world = null;
		this.block = null;
		this.blockMetadata = 0;
		this.x = 0;
		this.y = 0;
		this.z = 0;
		this.overrideTexture = null;
		this.destroyBlockProgress = null;
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param world the world
	 * @param block the block
	 * @param x the x
	 * @param y the y
	 * @param z the z
	 * @param metadata the metadata
	 */
	public void set(IBlockAccess world, Block block, int x, int y, int z, int metadata)
	{
		this.world = world;
		this.block = block;
		this.blockMetadata = metadata;
		this.x = x;
		this.y = y;
		this.z = z;
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param world the world
	 */
	public void set(IBlockAccess world)
	{
		this.world = world;
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param block the block
	 */
	public void set(Block block)
	{
		set(world, block, x, y, z, blockMetadata);
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param blockMetadata the block metadata
	 */
	public void set(int blockMetadata)
	{
		set(world, block, x, y, z, blockMetadata);
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param block the block
	 * @param blockMetadata the block metadata
	 */
	public void set(Block block, int blockMetadata)
	{
		set(world, block, x, y, z, blockMetadata);
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param x the x
	 * @param y the y
	 * @param z the z
	 */
	public void set(int x, int y, int z)
	{
		set(world, block, x, y, z, blockMetadata);
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param te the te
	 * @param partialTick the partial tick
	 */
	public void set(TileEntity te, float partialTick)
	{
		set(te.getWorld(), te.getBlockType(), te.xCoord, te.yCoord, te.zCoord, te.getBlockMetadata());
		this.partialTick = partialTick;
		this.tileEntity = te;
	}

	/**
	 * Sets informations for this {@link MalisisRenderer}.
	 *
	 * @param type the type
	 * @param itemStack the item stack
	 */
	public void set(ItemRenderType type, ItemStack itemStack)
	{
		if (itemStack.getItem() instanceof ItemBlock)
			set(Block.getBlockFromItem(itemStack.getItem()));
		this.itemStack = itemStack;
		this.itemRenderType = type;
	}

	// #end

	// #region ISBRH
	/**
	 * Renders inventory block.
	 *
	 * @param block the block
	 * @param metadata the metadata
	 * @param modelId renderId
	 * @param renderer RenderBlocks
	 */
	@Override
	public void renderInventoryBlock(Block block, int metadata, int modelId, RenderBlocks renderer)
	{
		set(block, metadata);
		renderBlocks = renderer;
		prepare(RenderType.ISBRH_INVENTORY);
		render();
		clean();
	}

	/**
	 * Renders world block.
	 *
	 * @param world the world
	 * @param x the x
	 * @param y the y
	 * @param z the z
	 * @param block the block
	 * @param modelId renderId
	 * @param renderer RenderBlocks
	 * @return true, if something was drawn, false otherwise
	 */
	@Override
	public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
	{
		set(world, block, x, y, z, world.getBlockMetadata(x, y, z));
		tileEntity = world.getTileEntity(x, y, z);
		renderBlocks = renderer;
		vertexDrawn = false;

		prepare(RenderType.ISBRH_WORLD);
		if (renderer.hasOverrideBlockTexture())
			overrideTexture = renderer.overrideBlockTexture;
		render();
		clean();
		return vertexDrawn;
	}

	/**
	 * Checks whether this {@link MalisisRenderer} should handle the rendering in inventory
	 *
	 * @param modelId renderId
	 * @return true, if this {@link MalisisRenderer} should be used for rendering the block in inventory
	 */
	@Override
	public boolean shouldRender3DInInventory(int modelId)
	{
		return true;
	}

	// #end ISBRH

	// #region IItemRenderer
	/**
	 * Checks whether to use this {@link MalisisRenderer} for the specified {@link net.minecraftforge.client.IItemRenderer.ItemRenderType}.
	 *
	 * @param item the item
	 * @param type ItemRenderType
	 * @return true, if this {@link MalisisRenderer} should be used for rendering the block in inventory
	 */
	@Override
	public boolean handleRenderType(ItemStack item, ItemRenderType type)
	{
		return true;
	}

	/**
	 * Checks whether a render helper should be used for this {@link MalisisRenderer}.
	 *
	 * @param type the type
	 * @param item the item
	 * @param helper the helper
	 * @return true, if successful
	 */
	@Override
	public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper)
	{
		return true;
	}

	/**
	 * Renders the item.
	 *
	 * @param type the type
	 * @param item the item
	 * @param data the data
	 */
	@Override
	public void renderItem(ItemRenderType type, ItemStack item, Object... data)
	{
		set(type, item);
		prepare(RenderType.ITEM_INVENTORY);
		render();
		clean();
	}

	// #end IItemRenderer

	// #region TESR
	/**
	 * Renders a {@link TileEntitySpecialRenderer}.
	 *
	 * @param te the TileEntity
	 * @param x the x
	 * @param y the y
	 * @param z the z
	 * @param partialTick the partial tick
	 */
	@Override
	public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTick)
	{
		set(te, partialTick);
		prepare(RenderType.TESR_WORLD, x, y, z);
		render();
		if (getBlockDamage)
		{
			destroyBlockProgress = getBlockDestroyProgress();
			if (destroyBlockProgress != null)
			{
				next();

				GL11.glEnable(GL11.GL_BLEND);
				OpenGlHelper.glBlendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR, GL11.GL_ONE, GL11.GL_ZERO);
				GL11.glAlphaFunc(GL11.GL_GREATER, 0);
				GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F);

				t.disableColor();
				renderDestroyProgress();
				next();
				GL11.glDisable(GL11.GL_BLEND);
			}
		}
		clean();
	}

	// #end TESR

	// #region IRenderWorldLast
	@Override
	public boolean shouldSetViewportPosition()
	{
		return true;
	}

	@Override
	public boolean shouldRender(RenderWorldLastEvent event, IBlockAccess world)
	{
		return true;
	}

	@Override
	public void renderWorldLastEvent(RenderWorldLastEvent event, IBlockAccess world)
	{
		set(world);
		partialTick = event.partialTicks;
		renderGlobal = event.context;
		double x = 0, y = 0, z = 0;
		if (shouldSetViewportPosition())
		{
			EntityClientPlayerMP p = Minecraft.getMinecraft().thePlayer;
			x = -(p.lastTickPosX + (p.posX - p.lastTickPosX) * partialTick);
			y = -(p.lastTickPosY + (p.posY - p.lastTickPosY) * partialTick);
			z = -(p.lastTickPosZ + (p.posZ - p.lastTickPosZ) * partialTick);
		}

		prepare(RenderType.WORLD_LAST, x, y, z);

		render();

		clean();
	}

	// #end IRenderWorldLast

	// #region prepare()
	/**
	 * Prepares the {@link Tessellator} and the GL states for the renderType. data is only used for TESR and IRWL.
* TESR and IRWL rendering are surrounded by glPushAttrib(GL_LIGHTING_BIT) and block texture sheet is bound. * * @param renderType the render type * @param data the data */ public void prepare(RenderType renderType, double... data) { _initialize(); vertexDrawn = false; this.renderType = renderType; if (renderType == RenderType.ISBRH_WORLD) { tessellatorShift(); } else if (renderType == RenderType.ISBRH_INVENTORY) { GL11.glTranslatef(-0.5F, -0.5F, -0.5F); startDrawing(); } else if (renderType == RenderType.ITEM_INVENTORY) { GL11.glPushAttrib(GL11.GL_LIGHTING_BIT); startDrawing(); } else if (renderType == RenderType.TESR_WORLD) { GL11.glPushAttrib(GL11.GL_LIGHTING_BIT); RenderHelper.disableStandardItemLighting(); GL11.glEnable(GL11.GL_COLOR_MATERIAL); GL11.glShadeModel(GL11.GL_SMOOTH); GL11.glPushMatrix(); GL11.glTranslated(data[0], data[1], data[2]); bindTexture(TextureMap.locationBlocksTexture); startDrawing(); } else if (renderType == RenderType.WORLD_LAST) { GL11.glPushAttrib(GL11.GL_LIGHTING_BIT); RenderHelper.disableStandardItemLighting(); GL11.glEnable(GL11.GL_COLOR_MATERIAL); GL11.glShadeModel(GL11.GL_SMOOTH); GL11.glPushMatrix(); GL11.glTranslated(data[0], data[1], data[2]); bindTexture(TextureMap.locationBlocksTexture); startDrawing(); } } /** * Tells the {@link Tessellator} to start drawing GL_QUADS. */ public void startDrawing() { startDrawing(GL11.GL_QUADS); } /** * Tells the {@link Tessellator} to start drawing drawMode. * * @param drawMode the draw mode */ public void startDrawing(int drawMode) { if (isDrawing()) draw(); t.startDrawing(drawMode); this.drawMode = drawMode; } /** * Checks if the {@link Tessellator} is currently drawing. * * @return true, if is drawing */ public boolean isDrawing() { if (isDrawingField == null) isDrawingField = AsmUtils.changeFieldAccess(Tessellator.class, "isDrawing", "field_78415_z"); try { return isDrawingField.getBoolean(t); } catch (IllegalArgumentException | IllegalAccessException e) { MalisisCore.log.error("[MalisisRenderer] Failed to get Tessellator.isDrawing value", e); return false; } } /** * Triggers a draw and restart drawing with current {@link MalisisRenderer#drawMode}. */ public void next() { next(drawMode); } /** * Triggers a draw and restart drawing with drawMode. * * @param drawMode the draw mode */ public void next(int drawMode) { draw(); startDrawing(drawMode); } /** * Triggers a draw. */ public void draw() { if (isDrawing()) t.draw(); } /** * Cleans the current renderer state. */ public void clean() { if (renderType == RenderType.ISBRH_WORLD) { tessellatorUnshift(); } else if (renderType == RenderType.ISBRH_INVENTORY) { draw(); GL11.glTranslatef(0.5F, 0.5F, 0.5F); } else if (renderType == RenderType.ITEM_INVENTORY) { draw(); GL11.glPopAttrib(); } else if (renderType == RenderType.TESR_WORLD) { draw(); GL11.glPopMatrix(); GL11.glPopAttrib(); } else if (renderType == RenderType.WORLD_LAST) { draw(); GL11.glPopMatrix(); GL11.glPopAttrib(); } reset(); } /** * Shifts the {@link Tessellator} for ISBRH rendering. */ public void tessellatorShift() { if (isShifted) return; isShifted = true; t.addTranslation(x, y, z); } /** * Unshifts the {@link Tessellator} for ISBRH rendering. */ public void tessellatorUnshift() { if (!isShifted) return; isShifted = false; t.addTranslation(-x, -y, -z); } /** * Enables the blending for the rendering. Ineffective for ISBRH. */ public void enableBlending() { if (renderType == RenderType.ISBRH_WORLD) return; GL11.glEnable(GL11.GL_BLEND); GL11.glEnable(GL11.GL_COLOR_MATERIAL); GL11.glShadeModel(GL11.GL_SMOOTH); OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO); GL11.glAlphaFunc(GL11.GL_GREATER, 0.0F); } /** * Disables textures. */ public void disableTextures() { GL11.glDisable(GL11.GL_TEXTURE_2D); } /** * Enables textures */ public void enableTextures() { GL11.glEnable(GL11.GL_TEXTURE_2D); } @Override protected void bindTexture(ResourceLocation resourceLocaltion) { Minecraft.getMinecraft().getTextureManager().bindTexture(resourceLocaltion); } // #end prepare() /** * _initialize. */ protected final void _initialize() { if (initialized) return; initialize(); initialized = true; } /** * Initializes this {@link MalisisRenderer}. Does nothing by default.
* Called the first time a rendering is done and should be overridden if some setup is needed for the rendering (building shape and * parameters). */ protected void initialize() {} /** * Renders the block using the default Minecraft rendering system. */ public void renderStandard() { renderStandard(renderBlocks); } /** * Renders the blocks using the default Minecraft rendering system with the specified renderer. * * @param renderer the renderer */ public void renderStandard(RenderBlocks renderer) { if (renderer == null) return; boolean b = isShifted; if (b) tessellatorUnshift(); renderer.setRenderBoundsFromBlock(block); renderer.renderStandardBlock(block, x, y, z); if (b) tessellatorShift(); } /** * Main rendering method. Draws simple cube by default.
* Should be overridden to handle the rendering. */ public void render() { drawShape(shape, rp); } /** * Renders the destroy progress manually for TESR. Called if {@link MalisisRenderer#destroyBlockProgress} is not null. */ public void renderDestroyProgress() { if (destroyBlockProgress != null) overrideTexture = damagedIcons[destroyBlockProgress.getPartialBlockDamage()]; // enableBlending(); render(); } /** * Draws a {@link Shape} without {@link RenderParameters} (default will be used). * * @param shape the shape */ public void drawShape(Shape shape) { drawShape(shape, null); } /** * Draws a {@link Shape} with specified {@link RenderParameters}. * * @param s the s * @param params the params */ public void drawShape(Shape s, RenderParameters params) { if (s == null) return; shape = s; rp = params != null ? params : new RenderParameters(); //apply transformations s.applyMatrix(); // vertex position if (rp.vertexPositionRelativeToRenderBounds.get()) calcVertexesPosition(getRenderBounds()); if (rp.applyTexture.get()) applyTexture(s, rp); for (Face f : s.getFaces()) drawFace(f, f.getParameters()); } /** * Draws a {@link Face} with its own {@link RenderParameters}. * * @param face the face */ public void drawFace(Face face) { drawFace(face, face.getParameters()); } /** * Draws a {@link Face} with specified {@link RenderParameters}. * * @param f the f * @param faceParams the face params */ protected void drawFace(Face f, RenderParameters faceParams) { if (f == null) return; int vertexCount = f.getVertexes().length; if (vertexCount != 4 && renderType == RenderType.ISBRH_WORLD) { MalisisCore.log.error("[MalisisRenderer] Attempting to render a face containing {} vertexes in ISBRH. Ignored", vertexCount); return; } face = f; params = new RenderParameters(); params.merge(rp); params.merge(faceParams); if (!shouldRenderFace(face)) return; //use normals if available if ((renderType == RenderType.ITEM_INVENTORY || renderType == RenderType.ISBRH_INVENTORY || params.useNormals.get()) && params.direction.get() != null) t.setNormal(params.direction.get().offsetX, params.direction.get().offsetY, params.direction.get().offsetZ); baseBrightness = getBaseBrightness(); drawVertexes(face.getVertexes()); //we need to separate each face if (drawMode == GL11.GL_POLYGON || drawMode == GL11.GL_LINE || drawMode == GL11.GL_LINE_STRIP || drawMode == GL11.GL_LINE_LOOP) next(); } /** * * Draws an array of {@link Vertex vertexes} (usually {@link Face#getVertexes()}). * * @param vertexes the vertexes */ protected void drawVertexes(Vertex[] vertexes) { for (int i = 0; i < vertexes.length; i++) drawVertex(vertexes[i], i); } /** * Draws a single {@link Vertex}. * * @param vertex the vertex * @param number the offset inside the face. (Used for AO) */ protected void drawVertex(Vertex vertex, int number) { if (vertex == null) vertex = new Vertex(0, 0, 0); // brightness int brightness = calcVertexBrightness(vertex, (int[][]) params.aoMatrix.get(number)); vertex.setBrightness(brightness); // color int color = calcVertexColor(vertex, (int[][]) params.aoMatrix.get(number)); vertex.setColor(color); // alpha if (!params.usePerVertexAlpha.get()) vertex.setAlpha(params.alpha.get()); t.setColorRGBA_I(vertex.getColor(), vertex.getAlpha()); t.setBrightness(vertex.getBrightness()); if (params.useTexture.get()) t.addVertexWithUV(vertex.getX(), vertex.getY(), vertex.getZ(), vertex.getU(), vertex.getV()); else t.addVertex(vertex.getX(), vertex.getY(), vertex.getZ()); vertexDrawn = true; } /** * Draws a string at the specified coordinates, with color and shadow. The string gets translated. Uses FontRenderer.drawString(). * * @param font the font * @param text the text * @param x the x * @param y the y * @param z the z * @param fro the fro */ public void drawText(MalisisFont font, String text, float x, float y, float z, FontRenderOptions fro) { if (font == null) font = MalisisFont.minecraftFont; if (fro == null) fro = new FontRenderOptions(); font.render(this, text, x, y, z, fro); } /** * Gets the IIcon corresponding to the specified {@link RenderParameters}. * * @param params the params * @return the icon */ protected IIcon getIcon(RenderParameters params) { IIcon icon = params.icon.get(); if (params.useCustomTexture.get()) icon = new MalisisIcon(); //use a generic icon where UVs go from 0 to 1 else if (overrideTexture != null) icon = overrideTexture; else if (block != null && icon == null) { int side = 0; if (params.textureSide.get() != null) side = params.textureSide.get().ordinal(); if (world != null && params.useWorldSensitiveIcon.get()) icon = block.getIcon(world, x, y, z, side); else icon = block.getIcon(side, blockMetadata); } return icon; } /** * Checks if a {@link Face} should be rendered. {@link RenderParameters#direction} needs to be defined for the face. * * @param face the face * @return true, if successful */ protected boolean shouldRenderFace(Face face) { if (renderType != RenderType.ISBRH_WORLD || world == null || block == null) return true; if (rp != null && rp.renderAllFaces.get()) return true; if (renderBlocks != null && renderBlocks.renderAllFaces == true) return true; RenderParameters p = face.getParameters(); if (p.direction.get() == null || p.renderAllFaces.get()) return true; boolean b = block.shouldSideBeRendered(world, x + p.direction.get().offsetX, y + p.direction.get().offsetY, z + p.direction.get().offsetZ, p.direction.get().ordinal()); return b; } /** * Applies the texture to the {@link Shape}.
* Usually necessary before some shape transformations in conjunction with {@link RenderParameters#applyTexture} set to * false to prevent reapplying texture when rendering. * * @param shape the shape */ public void applyTexture(Shape shape) { applyTexture(shape, null); } /** * Applies the texture to the {@link Shape} with specified {@link RenderParameters}.
* Usually necessary before some shape transformations in conjunction with {@link RenderParameters#applyTexture} set to * false to prevent reapplying texture when rendering. * * @param shape the shape * @param parameters the parameters */ public void applyTexture(Shape shape, RenderParameters parameters) { //shape.applyMatrix(); for (Face f : shape.getFaces()) { face = f; RenderParameters params = new RenderParameters(); params.merge(f.getParameters()); params.merge(parameters); IIcon icon = getIcon(params); if (icon != null) { boolean flipU = params.flipU.get(); if (params.direction.get() == ForgeDirection.NORTH || params.direction.get() == ForgeDirection.EAST) flipU = !flipU; f.setTexture(icon, flipU, params.flipV.get(), params.interpolateUV.get()); } } } /** * Calculates the ambient occlusion for a {@link Vertex} and also apply the side dependent shade.
* aoMatrix is the list of block coordinates necessary to compute AO. If it's empty, only the global face shade is applied.
* Also, params.colorMultiplier is applied as well. * * @param vertex the vertex * @param aoMatrix the ao matrix * @return the int */ protected int calcVertexColor(Vertex vertex, int[][] aoMatrix) { int color = 0xFFFFFF; if (params.usePerVertexColor.get()) //vertex should use their own colors color = vertex.getColor(); if (params.colorMultiplier.get() != null) //global color multiplier is set color = params.colorMultiplier.get(); else if (block != null) //use block color mulitplier color = world != null ? block.colorMultiplier(world, x, y, z) : block.getRenderColor(blockMetadata); if (drawMode == GL11.GL_LINE) //no AO for lines return color; if (renderType != RenderType.ISBRH_WORLD && renderType != RenderType.TESR_WORLD) //no AO for item/inventories return color; float factor = 1; //calculate AO if (params.calculateAOColor.get() && aoMatrix != null && Minecraft.isAmbientOcclusionEnabled() && block.getLightValue(world, x, y, z) == 0) { factor = getBlockAmbientOcclusion(world, x + params.direction.get().offsetX, y + params.direction.get().offsetY, z + params.direction.get().offsetZ); for (int i = 0; i < aoMatrix.length; i++) factor += getBlockAmbientOcclusion(world, x + aoMatrix[i][0], y + aoMatrix[i][1], z + aoMatrix[i][2]); factor /= (aoMatrix.length + 1); } //apply face dependent shading factor *= params.colorFactor.get(); int r = (int) ((color >> 16 & 255) * factor); int g = (int) ((color >> 8 & 255) * factor); int b = (int) ((color & 255) * factor); color = r << 16 | g << 8 | b; return color; } /** * Gets the base brightness for the current {@link Face}.
* If params.useBlockBrightness = false, params.brightness. Else, the brightness is determined based on * params.offset and getBlockBounds() * * @return the base brightness */ protected int getBaseBrightness() { if (!params.useEnvironmentBrightness.get()) return params.brightness.get(); if (block != null) { if (world != null && block.getLightValue(world, x, y, z) != 0) return block.getLightValue(world, x, y, z) << 4; else if (block.getLightValue() != 0) return block.getLightValue() << 4; } if (renderType == RenderType.ISBRH_INVENTORY || renderType == RenderType.ITEM_INVENTORY) return Minecraft.getMinecraft().thePlayer.getBrightnessForRender(getPartialTick()); //not in world if (world == null) return params.brightness.get(); //no direction, we can only use current block brightness if (params.direction.get() == null) return block.getMixedBrightnessForBlock(world, x, y, z); AxisAlignedBB bounds = getRenderBounds(); ForgeDirection dir = params.direction.get(); int ox = x + dir.offsetX; int oy = y + dir.offsetY; int oz = z + dir.offsetZ; //use the brightness of the block next to it if (bounds != null) { if (dir == ForgeDirection.WEST && bounds.minX > 0) ox += 1; else if (dir == ForgeDirection.EAST && bounds.maxX < 1) ox -= 1; else if (dir == ForgeDirection.NORTH && bounds.minZ > 0) oz += 1; else if (dir == ForgeDirection.SOUTH && bounds.maxZ < 1) oz -= 1; else if (dir == ForgeDirection.DOWN && bounds.minY > 0) oy += 1; else if (dir == ForgeDirection.UP && bounds.maxY < 1) oy -= 1; } return getMixedBrightnessForBlock(world, ox, oy, oz); } /** * Calculates the ambient occlusion brightness for a {@link Vertex}. aoMatrix is the list of block coordinates necessary to * compute AO. Only first 3 blocks are used.
* * @param vertex the vertex * @param aoMatrix the ao matrix * @return the int */ protected int calcVertexBrightness(Vertex vertex, int[][] aoMatrix) { if (params.usePerVertexBrightness.get()) return vertex.getBrightness(); if (drawMode == GL11.GL_LINE) //no AO for lines return baseBrightness; if (renderType != RenderType.ISBRH_WORLD && renderType != RenderType.TESR_WORLD) //not in world return baseBrightness; if (!params.calculateBrightness.get() || aoMatrix == null) //no data return baseBrightness; if (!Minecraft.isAmbientOcclusionEnabled() || block.getLightValue(world, x, y, z) != 0) // emit light return baseBrightness; int[] b = new int[Math.max(3, aoMatrix.length)]; for (int i = 0; i < b.length; i++) b[i] += getMixedBrightnessForBlock(world, x + aoMatrix[i][0], y + aoMatrix[i][1], z + aoMatrix[i][2]); int brightness = getAoBrightness(b[0], b[1], b[2], baseBrightness); return brightness; } /** * Does the actual brightness calculation (copied from net.minecraft.client.renderer.BlocksRenderer.java) * * @param b1 the b1 * @param b2 the b2 * @param b3 the b3 * @param base the base * @return the ao brightness */ protected int getAoBrightness(int b1, int b2, int b3, int base) { if (b1 == 0) b1 = base; if (b2 == 0) b2 = base; if (b3 == 0) b3 = base; return b1 + b2 + b3 + base >> 2 & 16711935; } /** * Gets the block ambient occlusion value. Contrary to base Minecraft code, it's the actual block at the x, y and z * coordinates which is used to get the value, and not value of the block drawn. This allows to have different logic behaviors for AO * values for a block. * * @param world the world * @param x the x * @param y the y * @param z the z * @return the block ambient occlusion */ protected float getBlockAmbientOcclusion(IBlockAccess world, int x, int y, int z) { Block block = world.getBlock(x, y, z); if (block == null) return 1.0F; return block.getAmbientOcclusionLightValue(); } /** * Gets the mix brightness for a block (sky + block source). * * @param world the world * @param x the x * @param y the y * @param z the z * @return the mixed brightness for block */ protected int getMixedBrightnessForBlock(IBlockAccess world, int x, int y, int z) { // return world.getLightBrightnessForSkyBlocks(x, y, z, 0); return world.getBlock(x, y, z).getMixedBrightnessForBlock(world, x, y, z); } /** * Gets the rendering bounds. If params.useBlockBounds = false, params.renderBounds is used instead of the actual block * bounds. * * @return the render bounds */ protected AxisAlignedBB getRenderBounds() { if (block == null || !rp.useBlockBounds.get()) return rp.renderBounds.get(); if (world != null) block.setBlockBoundsBasedOnState(world, x, y, z); return AxisAlignedBB.getBoundingBox(block.getBlockBoundsMinX(), block.getBlockBoundsMinY(), block.getBlockBoundsMinZ(), block.getBlockBoundsMaxX(), block.getBlockBoundsMaxY(), block.getBlockBoundsMaxZ()); } /** * Modifies the {@link Vertex vertexes} coordinates relative to the bounds specified.
* Eg : if x = 0.5, minX = 1, maxX = 3, x becomes 2 * * @param bounds the bounds */ protected void calcVertexesPosition(AxisAlignedBB bounds) { if (bounds == null) return; for (Face f : shape.getFaces()) { face = f; for (Vertex v : f.getVertexes()) v.interpolateCoord(bounds); } } /** * Gets and hold reference to damagedBlocks from Minecraft.renderGlobal via reflection. * * @return the damaged blocks */ protected Map getDamagedBlocks() { if (damagedBlocks != null) return damagedBlocks; try { Field modifiers = Field.class.getDeclaredField("modifiers"); modifiers.setAccessible(true); Field f = ReflectionHelper.findField(RenderGlobal.class, MalisisCore.isObfEnv ? "field_94141_F" : "destroyBlockIcons"); modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL); damagedIcons = (IIcon[]) f.get(Minecraft.getMinecraft().renderGlobal); f = ReflectionHelper.findField(RenderGlobal.class, MalisisCore.isObfEnv ? "field_72738_E" : "damagedBlocks"); modifiers.setInt(f, f.getModifiers()); damagedBlocks = (HashMap) f.get(Minecraft.getMinecraft().renderGlobal); return damagedBlocks; } catch (Exception e) { e.printStackTrace(); } return null; } /** * Gets the destroy block progress for this rendering. Only used for TESR. * * @return the block destroy progress */ protected DestroyBlockProgress getBlockDestroyProgress() { if (renderType != RenderType.TESR_WORLD) return null; Map damagedBlocks = getDamagedBlocks(); if (damagedBlocks == null || damagedBlocks.isEmpty()) return null; Iterator iterator = damagedBlocks.values().iterator(); while (iterator.hasNext()) { DestroyBlockProgress dbp = (DestroyBlockProgress) iterator.next(); if (isCurrentBlockDestroyProgress(dbp)) return dbp; } return null; } /** * Checks whether the DestroyBlockProgress specified should apply for this TESR. * * @param dbp the dbp * @return true, if is current block destroy progress */ protected boolean isCurrentBlockDestroyProgress(DestroyBlockProgress dbp) { return dbp.getPartialBlockX() == x && dbp.getPartialBlockY() == y && dbp.getPartialBlockZ() == z; } /** * Gets the render id of this {@link MalisisRenderer}. * * @return the render id */ @Override public int getRenderId() { return renderId; } /** * Registers this {@link MalisisRenderer} to be used for rendering for specified classes.
* Classes have to extend Block or TileEntity.
* A static renderId field is required inside the class extending Block ! * * @param listClass the list class */ public void registerFor(Class... listClass) { for (Class clazz : listClass) { if (Block.class.isAssignableFrom(clazz)) { try { clazz.getField("renderId").set(null, renderId); RenderingRegistry.registerBlockHandler(this); } catch (ReflectiveOperationException e) { MalisisCore.log.error("[MalisisRenderer] Tried to register ISBRH for block class {} that does not have renderId field", clazz.getSimpleName()); e.printStackTrace(); } } else if (TileEntity.class.isAssignableFrom(clazz)) { ClientRegistry.bindTileEntitySpecialRenderer(clazz, this); } } } /** * Registers this {@link MalisisRenderer} to be used for rendering the specified item. * * @param item the item */ public void registerFor(Item item) { MinecraftForgeClient.registerItemRenderer(item, this); } /** * Registers this {@link MalisisRenderer} to be used for {@link RenderWorldLastEvent}. */ public void registerForRenderWorldLast() { RenderWorldEventHandler.register(this); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy