Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

Hi,

I've recently started modding and was looking for a tool to properly generate a texture map for mobs.

Fortunately notch already wrote such a tool (http://pastebin.com/0AcY6YV2).

However this does not work with forge so I changed the necessary variables to make it work.

 

To use it simply pass a "new ModelMob().parts" in the main class and wait for the results.

You will need to put all of your boxes into a list called parts (protected ArrayList<ModelRenderer> parts = new ArrayList<ModelRenderer>(); ).

 

Here's an example mob (only the constructor and the list):

protected ArrayList<ModelRenderer> parts = new ArrayList<ModelRenderer>();
ModelMob()
{
textureWidth = 128; //change this to the same size as in ImageGenerator (WIDTH)
textureHeight = 64;

setTextureOffset("null.part1", 0, 0); // important (needs to be called with any offset for the first time, otherwise you will get a NullPtr exception)
setTextureOffset("null.part2", 0, 0); // change it to the output of ImageGenerator afterwards

ModelRenderer part1 = new ModelRenderer(this, 0, 0);
parts.add(part1);
part1.addBox("part1",-8F, -8F, 0F, 16, 16, 32);
//some other code

ModelRenderer part2 = new ModelRenderer(this, 0, 0);
parts.add(part2);
part2.addBox("part2",-0.5F, 0F, 0F, 1, 8, ;
//some other code
}

 

Finally here is the actual code:

 

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;

import javax.imageio.ImageIO;

import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelRenderer;


/*
* Generates a texture map for a specified model 
* modified from: http://pastebin.com/0AcY6YV2
*/

public class ImageGenerator {
    private static final int WIDTH = 256;
    private static final int HEIGHT = 256;

    private class Region {
        public int x1, y1, x2, y2;

        public Region(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }

        public void move(int xo, int yo) {
            x1 += xo;
            y1 += yo;
            x2 += xo;
            y2 += yo;
        }

        public boolean overlaps(Region r2, int xo, int yo) {
            if (r2.x2 + xo <= x1) return false;
            if (r2.y2 + yo <= y1) return false;
            if (r2.x1 + xo >= x2) return false;
            if (r2.y1 + yo >= y2) return false;
            return true;
        }

        public void render(Graphics g) {
            g.fillRect(x1, y1, x2 - x1, y2 - y1);
        }
    }

    private class UnfoldedCube {
        public int x, y;
        public Region[] cubeRegions = new Region[6];
        public String id;
        public int width, height;

        public UnfoldedCube(ModelBox cube) {
            int xs = (int) Math.ceil(cube.posX2 - cube.posX1);
            int ys = (int) Math.ceil(cube.posY2 - cube.posY1);
            int zs = (int) Math.ceil(cube.posZ2 - cube.posZ1);

            width = xs * 2 + zs * 2;
            height = zs + ys;

            id = cube.field_78247_g;

            cubeRegions[0] = new Region(0, zs, zs, zs + ys);
            cubeRegions[1] = new Region(zs, zs, zs + xs, zs + ys);
            cubeRegions[2] = new Region(zs + xs, zs, zs + xs + zs, zs + ys);
            cubeRegions[3] = new Region(zs + xs + zs, zs, zs + xs + zs + xs, zs + ys);
            cubeRegions[4] = new Region(zs, 0, zs + xs, zs);
            cubeRegions[5] = new Region(zs + xs, 0, zs + xs * 2, zs);
        }

        public boolean fits(int x, int y) {
            for (int i = 0; i < 6; i++) {
                if (!isFree(cubeRegions[i], x, y)) return false;
            }
            return true;
        }

        public void place(int x, int y) {
            this.x = x;
            this.y = y;
            for (int i = 0; i < 6; i++) {
                cubeRegions[i].move(x, y);
                occupiedRegions.add(cubeRegions[i]);
            }
        }

        public void render(Graphics g) {
            float hue = (float) Math.random();
            g.setColor(new Color(Color.HSBtoRGB(hue, 1, 0.7f)));
            cubeRegions[5].render(g);
            g.setColor(new Color(Color.HSBtoRGB(hue, 1, 1.0f)));
            cubeRegions[4].render(g);
            g.setColor(new Color(Color.HSBtoRGB(hue, 1, 0.9f)));
            cubeRegions[1].render(g);
            cubeRegions[3].render(g);
            g.setColor(new Color(Color.HSBtoRGB(hue, 1, 0.8f)));
            cubeRegions[0].render(g);
            cubeRegions[2].render(g);
        }
    }

    private List<Region> occupiedRegions = new ArrayList<Region>();

    private boolean isFree(Region region, int xo, int yo) {
        if (region.x1 + xo < 0) return false;
        if (region.y1 + yo < 0) return false;
        if (region.x2 + xo > WIDTH) return false;
        if (region.y2 + yo > HEIGHT) return false;

        for (int i = 0; i < occupiedRegions.size(); i++) {
            if (occupiedRegions.get(i).overlaps(region, xo, yo)) return false;
        }

        return true;
    }

    public void generateImage(List<ModelRenderer> parts) {

        List<ModelBox> cubes = new ArrayList<ModelBox>();
        for (ModelRenderer mp : parts) {
            getCubes(mp, cubes);
        }

        Collections.sort(cubes, new Comparator<ModelBox>() {
            @Override
            public int compare(ModelBox c0, ModelBox c1) {
                int xs = (int) Math.ceil(c0.posX2 - c0.posX1);
                int ys = (int) Math.ceil(c0.posY2 - c0.posY1);
                int zs = (int) Math.ceil(c0.posZ2 - c0.posZ1);

                int ww0 = xs * 2 + zs * 2;
                int hh0 = zs + ys;

                xs = (int) Math.ceil(c1.posX2 - c1.posX1);
                ys = (int) Math.ceil(c1.posY2 - c1.posY1);
                zs = (int) Math.ceil(c1.posZ2 - c1.posZ1);

                int ww1 = xs * 2 + zs * 2;
                int hh1 = zs + ys;

                if (ww0 * hh0 < ww1 * hh1) {
                    return 1;
                } else if (ww0 * hh0 > ww1 * hh1) {
                    return -1;
                }

                return 0;
            }
        });

        List<UnfoldedCube> unfolded = new ArrayList<UnfoldedCube>();
        for (ModelBox cube : cubes) {
            UnfoldedCube uc = new UnfoldedCube(cube);

            boolean placed = false;
            positionLoop: for (int y = 0; y < HEIGHT - uc.height; y++) {
                for (int x = 0; x < WIDTH - uc.width; x++) {
                    if (uc.fits(x, y)) {
                        uc.place(x, y);
                        placed = true;
                        break positionLoop;
                    }
                }
            }
            if (!placed) {
                System.out.println("Failed to place " + uc.id);
            } else {
                unfolded.add(uc);
            }
        }

        BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics g = img.getGraphics();
        System.out.println("----------------");
        for (UnfoldedCube uc : unfolded) {
            System.out.println("setTextureOffset(\"" + uc.id + "\", " + uc.x + ", " + uc.y + ");");
            uc.render(g);
        }
        try {
            ImageIO.write(img, "png", new File("output.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void getCubes(ModelRenderer mp, List<ModelBox> cubeList) {
        addLoop: for (ModelBox cube : (List<ModelBox>)mp.cubeList) {
            if (cube.field_78247_g != null) {
                for (ModelBox otherCube : cubeList) {
                    if (otherCube.field_78247_g != null) {
                        if (otherCube.field_78247_g.equals(cube.field_78247_g)) {
                            System.out.println("Duplicate " + cube.field_78247_g);
                            continue addLoop;
                        }
                    }
                }
            }
            cubeList.add(cube);
        }
    }

    public static void main(String[] args) {
        new ImageGenerator().generateImage(new ModelMob().parts );
    }
}

 

I hope it helps.

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...

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.