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

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

There is a newer version: 0.0.114+1.20.2
Show newest version
/*******************************************************************************
 * Copyright 2019 grondag
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.  You may obtain a copy
 * of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/

package com.parzivail.util.client.model;

import ;
import com.google.common.collect.ImmutableList;
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
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_1309;
import net.minecraft.class_1799;
import net.minecraft.class_1920;
import net.minecraft.class_1922;
import net.minecraft.class_2338;
import net.minecraft.class_2350;
import net.minecraft.class_2680;
import net.minecraft.class_5819;
import net.minecraft.class_638;
import net.minecraft.class_777;
import net.minecraft.class_806;
import net.minecraft.class_809;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * Simple baked model supporting the Fabric Render API features.
 */
public abstract class DynamicBakedModel extends AbstractModel
{
	public enum CacheMethod
	{
		SINGLETON,
		BLOCKSTATE_KEY,
		RENDER_SEED_KEY,
		NO_CACHING
	}

	// These are dirty hacks to at least have some semblance of "working" models when
	// a rendering mod replaces Indigo without implementing FRAPI. I hate them, and
	// they only work because AbstractBlockState::getModelOffset is called before each
	// block is rendered.
	// TODO: figure out a better way to do this
	private static final ThreadLocal lastQueriedWorld = new ThreadLocal<>();
	private static final ThreadLocal lastQueriedPos = new ThreadLocal<>();

	protected final ItemProxy itemProxy = new ItemProxy();
	protected final HashMap meshes = new HashMap<>();
	protected WeakReference[]> quadLists = null;

	public DynamicBakedModel(class_1058 sprite, class_809 transformation)
	{
		super(sprite, transformation);
	}

	public static void cacheBlockPosQuery(class_1922 world, class_2338 pos)
	{
		lastQueriedWorld.set(world);
		lastQueriedPos.set(pos);
	}

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

	protected CacheMethod getDiscriminator()
	{
		return CacheMethod.SINGLETON;
	}

	protected abstract Mesh createBlockMesh(class_1920 blockView, class_2680 state, class_2338 pos, Supplier randomSupplier, RenderContext context, Matrix4f transformation);

	protected abstract Mesh createItemMesh(class_1799 stack, Supplier randomSupplier, RenderContext context, Matrix4f transformation);

	protected Mesh createOrCacheBlockMesh(class_1920 blockView, class_2680 state, class_2338 pos, Supplier randomSupplier, RenderContext context, Matrix4f transformation)
	{
		var cacheDiscriminator = switch (getDiscriminator())
				{
					case SINGLETON -> class_2338.field_10980;
					case BLOCKSTATE_KEY -> state;
					case RENDER_SEED_KEY -> state == null ? 0 : state.method_26190(pos);
					default -> null;
				};

		if (cacheDiscriminator == null)
			return createBlockMesh(blockView, state, pos, randomSupplier, context, transformation);

		var cacheId = new ModelCacheId(cacheDiscriminator, transformation);

		if (meshes.containsKey(cacheId))
			return meshes.get(cacheId);

		var m = createBlockMesh(blockView, state, pos, randomSupplier, context, transformation);
		meshes.put(cacheId, m);

		return m;
	}

	protected Mesh createOrCacheItemMesh(class_1799 stack, Supplier randomSupplier, RenderContext context, Matrix4f transformation)
	{
		var cacheId = new ModelCacheId(null, transformation);

		if (meshes.containsKey(cacheId))
			return meshes.get(cacheId);

		var m = createItemMesh(stack, randomSupplier, context, transformation);
		meshes.put(cacheId, m);

		return m;
	}

	protected abstract Matrix4f createTransformation(class_2680 state);

	@Override
	public List method_4707(class_2680 state, class_2350 face, class_5819 rand)
	{
		var lists = quadLists == null ? null : quadLists.get();
		if (lists == null)
		{
			var world = lastQueriedWorld.get() instanceof class_1920 brv ? brv : null;
			var pos = lastQueriedPos.get();
			if (pos == null)
				pos = class_2338.field_10980;

			lists = ModelHelper.toQuadLists(createOrCacheBlockMesh(world, state, pos, () -> rand, null, createTransformation(state)));
			quadLists = new WeakReference<>(lists);
		}
		final var result = lists[face == null ? 6 : face.method_10146()];
		return result == null ? ImmutableList.of() : result;
	}

	@Override
	public void emitBlockQuads(class_1920 blockView, class_2680 state, class_2338 pos, Supplier randomSupplier, RenderContext context)
	{
		context.meshConsumer().accept(createOrCacheBlockMesh(blockView, state, pos, randomSupplier, context, createTransformation(state)));
	}

	@Override
	public class_806 method_4710()
	{
		return itemProxy;
	}

	@Override
	public void emitItemQuads(class_1799 stack, Supplier randomSupplier, RenderContext context)
	{
		context.meshConsumer().accept(createOrCacheItemMesh(stack, randomSupplier, context, createTransformation(null)));
	}

	protected class ItemProxy extends class_806
	{
		public ItemProxy()
		{
			super(null, null, Collections.emptyList());
		}

		@Override
		public class_1087 method_3495(class_1087 model, class_1799 stack, @Nullable class_638 world, @Nullable class_1309 entity, int seed)
		{
			return DynamicBakedModel.this;
		}
	}

	private record ModelCacheId(Object discriminator, Matrix4f transformation)
	{
		@Override
		public int hashCode()
		{
			if (discriminator == null)
				return transformation.hashCode() * 31;

			return discriminator.hashCode();
		}

		@Override
		public boolean equals(Object o)
		{
			if (this == o)
				return true;
			if (!(o instanceof ModelCacheId cacheId))
				return false;

			if (this.discriminator == null && cacheId.discriminator == null)
				return Objects.equals(transformation, cacheId.transformation);

			return Objects.equals(discriminator, cacheId.discriminator);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy