Compiling models

- Make model builders abstract
- Move BakedModelBufferer as is into forge project
- Create Forge*ModelBuilders with modeldata parameters
- Wrap ModelBuilder ctors in factory methods
- Add FlywheelLibPlatform api, similar to api.internal package but for
  lib-only/platform specific stuff
- Move TransformStack wrapping into FlywheelLibPlatform
- Create vanilla renderer through FlywheelLibPlatform
- Handle partial model initialization in separate event handler class
- Fix test configuration in common project
This commit is contained in:
Jozufozu 2024-04-19 23:01:28 -07:00
parent ff0a928479
commit 57ac1b08f4
20 changed files with 413 additions and 205 deletions

View file

@ -6,9 +6,11 @@ dependencies {
modCompileOnly "net.fabricmc:fabric-loader:$fabric_loader_version"
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
}
test.configure {
test {
useJUnitPlatform()
}

View file

@ -12,8 +12,6 @@ import com.jozufozu.flywheel.api.vertex.VertexViewProvider;
import com.jozufozu.flywheel.api.visualization.BlockEntityVisualizer;
import com.jozufozu.flywheel.api.visualization.EntityVisualizer;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.lib.transform.PoseTransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.world.entity.Entity;
@ -94,6 +92,4 @@ public interface InternalFlywheelApi {
<T extends BlockEntity> void setVisualizer(BlockEntityType<T> type, BlockEntityVisualizer<? super T> visualizer);
<T extends Entity> void setVisualizer(EntityType<T> type, EntityVisualizer<? super T> visualizer);
PoseTransformStack getPoseTransformStackOf(PoseStack stack);
}

View file

@ -111,9 +111,4 @@ public final class InternalFlywheelImpl implements InternalFlywheelApi {
public <T extends Entity> void setVisualizer(EntityType<T> type, EntityVisualizer<? super T> visualizer) {
VisualizerRegistryImpl.setVisualizer(type, visualizer);
}
@Override
public PoseTransformStack getPoseTransformStackOf(PoseStack stack) {
return ((PoseStackExtension) stack).flywheel$transformStack();
}
}

View file

@ -0,0 +1,64 @@
package com.jozufozu.flywheel.lib.internal;
import java.lang.reflect.Constructor;
import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder;
import com.jozufozu.flywheel.lib.transform.PoseTransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
public interface FlywheelLibPlatform {
FlywheelLibPlatform INSTANCE = load();
// Adapted from https://github.com/CaffeineMC/sodium-fabric/blob/bf4fc9dab16e1cca07b2f23a1201c9bf237c8044/src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java
private static FlywheelLibPlatform load() {
Class<FlywheelLibPlatform> apiClass = FlywheelLibPlatform.class;
Class<?> implClass;
try {
implClass = Class.forName("com.jozufozu.flywheel.impl.FlywheelLibPlatformImpl");
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Could not find implementation", e);
}
if (!apiClass.isAssignableFrom(implClass)) {
throw new RuntimeException("Class %s does not implement interface %s"
.formatted(implClass.getName(), apiClass.getName()));
}
Constructor<?> implConstructor;
try {
implConstructor = implClass.getConstructor();
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Could not find default constructor", e);
}
Object implInstance;
try {
implInstance = implConstructor.newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Could not instantiate implementation", e);
}
return apiClass.cast(implInstance);
}
PoseTransformStack getPoseTransformStackOf(PoseStack stack);
BlockRenderDispatcher createVanillaRenderer();
BakedModelBuilder bakedModelBuilder(BakedModel bakedModel);
BlockModelBuilder blockModelBuilder(BlockState state);
MultiBlockModelBuilder multiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions);
}

View file

@ -0,0 +1,12 @@
@ApiStatus.Internal
@ParametersAreNonnullByDefault
@FieldsAreNonnullByDefault
@MethodsReturnNonnullByDefault
package com.jozufozu.flywheel.lib.internal;
import javax.annotation.ParametersAreNonnullByDefault;
import org.jetbrains.annotations.ApiStatus;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.lib.model;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Collection;
@ -8,8 +7,8 @@ import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import org.joml.Vector4f;
import org.lwjgl.system.MemoryUtil;
import org.slf4j.Logger;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
@ -22,43 +21,21 @@ import com.jozufozu.flywheel.lib.vertex.PosVertexView;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.BufferBuilder.DrawState;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
public final class ModelUtil {
private static final Logger LOGGER = LogUtils.getLogger();
/**
* An alternative BlockRenderDispatcher that circumvents the Forge rendering pipeline to ensure consistency.
* Meant to be used for virtual rendering.
*/
public static final BlockRenderDispatcher VANILLA_RENDERER = createVanillaRenderer();
public static final BlockRenderDispatcher VANILLA_RENDERER = FlywheelLibPlatform.INSTANCE.createVanillaRenderer();
private static final float BOUNDING_SPHERE_EPSILON = 1e-4f;
private ModelUtil() {
}
private static BlockRenderDispatcher createVanillaRenderer() {
BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer();
BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null);
try {
for (Field field : BlockRenderDispatcher.class.getDeclaredFields()) {
field.setAccessible(true);
field.set(dispatcher, field.get(defaultDispatcher));
}
ObfuscationReflectionHelper.setPrivateValue(BlockRenderDispatcher.class, dispatcher, new ModelBlockRenderer(Minecraft.getInstance().getBlockColors()), "f_110900_");
} catch (Exception e) {
LOGGER.error("Failed to initialize vanilla BlockRenderDispatcher!", e);
return defaultDispatcher;
}
return dispatcher;
}
public static MemoryBlock convertVanillaBuffer(BufferBuilder.RenderedBuffer buffer, VertexView vertexView) {
DrawState drawState = buffer.drawState();
int vertexCount = drawState.vertexCount();

View file

@ -19,8 +19,10 @@ import net.minecraft.world.level.block.state.BlockState;
* method with the same parameters will return the same object.
*/
public final class Models {
private static final ModelCache<BlockState> BLOCK_STATE = new ModelCache<>(it -> new BlockModelBuilder(it).build());
private static final ModelCache<PartialModel> PARTIAL = new ModelCache<>(it -> new BakedModelBuilder(it.get()).build());
private static final ModelCache<BlockState> BLOCK_STATE = new ModelCache<>(it -> BlockModelBuilder.create(it)
.build());
private static final ModelCache<PartialModel> PARTIAL = new ModelCache<>(it -> BakedModelBuilder.create(it.get())
.build());
private static final ModelCache<TransformedPartial<?>> TRANSFORMED_PARTIAL = new ModelCache<>(TransformedPartial::create);
private Models() {
@ -85,7 +87,7 @@ public final class Models {
private Model create() {
var stack = new PoseStack();
transformer.accept(key, stack);
return new BakedModelBuilder(partial.get())
return BakedModelBuilder.create(partial.get())
.poseStack(stack)
.build();
}

View file

@ -8,11 +8,12 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import com.mojang.blaze3d.vertex.PoseStack;
@ -21,22 +22,23 @@ import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
public class BakedModelBuilder {
private final BakedModel bakedModel;
public abstract class BakedModelBuilder {
protected final BakedModel bakedModel;
@Nullable
private BlockAndTintGetter level;
protected BlockAndTintGetter level;
@Nullable
private BlockState blockState;
protected BlockState blockState;
@Nullable
private PoseStack poseStack;
protected PoseStack poseStack;
@Nullable
private ModelData modelData;
@Nullable
private BiFunction<RenderType, Boolean, Material> materialFunc;
protected BiFunction<RenderType, Boolean, Material> materialFunc;
public BakedModelBuilder(BakedModel bakedModel) {
public static BakedModelBuilder create(BakedModel bakedModel) {
return FlywheelLibPlatform.INSTANCE.bakedModelBuilder(bakedModel);
}
protected BakedModelBuilder(BakedModel bakedModel) {
this.bakedModel = bakedModel;
}
@ -55,43 +57,10 @@ public class BakedModelBuilder {
return this;
}
public BakedModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
public BakedModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
this.materialFunc = materialFunc;
return this;
}
public SimpleModel build() {
if (level == null) {
level = VirtualEmptyBlockGetter.INSTANCE;
}
if (blockState == null) {
blockState = Blocks.AIR.defaultBlockState();
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, resultConsumer);
return new SimpleModel(out.build());
}
public abstract SimpleModel build();
}

View file

@ -8,31 +8,33 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
public class BlockModelBuilder {
private final BlockState state;
public abstract class BlockModelBuilder {
protected final BlockState state;
@Nullable
private BlockAndTintGetter level;
protected BlockAndTintGetter level;
@Nullable
private PoseStack poseStack;
protected PoseStack poseStack;
@Nullable
private ModelData modelData;
@Nullable
private BiFunction<RenderType, Boolean, Material> materialFunc;
protected BiFunction<RenderType, Boolean, Material> materialFunc;
public BlockModelBuilder(BlockState state) {
public static BlockModelBuilder create(BlockState state) {
return FlywheelLibPlatform.INSTANCE.blockModelBuilder(state);
}
protected BlockModelBuilder(BlockState state) {
this.state = state;
}
@ -46,40 +48,10 @@ public class BlockModelBuilder {
return this;
}
public BlockModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
public BlockModelBuilder materialFunc(BiFunction<RenderType, Boolean, Material> materialFunc) {
this.materialFunc = materialFunc;
return this;
}
public SimpleModel build() {
if (level == null) {
level = VirtualEmptyBlockGetter.INSTANCE;
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, resultConsumer);
return new SimpleModel(out.build());
}
public abstract SimpleModel build();
}

View file

@ -17,14 +17,14 @@ class MeshEmitter implements VertexConsumer {
private boolean lastQuadWasShaded;
private boolean seenFirstQuad;
@Nullable
private BakedModelBufferer.ResultConsumer resultConsumer;
private MeshEmitter.ResultConsumer resultConsumer;
MeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) {
this.bufferBuilder = bufferBuilder;
this.renderType = renderType;
}
public void begin(BakedModelBufferer.ResultConsumer resultConsumer) {
public void begin(ResultConsumer resultConsumer) {
this.resultConsumer = resultConsumer;
begin();
@ -112,4 +112,8 @@ class MeshEmitter implements VertexConsumer {
public void unsetDefaultColor() {
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");
}
public interface ResultConsumer {
void accept(RenderType renderType, boolean shaded, BufferBuilder.RenderedBuffer data);
}
}

View file

@ -1,39 +1,32 @@
package com.jozufozu.flywheel.lib.model.baked;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.BakedModelBufferer.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraftforge.client.model.data.ModelData;
public class MultiBlockModelBuilder {
private final BlockAndTintGetter level;
private final Iterable<BlockPos> positions;
public abstract class MultiBlockModelBuilder {
protected final BlockAndTintGetter level;
protected final Iterable<BlockPos> positions;
@Nullable
private PoseStack poseStack;
protected PoseStack poseStack;
protected boolean renderFluids = false;
@Nullable
private Function<BlockPos, ModelData> modelDataLookup;
private boolean renderFluids = false;
@Nullable
private BiFunction<RenderType, Boolean, Material> materialFunc;
protected BiFunction<RenderType, Boolean, Material> materialFunc;
public MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
public static MultiBlockModelBuilder create(BlockAndTintGetter level, Iterable<BlockPos> positions) {
return FlywheelLibPlatform.INSTANCE.multiBlockModelBuilder(level, positions);
}
protected MultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
this.level = level;
this.positions = positions;
}
@ -43,11 +36,6 @@ public class MultiBlockModelBuilder {
return this;
}
public MultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
this.modelDataLookup = modelDataLookup;
return this;
}
public MultiBlockModelBuilder enableFluidRendering() {
renderFluids = true;
return this;
@ -58,27 +46,5 @@ public class MultiBlockModelBuilder {
return this;
}
public SimpleModel build() {
if (modelDataLookup == null) {
modelDataLookup = pos -> ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, resultConsumer);
return new SimpleModel(out.build());
}
public abstract SimpleModel build();
}

View file

@ -5,7 +5,6 @@ import java.util.List;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.event.ModelEvent;
/**
* A helper class for loading and accessing json models.
@ -19,8 +18,8 @@ import net.minecraftforge.client.event.ModelEvent;
* Attempting to create a PartialModel after {@link ModelEvent.RegisterAdditional} will cause an error.
*/
public class PartialModel {
private static final List<PartialModel> ALL = new ArrayList<>();
private static boolean tooLate = false;
static final List<PartialModel> ALL = new ArrayList<>();
static boolean tooLate = false;
protected final ResourceLocation modelLocation;
protected BakedModel bakedModel;
@ -34,30 +33,11 @@ public class PartialModel {
ALL.add(this);
}
public static void onModelRegistry(ModelEvent.RegisterAdditional event) {
for (PartialModel partial : ALL) {
event.register(partial.getLocation());
}
tooLate = true;
}
public static void onModelBake(ModelEvent.BakingCompleted event) {
var modelRegistry = event.getModels();
for (PartialModel partial : ALL) {
partial.set(modelRegistry.get(partial.getLocation()));
}
}
public String getName() {
return getLocation()
.toString();
}
protected void set(BakedModel bakedModel) {
this.bakedModel = bakedModel;
}
public ResourceLocation getLocation() {
return modelLocation;
}
@ -65,4 +45,8 @@ public class PartialModel {
public BakedModel get() {
return bakedModel;
}
void set(BakedModel bakedModel) {
this.bakedModel = bakedModel;
}
}

View file

@ -1,11 +1,11 @@
package com.jozufozu.flywheel.lib.transform;
import com.jozufozu.flywheel.api.internal.InternalFlywheelApi;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.mojang.blaze3d.vertex.PoseStack;
public interface TransformStack<Self extends TransformStack<Self>> extends Transform<Self> {
static PoseTransformStack of(PoseStack stack) {
return InternalFlywheelApi.INSTANCE.getPoseTransformStackOf(stack);
return FlywheelLibPlatform.INSTANCE.getPoseTransformStackOf(stack);
}
Self pushPose();

View file

@ -19,7 +19,7 @@ import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler;
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
import com.jozufozu.flywheel.lib.model.ModelCache;
import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.model.baked.PartialModel;
import com.jozufozu.flywheel.lib.model.baked.PartialModelEventHandler;
import com.jozufozu.flywheel.lib.util.LevelAttached;
import com.jozufozu.flywheel.lib.util.StringUtil;
@ -98,8 +98,8 @@ public class FlywheelForge {
modEventBus.<EndClientResourceReloadEvent>addListener($ -> ModelCache.onEndClientResourceReload());
modEventBus.<EndClientResourceReloadEvent>addListener($ -> ModelHolder.onEndClientResourceReload());
modEventBus.addListener(PartialModel::onModelRegistry);
modEventBus.addListener(PartialModel::onModelBake);
modEventBus.addListener(PartialModelEventHandler::onModelRegistry);
modEventBus.addListener(PartialModelEventHandler::onModelBake);
Flywheel.earlyInit();
CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString);

View file

@ -0,0 +1,67 @@
package com.jozufozu.flywheel.impl;
import java.lang.reflect.Field;
import org.slf4j.Logger;
import com.jozufozu.flywheel.impl.extension.PoseStackExtension;
import com.jozufozu.flywheel.lib.internal.FlywheelLibPlatform;
import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.ForgeBakedModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.ForgeBlockModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.ForgeMultiBlockModelBuilder;
import com.jozufozu.flywheel.lib.model.baked.MultiBlockModelBuilder;
import com.jozufozu.flywheel.lib.transform.PoseTransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
public class FlywheelLibPlatformImpl implements FlywheelLibPlatform {
private static final Logger LOGGER = LogUtils.getLogger();
@Override
public PoseTransformStack getPoseTransformStackOf(PoseStack stack) {
return ((PoseStackExtension) stack).flywheel$transformStack();
}
@Override
public BlockRenderDispatcher createVanillaRenderer() {
BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer();
BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null);
try {
for (Field field : BlockRenderDispatcher.class.getDeclaredFields()) {
field.setAccessible(true);
field.set(dispatcher, field.get(defaultDispatcher));
}
ObfuscationReflectionHelper.setPrivateValue(BlockRenderDispatcher.class, dispatcher, new ModelBlockRenderer(Minecraft.getInstance().getBlockColors()), "f_110900_");
} catch (Exception e) {
LOGGER.error("Failed to initialize vanilla BlockRenderDispatcher!", e);
return defaultDispatcher;
}
return dispatcher;
}
@Override
public BakedModelBuilder bakedModelBuilder(BakedModel bakedModel) {
return new ForgeBakedModelBuilder(bakedModel);
}
@Override
public BlockModelBuilder blockModelBuilder(BlockState state) {
return new ForgeBlockModelBuilder(state);
}
@Override
public MultiBlockModelBuilder multiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
return new ForgeMultiBlockModelBuilder(level, positions);
}
}

View file

@ -33,7 +33,7 @@ final class BakedModelBufferer {
private BakedModelBufferer() {
}
public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) {
public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter level, BakedModel model, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) {
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
if (poseStack == null) {
poseStack = objects.identityPoseStack;
@ -59,7 +59,7 @@ final class BakedModelBufferer {
}
}
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, ResultConsumer resultConsumer) {
public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter level, BlockState state, @Nullable PoseStack poseStack, ModelData modelData, MeshEmitter.ResultConsumer resultConsumer) {
if (state.getRenderShape() != RenderShape.MODEL) {
return;
}
@ -67,7 +67,7 @@ final class BakedModelBufferer {
bufferSingle(renderDispatcher.getModelRenderer(), level, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer);
}
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, ResultConsumer resultConsumer) {
public static void bufferMultiBlock(BlockRenderDispatcher renderDispatcher, Iterator<BlockPos> posIterator, BlockAndTintGetter level, @Nullable PoseStack poseStack, Function<BlockPos, ModelData> modelDataLookup, boolean renderFluids, MeshEmitter.ResultConsumer resultConsumer) {
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
if (poseStack == null) {
poseStack = objects.identityPoseStack;
@ -142,13 +142,13 @@ final class BakedModelBufferer {
public final TransformingVertexConsumer transformingWrapper = new TransformingVertexConsumer();
public final MeshEmitter[] emitters = new MeshEmitter[CHUNK_LAYER_AMOUNT];
public final ForgeMeshEmitter[] emitters = new ForgeMeshEmitter[CHUNK_LAYER_AMOUNT];
{
for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) {
var renderType = CHUNK_LAYERS[layerIndex];
var buffer = new BufferBuilder(renderType.bufferSize());
emitters[layerIndex] = new MeshEmitter(buffer, renderType);
emitters[layerIndex] = new ForgeMeshEmitter(buffer, renderType);
}
}
}

View file

@ -0,0 +1,62 @@
package com.jozufozu.flywheel.lib.model.baked;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.client.model.data.ModelData;
public class ForgeBakedModelBuilder extends BakedModelBuilder {
@Nullable
private ModelData modelData;
public ForgeBakedModelBuilder(BakedModel bakedModel) {
super(bakedModel);
}
public ForgeBakedModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
public SimpleModel build() {
if (level == null) {
level = VirtualEmptyBlockGetter.INSTANCE;
}
if (blockState == null) {
blockState = Blocks.AIR.defaultBlockState();
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=BakedModelBuilder," + "bakedModel=" + bakedModel + ",renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), level, bakedModel, blockState, poseStack, modelData, resultConsumer);
return new SimpleModel(out.build());
}
}

View file

@ -0,0 +1,58 @@
package com.jozufozu.flywheel.lib.model.baked;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.data.ModelData;
public class ForgeBlockModelBuilder extends BlockModelBuilder {
@Nullable
private ModelData modelData;
public ForgeBlockModelBuilder(BlockState state) {
super(state);
}
public ForgeBlockModelBuilder modelData(ModelData modelData) {
this.modelData = modelData;
return this;
}
public SimpleModel build() {
if (level == null) {
level = VirtualEmptyBlockGetter.INSTANCE;
}
if (modelData == null) {
modelData = ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=BlockModelBuilder," + "blockState=" + state + ",renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferBlock(ModelUtil.VANILLA_RENDERER, level, state, poseStack, modelData, resultConsumer);
return new SimpleModel(out.build());
}
}

View file

@ -0,0 +1,58 @@
package com.jozufozu.flywheel.lib.model.baked;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.api.vertex.VertexView;
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.jozufozu.flywheel.lib.model.ModelUtil;
import com.jozufozu.flywheel.lib.model.SimpleMesh;
import com.jozufozu.flywheel.lib.model.SimpleModel;
import com.jozufozu.flywheel.lib.model.baked.MeshEmitter.ResultConsumer;
import com.jozufozu.flywheel.lib.vertex.NoOverlayVertexView;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraftforge.client.model.data.ModelData;
public class ForgeMultiBlockModelBuilder extends MultiBlockModelBuilder {
@Nullable
private Function<BlockPos, ModelData> modelDataLookup;
public ForgeMultiBlockModelBuilder(BlockAndTintGetter level, Iterable<BlockPos> positions) {
super(level, positions);
}
public ForgeMultiBlockModelBuilder modelDataLookup(Function<BlockPos, ModelData> modelDataLookup) {
this.modelDataLookup = modelDataLookup;
return this;
}
public SimpleModel build() {
if (modelDataLookup == null) {
modelDataLookup = pos -> ModelData.EMPTY;
}
if (materialFunc == null) {
materialFunc = ModelUtil::getMaterial;
}
var out = ImmutableList.<Model.ConfiguredMesh>builder();
ResultConsumer resultConsumer = (renderType, shaded, data) -> {
Material material = materialFunc.apply(renderType, shaded);
if (material != null) {
VertexView vertexView = new NoOverlayVertexView();
MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, vertexView);
var mesh = new SimpleMesh(vertexView, meshData, "source=MultiBlockModelBuilder," + "renderType=" + renderType + ",shaded=" + shaded);
out.add(new Model.ConfiguredMesh(material, mesh));
}
};
BakedModelBufferer.bufferMultiBlock(ModelUtil.VANILLA_RENDERER, positions.iterator(), level, poseStack, modelDataLookup, renderFluids, resultConsumer);
return new SimpleModel(out.build());
}
}

View file

@ -0,0 +1,20 @@
package com.jozufozu.flywheel.lib.model.baked;
import net.minecraftforge.client.event.ModelEvent;
public class PartialModelEventHandler {
public static void onModelRegistry(ModelEvent.RegisterAdditional event) {
for (PartialModel partial : PartialModel.ALL) {
event.register(partial.getLocation());
}
PartialModel.tooLate = true;
}
public static void onModelBake(ModelEvent.BakingCompleted event) {
var modelRegistry = event.getModels();
for (PartialModel partial : PartialModel.ALL) {
partial.set(modelRegistry.get(partial.getLocation()));
}
}
}