Skybox IX

neoforge
This commit is contained in:
techno-sam
2026-05-14 17:32:03 +02:00
parent 4ae5ff2b7c
commit f4d0573332
22 changed files with 259 additions and 60 deletions
@@ -3,6 +3,7 @@ package io.github.slimeistdev.crystalline_sky.neoforge;
import io.github.slimeistdev.crystalline_sky.CrystallineSky;
import io.github.slimeistdev.crystalline_sky.CrystallineSkyClient;
import io.github.slimeistdev.crystalline_sky.multiloader.neoforge.ItemGroupRegistrationEventImpl;
import io.github.slimeistdev.crystalline_sky.neoforge.skybox_model.SkyboxGeometryLoader;
import io.github.slimeistdev.crystalline_sky.registry.CrystallineItems;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineAtlases;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineRenderTypes;
@@ -12,6 +13,7 @@ import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.ModelEvent.RegisterGeometryLoaders;
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
import net.neoforged.neoforge.client.event.RegisterMaterialAtlasesEvent;
import net.neoforged.neoforge.client.event.RegisterNamedRenderTypesEvent;
@@ -49,4 +51,9 @@ public class CrystallineSkyClientImpl {
public static void registerAtlases(RegisterMaterialAtlasesEvent event) {
CrystallineAtlases.register(event::register);
}
@SubscribeEvent
public static void registerGeometryLoaders(RegisterGeometryLoaders event) {
event.register(CrystallineSky.id("skybox"), new SkyboxGeometryLoader());
}
}
@@ -0,0 +1,101 @@
package io.github.slimeistdev.crystalline_sky.neoforge.skybox_model;
import io.github.slimeistdev.crystalline_sky.util.SharedRenderVariables;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.client.model.BakedModelWrapper;
import net.neoforged.neoforge.client.model.IQuadTransformer;
import net.neoforged.neoforge.client.model.QuadTransformers;
import net.neoforged.neoforge.client.model.data.ModelData;
import net.neoforged.neoforge.common.util.TriState;
import org.jetbrains.annotations.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class SkyboxBakedModel<T extends BakedModel> extends BakedModelWrapper<T> {
private static final IQuadTransformer TRANSFORMER = QuadTransformers.settingMaxEmissivity()
.andThen(q -> {
TextureAtlasSprite sprite = q.getSprite();
float u0 = sprite.getU0();
float v0 = sprite.getV0();
int u1 = (int) (sprite.getU1() * 0xffff);
int v1 = (int) (sprite.getV1() * 0xffff);
int uv1 = (u1 << 16) | v1;
var vertices = q.getVertices();
for (int j = 0; j < 4; j++) {
vertices[j * IQuadTransformer.STRIDE + IQuadTransformer.UV0] = Float.floatToRawIntBits(u0);
vertices[j * IQuadTransformer.STRIDE + IQuadTransformer.UV0 + 1] = Float.floatToRawIntBits(v0);
vertices[j * IQuadTransformer.STRIDE + IQuadTransformer.COLOR] = uv1;
}
});
private record CacheKey(@Nullable BlockState state, @Nullable Direction side) {}
private final Map<CacheKey, List<BakedQuad>> quadCache = new HashMap<>();
public SkyboxBakedModel(T originalModel) {
super(originalModel);
}
@Override
public boolean useAmbientOcclusion() {
return false;
}
@Override
public TriState useAmbientOcclusion(BlockState state, ModelData data, RenderType renderType) {
return TriState.FALSE;
}
@Override
public boolean usesBlockLight() {
return false;
}
private static BakedQuad copyFullBright(BakedQuad quad) {
var vertices = quad.getVertices();
return new BakedQuad(
Arrays.copyOf(vertices, vertices.length),
-1, // no tint index
quad.getDirection(),
quad.getSprite(),
false, // no shade
false // no ao
);
}
private static List<BakedQuad> process(List<BakedQuad> inputs) {
return inputs.stream().map(SkyboxBakedModel::copyFullBright).peek(TRANSFORMER::processInPlace).toList();
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) {
CacheKey key = new CacheKey(state, side);
return quadCache.computeIfAbsent(key, $ -> {
SharedRenderVariables.pushShadeFullBright();
List<BakedQuad> quads = super.getQuads(state, side, rand);
List<BakedQuad> out = process(quads);
SharedRenderVariables.popShadeFullBright();
return out;
});
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand, ModelData extraData, @Nullable RenderType renderType) {
return getQuads(state, side, rand);
}
}
@@ -0,0 +1,21 @@
package io.github.slimeistdev.crystalline_sky.neoforge.skybox_model;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.neoforged.neoforge.client.model.geometry.IGeometryLoader;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class SkyboxGeometryLoader implements IGeometryLoader<SkyboxWrappingGeometry<BlockModel>> {
@Override
public SkyboxWrappingGeometry<BlockModel> read(JsonObject jsonObject, JsonDeserializationContext context) throws JsonParseException {
jsonObject.remove("loader");
BlockModel base = context.deserialize(jsonObject, BlockModel.class);
return new SkyboxWrappingGeometry<>(base);
}
}
@@ -0,0 +1,37 @@
package io.github.slimeistdev.crystalline_sky.neoforge.skybox_model;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.client.renderer.block.model.ItemOverrides;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.Material;
import net.minecraft.client.resources.model.ModelBaker;
import net.minecraft.client.resources.model.ModelState;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.client.model.geometry.IGeometryBakingContext;
import net.neoforged.neoforge.client.model.geometry.IUnbakedGeometry;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Objects;
import java.util.function.Function;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class SkyboxWrappingGeometry<T extends UnbakedModel> implements IUnbakedGeometry<SkyboxWrappingGeometry<T>> {
private final T wrapped;
public SkyboxWrappingGeometry(T wrapped) {
this.wrapped = wrapped;
}
@Override
public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelState, ItemOverrides overrides) {
return new SkyboxBakedModel<>(Objects.requireNonNull(wrapped.bake(baker, spriteGetter, modelState)));
}
@Override
public void resolveParents(Function<ResourceLocation, UnbakedModel> modelGetter, IGeometryBakingContext context) {
wrapped.resolveParents(modelGetter);
}
}