cubeItems.ModelCubeWorld.java Source code

Java tutorial

Introduction

Here is the source code for cubeItems.ModelCubeWorld.java

Source

/**
 * This class was created by <Vazkii>. It can be integrated in any of your
 * minecraft projects at will. If your mod is open source, this header must
 * be present.
 *
 * This class is licensed under a CC-BY 3.0 license.
 * http://creativecommons.org/licenses/by/3.0/
 */
package cubeItems;

import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glColor3ub;
import static org.lwjgl.opengl.GL11.glDisable;
import static org.lwjgl.opengl.GL11.glEnable;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glRotatef;
import static org.lwjgl.opengl.GL11.glScalef;
import static org.lwjgl.opengl.GL11.glTranslatef;
import static org.lwjgl.opengl.GL12.GL_RESCALE_NORMAL;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
import net.minecraftforge.common.util.ForgeDirection;

import org.lwjgl.opengl.GL11;

public class ModelCubeWorld extends ModelBase {

    byte[][][][] modelData;
    int[] pointers;

    final ModelRenderer cube;

    public static final int MAX_COLOR = 256;

    public static final float LUMINANCE_RED = 0.2126f;
    public static final float LUMINANCE_GREEN = 0.7152f;

    public static final float LUMINANCE_BLUE = 0.0722f;

    double hue = 180;

    /* ===== SUBARAKI ===== */

    double saturation = 50;
    double lightness = 0;
    int[] lum_red_lookup;
    int[] lum_green_lookup;

    int[] lum_blue_lookup;
    int[] final_red_lookup;
    int[] final_green_lookup;

    int[] final_blue_lookup;

    /**
     * @param stream
     *            An InputStream where the model can be loaded from. You can get
     *            one using {@link Class#getResourceAsStream(String)}, for
     *            loading resources in the mod's package. Input streams are
     *            diverse, so this constructor can be called from a URL
     *            connection, a file in the local file system, or even an
     *            incoming packet.
     */
    public ModelCubeWorld(InputStream stream) {
        cube = new ModelRenderer(this, 0, 0).addBox(0F, 0F, 0F, 1, 1, 1);

        int i;
        int it = 0;
        int area = 0;

        byte[] sizesBuffer = new byte[12];

        try {
            while ((i = stream.read()) != -1) {
                final byte val = (byte) (i & 0xFF);
                if (it < 12) {
                    sizesBuffer[it] = val;
                } else {
                    if (it == 12) {
                        final int x = sizesBuffer[0] | (sizesBuffer[1] << 8) | (sizesBuffer[2] << 16)
                                | (sizesBuffer[3] << 24);
                        final int y = sizesBuffer[4] | (sizesBuffer[5] << 8) | (sizesBuffer[6] << 16)
                                | (sizesBuffer[7] << 24);
                        final int z = sizesBuffer[8] | (sizesBuffer[9] << 8) | (sizesBuffer[10] << 16)
                                | (sizesBuffer[11] << 24);

                        modelData = new byte[x][y][z][3];
                        area = x * y;

                        sizesBuffer = null;
                    }

                    final int it1 = it - 12;
                    final int it1d = it1 / 3;

                    final int z = it1d / area;

                    final int it2d = it1d - (area * z); // Exploiting the lack
                    // of rounding in
                    // integer values
                    final int x = it2d % modelData.length;
                    final int y = it2d / modelData.length;

                    if ((x >= modelData.length) || (y >= modelData[0].length) || (z >= modelData[0][0].length)) {
                        it++;
                        continue;
                    }

                    modelData[x][y][z][it1 % 3] = val;
                }

                it++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        calculatePointers(false);
    }

    /**
     * Recalculates the pointers for the rendering. Must be done if you change
     * the model data, otherwise it won't make use of the new data.
     * 
     * @param renderHidden
     *            If true, the renderer will draw every single cube, even cubes
     *            that are obstructed on all 6 sides. Not recommended!
     */
    public void calculatePointers(final boolean renderHidden) {
        List<Integer> newPointers = new ArrayList();

        for (int x = 0; x < modelData.length; x++) {
            for (int y = 0; y < modelData[0].length; y++) {
                for (int z = 0; z < modelData[0][0].length; z++) {
                    if (cubeExists(x, y, z)) {
                        if (!renderHidden) {
                            int hiddenSides = 0;
                            for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
                                if (cubeExists(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ)) {
                                    ++hiddenSides;
                                }
                            }

                            if (hiddenSides == 6) {
                                continue;
                            }
                        }

                        newPointers.add((x & 1023) | ((y & 1023) << 10) | ((z & 1023) << 20));
                    }
                }
            }
        }

        pointers = new int[newPointers.size()];
        int it = 0;
        for (int i : newPointers) {
            pointers[it] = i;
            it++;
        }
    }

    /**
     * Returns true if a cube exists at the coordinates passed in.
     */
    public boolean cubeExists(final int x, final int y, final int z) {
        final int xs = modelData.length;
        final int ys = modelData[0].length;
        final int zs = modelData[0][0].length;

        if ((x >= xs) || (x < 0) || (y >= ys) || (y < 0) || (z >= zs) || (z < 0)) {
            return false;
        }

        final byte[] values = modelData[x][y][z];
        return (values[0] != 0) || (values[1] != 0) || (values[2] != 0);
    }

    /**
     * Returns the data of the model, in a four dimensional byte array.<br>
     * <br>
     * Dimension 0 - The X coordinates<br>
     * Dimension 1 - The Y coordinates<br>
     * Dimension 2 - The Z coordinates<br>
     * Dimension 3 - Always of length 3, contains, respectively, red, green and
     * blue values.
     * 
     */
    public byte[][][][] getModelData() {
        return modelData;
    }

    /**
     * Actually renders the model, requires previous translation. The model is
     * rendered in a scale of 0.0625F, or 1/16, the side of each voxel is one
     * 16th of the side of a regular minecraft block.
     */
    public void render() {
        glPushMatrix();
        glDisable(GL_TEXTURE_2D);
        glEnable(GL_RESCALE_NORMAL);

        final float scale = 0.0625F;
        glScalef(scale, scale, scale);
        glRotatef(-90F, 1F, 0F, 0F);

        for (int i : pointers) {
            final int x = i & 1023;
            final int y = (i >> 10) & 1023;
            final int z = (i >> 20) & 1023;

            glTranslatef(x, y, z);

            final byte[] color = modelData[x][y][z];
            glColor3ub(color[0], color[1], color[2]);

            cube.render(1F);

            glTranslatef(-x, -y, -z);
        }

        glEnable(GL_TEXTURE_2D);
        glDisable(GL_RESCALE_NORMAL);
        glPopMatrix();
    }

    // prevent people from using the modelbase renderer and render nothing at
    // all.
    @Override
    public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7) {
        render();
    }

    /**
     * Contrairy to as the name says, this does not render the color from the
     * model, but allows you to apply another layer of color OVER the current
     * layer. This allows e.a. greyscale models to be colored as desired.
     * 
     * Has to be worked on : for now, it replaces the color, giving every cube
     * the same color
     * */
    public void renderWithColor(float red, float green, float blue, float alpha) {

        glPushMatrix();
        glDisable(GL_TEXTURE_2D);
        glEnable(GL_RESCALE_NORMAL);

        final float scale = 0.0625F;
        glScalef(scale, scale, scale);
        glRotatef(-90F, 1F, 0F, 0F);

        for (int i : pointers) {
            final int x = i & 1023;
            final int y = (i >> 10) & 1023;
            final int z = (i >> 20) & 1023;

            glTranslatef(x, y, z);

            final byte[] color = modelData[x][y][z];
            glColor3ub(color[0], color[1], color[2]);

            /*
             * added this in.
             */
            GL11.glColor3f(red, green, blue);

            cube.render(1F);

            glTranslatef(-x, -y, -z);
        }

        glEnable(GL_TEXTURE_2D);
        glDisable(GL_RESCALE_NORMAL);
        glPopMatrix();
    }
}