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

io.github.kosmx.bendylib.impl.BendableCuboid Maven / Gradle / Ivy

The newest version!
package io.github.kosmx.bendylib.impl;

import io.github.kosmx.bendylib.ICuboidBuilder;
import io.github.kosmx.bendylib.impl.accessors.DirectionMutator;
import net.minecraft.class_1159;
import net.minecraft.class_1160;
import net.minecraft.class_1162;
import net.minecraft.class_2350;
import net.minecraft.class_4587;
import net.minecraft.class_4588;
import net.minecraft.class_630;
import net.minecraft.util.math.*;

import java.util.*;
import java.util.function.Consumer;

/**
 * Bendable cuboid literally...
 * If you don't know the math behind it
 * (Vectors, matrices, quaternions)
 * don't try to edit.
 *
 * Use {@link BendableCuboid#setRotationDeg(float, float)} to bend the cube
 */
public class BendableCuboid implements ICuboid, IBendable, IterableRePos {
    protected final Quad[] sides;
    protected final RememberingPos[] positions;
    //protected final Matrix4f matrix; - Shouldn't use... Change the moveVec instead of this.
    protected class_1159 lastPosMatrix;
    //protected final RepositionableVertex.Pos3f[] positions = new RepositionableVertex.Pos3f[8];
    //protected final Vec3f[] origins = new Vec3f[4];
    public final float minX;
    public final float minY;
    public final float minZ;
    public final float maxX;
    public final float maxY;
    public final float maxZ;
    //protected final float size;
    //to shift the matrix to the center axis
    protected final float fixX;
    protected final float fixY;
    protected final float fixZ;
    protected final class_2350 direction;
    protected final Plane basePlane;
    protected final Plane otherPlane;
    protected final float fullSize;

    private float bend, bendAxis;

    //Use Builder
    protected BendableCuboid(Quad[] sides, RememberingPos[] positions, float minX, float minY, float minZ, float maxX, float maxY, float maxZ, float fixX, float fixY, float fixZ, class_2350 direction, Plane basePlane, Plane otherPlane, float fullSize) {
        this.sides = sides;
        this.positions = positions;
        this.minX = minX;
        this.minY = minY;
        this.minZ = minZ;
        this.maxX = maxX;
        this.maxY = maxY;
        this.maxZ = maxZ;
        this.fixX = fixX;
        this.fixY = fixY;
        this.fixZ = fixZ;
        //this.size = size;
        this.direction = direction;
        this.basePlane = basePlane;
        this.otherPlane = otherPlane;
        this.fullSize = fullSize;

        this.applyBend(0, 0);//Init values to render
    }

    public class_1159 applyBend(float bendAxis, float bendValue){
        this.bend = bendValue; this.bendAxis = bendAxis;
        return this.applyBend(bendAxis, bendValue, this);
    }

    @Override
    public class_2350 getBendDirection() {
        return this.direction;
    }

    @Override
    public float getBendX() {
        return fixX;
    }

    @Override
    public float getBendY() {
        return fixY;
    }

    @Override
    public float getBendZ() {
        return fixZ;
    }

    @Override
    public Plane getBasePlane() {
        return basePlane;
    }

    @Override
    public Plane getOtherSidePlane() {
        return otherPlane;
    }

    @Override
    public float bendHeight() {
        return fullSize;
    }

    @Override
    public void iteratePositions(Consumer consumer){
        for(IPosWithOrigin pos:positions){
            consumer.accept(pos);
        }
    }

    /**
     * a.k.a BendableCuboidFactory
     */
    public static class Builder implements ICuboidBuilder {
        /**
         * Size parameters
         */
        public class_2350 direction; //now, way better

        public Builder setDirection(class_2350 d){
            this.direction = d;
            return this;
        }

        public BendableCuboid build(Data data){
            ArrayList planes = new ArrayList<>();
            HashMap positions = new HashMap<>();
            float minX = data.x, minY = data.y, minZ = data.z, maxX = data.x + data.sizeX, maxY = data.y + data.sizeY, maxZ = data.z + data.sizeZ;
            float pminX = data.x - data.extraX, pminY = data.y - data.extraY, pminZ = data.z - data.extraZ, pmaxX = maxX + data.extraX, pmaxY = maxY + data.extraY, pmaxZ = maxZ + data.extraZ;
            if(data.mirror){
                float tmp = pminX;
                pminX = pmaxX;
                pmaxX = tmp;
            }

            //this is copy from MC's cuboid constructor
            class_1160 vertex1 = new class_1160(pminX, pminY, pminZ);
            class_1160 vertex2 = new class_1160(pmaxX, pminY, pminZ);
            class_1160 vertex3 = new class_1160(pmaxX, pmaxY, pminZ);
            class_1160 vertex4 = new class_1160(pminX, pmaxY, pminZ);
            class_1160 vertex5 = new class_1160(pminX, pminY, pmaxZ);
            class_1160 vertex6 = new class_1160(pmaxX, pminY, pmaxZ);
            class_1160 vertex7 = new class_1160(pmaxX, pmaxY, pmaxZ);
            class_1160 vertex8 = new class_1160(pminX, pmaxY, pmaxZ);

            int j = data.u;
            int k = (int) (data.u + data.sizeZ);
            int l = (int) (data.u + data.sizeZ + data.sizeX);
            int m = (int) (data.u + data.sizeZ + data.sizeX + data.sizeX);
            int n = (int) (data.u + data.sizeZ + data.sizeX + data.sizeZ);
            int o = (int) (data.u + data.sizeZ + data.sizeX + data.sizeZ + data.sizeX);
            int p = data.v;
            int q = (int) (data.v + data.sizeZ);
            int r = (int) (data.v + data.sizeZ + data.sizeY);
            createAndAddQuads(planes, positions, new class_1160[]{vertex6, vertex5, vertex2}, k, p, l, q, data.textureWidth, data.textureHeight, data.mirror, data);
            createAndAddQuads(planes, positions, new class_1160[]{vertex3, vertex4, vertex7}, l, q, m, p, data.textureWidth, data.textureHeight, data.mirror, data);
            createAndAddQuads(planes, positions, new class_1160[]{vertex1, vertex5, vertex4}, j, q, k, r, data.textureWidth, data.textureHeight, data.mirror, data);
            createAndAddQuads(planes, positions, new class_1160[]{vertex2, vertex1, vertex3}, k, q, l, r, data.textureWidth, data.textureHeight, data.mirror, data);
            createAndAddQuads(planes, positions, new class_1160[]{vertex6, vertex2, vertex7}, l, q, n, r, data.textureWidth, data.textureHeight, data.mirror, data);
            createAndAddQuads(planes, positions, new class_1160[]{vertex5, vertex6, vertex8}, n, q, o, r, data.textureWidth, data.textureHeight, data.mirror, data);

            Plane aPlane = new Plane(direction.method_23955(), vertex7);
            Plane bPlane = new Plane(direction.method_23955(), vertex1);
            boolean bl = direction == class_2350.field_11036 || direction == class_2350.field_11035 || direction == class_2350.field_11034;
            float fullSize = - direction.method_23955().method_4950(vertex1) + direction.method_23955().method_4950(vertex7);
            float bendX = ((float) data.sizeX + data.x + data.x)/2;
            float bendY = ((float) data.sizeY + data.y + data.y)/2;
            float bendZ = ((float) data.sizeZ + data.z + data.z)/2;
            return new BendableCuboid(planes.toArray(new Quad[0]), positions.values().toArray(new RememberingPos[0]), minX, minY, minZ, maxX, maxY, maxZ, bendX, bendY, bendZ, direction, bl ? aPlane : bPlane, bl ? bPlane : aPlane, fullSize);
        }
        //edge[2] can be calculated from edge 0, 1, 3...
        private void createAndAddQuads(Collection quads, HashMap positions, class_1160[] edges, int u1, int v1, int u2, int v2, float squishU, float squishV, boolean flip, Data data){
            int du = u2 < u1 ? 1 : -1;
            int dv = v1 < v2 ? 1 : -1;
            for(int localU = u2; localU != u1; localU += du){
                for(int localV = v1; localV != v2; localV += dv){
                    int localU2 = localU + du;
                    int localV2 = localV + dv;
                    RememberingPos rp0 = getOrCreate(positions, transformVector(edges[0].method_23850(), edges[1].method_23850(), edges[2].method_23850(), u2, v1, u1, v2, localU2, localV));
                    RememberingPos rp1 = getOrCreate(positions, transformVector(edges[0].method_23850(), edges[1].method_23850(), edges[2].method_23850(), u2, v1, u1, v2, localU2, localV2));
                    RememberingPos rp2 = getOrCreate(positions, transformVector(edges[0].method_23850(), edges[1].method_23850(), edges[2].method_23850(), u2, v1, u1, v2, localU, localV2));
                    RememberingPos rp3 = getOrCreate(positions, transformVector(edges[0].method_23850(), edges[1].method_23850(), edges[2].method_23850(), u2, v1, u1, v2, localU, localV));
                    quads.add(new Quad(new RememberingPos[]{rp3, rp0, rp1, rp2}, localU2, localV, localU, localV2, data.textureWidth, data.textureHeight, data.mirror));
                }
            }
        }

        class_1160 transformVector(class_1160 pos, class_1160 vectorU, class_1160 vectorV, int u1, int v1, int u2, int v2, int u, int v){
            vectorU.method_4944(pos);
            vectorU.method_4942(((float)u - u1)/(u2-u1));
            vectorV.method_4944(pos);
            vectorV.method_4942(((float)v - v1)/(v2-v1));
            pos.method_23846(vectorU);
            pos.method_23846(vectorV);
            return pos;
        }


        RememberingPos getOrCreate(HashMap positions, class_1160 pos){
            if(!positions.containsKey(pos)){
                positions.put(pos, new RememberingPos(pos));
            }
            return positions.get(pos);
        }

    }

    /**
     * Use {@link IBendable#applyBend(float, float, IterableRePos)} instead
     * @param axisf bend around this axis
     * @param value bend value in radians
     * @return Used Matrix4f
     */
    @Deprecated
    public class_1159 setRotationRad(float axisf, float value){
        return this.applyBend(axisf, value);
    }

    /**
     * Set the bend's rotation
     * @param axis rotation axis in deg
     * @param val rotation's value in deg
     * @return Rotated Matrix4f
     */
    public class_1159 setRotationDeg(float axis, float val){
        return this.setRotationRad(axis * 0.0174533f, val * 0.0174533f);
    }

    @Override
    public void render(class_4587.class_4665 matrices, class_4588 vertexConsumer, float red, float green, float blue, float alpha, int light, int overlay) {
        for(Quad quad:sides){
            quad.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha);
        }
    }

    @Override
    public void copyState(ICuboid other) {
        if(other instanceof BendableCuboid b){
            this.applyBend(b.bendAxis, b.bend); //This works only in J16 or higher
        }
    }

    public class_1159 getLastPosMatrix(){
        return this.lastPosMatrix.method_22673();
    }

    /*
     * A replica of {@link ModelPart.Quad}
     * with IVertex and render()
     */
    public static class Quad{
        public final IVertex[] vertices;
        final float u1, u2, v1, v2, su, sv;

        public Quad(RememberingPos[] vertices, float u1, float v1, float u2, float v2, float squishU, float squishV, boolean flip){
            this.u1 = u1; this.u2 = u2; this.v1 = v1; this.v2 = v2; su = squishU; sv = squishV;
            float f = 0/squishU;
            float g = 0/squishV;
            this.vertices = new IVertex[4];
            this.vertices[0] = new RepositionableVertex(u2 / squishU - f, v1 / squishV + g, vertices[0]);
            this.vertices[1] = new RepositionableVertex(u1 / squishU + f, v1 / squishV + g, vertices[1]);
            this.vertices[2] = new RepositionableVertex(u1 / squishU + f, v2 / squishV - g, vertices[2]);
            this.vertices[3] = new RepositionableVertex(u2 / squishU - f, v2 / squishV - g, vertices[3]);
            if(flip){
                int i = vertices.length;

                for(int j = 0; j < i / 2; ++j) {
                    IVertex vertex = this.vertices[j];
                    this.vertices[j] = this.vertices[i - 1 - j];
                    this.vertices[i - 1 - j] = vertex;
                }
            }
        }
        public void render(class_4587.class_4665 matrices, class_4588 vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha){
            class_1160 direction = this.getDirection();
            direction.method_23215(matrices.method_23762());

            for (int i = 0; i != 4; ++i){
                IVertex vertex = this.vertices[i];
                class_1160 vertexPos = vertex.getPos();
                class_1162 pos = new class_1162(vertexPos.method_4943()/16f, vertexPos.method_4945()/16f, vertexPos.method_4947()/16f, 1);
                pos.method_22674(matrices.method_23761());
                vertexConsumer.method_23919(pos.method_4953(), pos.method_4956(), pos.method_4957(), red, green, blue, alpha, vertex.getU(), vertex.getV(), overlay, light, direction.method_4943(), direction.method_4945(), direction.method_4947());
            }
        }

        /**
         * calculate the normal vector from the vertices' coordinates with cross product
         * @return the normal vector (direction)
         */
        private class_1160 getDirection(){
            class_1160 buf = vertices[3].getPos().method_23850();
            buf.method_4942(-1);
            class_1160 vecB = vertices[1].getPos().method_23850();
            vecB.method_23846(buf);
            buf = vertices[2].getPos().method_23850();
            buf.method_4942(-1);
            class_1160 vecA = vertices[0].getPos().method_23850();
            vecA.method_23846(buf);
            vecA.method_4951(vecB);
            //Return the cross product, if it's zero then return anything non-zero to not cause crash...
            return vecA.method_4952() ? vecA : class_2350.field_11043.method_23955();
        }

        @SuppressWarnings({"ConstantConditions"})
        private class_630.class_593 toModelPart_Quad(){
            class_630.class_593 quad = new class_630.class_593(new class_630.class_618[]{
                    vertices[0].toMojVertex(),
                    vertices[1].toMojVertex(),
                    vertices[2].toMojVertex(),
                    vertices[3].toMojVertex()
            }, u1, v1, u2, v2, su, sv, false, class_2350.field_11036);
            ((DirectionMutator)quad).setDirection(this.getDirection());
            return quad;
        }
    }

    @Override
    public boolean disableAfterDraw() {
        return false;
    }

    @Override
    public List getQuads() {
        List sides = new ArrayList<>();
        for(Quad quad : this.sides){
            sides.add(quad.toModelPart_Quad());
        }
        return sides;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy