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

com.github.dabasan.jxm.bd1.BD1Manipulator Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
package com.github.dabasan.jxm.bd1;

import org.joml.Matrix4f;
import org.joml.Matrix4fc;
import org.joml.Vector3f;

import java.io.*;
import java.util.*;

/**
 * BD1 manipulator
 *
 * @author maeda6uiui
 */
public class BD1Manipulator {
    private List blocks;
    private Map textureFilenames;

    /**
     * Creates a BD1 manipulator.
     */
    public BD1Manipulator() {
        blocks = new ArrayList<>();
        textureFilenames = new HashMap<>();

        for (int i = 0; i < 10; i++) {
            textureFilenames.put(i, "");
        }
    }

    private void readConstructorBase(InputStream is) throws IOException {
        var reader = new BD1Reader(is);

        blocks = reader.getBlocks();
        textureFilenames = reader.getTextureFilenames();
    }

    /**
     * Creates a BD1 manipulator and loads a BD1.
     *
     * @param is input stream to load a BD1 from
     * @throws IOException if it fails to load
     */
    public BD1Manipulator(InputStream is) throws IOException {
        this.readConstructorBase(is);
    }

    /**
     * Creates a BD1 manipulator and loads a BD1.
     *
     * @param file file to load a BD1 from
     * @throws IOException if it fails to load
     */
    public BD1Manipulator(File file) throws IOException {
        try (var bis = new BufferedInputStream(new FileInputStream(file))) {
            this.readConstructorBase(bis);
        }
    }

    /**
     * Creates a BD1 manipulator and loads a BD1.
     *
     * @param filepath filepath to load a BD1 from
     * @throws IOException if it fails to load
     */
    public BD1Manipulator(String filepath) throws IOException {
        try (var bis = new BufferedInputStream(new FileInputStream(filepath))) {
            this.readConstructorBase(bis);
        }
    }

    /**
     * Returns blocks.
     *
     * @return blocks
     */
    public List getBlocks() {
        return new ArrayList<>(blocks);
    }

    /**
     * Sets blocks.
     *
     * @param blocks blocks to set
     */
    public void setBlocks(List blocks) {
        this.blocks = Objects.requireNonNull(blocks);
    }

    /**
     * Returns the number of blocks.
     *
     * @return number of blocks
     */
    public int getNumBlocks() {
        return blocks.size();
    }

    /**
     * Returns the filename of a texture. Returns null if the texture specified
     * does not exist.
     *
     * @param textureID texture ID to set
     * @return texture filename
     */
    public String getTextureFilename(int textureID) {
        return textureFilenames.get(textureID);
    }

    /**
     * Returns all filenames of the textures.
     *
     * @return all filenames of the textures
     */
    public Map getTextureFilenames() {
        return new HashMap<>(textureFilenames);
    }

    /**
     * Sets the filename of a texture.
     *
     * @param textureID       texture ID
     * @param textureFilename texture filename
     */
    public void setTextureFilename(int textureID, String textureFilename) {
        textureFilenames.put(textureID, Objects.requireNonNull(textureFilename));
    }

    /**
     * Sets the filenames of the textures.
     *
     * @param textureFilenames filenames of the textures
     */
    public void setTextureFilenames(Map textureFilenames) {
        this.textureFilenames = Objects.requireNonNull(textureFilenames);
    }

    /**
     * Transforms the blocks with a matrix.
     *
     * @param mat matrix for transformation
     * @return this
     */
    public BD1Manipulator transform(Matrix4fc mat) {
        for (var block : blocks) {
            for (Vector3f vertexPosition : block.vertexPositions) {
                vertexPosition = mat.transformPosition(vertexPosition);
            }
        }

        return this;
    }

    /**
     * Translates the blocks.
     *
     * @param translationX amount of translation along the X-axis
     * @param translationY amount of translation along the Y-axis
     * @param translationZ amount of translation along the Z-axis
     * @return this
     */
    public BD1Manipulator translate(float translationX, float translationY, float translationZ) {
        var translationMat = new Matrix4f().translate(translationX, translationY, translationZ);
        this.transform(translationMat);

        return this;
    }

    /**
     * Rotates the blocks around the X-axis.
     *
     * @param th rotation angle in radian
     * @return this
     */
    public BD1Manipulator rotX(float th) {
        var rotMat = new Matrix4f().rotate(th, 1.0f, 0.0f, 0.0f);
        this.transform(rotMat);

        return this;
    }

    /**
     * Rotates the blocks around the Y-axis.
     *
     * @param th rotation angle in radian
     * @return this
     */
    public BD1Manipulator rotY(float th) {
        var rotMat = new Matrix4f().rotate(th, 0.0f, 1.0f, 0.0f);
        this.transform(rotMat);

        return this;
    }

    /**
     * Rotates the blocks around the Z-axis.
     *
     * @param th rotation angle in radian
     * @return this
     */
    public BD1Manipulator rotZ(float th) {
        var rotMat = new Matrix4f().rotate(th, 0.0f, 0.0f, 1.0f);
        this.transform(rotMat);

        return this;
    }

    /**
     * Rotates the blocks around an arbitrary axis.
     *
     * @param th    rotation angle in radian
     * @param axisX X-component of the axis
     * @param axisY Y-component of the axis
     * @param axisZ Z-component of the axis
     * @return this
     */
    public BD1Manipulator rot(float th, float axisX, float axisY, float axisZ) {
        var rotMat = new Matrix4f().rotate(th, axisX, axisY, axisZ);
        this.transform(rotMat);

        return this;
    }

    /**
     * Rescales the blocks.
     *
     * @param scaleX X-axis scale
     * @param scaleY Y-axis scale
     * @param scaleZ Z-axis scale
     * @return this
     */
    public BD1Manipulator rescale(float scaleX, float scaleY, float scaleZ) {
        var scaleMat = new Matrix4f().scale(scaleX, scaleY, scaleZ);
        this.transform(scaleMat);

        return this;
    }

    /**
     * Inverts the level with respect to the Z-axis.
     *
     * @return this
     */
    public BD1Manipulator invertZ() {
        for (var block : blocks) {
            for (int i = 0; i < 8; i++) {
                block.vertexPositions[i].z *= (-1.0f);
            }
        }

        for (var block : blocks) {
            // Vertex positions
            // Copy original vertex positions
            var origVertexPositions = new Vector3f[8];
            for (int i = 0; i < 8; i++) {
                origVertexPositions[i] = new Vector3f(block.vertexPositions[i]);
            }

            // Reverse the order of the vertices
            var newVertexPositions = new Vector3f[8];
            for (int i = 0; i < 4; i++) {
                newVertexPositions[i] = origVertexPositions[3 - i];
            }
            for (int i = 0; i < 4; i++) {
                newVertexPositions[i + 4] = origVertexPositions[7 - i];
            }

            block.vertexPositions = newVertexPositions;

            // UVs
            UV[] uvs = block.uvs;

            // Copy original UVs
            var origUVs = new UV[24];
            for (int i = 0; i < 24; i++) {
                origUVs[i] = new UV(uvs[i]);
            }

            // Arrange UVs
            var newUVs = new UV[24];
            for (int i = 0; i < 6; i++) {
                int[] uvIndices;

                if (i == 2) {
                    uvIndices = BD1Functions.getFaceCorrespondingUVIndices(4);
                } else if (i == 4) {
                    uvIndices = BD1Functions.getFaceCorrespondingUVIndices(2);
                } else {
                    uvIndices = BD1Functions.getFaceCorrespondingUVIndices(i);
                }

                for (int j = 0; j < 4; j++) {
                    newUVs[i * 4 + j] = origUVs[uvIndices[j]];
                }
            }

            block.uvs = newUVs;

            // Arrange texture IDs
            int[] textureIDs = block.textureIDs;
            var origTextureIDs = textureIDs.clone();

            var newTextureIDs = new int[6];
            for (int i = 0; i < 6; i++) {
                if (i == 2) {
                    newTextureIDs[i] = origTextureIDs[4];
                } else if (i == 4) {
                    newTextureIDs[i] = origTextureIDs[2];
                } else {
                    newTextureIDs[i] = origTextureIDs[i];
                }
            }

            block.textureIDs = newTextureIDs;
        }

        return this;
    }

    private void saveAsBD1Base(OutputStream os) throws IOException {
        var writer = new BD1Writer();
        writer.write(os, blocks, textureFilenames);
    }

    /**
     * Saves the blocks as a BD1.
     *
     * @param os output stream to write the blocks to
     * @throws IOException if it fails to output
     */
    public void saveAsBD1(OutputStream os) throws IOException {
        this.saveAsBD1Base(os);
    }

    /**
     * Saves the blocks as a BD1.
     *
     * @param file file to write the blocks to
     * @throws IOException if it fails to output
     */
    public void saveAsBD1(File file) throws IOException {
        try (var bos = new BufferedOutputStream(new FileOutputStream(file))) {
            this.saveAsBD1(bos);
        }
    }

    /**
     * Saves the blocks as a BD1.
     *
     * @param filepath filepath to write the blocks to
     * @throws IOException if it fails to output
     */
    public void saveAsBD1(String filepath) throws IOException {
        try (var bos = new BufferedOutputStream(new FileOutputStream(filepath))) {
            this.saveAsBD1Base(bos);
        }
    }

    private void saveAsOBJBase(
            OutputStream osObj, OutputStream osMtl, String mtlFilename, boolean flipV) throws IOException {
        BD1OBJWriter.write(osObj, osMtl, mtlFilename, blocks, textureFilenames, flipV);
    }

    /**
     * Saves the blocks as an OBJ.
     *
     * @param osObj       output stream for OBJ
     * @param osMtl       output stream for MTL
     * @param mtlFilename filename of the MTL
     * @param flipV       flips texture V-coordinate if true
     * @throws IOException if it fails to output
     */
    public void saveAsOBJ(
            OutputStream osObj, OutputStream osMtl, String mtlFilename, boolean flipV) throws IOException {
        this.saveAsOBJBase(osObj, osMtl, mtlFilename, flipV);
    }

    /**
     * Saves the blocks as an OBJ.
     *
     * @param fileObj     file for the OBJ
     * @param fileMtl     file for the MTL
     * @param mtlFilename filename of the MTL
     * @param flipV       Flips texture V-coordinate if true
     * @throws IOException if it fails to output
     */
    public void saveAsOBJ(File fileObj, File fileMtl, String mtlFilename, boolean flipV) throws IOException {
        try (var bosObj = new BufferedOutputStream(new FileOutputStream(fileObj));
             var bosMtl = new BufferedOutputStream(new FileOutputStream(fileMtl))) {
            this.saveAsOBJBase(bosObj, bosMtl, mtlFilename, flipV);
        }
    }

    /**
     * Saves the blocks as an OBJ.
     *
     * @param filepathObj filepath of the OBJ
     * @param filepathMtl filepath of the MTL
     * @param mtlFilename filename of the MTL
     * @param flipV       flips texture V-coordinate if true
     * @throws IOException if it fails to output
     */
    public void saveAsOBJ(
            String filepathObj, String filepathMtl, String mtlFilename, boolean flipV) throws IOException {
        try (var bosObj = new BufferedOutputStream(new FileOutputStream(filepathObj));
             var bosMtl = new BufferedOutputStream(new FileOutputStream(filepathMtl))) {
            this.saveAsOBJBase(bosObj, bosMtl, mtlFilename, flipV);
        }
    }

    /**
     * Returns buffer representation of BD1 blocks.
     *
     * @param flipV flips texture V-coordinate if true
     * @return list containing buffers
     */
    public List getBuffers(boolean flipV) {
        Map> faces = BD1FaceGenerator.generateFaces(blocks);
        List buffers = BD1BufferGenerator.generateBuffers(faces, flipV);

        return buffers;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy