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

com.parzivail.util.client.model.ConnectedTextureModel Maven / Gradle / Ivy

There is a newer version: 0.0.114+1.20.2
Show newest version
package com.parzivail.util.client.model;

import F;
import I;
import com.mojang.datafixers.util.Pair;
import com.parzivail.util.client.ConnectedTextureHelper;
import com.parzivail.util.client.ConnectedTextureHelper.Sides;
import com.parzivail.util.client.SubSprite;
import com.parzivail.util.math.MathUtil;
import com.parzivail.util.math.SpriteSheetPoint;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.minecraft.class_1058;
import net.minecraft.class_1087;
import net.minecraft.class_1100;
import net.minecraft.class_1799;
import net.minecraft.class_1920;
import net.minecraft.class_2338;
import net.minecraft.class_2350;
import net.minecraft.class_2429;
import net.minecraft.class_2680;
import net.minecraft.class_2746;
import net.minecraft.class_2960;
import net.minecraft.class_3665;
import net.minecraft.class_4730;
import net.minecraft.class_5819;
import net.minecraft.class_7775;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Vector3f;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;

@Environment(EnvType.CLIENT)
public class ConnectedTextureModel extends DynamicBakedModel
{
	private static final Vector3f[] ORIGINS = new Vector3f[6];
	private static final Vector3f[] DELTAU = new Vector3f[6];
	private static final Vector3f[] DELTAV = new Vector3f[6];

	static
	{
		ORIGINS[class_2350.field_11036.method_10146()] = new Vector3f(0, 1, 0);
		ORIGINS[class_2350.field_11033.method_10146()] = new Vector3f(1, 0, 0);
		ORIGINS[class_2350.field_11039.method_10146()] = new Vector3f(0, 1, 0);
		ORIGINS[class_2350.field_11034.method_10146()] = new Vector3f(1, 1, 1);
		ORIGINS[class_2350.field_11043.method_10146()] = new Vector3f(1, 1, 0);
		ORIGINS[class_2350.field_11035.method_10146()] = new Vector3f(0, 1, 1);

		DELTAU[class_2350.field_11036.method_10146()] = MathUtil.V3F_POS_X;
		DELTAV[class_2350.field_11036.method_10146()] = MathUtil.V3F_POS_Z;

		DELTAU[class_2350.field_11033.method_10146()] = MathUtil.V3F_NEG_X;
		DELTAV[class_2350.field_11033.method_10146()] = MathUtil.V3F_POS_Z;

		DELTAU[class_2350.field_11035.method_10146()] = MathUtil.V3F_POS_X;
		DELTAV[class_2350.field_11035.method_10146()] = MathUtil.V3F_NEG_Y;

		DELTAU[class_2350.field_11043.method_10146()] = MathUtil.V3F_NEG_X;
		DELTAV[class_2350.field_11043.method_10146()] = MathUtil.V3F_NEG_Y;

		DELTAU[class_2350.field_11039.method_10146()] = MathUtil.V3F_POS_Z;
		DELTAV[class_2350.field_11039.method_10146()] = MathUtil.V3F_NEG_Y;

		DELTAU[class_2350.field_11034.method_10146()] = MathUtil.V3F_NEG_Z;
		DELTAV[class_2350.field_11034.method_10146()] = MathUtil.V3F_NEG_Y;
	}

	private final boolean hConnect;
	private final boolean vConnect;
	private final boolean lConnect;
	private final EnumSet capDirections;
	private final class_1058 borderSprite;
	private final class_1058 capSprite;

	public ConnectedTextureModel(boolean hConnect, boolean vConnect, boolean lConnect, EnumSet capDirections, class_1058 blankSprite, class_1058 borderSprite, class_1058 capSprite)
	{
		super(blankSprite, ModelHelper.MODEL_TRANSFORM_BLOCK);
		this.hConnect = hConnect;
		this.vConnect = vConnect;
		this.lConnect = lConnect;
		this.capDirections = capDirections;
		this.borderSprite = borderSprite;
		this.capSprite = capSprite;
	}

	@Override
	protected CacheMethod getDiscriminator()
	{
		return CacheMethod.NO_CACHING;
	}

	@Override
	protected Mesh createBlockMesh(class_1920 blockView, class_2680 state, class_2338 pos, Supplier randomSupplier, RenderContext context, Matrix4f transformation)
	{
		//		var minecraft = MinecraftClient.getInstance();

		var meshBuilder = createMeshBuilder();//RENDERER.meshBuilder();
		var quadEmitter = meshBuilder.getEmitter();

		//		var blockModels = minecraft.getBlockRenderManager().getModels();

		// TODO: fix item lighting
		//		if (state == null) // Assume it's an item
		//		{
		//			model = Client.minecraft.getItemRenderer().getHeldItemModel(new ItemStack(SwgBlocks.Panel.LabWall), null, null);
		//		}

		for (var i = 0; i < ModelHelper.NULL_FACE_ID; i++)
		{
			if (state != null && !(state.method_26204() instanceof class_2429))
				continue;

			final var faceDirection = ModelHelper.faceFromIndex(i);
			if (faceDirection != null)
			{
				final var facingProp = class_2429.field_11329.get(faceDirection);

				if (state != null && state.method_11654(facingProp))
				{
					quadEmitter.emit();
					continue;
				}
			}

			var sprite = modelSprite;

			if (capSprite != null && capDirections.contains(faceDirection))
				sprite = capSprite;

			Vector3f min = ORIGINS[faceDirection.method_10146()];
			Vector3f dU = DELTAU[faceDirection.method_10146()];
			Vector3f dV = DELTAV[faceDirection.method_10146()];

			emitTopQuad(quadEmitter, sprite, borderSprite, blockView, state, pos, faceDirection, min, dU, dV);
		}

		return meshBuilder.build();
	}

	private static Vector3f uv(Vector3f min, Vector3f dU, Vector3f dV, float u, float v)
	{
		return new Vector3f(
				min.x + dU.x * u + dV.x * v,
				min.y + dU.y * u + dV.y * v,
				min.z + dU.z * u + dV.z * v
		);
	}

	private void emitTopQuad(QuadEmitter quadEmitter, class_1058 blankSprite, class_1058 borderSprite, class_1920 blockView, class_2680 state, class_2338 pos, class_2350 direction, Vector3f min, Vector3f dU, Vector3f dV)
	{
		var subSpriteEntry = ConnectedTextureHelper.getConnectedBlockTexture(blockView, state, pos, direction, hConnect, vConnect, lConnect);
		var normal = direction.method_23955();

		if (subSpriteEntry == null)
		{
			// No corners or edges
			quadEmitter
					.colorIndex(1)
					.spriteColor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
					.pos(0, min)
					.normal(0, normal)
					.sprite(0, 0, blankSprite.method_4594(), blankSprite.method_4593())
					.pos(1, uv(min, dU, dV, 0, 1))
					.normal(1, normal)
					.sprite(1, 0, blankSprite.method_4594(), blankSprite.method_4575())
					.pos(2, uv(min, dU, dV, 1, 1))
					.normal(2, normal)
					.sprite(2, 0, blankSprite.method_4577(), blankSprite.method_4575())
					.pos(3, uv(min, dU, dV, 1, 0))
					.normal(3, normal)
					.sprite(3, 0, blankSprite.method_4577(), blankSprite.method_4593())
					.emit();

			return;
		}

		// top left
		var subSprite = getSubSprite(subSpriteEntry.TopLeft(), blankSprite, borderSprite, 4, 4);

		quadEmitter
				.colorIndex(1)
				.spriteColor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
				.pos(0, min)
				.normal(0, normal)
				.sprite(0, 0, subSprite.minU(), subSprite.minV())
				.pos(1, uv(min, dU, dV, 0, 0.5f))
				.normal(1, normal)
				.sprite(1, 0, subSprite.minU(), subSprite.maxV())
				.pos(2, uv(min, dU, dV, 0.5f, 0.5f))
				.normal(2, normal)
				.sprite(2, 0, subSprite.maxU(), subSprite.maxV())
				.pos(3, uv(min, dU, dV, 0.5f, 0))
				.normal(3, normal)
				.sprite(3, 0, subSprite.maxU(), subSprite.minV())
				.emit();

		// top right
		subSprite = getSubSprite(subSpriteEntry.TopRight(), blankSprite, borderSprite, 4, 4);

		quadEmitter
				.colorIndex(1)
				.spriteColor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
				.pos(0, uv(min, dU, dV, 0.5f, 0))
				.normal(0, normal)
				.sprite(0, 0, subSprite.minU(), subSprite.minV())
				.pos(1, uv(min, dU, dV, 0.5f, 0.5f))
				.normal(1, normal)
				.sprite(1, 0, subSprite.minU(), subSprite.maxV())
				.pos(2, uv(min, dU, dV, 1, 0.5f))
				.normal(2, normal)
				.sprite(2, 0, subSprite.maxU(), subSprite.maxV())
				.pos(3, uv(min, dU, dV, 1, 0))
				.normal(3, normal)
				.sprite(3, 0, subSprite.maxU(), subSprite.minV())
				.emit();

		// bottom left
		subSprite = getSubSprite(subSpriteEntry.BottomLeft(), blankSprite, borderSprite, 4, 4);

		quadEmitter
				.colorIndex(1)
				.spriteColor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
				.pos(0, uv(min, dU, dV, 0, 0.5f))
				.normal(0, normal)
				.sprite(0, 0, subSprite.minU(), subSprite.minV())
				.pos(1, uv(min, dU, dV, 0, 1))
				.normal(1, normal)
				.sprite(1, 0, subSprite.minU(), subSprite.maxV())
				.pos(2, uv(min, dU, dV, 0.5f, 1))
				.normal(2, normal)
				.sprite(2, 0, subSprite.maxU(), subSprite.maxV())
				.pos(3, uv(min, dU, dV, 0.5f, 0.5f))
				.normal(3, normal)
				.sprite(3, 0, subSprite.maxU(), subSprite.minV())
				.emit();

		// bottom right
		subSprite = getSubSprite(subSpriteEntry.BottomRight(), blankSprite, borderSprite, 4, 4);

		quadEmitter
				.colorIndex(1)
				.spriteColor(0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)
				.pos(0, uv(min, dU, dV, 0.5f, 0.5f))
				.normal(0, normal)
				.sprite(0, 0, subSprite.minU(), subSprite.minV())
				.pos(1, uv(min, dU, dV, 0.5f, 1))
				.normal(1, normal)
				.sprite(1, 0, subSprite.minU(), subSprite.maxV())
				.pos(2, uv(min, dU, dV, 1, 1))
				.normal(2, normal)
				.sprite(2, 0, subSprite.maxU(), subSprite.maxV())
				.pos(3, uv(min, dU, dV, 1, 0.5f))
				.normal(3, normal)
				.sprite(3, 0, subSprite.maxU(), subSprite.minV())
				.emit();
	}

	private static SubSprite getSubSprite(SpriteSheetPoint point, class_1058 blankSprite, class_1058 borderSprite, int columns, int rows)
	{
		var sprite = borderSprite;

		if (point.sheet() == 1) // "blank" cornerless texture
		{
			sprite = blankSprite;
			rows = 2;
			columns = 2;
		}

		var spriteWidth = sprite.method_4577() - sprite.method_4594();
		var spriteHeight = sprite.method_4575() - sprite.method_4593();

		var columnSpan = spriteWidth / columns;
		var rowSpan = spriteHeight / rows;

		return new SubSprite(sprite.method_4594() + point.x() * columnSpan, sprite.method_4593() + point.y() * rowSpan, sprite.method_4594() + (point.x() + 1) * columnSpan, sprite.method_4593() + (point.y() + 1) * rowSpan);
	}

	@Override
	protected Mesh createItemMesh(class_1799 stack, Supplier randomSupplier, RenderContext context, Matrix4f transformation)
	{
		return createBlockMesh(null, null, null, null, null, transformation);
	}

	@Override
	protected Matrix4f createTransformation(class_2680 state)
	{
		return new Matrix4f();
	}

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

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

	public static class Unbaked extends ClonableUnbakedModel
	{
		private final Function, ConnectedTextureModel> baker;
		private ConnectedTextureModel cachedBakedModel;
		private final boolean hConnect;
		private final boolean vConnect;
		private final boolean lConnect;
		private final EnumSet capDirections;
		private final class_4730 sprite;
		private final class_4730 borderSprite;
		private final class_4730 capSprite;

		public Unbaked(boolean hConnect, boolean vConnect, boolean lConnect, EnumSet capDirections, class_4730 sprite, class_4730 borderSprite, class_4730 capSprite)
		{
			this.hConnect = hConnect;
			this.vConnect = vConnect;
			this.lConnect = lConnect;
			this.capDirections = capDirections;
			this.sprite = sprite;
			this.borderSprite = borderSprite;
			this.capSprite = capSprite;
			this.baker = spriteLoader -> new ConnectedTextureModel(hConnect, vConnect, lConnect, capDirections, spriteLoader.apply(sprite), spriteLoader.apply(borderSprite), capSprite == null ? null : spriteLoader.apply(capSprite));
		}

		@Override
		public Collection method_4755()
		{
			return Collections.emptyList();
		}

		@Override
		public void method_45785(Function modelLoader)
		{
			// TODO: parents?
		}

		@Nullable
		@Override
		public class_1087 method_4753(class_7775 baker, Function textureGetter, class_3665 rotationContainer, class_2960 modelId)
		{
			if (cachedBakedModel != null)
				return cachedBakedModel;

			var result = this.baker.apply(textureGetter);
			cachedBakedModel = result;
			return result;
		}

		// TODO: no longer required?
		//		@Override
		public Collection getTextureDependencies(Function unbakedModelGetter, Set> unresolvedTextureReferences)
		{
			var ids = new ArrayList();

			ids.add(sprite);
			ids.add(borderSprite);

			if (capSprite != null)
				ids.add(capSprite);

			return ids;
		}

		@Override
		public ClonableUnbakedModel copy()
		{
			return new Unbaked(hConnect, vConnect, lConnect, capDirections.clone(), sprite, borderSprite, capSprite);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy