package software.bernie.geckolib.renderer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3f; import software.bernie.geckolib.GeckoLibServices; import software.bernie.geckolib.animatable.GeoAnimatable; import software.bernie.geckolib.animation.AnimationState; import software.bernie.geckolib.cache.object.BakedGeoModel; import software.bernie.geckolib.cache.object.GeoBone; import software.bernie.geckolib.cache.texture.AnimatableTexture; import software.bernie.geckolib.constant.DataTickets; import software.bernie.geckolib.model.DefaultedBlockGeoModel; import software.bernie.geckolib.model.GeoModel; import software.bernie.geckolib.renderer.layer.GeoRenderLayer; import software.bernie.geckolib.renderer.layer.GeoRenderLayersContainer; import software.bernie.geckolib.util.RenderUtil; import java.util.List; import net.minecraft.class_1921; import net.minecraft.class_2318; import net.minecraft.class_2338; import net.minecraft.class_2350; import net.minecraft.class_2383; import net.minecraft.class_2586; import net.minecraft.class_2591; import net.minecraft.class_2680; import net.minecraft.class_4587; import net.minecraft.class_4588; import net.minecraft.class_4597; import net.minecraft.class_7833; import net.minecraft.class_7923; import net.minecraft.class_827; /** * Base {@link GeoRenderer} class for rendering {@link class_2586 Blocks} specifically *
* All blocks added to be rendered by GeckoLib should use an instance of this class.
*/
public class GeoBlockRenderer
* This is mostly useful for things like items, which have a single registered instance for all objects
*/
@Override
public long getInstanceId(T animatable) {
return animatable.method_11016().hashCode();
}
/**
* Returns the list of registered {@link GeoRenderLayer GeoRenderLayers} for this renderer
*/
@Override
public List
* {@link class_4587} translations made here are kept until the end of the render process
*/
@Override
public void preRender(class_4587 poseStack, T animatable, BakedGeoModel model, @Nullable class_4597 bufferSource, @Nullable class_4588 buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {
this.blockRenderTranslations = new Matrix4f(poseStack.method_23760().method_23761());
if (!isReRender)
poseStack.method_22904(0.5, 0, 0.5);
scaleModelForRender(this.scaleWidth, this.scaleHeight, poseStack, animatable, model, isReRender, partialTick, packedLight, packedOverlay);
}
@Override
@ApiStatus.Internal
public void method_3569(T animatable, float partialTick, class_4587 poseStack, class_4597 bufferSource,
int packedLight, int packedOverlay) {
this.animatable = animatable;
defaultRender(poseStack, this.animatable, bufferSource, null, null, 0, partialTick, packedLight);
}
/**
* The actual render method that subtype renderers should override to handle their specific rendering tasks
*
* {@link GeoRenderer#preRender} has already been called by this stage, and {@link GeoRenderer#postRender} will be called directly after
*/
@Override
public void actuallyRender(class_4587 poseStack, T animatable, BakedGeoModel model, @Nullable class_1921 renderType,
class_4597 bufferSource, @Nullable class_4588 buffer, boolean isReRender, float partialTick, int packedLight,
int packedOverlay, int colour) {
if (!isReRender) {
AnimationState
* Use this method to clean up any leftover persistent objects stored during rendering or any other post-render maintenance tasks as required
*/
@Override
public void doPostRenderCleanup() {
this.animatable = null;
}
/**
* Renders the provided {@link GeoBone} and its associated child bones
*/
@Override
public void renderRecursively(class_4587 poseStack, T animatable, GeoBone bone, class_1921 renderType, class_4597 bufferSource, class_4588 buffer, boolean isReRender, float partialTick, int packedLight,
int packedOverlay, int colour) {
if (bone.isTrackingMatrices()) {
Matrix4f poseState = new Matrix4f(poseStack.method_23760().method_23761());
Matrix4f localMatrix = RenderUtil.invertAndMultiplyMatrices(poseState, this.blockRenderTranslations);
Matrix4f worldState = new Matrix4f(localMatrix);
class_2338 pos = this.animatable.method_11016();
bone.setModelSpaceMatrix(RenderUtil.invertAndMultiplyMatrices(poseState, this.modelRenderTranslations));
bone.setLocalSpaceMatrix(localMatrix);
bone.setWorldSpaceMatrix(worldState.translate(new Vector3f(pos.method_10263(), pos.method_10264(), pos.method_10260())));
}
GeoRenderer.super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay,
colour);
}
/**
* Rotate the {@link class_4587} based on the determined {@link class_2350} the block is facing
*/
protected void rotateBlock(class_2350 facing, class_4587 poseStack) {
switch (facing) {
case field_11035 -> poseStack.method_22907(class_7833.field_40716.rotationDegrees(180));
case field_11039 -> poseStack.method_22907(class_7833.field_40716.rotationDegrees(90));
case field_11043 -> poseStack.method_22907(class_7833.field_40716.rotationDegrees(0));
case field_11034 -> poseStack.method_22907(class_7833.field_40716.rotationDegrees(270));
case field_11036 -> poseStack.method_22907(class_7833.field_40714.rotationDegrees(90));
case field_11033 -> poseStack.method_22907(class_7833.field_40713.rotationDegrees(90));
}
}
/**
* Attempt to extract a direction from the block so that the model can be oriented correctly
*/
protected class_2350 getFacing(T block) {
class_2680 blockState = block.method_11010();
if (blockState.method_28498(class_2383.field_11177))
return blockState.method_11654(class_2383.field_11177);
if (blockState.method_28498(class_2318.field_10927))
return blockState.method_11654(class_2318.field_10927);
return class_2350.field_11043;
}
/**
* Update the current frame of a {@link AnimatableTexture potentially animated} texture used by this GeoRenderer
*
* This should only be called immediately prior to rendering
*
* @see AnimatableTexture#setAndUpdate
*/
@Override
public void updateAnimatedTextureFrame(T animatable) {
AnimatableTexture.setAndUpdate(getTextureLocation(animatable));
}
/**
* Create and fire the relevant {@code CompileLayers} event hook for this renderer
*/
@Override
public void fireCompileRenderLayersEvent() {
GeckoLibServices.Client.EVENTS.fireCompileBlockRenderLayers(this);
}
/**
* Create and fire the relevant {@code Pre-Render} event hook for this renderer
*
* @return Whether the renderer should proceed based on the cancellation state of the event
*/
@Override
public boolean firePreRenderEvent(class_4587 poseStack, BakedGeoModel model, class_4597 bufferSource, float partialTick, int packedLight) {
return GeckoLibServices.Client.EVENTS.fireBlockPreRender(this, poseStack, model, bufferSource, partialTick, packedLight);
}
/**
* Create and fire the relevant {@code Post-Render} event hook for this renderer
*/
@Override
public void firePostRenderEvent(class_4587 poseStack, BakedGeoModel model, class_4597 bufferSource, float partialTick, int packedLight) {
GeckoLibServices.Client.EVENTS.fireBlockPostRender(this, poseStack, model, bufferSource, partialTick, packedLight);
}
}