Jump to content

[1.6.2] Render fire in a custom block


Frepo

Recommended Posts

Hi ya all!

So I've made myself a custom block called "Campfire". Which is basically a small ring of stones (model made in Techne). I'm rendering it with my TileEntityCampfireRenderer class that extends TileEntitySpecialRenderer. And it works fine. Now I want to add fire when something is cooking in it. I was thinking of rendering a smaller BlockFire inside the stone ring.

 

Does anyone have a suggestion on how to approach this? I would like to copy the code from renderBlockFire (in the RenderBlocks class)... but is uses a RenderBlocks instance that I don't have in my render function. Seems like I have to implement ISimpleBlockRenderingHandler to get it, but then I don't know how to call the renderWorldBlock method. If I change the getRenderType method from -1 to return a custom value it would only render the fire, and not the model, right?

 

BlockCampfire

 

 

package fcraft.blocks;

import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

import java.util.List;
import java.util.Random;

import fcraft.FrepoCraftMain;
import fcraft.gui.GuiHandler;
import fcraft.tileentity.TileEntityCampfire;
import fcraft.tileentity.TileEntityFCFurnace;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;

public class BlockCampfire extends BlockContainer
{

    private final Random furnaceRand = new Random();
    private final boolean isActive;
    private static boolean keepFurnaceInventory;


    protected BlockCampfire(int par1, boolean par2)
    {
        super(par1, Material.rock);
        this.isActive = par2;
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.325F, 1.0F);
    }

    /**
     * Returns the ID of the items to drop on destruction.
     */
    public int idDropped(int par1, Random par2Random, int par3)
    {
        return BlockData.campfireIdle.blockID;
    }
    
    /**
     * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
     */
    public boolean renderAsNormalBlock()
    {
        return false;
    }

    /**
     * Is this block (a) opaque and (b) a full 1m cube?  This determines whether or not to render the shared face of two
     * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
     */
    public boolean isOpaqueCube()
    {
        return false;
    }

    /**
     * Called whenever the block is added into the world. Args: world, x, y, z
     */
    public void onBlockAdded(World par1World, int par2, int par3, int par4)
    {
        super.onBlockAdded(par1World, par2, par3, par4);
        this.setDefaultDirection(par1World, par2, par3, par4);
    }

    /** set a blocks direction */
    private void setDefaultDirection(World par1World, int par2, int par3, int par4)
    {
        if (!par1World.isRemote)
        {
            par1World.setBlockMetadataWithNotify(par2, par3, par4, 0, 2);
        }
    }

    @SideOnly(Side.CLIENT)
    /** From the specified side and block metadata retrieves the blocks texture. Args: side, metadata */
    public Icon getIcon(int par1, int par2)
    {
    	return this.blockIcon;
    }
    
    /**
     * The type of render function that is called for this block
     */
    public int getRenderType()
    {
        return -1;
    }

    @SideOnly(Side.CLIENT)
    /**
     * When this method is called, your block should register all the icons it needs with the given IconRegister. This
     * is the only chance you get to register icons.
     */
    public void registerIcons(IconRegister par1IconRegister)
    {
        this.blockIcon = par1IconRegister.registerIcon("fc_images:campfire2D");
    }
    
    /**
     * Called upon block activation (right click on the block.)
     */
    @Override
    public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int metadata, float var1, float var2, float var3) {
            
    	TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
    	
        if (tileEntity == null || player.isSneaking()) {
             return false;
        }
        
        player.openGui(FrepoCraftMain.instance, GuiHandler.campfireGUI_ID, world, x, y, z);

        return true;
            
    }
    
    /**
     * Update which block ID the furnace is using depending on whether or not it is burning
     */
    public static void updateFurnaceBlockState(boolean par0, World par1World, int par2, int par3, int par4)
    {
    	TileEntityCampfire tileentity = (TileEntityCampfire)par1World.getBlockTileEntity(par2, par3, par4);
        keepFurnaceInventory = true;
    
        if (par0)
        {
        	par1World.setBlock(par2, par3, par4, BlockData.campfireBurning.blockID);
        }
        else
        {
        	par1World.setBlock(par2, par3, par4, BlockData.campfireIdle.blockID);
        }
        
        keepFurnaceInventory = false;
        par1World.setBlockMetadataWithNotify(par2, par3, par4, 0, 2);

        if (tileentity != null)
        {
            tileentity.validate();
            par1World.setBlockTileEntity(par2, par3, par4, tileentity);
        }
    }

    @SideOnly(Side.CLIENT)
    /** A randomly called display update to be able to add particles or other items for display */
    public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
    {
    	TileEntityCampfire tileentity = (TileEntityCampfire)par1World.getBlockTileEntity(par2, par3, par4);
    	
    	if (tileentity != null && tileentity instanceof TileEntityCampfire)
        {
            tileentity.validate();
            tileentity.generateCampfireFlames(par1World, par2, par3, par4, par5Random);
        }
    }

    /**
     * Returns a new instance of a block's tile entity class. Called on placing the block.
     */
    public TileEntity createNewTileEntity(World par1World)
    {
        return new TileEntityCampfire();
    }

    /**
     * Called when the block is placed in the world.
     */
    public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLivingBase par5EntityLivingBase, ItemStack par6ItemStack)
    {
        if (par6ItemStack.hasDisplayName())
        {
            ((TileEntityCampfire)par1World.getBlockTileEntity(par2, par3, par4)).setGuiDisplayName(par6ItemStack.getDisplayName());
        }
    }

    /**
     * ejects contained items into the world, and notifies neighbours of an update, as appropriate
     */
    public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
    {
        if (!keepFurnaceInventory)
        {
            TileEntityCampfire tileentitycampfire = (TileEntityCampfire)par1World.getBlockTileEntity(par2, par3, par4);

            if (tileentitycampfire != null)
            {
                for (int j1 = 0; j1 < tileentitycampfire.getSizeInventory(); ++j1)
                {
                    ItemStack itemstack = tileentitycampfire.getStackInSlot(j1);

                    if (itemstack != null)
                    {
                        float f = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
                        float f1 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
                        float f2 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;

                        while (itemstack.stackSize > 0)
                        {
                            int k1 = this.furnaceRand.nextInt(21) + 10;

                            if (k1 > itemstack.stackSize)
                            {
                                k1 = itemstack.stackSize;
                            }

                            itemstack.stackSize -= k1;
                            EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));

                            if (itemstack.hasTagCompound())
                            {
                                entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
                            }

                            float f3 = 0.05F;
                            entityitem.motionX = (double)((float)this.furnaceRand.nextGaussian() * f3);
                            entityitem.motionY = (double)((float)this.furnaceRand.nextGaussian() * f3 + 0.2F);
                            entityitem.motionZ = (double)((float)this.furnaceRand.nextGaussian() * f3);
                            par1World.spawnEntityInWorld(entityitem);
                        }
                    }
                }
            }
        }

        super.breakBlock(par1World, par2, par3, par4, par5, par6);
    }

    @SideOnly(Side.CLIENT)
    /** only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative) */
    public int idPicked(World par1World, int par2, int par3, int par4)
    {
        return BlockData.campfireIdle.blockID;
    }
    
//    @SideOnly(Side.CLIENT)
//	public void addInformation(ItemStack stack, EntityPlayer player, List tooltip, boolean bool){
//    	tooltip.add("- Heat capacity: 1600 fC");
//	}
}

 

 

 

TileEntityCampfireRenderer

 

 

package fcraft.client;

import static net.minecraftforge.common.ForgeDirection.DOWN;
import static net.minecraftforge.common.ForgeDirection.EAST;
import static net.minecraftforge.common.ForgeDirection.NORTH;
import static net.minecraftforge.common.ForgeDirection.SOUTH;
import static net.minecraftforge.common.ForgeDirection.UP;
import static net.minecraftforge.common.ForgeDirection.WEST;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.model.ModelSign;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntitySign;
import net.minecraft.util.Icon;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;

import org.lwjgl.opengl.GL11;

import fcraft.blocks.BlockData;
import fcraft.model.ModelCampfire;
import fcraft.tileentity.TileEntityCampfire;

@SideOnly(Side.CLIENT)
public class TileEntityCampfireRenderer extends TileEntitySpecialRenderer
{
    private static final ResourceLocation field_110638_a = new ResourceLocation("fc_images:textures/entity/entity_campfire.png");

    /** The ModelSign instance used by the TileEntitySignRenderer */
    private final ModelCampfire model = new ModelCampfire();

    public void renderTileEntityCampfireAt(TileEntityCampfire entity, double x, double y, double z, float f)
    {

    	GL11.glPushMatrix();
        GL11.glTranslatef((float)x + 0.5F, (float)y + 1.5F, (float)z + 0.5F);
        GL11.glRotatef(180, 0.0F, 0.0F, 1.0F);
    
        this.func_110628_a(field_110638_a); // bind texture
        
        GL11.glPushMatrix();
        	this.model.renderModel(0.0625F);
        GL11.glPopMatrix();
        
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        GL11.glPopMatrix();
        
    }

    public void renderTileEntityAt(TileEntity par1TileEntity, double par2, double par4, double par6, float par8)
    {
    	this.renderTileEntityCampfireAt((TileEntityCampfire)par1TileEntity, par2, par4, par6, par8);
    }
}

 

 

Link to comment
Share on other sites

Don't bother trying to render an actual block of fire.  Just grab its texture and render it onto some quads yourself.

 

The main reason to do this is because Fire renders differently based on the surrounding blocks.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Ah thanks! Sounds like a smart thing to do. Only problem being I'm not so hot as writing the openGL code, and the fire being animated doesn't make things easier.

So I have to choose either to try to copy and implement the code from BlockFire, or learn how to animate stuff in openGL. Initially it just sounds easier to figure out how to get it to render a fire block inside the campfire.

 

But your suggestion sounds much more... well.. professional. So now I want to try that out instead.

 

So the fire texture is 16x512 pixels = 32 frames. And it has 2 layers.

 

1. How do I define the box?

2. How do I set the UV-coords for each frame?

3. How do set a framerate?

 

4. Where is the actual openGL code for BlockFire. I don't understand the tessellator in renderBlockFire. It seems to be setting the coordinates for rendering the fire animation. But where is the G11.blablabla code?

 

Link to comment
Share on other sites

Frame rate is taken care of for you.

"box" and UV coordinates are handled by the tesselator*

You'd be drawing single vertices at a time, so four to define one side of a flat plane.  It's annoying to work with, but for four quads (there's no reason to do more than the X shaped bit in the middle, similar to flowers and wheat) it won't be too bad.  Just do it one quad at a time and use Mojang's renderers as a reference.

 

*tessellator.addVertexUV(x, y, z, U, V); //U and V are the texture coordinates 0 to 1 inclusive where 0,0 is the upper left and 1,1 is the bottom right (if I recall correctly).  I may be missing a parameter (vector normal?), but I'm doing this offhand.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Yeah I was thinking exacly the same on using 2 quads in a X-shape. So far I've researched my way to add the vertexes and understand the UV-coords.

But how do I "grab" the texture?

 

This is as far as I've come. Just testing to se if I can render 1 frame of the fire

 

private static final ResourceLocation texFireFlame = new ResourceLocation("fc_images:textures/blocks/fire_0.png");
....
Tessellator tessellator = Tessellator.instance;

this.func_110628_a(texCampfire);

GL11.glPushMatrix();
        	tessellator.startDrawingQuads();
                tessellator.addVertexWithUV((double)x+0.3D, (double)y     , (double)z+0.3F, 0, 0);
        tessellator.addVertexWithUV((double)x+0.7D, (double)y     , (double)z+0.7F, 1D/16D, 1D/16D);
                tessellator.addVertexWithUV((double)x+0.3D, (double)y+0.6D, (double)z+0.3F, 0, 0);
        tessellator.addVertexWithUV((double)x+0.7D, (double)y+0.6D, (double)z+0.7F, 1D/16D, 1D/16D);
        tessellator.draw();
GL11.glPopMatrix();

 

It doesn't crash. But nothing is rendered.

Link to comment
Share on other sites

Haha since nothing is rendered I guess I DON'T understand the UV-coords! xD

Seemed simple enough, as you said 0,0 being one corner and 1,1 being the opposite. But it feels like I've missed out on something with the texture. Perhaps I can't use a resource location like this. Maybe I need to bind it somehow to the tessellator. But there is nothing like tessellator.bindTexture("texture") or anything like that.

Link to comment
Share on other sites

Now I'm clueless of how to get the fire to animate. You said something that it was taken care of already? EXPLAIN YOURSELF! please :)

 

Sorry, I haven't done anything with animated textures. :x

But I know that Minecraft does have some kind of internal mechanism to deal with animations.

 

As for snagging the Fire block's texture:

 

Block.fire.getIcon(0,0)

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.