diff --git a/build.gradle b/build.gradle index d16ee74b7..f216a5668 100644 --- a/build.gradle +++ b/build.gradle @@ -135,12 +135,12 @@ dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" jarJar('org.joml:joml:1.10.5') { - jarJar.ranged(it, '[1.10.0,1.11.0)') + jarJar.ranged(it, '[1.10.5,1.11.0)') } library 'org.joml:joml:1.10.5' jarJar('com.dreizak:miniball:1.0.3') { - jarJar.ranged(it, '[1.0,2.0)') + jarJar.ranged(it, '[1.0.3,2.0.0)') } library 'com.dreizak:miniball:1.0.3' diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 145d5f661..8a61064ab 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -1,8 +1,11 @@ package com.jozufozu.flywheel; +import java.util.ArrayList; + import org.apache.maven.artifact.versioning.ArtifactVersion; import org.slf4j.Logger; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.backend.Backends; import com.jozufozu.flywheel.backend.Loader; import com.jozufozu.flywheel.backend.compile.Pipelines; @@ -11,29 +14,34 @@ import com.jozufozu.flywheel.backend.engine.batching.DrawBuffer; import com.jozufozu.flywheel.config.BackendArgument; import com.jozufozu.flywheel.config.FlwCommands; import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.handler.EntityWorldHandler; -import com.jozufozu.flywheel.handler.ForgeEvents; import com.jozufozu.flywheel.impl.BackendManagerImpl; import com.jozufozu.flywheel.impl.IdRegistryImpl; import com.jozufozu.flywheel.impl.RegistryImpl; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; +import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler; import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.instance.InstanceTypes; +import com.jozufozu.flywheel.lib.light.LightUpdater; import com.jozufozu.flywheel.lib.material.MaterialIndices; import com.jozufozu.flywheel.lib.material.Materials; +import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; import com.jozufozu.flywheel.lib.model.Models; -import com.jozufozu.flywheel.lib.model.PartialModel; +import com.jozufozu.flywheel.lib.model.baked.PartialModel; +import com.jozufozu.flywheel.lib.util.LevelAttached; import com.jozufozu.flywheel.lib.util.ShadersModHandler; +import com.jozufozu.flywheel.lib.util.StringUtil; import com.jozufozu.flywheel.lib.vertex.VertexTypes; -import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; import com.jozufozu.flywheel.vanilla.VanillaVisuals; import com.mojang.logging.LogUtils; +import net.minecraft.client.Minecraft; import net.minecraft.commands.synchronization.ArgumentTypes; import net.minecraft.commands.synchronization.EmptyArgumentSerializer; +import net.minecraft.core.Vec3i; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.IExtensionPoint; @@ -73,24 +81,24 @@ public class Flywheel { } private static void clientInit(IEventBus forgeEventBus, IEventBus modEventBus) { - forgeEventBus.addListener(FlwCommands::registerClientCommands); + forgeEventBus.addListener(Flywheel::addDebugInfo); forgeEventBus.addListener(BackendManagerImpl::onReloadRenderers); - forgeEventBus.addListener(Models::onReloadRenderers); + forgeEventBus.addListener(VisualizationEventHandler::onClientTick); + forgeEventBus.addListener(VisualizationEventHandler::onBeginFrame); + forgeEventBus.addListener(VisualizationEventHandler::onRenderStage); + forgeEventBus.addListener(VisualizationEventHandler::onEntityJoinWorld); + forgeEventBus.addListener(VisualizationEventHandler::onEntityLeaveWorld); + + forgeEventBus.addListener(FlwCommands::registerClientCommands); + forgeEventBus.addListener(DrawBuffer::onReloadRenderers); forgeEventBus.addListener(UniformBuffer::onReloadRenderers); - forgeEventBus.addListener(VisualizedRenderDispatcher::onRenderStage); - forgeEventBus.addListener(VisualizedRenderDispatcher::onBeginFrame); - forgeEventBus.addListener(VisualizedRenderDispatcher::tick); - - forgeEventBus.addListener(EntityWorldHandler::onEntityJoinWorld); - forgeEventBus.addListener(EntityWorldHandler::onEntityLeaveWorld); - - forgeEventBus.addListener(ForgeEvents::addToDebugScreen); - forgeEventBus.addListener(ForgeEvents::unloadWorld); - forgeEventBus.addListener(ForgeEvents::tickLight); + forgeEventBus.addListener(LightUpdater::onClientTick); + forgeEventBus.addListener(Models::onReloadRenderers); + forgeEventBus.addListener((WorldEvent.Unload e) -> LevelAttached.onUnloadLevel(e)); modEventBus.addListener(PartialModel::onModelRegistry); modEventBus.addListener(PartialModel::onModelBake); @@ -114,13 +122,6 @@ public class Flywheel { MaterialIndices.init(); VanillaVisuals.init(); - - // https://github.com/Jozufozu/Flywheel/issues/69 - // Weird issue with accessor loading. - // Only thing I've seen that's close to a fix is to force the class to load before trying to use it. - // From the SpongePowered discord: - // https://discord.com/channels/142425412096491520/626802111455297538/675007581168599041 - LOGGER.debug("Successfully loaded {}", PausedPartialTickAccessor.class.getName()); } private static void setup(final FMLCommonSetupEvent event) { @@ -130,6 +131,30 @@ public class Flywheel { ArgumentTypes.register(rl("backend").toString(), BackendArgument.class, new EmptyArgumentSerializer<>(() -> BackendArgument.INSTANCE)); } + private static void addDebugInfo(RenderGameOverlayEvent.Text event) { + Minecraft mc = Minecraft.getInstance(); + if (!mc.options.renderDebug) { + return; + } + + ArrayList info = event.getRight(); + info.add(""); + info.add("Flywheel: " + getVersion()); + info.add("Backend: " + BackendManagerImpl.getBackendString()); + info.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); + + VisualizationManager manager = VisualizationManager.get(mc.level); + if (manager != null) { + info.add("B: " + manager.getBlockEntities().getVisualCount() + + ", E: " + manager.getEntities().getVisualCount() + + ", F: " + manager.getEffects().getVisualCount()); + Vec3i renderOrigin = manager.getRenderOrigin(); + info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); + } + + info.add("Memory Usage: CPU: " + StringUtil.formatBytes(FlwMemoryTracker.getCPUMemory()) + ", GPU: " + StringUtil.formatBytes(FlwMemoryTracker.getGPUMemory())); + } + public static ArtifactVersion getVersion() { return version; } diff --git a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java index b59b3cd2c..bdce50a09 100644 --- a/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java +++ b/src/main/java/com/jozufozu/flywheel/api/backend/Engine.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.api.backend; -import java.util.List; - import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.InstancerProvider; @@ -26,7 +24,7 @@ public interface Engine extends InstancerProvider { Vec3i renderOrigin(); - void addDebugInfo(List info); - + // TODO: "delete" implies that the object cannot be used afterwards, but all current implementations + // support the "invalidate" contract as well, meaning they can be reused after this call. Rename? void delete(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java b/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java index dd58926ab..10a1491e1 100644 --- a/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/event/RenderContext.java @@ -9,11 +9,11 @@ import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.RenderBuffers; public record RenderContext(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, - Matrix4f projection, Matrix4f viewProjection, Camera camera) { - public static RenderContext create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, Matrix4f projection, Camera camera) { + Matrix4f projection, Matrix4f viewProjection, Camera camera, float partialTick) { + public static RenderContext create(LevelRenderer renderer, ClientLevel level, RenderBuffers buffers, PoseStack stack, Matrix4f projection, Camera camera, float partialTick) { Matrix4f viewProjection = projection.copy(); viewProjection.multiply(stack.last().pose()); - return new RenderContext(renderer, level, buffers, stack, projection, viewProjection, camera); + return new RenderContext(renderer, level, buffers, stack, projection, viewProjection, camera, partialTick); } } diff --git a/src/main/java/com/jozufozu/flywheel/api/material/Material.java b/src/main/java/com/jozufozu/flywheel/api/material/Material.java index 5a666eaff..b58ef0d1d 100644 --- a/src/main/java/com/jozufozu/flywheel/api/material/Material.java +++ b/src/main/java/com/jozufozu/flywheel/api/material/Material.java @@ -17,7 +17,7 @@ public interface Material { void clear(); - RenderType getBatchingRenderType(); + RenderType getFallbackRenderType(); MaterialVertexTransformer getVertexTransformer(); } diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/Effect.java b/src/main/java/com/jozufozu/flywheel/api/visual/Effect.java index bcab669fa..611fbabb1 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/Effect.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/Effect.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.api.visual; import com.jozufozu.flywheel.api.visualization.VisualizationContext; +// TODO: Consider adding LevelAccessor getter public interface Effect { EffectVisual visualize(VisualizationContext ctx); } diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/PlannedVisual.java b/src/main/java/com/jozufozu/flywheel/api/visual/PlannedVisual.java index 0168a4c63..c9c44fffc 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/PlannedVisual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/PlannedVisual.java @@ -5,8 +5,6 @@ import com.jozufozu.flywheel.lib.task.UnitPlan; /** * An interface giving {@link Visual}s a way to define complex, parallelized update plans. - *

- * Plans allow for */ public interface PlannedVisual extends Visual { default Plan planFrame() { diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java b/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java index b38dc666a..52233438e 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/Visual.java @@ -10,14 +10,14 @@ public interface Visual { /** * Initialize instances here. */ - void init(); + void init(float partialTick); /** * Update instances here. Good for when instances don't change very often and when animations are GPU based. * *

If your animations are complex or more CPU driven, see {@link DynamicVisual} or {@link TickableVisual}. */ - void update(); + void update(float partialTick); /** * When a visual is reset, the visual is deleted and re-created. diff --git a/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java b/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java index 6778a84b3..dc0011b3b 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java +++ b/src/main/java/com/jozufozu/flywheel/api/visual/VisualFrameContext.java @@ -3,5 +3,5 @@ package com.jozufozu.flywheel.api.visual; import org.joml.FrustumIntersection; public record VisualFrameContext(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum, - DistanceUpdateLimiter limiter) { + float partialTick, DistanceUpdateLimiter limiter) { } diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualManager.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualManager.java new file mode 100644 index 000000000..36b398b7e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualManager.java @@ -0,0 +1,16 @@ +package com.jozufozu.flywheel.api.visualization; + +public interface VisualManager { + /** + * Get the number of game objects that are currently being visualized. + * + * @return The visual count. + */ + int getVisualCount(); + + void queueAdd(T obj); + + void queueRemove(T obj); + + void queueUpdate(T obj); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/FlywheelLevel.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationLevel.java similarity index 59% rename from src/main/java/com/jozufozu/flywheel/api/FlywheelLevel.java rename to src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationLevel.java index de4e0c3ed..6339cbad9 100644 --- a/src/main/java/com/jozufozu/flywheel/api/FlywheelLevel.java +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationLevel.java @@ -1,4 +1,6 @@ -package com.jozufozu.flywheel.api; +package com.jozufozu.flywheel.api.visualization; + +import net.minecraft.world.level.LevelAccessor; /** * A marker interface custom levels can override to indicate @@ -7,8 +9,8 @@ package com.jozufozu.flywheel.api; * * {@link net.minecraft.client.Minecraft#level Minecraft#level} is special cased and will support Flywheel by default. */ -public interface FlywheelLevel { - default boolean supportsFlywheel() { +public interface VisualizationLevel extends LevelAccessor { + default boolean supportsVisualization() { return true; } } diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationManager.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationManager.java new file mode 100644 index 000000000..8463949ee --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizationManager.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.api.visualization; + +import org.jetbrains.annotations.Nullable; + +import com.jozufozu.flywheel.api.visual.Effect; +import com.jozufozu.flywheel.api.visual.Visual; +import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl; + +import net.minecraft.core.Vec3i; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; + +public interface VisualizationManager { + static boolean supportsVisualization(@Nullable LevelAccessor level) { + return VisualizationManagerImpl.supportsVisualization(level); + } + + @Nullable + static VisualizationManager get(@Nullable LevelAccessor level) { + return VisualizationManagerImpl.get(level); + } + + static VisualizationManager getOrThrow(@Nullable LevelAccessor level) { + return VisualizationManagerImpl.getOrThrow(level); + } + + /** + * Call this when you want to run {@link Visual#update()}. + * @param blockEntity The block entity whose visual you want to update. + */ + static void queueUpdate(BlockEntity blockEntity) { + Level level = blockEntity.getLevel(); + VisualizationManager manager = get(level); + if (manager == null) { + return; + } + + manager.getBlockEntities().queueUpdate(blockEntity); + } + + /** + * Call this when you want to run {@link Visual#update()}. + * @param entity The entity whose visual you want to update. + */ + static void queueUpdate(Entity entity) { + Level level = entity.level; + VisualizationManager manager = get(level); + if (manager == null) { + return; + } + + manager.getEntities().queueUpdate(entity); + } + + /** + * Call this when you want to run {@link Visual#update()}. + * @param effect The effect whose visual you want to update. + */ + static void queueUpdate(LevelAccessor level, Effect effect) { + VisualizationManager manager = get(level); + if (manager == null) { + return; + } + + manager.getEffects().queueUpdate(effect); + } + + Vec3i getRenderOrigin(); + + VisualManager getBlockEntities(); + + VisualManager getEntities(); + + VisualManager getEffects(); +} diff --git a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizerRegistry.java b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizerRegistry.java index 13625526f..3bd1238ad 100644 --- a/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizerRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/api/visualization/VisualizerRegistry.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.api.visualization; import org.jetbrains.annotations.Nullable; -import com.jozufozu.flywheel.impl.VisualizerRegistryImpl; +import com.jozufozu.flywheel.impl.visualization.VisualizerRegistryImpl; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 1a113c117..610864209 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -26,6 +26,9 @@ public class Loader implements ResourceManagerReloadListener { FlwPrograms.reload(manager); // TODO: Move this to the impl package + // TODO: To ensure this runs after all backends are ready, inject into Minecraft after the reload and before levelRenderer.allChanged() + // Alternatively, consider adding API + // TODO: This should reset all VisualizationManagerImpls, not just the one for the static client level BackendManagerImpl.refresh(Minecraft.getInstance().level); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java b/src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java index 6ccfbdddf..a58fd3763 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/Compile.java @@ -6,7 +6,9 @@ import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Function; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.backend.compile.core.ProgramLinker; @@ -16,7 +18,6 @@ import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.SourceComponent; -import com.jozufozu.flywheel.util.NotNullFunction; import net.minecraft.resources.ResourceLocation; @@ -98,11 +99,11 @@ public class Compile { return withComponent($ -> component); } - public ShaderCompilerBuilder withComponent(NotNullFunction sourceFetcher) { + public ShaderCompilerBuilder withComponent(Function sourceFetcher) { return with((key, $) -> sourceFetcher.apply(key)); } - public ShaderCompilerBuilder withResource(NotNullFunction sourceFetcher) { + public ShaderCompilerBuilder withResource(Function sourceFetcher) { return with((key, loader) -> loader.find(sourceFetcher.apply(key))); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/Pipeline.java b/src/main/java/com/jozufozu/flywheel/backend/compile/Pipeline.java index da21f8f53..a8c513f1d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/Pipeline.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/Pipeline.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.compile; import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.backend.compile.Pipeline.InstanceAssembler; import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.SourceComponent; diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/component/StringSubstitutionSourceComponent.java b/src/main/java/com/jozufozu/flywheel/backend/compile/component/StringSubstitutionSourceComponent.java index 66eb668f9..01d91f771 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/component/StringSubstitutionSourceComponent.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/component/StringSubstitutionSourceComponent.java @@ -4,7 +4,7 @@ import java.util.Collection; import java.util.Map; import com.jozufozu.flywheel.glsl.SourceComponent; -import com.jozufozu.flywheel.util.ResourceUtil; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java index 92ec50c1b..a5d4683ce 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/Compilation.java @@ -15,7 +15,7 @@ import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceFile; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilerStats.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilerStats.java index cdaee24fe..3e8f9ed48 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilerStats.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/CompilerStats.java @@ -12,7 +12,7 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.glsl.LoadError; import com.jozufozu.flywheel.glsl.LoadResult; import com.jozufozu.flywheel.glsl.error.ErrorBuilder; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; public class CompilerStats { private long compileStart; diff --git a/src/main/java/com/jozufozu/flywheel/backend/compile/core/FailedCompilation.java b/src/main/java/com/jozufozu/flywheel/backend/compile/core/FailedCompilation.java index 55fbde354..d5b91d2c8 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/compile/core/FailedCompilation.java +++ b/src/main/java/com/jozufozu/flywheel/backend/compile/core/FailedCompilation.java @@ -11,10 +11,10 @@ import org.jetbrains.annotations.NotNull; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceLines; +import com.jozufozu.flywheel.glsl.error.ConsoleColors; import com.jozufozu.flywheel.glsl.error.ErrorBuilder; import com.jozufozu.flywheel.glsl.span.Span; -import com.jozufozu.flywheel.util.ConsoleColors; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java index cd8b93f0a..569f88ed0 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/UniformBuffer.java @@ -11,15 +11,16 @@ import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.gl.buffer.GlBuffer; import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.lib.math.MoreMath; -import com.jozufozu.flywheel.lib.math.RenderMath; import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import net.minecraft.util.Mth; + public class UniformBuffer { private static final int OFFSET_ALIGNMENT = GL32.glGetInteger(GL32.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); private static final int MAX_SIZE = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BLOCK_SIZE); private static final int MAX_BINDINGS = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BUFFER_BINDINGS); - private static final boolean PO2_ALIGNMENT = RenderMath.isPowerOf2(OFFSET_ALIGNMENT); + private static final boolean PO2_ALIGNMENT = Mth.isPowerOfTwo(OFFSET_ALIGNMENT); private static UniformBuffer instance; private final ProviderSet providerSet; diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchContext.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchContext.java index 3e417d66d..1e686803d 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchContext.java @@ -5,7 +5,7 @@ import org.joml.FrustumIntersection; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.lib.math.MatrixUtil; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.FlwUtil; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.multiplayer.ClientLevel; diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java index 7bba67929..671241c24 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/batching/BatchingEngine.java @@ -89,12 +89,6 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan initializedInstancers.clear(); } - @Override - public void addDebugInfo(List info) { - info.add("Batching"); - info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); - } - private void flush() { for (var instancer : uninitializedInstancers) { add(instancer.instancer(), instancer.model(), instancer.stage()); @@ -111,7 +105,7 @@ public class BatchingEngine extends AbstractEngine implements SimplyComposedPlan var meshes = model.getMeshes(); for (var entry : meshes.entrySet()) { var material = entry.getKey(); - RenderType renderType = material.getBatchingRenderType(); + RenderType renderType = material.getFallbackRenderType(); var transformCall = new TransformCall<>(instancer, material, alloc(entry.getValue(), renderType.format())); stagePlan.put(renderType, transformCall); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java index 0235357d9..088264b10 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java @@ -12,7 +12,7 @@ import com.jozufozu.flywheel.api.instance.Instancer; import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.engine.InstancerKey; -import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.lib.util.Pair; public class IndirectDrawManager { private final Map, IndirectInstancer> instancers = new HashMap<>(); @@ -43,7 +43,7 @@ public class IndirectDrawManager { } } - public void delete() { + public void invalidate() { instancers.clear(); renderLists.values() diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java index 4746f7df9..f84a71c06 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.backend.engine.indirect; -import java.util.List; - import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.event.RenderContext; @@ -78,12 +76,6 @@ public class IndirectEngine extends AbstractEngine { @Override public void delete() { - drawManager.delete(); - } - - @Override - public void addDebugInfo(List info) { - info.add("GL46 Indirect"); - info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); + drawManager.invalidate(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/EBOCache.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/EBOCache.java index 66f7cc5f2..1fefedb4c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/EBOCache.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/EBOCache.java @@ -21,7 +21,7 @@ public class EBOCache { private final List quads = new ArrayList<>(); private final Object2ReferenceMap others = new Object2ReferenceOpenHashMap<>(); - public void delete() { + public void invalidate() { quads.forEach(Entry::delete); others.values() .forEach(Entry::delete); diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java index e48d7d816..20d13290a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancedDrawManager.java @@ -57,7 +57,7 @@ public class InstancedDrawManager { } } - public void delete() { + public void invalidate() { instancers.clear(); meshPools.values() @@ -71,7 +71,7 @@ public class InstancedDrawManager { initializedInstancers.forEach(InstancedInstancer::delete); initializedInstancers.clear(); - eboCache.delete(); + eboCache.invalidate(); } public void clearInstancers() { diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java index 04edaca46..a0492528c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/instancing/InstancingEngine.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.backend.engine.instancing; -import java.util.List; - import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.context.Context; @@ -122,12 +120,6 @@ public class InstancingEngine extends AbstractEngine { @Override public void delete() { - drawManager.delete(); - } - - @Override - public void addDebugInfo(List info) { - info.add("GL33 Instanced Arrays"); - info.add("Origin: " + renderOrigin.getX() + ", " + renderOrigin.getY() + ", " + renderOrigin.getZ()); + drawManager.invalidate(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/task/FlwTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/backend/task/FlwTaskExecutor.java deleted file mode 100644 index b88a1be76..000000000 --- a/src/main/java/com/jozufozu/flywheel/backend/task/FlwTaskExecutor.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jozufozu.flywheel.backend.task; - -public class FlwTaskExecutor { - private static ParallelTaskExecutor executor; - - /** - * Get a thread pool for running Flywheel related work in parallel. - * @return A global Flywheel thread pool. - */ - public static ParallelTaskExecutor get() { - if (executor == null) { - executor = new ParallelTaskExecutor("Flywheel"); - executor.startWorkers(); - } - - return executor; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java index cf3248d6b..ddddc224d 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayDSA.java @@ -7,7 +7,7 @@ import org.lwjgl.opengl.GL45C; import org.lwjgl.system.Checks; import com.jozufozu.flywheel.gl.GlCompat; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.FlwUtil; public class GlVertexArrayDSA extends GlVertexArray { public static final boolean SUPPORTED = isSupported(); diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java index a42d8d905..dfbb2f0f6 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArrayGL3.java @@ -12,7 +12,7 @@ import org.lwjgl.system.Checks; import com.jozufozu.flywheel.gl.GlCompat; import com.jozufozu.flywheel.gl.buffer.GlBufferType; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.FlwUtil; public abstract class GlVertexArrayGL3 extends GlVertexArray { private final BitSet attributeDirty = new BitSet(MAX_ATTRIBS); diff --git a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java index 62132c72f..466d73f03 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java +++ b/src/main/java/com/jozufozu/flywheel/gl/array/GlVertexArraySeparateAttributes.java @@ -9,7 +9,7 @@ import org.lwjgl.system.Checks; import com.jozufozu.flywheel.gl.GlCompat; import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.buffer.GlBufferType; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.FlwUtil; public class GlVertexArraySeparateAttributes extends GlVertexArray { public static final boolean SUPPORTED = isSupported(); diff --git a/src/main/java/com/jozufozu/flywheel/gl/shader/GlProgram.java b/src/main/java/com/jozufozu/flywheel/gl/shader/GlProgram.java index 2bb8b4771..400552d0c 100644 --- a/src/main/java/com/jozufozu/flywheel/gl/shader/GlProgram.java +++ b/src/main/java/com/jozufozu/flywheel/gl/shader/GlProgram.java @@ -1,11 +1,11 @@ package com.jozufozu.flywheel.gl.shader; +import static org.lwjgl.opengl.GL20.glDeleteProgram; +import static org.lwjgl.opengl.GL20.glGetUniformLocation; +import static org.lwjgl.opengl.GL20.glUniform1i; import static org.lwjgl.opengl.GL31.GL_INVALID_INDEX; import static org.lwjgl.opengl.GL31.glGetUniformBlockIndex; import static org.lwjgl.opengl.GL31.glUniformBlockBinding; -import static org.lwjgl.opengl.GL32.glDeleteProgram; -import static org.lwjgl.opengl.GL32.glGetUniformLocation; -import static org.lwjgl.opengl.GL32.glUniform1i; import org.slf4j.Logger; diff --git a/src/main/java/com/jozufozu/flywheel/glsl/LoadError.java b/src/main/java/com/jozufozu/flywheel/glsl/LoadError.java index b31de80e5..84d5f7f62 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/LoadError.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/LoadError.java @@ -7,7 +7,7 @@ import java.util.stream.Collectors; import com.jozufozu.flywheel.glsl.error.ErrorBuilder; import com.jozufozu.flywheel.glsl.span.Span; -import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.lib.util.Pair; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/glsl/ShaderSources.java b/src/main/java/com/jozufozu/flywheel/glsl/ShaderSources.java index 0bebd5e4f..2f918a9b0 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/ShaderSources.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/ShaderSources.java @@ -1,6 +1,8 @@ package com.jozufozu.flywheel.glsl; import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashMap; @@ -10,10 +12,10 @@ import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.VisibleForTesting; -import com.jozufozu.flywheel.util.ResourceUtil; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; /** @@ -66,11 +68,9 @@ public class ShaderSources { @NotNull protected LoadResult load(ResourceLocation loc) { - try { - var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc)); - - var sourceString = StringUtil.readToString(resource.getInputStream()); - + try (Resource resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc))) { + InputStream stream = resource.getInputStream(); + String sourceString = new String(stream.readAllBytes(), StandardCharsets.UTF_8); return SourceFile.parse(this, loc, sourceString); } catch (IOException e) { return new LoadResult.Failure(new LoadError.IOError(loc, e)); diff --git a/src/main/java/com/jozufozu/flywheel/glsl/SourceFile.java b/src/main/java/com/jozufozu/flywheel/glsl/SourceFile.java index cafc0a41b..646bcd478 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/SourceFile.java @@ -17,8 +17,8 @@ import com.jozufozu.flywheel.glsl.parse.ShaderFunction; import com.jozufozu.flywheel.glsl.parse.ShaderStruct; import com.jozufozu.flywheel.glsl.span.Span; import com.jozufozu.flywheel.glsl.span.StringSpan; -import com.jozufozu.flywheel.util.Pair; -import com.jozufozu.flywheel.util.ResourceUtil; +import com.jozufozu.flywheel.lib.util.Pair; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java b/src/main/java/com/jozufozu/flywheel/glsl/error/ConsoleColors.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java rename to src/main/java/com/jozufozu/flywheel/glsl/error/ConsoleColors.java index 9a67f6d00..3325ab15d 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ConsoleColors.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/error/ConsoleColors.java @@ -1,7 +1,7 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.glsl.error; // https://stackoverflow.com/a/45444716 -public class ConsoleColors { +public final class ConsoleColors { // Reset public static final String RESET = "\033[0m"; // Text Reset @@ -74,4 +74,7 @@ public class ConsoleColors { public static final String PURPLE_BACKGROUND_BRIGHT = "\033[0;105m"; // PURPLE public static final String CYAN_BACKGROUND_BRIGHT = "\033[0;106m"; // CYAN public static final String WHITE_BACKGROUND_BRIGHT = "\033[0;107m"; // WHITE + + private ConsoleColors() { + } } diff --git a/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorBuilder.java index c74591f9e..3d813382c 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorBuilder.java @@ -19,8 +19,7 @@ import com.jozufozu.flywheel.glsl.error.lines.SourceLine; import com.jozufozu.flywheel.glsl.error.lines.SpanHighlightLine; import com.jozufozu.flywheel.glsl.error.lines.TextLine; import com.jozufozu.flywheel.glsl.span.Span; -import com.jozufozu.flywheel.util.ConsoleColors; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorLevel.java b/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorLevel.java index 1bbe60c68..130cb3ec0 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorLevel.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/error/ErrorLevel.java @@ -1,7 +1,5 @@ package com.jozufozu.flywheel.glsl.error; -import com.jozufozu.flywheel.util.ConsoleColors; - public enum ErrorLevel { WARN(ConsoleColors.YELLOW, "warn"), ERROR(ConsoleColors.RED, "error"), diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/FnSignature.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/FnSignature.java index d94bc6c1c..a23cf92b3 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/FnSignature.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/FnSignature.java @@ -4,7 +4,7 @@ import java.util.Collection; import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; -import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.lib.util.Pair; public record FnSignature(String returnType, String name, ImmutableList> args) { diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java index e17431e2d..360588cbd 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslFn.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.glsl.generate; import java.util.function.Consumer; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; public class GlslFn implements GlslBuilder.Declaration { private final GlslBlock body = new GlslBlock(); diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslStruct.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslStruct.java index f78663eaa..c04811687 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslStruct.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslStruct.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import com.jozufozu.flywheel.util.Pair; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.Pair; +import com.jozufozu.flywheel.lib.util.StringUtil; public class GlslStruct implements GlslBuilder.Declaration { diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslSwitch.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslSwitch.java index a8e6ad8d4..6c3e0da93 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslSwitch.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslSwitch.java @@ -6,8 +6,8 @@ import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; -import com.jozufozu.flywheel.util.Pair; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.Pair; +import com.jozufozu.flywheel.lib.util.StringUtil; public class GlslSwitch implements GlslStmt { diff --git a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslUniformBlock.java b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslUniformBlock.java index c0a4026a5..420392215 100644 --- a/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslUniformBlock.java +++ b/src/main/java/com/jozufozu/flywheel/glsl/generate/GlslUniformBlock.java @@ -4,8 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import com.jozufozu.flywheel.util.Pair; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.Pair; +import com.jozufozu.flywheel.lib.util.StringUtil; public class GlslUniformBlock implements GlslBuilder.Declaration { private String qualifier; diff --git a/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java b/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java deleted file mode 100644 index 035b3b4bb..000000000 --- a/src/main/java/com/jozufozu/flywheel/handler/EntityWorldHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jozufozu.flywheel.handler; - -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; -import com.jozufozu.flywheel.util.FlwUtil; - -import net.minecraft.world.level.Level; -import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.event.entity.EntityLeaveWorldEvent; - -public class EntityWorldHandler { - public static void onEntityJoinWorld(EntityJoinWorldEvent event) { - Level level = event.getWorld(); - if (!level.isClientSide) { - return; - } - - if (FlwUtil.canUseVisualization(level)) { - VisualizedRenderDispatcher.getEntities(level) - .queueAdd(event.getEntity()); - } - } - - public static void onEntityLeaveWorld(EntityLeaveWorldEvent event) { - Level level = event.getWorld(); - if (!level.isClientSide) { - return; - } - - if (FlwUtil.canUseVisualization(level)) { - VisualizedRenderDispatcher.getEntities(level) - .queueRemove(event.getEntity()); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java b/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java deleted file mode 100644 index e15e67ecd..000000000 --- a/src/main/java/com/jozufozu/flywheel/handler/ForgeEvents.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jozufozu.flywheel.handler; - -import java.util.ArrayList; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; -import com.jozufozu.flywheel.lib.light.LightUpdater; -import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; -import com.jozufozu.flywheel.util.FlwUtil; -import com.jozufozu.flywheel.util.StringUtil; -import com.jozufozu.flywheel.util.WorldAttached; - -import net.minecraft.client.Minecraft; -import net.minecraftforge.client.event.RenderGameOverlayEvent; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.world.WorldEvent; - -public class ForgeEvents { - public static void addToDebugScreen(RenderGameOverlayEvent.Text event) { - if (Minecraft.getInstance().options.renderDebug) { - ArrayList debug = event.getRight(); - debug.add(""); - debug.add("Flywheel: " + Flywheel.getVersion()); - - VisualizedRenderDispatcher.addDebugInfo(debug); - - debug.add("Memory Usage: CPU: " + StringUtil.formatBytes(FlwMemoryTracker.getCPUMemory()) + ", GPU: " + StringUtil.formatBytes(FlwMemoryTracker.getGPUMemory())); - } - } - - public static void unloadWorld(WorldEvent.Unload event) { - WorldAttached.invalidateWorld(event.getWorld()); - } - - public static void tickLight(TickEvent.ClientTickEvent event) { - if (event.phase == TickEvent.Phase.END && FlwUtil.isGameActive()) { - LightUpdater.get(Minecraft.getInstance().level) - .tick(); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java b/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java index 2a438211b..e0d4202f8 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/BackendManagerImpl.java @@ -8,13 +8,14 @@ import com.jozufozu.flywheel.api.backend.Backend; import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; import com.jozufozu.flywheel.backend.Backends; import com.jozufozu.flywheel.config.FlwConfig; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; +import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl; import com.jozufozu.flywheel.lib.backend.SimpleBackend; import com.mojang.logging.LogUtils; import net.minecraft.ChatFormatting; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; import net.minecraftforge.fml.CrashReportCallables; public final class BackendManagerImpl { @@ -23,7 +24,7 @@ public final class BackendManagerImpl { private static final Backend OFF_BACKEND = SimpleBackend.builder() .engineMessage(new TextComponent("Disabled Flywheel").withStyle(ChatFormatting.RED)) .engineFactory(level -> { - throw new IllegalStateException("Cannot create engine when backend is off."); + throw new UnsupportedOperationException("Cannot create engine when backend is off."); }) .supported(() -> true) .register(Flywheel.rl("off")); @@ -32,6 +33,9 @@ public final class BackendManagerImpl { private static Backend backend = OFF_BACKEND; + private BackendManagerImpl() { + } + public static Backend getBackend() { return backend; } @@ -62,7 +66,7 @@ public final class BackendManagerImpl { backend = chooseBackend(); if (level != null) { - VisualizedRenderDispatcher.resetVisualWorld(level); + VisualizationManagerImpl.reset(level); } } @@ -77,16 +81,15 @@ public final class BackendManagerImpl { return actual; } - public static void init() { - CrashReportCallables.registerCrashCallable("Flywheel Backend", () -> { - var backendId = Backend.REGISTRY.getId(backend); - if (backendId == null) { - return "Unregistered"; - } - return backendId.toString(); - }); + public static String getBackendString() { + ResourceLocation backendId = Backend.REGISTRY.getId(backend); + if (backendId == null) { + return "[unregistered]"; + } + return backendId.toString(); } - private BackendManagerImpl() { + public static void init() { + CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString); } } diff --git a/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java new file mode 100644 index 000000000..73c33d00f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/task/FlwTaskExecutor.java @@ -0,0 +1,29 @@ +package com.jozufozu.flywheel.impl.task; + +import org.apache.commons.lang3.concurrent.AtomicSafeInitializer; +import org.apache.commons.lang3.concurrent.ConcurrentUtils; + +public final class FlwTaskExecutor { + // TODO: system property to use SerialTaskExecutor + private static final Initializer INITIALIZER = new Initializer(); + + private FlwTaskExecutor() { + } + + /** + * Get a thread pool for running Flywheel related work in parallel. + * @return A global Flywheel thread pool. + */ + public static ParallelTaskExecutor get() { + return ConcurrentUtils.initializeUnchecked(INITIALIZER); + } + + private static class Initializer extends AtomicSafeInitializer { + @Override + protected ParallelTaskExecutor initialize() { + ParallelTaskExecutor executor = new ParallelTaskExecutor("Flywheel"); + executor.startWorkers(); + return executor; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/task/ParallelTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/impl/task/ParallelTaskExecutor.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/backend/task/ParallelTaskExecutor.java rename to src/main/java/com/jozufozu/flywheel/impl/task/ParallelTaskExecutor.java index bfc6aa064..99e80d0ae 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/task/ParallelTaskExecutor.java +++ b/src/main/java/com/jozufozu/flywheel/impl/task/ParallelTaskExecutor.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.task; +package com.jozufozu.flywheel.impl.task; import java.util.ArrayList; import java.util.Deque; @@ -13,8 +13,6 @@ import org.slf4j.Logger; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.task.TaskExecutor; -import com.jozufozu.flywheel.lib.task.ThreadGroupNotifier; -import com.jozufozu.flywheel.lib.task.WaitGroup; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.logging.LogUtils; diff --git a/src/main/java/com/jozufozu/flywheel/backend/task/SerialTaskExecutor.java b/src/main/java/com/jozufozu/flywheel/impl/task/SerialTaskExecutor.java similarity index 91% rename from src/main/java/com/jozufozu/flywheel/backend/task/SerialTaskExecutor.java rename to src/main/java/com/jozufozu/flywheel/impl/task/SerialTaskExecutor.java index f7730b406..e5098a2b1 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/task/SerialTaskExecutor.java +++ b/src/main/java/com/jozufozu/flywheel/impl/task/SerialTaskExecutor.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.backend.task; +package com.jozufozu.flywheel.impl.task; import com.jozufozu.flywheel.api.task.TaskExecutor; diff --git a/src/main/java/com/jozufozu/flywheel/lib/task/ThreadGroupNotifier.java b/src/main/java/com/jozufozu/flywheel/impl/task/ThreadGroupNotifier.java similarity index 89% rename from src/main/java/com/jozufozu/flywheel/lib/task/ThreadGroupNotifier.java rename to src/main/java/com/jozufozu/flywheel/impl/task/ThreadGroupNotifier.java index c3542ade9..03c79124a 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/task/ThreadGroupNotifier.java +++ b/src/main/java/com/jozufozu/flywheel/impl/task/ThreadGroupNotifier.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.task; +package com.jozufozu.flywheel.impl.task; /** * Thin wrapper around Java's built-in object synchronization primitives. diff --git a/src/main/java/com/jozufozu/flywheel/lib/task/WaitGroup.java b/src/main/java/com/jozufozu/flywheel/impl/task/WaitGroup.java similarity index 87% rename from src/main/java/com/jozufozu/flywheel/lib/task/WaitGroup.java rename to src/main/java/com/jozufozu/flywheel/impl/task/WaitGroup.java index 793932fc0..4c27d960c 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/task/WaitGroup.java +++ b/src/main/java/com/jozufozu/flywheel/impl/task/WaitGroup.java @@ -1,15 +1,10 @@ -package com.jozufozu.flywheel.lib.task; +package com.jozufozu.flywheel.impl.task; import java.util.concurrent.atomic.AtomicInteger; -import org.slf4j.Logger; - import com.google.common.base.Preconditions; -import com.mojang.logging.LogUtils; public class WaitGroup { - private static final Logger LOGGER = LogUtils.getLogger(); - private final AtomicInteger counter = new AtomicInteger(0); public void add() { diff --git a/src/main/java/com/jozufozu/flywheel/impl/vertex/InferredVertexListProviderImpl.java b/src/main/java/com/jozufozu/flywheel/impl/vertex/InferredVertexListProviderImpl.java index 186cd628a..33a6a92d8 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/vertex/InferredVertexListProviderImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/vertex/InferredVertexListProviderImpl.java @@ -5,11 +5,9 @@ import com.jozufozu.flywheel.api.vertex.VertexListProvider; import com.mojang.blaze3d.vertex.VertexFormat; public class InferredVertexListProviderImpl implements VertexListProvider { - private final VertexFormat format; private final InferredVertexFormatInfo formatInfo; public InferredVertexListProviderImpl(VertexFormat format) { - this.format = format; formatInfo = new InferredVertexFormatInfo(format); } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/FrameContext.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/FrameContext.java index b3dd3ef6d..8f61ae1c5 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/FrameContext.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/FrameContext.java @@ -2,5 +2,5 @@ package com.jozufozu.flywheel.impl.visualization; import org.joml.FrustumIntersection; -public record FrameContext(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum) { +public record FrameContext(double cameraX, double cameraY, double cameraZ, FrustumIntersection frustum, float partialTick) { } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationEventHandler.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationEventHandler.java new file mode 100644 index 000000000..64a89b977 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationEventHandler.java @@ -0,0 +1,87 @@ +package com.jozufozu.flywheel.impl.visualization; + +import com.jozufozu.flywheel.api.event.BeginFrameEvent; +import com.jozufozu.flywheel.api.event.RenderStageEvent; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; +import com.jozufozu.flywheel.lib.util.FlwUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.EntityLeaveWorldEvent; + +public final class VisualizationEventHandler { + private VisualizationEventHandler() { + } + + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END || !FlwUtil.isGameActive()) { + return; + } + + Minecraft mc = Minecraft.getInstance(); + if (mc.isPaused()) { + return; + } + + Entity cameraEntity = mc.getCameraEntity() == null ? mc.player : mc.getCameraEntity(); + if (cameraEntity == null) { + return; + } + + Level level = cameraEntity.level; + VisualizationManagerImpl manager = VisualizationManagerImpl.get(level); + if (manager == null) { + return; + } + + double cameraX = cameraEntity.getX(); + double cameraY = cameraEntity.getEyeY(); + double cameraZ = cameraEntity.getZ(); + + manager.tick(cameraX, cameraY, cameraZ); + } + + public static void onBeginFrame(BeginFrameEvent event) { + ClientLevel level = event.getContext().level(); + VisualizationManagerImpl manager = VisualizationManagerImpl.get(level); + if (manager == null) { + return; + } + + manager.beginFrame(event.getContext()); + } + + public static void onRenderStage(RenderStageEvent event) { + ClientLevel level = event.getContext().level(); + VisualizationManagerImpl manager = VisualizationManagerImpl.get(level); + if (manager == null) { + return; + } + + manager.renderStage(event.getContext(), event.getStage()); + } + + public static void onEntityJoinWorld(EntityJoinWorldEvent event) { + Level level = event.getWorld(); + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { + return; + } + + manager.getEntities().queueAdd(event.getEntity()); + } + + public static void onEntityLeaveWorld(EntityLeaveWorldEvent event) { + Level level = event.getWorld(); + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { + return; + } + + manager.getEntities().queueRemove(event.getEntity()); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationHelper.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationHelper.java index cb0678adf..b5b0c6da4 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationHelper.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationHelper.java @@ -4,14 +4,19 @@ import org.jetbrains.annotations.Nullable; 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.api.visualization.VisualizerRegistry; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; public final class VisualizationHelper { + private VisualizationHelper() { + } + @SuppressWarnings("unchecked") @Nullable public static BlockEntityVisualizer getVisualizer(T blockEntity) { @@ -72,6 +77,20 @@ public final class VisualizationHelper { return visualizer.shouldSkipRender(entity); } - private VisualizationHelper() { + public static boolean tryAddBlockEntity(T blockEntity) { + Level level = blockEntity.getLevel(); + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { + return false; + } + + BlockEntityVisualizer visualizer = getVisualizer(blockEntity); + if (visualizer == null) { + return false; + } + + manager.getBlockEntities().queueAdd(blockEntity); + + return visualizer.shouldSkipRender(blockEntity); } } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualWorld.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java similarity index 55% rename from src/main/java/com/jozufozu/flywheel/impl/visualization/VisualWorld.java rename to src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java index 06bbd3b2a..d54937110 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualWorld.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizationManagerImpl.java @@ -1,7 +1,6 @@ package com.jozufozu.flywheel.impl.visualization; -import java.util.List; - +import org.jetbrains.annotations.Nullable; import org.joml.FrustumIntersection; import com.jozufozu.flywheel.api.backend.BackendManager; @@ -13,42 +12,47 @@ import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.Effect; import com.jozufozu.flywheel.api.visual.TickableVisual; -import com.jozufozu.flywheel.backend.task.FlwTaskExecutor; -import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor; -import com.jozufozu.flywheel.config.FlwCommands; -import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.api.visualization.VisualManager; +import com.jozufozu.flywheel.api.visualization.VisualizationLevel; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; +import com.jozufozu.flywheel.extension.ClientLevelExtension; +import com.jozufozu.flywheel.impl.task.FlwTaskExecutor; +import com.jozufozu.flywheel.impl.task.ParallelTaskExecutor; import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager; import com.jozufozu.flywheel.impl.visualization.manager.EffectVisualManager; import com.jozufozu.flywheel.impl.visualization.manager.EntityVisualManager; -import com.jozufozu.flywheel.impl.visualization.manager.VisualManager; import com.jozufozu.flywheel.lib.math.MatrixUtil; import com.jozufozu.flywheel.lib.task.NestedPlan; import com.jozufozu.flywheel.lib.task.SimplyComposedPlan; -import com.jozufozu.flywheel.util.Unit; +import com.jozufozu.flywheel.lib.util.LevelAttached; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.Vec3i; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.entity.BlockEntity; /** - * A manager class for a single world where instancing is supported. + * A manager class for a single world where visualization is supported. */ -// AutoCloseable is implemented to prevent leaking this object from WorldAttached -public class VisualWorld implements AutoCloseable { +public class VisualizationManagerImpl implements VisualizationManager { + private static final LevelAttached MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete); + private final Engine engine; private final ParallelTaskExecutor taskExecutor; - private final VisualManager blockEntities; - private final VisualManager entities; - private final VisualManager effects; + private final BlockEntityVisualManager blockEntities; + private final EntityVisualManager entities; + private final EffectVisualManager effects; private final Plan tickPlan; private final Plan framePlan; - public VisualWorld(LevelAccessor level) { + private VisualizationManagerImpl(LevelAccessor level) { engine = BackendManager.getBackend() .createEngine(level); + // FIXME: All VisualizationManagerImpls use the same executor so calls like syncPoint and discardAndAwait could adversely impact other active VisualizationManagerImpls taskExecutor = FlwTaskExecutor.get(); blockEntities = new BlockEntityVisualManager(engine); @@ -62,18 +66,74 @@ public class VisualWorld implements AutoCloseable { framePlan = new FramePlan(); } - public Engine getEngine() { - return engine; + public static boolean supportsVisualization(@Nullable LevelAccessor level) { + if (!BackendManager.isOn()) { + return false; + } + + if (level == null) { + return false; + } + + if (!level.isClientSide()) { + return false; + } + + if (level instanceof VisualizationLevel flywheelLevel && flywheelLevel.supportsVisualization()) { + return true; + } + + return level == Minecraft.getInstance().level; } + @Nullable + public static VisualizationManagerImpl get(@Nullable LevelAccessor level) { + if (!supportsVisualization(level)) { + return null; + } + + return MANAGERS.get(level); + } + + public static VisualizationManagerImpl getOrThrow(@Nullable LevelAccessor level) { + if (!supportsVisualization(level)) { + throw new IllegalStateException("Cannot retrieve visualization manager when visualization is not supported by level '" + level + "'!"); + } + + return MANAGERS.get(level); + } + + // TODO: Consider making this reset action reuse the existing added game objects instead of readding them, potentially by keeping the same VisualizationManagerImpl and not fully deleting it + // TODO: Consider changing parameter type to Level since it is also possible to get all entities from it + public static void reset(ClientLevel level) { + MANAGERS.remove(level); + VisualizationManagerImpl manager = get(level); + if (manager == null) { + return; + } + + // Block entities are loaded while chunks are baked. + // Entities are loaded with the level, so when chunks are reloaded they need to be re-added. + ClientLevelExtension.getAllLoadedEntities(level) + .forEach(manager.getEntities()::queueAdd); + } + + @Override + public Vec3i getRenderOrigin() { + return engine.renderOrigin(); + } + + @Override public VisualManager getBlockEntities() { return blockEntities; } + @Override public VisualManager getEntities() { return entities; } + @Override public VisualManager getEffects() { return effects; } @@ -111,16 +171,8 @@ public class VisualWorld implements AutoCloseable { engine.renderStage(taskExecutor, context, stage); } - public void addDebugInfo(List info) { - info.add("B: " + blockEntities.getVisualCount() - + ", E: " + entities.getVisualCount() - + ", F: " + effects.getVisualCount()); - info.add("Update limiting: " + FlwCommands.boolToText(FlwConfig.get().limitUpdates()).getString()); - engine.addDebugInfo(info); - } - /** - * Free all acquired resources and invalidate this visual world. + * Free all acquired resources and delete this manager. */ public void delete() { taskExecutor.discardAndAwait(); @@ -130,13 +182,8 @@ public class VisualWorld implements AutoCloseable { engine.delete(); } - @Override - public void close() { - delete(); - } - private class FramePlan implements SimplyComposedPlan { - private final Plan recreationPlan = NestedPlan.of(blockEntities.createRecreationPlan(), entities.createRecreationPlan(), effects.createRecreationPlan()); + private final Plan recreationPlan = NestedPlan.of(blockEntities.createRecreationPlan(), entities.createRecreationPlan(), effects.createRecreationPlan()); private final Plan normalPlan = blockEntities.createFramePlan() .and(entities.createFramePlan()) .and(effects.createFramePlan()); @@ -146,9 +193,10 @@ public class VisualWorld implements AutoCloseable { @Override public void execute(TaskExecutor taskExecutor, RenderContext context, Runnable onCompletion) { Runnable then = () -> enginePlan.execute(taskExecutor, context, onCompletion); + float partialTick = context.partialTick(); if (engine.updateRenderOrigin(context.camera())) { - recreationPlan.execute(taskExecutor, Unit.INSTANCE, then); + recreationPlan.execute(taskExecutor, partialTick, then); } else { Vec3i renderOrigin = engine.renderOrigin(); var cameraPos = context.camera() @@ -161,7 +209,7 @@ public class VisualWorld implements AutoCloseable { proj.translate((float) (renderOrigin.getX() - cameraX), (float) (renderOrigin.getY() - cameraY), (float) (renderOrigin.getZ() - cameraZ)); FrustumIntersection frustum = new FrustumIntersection(proj); - var frameContext = new FrameContext(cameraX, cameraY, cameraZ, frustum); + var frameContext = new FrameContext(cameraX, cameraY, cameraZ, frustum, partialTick); normalPlan.execute(taskExecutor, frameContext, then); } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizedRenderDispatcher.java deleted file mode 100644 index 7345fd775..000000000 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizedRenderDispatcher.java +++ /dev/null @@ -1,191 +0,0 @@ -package com.jozufozu.flywheel.impl.visualization; - -import java.util.List; - -import com.jozufozu.flywheel.api.event.BeginFrameEvent; -import com.jozufozu.flywheel.api.event.RenderStageEvent; -import com.jozufozu.flywheel.api.visual.Effect; -import com.jozufozu.flywheel.api.visual.Visual; -import com.jozufozu.flywheel.api.visualization.BlockEntityVisualizer; -import com.jozufozu.flywheel.extension.ClientLevelExtension; -import com.jozufozu.flywheel.impl.visualization.manager.VisualManager; -import com.jozufozu.flywheel.lib.util.AnimationTickHolder; -import com.jozufozu.flywheel.util.FlwUtil; -import com.jozufozu.flywheel.util.WorldAttached; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.core.Vec3i; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraftforge.event.TickEvent; - -public class VisualizedRenderDispatcher { - private static final WorldAttached VISUAL_WORLDS = new WorldAttached<>(VisualWorld::new); - - /** - * Call this when you want to run {@link Visual#update()}. - * @param blockEntity The block entity whose visual you want to update. - */ - public static void queueUpdate(BlockEntity blockEntity) { - if (!(blockEntity.getLevel() instanceof ClientLevel level)) { - return; - } - - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VISUAL_WORLDS.get(level) - .getBlockEntities() - .queueUpdate(blockEntity); - } - - /** - * Call this when you want to run {@link Visual#update()}. - * @param entity The entity whose visual you want to update. - */ - public static void queueUpdate(Entity entity) { - Level level = entity.level; - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VISUAL_WORLDS.get(level) - .getEntities() - .queueUpdate(entity); - } - - /** - * Call this when you want to run {@link Visual#update()}. - * @param effect The effect whose visual you want to update. - */ - public static void queueUpdate(LevelAccessor level, Effect effect) { - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VISUAL_WORLDS.get(level) - .getEffects() - .queueUpdate(effect); - } - - /** - * Get or create the {@link VisualWorld} for the given world. - * @throws IllegalStateException if the backend is off - */ - private static VisualWorld getVisualWorld(LevelAccessor level) { - if (!FlwUtil.canUseVisualization(level)) { - throw new IllegalStateException("Cannot retrieve visual world when backend is off!"); - } - return VISUAL_WORLDS.get(level); - } - - public static VisualManager getBlockEntities(LevelAccessor level) { - return getVisualWorld(level).getBlockEntities(); - } - - public static VisualManager getEntities(LevelAccessor level) { - return getVisualWorld(level).getEntities(); - } - - public static VisualManager getEffects(LevelAccessor level) { - return getVisualWorld(level).getEffects(); - } - - public static Vec3i getRenderOrigin(LevelAccessor level) { - return getVisualWorld(level).getEngine().renderOrigin(); - } - - public static void tick(TickEvent.ClientTickEvent event) { - if (!FlwUtil.isGameActive() || event.phase == TickEvent.Phase.START) { - return; - } - - AnimationTickHolder.tick(); - - Minecraft mc = Minecraft.getInstance(); - if (mc.isPaused()) { - return; - } - - Entity cameraEntity = mc.getCameraEntity() == null ? mc.player : mc.getCameraEntity(); - if (cameraEntity == null) { - return; - } - - Level level = cameraEntity.level; - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - double cameraX = cameraEntity.getX(); - double cameraY = cameraEntity.getEyeY(); - double cameraZ = cameraEntity.getZ(); - - VISUAL_WORLDS.get(level).tick(cameraX, cameraY, cameraZ); - } - - public static void onBeginFrame(BeginFrameEvent event) { - if (!FlwUtil.isGameActive()) { - return; - } - - ClientLevel level = event.getContext().level(); - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VISUAL_WORLDS.get(level).beginFrame(event.getContext()); - } - - public static void onRenderStage(RenderStageEvent event) { - ClientLevel level = event.getContext().level(); - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VISUAL_WORLDS.get(level).renderStage(event.getContext(), event.getStage()); - } - - public static void resetVisualWorld(ClientLevel level) { - VISUAL_WORLDS.remove(level, VisualWorld::delete); - - if (!FlwUtil.canUseVisualization(level)) { - return; - } - - VisualWorld world = VISUAL_WORLDS.get(level); - // Block entities are loaded while chunks are baked. - // Entities are loaded with the level, so when chunks are reloaded they need to be re-added. - ClientLevelExtension.getAllLoadedEntities(level) - .forEach(world.getEntities()::queueAdd); - } - - public static boolean tryAddBlockEntity(T blockEntity) { - Level level = blockEntity.getLevel(); - if (!FlwUtil.canUseVisualization(level)) { - return false; - } - - BlockEntityVisualizer visualizer = VisualizationHelper.getVisualizer(blockEntity); - if (visualizer == null) { - return false; - } - - getBlockEntities(level).queueAdd(blockEntity); - - return visualizer.shouldSkipRender(blockEntity); - } - - public static void addDebugInfo(List info) { - ClientLevel level = Minecraft.getInstance().level; - if (FlwUtil.canUseVisualization(level)) { - VISUAL_WORLDS.get(level).addDebugInfo(info); - } else { - info.add("Disabled"); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/impl/VisualizerRegistryImpl.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizerRegistryImpl.java similarity index 95% rename from src/main/java/com/jozufozu/flywheel/impl/VisualizerRegistryImpl.java rename to src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizerRegistryImpl.java index 00b4876d0..a9fe88a67 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/VisualizerRegistryImpl.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/VisualizerRegistryImpl.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.impl; +package com.jozufozu.flywheel.impl.visualization; import org.jetbrains.annotations.Nullable; @@ -12,7 +12,7 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -//TODO: Add freezing +// TODO: Add freezing @SuppressWarnings("unchecked") public final class VisualizerRegistryImpl { @Nullable diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/VisualManager.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/AbstractVisualManager.java similarity index 83% rename from src/main/java/com/jozufozu/flywheel/impl/visualization/manager/VisualManager.java rename to src/main/java/com/jozufozu/flywheel/impl/visualization/manager/AbstractVisualManager.java index 8b53871dd..1b0bbf5e7 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/VisualManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/AbstractVisualManager.java @@ -6,6 +6,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visual.VisualTickContext; +import com.jozufozu.flywheel.api.visualization.VisualManager; import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.impl.visualization.FrameContext; import com.jozufozu.flywheel.impl.visualization.TickContext; @@ -15,15 +16,14 @@ import com.jozufozu.flywheel.impl.visualization.ratelimit.NonLimiter; import com.jozufozu.flywheel.impl.visualization.storage.Storage; import com.jozufozu.flywheel.impl.visualization.storage.Transaction; import com.jozufozu.flywheel.lib.task.SimplePlan; -import com.jozufozu.flywheel.util.Unit; -public abstract class VisualManager { +public abstract class AbstractVisualManager implements VisualManager { private final Queue> queue = new ConcurrentLinkedQueue<>(); protected DistanceUpdateLimiterImpl tickLimiter; protected DistanceUpdateLimiterImpl frameLimiter; - public VisualManager() { + public AbstractVisualManager() { tickLimiter = createUpdateLimiter(); frameLimiter = createUpdateLimiter(); } @@ -39,15 +39,12 @@ public abstract class VisualManager { } } - /** - * Get the number of game objects that are currently being visualized. - * - * @return The object count. - */ + @Override public int getVisualCount() { return getStorage().getAllVisuals().size(); } + @Override public void queueAdd(T obj) { if (!getStorage().willAccept(obj)) { return; @@ -56,10 +53,12 @@ public abstract class VisualManager { queue.add(Transaction.add(obj)); } + @Override public void queueRemove(T obj) { queue.add(Transaction.remove(obj)); } + @Override public void queueUpdate(T obj) { if (!getStorage().willAccept(obj)) { return; @@ -68,7 +67,7 @@ public abstract class VisualManager { queue.add(Transaction.update(obj)); } - public Plan createRecreationPlan() { + public Plan createRecreationPlan() { return SimplePlan.of(getStorage()::recreateAll); } @@ -76,32 +75,32 @@ public abstract class VisualManager { getStorage().invalidate(); } - protected void processQueue() { + protected void processQueue(float partialTick) { var storage = getStorage(); Transaction transaction; while ((transaction = queue.poll()) != null) { - transaction.apply(storage); + transaction.apply(storage, partialTick); } } public Plan createTickPlan() { return SimplePlan.of(() -> { tickLimiter.tick(); - processQueue(); + processQueue(0); }) .thenMap(this::createVisualTickContext, getStorage().getTickPlan()); } public Plan createFramePlan() { - return SimplePlan.of(() -> { + return SimplePlan.of(context -> { frameLimiter.tick(); - processQueue(); + processQueue(context.partialTick()); }) .thenMap(this::createVisualContext, getStorage().getFramePlan()); } private VisualFrameContext createVisualContext(FrameContext ctx) { - return new VisualFrameContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), ctx.frustum(), frameLimiter); + return new VisualFrameContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), ctx.frustum(), ctx.partialTick(), frameLimiter); } private VisualTickContext createVisualTickContext(TickContext ctx) { diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/BlockEntityVisualManager.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/BlockEntityVisualManager.java index 58a92c49f..91cc4f795 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/BlockEntityVisualManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/BlockEntityVisualManager.java @@ -10,7 +10,6 @@ import com.jozufozu.flywheel.api.visual.Visual; import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.impl.visualization.VisualizationHelper; import com.jozufozu.flywheel.impl.visualization.storage.Storage; -import com.jozufozu.flywheel.util.FlwUtil; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; @@ -19,7 +18,7 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; -public class BlockEntityVisualManager extends VisualManager { +public class BlockEntityVisualManager extends AbstractVisualManager { private final BlockEntityStorage storage; public BlockEntityVisualManager(Engine engine) { @@ -56,7 +55,6 @@ public class BlockEntityVisualManager extends VisualManager { } Level level = blockEntity.getLevel(); - if (level == null) { return false; } @@ -65,15 +63,9 @@ public class BlockEntityVisualManager extends VisualManager { return false; } - if (FlwUtil.isFlywheelLevel(level)) { - BlockPos pos = blockEntity.getBlockPos(); - - BlockGetter existingChunk = level.getChunkForCollisions(pos.getX() >> 4, pos.getZ() >> 4); - - return existingChunk != null; - } - - return false; + BlockPos pos = blockEntity.getBlockPos(); + BlockGetter existingChunk = level.getChunkForCollisions(pos.getX() >> 4, pos.getZ() >> 4); + return existingChunk != null; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EffectVisualManager.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EffectVisualManager.java index 4ddea3dcf..9814578ac 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EffectVisualManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EffectVisualManager.java @@ -6,7 +6,7 @@ import com.jozufozu.flywheel.api.visual.EffectVisual; import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.impl.visualization.storage.Storage; -public class EffectVisualManager extends VisualManager { +public class EffectVisualManager extends AbstractVisualManager { private final EffectStorage storage; public EffectVisualManager(Engine engine) { diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EntityVisualManager.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EntityVisualManager.java index e970e1711..f4b33bb4d 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EntityVisualManager.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/manager/EntityVisualManager.java @@ -7,12 +7,11 @@ import com.jozufozu.flywheel.api.visual.Visual; import com.jozufozu.flywheel.api.visualization.VisualizationContext; import com.jozufozu.flywheel.impl.visualization.VisualizationHelper; import com.jozufozu.flywheel.impl.visualization.storage.Storage; -import com.jozufozu.flywheel.util.FlwUtil; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; -public class EntityVisualManager extends VisualManager { +public class EntityVisualManager extends AbstractVisualManager { private final EntityStorage storage; public EntityVisualManager(Engine engine) { @@ -51,8 +50,7 @@ public class EntityVisualManager extends VisualManager { } Level level = entity.level; - - return FlwUtil.isFlywheelLevel(level); + return level != null; } } } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Storage.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Storage.java index b8c608e89..11b5a16dd 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Storage.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Storage.java @@ -41,11 +41,11 @@ public abstract class Storage { return visuals.values(); } - public void add(T obj) { + public void add(T obj, float partialTick) { Visual visual = visuals.get(obj); if (visual == null) { - create(obj); + create(obj, partialTick); } } @@ -64,7 +64,7 @@ public abstract class Storage { visual.delete(); } - public void update(T obj) { + public void update(T obj, float partialTick) { Visual visual = visuals.get(obj); if (visual == null) { @@ -76,13 +76,13 @@ public abstract class Storage { // delete and re-create the visual. // resetting a visual supersedes updating it. remove(obj); - create(obj); + create(obj, partialTick); } else { - visual.update(); + visual.update(partialTick); } } - public void recreateAll() { + public void recreateAll(float partialTick) { tickableVisuals.clear(); dynamicVisuals.clear(); plannedVisuals.clear(); @@ -92,7 +92,7 @@ public abstract class Storage { Visual out = createRaw(obj); if (out != null) { - setup(out); + setup(out, partialTick); } return out; @@ -110,11 +110,11 @@ public abstract class Storage { visuals.clear(); } - private void create(T obj) { + private void create(T obj, float partialTick) { Visual visual = createRaw(obj); if (visual != null) { - setup(visual); + setup(visual, partialTick); visuals.put(obj, visual); } } @@ -130,8 +130,8 @@ public abstract class Storage { return tickPlan.and(ForEachPlan.of(() -> tickableVisuals, TickableVisual::tick)); } - private void setup(Visual visual) { - visual.init(); + private void setup(Visual visual, float partialTick) { + visual.init(partialTick); if (visual instanceof TickableVisual tickable) { tickableVisuals.add(tickable); diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Transaction.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Transaction.java index f7526e3b9..b50ba0cbd 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Transaction.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/Transaction.java @@ -13,11 +13,11 @@ public record Transaction(T obj, Action action) { return new Transaction<>(obj, Action.UPDATE); } - public void apply(Storage storage) { + public void apply(Storage storage, float partialTick) { switch (action) { - case ADD -> storage.add(obj); + case ADD -> storage.add(obj, partialTick); case REMOVE -> storage.remove(obj); - case UPDATE -> storage.update(obj); + case UPDATE -> storage.update(obj, partialTick); } } } diff --git a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/VisualUpdatePlan.java b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/VisualUpdatePlan.java index 5fe0c8df6..1a222aff6 100644 --- a/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/VisualUpdatePlan.java +++ b/src/main/java/com/jozufozu/flywheel/impl/visualization/storage/VisualUpdatePlan.java @@ -15,6 +15,7 @@ public class VisualUpdatePlan implements SimplyComposedPlan { private final Supplier>> initializer; @Nullable private Plan plan; + private boolean initialized = false; private boolean needsSimplify = true; public VisualUpdatePlan(Supplier>> initializer) { @@ -32,13 +33,21 @@ public class VisualUpdatePlan implements SimplyComposedPlan { } else { this.plan = this.plan.and(plan); } + needsSimplify = true; } @NotNull private Plan updatePlans() { - if (plan == null) { - plan = new NestedPlan<>(initializer.get()).simplify(); + if (!initialized) { + Plan mainPlan = new NestedPlan<>(initializer.get()); + if (plan != null) { + plan = mainPlan.and(plan); + } else { + plan = mainPlan; + } + plan = plan.simplify(); + initialized = true; } else if (needsSimplify) { plan = plan.simplify(); } @@ -49,5 +58,6 @@ public class VisualUpdatePlan implements SimplyComposedPlan { public void clear() { plan = null; + initialized = false; } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/box/ImmutableBox.java b/src/main/java/com/jozufozu/flywheel/lib/box/Box.java similarity index 81% rename from src/main/java/com/jozufozu/flywheel/lib/box/ImmutableBox.java rename to src/main/java/com/jozufozu/flywheel/lib/box/Box.java index 0ed8fbc22..2f96d2e8d 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/box/ImmutableBox.java +++ b/src/main/java/com/jozufozu/flywheel/lib/box/Box.java @@ -1,10 +1,9 @@ package com.jozufozu.flywheel.lib.box; -import static com.jozufozu.flywheel.lib.math.RenderMath.isPowerOf2; - +import net.minecraft.util.Mth; import net.minecraft.world.phys.AABB; -public interface ImmutableBox { +public interface Box { int getMinX(); int getMinY(); @@ -33,16 +32,16 @@ public interface ImmutableBox { return sizeX() * sizeY() * sizeZ(); } - default boolean empty() { + default boolean isEmpty() { // if any dimension has side length 0 this box contains no volume return getMinX() == getMaxX() || getMinY() == getMaxY() || getMinZ() == getMaxZ(); } - default boolean sameAs(ImmutableBox other) { + default boolean sameAs(Box other) { return getMinX() == other.getMinX() && getMinY() == other.getMinY() && getMinZ() == other.getMinZ() && getMaxX() == other.getMaxX() && getMaxY() == other.getMaxY() && getMaxZ() == other.getMaxZ(); } - default boolean sameAs(ImmutableBox other, int margin) { + default boolean sameAs(Box other, int margin) { return getMinX() == other.getMinX() - margin && getMinY() == other.getMinY() - margin && getMinZ() == other.getMinZ() - margin && @@ -60,33 +59,11 @@ public interface ImmutableBox { && getMaxZ() == Math.ceil(other.maxZ); } - default boolean hasPowerOf2Sides() { - // this is only true if all individual side lengths are powers of 2 - return isPowerOf2(volume()); + default boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { + return this.getMinX() < maxX && this.getMaxX() > minX && this.getMinY() < maxY && this.getMaxY() > minY && this.getMinZ() < maxZ && this.getMaxZ() > minZ; } - default MutableBox intersect(ImmutableBox other) { - int minX = Math.max(this.getMinX(), other.getMinX()); - int minY = Math.max(this.getMinY(), other.getMinY()); - int minZ = Math.max(this.getMinZ(), other.getMinZ()); - int maxX = Math.min(this.getMaxX(), other.getMaxX()); - int maxY = Math.min(this.getMaxY(), other.getMaxY()); - int maxZ = Math.min(this.getMaxZ(), other.getMaxZ()); - return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); - } - - default ImmutableBox union(ImmutableBox other) { - int minX = Math.min(this.getMinX(), other.getMinX()); - int minY = Math.min(this.getMinY(), other.getMinY()); - int minZ = Math.min(this.getMinZ(), other.getMinZ()); - int maxX = Math.max(this.getMaxX(), other.getMaxX()); - int maxY = Math.max(this.getMaxY(), other.getMaxY()); - int maxZ = Math.max(this.getMaxZ(), other.getMaxZ()); - return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); - } - - - default boolean intersects(ImmutableBox other) { + default boolean intersects(Box other) { return this.intersects(other.getMinX(), other.getMinY(), other.getMinZ(), other.getMaxX(), other.getMaxY(), other.getMaxZ()); } @@ -99,7 +76,7 @@ public interface ImmutableBox { && z <= getMaxZ(); } - default boolean contains(ImmutableBox other) { + default boolean contains(Box other) { return other.getMinX() >= this.getMinX() && other.getMaxX() <= this.getMaxX() && other.getMinY() >= this.getMinY() @@ -108,26 +85,48 @@ public interface ImmutableBox { && other.getMaxZ() <= this.getMaxZ(); } - default boolean isContainedBy(MutableBox other) { - return other.contains(this); - } - - default boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - return this.getMinX() < maxX && this.getMaxX() > minX && this.getMinY() < maxY && this.getMaxY() > minY && this.getMinZ() < maxZ && this.getMaxZ() > minZ; - } - default void forEachContained(CoordinateConsumer func) { - if (empty()) return; + int minX = getMinX(); + int minY = getMinY(); + int minZ = getMinZ(); + int maxX = getMaxX(); + int maxY = getMaxY(); + int maxZ = getMaxZ(); - for (int x = getMinX(); x < getMaxX(); x++) { - for (int y = getMinY(); y < getMaxY(); y++) { - for (int z = getMinZ(); z < getMaxZ(); z++) { - func.consume(x, y, z); + for (int x = minX; x < maxX; x++) { + for (int y = minY; y < maxY; y++) { + for (int z = minZ; z < maxZ; z++) { + func.accept(x, y, z); } } } } + default boolean hasPowerOf2Sides() { + // this is only true if all individual side lengths are powers of 2 + return Mth.isPowerOfTwo(volume()); + } + + default MutableBox union(Box other) { + int minX = Math.min(this.getMinX(), other.getMinX()); + int minY = Math.min(this.getMinY(), other.getMinY()); + int minZ = Math.min(this.getMinZ(), other.getMinZ()); + int maxX = Math.max(this.getMaxX(), other.getMaxX()); + int maxY = Math.max(this.getMaxY(), other.getMaxY()); + int maxZ = Math.max(this.getMaxZ(), other.getMaxZ()); + return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); + } + + default MutableBox intersect(Box other) { + int minX = Math.max(this.getMinX(), other.getMinX()); + int minY = Math.max(this.getMinY(), other.getMinY()); + int minZ = Math.max(this.getMinZ(), other.getMinZ()); + int maxX = Math.min(this.getMaxX(), other.getMaxX()); + int maxY = Math.min(this.getMaxY(), other.getMaxY()); + int maxZ = Math.min(this.getMaxZ(), other.getMaxZ()); + return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); + } + default AABB toAABB() { return new AABB(getMinX(), getMinY(), getMinZ(), getMaxX(), getMaxY(), getMaxZ()); } @@ -138,6 +137,6 @@ public interface ImmutableBox { @FunctionalInterface interface CoordinateConsumer { - void consume(int x, int y, int z); + void accept(int x, int y, int z); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/box/MutableBox.java b/src/main/java/com/jozufozu/flywheel/lib/box/MutableBox.java index e8300bcb6..b70a675d0 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/box/MutableBox.java +++ b/src/main/java/com/jozufozu/flywheel/lib/box/MutableBox.java @@ -10,13 +10,13 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.Vec3i; import net.minecraft.world.phys.AABB; -public class MutableBox implements ImmutableBox { - private int minX; - private int minY; - private int minZ; - private int maxX; - private int maxY; - private int maxZ; +public class MutableBox implements Box { + protected int minX; + protected int minY; + protected int minZ; + protected int maxX; + protected int maxY; + protected int maxZ; public MutableBox() { } @@ -30,10 +30,6 @@ public class MutableBox implements ImmutableBox { this.maxZ = maxZ; } - public static MutableBox ofRadius(int radius) { - return new MutableBox(-radius, -radius, -radius, radius + 1, radius + 1, radius + 1); - } - public static MutableBox from(AABB aabb) { int minX = (int) Math.floor(aabb.minX); int minY = (int) Math.floor(aabb.minY); @@ -44,25 +40,23 @@ public class MutableBox implements ImmutableBox { return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); } + public static MutableBox from(Vec3i pos) { + return new MutableBox(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1); + } + public static MutableBox from(SectionPos pos) { return new MutableBox(pos.minBlockX(), pos.minBlockY(), pos.minBlockZ(), pos.maxBlockX() + 1, pos.maxBlockY() + 1, pos.maxBlockZ() + 1); } - public static MutableBox from(BlockPos start, BlockPos end) { + public static MutableBox from(Vec3i start, Vec3i end) { return new MutableBox(start.getX(), start.getY(), start.getZ(), end.getX() + 1, end.getY() + 1, end.getZ() + 1); } - public static MutableBox from(BlockPos pos) { - return new MutableBox(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1); + public static MutableBox ofRadius(int radius) { + return new MutableBox(-radius, -radius, -radius, radius + 1, radius + 1, radius + 1); } - public static MutableBox from(int sectionX, int sectionZ) { - int startX = sectionX << 4; - int startZ = sectionZ << 4; - return new MutableBox(startX, 0, startZ, startX + 16, 256, startZ + 16); - } - - public static ImmutableBox containingAll(Collection positions) { + public static Box containingAll(Collection positions) { if (positions.isEmpty()) { return new MutableBox(); } @@ -83,169 +77,6 @@ public class MutableBox implements ImmutableBox { return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); } - public void fixMinMax() { - int minX = Math.min(this.minX, this.maxX); - int minY = Math.min(this.minY, this.maxY); - int minZ = Math.min(this.minZ, this.maxZ); - int maxX = Math.max(this.minX, this.maxX); - int maxY = Math.max(this.minY, this.maxY); - int maxZ = Math.max(this.minZ, this.maxZ); - - this.minX = minX; - this.minY = minY; - this.minZ = minZ; - this.maxX = maxX; - this.maxY = maxY; - this.maxZ = maxZ; - } - - public void translate(Vec3i by) { - translate(by.getX(), by.getY(), by.getZ()); - } - - public void translate(int x, int y, int z) { - minX = minX + x; - maxX = maxX + x; - minY = minY + y; - maxY = maxY + y; - minZ = minZ + z; - maxZ = maxZ + z; - } - - public void mirrorAbout(Direction.Axis axis) { - Vec3i axisVec = Direction.get(Direction.AxisDirection.POSITIVE, axis) - .getNormal(); - int flipX = axisVec.getX() - 1; - int flipY = axisVec.getY() - 1; - int flipZ = axisVec.getZ() - 1; - - int maxX = this.maxX * flipX; - int maxY = this.maxY * flipY; - int maxZ = this.maxZ * flipZ; - this.maxX = this.minX * flipX; - this.maxY = this.minY * flipY; - this.maxZ = this.minZ * flipZ; - this.minX = maxX; - this.minY = maxY; - this.minZ = maxZ; - } - - /** - * Grow this bounding box to have power of 2 side length, scaling from the center. - */ - public void nextPowerOf2Centered() { - int sizeX = sizeX(); - int sizeY = sizeY(); - int sizeZ = sizeZ(); - - int newSizeX = RenderMath.nextPowerOf2(sizeX); - int newSizeY = RenderMath.nextPowerOf2(sizeY); - int newSizeZ = RenderMath.nextPowerOf2(sizeZ); - - int diffX = newSizeX - sizeX; - int diffY = newSizeY - sizeY; - int diffZ = newSizeZ - sizeZ; - - minX = minX - diffX / 2; // floor division for the minimums - minY = minY - diffY / 2; - minZ = minZ - diffZ / 2; - maxX = maxX + (diffX + 1) / 2; // ceiling divison for the maximums - maxY = maxY + (diffY + 1) / 2; - maxZ = maxZ + (diffZ + 1) / 2; - } - - /** - * Grow this bounding box to have power of 2 side lengths, scaling from the minimum coords. - */ - public void nextPowerOf2() { - int sizeX = RenderMath.nextPowerOf2(sizeX()); - int sizeY = RenderMath.nextPowerOf2(sizeY()); - int sizeZ = RenderMath.nextPowerOf2(sizeZ()); - - maxX = minX + sizeX; - maxY = minY + sizeY; - maxZ = minZ + sizeZ; - } - - public void grow(int s) { - this.grow(s, s, s); - } - - public void grow(int x, int y, int z) { - minX = minX - x; - minY = minY - y; - minZ = minZ - z; - maxX = maxX + x; - maxY = maxY + y; - maxZ = maxZ + z; - } - - public void intersectAssign(ImmutableBox other) { - minX = Math.max(this.minX, other.getMinX()); - minY = Math.max(this.minY, other.getMinY()); - minZ = Math.max(this.minZ, other.getMinZ()); - maxX = Math.min(this.maxX, other.getMaxX()); - maxY = Math.min(this.maxY, other.getMaxY()); - maxZ = Math.min(this.maxZ, other.getMaxZ()); - } - - public void unionAssign(ImmutableBox other) { - minX = Math.min(this.minX, other.getMinX()); - minY = Math.min(this.minY, other.getMinY()); - minZ = Math.min(this.minZ, other.getMinZ()); - maxX = Math.max(this.maxX, other.getMaxX()); - maxY = Math.max(this.maxY, other.getMaxY()); - maxZ = Math.max(this.maxZ, other.getMaxZ()); - } - - public void unionAssign(AABB other) { - minX = Math.min(this.minX, (int) Math.floor(other.minX)); - minY = Math.min(this.minY, (int) Math.floor(other.minY)); - minZ = Math.min(this.minZ, (int) Math.floor(other.minZ)); - maxX = Math.max(this.maxX, (int) Math.ceil(other.maxX)); - maxY = Math.max(this.maxY, (int) Math.ceil(other.maxY)); - maxZ = Math.max(this.maxZ, (int) Math.ceil(other.maxZ)); - } - - public void assign(AABB other) { - minX = (int) Math.floor(other.minX); - minY = (int) Math.floor(other.minY); - minZ = (int) Math.floor(other.minZ); - maxX = (int) Math.ceil(other.maxX); - maxY = (int) Math.ceil(other.maxY); - maxZ = (int) Math.ceil(other.maxZ); - } - - public void assign(ImmutableBox other) { - minX = other.getMinX(); - minY = other.getMinY(); - minZ = other.getMinZ(); - maxX = other.getMaxX(); - maxY = other.getMaxY(); - maxZ = other.getMaxZ(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ImmutableBox that = (ImmutableBox) o; - - return this.sameAs(that); - } - - @Override - public int hashCode() { - int result = getMinX(); - result = 31 * result + getMinY(); - result = 31 * result + getMinZ(); - result = 31 * result + getMaxX(); - result = 31 * result + getMaxY(); - result = 31 * result + getMaxZ(); - return result; - } - @Override public int getMinX() { return minX; @@ -276,14 +107,12 @@ public class MutableBox implements ImmutableBox { return maxZ; } - public MutableBox setMinX(int minX) { + public void setMinX(int minX) { this.minX = minX; - return this; } - public MutableBox setMinY(int minY) { + public void setMinY(int minY) { this.minY = minY; - return this; } public MutableBox setMinZ(int minZ) { @@ -291,142 +120,207 @@ public class MutableBox implements ImmutableBox { return this; } - public MutableBox setMaxX(int maxX) { + public void setMaxX(int maxX) { this.maxX = maxX; - return this; } - public MutableBox setMaxY(int maxY) { + public void setMaxY(int maxY) { this.maxY = maxY; - return this; } - public MutableBox setMaxZ(int maxZ) { + public void setMaxZ(int maxZ) { this.maxZ = maxZ; - return this; } - public MutableBox assign(BlockPos start, BlockPos end) { + public void setMin(int x, int y, int z) { + minX = x; + minY = y; + minZ = z; + } + + public void setMax(int x, int y, int z) { + maxX = x; + maxY = y; + maxZ = z; + } + + public void setMin(Vec3i v) { + setMin(v.getX(), v.getY(), v.getZ()); + } + + public void setMax(Vec3i v) { + setMax(v.getX(), v.getY(), v.getZ()); + } + + public void assign(Box other) { + minX = other.getMinX(); + minY = other.getMinY(); + minZ = other.getMinZ(); + maxX = other.getMaxX(); + maxY = other.getMaxY(); + maxZ = other.getMaxZ(); + } + + public void assign(AABB other) { + minX = (int) Math.floor(other.minX); + minY = (int) Math.floor(other.minY); + minZ = (int) Math.floor(other.minZ); + maxX = (int) Math.ceil(other.maxX); + maxY = (int) Math.ceil(other.maxY); + maxZ = (int) Math.ceil(other.maxZ); + } + + public void assign(Vec3i start, Vec3i end) { minX = start.getX(); minY = start.getY(); minZ = start.getZ(); maxX = end.getX() + 1; maxY = end.getY() + 1; maxZ = end.getZ() + 1; - return this; } - public MutableBox setMax(Vec3i v) { - return setMax(v.getX(), v.getY(), v.getZ()); + public void unionAssign(Box other) { + minX = Math.min(this.minX, other.getMinX()); + minY = Math.min(this.minY, other.getMinY()); + minZ = Math.min(this.minZ, other.getMinZ()); + maxX = Math.max(this.maxX, other.getMaxX()); + maxY = Math.max(this.maxY, other.getMaxY()); + maxZ = Math.max(this.maxZ, other.getMaxZ()); } - public MutableBox setMin(Vec3i v) { - return setMin(v.getX(), v.getY(), v.getZ()); + public void unionAssign(AABB other) { + minX = Math.min(this.minX, (int) Math.floor(other.minX)); + minY = Math.min(this.minY, (int) Math.floor(other.minY)); + minZ = Math.min(this.minZ, (int) Math.floor(other.minZ)); + maxX = Math.max(this.maxX, (int) Math.ceil(other.maxX)); + maxY = Math.max(this.maxY, (int) Math.ceil(other.maxY)); + maxZ = Math.max(this.maxZ, (int) Math.ceil(other.maxZ)); } - public MutableBox setMax(int x, int y, int z) { - maxX = x; - maxY = y; - maxZ = z; - return this; + public void intersectAssign(Box other) { + minX = Math.max(this.minX, other.getMinX()); + minY = Math.max(this.minY, other.getMinY()); + minZ = Math.max(this.minZ, other.getMinZ()); + maxX = Math.min(this.maxX, other.getMaxX()); + maxY = Math.min(this.maxY, other.getMaxY()); + maxZ = Math.min(this.maxZ, other.getMaxZ()); } - public MutableBox setMin(int x, int y, int z) { - minX = x; - minY = y; - minZ = z; - return this; + public void fixMinMax() { + int minX = Math.min(this.minX, this.maxX); + int minY = Math.min(this.minY, this.maxY); + int minZ = Math.min(this.minZ, this.maxZ); + int maxX = Math.max(this.minX, this.maxX); + int maxY = Math.max(this.minY, this.maxY); + int maxZ = Math.max(this.minZ, this.maxZ); + + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + } + + public void translate(int x, int y, int z) { + minX = minX + x; + maxX = maxX + x; + minY = minY + y; + maxY = maxY + y; + minZ = minZ + z; + maxZ = maxZ + z; + } + + public void translate(Vec3i by) { + translate(by.getX(), by.getY(), by.getZ()); + } + + public void grow(int x, int y, int z) { + minX = minX - x; + minY = minY - y; + minZ = minZ - z; + maxX = maxX + x; + maxY = maxY + y; + maxZ = maxZ + z; + } + + public void grow(int s) { + this.grow(s, s, s); + } + + /** + * Grow this box to have power of 2 side lengths, scaling from the minimum coords. + */ + public void nextPowerOf2() { + int sizeX = RenderMath.nextPowerOf2(sizeX()); + int sizeY = RenderMath.nextPowerOf2(sizeY()); + int sizeZ = RenderMath.nextPowerOf2(sizeZ()); + + maxX = minX + sizeX; + maxY = minY + sizeY; + maxZ = minZ + sizeZ; + } + + /** + * Grow this box to have power of 2 side length, scaling from the center. + */ + public void nextPowerOf2Centered() { + int sizeX = sizeX(); + int sizeY = sizeY(); + int sizeZ = sizeZ(); + + int newSizeX = RenderMath.nextPowerOf2(sizeX); + int newSizeY = RenderMath.nextPowerOf2(sizeY); + int newSizeZ = RenderMath.nextPowerOf2(sizeZ); + + int diffX = newSizeX - sizeX; + int diffY = newSizeY - sizeY; + int diffZ = newSizeZ - sizeZ; + + minX = minX - diffX / 2; // floor division for the minimums + minY = minY - diffY / 2; + minZ = minZ - diffZ / 2; + maxX = maxX + (diffX + 1) / 2; // ceiling divison for the maximums + maxY = maxY + (diffY + 1) / 2; + maxZ = maxZ + (diffZ + 1) / 2; + } + + public void mirrorAbout(Direction.Axis axis) { + Vec3i axisVec = Direction.get(Direction.AxisDirection.POSITIVE, axis) + .getNormal(); + int flipX = axisVec.getX() - 1; + int flipY = axisVec.getY() - 1; + int flipZ = axisVec.getZ() - 1; + + int maxX = this.maxX * flipX; + int maxY = this.maxY * flipY; + int maxZ = this.maxZ * flipZ; + this.maxX = this.minX * flipX; + this.maxY = this.minY * flipY; + this.maxZ = this.minZ * flipZ; + this.minX = maxX; + this.minY = maxY; + this.minZ = maxZ; } @Override - public int sizeX() { - return maxX - minX; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null) return false; + if (!(o instanceof Box that)) return false; + + return this.sameAs(that); } @Override - public int sizeY() { - return maxY - minY; - } - - @Override - public int sizeZ() { - return maxZ - minZ; - } - - @Override - public boolean empty() { - // if any dimension has side length 0 this box contains no volume - return minX == maxX || minY == maxY || minZ == maxZ; - } - - @Override - public boolean sameAs(ImmutableBox other) { - return minX == other.getMinX() && minY == other.getMinY() && minZ == other.getMinZ() && maxX == other.getMaxX() && maxY == other.getMaxY() && maxZ == other.getMaxZ(); - } - - @Override - public boolean sameAs(AABB other) { - return minX == Math.floor(other.minX) - && minY == Math.floor(other.minY) - && minZ == Math.floor(other.minZ) - && maxX == Math.ceil(other.maxX) - && maxY == Math.ceil(other.maxY) - && maxZ == Math.ceil(other.maxZ); - } - - @Override - public MutableBox intersect(ImmutableBox other) { - int minX = Math.max(this.minX, other.getMinX()); - int minY = Math.max(this.minY, other.getMinY()); - int minZ = Math.max(this.minZ, other.getMinZ()); - int maxX = Math.min(this.maxX, other.getMaxX()); - int maxY = Math.min(this.maxY, other.getMaxY()); - int maxZ = Math.min(this.maxZ, other.getMaxZ()); - return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); - } - - @Override - public ImmutableBox union(ImmutableBox other) { - int minX = Math.min(this.minX, other.getMinX()); - int minY = Math.min(this.minY, other.getMinY()); - int minZ = Math.min(this.minZ, other.getMinZ()); - int maxX = Math.max(this.maxX, other.getMaxX()); - int maxY = Math.max(this.maxY, other.getMaxY()); - int maxZ = Math.max(this.maxZ, other.getMaxZ()); - return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); - } - - @Override - public boolean contains(ImmutableBox other) { - return other.getMinX() >= this.minX && other.getMaxX() <= this.maxX && other.getMinY() >= this.minY && other.getMaxY() <= this.maxY && other.getMinZ() >= this.minZ && other.getMaxZ() <= this.maxZ; - } - - @Override - public boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - return this.minX < maxX && this.maxX > minX && this.minY < maxY && this.maxY > minY && this.minZ < maxZ && this.maxZ > minZ; - } - - @Override - public void forEachContained(CoordinateConsumer func) { - if (empty()) return; - - for (int x = minX; x < maxX; x++) { - for (int y = minY; y < maxY; y++) { - for (int z = minZ; z < maxZ; z++) { - func.consume(x, y, z); - } - } - } - } - - @Override - public AABB toAABB() { - return new AABB(minX, minY, minZ, maxX, maxY, maxZ); - } - - @Override - public MutableBox copy() { - return new MutableBox(minX, minY, minZ, maxX, maxY, maxZ); + public int hashCode() { + int result = minX; + result = 31 * result + minY; + result = 31 * result + minZ; + result = 31 * result + maxX; + result = 31 * result + maxY; + result = 31 * result + maxZ; + return result; } @Override diff --git a/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java b/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java index 89207df19..2a1a29976 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java +++ b/src/main/java/com/jozufozu/flywheel/lib/context/Contexts.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.ApiStatus; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.context.Context; -import com.jozufozu.flywheel.util.ResourceUtil; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -12,6 +12,9 @@ public final class Contexts { public static final SimpleContext WORLD = Context.REGISTRY.registerAndGet(new SimpleContext(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); public static final SimpleContext CRUMBLING = Context.REGISTRY.registerAndGet(new SimpleContext(Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); + private Contexts() { + } + @ApiStatus.Internal public static void init() { } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/InstanceTypes.java b/src/main/java/com/jozufozu/flywheel/lib/instance/InstanceTypes.java index 795f8853b..fb45107b4 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/InstanceTypes.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/InstanceTypes.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.ApiStatus; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.instance.InstanceType; -import com.jozufozu.flywheel.util.ResourceUtil; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -12,6 +12,9 @@ public final class InstanceTypes { public static final InstanceType TRANSFORMED = InstanceType.REGISTRY.registerAndGet(new TransformedType()); public static final InstanceType ORIENTED = InstanceType.REGISTRY.registerAndGet(new OrientedType()); + private InstanceTypes() { + } + @ApiStatus.Internal public static void init() { } diff --git a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java index 936f6b71f..3389b43ed 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java +++ b/src/main/java/com/jozufozu/flywheel/lib/instance/TransformedInstance.java @@ -11,12 +11,17 @@ import com.mojang.math.Quaternion; import net.minecraft.util.Mth; public class TransformedInstance extends ColoredLitInstance implements Transform { - private static final Matrix4f EMPTY_MATRIX_4f = new Matrix4f(); - private static final Matrix3f EMPTY_MATRIX_3f = new Matrix3f(); + private static final Matrix4f ZERO_MATRIX_4f = new Matrix4f(); + private static final Matrix3f ZERO_MATRIX_3f = new Matrix3f(); public final Matrix4f model = new Matrix4f(); public final Matrix3f normal = new Matrix3f(); + { + model.setIdentity(); + normal.setIdentity(); + } + public TransformedInstance(InstanceType type, InstanceHandle handle) { super(type, handle); } @@ -41,16 +46,16 @@ public class TransformedInstance extends ColoredLitInstance implements Transform public TransformedInstance setEmptyTransform() { setChanged(); - this.model.load(EMPTY_MATRIX_4f); - this.normal.load(EMPTY_MATRIX_3f); + model.load(ZERO_MATRIX_4f); + normal.load(ZERO_MATRIX_3f); return this; } public TransformedInstance loadIdentity() { setChanged(); - this.model.setIdentity(); - this.normal.setIdentity(); + model.setIdentity(); + normal.setIdentity(); return this; } @@ -95,13 +100,17 @@ public class TransformedInstance extends ColoredLitInstance implements Transform @Override public TransformedInstance mulPose(Matrix4f pose) { - this.model.multiply(pose); + setChanged(); + + model.multiply(pose); return this; } @Override public TransformedInstance mulNormal(Matrix3f normal) { - this.normal.mul(normal); + setChanged(); + + normal.mul(normal); return this; } diff --git a/src/main/java/com/jozufozu/flywheel/lib/layout/CommonItems.java b/src/main/java/com/jozufozu/flywheel/lib/layout/CommonItems.java index 3c4d54b0f..9a8c1fbe2 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/layout/CommonItems.java +++ b/src/main/java/com/jozufozu/flywheel/lib/layout/CommonItems.java @@ -5,7 +5,7 @@ import com.jozufozu.flywheel.gl.array.VertexAttribute; import com.jozufozu.flywheel.glsl.generate.FnSignature; import com.jozufozu.flywheel.glsl.generate.GlslExpr; -public class CommonItems { +public final class CommonItems { private static final String VEC2_TYPE = "vec2"; private static final String VEC3_TYPE = "vec3"; private static final String VEC4_TYPE = "vec4"; @@ -128,4 +128,7 @@ public class CommonItems { public static final MatInput MAT3 = new MatInput(3, 3, "mat3", "Mat3F", "unpackMat3F"); public static final MatInput MAT4 = new MatInput(4, 4, "mat4", "Mat4F", "unpackMat4F"); + + private CommonItems() { + } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/DummyLightUpdater.java b/src/main/java/com/jozufozu/flywheel/lib/light/DummyLightUpdater.java index f2256fce7..f41f560cf 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/DummyLightUpdater.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/DummyLightUpdater.java @@ -2,16 +2,15 @@ package com.jozufozu.flywheel.lib.light; import java.util.stream.Stream; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.lib.box.Box; import net.minecraft.core.SectionPos; import net.minecraft.world.level.LightLayer; -public class DummyLightUpdater extends LightUpdater { +public final class DummyLightUpdater extends LightUpdater { public static final DummyLightUpdater INSTANCE = new DummyLightUpdater(); private DummyLightUpdater() { - super(null); } @Override @@ -35,7 +34,7 @@ public class DummyLightUpdater extends LightUpdater { } @Override - public Stream getAllBoxes() { + public Stream getAllBoxes() { return Stream.empty(); } diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java b/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java index 8023c3b00..213a18a1d 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/GPULightVolume.java @@ -23,7 +23,7 @@ import org.lwjgl.opengl.GL30; import com.jozufozu.flywheel.gl.GlTexture; import com.jozufozu.flywheel.gl.GlTextureUnit; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.lib.box.Box; import com.jozufozu.flywheel.lib.box.MutableBox; import net.minecraft.world.level.BlockAndTintGetter; @@ -36,7 +36,7 @@ public class GPULightVolume extends LightVolume { private final GlTextureUnit textureUnit = GlTextureUnit.T4; protected boolean bufferDirty; - public GPULightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) { + public GPULightVolume(BlockAndTintGetter level, Box sampleVolume) { super(level, sampleVolume); this.sampleVolume.assign(sampleVolume); @@ -64,7 +64,7 @@ public class GPULightVolume extends LightVolume { } @Override - protected void setBox(ImmutableBox box) { + protected void setBox(Box box) { this.box.assign(box); this.box.nextPowerOf2Centered(); // called during super ctor @@ -110,7 +110,7 @@ public class GPULightVolume extends LightVolume { glTexture.delete(); } - public void move(ImmutableBox newSampleVolume) { + public void move(Box newSampleVolume) { if (lightData == null) return; if (box.contains(newSampleVolume)) { @@ -122,7 +122,7 @@ public class GPULightVolume extends LightVolume { } @Override - public ImmutableBox getVolume() { + public Box getVolume() { return sampleVolume; } diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/LightListener.java b/src/main/java/com/jozufozu/flywheel/lib/light/LightListener.java index e906b37b8..dfb3e9559 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/LightListener.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/LightListener.java @@ -1,6 +1,6 @@ package com.jozufozu.flywheel.lib.light; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.lib.box.Box; import net.minecraft.core.SectionPos; import net.minecraft.world.level.LightLayer; @@ -12,8 +12,7 @@ import net.minecraft.world.level.LightLayer; * It is the responsibility of the implementor to keep a reference to the level an object is contained in. */ public interface LightListener { - - ImmutableBox getVolume(); + Box getVolume(); /** * Check the status of the light listener. @@ -23,7 +22,7 @@ public interface LightListener { boolean isInvalid(); /** - * Called when a light updates in a chunk the implementor cares about. + * Called when light updates in a section the implementor cares about. */ void onLightUpdate(LightLayer type, SectionPos pos); } diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdated.java b/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdated.java deleted file mode 100644 index e15caacc1..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdated.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.jozufozu.flywheel.lib.light; - -import net.minecraft.client.Minecraft; -import net.minecraft.world.level.LevelAccessor; - -/** - * Marker interface for custom/fake levels to indicate that LightUpdater should bother interacting with it.

- * - * Implement this if your custom level has light updates at all. If so, be sure to call - * {@link com.jozufozu.flywheel.util.WorldAttached#invalidateWorld} when your level in unloaded. - */ -public interface LightUpdated extends LevelAccessor { - - /** - * @return {@code true} if this level is passing light updates into LightUpdater. - */ - default boolean receivesLightUpdates() { - return true; - } - - static boolean receivesLightUpdates(LevelAccessor level) { - // The client level is guaranteed to receive updates. - if (Minecraft.getInstance().level == level) { - return true; - } - // Custom/fake levels need to indicate that LightUpdater has meaning. - if (level instanceof LightUpdated c) { - return c.receivesLightUpdates(); - } - return false; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdatedLevel.java b/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdatedLevel.java new file mode 100644 index 000000000..d2b8d952a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdatedLevel.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.lib.light; + +import net.minecraft.world.level.LevelAccessor; + +/** + * Marker interface for custom/fake levels to indicate that LightUpdater should interact with it.

+ * + * Implement this if your custom level has light updates at all. If so, be sure to call + * {@link com.jozufozu.flywheel.lib.util.LevelAttached#invalidateLevel} when your level is unloaded. + */ +public interface LightUpdatedLevel extends LevelAccessor { + /** + * @return {@code true} if this level is passing light updates into LightUpdater. + */ + default boolean receivesLightUpdates() { + return true; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdater.java b/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdater.java index c7b0381dc..1f447ed85 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdater.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/LightUpdater.java @@ -5,107 +5,71 @@ import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Stream; -import com.jozufozu.flywheel.lib.box.ImmutableBox; -import com.jozufozu.flywheel.util.FlwUtil; -import com.jozufozu.flywheel.util.WorldAttached; +import org.jetbrains.annotations.ApiStatus; + +import com.jozufozu.flywheel.lib.box.Box; +import com.jozufozu.flywheel.lib.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.LevelAttached; import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.client.Minecraft; import net.minecraft.core.SectionPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LightLayer; +import net.minecraftforge.event.TickEvent; /** * Keeps track of what chunks/sections each listener is in, so we can update exactly what needs to be updated. * * @apiNote Custom/fake levels (that are {@code != Minecraft.getInstance.level}) need to implement - * {@link LightUpdated} for LightUpdater to work with them. + * {@link LightUpdatedLevel} for LightUpdater to work with them. */ public class LightUpdater { - private static final WorldAttached LEVELS = new WorldAttached<>(LightUpdater::new); - - private final LevelAccessor level; + private static final LevelAttached UPDATERS = new LevelAttached<>(level -> new LightUpdater()); private final WeakContainmentMultiMap listenersBySection = new WeakContainmentMultiMap<>(); private final Set tickingListeners = FlwUtil.createWeakHashSet(); - private final Queue queue = new ConcurrentLinkedQueue<>(); + private final Queue additionQueue = new ConcurrentLinkedQueue<>(); + + public static boolean supports(LevelAccessor level) { + // The client level is guaranteed to receive updates. + if (Minecraft.getInstance().level == level) { + return true; + } + // Custom/fake levels need to indicate that LightUpdater has meaning. + if (level instanceof LightUpdatedLevel c) { + return c.receivesLightUpdates(); + } + return false; + } public static LightUpdater get(LevelAccessor level) { - if (LightUpdated.receivesLightUpdates(level)) { - // The level is valid, add it to the map. - return LEVELS.get(level); + if (supports(level)) { + // The level is valid, so add it to the map. + return UPDATERS.get(level); } else { // Fake light updater for a fake level. return DummyLightUpdater.INSTANCE; } } - public LightUpdater(LevelAccessor level) { - this.level = level; - } - - public void tick() { - processQueue(); - tickSerial(); - } - - private void tickSerial() { - for (TickingLightListener tickingLightListener : tickingListeners) { - if (tickingLightListener.tickLightListener()) { - addListener(tickingLightListener); - } - } - } - /** * Add a listener. * * @param listener The object that wants to receive light update notifications. */ public void addListener(LightListener listener) { - queue.add(listener); - } - - private synchronized void processQueue() { - LightListener listener; - while ((listener = queue.poll()) != null) { - doAdd(listener); - } - } - - private void doAdd(LightListener listener) { - if (listener instanceof TickingLightListener) { - tickingListeners.add(((TickingLightListener) listener)); - } - - ImmutableBox box = listener.getVolume(); - - LongSet sections = this.listenersBySection.getAndResetContainment(listener); - - int minX = SectionPos.blockToSectionCoord(box.getMinX()); - int minY = SectionPos.blockToSectionCoord(box.getMinY()); - int minZ = SectionPos.blockToSectionCoord(box.getMinZ()); - int maxX = SectionPos.blockToSectionCoord(box.getMaxX()); - int maxY = SectionPos.blockToSectionCoord(box.getMaxY()); - int maxZ = SectionPos.blockToSectionCoord(box.getMaxZ()); - - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - long sectionPos = SectionPos.asLong(x, y, z); - this.listenersBySection.put(sectionPos, listener); - sections.add(sectionPos); - } - } - } + additionQueue.add(listener); } public void removeListener(LightListener listener) { - this.listenersBySection.remove(listener); + listenersBySection.remove(listener); } /** * Dispatch light updates to all registered {@link LightListener}s. + * * @param type The type of light that changed. * @param pos The section position where light changed. */ @@ -125,11 +89,63 @@ public class LightUpdater { } } - public Stream getAllBoxes() { + public Stream getAllBoxes() { return listenersBySection.stream().map(LightListener::getVolume); } public boolean isEmpty() { return listenersBySection.isEmpty(); } + + @ApiStatus.Internal + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END && FlwUtil.isGameActive()) { + get(Minecraft.getInstance().level) + .tick(); + } + } + + void tick() { + processQueue(); + + for (TickingLightListener tickingListener : tickingListeners) { + if (tickingListener.tickLightListener()) { + addListener(tickingListener); + } + } + } + + private synchronized void processQueue() { + LightListener listener; + while ((listener = additionQueue.poll()) != null) { + doAdd(listener); + } + } + + private void doAdd(LightListener listener) { + if (listener instanceof TickingLightListener ticking) { + tickingListeners.add(ticking); + } + + Box box = listener.getVolume(); + + LongSet sections = listenersBySection.getAndResetContainment(listener); + + int minX = SectionPos.blockToSectionCoord(box.getMinX()); + int minY = SectionPos.blockToSectionCoord(box.getMinY()); + int minZ = SectionPos.blockToSectionCoord(box.getMinZ()); + int maxX = SectionPos.blockToSectionCoord(box.getMaxX()); + int maxY = SectionPos.blockToSectionCoord(box.getMaxY()); + int maxZ = SectionPos.blockToSectionCoord(box.getMaxZ()); + + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + long sectionPos = SectionPos.asLong(x, y, z); + listenersBySection.put(sectionPos, listener); + sections.add(sectionPos); + } + } + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/LightVolume.java b/src/main/java/com/jozufozu/flywheel/lib/light/LightVolume.java index f589b7091..c8aa2b1fd 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/LightVolume.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/LightVolume.java @@ -2,7 +2,7 @@ package com.jozufozu.flywheel.lib.light; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.lib.box.Box; import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.memory.MemoryBlock; @@ -11,13 +11,13 @@ import net.minecraft.core.SectionPos; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.LightLayer; -public class LightVolume implements ImmutableBox, LightListener { +public class LightVolume implements Box, LightListener { protected final BlockAndTintGetter level; protected final MutableBox box = new MutableBox(); protected MemoryBlock lightData; - public LightVolume(BlockAndTintGetter level, ImmutableBox sampleVolume) { + public LightVolume(BlockAndTintGetter level, Box sampleVolume) { this.level = level; this.setBox(sampleVolume); @@ -25,7 +25,7 @@ public class LightVolume implements ImmutableBox, LightListener { } @Override - public ImmutableBox getVolume() { + public Box getVolume() { return box; } @@ -64,7 +64,7 @@ public class LightVolume implements ImmutableBox, LightListener { return lightData == null; } - protected void setBox(ImmutableBox box) { + protected void setBox(Box box) { this.box.assign(box); } @@ -76,7 +76,7 @@ public class LightVolume implements ImmutableBox, LightListener { } } - public void move(ImmutableBox newSampleVolume) { + public void move(Box newSampleVolume) { if (lightData == null) return; setBox(newSampleVolume); @@ -112,7 +112,7 @@ public class LightVolume implements ImmutableBox, LightListener { * * @param worldVolume the region in the world to copy data from. */ - public void copyLight(ImmutableBox worldVolume) { + public void copyLight(Box worldVolume) { BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); int xShift = box.getMinX(); @@ -143,7 +143,7 @@ public class LightVolume implements ImmutableBox, LightListener { * * @param worldVolume the region in the world to copy data from. */ - public void copyBlock(ImmutableBox worldVolume) { + public void copyBlock(Box worldVolume) { var pos = new BlockPos.MutableBlockPos(); int xShift = box.getMinX(); @@ -168,7 +168,7 @@ public class LightVolume implements ImmutableBox, LightListener { * * @param worldVolume the region in the world to copy data from. */ - public void copySky(ImmutableBox worldVolume) { + public void copySky(Box worldVolume) { var pos = new BlockPos.MutableBlockPos(); int xShift = box.getMinX(); diff --git a/src/main/java/com/jozufozu/flywheel/lib/light/WeakContainmentMultiMap.java b/src/main/java/com/jozufozu/flywheel/lib/light/WeakContainmentMultiMap.java index f5973b097..dfa18af76 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/light/WeakContainmentMultiMap.java +++ b/src/main/java/com/jozufozu/flywheel/lib/light/WeakContainmentMultiMap.java @@ -6,15 +6,14 @@ import java.util.Set; import java.util.WeakHashMap; import java.util.function.LongConsumer; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.lib.util.FlwUtil; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongRBTreeSet; import it.unimi.dsi.fastutil.longs.LongSet; -public class WeakContainmentMultiMap extends AbstractCollection { - +class WeakContainmentMultiMap extends AbstractCollection { private final Long2ObjectMap> forward; private final WeakHashMap reverse; diff --git a/src/main/java/com/jozufozu/flywheel/lib/material/Materials.java b/src/main/java/com/jozufozu/flywheel/lib/material/Materials.java index 6178eab54..8754a1fa1 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/material/Materials.java +++ b/src/main/java/com/jozufozu/flywheel/lib/material/Materials.java @@ -8,8 +8,8 @@ import com.jozufozu.flywheel.api.material.MaterialVertexTransformer; import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.lib.material.SimpleMaterial.GlStateShard; import com.jozufozu.flywheel.lib.math.DiffuseLightCalculator; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import com.jozufozu.flywheel.lib.util.ShadersModHandler; -import com.jozufozu.flywheel.util.ResourceUtil; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; @@ -134,6 +134,9 @@ public final class Materials { .batchingRenderType(RenderType.entitySolid(MINECART_LOCATION)) .register(); + private Materials() { + } + @ApiStatus.Internal public static void init() { } diff --git a/src/main/java/com/jozufozu/flywheel/lib/material/SimpleMaterial.java b/src/main/java/com/jozufozu/flywheel/lib/material/SimpleMaterial.java index 4d0c76c5d..1811d354e 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/material/SimpleMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/lib/material/SimpleMaterial.java @@ -49,7 +49,7 @@ public class SimpleMaterial implements Material { } @Override - public RenderType getBatchingRenderType() { + public RenderType getFallbackRenderType() { return batchingRenderType; } diff --git a/src/main/java/com/jozufozu/flywheel/lib/math/RenderMath.java b/src/main/java/com/jozufozu/flywheel/lib/math/RenderMath.java index d7d015161..ad29c1549 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/math/RenderMath.java +++ b/src/main/java/com/jozufozu/flywheel/lib/math/RenderMath.java @@ -36,19 +36,6 @@ public final class RenderMath { return (h == a) ? h : (h << 1); } - public static boolean isPowerOf2(int n) { - int b = n & (n - 1); - return b == 0 && n != 0; - } - - public static double lengthSqr(double x, double y, double z) { - return x * x + y * y + z * z; - } - - public static double length(double x, double y, double z) { - return Math.sqrt(lengthSqr(x, y, z)); - } - public static float diffuseLight(float x, float y, float z, boolean shaded) { if (!shaded) { return 1f; diff --git a/src/main/java/com/jozufozu/flywheel/lib/memory/DebugMemoryBlockImpl.java b/src/main/java/com/jozufozu/flywheel/lib/memory/DebugMemoryBlockImpl.java index e207a7b08..fb8bd8571 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/memory/DebugMemoryBlockImpl.java +++ b/src/main/java/com/jozufozu/flywheel/lib/memory/DebugMemoryBlockImpl.java @@ -3,7 +3,7 @@ package com.jozufozu.flywheel.lib.memory; import java.lang.ref.Cleaner; import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; class DebugMemoryBlockImpl extends MemoryBlockImpl { final CleaningAction cleaningAction; diff --git a/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java b/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java index 6aec1b3e3..06b3f2946 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java +++ b/src/main/java/com/jozufozu/flywheel/lib/memory/FlwMemoryTracker.java @@ -1,20 +1,23 @@ package com.jozufozu.flywheel.lib.memory; import java.lang.ref.Cleaner; -import java.nio.ByteBuffer; import org.lwjgl.system.MemoryUtil; -import com.jozufozu.flywheel.util.StringUtil; +import com.jozufozu.flywheel.lib.util.StringUtil; public final class FlwMemoryTracker { public static final boolean DEBUG_MEMORY_SAFETY = System.getProperty("flw.debugMemorySafety") != null; static final Cleaner CLEANER = Cleaner.create(); + // TODO: Should these be volatile? private static long cpuMemory = 0; private static long gpuMemory = 0; + private FlwMemoryTracker() { + } + public static long malloc(long size) { long ptr = MemoryUtil.nmemAlloc(size); if (ptr == MemoryUtil.NULL) { @@ -23,18 +26,6 @@ public final class FlwMemoryTracker { return ptr; } - /** - * @deprecated Use {@link MemoryBlock#malloc(long)} or {@link MemoryBlock#mallocTracked(long)} and - * {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is - * short-lived. - */ - @Deprecated - public static ByteBuffer mallocBuffer(int size) { - ByteBuffer buffer = MemoryUtil.memByteBuffer(malloc(size), size); - _allocCPUMemory(buffer.capacity()); - return buffer; - } - public static long calloc(long num, long size) { long ptr = MemoryUtil.nmemCalloc(num, size); if (ptr == MemoryUtil.NULL) { @@ -43,18 +34,6 @@ public final class FlwMemoryTracker { return ptr; } - /** - * @deprecated Use {@link MemoryBlock#calloc(long, long)} or {@link MemoryBlock#callocTracked(long, long)} and - * {@link MemoryBlock#asBuffer()} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and it is - * short-lived. - */ - @Deprecated - public static ByteBuffer callocBuffer(int num, int size) { - ByteBuffer buffer = MemoryUtil.memByteBuffer(calloc(num, size), num * size); - _allocCPUMemory(buffer.capacity()); - return buffer; - } - public static long realloc(long ptr, long size) { ptr = MemoryUtil.nmemRealloc(ptr, size); if (ptr == MemoryUtil.NULL) { @@ -63,32 +42,10 @@ public final class FlwMemoryTracker { return ptr; } - /** - * @deprecated Use {@link MemoryBlock#realloc(long)} or {@link MemoryBlock#reallocTracked(long)} instead. This method - * should only be used if specifically a {@linkplain ByteBuffer} is needed and it is short-lived. - */ - @Deprecated - public static ByteBuffer reallocBuffer(ByteBuffer buffer, int size) { - ByteBuffer newBuffer = MemoryUtil.memByteBuffer(realloc(MemoryUtil.memAddress(buffer), size), size); - _freeCPUMemory(buffer.capacity()); - _allocCPUMemory(newBuffer.capacity()); - return newBuffer; - } - public static void free(long ptr) { MemoryUtil.nmemFree(ptr); } - /** - * @deprecated Use {@link MemoryBlock#free} instead. This method should only be used if specifically a {@linkplain ByteBuffer} is needed and - * it is short-lived. - */ - @Deprecated - public static void freeBuffer(ByteBuffer buffer) { - free(MemoryUtil.memAddress(buffer)); - _freeCPUMemory(buffer.capacity()); - } - public static void _allocCPUMemory(long size) { cpuMemory += size; } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java b/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java index aa930bbda..e4afba7b6 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/ModelUtil.java @@ -37,6 +37,9 @@ public final class ModelUtil { */ public static final BlockRenderDispatcher VANILLA_RENDERER = createVanillaRenderer(); + private ModelUtil() { + } + private static BlockRenderDispatcher createVanillaRenderer() { BlockRenderDispatcher defaultDispatcher = Minecraft.getInstance().getBlockRenderer(); BlockRenderDispatcher dispatcher = new BlockRenderDispatcher(null, null, null); @@ -53,6 +56,10 @@ public final class ModelUtil { return dispatcher; } + public static boolean isVanillaBufferEmpty(Pair pair) { + return pair.getFirst().vertexCount() == 0; + } + public static MemoryBlock convertVanillaBuffer(Pair pair, VertexType vertexType) { DrawState drawState = pair.getFirst(); int vertexCount = drawState.vertexCount(); @@ -108,12 +115,12 @@ public final class ModelUtil { } @Override - public double coord(int i, int j) { - return switch (j) { + public double coord(int i, int dim) { + return switch (dim) { case 0 -> vertexList.x(i); case 1 -> vertexList.y(i); case 2 -> vertexList.z(i); - default -> throw new IllegalArgumentException("Invalid dimension: " + j); + default -> throw new IllegalArgumentException("Invalid dimension: " + dim); }; } }); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/Models.java b/src/main/java/com/jozufozu/flywheel/lib/model/Models.java index 9899fc7d6..ef49cbff9 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/Models.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/Models.java @@ -4,12 +4,15 @@ import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.jetbrains.annotations.ApiStatus; + import com.jozufozu.flywheel.api.event.ReloadRenderersEvent; import com.jozufozu.flywheel.api.model.Model; -import com.jozufozu.flywheel.lib.model.buffering.BakedModelBuilder; -import com.jozufozu.flywheel.lib.model.buffering.BlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.BakedModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.BlockModelBuilder; +import com.jozufozu.flywheel.lib.model.baked.PartialModel; import com.jozufozu.flywheel.lib.transform.TransformStack; -import com.jozufozu.flywheel.util.Pair; +import com.jozufozu.flywheel.lib.util.Pair; import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.core.Direction; @@ -20,6 +23,9 @@ public final class Models { private static final Map PARTIAL = new ConcurrentHashMap<>(); private static final Map, Model> PARTIAL_DIR = new ConcurrentHashMap<>(); + private Models() { + } + public static Model block(BlockState state) { return BLOCK_STATE.computeIfAbsent(state, it -> new BlockModelBuilder(it).build()); } @@ -32,7 +38,7 @@ public final class Models { return PARTIAL_DIR.computeIfAbsent(Pair.of(partial, dir), it -> new BakedModelBuilder(it.first().get()).poseStack(createRotation(it.second())).build()); } - public static PoseStack createRotation(Direction facing) { + private static PoseStack createRotation(Direction facing) { PoseStack stack = new PoseStack(); TransformStack.cast(stack) .centre() @@ -41,6 +47,7 @@ public final class Models { return stack; } + @ApiStatus.Internal public static void onReloadRenderers(ReloadRenderersEvent event) { deleteAll(BLOCK_STATE.values()); deleteAll(PARTIAL.values()); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java index 90d9b5c9c..51475933c 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/SimpleLazyModel.java @@ -1,41 +1,50 @@ package com.jozufozu.flywheel.lib.model; import java.util.Map; +import java.util.function.Supplier; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableMap; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Model; -import com.jozufozu.flywheel.util.Lazy; -import com.jozufozu.flywheel.util.NonNullSupplier; public class SimpleLazyModel implements Model { - private final Lazy supplier; + private final Supplier<@NotNull Mesh> meshSupplier; private final Material material; - public SimpleLazyModel(NonNullSupplier supplier, Material material) { - this.supplier = Lazy.of(supplier); + @Nullable + private Mesh mesh; + @Nullable + private Map meshMap; + + public SimpleLazyModel(Supplier<@NotNull Mesh> meshSupplier, Material material) { + this.meshSupplier = meshSupplier; this.material = material; } @Override public Map getMeshes() { - return ImmutableMap.of(material, supplier.get()); + if (mesh == null) { + mesh = meshSupplier.get(); + meshMap = ImmutableMap.of(material, mesh); + } + + return meshMap; } @Override public void delete() { - supplier.ifPresent(Mesh::delete); - } - - public int getVertexCount() { - return supplier.map(Mesh::vertexCount) - .orElse(0); + if (mesh != null) { + mesh.delete(); + } } @Override public String toString() { - return "SimpleLazyModel{" + supplier.map(Mesh::name) - .orElse("Uninitialized") + '}'; + String name = mesh != null ? mesh.name() : "Uninitialized"; + return "SimpleLazyModel{" + name + '}'; } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/BakedModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java similarity index 50% rename from src/main/java/com/jozufozu/flywheel/lib/model/buffering/BakedModelBuilder.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java index 38642adf3..453c9bd11 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/BakedModelBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BakedModelBuilder.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.model.buffering; +package com.jozufozu.flywheel.lib.model.baked; import java.util.function.BiFunction; @@ -8,18 +8,10 @@ import com.jozufozu.flywheel.api.model.Mesh; 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.TessellatedModel; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.BufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; import com.jozufozu.flywheel.lib.vertex.VertexTypes; -import com.jozufozu.flywheel.lib.virtualworld.VirtualEmptyBlockGetter; -import com.jozufozu.flywheel.lib.virtualworld.VirtualEmptyModelData; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexFormat; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.resources.model.BakedModel; @@ -29,8 +21,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.client.model.data.IModelData; public class BakedModelBuilder { - private static final int STARTING_CAPACITY = 64; - private final BakedModel bakedModel; private boolean shadeSeparated = true; private BlockAndTintGetter renderWorld; @@ -73,19 +63,13 @@ public class BakedModelBuilder { return this; } - @SuppressWarnings("unchecked") public TessellatedModel build() { - ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); - if (renderWorld == null) { renderWorld = VirtualEmptyBlockGetter.INSTANCE; } if (blockState == null) { blockState = Blocks.AIR.defaultBlockState(); } - if (poseStack == null) { - poseStack = objects.identityPoseStack; - } if (modelData == null) { modelData = VirtualEmptyModelData.INSTANCE; } @@ -96,35 +80,27 @@ public class BakedModelBuilder { ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); if (shadeSeparated) { - ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + } } }; - ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); + ModelBufferingUtil.bufferSingleShadeSeparated(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); } else { - BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ResultConsumer resultConsumer = (renderType, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, false); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); + ResultConsumer resultConsumer = (renderType, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, true); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "bakedModel=" + bakedModel.toString() + ",renderType=" + renderType.toString())); + } } }; - ModelBufferingUtil.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); + ModelBufferingUtil.bufferSingle(ModelUtil.VANILLA_RENDERER.getModelRenderer(), renderWorld, bakedModel, blockState, poseStack, modelData, resultConsumer); } return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java new file mode 100644 index 000000000..7339723aa --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/BlockModelBuilder.java @@ -0,0 +1,97 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.util.function.BiFunction; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Mesh; +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.baked.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.vertex.VertexTypes; +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.IModelData; + +public class BlockModelBuilder { + private final BlockState state; + private boolean shadeSeparated = true; + private BlockAndTintGetter renderWorld; + private PoseStack poseStack; + private IModelData modelData; + private BiFunction materialFunc; + + public BlockModelBuilder(BlockState state) { + this.state = state; + } + + public BlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + + public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public BlockModelBuilder poseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public BlockModelBuilder modelData(IModelData modelData) { + this.modelData = modelData; + return this; + } + + public BlockModelBuilder materialFunc(BiFunction materialFunc) { + this.materialFunc = materialFunc; + return this; + } + + public TessellatedModel build() { + if (renderWorld == null) { + renderWorld = VirtualEmptyBlockGetter.INSTANCE; + } + if (modelData == null) { + modelData = VirtualEmptyModelData.INSTANCE; + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); + + if (shadeSeparated) { + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); + } + } + }; + ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); + } else { + ResultConsumer resultConsumer = (renderType, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, true); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "state=" + state.toString() + ",renderType=" + renderType.toString())); + } + } + }; + ModelBufferingUtil.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, modelData, resultConsumer); + } + + return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java new file mode 100644 index 000000000..e5f32ae1e --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/ModelBufferingUtil.java @@ -0,0 +1,278 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.Random; + +import org.jetbrains.annotations.Nullable; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferBuilder.DrawState; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.datafixers.util.Pair; + +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.client.renderer.block.ModelBlockRenderer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.data.EmptyModelData; +import net.minecraftforge.client.model.data.IModelData; + +public final class ModelBufferingUtil { + private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); + private static final int CHUNK_LAYER_AMOUNT = CHUNK_LAYERS.length; + + private static final ThreadLocal THREAD_LOCAL_OBJECTS = ThreadLocal.withInitial(ModelBufferingObjects::new); + + public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ResultConsumer resultConsumer) { + ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + Random random = objects.random; + BufferBuilder[] buffers = objects.shadedBuffers; + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, renderType)) { + continue; + } + + BufferBuilder buffer = buffers[layerIndex]; + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + + ForgeHooksClient.setRenderType(renderType); + + poseStack.pushPose(); + blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, buffer, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + buffer.end(); + Pair data = buffer.popNextBuffer(); + resultConsumer.accept(renderType, data); + } + + ForgeHooksClient.setRenderType(null); + } + + public static void bufferSingleShadeSeparated(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { + ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + Random random = objects.random; + ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper; + BufferBuilder[] shadedBuffers = objects.shadedBuffers; + BufferBuilder[] unshadedBuffers = objects.unshadedBuffers; + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, renderType)) { + continue; + } + + BufferBuilder shadedBuffer = shadedBuffers[layerIndex]; + BufferBuilder unshadedBuffer = unshadedBuffers[layerIndex]; + shadeSeparatingWrapper.prepare(shadedBuffer, unshadedBuffer); + shadedBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + unshadedBuffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + + ForgeHooksClient.setRenderType(renderType); + + poseStack.pushPose(); + blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, shadeSeparatingWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + + shadedBuffer.end(); + unshadedBuffer.end(); + Pair shadedData = shadedBuffer.popNextBuffer(); + Pair unshadedData = unshadedBuffer.popNextBuffer(); + resultConsumer.accept(renderType, true, shadedData); + resultConsumer.accept(renderType, false, unshadedData); + } + + ForgeHooksClient.setRenderType(null); + + shadeSeparatingWrapper.clear(); + } + + public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ResultConsumer resultConsumer) { + if (state.getRenderShape() != RenderShape.MODEL) { + return; + } + + bufferSingle(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer); + } + + public static void bufferBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, @Nullable PoseStack poseStack, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { + if (state.getRenderShape() != RenderShape.MODEL) { + return; + } + + bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, modelData, resultConsumer); + } + + public static void bufferMultiBlock(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ResultConsumer resultConsumer) { + ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + Random random = objects.random; + + BufferBuilder[] buffers = objects.shadedBuffers; + for (BufferBuilder buffer : buffers) { + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + } + + ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); + ModelBlockRenderer.enableCaching(); + + for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { + BlockState state = blockInfo.state; + + if (state.getRenderShape() != RenderShape.MODEL) { + continue; + } + + BakedModel model = renderDispatcher.getBlockModel(state); + BlockPos pos = blockInfo.pos; + long seed = state.getSeed(pos); + IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, renderType)) { + continue; + } + + BufferBuilder buffer = buffers[layerIndex]; + + ForgeHooksClient.setRenderType(renderType); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, buffer, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + } + } + + ForgeHooksClient.setRenderType(null); + ModelBlockRenderer.clearCache(); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + BufferBuilder buffer = buffers[layerIndex]; + buffer.end(); + Pair data = buffer.popNextBuffer(); + resultConsumer.accept(renderType, data); + } + } + + public static void bufferMultiBlockShadeSeparated(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, @Nullable PoseStack poseStack, Map modelDataMap, ShadeSeparatedResultConsumer resultConsumer) { + ModelBufferingObjects objects = THREAD_LOCAL_OBJECTS.get(); + if (poseStack == null) { + poseStack = objects.identityPoseStack; + } + Random random = objects.random; + ShadeSeparatingVertexConsumer shadeSeparatingWrapper = objects.shadeSeparatingWrapper; + + BufferBuilder[] shadedBuffers = objects.shadedBuffers; + BufferBuilder[] unshadedBuffers = objects.unshadedBuffers; + for (BufferBuilder buffer : shadedBuffers) { + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + } + for (BufferBuilder buffer : unshadedBuffers) { + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); + } + + ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); + ModelBlockRenderer.enableCaching(); + + for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { + BlockState state = blockInfo.state; + + if (state.getRenderShape() != RenderShape.MODEL) { + continue; + } + + BakedModel model = renderDispatcher.getBlockModel(state); + BlockPos pos = blockInfo.pos; + long seed = state.getSeed(pos); + IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + + if (!ItemBlockRenderTypes.canRenderInLayer(state, renderType)) { + continue; + } + + shadeSeparatingWrapper.prepare(shadedBuffers[layerIndex], unshadedBuffers[layerIndex]); + + ForgeHooksClient.setRenderType(renderType); + + poseStack.pushPose(); + poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); + blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, shadeSeparatingWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); + poseStack.popPose(); + } + } + + ForgeHooksClient.setRenderType(null); + ModelBlockRenderer.clearCache(); + + shadeSeparatingWrapper.clear(); + + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + RenderType renderType = CHUNK_LAYERS[layerIndex]; + BufferBuilder shadedBuffer = shadedBuffers[layerIndex]; + BufferBuilder unshadedBuffer = unshadedBuffers[layerIndex]; + shadedBuffer.end(); + unshadedBuffer.end(); + Pair shadedData = shadedBuffer.popNextBuffer(); + Pair unshadedData = unshadedBuffer.popNextBuffer(); + resultConsumer.accept(renderType, true, shadedData); + resultConsumer.accept(renderType, false, unshadedData); + } + } + + public interface ResultConsumer { + void accept(RenderType renderType, Pair data); + } + + public interface ShadeSeparatedResultConsumer { + void accept(RenderType renderType, boolean shaded, Pair data); + } + + private static class ModelBufferingObjects { + public final PoseStack identityPoseStack = new PoseStack(); + public final Random random = new Random(); + + public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer(); + + public final BufferBuilder[] shadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT]; + public final BufferBuilder[] unshadedBuffers = new BufferBuilder[CHUNK_LAYER_AMOUNT]; + + { + for (int layerIndex = 0; layerIndex < CHUNK_LAYER_AMOUNT; layerIndex++) { + int initialSize = CHUNK_LAYERS[layerIndex].bufferSize(); + shadedBuffers[layerIndex] = new BufferBuilder(initialSize); + unshadedBuffers[layerIndex] = new BufferBuilder(initialSize); + } + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java new file mode 100644 index 000000000..53ab943f1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/MultiBlockModelBuilder.java @@ -0,0 +1,101 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.function.BiFunction; + +import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Mesh; +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.baked.ModelBufferingUtil.ResultConsumer; +import com.jozufozu.flywheel.lib.model.baked.ModelBufferingUtil.ShadeSeparatedResultConsumer; +import com.jozufozu.flywheel.lib.vertex.VertexTypes; +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.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import net.minecraftforge.client.model.data.IModelData; + +public class MultiBlockModelBuilder { + private final Collection blocks; + private boolean shadeSeparated = true; + private BlockAndTintGetter renderWorld; + private PoseStack poseStack; + private Map modelDataMap; + private BiFunction materialFunc; + + public MultiBlockModelBuilder(Collection blocks) { + this.blocks = blocks; + } + + public MultiBlockModelBuilder disableShadeSeparation() { + shadeSeparated = false; + return this; + } + + public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { + this.renderWorld = renderWorld; + return this; + } + + public MultiBlockModelBuilder poseStack(PoseStack poseStack) { + this.poseStack = poseStack; + return this; + } + + public MultiBlockModelBuilder modelDataMap(Map modelDataMap) { + this.modelDataMap = modelDataMap; + return this; + } + + public MultiBlockModelBuilder materialFunc(BiFunction materialFunc) { + this.materialFunc = materialFunc; + return this; + } + + public TessellatedModel build() { + if (renderWorld == null) { + renderWorld = VirtualEmptyBlockGetter.INSTANCE; + } + if (modelDataMap == null) { + modelDataMap = Collections.emptyMap(); + } + if (materialFunc == null) { + materialFunc = ModelUtil::getMaterial; + } + + ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); + + if (shadeSeparated) { + ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, shaded); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "renderType=" + renderType.toString() + ",shaded=" + shaded)); + } + } + }; + ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + } else { + ResultConsumer resultConsumer = (renderType, data) -> { + if (!ModelUtil.isVanillaBufferEmpty(data)) { + Material material = materialFunc.apply(renderType, true); + if (material != null) { + MemoryBlock meshData = ModelUtil.convertVanillaBuffer(data, VertexTypes.BLOCK); + meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, meshData, "renderType=" + renderType.toString())); + } + } + }; + ModelBufferingUtil.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, modelDataMap, resultConsumer); + } + + return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/PartialModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java similarity index 97% rename from src/main/java/com/jozufozu/flywheel/lib/model/PartialModel.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java index 3fa168cef..da395d465 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/PartialModel.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/PartialModel.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.model; +package com.jozufozu.flywheel.lib.model.baked; import java.util.ArrayList; import java.util.List; @@ -24,7 +24,6 @@ import net.minecraftforge.client.model.ForgeModelBakery; * Attempting to create a PartialModel after {@link ModelRegistryEvent} will cause an error. */ public class PartialModel { - private static final List ALL = new ArrayList<>(); private static boolean tooLate = false; @@ -68,5 +67,4 @@ public class PartialModel { public BakedModel get() { return bakedModel; } - } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/baked/ShadeSeparatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/ShadeSeparatingVertexConsumer.java new file mode 100644 index 000000000..6d0165403 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/ShadeSeparatingVertexConsumer.java @@ -0,0 +1,84 @@ +package com.jozufozu.flywheel.lib.model.baked; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; + +import net.minecraft.client.renderer.block.model.BakedQuad; + +class ShadeSeparatingVertexConsumer implements VertexConsumer { + private VertexConsumer shadedConsumer; + private VertexConsumer unshadedConsumer; + + public void prepare(VertexConsumer shadedConsumer, VertexConsumer unshadedConsumer) { + this.shadedConsumer = shadedConsumer; + this.unshadedConsumer = unshadedConsumer; + } + + public void clear() { + shadedConsumer = null; + unshadedConsumer = null; + } + + @Override + public void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { + if (quad.isShade()) { + shadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + } else { + unshadedConsumer.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); + } + } + + @Override + public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { + if (bakedQuad.isShade()) { + shadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } else { + unshadedConsumer.putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); + } + } + + @Override + public VertexConsumer vertex(double x, double y, double z) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public VertexConsumer color(int red, int green, int blue, int alpha) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public VertexConsumer uv(float u, float v) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public VertexConsumer overlayCoords(int u, int v) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public VertexConsumer uv2(int u, int v) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public VertexConsumer normal(float x, float y, float z) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public void endVertex() { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public void defaultColor(int red, int green, int blue, int alpha) { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } + + @Override + public void unsetDefaultColor() { + throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!"); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/TessellatedModel.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/TessellatedModel.java similarity index 94% rename from src/main/java/com/jozufozu/flywheel/lib/model/TessellatedModel.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/TessellatedModel.java index ec7fe9541..f20dff2d4 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/model/TessellatedModel.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/TessellatedModel.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.model; +package com.jozufozu.flywheel.lib.model.baked; import java.util.Map; diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyBlockGetter.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java similarity index 90% rename from src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyBlockGetter.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java index 34f43497b..125554e54 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyBlockGetter.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyBlockGetter.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.virtualworld; +package com.jozufozu.flywheel.lib.model.baked; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; @@ -99,7 +99,7 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { } @Override - public void onBlockEmissionIncrease(BlockPos pos, int p_164456_) { + public void onBlockEmissionIncrease(BlockPos pos, int emissionLevel) { } @Override @@ -108,16 +108,16 @@ public interface VirtualEmptyBlockGetter extends BlockAndTintGetter { } @Override - public int runUpdates(int p_164449_, boolean p_164450_, boolean p_164451_) { - return p_164449_; + public int runUpdates(int pos, boolean isQueueEmpty, boolean updateBlockLight) { + return pos; } @Override - public void updateSectionStatus(SectionPos pos, boolean p_75838_) { + public void updateSectionStatus(SectionPos pos, boolean isQueueEmpty) { } @Override - public void enableLightSources(ChunkPos pos, boolean p_164453_) { + public void enableLightSources(ChunkPos pos, boolean isQueueEmpty) { } @Override diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyModelData.java b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyModelData.java similarity index 71% rename from src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyModelData.java rename to src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyModelData.java index 8b768ccf0..9aa76083a 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualEmptyModelData.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/baked/VirtualEmptyModelData.java @@ -1,15 +1,16 @@ -package com.jozufozu.flywheel.lib.virtualworld; +package com.jozufozu.flywheel.lib.model.baked; + +import org.jetbrains.annotations.Nullable; import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.data.ModelProperty; /** * This model data instance is passed whenever a model is rendered without - * available in-world context. IBakedModel#getModelData can react accordingly - * and avoid looking for model data itself + * available in-world context. BakedModel#getModelData can react accordingly + * and avoid looking for model data itself. **/ public enum VirtualEmptyModelData implements IModelData { - INSTANCE; public static boolean is(IModelData data) { @@ -22,13 +23,14 @@ public enum VirtualEmptyModelData implements IModelData { } @Override + @Nullable public T getData(ModelProperty prop) { return null; } @Override + @Nullable public T setData(ModelProperty prop, T data) { return null; } - } diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/BlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/BlockModelBuilder.java deleted file mode 100644 index 0008d73eb..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/BlockModelBuilder.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import java.util.function.BiFunction; - -import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.model.Mesh; -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.TessellatedModel; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.BufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; -import com.jozufozu.flywheel.lib.vertex.VertexTypes; -import com.jozufozu.flywheel.lib.virtualworld.VirtualEmptyBlockGetter; -import com.jozufozu.flywheel.lib.virtualworld.VirtualEmptyModelData; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexFormat; - -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.IModelData; - -public class BlockModelBuilder { - private static final int STARTING_CAPACITY = 64; - - private final BlockState state; - private boolean shadeSeparated = true; - private BlockAndTintGetter renderWorld; - private PoseStack poseStack; - private IModelData modelData; - private BiFunction materialFunc; - - public BlockModelBuilder(BlockState state) { - this.state = state; - } - - public BlockModelBuilder disableShadeSeparation() { - shadeSeparated = false; - return this; - } - - public BlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { - this.renderWorld = renderWorld; - return this; - } - - public BlockModelBuilder poseStack(PoseStack poseStack) { - this.poseStack = poseStack; - return this; - } - - public BlockModelBuilder modelData(IModelData modelData) { - this.modelData = modelData; - return this; - } - - public BlockModelBuilder materialFunc(BiFunction materialFunc) { - this.materialFunc = materialFunc; - return this; - } - - @SuppressWarnings("unchecked") - public TessellatedModel build() { - ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); - - if (renderWorld == null) { - renderWorld = VirtualEmptyBlockGetter.INSTANCE; - } - if (poseStack == null) { - poseStack = objects.identityPoseStack; - } - if (modelData == null) { - modelData = VirtualEmptyModelData.INSTANCE; - } - if (materialFunc == null) { - materialFunc = ModelUtil::getMaterial; - } - - ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); - - if (shadeSeparated) { - ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "state=" + state.toString() + ",renderType=" + renderType.toString() + ",shaded=" + shaded)); - } - }; - ModelBufferingUtil.bufferBlockShadeSeparated(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelData, resultConsumer); - } else { - BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ResultConsumer resultConsumer = (renderType, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, false); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "state=" + state.toString() + ",renderType=" + renderType.toString())); - } - }; - ModelBufferingUtil.bufferBlock(ModelUtil.VANILLA_RENDERER, renderWorld, state, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelData, resultConsumer); - } - - return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/LazyDelegatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/LazyDelegatingVertexConsumer.java deleted file mode 100644 index 9406af498..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/LazyDelegatingVertexConsumer.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.model.BakedQuad; - -public interface LazyDelegatingVertexConsumer extends VertexConsumer { - T getDelegate(); - - @Override - default VertexConsumer vertex(double x, double y, double z) { - return getDelegate().vertex(x, y, z); - } - - @Override - default VertexConsumer color(int red, int green, int blue, int alpha) { - return getDelegate().color(red, green, blue, alpha); - } - - @Override - default VertexConsumer uv(float u, float v) { - return getDelegate().uv(u, v); - } - - @Override - default VertexConsumer overlayCoords(int u, int v) { - return getDelegate().overlayCoords(u, v); - } - - @Override - default VertexConsumer uv2(int u, int v) { - return getDelegate().uv2(u, v); - } - - @Override - default VertexConsumer normal(float x, float y, float z) { - return getDelegate().normal(x, y, z); - } - - @Override - default void endVertex() { - getDelegate().endVertex(); - } - - @Override - default void defaultColor(int red, int green, int blue, int alpha) { - getDelegate().defaultColor(red, green, blue, alpha); - } - - @Override - default void unsetDefaultColor() { - getDelegate().unsetDefaultColor(); - } - - @Override - default void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { - getDelegate().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); - } - - @Override - default void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { - getDelegate().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingObjects.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingObjects.java deleted file mode 100644 index d91574699..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingObjects.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import java.util.Random; - -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.BufferWrapper; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatingBufferWrapper; -import com.mojang.blaze3d.vertex.PoseStack; - -public class ModelBufferingObjects { - public static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(ModelBufferingObjects::new); - - public final PoseStack identityPoseStack = new PoseStack(); - @SuppressWarnings("rawtypes") - public final BufferWrapper bufferWrapper = new BufferWrapper<>(); - @SuppressWarnings("rawtypes") - public final ShadeSeparatingBufferWrapper shadeSeparatingBufferWrapper = new ShadeSeparatingBufferWrapper<>(); - public final Random random = new Random(); -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingUtil.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingUtil.java deleted file mode 100644 index 65ec74586..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ModelBufferingUtil.java +++ /dev/null @@ -1,283 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import java.util.Collection; -import java.util.Map; -import java.util.Random; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.ItemBlockRenderTypes; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.BlockRenderDispatcher; -import net.minecraft.client.renderer.block.ModelBlockRenderer; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.RenderShape; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; - -public final class ModelBufferingUtil { - private static final RenderType[] CHUNK_LAYERS = RenderType.chunkBufferLayers().toArray(RenderType[]::new); - private static final int CHUNK_LAYERS_AMOUNT = CHUNK_LAYERS.length; - - public static void bufferSingle(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, IModelData modelData, ResultConsumer resultConsumer) { - bufferWrapper.bufferFactory = bufferFactory; - - for (RenderType type : CHUNK_LAYERS) { - if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { - continue; - } - - bufferWrapper.currentRenderType = type; - bufferWrapper.delegate = null; - - ForgeHooksClient.setRenderType(type); - - poseStack.pushPose(); - blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, bufferWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); - poseStack.popPose(); - - T buffer = bufferWrapper.delegate; - if (buffer != null) { - resultConsumer.accept(type, buffer); - } - } - - ForgeHooksClient.setRenderType(null); - - bufferWrapper.bufferFactory = null; - bufferWrapper.currentRenderType = null; - bufferWrapper.delegate = null; - } - - public static void bufferSingleShadeSeparated(ModelBlockRenderer blockRenderer, BlockAndTintGetter renderWorld, BakedModel model, BlockState state, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { - bufferWrapper.bufferFactory = bufferFactory; - - for (RenderType type : CHUNK_LAYERS) { - if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { - continue; - } - - bufferWrapper.currentRenderType = type; - bufferWrapper.shadedConsumer = null; - bufferWrapper.unshadedConsumer = null; - - ForgeHooksClient.setRenderType(type); - - poseStack.pushPose(); - blockRenderer.tesselateBlock(renderWorld, model, state, BlockPos.ZERO, poseStack, bufferWrapper, false, random, 42L, OverlayTexture.NO_OVERLAY, modelData); - poseStack.popPose(); - - T shadedConsumer = bufferWrapper.shadedConsumer; - T unshadedConsumer = bufferWrapper.unshadedConsumer; - if (shadedConsumer != null) { - resultConsumer.accept(type, true, shadedConsumer); - } - if (unshadedConsumer != null) { - resultConsumer.accept(type, false, unshadedConsumer); - } - } - - ForgeHooksClient.setRenderType(null); - - bufferWrapper.bufferFactory = null; - bufferWrapper.currentRenderType = null; - bufferWrapper.shadedConsumer = null; - bufferWrapper.unshadedConsumer = null; - } - - public static void bufferBlock(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, IModelData modelData, ResultConsumer resultConsumer) { - if (state.getRenderShape() != RenderShape.MODEL) { - return; - } - - bufferSingle(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, bufferFactory, bufferWrapper, random, modelData, resultConsumer); - } - - public static void bufferBlockShadeSeparated(BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, BlockState state, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, IModelData modelData, ShadeSeparatedResultConsumer resultConsumer) { - if (state.getRenderShape() != RenderShape.MODEL) { - return; - } - - bufferSingleShadeSeparated(renderDispatcher.getModelRenderer(), renderWorld, renderDispatcher.getBlockModel(state), state, poseStack, bufferFactory, bufferWrapper, random, modelData, resultConsumer); - } - - public static void bufferMultiBlock(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, PoseStack poseStack, BufferFactory bufferFactory, BufferWrapper bufferWrapper, Random random, Map modelDataMap, ResultConsumer resultConsumer) { - ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); - ModelBlockRenderer.enableCaching(); - - bufferWrapper.bufferFactory = bufferFactory; - @SuppressWarnings("unchecked") - T[] bufferCache = (T[]) new VertexConsumer[CHUNK_LAYERS_AMOUNT]; - - for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { - BlockState state = blockInfo.state; - - if (state.getRenderShape() != RenderShape.MODEL) { - continue; - } - - BakedModel model = renderDispatcher.getBlockModel(state); - BlockPos pos = blockInfo.pos; - long seed = state.getSeed(pos); - IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); - - for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { - RenderType type = CHUNK_LAYERS[layerIndex]; - - if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { - continue; - } - - bufferWrapper.currentRenderType = type; - bufferWrapper.delegate = bufferCache[layerIndex]; - - ForgeHooksClient.setRenderType(type); - - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, bufferWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); - poseStack.popPose(); - - bufferCache[layerIndex] = bufferWrapper.delegate; - } - } - - ForgeHooksClient.setRenderType(null); - ModelBlockRenderer.clearCache(); - - bufferWrapper.bufferFactory = null; - bufferWrapper.currentRenderType = null; - bufferWrapper.delegate = null; - - for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { - T buffer = bufferCache[layerIndex]; - if (buffer != null) { - resultConsumer.accept(CHUNK_LAYERS[layerIndex], buffer); - } - } - } - - public static void bufferMultiBlockShadeSeparated(Collection blocks, BlockRenderDispatcher renderDispatcher, BlockAndTintGetter renderWorld, PoseStack poseStack, ShadeSeparatedBufferFactory bufferFactory, ShadeSeparatingBufferWrapper bufferWrapper, Random random, Map modelDataMap, ShadeSeparatedResultConsumer resultConsumer) { - ModelBlockRenderer blockRenderer = renderDispatcher.getModelRenderer(); - ModelBlockRenderer.enableCaching(); - - bufferWrapper.bufferFactory = bufferFactory; - @SuppressWarnings("unchecked") - T[] bufferCache = (T[]) new VertexConsumer[CHUNK_LAYERS_AMOUNT * 2]; - - for (StructureTemplate.StructureBlockInfo blockInfo : blocks) { - BlockState state = blockInfo.state; - - if (state.getRenderShape() != RenderShape.MODEL) { - continue; - } - - BakedModel model = renderDispatcher.getBlockModel(state); - BlockPos pos = blockInfo.pos; - long seed = state.getSeed(pos); - IModelData modelData = modelDataMap.getOrDefault(pos, EmptyModelData.INSTANCE); - - for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { - RenderType type = CHUNK_LAYERS[layerIndex]; - - if (!ItemBlockRenderTypes.canRenderInLayer(state, type)) { - continue; - } - - bufferWrapper.currentRenderType = type; - bufferWrapper.shadedConsumer = bufferCache[layerIndex]; - bufferWrapper.unshadedConsumer = bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT]; - - ForgeHooksClient.setRenderType(type); - - poseStack.pushPose(); - poseStack.translate(pos.getX(), pos.getY(), pos.getZ()); - blockRenderer.tesselateBlock(renderWorld, model, state, pos, poseStack, bufferWrapper, true, random, seed, OverlayTexture.NO_OVERLAY, modelData); - poseStack.popPose(); - - bufferCache[layerIndex] = bufferWrapper.shadedConsumer; - bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT] = bufferWrapper.unshadedConsumer; - } - } - - ForgeHooksClient.setRenderType(null); - ModelBlockRenderer.clearCache(); - - bufferWrapper.bufferFactory = null; - bufferWrapper.currentRenderType = null; - bufferWrapper.shadedConsumer = null; - bufferWrapper.unshadedConsumer = null; - - for (int layerIndex = 0; layerIndex < CHUNK_LAYERS_AMOUNT; layerIndex++) { - RenderType type = CHUNK_LAYERS[layerIndex]; - T shadedConsumer = bufferCache[layerIndex]; - T unshadedConsumer = bufferCache[layerIndex + CHUNK_LAYERS_AMOUNT]; - if (shadedConsumer != null) { - resultConsumer.accept(type, true, shadedConsumer); - } - if (unshadedConsumer != null) { - resultConsumer.accept(type, false, unshadedConsumer); - } - } - } - - public interface BufferFactory { - T get(RenderType renderType); - } - - public interface ShadeSeparatedBufferFactory { - T get(RenderType renderType, boolean shaded); - } - - public interface ResultConsumer { - void accept(RenderType renderType, T vertexConsumer); - } - - public interface ShadeSeparatedResultConsumer { - void accept(RenderType renderType, boolean shaded, T vertexConsumer); - } - - public static class BufferWrapper implements LazyDelegatingVertexConsumer { - protected BufferFactory bufferFactory; - protected RenderType currentRenderType; - protected T delegate; - - @Override - public T getDelegate() { - if (delegate == null) { - delegate = bufferFactory.get(currentRenderType); - } - return delegate; - } - } - - public static class ShadeSeparatingBufferWrapper implements ShadeSeparatingVertexConsumer { - protected ShadeSeparatedBufferFactory bufferFactory; - protected RenderType currentRenderType; - protected T shadedConsumer; - protected T unshadedConsumer; - - @Override - public T getShadedConsumer() { - if (shadedConsumer == null) { - shadedConsumer = bufferFactory.get(currentRenderType, true); - } - return shadedConsumer; - } - - @Override - public T getUnshadedConsumer() { - if (unshadedConsumer == null) { - unshadedConsumer = bufferFactory.get(currentRenderType, false); - } - return unshadedConsumer; - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/MultiBlockModelBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/MultiBlockModelBuilder.java deleted file mode 100644 index ec4a4d36e..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/MultiBlockModelBuilder.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.function.BiFunction; - -import com.google.common.collect.ImmutableMap; -import com.jozufozu.flywheel.api.material.Material; -import com.jozufozu.flywheel.api.model.Mesh; -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.TessellatedModel; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.BufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ResultConsumer; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedBufferFactory; -import com.jozufozu.flywheel.lib.model.buffering.ModelBufferingUtil.ShadeSeparatedResultConsumer; -import com.jozufozu.flywheel.lib.vertex.VertexTypes; -import com.jozufozu.flywheel.lib.virtualworld.VirtualEmptyBlockGetter; -import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexFormat; - -import net.minecraft.client.renderer.RenderType; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; -import net.minecraftforge.client.model.data.IModelData; - -public class MultiBlockModelBuilder { - private static final int STARTING_CAPACITY = 1024; - - private final Collection blocks; - private boolean shadeSeparated = true; - private VertexFormat vertexFormat; - private BlockAndTintGetter renderWorld; - private PoseStack poseStack; - private Map modelDataMap; - private BiFunction materialFunc; - - public MultiBlockModelBuilder(Collection blocks) { - this.blocks = blocks; - } - - public MultiBlockModelBuilder disableShadeSeparation() { - shadeSeparated = false; - return this; - } - - public MultiBlockModelBuilder renderWorld(BlockAndTintGetter renderWorld) { - this.renderWorld = renderWorld; - return this; - } - - public MultiBlockModelBuilder poseStack(PoseStack poseStack) { - this.poseStack = poseStack; - return this; - } - - public MultiBlockModelBuilder modelDataMap(Map modelDataMap) { - this.modelDataMap = modelDataMap; - return this; - } - - public MultiBlockModelBuilder materialFunc(BiFunction materialFunc) { - this.materialFunc = materialFunc; - return this; - } - - @SuppressWarnings("unchecked") - public TessellatedModel build() { - ModelBufferingObjects objects = ModelBufferingObjects.THREAD_LOCAL.get(); - - if (vertexFormat == null) { - vertexFormat = DefaultVertexFormat.BLOCK; - } - if (renderWorld == null) { - renderWorld = VirtualEmptyBlockGetter.INSTANCE; - } - if (poseStack == null) { - poseStack = objects.identityPoseStack; - } - if (modelDataMap == null) { - modelDataMap = Collections.emptyMap(); - } - if (materialFunc == null) { - materialFunc = ModelUtil::getMaterial; - } - - ImmutableMap.Builder meshMapBuilder = ImmutableMap.builder(); - - if (shadeSeparated) { - ShadeSeparatedBufferFactory bufferFactory = (renderType, shaded) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ShadeSeparatedResultConsumer resultConsumer = (renderType, shaded, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, shaded); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "renderType=" + renderType.toString() + ",shaded=" + shaded)); - } - }; - ModelBufferingUtil.bufferMultiBlockShadeSeparated(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.shadeSeparatingBufferWrapper, objects.random, modelDataMap, resultConsumer); - } else { - BufferFactory bufferFactory = (renderType) -> { - BufferBuilder buffer = new BufferBuilder(STARTING_CAPACITY); - buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK); - return buffer; - }; - ResultConsumer resultConsumer = (renderType, buffer) -> { - buffer.end(); - Material material = materialFunc.apply(renderType, false); - if (material != null) { - MemoryBlock data = ModelUtil.convertVanillaBuffer(buffer.popNextBuffer(), VertexTypes.BLOCK); - meshMapBuilder.put(material, new SimpleMesh(VertexTypes.BLOCK, data, "renderType=" + renderType.toString())); - } - }; - ModelBufferingUtil.bufferMultiBlock(blocks, ModelUtil.VANILLA_RENDERER, renderWorld, poseStack, bufferFactory, objects.bufferWrapper, objects.random, modelDataMap, resultConsumer); - } - - return new TessellatedModel(meshMapBuilder.build(), shadeSeparated); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ShadeSeparatingVertexConsumer.java b/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ShadeSeparatingVertexConsumer.java deleted file mode 100644 index ac32a168e..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/model/buffering/ShadeSeparatingVertexConsumer.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.jozufozu.flywheel.lib.model.buffering; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; - -import net.minecraft.client.renderer.block.model.BakedQuad; - -public interface ShadeSeparatingVertexConsumer extends VertexConsumer { - T getShadedConsumer(); - - T getUnshadedConsumer(); - - @Override - default void putBulkData(PoseStack.Pose poseEntry, BakedQuad quad, float[] colorMuls, float red, float green, float blue, int[] combinedLights, int combinedOverlay, boolean mulColor) { - if (quad.isShade()) { - getShadedConsumer().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); - } else { - getUnshadedConsumer().putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor); - } - } - - @Override - default void putBulkData(PoseStack.Pose matrixEntry, BakedQuad bakedQuad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) { - if (bakedQuad.isShade()) { - getShadedConsumer().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } else { - getUnshadedConsumer().putBulkData(matrixEntry, bakedQuad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor); - } - } - - @Override - default VertexConsumer vertex(double x, double y, double z) { - return getUnshadedConsumer().vertex(x, y, z); - } - - @Override - default VertexConsumer color(int red, int green, int blue, int alpha) { - return getUnshadedConsumer().color(red, green, blue, alpha); - } - - @Override - default VertexConsumer uv(float u, float v) { - return getUnshadedConsumer().uv(u, v); - } - - @Override - default VertexConsumer overlayCoords(int u, int v) { - return getUnshadedConsumer().overlayCoords(u, v); - } - - @Override - default VertexConsumer uv2(int u, int v) { - return getUnshadedConsumer().uv2(u, v); - } - - @Override - default VertexConsumer normal(float x, float y, float z) { - return getUnshadedConsumer().normal(x, y, z); - } - - @Override - default void endVertex() { - getUnshadedConsumer().endVertex(); - } - - @Override - default void defaultColor(int red, int green, int blue, int alpha) { - getUnshadedConsumer().defaultColor(red, green, blue, alpha); - } - - @Override - default void unsetDefaultColor() { - getUnshadedConsumer().unsetDefaultColor(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPartBuilder.java b/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java similarity index 56% rename from src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPartBuilder.java rename to src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java index 84f8aa830..456be6dfc 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPartBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/lib/model/part/ModelPartBuilder.java @@ -1,10 +1,17 @@ -package com.jozufozu.flywheel.lib.modelpart; +package com.jozufozu.flywheel.lib.model.part; import java.util.ArrayList; -import java.util.EnumSet; import java.util.List; -import java.util.Set; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.system.MemoryUtil; + +import com.jozufozu.flywheel.api.model.Mesh; +import com.jozufozu.flywheel.api.vertex.VertexType; +import com.jozufozu.flywheel.lib.math.RenderMath; +import com.jozufozu.flywheel.lib.memory.MemoryBlock; +import com.jozufozu.flywheel.lib.model.SimpleMesh; +import com.jozufozu.flywheel.lib.vertex.VertexTypes; import com.mojang.math.Matrix3f; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; @@ -13,18 +20,18 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.core.Direction; public class ModelPartBuilder { - private final float sizeU; - private final float sizeV; - - private TextureAtlasSprite sprite; + private final String name; + private final float textureWidth; + private final float textureHeight; private final List cuboids = new ArrayList<>(); - private final String name; + @Nullable + private TextureAtlasSprite sprite; - public ModelPartBuilder(String name, int sizeU, int sizeV) { + public ModelPartBuilder(String name, int textureWidth, int textureHeight) { this.name = name; - this.sizeU = (float) sizeU; - this.sizeV = (float) sizeV; + this.textureWidth = (float) textureWidth; + this.textureHeight = (float) textureHeight; } public ModelPartBuilder sprite(TextureAtlasSprite sprite) { @@ -33,11 +40,7 @@ public class ModelPartBuilder { } public CuboidBuilder cuboid() { - return new CuboidBuilder(this); - } - - public ModelPart build() { - return new ModelPart(cuboids, name); + return new CuboidBuilder(); } private ModelPartBuilder addCuboid(CuboidBuilder builder) { @@ -45,10 +48,23 @@ public class ModelPartBuilder { return this; } - public static class CuboidBuilder { + public Mesh build() { + VertexType vertexType = VertexTypes.POS_TEX_NORMAL; + int vertices = cuboids.size() * 24; + MemoryBlock contents = MemoryBlock.malloc(vertexType.getLayout().getStride() * vertices); + + long ptr = contents.ptr(); + VertexWriter writer = new VertexWriter(ptr); + for (CuboidBuilder cuboid : cuboids) { + cuboid.write(writer); + } + + return new SimpleMesh(vertexType, contents, name); + } + + public class CuboidBuilder { private TextureAtlasSprite sprite; - private Set visibleFaces = EnumSet.allOf(Direction.class); private int textureOffsetU; private int textureOffsetV; @@ -59,44 +75,46 @@ public class ModelPartBuilder { private float posY2; private float posZ2; - private boolean invertYZ; - private boolean useRotation; private float rotationX; private float rotationY; private float rotationZ; - private final ModelPartBuilder partBuilder; + private boolean invertYZ; - private CuboidBuilder(ModelPartBuilder partBuilder) { - this.partBuilder = partBuilder; - this.sprite = partBuilder.sprite; + private CuboidBuilder() { + sprite = ModelPartBuilder.this.sprite; + } + + public CuboidBuilder sprite(TextureAtlasSprite sprite) { + this.sprite = sprite; + return this; } public CuboidBuilder textureOffset(int u, int v) { - this.textureOffsetU = u; - this.textureOffsetV = v; + textureOffsetU = u; + textureOffsetV = v; return this; } public CuboidBuilder start(float x, float y, float z) { - this.posX1 = x; - this.posY1 = y; - this.posZ1 = z; + posX1 = x; + posY1 = y; + posZ1 = z; return this; } public CuboidBuilder end(float x, float y, float z) { - this.posX2 = x; - this.posY2 = y; - this.posZ2 = z; + posX2 = x; + posY2 = y; + posZ2 = z; return this; } public CuboidBuilder size(float x, float y, float z) { - this.posX2 = posX1 + x; - this.posY2 = posY1 + y; - this.posZ2 = posZ1 + z; + posX2 = posX1 + x; + posY2 = posY1 + y; + posZ2 = posZ1 + z; return this; } @@ -112,32 +130,27 @@ public class ModelPartBuilder { public CuboidBuilder rotate(float x, float y, float z) { useRotation = true; - this.rotationX = x; - this.rotationY = y; - this.rotationZ = z; + rotationX = x; + rotationY = y; + rotationZ = z; return this; } public CuboidBuilder rotateX(float x) { useRotation = true; - this.rotationX = x; + rotationX = x; return this; } public CuboidBuilder rotateY(float y) { useRotation = true; - this.rotationY = y; + rotationY = y; return this; } public CuboidBuilder rotateZ(float z) { useRotation = true; - this.rotationZ = z; - return this; - } - - public CuboidBuilder sprite(TextureAtlasSprite sprite) { - this.sprite = sprite; + rotationZ = z; return this; } @@ -145,19 +158,15 @@ public class ModelPartBuilder { * Pulls the cuboid "inside out" through the Y and Z axes. */ public CuboidBuilder invertYZ() { - this.invertYZ = true; + invertYZ = true; return this; } public ModelPartBuilder endCuboid() { - return partBuilder.addCuboid(this); + return ModelPartBuilder.this.addCuboid(this); } - public int vertices() { - return visibleFaces.size() * 4; - } - - public void write(VertexWriter writer) { + private void write(VertexWriter writer) { float sizeX = posX2 - posX1; float sizeY = posY2 - posY1; float sizeZ = posZ2 - posZ1; @@ -215,41 +224,64 @@ public class ModelPartBuilder { float f12 = getV((float)textureOffsetV + sizeZ + sizeY); if (invertYZ) { - quad(writer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down); - quad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up); - quad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west); - quad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north); - quad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east); - quad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south); + writeQuad(writer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down); + writeQuad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up); + writeQuad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west); + writeQuad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north); + writeQuad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east); + writeQuad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south); } else { - quad(writer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down); - quad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up); - quad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west); - quad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north); - quad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east); - quad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south); + writeQuad(writer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down); + writeQuad(writer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up); + writeQuad(writer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west); + writeQuad(writer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north); + writeQuad(writer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east); + writeQuad(writer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south); } } - public void quad(VertexWriter writer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { + private void writeQuad(VertexWriter writer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) { writer.putVertex(vertices[0].x(), vertices[0].y(), vertices[0].z(), maxU, minV, normal.x(), normal.y(), normal.z()); writer.putVertex(vertices[1].x(), vertices[1].y(), vertices[1].z(), minU, minV, normal.x(), normal.y(), normal.z()); writer.putVertex(vertices[2].x(), vertices[2].y(), vertices[2].z(), minU, maxV, normal.x(), normal.y(), normal.z()); writer.putVertex(vertices[3].x(), vertices[3].y(), vertices[3].z(), maxU, maxV, normal.x(), normal.y(), normal.z()); } - public float getU(float u) { - if (sprite != null) - return sprite.getU(u * 16 / partBuilder.sizeU); - else - return u / partBuilder.sizeU; + private float getU(float u) { + if (sprite != null) { + return sprite.getU(u * 16 / textureWidth); + } else { + return u / textureWidth; + } } - public float getV(float v) { - if (sprite != null) - return sprite.getV(v * 16 / partBuilder.sizeV); - else - return v / partBuilder.sizeV; + private float getV(float v) { + if (sprite != null) { + return sprite.getV(v * 16 / textureHeight); + } else { + return v / textureHeight; + } + } + } + + private static class VertexWriter { + private long ptr; + + public VertexWriter(long ptr) { + this.ptr = ptr; + } + + public void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ) { + MemoryUtil.memPutFloat(ptr, x); + MemoryUtil.memPutFloat(ptr + 4, y); + MemoryUtil.memPutFloat(ptr + 8, z); + MemoryUtil.memPutFloat(ptr + 12, u); + MemoryUtil.memPutFloat(ptr + 16, v); + MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(nX)); + MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(nY)); + MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ)); + + ptr += 23; } } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPart.java b/src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPart.java deleted file mode 100644 index c5596bf8b..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/modelpart/ModelPart.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.jozufozu.flywheel.lib.modelpart; - -import java.util.List; - -import org.joml.Vector4f; -import org.joml.Vector4fc; - -import com.jozufozu.flywheel.api.vertex.MutableVertexList; -import com.jozufozu.flywheel.api.vertex.ReusableVertexList; -import com.jozufozu.flywheel.lib.memory.MemoryBlock; -import com.jozufozu.flywheel.lib.model.ModelUtil; -import com.jozufozu.flywheel.lib.model.QuadMesh; -import com.jozufozu.flywheel.lib.vertex.PosTexNormalVertex; -import com.jozufozu.flywheel.lib.vertex.VertexTypes; - -public class ModelPart implements QuadMesh { - private final int vertexCount; - private final MemoryBlock contents; - private final ReusableVertexList vertexList; - private final Vector4f boundingSphere; - private final String name; - - public ModelPart(List cuboids, String name) { - this.name = name; - - this.vertexCount = countVertices(cuboids); - - contents = MemoryBlock.malloc(size()); - long ptr = contents.ptr(); - VertexWriter writer = new VertexWriterImpl(ptr); - for (ModelPartBuilder.CuboidBuilder cuboid : cuboids) { - cuboid.write(writer); - } - - vertexList = vertexType().createVertexList(); - vertexList.ptr(ptr); - vertexList.vertexCount(vertexCount); - - boundingSphere = ModelUtil.computeBoundingSphere(vertexList); - } - - public static ModelPartBuilder builder(String name, int sizeU, int sizeV) { - return new ModelPartBuilder(name, sizeU, sizeV); - } - - @Override - public PosTexNormalVertex vertexType() { - return VertexTypes.POS_TEX_NORMAL; - } - - @Override - public int vertexCount() { - return vertexCount; - } - - @Override - public void write(long ptr) { - contents.copyTo(ptr); - } - - @Override - public void write(MutableVertexList dst) { - vertexList.writeAll(dst); - } - - @Override - public Vector4fc boundingSphere() { - return boundingSphere; - } - - @Override - public void delete() { - contents.free(); - } - - @Override - public String name() { - return name; - } - - private static int countVertices(List cuboids) { - int vertices = 0; - for (ModelPartBuilder.CuboidBuilder cuboid : cuboids) { - vertices += cuboid.vertices(); - } - return vertices; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriter.java b/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriter.java deleted file mode 100644 index 09efa6bcc..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.jozufozu.flywheel.lib.modelpart; - -public interface VertexWriter { - void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ); -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriterImpl.java b/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriterImpl.java deleted file mode 100644 index 125e7526b..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/modelpart/VertexWriterImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.jozufozu.flywheel.lib.modelpart; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.lib.math.RenderMath; - -public class VertexWriterImpl implements VertexWriter { - private long ptr; - - public VertexWriterImpl(long ptr) { - this.ptr = ptr; - } - - @Override - public void putVertex(float x, float y, float z, float u, float v, float nX, float nY, float nZ) { - MemoryUtil.memPutFloat(ptr, x); - MemoryUtil.memPutFloat(ptr + 4, y); - MemoryUtil.memPutFloat(ptr + 8, z); - MemoryUtil.memPutFloat(ptr + 12, u); - MemoryUtil.memPutFloat(ptr + 16, v); - MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(nX)); - MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(nY)); - MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(nZ)); - - ptr += 23; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/task/PlanUtil.java b/src/main/java/com/jozufozu/flywheel/lib/task/PlanUtil.java index 352cc249e..5cda49541 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/task/PlanUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/task/PlanUtil.java @@ -7,7 +7,7 @@ import java.util.function.BiConsumer; import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.lib.math.MoreMath; -public class PlanUtil { +public final class PlanUtil { public static void distribute(TaskExecutor taskExecutor, C context, Runnable onCompletion, List list, BiConsumer action) { final int size = list.size(); @@ -93,4 +93,7 @@ public class PlanUtil { public static int sliceSize(TaskExecutor taskExecutor, int totalSize) { return MoreMath.ceilingDiv(totalSize, taskExecutor.getThreadCount() * 32); } + + private PlanUtil() { + } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/transform/Rotate.java b/src/main/java/com/jozufozu/flywheel/lib/transform/Rotate.java index 2f7c4cc89..cb068cd58 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/transform/Rotate.java +++ b/src/main/java/com/jozufozu/flywheel/lib/transform/Rotate.java @@ -6,9 +6,9 @@ import com.mojang.math.Vector3f; import net.minecraft.core.Direction; public interface Rotate { - Self multiply(Quaternion quaternion); + @SuppressWarnings("unchecked") default Self rotate(Direction axis, float radians) { if (radians == 0) return (Self) this; @@ -46,18 +46,21 @@ public interface Rotate { return multiplyRadians(Vector3f.ZP, angle); } + @SuppressWarnings("unchecked") default Self multiply(Vector3f axis, double angle) { if (angle == 0) return (Self) this; return multiply(axis.rotationDegrees((float) angle)); } + @SuppressWarnings("unchecked") default Self multiplyRadians(Vector3f axis, double angle) { if (angle == 0) return (Self) this; return multiply(axis.rotation((float) angle)); } + @SuppressWarnings("unchecked") default Self rotateToFace(Direction facing) { switch (facing) { case SOUTH -> multiply(Vector3f.YP.rotationDegrees(180)); diff --git a/src/main/java/com/jozufozu/flywheel/lib/transform/Transform.java b/src/main/java/com/jozufozu/flywheel/lib/transform/Transform.java index 4d1aa8b82..4805f74ca 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/transform/Transform.java +++ b/src/main/java/com/jozufozu/flywheel/lib/transform/Transform.java @@ -22,12 +22,14 @@ public interface Transform> extends Translate return transform(last.pose(), last.normal()); } + @SuppressWarnings("unchecked") default Self rotateCentered(Direction axis, float radians) { translate(.5f, .5f, .5f).rotate(axis, radians) .translate(-.5f, -.5f, -.5f); return (Self) this; } + @SuppressWarnings("unchecked") default Self rotateCentered(Quaternion q) { translate(.5f, .5f, .5f).multiply(q) .translate(-.5f, -.5f, -.5f); diff --git a/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java b/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java index b33e94a0b..f24736d78 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java +++ b/src/main/java/com/jozufozu/flywheel/lib/uniform/FlwShaderUniforms.java @@ -8,7 +8,7 @@ import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.event.BeginFrameEvent; import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.uniform.ShaderUniforms; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.lib.math.MatrixUtil; import com.jozufozu.flywheel.lib.math.MoreMath; import com.mojang.blaze3d.systems.RenderSystem; @@ -73,7 +73,8 @@ public class FlwShaderUniforms implements ShaderUniforms { } RenderContext context = event.getContext(); - Vec3i renderOrigin = VisualizedRenderDispatcher.getRenderOrigin(context.level()); + Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level()) + .getRenderOrigin(); Vec3 camera = context.camera() .getPosition(); diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/AnimationTickHolder.java b/src/main/java/com/jozufozu/flywheel/lib/util/AnimationTickHolder.java deleted file mode 100644 index f4b36be02..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/util/AnimationTickHolder.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.jozufozu.flywheel.lib.util; - -import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; - -import net.minecraft.client.Minecraft; - -/** - * Static access to tick-count and partialTick time, accounting for pausing. - */ -public final class AnimationTickHolder { - // Wrap around every 24 hours to maintain floating point accuracy. - private static final int WRAPPING_INTERVAL = 1_728_000; - private static int ticks; - private static int pausedTicks; - - public static void tick() { - if (!Minecraft.getInstance() - .isPaused()) { - ticks = (ticks + 1) % WRAPPING_INTERVAL; - } else { - pausedTicks = (pausedTicks + 1) % WRAPPING_INTERVAL; - } - } - - public static int getTicks() { - return getTicks(false); - } - - public static int getTicks(boolean includePaused) { - return includePaused ? ticks + pausedTicks : ticks; - } - - public static float getRenderTime() { - return getTicks() + getPartialTicks(); - } - - public static float getPartialTicks() { - Minecraft mc = Minecraft.getInstance(); - return (mc.isPaused() ? ((PausedPartialTickAccessor) mc).flywheel$getPausePartialTick() : mc.getFrameTime()); - } - - // Unused but might be useful for debugging. - public static void _reset() { - ticks = 0; - pausedTicks = 0; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/lib/util/FlwUtil.java new file mode 100644 index 000000000..60daa2fb8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/util/FlwUtil.java @@ -0,0 +1,42 @@ +package com.jozufozu.flywheel.lib.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.WeakHashMap; + +import com.mojang.blaze3d.vertex.PoseStack; + +import net.minecraft.client.Minecraft; + +public final class FlwUtil { + private FlwUtil() { + } + + public static boolean isGameActive() { + return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null); + } + + public static Set createWeakHashSet() { + return Collections.newSetFromMap(new WeakHashMap<>()); + } + + public static PoseStack copyPoseStack(PoseStack stack) { + PoseStack copy = new PoseStack(); + copy.last() + .pose() + .load(stack.last() + .pose()); + copy.last() + .normal() + .load(stack.last() + .normal()); + return copy; + } + + public static int[] initArray(int size, int fill) { + var out = new int[size]; + Arrays.fill(out, fill); + return out; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java deleted file mode 100644 index aed6f4591..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/util/FullscreenQuad.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.jozufozu.flywheel.lib.util; - -import static org.lwjgl.opengl.GL11.GL_TRIANGLES; -import static org.lwjgl.opengl.GL11.glDrawArrays; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.Flywheel; -import com.jozufozu.flywheel.api.layout.BufferLayout; -import com.jozufozu.flywheel.gl.GlStateTracker; -import com.jozufozu.flywheel.gl.array.GlVertexArray; -import com.jozufozu.flywheel.gl.buffer.GlBuffer; -import com.jozufozu.flywheel.gl.buffer.MappedBuffer; -import com.jozufozu.flywheel.lib.layout.CommonItems; -import com.jozufozu.flywheel.util.Lazy; - -public class FullscreenQuad { - - public static final Lazy INSTANCE = Lazy.of(FullscreenQuad::new); - private static final BufferLayout LAYOUT = BufferLayout.builder() - .addItem(CommonItems.VEC4, "posTex") - .build(); - - private static final float[] vertices = { - // pos // tex - -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, - - -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f}; - - private static final int bufferSize = vertices.length * 4; - - private final GlVertexArray vao; - private final GlBuffer vbo; - - private FullscreenQuad() { - try (var restoreState = GlStateTracker.getRestoreState()) { - vbo = new GlBuffer(); - vbo.ensureCapacity(bufferSize); - try (MappedBuffer buffer = vbo.map()) { - var ptr = buffer.ptr(); - - for (var i = 0; i < vertices.length; i++) { - MemoryUtil.memPutFloat(ptr + i * Float.BYTES, vertices[i]); - } - - } catch (Exception e) { - Flywheel.LOGGER.error("Could not create fullscreen quad.", e); - } - - vao = GlVertexArray.create(); - - vao.bindVertexBuffer(0, vbo.handle(), 0L, LAYOUT.getStride()); - vao.bindAttributes(0, 0, LAYOUT.attributes()); - } - } - - /** - * Draw the fullscreen quad.
- * note: may bind a VAO, but will not restore prior state. - */ - public void draw() { - vao.bindForDraw(); - glDrawArrays(GL_TRIANGLES, 0, 6); - } - - public void delete() { - vao.delete(); - vbo.delete(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java b/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java new file mode 100644 index 000000000..e6139c2a8 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/util/LevelAttached.java @@ -0,0 +1,95 @@ +package com.jozufozu.flywheel.lib.util; + +import java.lang.ref.Cleaner; +import java.lang.ref.WeakReference; +import java.util.Iterator; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.jetbrains.annotations.ApiStatus; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +import net.minecraft.world.level.LevelAccessor; +import net.minecraftforge.event.world.WorldEvent; + +// FIXME +public final class LevelAttached { + private static final ConcurrentLinkedDeque>> ALL = new ConcurrentLinkedDeque<>(); + private static final Cleaner CLEANER = Cleaner.create(); + + private final LoadingCache cache; + + public LevelAttached(Function factory, Consumer finalizer) { + WeakReference> thisRef = new WeakReference<>(this); + ALL.add(thisRef); + + cache = CacheBuilder.newBuilder() + .removalListener(n -> finalizer.accept(n.getValue())) + .build(new CacheLoader<>() { + @Override + public T load(LevelAccessor key) { + return factory.apply(key); + } + }); + + CLEANER.register(this, new CleaningAction(thisRef, cache)); + } + + public LevelAttached(Function factory) { + this(factory, t -> {}); + } + + @ApiStatus.Internal + public static void onUnloadLevel(WorldEvent.Unload event) { + invalidateLevel(event.getWorld()); + } + + public static void invalidateLevel(LevelAccessor level) { + Iterator>> iterator = ALL.iterator(); + while (iterator.hasNext()) { + LevelAttached attached = iterator.next().get(); + if (attached == null) { + iterator.remove(); + } else { + attached.remove(level); + } + } + } + + public T get(LevelAccessor level) { + return cache.getUnchecked(level); + } + + public void remove(LevelAccessor level) { + cache.invalidate(level); + } + + public T refresh(LevelAccessor level) { + remove(level); + return get(level); + } + + public void reset() { + cache.invalidateAll(); + } + + private static class CleaningAction implements Runnable { + private final WeakReference> ref; + private final LoadingCache cache; + + private CleaningAction(WeakReference> ref, LoadingCache cache) { + this.ref = ref; + this.cache = cache; + } + + @Override + public void run() { + ALL.remove(ref); + cache.invalidateAll(); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/Pair.java b/src/main/java/com/jozufozu/flywheel/lib/util/Pair.java similarity index 64% rename from src/main/java/com/jozufozu/flywheel/util/Pair.java rename to src/main/java/com/jozufozu/flywheel/lib/util/Pair.java index bc7dd61bb..1ad63730a 100644 --- a/src/main/java/com/jozufozu/flywheel/util/Pair.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/Pair.java @@ -1,18 +1,12 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.lib.util; import java.util.Objects; -import java.util.function.Function; public record Pair(F first, S second) { - public static Pair of(F first, S second) { return new Pair<>(first, second); } - public static Function, Pair> both(Function map) { - return pair -> of(map.apply(pair.first), map.apply(pair.second)); - } - public Pair swap() { return Pair.of(second, first); } @@ -32,16 +26,11 @@ public record Pair(F first, S second) { @Override public int hashCode() { - return (nullHash(first) * 31) ^ nullHash(second); + return (Objects.hashCode(first) * 31) ^ Objects.hashCode(second); } @Override public String toString() { return "(" + first + ", " + second + ")"; } - - static int nullHash(Object o) { - return o == null ? 0 : o.hashCode(); - } - } diff --git a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java b/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java similarity index 79% rename from src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java rename to src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java index 0a3de1daa..bc33b45db 100644 --- a/src/main/java/com/jozufozu/flywheel/util/ResourceUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/ResourceUtil.java @@ -1,7 +1,9 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.lib.util; import java.util.regex.Pattern; +import com.jozufozu.flywheel.Flywheel; + import net.minecraft.resources.ResourceLocation; public class ResourceUtil { @@ -9,16 +11,18 @@ public class ResourceUtil { private static final Pattern UNSAFE_CHARS = Pattern.compile("[^a-zA-Z0-9_]"); public static ResourceLocation defaultToFlywheelNamespace(String location) { - String[] astring = new String[]{"flywheel", location}; - int i = location.indexOf(':'); + String namespace = Flywheel.ID; + String path = location; + + int i = location.indexOf(ResourceLocation.NAMESPACE_SEPARATOR); if (i >= 0) { - astring[1] = location.substring(i + 1); + path = location.substring(i + 1); if (i >= 1) { - astring[0] = location.substring(0, i); + namespace = location.substring(0, i); } } - return new ResourceLocation(astring[0], astring[1]); + return new ResourceLocation(namespace, path); } public static ResourceLocation subPath(ResourceLocation root, String subPath) { diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/ShadersModHandler.java b/src/main/java/com/jozufozu/flywheel/lib/util/ShadersModHandler.java index 9b1435663..1c70cd4c9 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/util/ShadersModHandler.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/ShadersModHandler.java @@ -1,26 +1,20 @@ package com.jozufozu.flywheel.lib.util; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.function.BooleanSupplier; -import javax.annotation.Nullable; - import org.jetbrains.annotations.ApiStatus; import org.slf4j.Logger; import com.mojang.logging.LogUtils; import net.irisshaders.iris.api.v0.IrisApi; -import net.minecraft.client.Camera; -import net.minecraft.client.renderer.culling.Frustum; import net.minecraftforge.fml.ModList; public final class ShadersModHandler { private static final Logger LOGGER = LogUtils.getLogger(); - public static final String OPTIFINE_ROOT_PACKAGE = "net.optifine"; - public static final String OPTIFINE_SHADER_PACKAGE = "net.optifine.shaders"; + private static final String OPTIFINE_ROOT_PACKAGE = "net.optifine"; private static final boolean IS_OCULUS_LOADED; private static final boolean IS_OPTIFINE_INSTALLED; @@ -32,7 +26,7 @@ public final class ShadersModHandler { IS_OCULUS_LOADED = ModList.get() .isLoaded("oculus"); - // optfine and oculus are assumed to be mutually exclusive + // OptiFine and Oculus are assumed to be mutually exclusive if (IS_OPTIFINE_INSTALLED) { LOGGER.info("Optifine detected."); @@ -46,6 +40,9 @@ public final class ShadersModHandler { } } + private ShadersModHandler() { + } + public static boolean isOculusLoaded() { return IS_OCULUS_LOADED; } @@ -66,9 +63,6 @@ public final class ShadersModHandler { public static void init() { } - private ShadersModHandler() { - } - private interface InternalHandler { default boolean isShaderPackInUse() { return false; @@ -98,12 +92,10 @@ public final class ShadersModHandler { private static class Optifine implements InternalHandler { private final BooleanSupplier shadersEnabledSupplier; private final BooleanSupplier shadowPassSupplier; - private final FrustumConstructor shadowFrustumConstructor; Optifine() { shadersEnabledSupplier = createShadersEnabledSupplier(); shadowPassSupplier = createShadowPassSupplier(); - shadowFrustumConstructor = createShadowFrustumConstructor(); } @Override @@ -116,50 +108,6 @@ public final class ShadersModHandler { return shadowPassSupplier.getAsBoolean(); } - @Nullable - public Frustum createShadowFrustum(Camera camera, float partialTicks) { - var frustum = shadowFrustumConstructor.create(camera, partialTicks); - if (frustum != null) { - var position = camera.getPosition(); - frustum.prepare(position.x, position.y, position.z); - } - return frustum; - } - - private static FrustumConstructor createShadowFrustumConstructor() { - try { - Class ofShaders = Class.forName("net.optifine.shaders.ShadersRender"); - Method method = ofShaders.getDeclaredMethod("makeShadowFrustum", Camera.class, Float.TYPE); - method.setAccessible(true); - return (cam, pt) -> { - try { - return (Frustum) method.invoke(null, cam, pt); - } catch (Exception ignored) { - return null; - } - }; - } catch (Exception ignored) { - return ($, $$) -> null; - } - } - - private static BooleanSupplier createShadowPassSupplier() { - try { - Class ofShaders = Class.forName("net.optifine.shaders.Shaders"); - Field field = ofShaders.getDeclaredField("isShadowPass"); - field.setAccessible(true); - return () -> { - try { - return field.getBoolean(null); - } catch (IllegalAccessException ignored) { - return false; - } - }; - } catch (Exception ignored) { - return () -> false; - } - } - private static BooleanSupplier createShadersEnabledSupplier() { try { Class ofShaders = Class.forName("net.optifine.shaders.Shaders"); @@ -177,10 +125,21 @@ public final class ShadersModHandler { } } - @FunctionalInterface - public interface FrustumConstructor { - @Nullable - Frustum create(Camera camera, float partialTicks); + private static BooleanSupplier createShadowPassSupplier() { + try { + Class ofShaders = Class.forName("net.optifine.shaders.Shaders"); + Field field = ofShaders.getDeclaredField("isShadowPass"); + field.setAccessible(true); + return () -> { + try { + return field.getBoolean(null); + } catch (IllegalAccessException ignored) { + return false; + } + }; + } catch (Exception ignored) { + return () -> false; + } } } } diff --git a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java b/src/main/java/com/jozufozu/flywheel/lib/util/StringUtil.java similarity index 59% rename from src/main/java/com/jozufozu/flywheel/util/StringUtil.java rename to src/main/java/com/jozufozu/flywheel/lib/util/StringUtil.java index 59f3296e7..f2e842712 100644 --- a/src/main/java/com/jozufozu/flywheel/util/StringUtil.java +++ b/src/main/java/com/jozufozu/flywheel/lib/util/StringUtil.java @@ -1,28 +1,17 @@ -package com.jozufozu.flywheel.util; +package com.jozufozu.flywheel.lib.util; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.Nonnull; - -import org.lwjgl.system.MemoryUtil; - -import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; - -public class StringUtil { +public final class StringUtil { private static final NumberFormat THREE_DECIMAL_PLACES = new DecimalFormat("#0.000"); + private StringUtil() { + } + public static int countLines(String s) { int lines = 1; int length = s.length(); @@ -69,7 +58,6 @@ public class StringUtil { } public static String args(String functionName, Object... args) { - return functionName + '(' + Arrays.stream(args) .map(Object::toString) .collect(Collectors.joining(", ")) + ')'; @@ -110,54 +98,6 @@ public class StringUtil { return stream.collect(Collectors.joining("\n")); } - @Nonnull - public static String readToString(InputStream is) throws IOException { - ByteBuffer bytebuffer = null; - - try { - bytebuffer = readToBuffer(is); - int i = bytebuffer.position(); - ((Buffer) bytebuffer).rewind(); - return MemoryUtil.memASCII(bytebuffer, i); - } finally { - if (bytebuffer != null) { - FlwMemoryTracker.freeBuffer(bytebuffer); - } - } - } - - @Nonnull - public static ByteBuffer readToBuffer(InputStream is) throws IOException { - if (is instanceof FileInputStream fileinputstream) { - return readFileInputStream(fileinputstream); - } else { - return readInputStream(is); - } - } - - @Nonnull - private static ByteBuffer readInputStream(InputStream is) throws IOException { - ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer(8192); - ReadableByteChannel readablebytechannel = Channels.newChannel(is); - - while (readablebytechannel.read(bytebuffer) != -1) { - if (bytebuffer.remaining() == 0) { - bytebuffer = FlwMemoryTracker.reallocBuffer(bytebuffer, bytebuffer.capacity() * 2); - } - } - return bytebuffer; - } - - @Nonnull - private static ByteBuffer readFileInputStream(FileInputStream fileinputstream) throws IOException { - FileChannel filechannel = fileinputstream.getChannel(); - ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer((int) filechannel.size() + 1); - - while (filechannel.read(bytebuffer) != -1) { - } - return bytebuffer; - } - public static String repeatChar(char c, int n) { char[] arr = new char[n]; diff --git a/src/main/java/com/jozufozu/flywheel/lib/util/Unit.java b/src/main/java/com/jozufozu/flywheel/lib/util/Unit.java new file mode 100644 index 000000000..7a257f4a0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/util/Unit.java @@ -0,0 +1,5 @@ +package com.jozufozu.flywheel.lib.util; + +public enum Unit { + INSTANCE; +} diff --git a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java b/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java index 6d87ca504..2cba218d2 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java +++ b/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTransformations.java @@ -6,6 +6,9 @@ import com.mojang.math.Matrix3f; import com.mojang.math.Matrix4f; public final class VertexTransformations { + private VertexTransformations() { + } + public static void transformPos(MutableVertexList vertexList, int index, Matrix4f matrix) { float x = vertexList.x(index); float y = vertexList.y(index); diff --git a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTypes.java b/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTypes.java index 071d209da..ce7f684c3 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTypes.java +++ b/src/main/java/com/jozufozu/flywheel/lib/vertex/VertexTypes.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.ApiStatus; import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.vertex.VertexType; -import com.jozufozu.flywheel.util.ResourceUtil; +import com.jozufozu.flywheel.lib.util.ResourceUtil; import net.minecraft.resources.ResourceLocation; @@ -12,6 +12,9 @@ public final class VertexTypes { public static final BlockVertex BLOCK = VertexType.REGISTRY.registerAndGet(new BlockVertex()); public static final PosTexNormalVertex POS_TEX_NORMAL = VertexType.REGISTRY.registerAndGet(new PosTexNormalVertex()); + private VertexTypes() { + } + @ApiStatus.Internal public static void init() { } diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunk.java b/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunk.java deleted file mode 100644 index 382bd863e..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunk.java +++ /dev/null @@ -1,257 +0,0 @@ -package com.jozufozu.flywheel.lib.virtualworld; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import org.jetbrains.annotations.Nullable; - -import com.jozufozu.flywheel.util.Mods; - -import ca.spottedleaf.starlight.common.chunk.ExtendedChunk; -import ca.spottedleaf.starlight.common.light.StarLightEngine; -import it.unimi.dsi.fastutil.longs.LongSet; -import it.unimi.dsi.fastutil.longs.LongSets; -import it.unimi.dsi.fastutil.shorts.ShortList; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature; -import net.minecraft.world.level.levelgen.structure.StructureStart; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.ticks.BlackholeTickAccess; -import net.minecraft.world.ticks.TickContainerAccess; - -public class VirtualChunk extends ChunkAccess { - - final VirtualRenderWorld world; - boolean needsLight; - final int x; - final int z; - - private final LevelChunkSection[] sections; - - public VirtualChunk(VirtualRenderWorld world, int x, int z) { - super(new ChunkPos(x, z), UpgradeData.EMPTY, world, world.registryAccess() - .registry(Registry.BIOME_REGISTRY) - .orElseThrow(), 0L, null, null); - - this.world = world; - this.needsLight = true; - this.x = x; - this.z = z; - - int sectionCount = world.getSectionsCount(); - this.sections = new LevelChunkSection[sectionCount]; - - for (int i = 0; i < sectionCount; i++) { - sections[i] = new VirtualChunkSection(this, i << 4); - } - - Mods.STARLIGHT.executeIfInstalled(() -> () -> { - ((ExtendedChunk)this).setBlockNibbles(StarLightEngine.getFilledEmptyLight(this)); - ((ExtendedChunk)this).setSkyNibbles(StarLightEngine.getFilledEmptyLight(this)); - }); - } - - @Override - public Stream getLights() { - return world.blocksAdded.entrySet() - .stream() - .filter(it -> { - BlockPos blockPos = it.getKey(); - boolean chunkContains = blockPos.getX() >> 4 == x && blockPos.getZ() >> 4 == z; - return chunkContains && it.getValue() - .getLightEmission(world, blockPos) != 0; - }) - .map(Map.Entry::getKey); - } - - @Override - public LevelChunkSection[] getSections() { - return sections; - } - - @Override - public ChunkStatus getStatus() { - return ChunkStatus.LIGHT; - } - - @Nullable - @Override - public BlockState setBlockState(BlockPos p_177436_1_, BlockState p_177436_2_, boolean p_177436_3_) { - return null; - } - - @Override - public void setBlockEntity(BlockEntity p_177426_2_) {} - - @Override - public void addEntity(Entity p_76612_1_) {} - - @Override - public Set getBlockEntitiesPos() { - return null; - } - - @Override - public Collection> getHeightmaps() { - return null; - } - - @Override - public void setHeightmap(Heightmap.Types p_201607_1_, long[] p_201607_2_) {} - - @Override - public Heightmap getOrCreateHeightmapUnprimed(Heightmap.Types p_217303_1_) { - return null; - } - - @Override - public int getHeight(Heightmap.Types p_201576_1_, int p_201576_2_, int p_201576_3_) { - return 0; - } - - @Override - public void setUnsaved(boolean p_177427_1_) {} - - @Override - public boolean isUnsaved() { - return false; - } - - @Override - public void removeBlockEntity(BlockPos p_177425_1_) {} - - @Override - public ShortList[] getPostProcessing() { - return new ShortList[0]; - } - - @Nullable - @Override - public CompoundTag getBlockEntityNbt(BlockPos p_201579_1_) { - return null; - } - - @Nullable - @Override - public CompoundTag getBlockEntityNbtForSaving(BlockPos p_223134_1_) { - return null; - } - - @Override - public UpgradeData getUpgradeData() { - return null; - } - - @Override - public void setInhabitedTime(long p_177415_1_) {} - - @Override - public long getInhabitedTime() { - return 0; - } - - @Override - public boolean isLightCorrect() { - return needsLight; - } - - @Override - public void setLightCorrect(boolean needsLight) { - this.needsLight = needsLight; - } - - @Nullable - @Override - public BlockEntity getBlockEntity(BlockPos pos) { - return null; - } - - @Override - public BlockState getBlockState(BlockPos pos) { - return world.getBlockState(pos); - } - - @Override - public FluidState getFluidState(BlockPos p_204610_1_) { - return null; - } - - @Override - @Nullable - public StructureStart getStartForFeature(ConfiguredStructureFeature pStructure) { - return null; - } - - @Override - public void setStartForFeature(ConfiguredStructureFeature pStructure, StructureStart pStart) { - } - - @Override - public Map, StructureStart> getAllStarts() { - return Collections.emptyMap(); - } - - @Override - public void setAllStarts(Map, StructureStart> pStructureStarts) { - } - - @Override - public LongSet getReferencesForFeature(ConfiguredStructureFeature pStructure) { - return LongSets.emptySet(); - } - - @Override - public void addReferenceForFeature(ConfiguredStructureFeature pStructure, long pReference) { - } - - @Override - public Map, LongSet> getAllReferences() { - return Collections.emptyMap(); - } - - @Override - public void setAllReferences(Map, LongSet> pStructureReferences) { - } - - @Override - public int getHeight() { - return world.getHeight(); - } - - @Override - public int getMinBuildHeight() { - return world.getMinBuildHeight(); - } - - @Override - public TickContainerAccess getFluidTicks() { - return BlackholeTickAccess.emptyContainer(); - } - - @Override - public TicksToSave getTicksForSerialization() { - return null; - } - - @Override - public TickContainerAccess getBlockTicks() { - return BlackholeTickAccess.emptyContainer(); - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSection.java b/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSection.java deleted file mode 100644 index d8d095087..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSection.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.jozufozu.flywheel.lib.virtualworld; - -import net.minecraft.core.Registry; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; - -public class VirtualChunkSection extends LevelChunkSection { - - public VirtualChunk owner; - - public final int xStart; - public final int yStart; - public final int zStart; - - public VirtualChunkSection(VirtualChunk owner, int yBase) { - super(yBase, owner.world.registryAccess() - .registry(Registry.BIOME_REGISTRY) - .orElseThrow()); - this.owner = owner; - this.xStart = owner.getPos() - .getMinBlockX(); - this.yStart = yBase; - this.zStart = owner.getPos() - .getMinBlockZ(); - } - - @Override - public BlockState getBlockState(int x, int y, int z) { - // ChunkSection#getBlockState expects local chunk coordinates, so we add to get - // back into world coords. - return owner.world.getBlockState(x + xStart, y + yStart, z + zStart); - } - - @Override - public BlockState setBlockState(int p_177484_1_, int p_177484_2_, int p_177484_3_, BlockState p_177484_4_, - boolean p_177484_5_) { - throw new IllegalStateException("Chunk sections should not be mutated in a fake world."); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSource.java b/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSource.java deleted file mode 100644 index ef83ad93d..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualChunkSource.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.jozufozu.flywheel.lib.virtualworld; - -import java.util.HashMap; -import java.util.function.BooleanSupplier; - -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.lighting.LevelLightEngine; - -public class VirtualChunkSource extends ChunkSource { - private final VirtualRenderWorld world; - - public final HashMap chunks = new HashMap<>(); - - public VirtualChunkSource(VirtualRenderWorld world) { - this.world = world; - } - - @Override - public BlockGetter getChunkForLighting(int x, int z) { - return getChunk(x, z); - } - - @Override - public Level getLevel() { - return world; - } - - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus status, boolean p_212849_4_) { - return getChunk(x, z); - } - - public ChunkAccess getChunk(int x, int z) { - long pos = ChunkPos.asLong(x, z); - - return chunks.computeIfAbsent(pos, $ -> new VirtualChunk(world, x, z)); - } - - @Override - public String gatherStats() { - return "WrappedChunkProvider"; - } - - @Override - public LevelLightEngine getLightEngine() { - return world.getLightEngine(); - } - - @Override - public void tick(BooleanSupplier p_202162_, boolean p_202163_) { - } - - @Override - public int getLoadedChunksCount() { - return 0; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualLevelEntityGetter.java b/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualLevelEntityGetter.java deleted file mode 100644 index 41a4728e4..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualLevelEntityGetter.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jozufozu.flywheel.lib.virtualworld; - -import java.util.Collections; -import java.util.UUID; -import java.util.function.Consumer; - -import net.minecraft.world.level.entity.EntityAccess; -import net.minecraft.world.level.entity.EntityTypeTest; -import net.minecraft.world.level.entity.LevelEntityGetter; -import net.minecraft.world.phys.AABB; - -public class VirtualLevelEntityGetter implements LevelEntityGetter { - - @Override - public T get(int p_156931_) { - return null; - } - - @Override - public T get(UUID pUuid) { - return null; - } - - @Override - public Iterable getAll() { - return Collections.emptyList(); - } - - @Override - public void get(EntityTypeTest p_156935_, Consumer p_156936_) { - } - - @Override - public void get(AABB p_156937_, Consumer p_156938_) { - } - - @Override - public void get(EntityTypeTest p_156932_, AABB p_156933_, Consumer p_156934_) { - } - -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualRenderWorld.java b/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualRenderWorld.java deleted file mode 100644 index 6c2bb071b..000000000 --- a/src/main/java/com/jozufozu/flywheel/lib/virtualworld/VirtualRenderWorld.java +++ /dev/null @@ -1,376 +0,0 @@ -package com.jozufozu.flywheel.lib.virtualworld; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; - -import org.jetbrains.annotations.Nullable; - -import com.jozufozu.flywheel.api.FlywheelLevel; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Holder; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.SectionPos; -import net.minecraft.core.Vec3i; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.crafting.RecipeManager; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkSource; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.entity.LevelEntityGetter; -import net.minecraft.world.level.gameevent.GameEvent; -import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.saveddata.maps.MapItemSavedData; -import net.minecraft.world.level.storage.WritableLevelData; -import net.minecraft.world.scores.Scoreboard; -import net.minecraft.world.ticks.LevelTickAccess; - -public class VirtualRenderWorld extends Level implements FlywheelLevel { - public final Map blocksAdded = new HashMap<>(); - public final Map besAdded = new HashMap<>(); - public final Set spannedSections = new HashSet<>(); - private final BlockPos.MutableBlockPos scratch = new BlockPos.MutableBlockPos(); - - protected final Level level; - protected final LevelLightEngine lighter; - protected final VirtualChunkSource chunkSource; - protected final LevelEntityGetter entityGetter = new VirtualLevelEntityGetter<>(); - - protected final int height; - protected final int minBuildHeight; - protected final Vec3i biomeOffset; - - public VirtualRenderWorld(Level level) { - this(level, Vec3i.ZERO, level.getHeight(), level.getMinBuildHeight()); - } - - public VirtualRenderWorld(Level level, Vec3i biomeOffset) { - this(level, biomeOffset, level.getHeight(), level.getMinBuildHeight()); - } - - public VirtualRenderWorld(Level level, Vec3i biomeOffset, int height, int minBuildHeight) { - super((WritableLevelData) level.getLevelData(), level.dimension(), level.dimensionTypeRegistration(), level::getProfiler, - true, false, 0); - this.biomeOffset = biomeOffset; - this.level = level; - this.height = nextMultipleOf16(height); - this.minBuildHeight = nextMultipleOf16(minBuildHeight); - this.chunkSource = new VirtualChunkSource(this); - this.lighter = new LevelLightEngine(chunkSource, true, false); - } - - /** - * We need to ensure that height and minBuildHeight are multiples of 16. - * Adapted from: https://math.stackexchange.com/questions/291468 - */ - public static int nextMultipleOf16(int a) { - if (a < 0) { - return -(((Math.abs(a) - 1) | 15) + 1); - } else { - return ((a - 1) | 15) + 1; - } - } - - /** - * Run this after you're done using setBlock(). - */ - public void runLightingEngine() { - for (Map.Entry entry : blocksAdded.entrySet()) { - BlockPos pos = entry.getKey(); - BlockState state = entry.getValue(); - int light = state.getLightEmission(this, pos); - if (light > 0) { - lighter.onBlockEmissionIncrease(pos, light); - } - } - - lighter.runUpdates(Integer.MAX_VALUE, false, false); - } - - public void setBlockEntities(Collection blockEntities) { - besAdded.clear(); - blockEntities.forEach(be -> besAdded.put(be.getBlockPos(), be)); - } - - public void clear() { - blocksAdded.clear(); - } - - // MEANINGFUL OVERRIDES - - @Override - public boolean setBlock(BlockPos pos, BlockState newState, int flags) { - blocksAdded.put(pos, newState); - - SectionPos sectionPos = SectionPos.of(pos); - if (spannedSections.add(sectionPos)) { - lighter.updateSectionStatus(sectionPos, false); - } - - if ((flags & Block.UPDATE_SUPPRESS_LIGHT) == 0) { - lighter.checkBlock(pos); - } - - return true; - } - - @Override - public int getHeight() { - return height; - } - - @Override - public int getMinBuildHeight() { - return minBuildHeight; - } - - @Override - public ChunkSource getChunkSource() { - return chunkSource; - } - - @Override - public LevelLightEngine getLightEngine() { - return lighter; - } - - @Override - protected LevelEntityGetter getEntities() { - return entityGetter; - } - - @Override - public BlockState getBlockState(@Nullable BlockPos pos) { - BlockState state = blocksAdded.get(pos); - if (state != null) - return state; - return Blocks.AIR.defaultBlockState(); - } - - @Override - public boolean setBlockAndUpdate(BlockPos pos, BlockState state) { - return setBlock(pos, state, 0); - } - - @Override - @Nullable - public BlockEntity getBlockEntity(BlockPos pos) { - return besAdded.get(pos); - } - - @Override - public boolean isStateAtPosition(BlockPos pos, Predicate condition) { - return condition.test(getBlockState(pos)); - } - - public BlockState getBlockState(int x, int y, int z) { - return getBlockState(scratch.set(x, y, z)); - } - - // BIOME OFFSET - - @Override - public Holder getBiome(BlockPos pPos) { - return super.getBiome(pPos.offset(biomeOffset)); - } - - @Override - public Holder getUncachedNoiseBiome(int pX, int pY, int pZ) { - // Control flow should never reach this method, - // so we add biomeOffset in case some other mod calls this directly. - return level.getUncachedNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ()); - } - - @Override - public Holder getNoiseBiome(int pX, int pY, int pZ) { - // Control flow should never reach this method, - // so we add biomeOffset in case some other mod calls this directly. - return level.getNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ()); - } - - // RENDERING CONSTANTS - - @Override - public int getMaxLocalRawBrightness(BlockPos pos) { - return 15; - } - - @Override - public float getShade(Direction p_230487_1_, boolean p_230487_2_) { - return 1f; - } - - // THIN WRAPPERS AHEAD - - @Override - public BiomeManager getBiomeManager() { - return level.getBiomeManager(); - } - - @Override - public RegistryAccess registryAccess() { - return level.registryAccess(); - } - - @Override - public LevelTickAccess getBlockTicks() { - return level.getBlockTicks(); - } - - @Override - public LevelTickAccess getFluidTicks() { - return level.getFluidTicks(); - } - - @Override - public RecipeManager getRecipeManager() { - return level.getRecipeManager(); - } - - @Override - public int getFreeMapId() { - return level.getFreeMapId(); - } - - @Override - public Scoreboard getScoreboard() { - return level.getScoreboard(); - } - - // UNIMPORTANT CONSTANTS - - @Override - @Nullable - public Entity getEntity(int id) { - return null; - } - - @Override - @Nullable - public MapItemSavedData getMapData(String mapName) { - return null; - } - - @Override - public boolean isLoaded(BlockPos pos) { - return true; - } - - @Override - public boolean isAreaLoaded(BlockPos center, int range) { - return true; - } - - @Override - public List players() { - return Collections.emptyList(); - } - - @Override - public String gatherChunkSourceStats() { - return ""; - } - - // NOOP - - @Override - public void levelEvent(@Nullable Player player, int type, BlockPos pos, int data) {} - - @Override - public void playSound(@Nullable Player player, double x, double y, double z, SoundEvent soundIn, - SoundSource category, float volume, float pitch) {} - - @Override - public void playSound(@Nullable Player p_217384_1_, Entity p_217384_2_, SoundEvent p_217384_3_, - SoundSource p_217384_4_, float p_217384_5_, float p_217384_6_) {} - - @Override - public void setMapData(String pMapId, MapItemSavedData pData) {} - - @Override - public void destroyBlockProgress(int breakerId, BlockPos pos, int progress) {} - - @Override - public void updateNeighbourForOutputSignal(BlockPos p_175666_1_, Block p_175666_2_) {} - - @Override - public void gameEvent(@Nullable Entity pEntity, GameEvent pEvent, BlockPos pPos) {} - - @Override - public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {} - - // Override Starlight's ExtendedWorld interface methods: - - public LevelChunk getChunkAtImmediately(final int chunkX, final int chunkZ) { - return chunkSource.getChunk(chunkX, chunkZ, false); - } - - public ChunkAccess getAnyChunkImmediately(final int chunkX, final int chunkZ) { - return chunkSource.getChunk(chunkX, chunkZ); - } - - // Intentionally copied from LevelHeightAccessor. Lithium overrides these methods so we need to, too. - - @Override - public int getMaxBuildHeight() { - return this.getMinBuildHeight() + this.getHeight(); - } - - @Override - public int getSectionsCount() { - return this.getMaxSection() - this.getMinSection(); - } - - @Override - public int getMinSection() { - return SectionPos.blockToSectionCoord(this.getMinBuildHeight()); - } - - @Override - public int getMaxSection() { - return SectionPos.blockToSectionCoord(this.getMaxBuildHeight() - 1) + 1; - } - - @Override - public boolean isOutsideBuildHeight(BlockPos pos) { - return this.isOutsideBuildHeight(pos.getY()); - } - - @Override - public boolean isOutsideBuildHeight(int y) { - return y < this.getMinBuildHeight() || y >= this.getMaxBuildHeight(); - } - - @Override - public int getSectionIndex(int y) { - return this.getSectionIndexFromSectionY(SectionPos.blockToSectionCoord(y)); - } - - @Override - public int getSectionIndexFromSectionY(int sectionY) { - return sectionY - this.getMinSection(); - } - - @Override - public int getSectionYFromSectionIndex(int sectionIndex) { - return sectionIndex + this.getMinSection(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractBlockEntityVisual.java b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractBlockEntityVisual.java index 14c16bde7..7501263b4 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractBlockEntityVisual.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractBlockEntityVisual.java @@ -6,9 +6,9 @@ import com.jozufozu.flywheel.api.visual.BlockEntityVisual; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.TickableVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; +import com.jozufozu.flywheel.api.visualization.VisualManager; import com.jozufozu.flywheel.api.visualization.VisualizationContext; -import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.lib.box.Box; import com.jozufozu.flywheel.lib.box.MutableBox; import net.minecraft.core.BlockPos; @@ -52,13 +52,13 @@ public abstract class AbstractBlockEntityVisual extends A } @Override - public ImmutableBox getVolume() { + public Box getVolume() { return MutableBox.from(pos); } /** * In order to accommodate for floating point precision errors at high coordinates, - * {@link BlockEntityVisualManager}s are allowed to arbitrarily adjust the origin, and + * {@link VisualManager}s are allowed to arbitrarily adjust the origin, and * shift the world matrix provided as a shader uniform accordingly. * * @return The {@link BlockPos position} of the {@link BlockEntity} this visual @@ -72,7 +72,7 @@ public abstract class AbstractBlockEntityVisual extends A * @param frustum The current frustum. * @return {@code true} if this visual within the given frustum. */ - public boolean visible(FrustumIntersection frustum) { + public boolean isVisible(FrustumIntersection frustum) { return frustum.testAab(visualPos.getX(), visualPos.getY(), visualPos.getZ(), visualPos.getX() + 1, visualPos.getY() + 1, visualPos.getZ() + 1); } diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java index a1ba4030d..13990342e 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java @@ -6,8 +6,8 @@ import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.EntityVisual; import com.jozufozu.flywheel.api.visual.TickableVisual; import com.jozufozu.flywheel.api.visualization.VisualizationContext; -import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityVisualManager; -import com.jozufozu.flywheel.lib.box.ImmutableBox; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; +import com.jozufozu.flywheel.lib.box.Box; import com.jozufozu.flywheel.lib.box.MutableBox; import com.jozufozu.flywheel.lib.light.TickingLightListener; import com.mojang.math.Vector3f; @@ -57,7 +57,7 @@ public abstract class AbstractEntityVisual extends AbstractVis } @Override - public ImmutableBox getVolume() { + public Box getVolume() { return bounds; } @@ -78,7 +78,7 @@ public abstract class AbstractEntityVisual extends AbstractVis /** * In order to accommodate for floating point precision errors at high coordinates, - * {@link BlockEntityVisualManager}s are allowed to arbitrarily adjust the origin, and + * {@link VisualizationManager}s are allowed to arbitrarily adjust the origin, and * shift the world matrix provided as a shader uniform accordingly. * * @return The position this visual should be rendered at to appear in the correct location. @@ -92,17 +92,19 @@ public abstract class AbstractEntityVisual extends AbstractVis /** * In order to accommodate for floating point precision errors at high coordinates, - * {@link BlockEntityVisualManager}s are allowed to arbitrarily adjust the origin, and + * {@link VisualizationManager}s are allowed to arbitrarily adjust the origin, and * shift the world matrix provided as a shader uniform accordingly. * * @return The position this visual should be rendered at to appear in the correct location. */ public Vector3f getVisualPosition(float partialTicks) { Vec3 pos = entity.position(); - return new Vector3f((float) (Mth.lerp(partialTicks, entity.xOld, pos.x) - renderOrigin.getX()), (float) (Mth.lerp(partialTicks, entity.yOld, pos.y) - renderOrigin.getY()), (float) (Mth.lerp(partialTicks, entity.zOld, pos.z) - renderOrigin.getZ())); + return new Vector3f((float) (Mth.lerp(partialTicks, entity.xOld, pos.x) - renderOrigin.getX()), + (float) (Mth.lerp(partialTicks, entity.yOld, pos.y) - renderOrigin.getY()), + (float) (Mth.lerp(partialTicks, entity.zOld, pos.z) - renderOrigin.getZ())); } - public boolean visible(FrustumIntersection frustum) { + public boolean isVisible(FrustumIntersection frustum) { return entity.noCulling || visibilityTester.check(frustum); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractVisual.java b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractVisual.java index bd1753657..704b439a1 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractVisual.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractVisual.java @@ -29,13 +29,13 @@ public abstract class AbstractVisual implements Visual, LightListener { } @Override - public void init() { + public void init(float partialTick) { LightUpdater.get(level).addListener(this); updateLight(); } @Override - public void update() { + public void update(float partialTick) { } @Override diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/EntityVisibilityTester.java b/src/main/java/com/jozufozu/flywheel/lib/visual/EntityVisibilityTester.java index 8dfff1c0d..806dfeb97 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/EntityVisibilityTester.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/EntityVisibilityTester.java @@ -20,7 +20,6 @@ public class EntityVisibilityTester { public EntityVisibilityTester(Entity entity, Vec3i renderOrigin) { this.entity = entity; - this.renderOrigin = renderOrigin; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java index e91321ca5..4f2fdc8ed 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/BufferBuilderMixin.java @@ -18,9 +18,6 @@ public abstract class BufferBuilderMixin implements BufferBuilderExtension { @Shadow private ByteBuffer buffer; - @Shadow - private int nextElementByte; - @Shadow private int vertices; @@ -40,14 +37,12 @@ public abstract class BufferBuilderMixin implements BufferBuilderExtension { @Shadow private boolean building; - @Shadow - private void ensureCapacity(int increaseAmount) { - } - @Override public void flywheel$freeBuffer() { if (buffer != null) { - MemoryUtil.memFree(buffer); + // The buffer is created using MemoryTracker, which uses a non-default allocator. + // The same allocator must be used here to free the buffer. + MemoryUtil.getAllocator(false).free(MemoryUtil.memAddress0(buffer)); buffer = null; } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java index b947f1187..ba1513e0f 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/ClientLevelMixin.java @@ -9,9 +9,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.google.common.collect.Lists; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.extension.ClientLevelExtension; import com.jozufozu.flywheel.impl.visualization.VisualizationHelper; -import com.jozufozu.flywheel.util.FlwUtil; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.world.entity.Entity; @@ -29,7 +29,7 @@ public abstract class ClientLevelMixin implements ClientLevelExtension { @Inject(method = "entitiesForRendering()Ljava/lang/Iterable;", at = @At("RETURN"), cancellable = true) private void flywheel$filterEntities(CallbackInfoReturnable> cir) { - if (!FlwUtil.canUseVisualization((ClientLevel) (Object) this)) { + if (!VisualizationManager.supportsVisualization((ClientLevel) (Object) this)) { return; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java index c2187ecdf..ea8673579 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/ClientMainMixin.java @@ -12,7 +12,7 @@ public class ClientMainMixin { @Inject(method = "main([Ljava/lang/String;)V", at = @At("HEAD")) private static void flywheel$injectRenderDoc(CallbackInfo ci) { // Only try to load RenderDoc if a system property is set to true. - if (!Boolean.getBoolean("flw.loadRenderDoc")) { + if (System.getProperty("flw.loadRenderDoc") == null) { return; } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java index 9d676fcb3..f09813b56 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java @@ -40,7 +40,7 @@ public class LevelRendererMixin { @Inject(method = "renderLevel", at = @At("HEAD")) private void flywheel$beginRender(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) { - flywheel$renderContext = RenderContext.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera); + flywheel$renderContext = RenderContext.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick); MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(flywheel$renderContext)); } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java b/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java deleted file mode 100644 index 8e196640b..000000000 --- a/src/main/java/com/jozufozu/flywheel/mixin/PausedPartialTickAccessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.jozufozu.flywheel.mixin; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.client.Minecraft; - -@Mixin(Minecraft.class) -public interface PausedPartialTickAccessor { - @Accessor("pausePartialTick") - float flywheel$getPausePartialTick(); -} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java index c0aea1f06..66e7f1fd2 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/sodium/ChunkRenderRebuildTaskMixin.java @@ -4,7 +4,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; +import com.jozufozu.flywheel.impl.visualization.VisualizationHelper; import me.jellysquid.mods.sodium.client.render.chunk.tasks.ChunkRenderRebuildTask; import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; @@ -15,7 +15,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; public class ChunkRenderRebuildTaskMixin { @Redirect(method = "performBuild", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderDispatcher;getRenderer(Lnet/minecraft/world/level/block/entity/BlockEntity;)Lnet/minecraft/client/renderer/blockentity/BlockEntityRenderer;")) private BlockEntityRenderer flywheel$redirectGetRenderer(BlockEntityRenderDispatcher dispatcher, BlockEntity blockEntity) { - if (VisualizedRenderDispatcher.tryAddBlockEntity(blockEntity)) { + if (VisualizationHelper.tryAddBlockEntity(blockEntity)) { return null; } return dispatcher.getRenderer(blockEntity); diff --git a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/ChunkRebuildHooksMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/ChunkRebuildHooksMixin.java index 2a4e09437..aa660871d 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/ChunkRebuildHooksMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/ChunkRebuildHooksMixin.java @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; +import com.jozufozu.flywheel.impl.visualization.VisualizationHelper; import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraft.world.level.block.entity.BlockEntity; @@ -16,7 +16,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; public class ChunkRebuildHooksMixin { @Inject(method = "handleBlockEntity(Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$CompiledChunk;Ljava/util/Set;Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At("HEAD"), cancellable = true) private void flywheel$tryAddBlockEntity(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set globalBlockEntities, BlockEntity blockEntity, CallbackInfo ci) { - if (VisualizedRenderDispatcher.tryAddBlockEntity(blockEntity)) { + if (VisualizationHelper.tryAddBlockEntity(blockEntity)) { ci.cancel(); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualAddMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualAddMixin.java index 5ed10212e..6f3435623 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualAddMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualAddMixin.java @@ -7,8 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -23,11 +22,11 @@ public class VisualAddMixin { @Inject(method = "setBlockEntity(Lnet/minecraft/world/level/block/entity/BlockEntity;)V", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) private void flywheel$onBlockEntityAdded(BlockEntity blockEntity, CallbackInfo ci) { - if (!FlwUtil.canUseVisualization(level)) { + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { return; } - VisualizedRenderDispatcher.getBlockEntities(level) - .queueAdd(blockEntity); + manager.getBlockEntities().queueAdd(blockEntity); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualRemoveMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualRemoveMixin.java index bd95b1c2a..b5167d56a 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualRemoveMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualRemoveMixin.java @@ -7,8 +7,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; @@ -21,11 +20,11 @@ public class VisualRemoveMixin { @Inject(method = "setRemoved()V", at = @At("TAIL")) private void flywheel$removeVisual(CallbackInfo ci) { - if (!FlwUtil.canUseVisualization(level)) { + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { return; } - VisualizedRenderDispatcher.getBlockEntities(level) - .queueRemove((BlockEntity) (Object) this); + manager.getBlockEntities().queueRemove((BlockEntity) (Object) this); } } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualUpdateMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualUpdateMixin.java index 50bc9732e..7e7021975 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualUpdateMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/visualmanage/VisualUpdateMixin.java @@ -6,8 +6,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.jozufozu.flywheel.impl.visualization.VisualizedRenderDispatcher; -import com.jozufozu.flywheel.util.FlwUtil; +import com.jozufozu.flywheel.api.visualization.VisualizationManager; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.LevelRenderer; @@ -25,7 +24,8 @@ public class VisualUpdateMixin { */ @Inject(method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V", at = @At("TAIL")) private void flywheel$checkUpdate(BlockPos pos, BlockState oldState, BlockState newState, CallbackInfo ci) { - if (!FlwUtil.canUseVisualization(level)) { + VisualizationManager manager = VisualizationManager.get(level); + if (manager == null) { return; } @@ -34,7 +34,6 @@ public class VisualUpdateMixin { return; } - VisualizedRenderDispatcher.getBlockEntities(level) - .queueUpdate(blockEntity); + manager.getBlockEntities().queueUpdate(blockEntity); } } diff --git a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java b/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java deleted file mode 100644 index 8d7f553ab..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/FlwUtil.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Set; -import java.util.WeakHashMap; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.Nullable; - -import com.jozufozu.flywheel.api.FlywheelLevel; -import com.jozufozu.flywheel.api.backend.BackendManager; -import com.mojang.blaze3d.vertex.PoseStack; - -import net.minecraft.client.Minecraft; -import net.minecraft.world.level.LevelAccessor; - -public final class FlwUtil { - public static boolean isGameActive() { - return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null); - } - - @Contract("null -> false") - public static boolean canUseVisualization(@Nullable LevelAccessor level) { - return BackendManager.isOn() && isFlywheelLevel(level); - } - - /** - * Used to avoid calling Flywheel functions on (fake) levels that don't specifically support it. - */ - public static boolean isFlywheelLevel(@Nullable LevelAccessor level) { - if (level == null) { - return false; - } - - if (!level.isClientSide()) { - return false; - } - - if (level instanceof FlywheelLevel flywheelLevel && flywheelLevel.supportsFlywheel()) { - return true; - } - - return level == Minecraft.getInstance().level; - } - - public static Set createWeakHashSet() { - return Collections.newSetFromMap(new WeakHashMap<>()); - } - - public static PoseStack copyPoseStack(PoseStack stack) { - PoseStack copy = new PoseStack(); - copy.last() - .pose() - .load(stack.last() - .pose()); - copy.last() - .normal() - .load(stack.last() - .normal()); - return copy; - } - - public static int[] initArray(int size, int fill) { - var out = new int[size]; - Arrays.fill(out, fill); - return out; - } -} diff --git a/src/main/java/com/jozufozu/flywheel/util/Lazy.java b/src/main/java/com/jozufozu/flywheel/util/Lazy.java deleted file mode 100644 index eb4c5fe7d..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/Lazy.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -import org.jetbrains.annotations.NotNull; - -public class Lazy implements Supplier { - private final NonNullSupplier supplier; - - private T value; - - public Lazy(NonNullSupplier supplier) { - this.supplier = supplier; - } - - @NotNull - public T get() { - if (value == null) { - value = supplier.get(); - } - - return value; - } - - public boolean isInitialized() { - return value != null; - } - - public Lazy lazyMap(Function func) { - return new Lazy<>(() -> func.apply(get())); - } - - public static Lazy of(NonNullSupplier factory) { - return new Lazy<>(factory); - } - - public void ifPresent(Consumer func) { - if (value != null) { - func.accept(value); - } - } - - /** - * If initialized, maps the stored value based on the function, otherwise returns the None. - * @param func The function to map the value with. - * @param The type of the mapped value. - * @return The mapped value, or None if not initialized. - */ - public Optional map(Function func) { - if (value != null) { - return Optional.of(func.apply(value)); - } else { - return Optional.empty(); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/util/Mods.java b/src/main/java/com/jozufozu/flywheel/util/Mods.java deleted file mode 100644 index 8ca9b6380..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/Mods.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.util.Optional; -import java.util.function.Supplier; - -import net.minecraftforge.fml.ModList; - -/** - * For compatibility with and without another mod present, we have to define load conditions of the specific code - */ -public enum Mods { - STARLIGHT("starlight"); - - private final String id; - - Mods(String id) { - this.id = id; - } - - /** - * @return a whether the mod is loaded or not based on mod id - */ - public boolean isLoaded() { - return ModList.get().isLoaded(id); - } - - /** - * Simple hook to run code if a mod is installed - * @param toRun will be run only if the mod is loaded - * @return Optional.empty() if the mod is not loaded, otherwise an Optional of the return value of the given supplier - */ - public Optional runIfInstalled(Supplier> toRun) { - if (isLoaded()) { - return Optional.of(toRun.get() - .get()); - } - return Optional.empty(); - } - - /** - * Simple hook to execute code if a mod is installed - * @param toExecute will be executed only if the mod is loaded - */ - public void executeIfInstalled(Supplier toExecute) { - if (isLoaded()) { - toExecute.get().run(); - } - } -} diff --git a/src/main/java/com/jozufozu/flywheel/util/NonNullSupplier.java b/src/main/java/com/jozufozu/flywheel/util/NonNullSupplier.java deleted file mode 100644 index 7c41f2404..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/NonNullSupplier.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.jozufozu.flywheel.util; - -import org.jetbrains.annotations.NotNull; - -@FunctionalInterface -public interface NonNullSupplier { - @NotNull - T get(); -} diff --git a/src/main/java/com/jozufozu/flywheel/util/NotNullFunction.java b/src/main/java/com/jozufozu/flywheel/util/NotNullFunction.java deleted file mode 100644 index fd83d37c3..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/NotNullFunction.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.jozufozu.flywheel.util; - -import org.jetbrains.annotations.NotNull; - -@FunctionalInterface -public interface NotNullFunction { - @NotNull R apply(T t); -} diff --git a/src/main/java/com/jozufozu/flywheel/util/Unit.java b/src/main/java/com/jozufozu/flywheel/util/Unit.java deleted file mode 100644 index 694edbbc4..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/Unit.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.jozufozu.flywheel.util; - -public enum Unit { - INSTANCE; -} diff --git a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java b/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java deleted file mode 100644 index 244dff288..000000000 --- a/src/main/java/com/jozufozu/flywheel/util/WorldAttached.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.jozufozu.flywheel.util; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.jetbrains.annotations.NotNull; - -import net.minecraft.world.level.LevelAccessor; - -public class WorldAttached { - - // weak references to prevent leaking hashmaps when a WorldAttached is GC'd during runtime - static List>> allMaps = new ArrayList<>(); - private final Map attached; - private final Function factory; - - public WorldAttached(Function factory) { - this.factory = factory; - attached = new HashMap<>(); - allMaps.add(new WeakReference<>(attached)); - } - - public static void invalidateWorld(LevelAccessor world) { - var i = allMaps.iterator(); - while (i.hasNext()) { - Map map = i.next() - .get(); - if (map == null) { - // If the map has been GC'd, remove the weak reference - i.remove(); - } else { - // Prevent leaks - Object attached = map.remove(world); - - // No, *really* prevent leaks - if (attached instanceof AutoCloseable closeable) { - try { - closeable.close(); - } catch (Exception ignored) { - - } - } - } - } - } - - @NotNull - public T get(LevelAccessor world) { - T t = attached.get(world); - if (t != null) return t; - T entry = factory.apply(world); - put(world, entry); - return entry; - } - - public void put(LevelAccessor world, T entry) { - attached.put(world, entry); - } - - /** - * Replaces the entry with a new one from the factory and returns the new entry. - */ - @NotNull - public T replace(LevelAccessor world) { - attached.remove(world); - - return get(world); - } - - /** - * Replaces the entry with a new one from the factory and returns the new entry. - */ - @NotNull - public T replace(LevelAccessor world, Consumer finalizer) { - remove(world, finalizer); - - return get(world); - } - - public void remove(LevelAccessor world, Consumer finalizer) { - T removed = attached.remove(world); - - if (removed != null) - finalizer.accept(removed); - } - - /** - * Deletes all entries after calling a function on them. - * - * @param finalizer Do something with all of the world-value pairs - */ - public void empty(BiConsumer finalizer) { - attached.forEach(finalizer); - attached.clear(); - } - - /** - * Deletes all entries after calling a function on them. - * - * @param finalizer Do something with all of the values - */ - public void empty(Consumer finalizer) { - attached.values() - .forEach(finalizer); - attached.clear(); - } -} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java index 277048736..65b0a9bc3 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/BellVisual.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; @@ -13,8 +14,7 @@ import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.OrientedInstance; import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.modelpart.ModelPart; -import com.jozufozu.flywheel.lib.util.AnimationTickHolder; +import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; @@ -35,26 +35,26 @@ public class BellVisual extends AbstractBlockEntityVisual imple } @Override - public void init() { + public void init(float partialTick) { bell = createBellInstance().setPivot(0.5f, 0.75f, 0.5f) .setPosition(getVisualPosition()); - updateRotation(); + updateRotation(partialTick); - super.init(); + super.init(partialTick); } @Override public void beginFrame(VisualFrameContext context) { - if (doDistanceLimitThisFrame(context) || !visible(context.frustum())) { + if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) { return; } - updateRotation(); + updateRotation(context.partialTick()); } - private void updateRotation() { - float ringTime = (float) blockEntity.ticks + AnimationTickHolder.getPartialTicks(); + private void updateRotation(float partialTick) { + float ringTime = (float) blockEntity.ticks + partialTick; if (ringTime == lastRingTime) { return; @@ -94,8 +94,8 @@ public class BellVisual extends AbstractBlockEntityVisual imple } @NotNull - private static ModelPart createBellMesh() { - return ModelPart.builder("bell", 32, 32) + private static Mesh createBellMesh() { + return new ModelPartBuilder("bell", 32, 32) .sprite(BellRenderer.BELL_RESOURCE_LOCATION.sprite()) .cuboid() .start(5.0F, 6.0F, 5.0F) diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java index d75b21146..83d42717d 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestVisual.java @@ -6,6 +6,7 @@ import java.util.function.BiFunction; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; @@ -14,8 +15,7 @@ import com.jozufozu.flywheel.lib.instance.OrientedInstance; import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.modelpart.ModelPart; -import com.jozufozu.flywheel.lib.util.AnimationTickHolder; +import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.math.Quaternion; import com.mojang.math.Vector3f; @@ -52,7 +52,7 @@ public class ChestVisual extends Abstrac } @Override - public void init() { + public void init(float partialTick) { Block block = blockState.getBlock(); chestType = blockState.hasProperty(ChestBlock.TYPE) ? blockState.getValue(ChestBlock.TYPE) : ChestType.SINGLE; @@ -77,16 +77,16 @@ public class ChestVisual extends Abstrac lidProgress = $ -> 0f; } - super.init(); + super.init(partialTick); } @Override public void beginFrame(VisualFrameContext context) { - if (doDistanceLimitThisFrame(context) || !visible(context.frustum())) { + if (doDistanceLimitThisFrame(context) || !isVisible(context.frustum())) { return; } - float progress = lidProgress.get(AnimationTickHolder.getPartialTicks()); + float progress = lidProgress.get(context.partialTick()); if (lastProgress == progress) { return; @@ -136,9 +136,9 @@ public class ChestVisual extends Abstrac .createInstance(); } - private static ModelPart createBodyMesh(ChestType type, TextureAtlasSprite sprite) { + private static Mesh createBodyMesh(ChestType type, TextureAtlasSprite sprite) { return switch (type) { - case LEFT -> ModelPart.builder("chest_base_left", 64, 64) + case LEFT -> new ModelPartBuilder("chest_base_left", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 19) @@ -146,7 +146,7 @@ public class ChestVisual extends Abstrac .size(15, 10, 14) .endCuboid() .build(); - case RIGHT -> ModelPart.builder("chest_base_right", 64, 64) + case RIGHT -> new ModelPartBuilder("chest_base_right", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 19) @@ -154,7 +154,7 @@ public class ChestVisual extends Abstrac .size(15, 10, 14) .endCuboid() .build(); - default -> ModelPart.builder("chest_base", 64, 64) + default -> new ModelPartBuilder("chest_base", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 19) @@ -165,9 +165,9 @@ public class ChestVisual extends Abstrac }; } - private static ModelPart createLidMesh(ChestType type, TextureAtlasSprite sprite) { + private static Mesh createLidMesh(ChestType type, TextureAtlasSprite sprite) { return switch (type) { - case LEFT -> ModelPart.builder("chest_lid_left", 64, 64) + case LEFT -> new ModelPartBuilder("chest_lid_left", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 0) @@ -179,7 +179,7 @@ public class ChestVisual extends Abstrac .size(1, 4, 1) .endCuboid() .build(); - case RIGHT -> ModelPart.builder("chest_lid_right", 64, 64) + case RIGHT -> new ModelPartBuilder("chest_lid_right", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 0) @@ -191,7 +191,7 @@ public class ChestVisual extends Abstrac .size(1, 4, 1) .endCuboid() .build(); - default -> ModelPart.builder("chest_lid", 64, 64) + default -> new ModelPartBuilder("chest_lid", 64, 64) .sprite(sprite) .cuboid() .textureOffset(0, 0) diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java index 9636778f1..a4ac5869e 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java @@ -3,6 +3,7 @@ package com.jozufozu.flywheel.vanilla; import org.jetbrains.annotations.NotNull; import com.jozufozu.flywheel.api.event.RenderStage; +import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.TickableVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; @@ -13,9 +14,8 @@ import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.model.Models; import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.modelpart.ModelPart; +import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; import com.jozufozu.flywheel.lib.transform.TransformStack; -import com.jozufozu.flywheel.lib.util.AnimationTickHolder; import com.jozufozu.flywheel.lib.visual.AbstractEntityVisual; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Vector3f; @@ -41,14 +41,14 @@ public class MinecartVisual extends AbstractEntityVi } @Override - public void init() { + public void init(float partialTick) { body = createBodyInstance(); blockState = entity.getDisplayBlockState(); contents = createContentsInstance(); - updatePosition(); + updatePosition(partialTick); - super.init(); + super.init(partialTick); } @Override @@ -67,25 +67,25 @@ public class MinecartVisual extends AbstractEntityVi @Override public void beginFrame(VisualFrameContext context) { - if (visible(context.frustum())) { + if (isVisible(context.frustum())) { return; } + // TODO: add proper way to temporarily disable rendering a specific instance if (!active) { return; } - updatePosition(); + updatePosition(context.partialTick()); } - private void updatePosition() { + private void updatePosition(float partialTick) { TransformStack tstack = TransformStack.cast(stack); stack.setIdentity(); - float pt = AnimationTickHolder.getPartialTicks(); - tstack.translate(Mth.lerp(pt, entity.xOld, entity.getX()) - renderOrigin.getX(), Mth.lerp(pt, entity.yOld, entity.getY()) - renderOrigin.getY(), Mth.lerp(pt, entity.zOld, entity.getZ()) - renderOrigin.getZ()); + tstack.translate(Mth.lerp(partialTick, entity.xOld, entity.getX()) - renderOrigin.getX(), Mth.lerp(partialTick, entity.yOld, entity.getY()) - renderOrigin.getY(), Mth.lerp(partialTick, entity.zOld, entity.getZ()) - renderOrigin.getZ()); - float yaw = Mth.lerp(pt, entity.yRotO, entity.getYRot()); + float yaw = Mth.lerp(partialTick, entity.yRotO, entity.getYRot()); long i = (long) entity.getId() * 493286711L; i = i * i * 4392167121L + i * 98761L; @@ -94,11 +94,11 @@ public class MinecartVisual extends AbstractEntityVi float f2 = (((float)(i >> 24 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F; tstack.translate(f, f1, f2); tstack.nudge(entity.getId()); - double d0 = Mth.lerp(pt, entity.xOld, entity.getX()); - double d1 = Mth.lerp(pt, entity.yOld, entity.getY()); - double d2 = Mth.lerp(pt, entity.zOld, entity.getZ()); + double d0 = Mth.lerp(partialTick, entity.xOld, entity.getX()); + double d1 = Mth.lerp(partialTick, entity.yOld, entity.getY()); + double d2 = Mth.lerp(partialTick, entity.zOld, entity.getZ()); Vec3 vector3d = entity.getPos(d0, d1, d2); - float f3 = Mth.lerp(pt, entity.xRotO, entity.getXRot()); + float f3 = Mth.lerp(partialTick, entity.xRotO, entity.getXRot()); if (vector3d != null) { Vec3 vector3d1 = entity.getPosOffs(d0, d1, d2, 0.3F); Vec3 vector3d2 = entity.getPosOffs(d0, d1, d2, -0.3F); @@ -122,8 +122,8 @@ public class MinecartVisual extends AbstractEntityVi tstack.translate(0.0D, 0.375D, 0.0D); tstack.multiply(Vector3f.YP.rotationDegrees(180 - yaw)); tstack.multiply(Vector3f.ZP.rotationDegrees(-f3)); - float f5 = (float)entity.getHurtTime() - pt; - float f6 = entity.getDamage() - pt; + float f5 = (float)entity.getHurtTime() - partialTick; + float f6 = entity.getDamage() - partialTick; if (f6 < 0) { f6 = 0; } @@ -186,14 +186,13 @@ public class MinecartVisual extends AbstractEntityVi } @NotNull - private static ModelPart createBodyMesh() { - int y = -3; - return ModelPart.builder("minecart", 64, 32) - .cuboid().invertYZ().start(-10, -8, -y).size(20, 16, 2).textureOffset(0, 10).rotateZ((float) Math.PI).rotateX(((float)Math.PI / 2F)).endCuboid() - .cuboid().invertYZ().start(-8, y, -10).size(16, 8, 2).rotateY(((float)Math.PI * 1.5F)).endCuboid() - .cuboid().invertYZ().start(-8, y, -10).size(16, 8, 2).rotateY(((float)Math.PI / 2F)).endCuboid() - .cuboid().invertYZ().start(-8, y, -8).size(16, 8, 2).rotateY((float)Math.PI).endCuboid() - .cuboid().invertYZ().start(-8, y, -8).size(16, 8, 2).endCuboid() + private static Mesh createBodyMesh() { + return new ModelPartBuilder("minecart", 64, 32) + .cuboid().invertYZ().start(-10, -8, 3).size(20, 16, 2).textureOffset(0, 10).rotateZ((float) Math.PI).rotateX(((float)Math.PI / 2F)).endCuboid() + .cuboid().invertYZ().start(-8, -3, -10).size(16, 8, 2).rotateY(((float)Math.PI * 1.5F)).endCuboid() + .cuboid().invertYZ().start(-8, -3, -10).size(16, 8, 2).rotateY(((float)Math.PI / 2F)).endCuboid() + .cuboid().invertYZ().start(-8, -3, -8).size(16, 8, 2).rotateY((float)Math.PI).endCuboid() + .cuboid().invertYZ().start(-8, -3, -8).size(16, 8, 2).endCuboid() .build(); } diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java index 33f26c117..546419197 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxVisual.java @@ -5,6 +5,7 @@ import java.util.function.Function; import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.instance.Instance; +import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.visual.DynamicVisual; import com.jozufozu.flywheel.api.visual.VisualFrameContext; import com.jozufozu.flywheel.api.visualization.VisualizationContext; @@ -12,9 +13,8 @@ import com.jozufozu.flywheel.lib.instance.InstanceTypes; import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.model.SimpleLazyModel; -import com.jozufozu.flywheel.lib.modelpart.ModelPart; +import com.jozufozu.flywheel.lib.model.part.ModelPartBuilder; import com.jozufozu.flywheel.lib.transform.TransformStack; -import com.jozufozu.flywheel.lib.util.AnimationTickHolder; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Quaternion; @@ -45,7 +45,7 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual 0.005f) { return; } @@ -90,8 +94,7 @@ public class ExampleEffect implements Effect { ExampleEffect effect = new ExampleEffect(level, new Vector3f(x, y, z)); ALL_EFFECTS.add(effect); - VisualizedRenderDispatcher.getEffects(level) - .queueAdd(effect); + manager.getEffects().queueAdd(effect); } @Override @@ -130,13 +133,11 @@ public class ExampleEffect implements Effect { } @Override - public void init() { - + public void init(float partialTick) { } @Override - public void update() { - + public void update(float partialTick) { } @Override @@ -283,12 +284,11 @@ public class ExampleEffect implements Effect { instance.delete(); } - public void beginFrame() { - float partialTicks = AnimationTickHolder.getPartialTicks(); - - var x = Mth.lerp(partialTicks, self.lastPosition.x, self.position.x); - var y = Mth.lerp(partialTicks, self.lastPosition.y, self.position.y); - var z = Mth.lerp(partialTicks, self.lastPosition.z, self.position.z); + public void beginFrame(VisualFrameContext context) { + float partialTick = context.partialTick(); + var x = Mth.lerp(partialTick, self.lastPosition.x, self.position.x); + var y = Mth.lerp(partialTick, self.lastPosition.y, self.position.y); + var z = Mth.lerp(partialTick, self.lastPosition.z, self.position.z); instance.loadIdentity() .translateBack(renderOrigin) diff --git a/src/main/resources/flywheel.mixins.json b/src/main/resources/flywheel.mixins.json index 94beb07d1..f1d9d86ae 100644 --- a/src/main/resources/flywheel.mixins.json +++ b/src/main/resources/flywheel.mixins.json @@ -15,7 +15,6 @@ "LevelRendererAccessor", "LevelRendererMixin", "LightUpdateMixin", - "PausedPartialTickAccessor", "RenderTypeMixin", "VertexFormatMixin", "fix.FixFabulousDepthMixin", diff --git a/src/test/java/com/jozufozu/flywheel/lib/task/WaitGroupTest.java b/src/test/java/com/jozufozu/flywheel/impl/task/WaitGroupTest.java similarity index 91% rename from src/test/java/com/jozufozu/flywheel/lib/task/WaitGroupTest.java rename to src/test/java/com/jozufozu/flywheel/impl/task/WaitGroupTest.java index 4f5618a31..4e829cff8 100644 --- a/src/test/java/com/jozufozu/flywheel/lib/task/WaitGroupTest.java +++ b/src/test/java/com/jozufozu/flywheel/impl/task/WaitGroupTest.java @@ -1,4 +1,4 @@ -package com.jozufozu.flywheel.lib.task; +package com.jozufozu.flywheel.impl.task; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/jozufozu/flywheel/lib/task/PlanCompositionTest.java b/src/test/java/com/jozufozu/flywheel/lib/task/PlanCompositionTest.java index a088f327f..3e00f5593 100644 --- a/src/test/java/com/jozufozu/flywheel/lib/task/PlanCompositionTest.java +++ b/src/test/java/com/jozufozu/flywheel/lib/task/PlanCompositionTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.jozufozu.flywheel.api.task.Plan; -import com.jozufozu.flywheel.util.Unit; +import com.jozufozu.flywheel.lib.util.Unit; public class PlanCompositionTest { diff --git a/src/test/java/com/jozufozu/flywheel/lib/task/PlanExecutionTest.java b/src/test/java/com/jozufozu/flywheel/lib/task/PlanExecutionTest.java index 839db793e..f06b19808 100644 --- a/src/test/java/com/jozufozu/flywheel/lib/task/PlanExecutionTest.java +++ b/src/test/java/com/jozufozu/flywheel/lib/task/PlanExecutionTest.java @@ -12,8 +12,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import com.jozufozu.flywheel.api.task.Plan; -import com.jozufozu.flywheel.backend.task.ParallelTaskExecutor; -import com.jozufozu.flywheel.util.Unit; +import com.jozufozu.flywheel.impl.task.ParallelTaskExecutor; +import com.jozufozu.flywheel.lib.util.Unit; import it.unimi.dsi.fastutil.ints.IntArrayList; diff --git a/src/test/java/com/jozufozu/flywheel/lib/task/PlanSimplificationTest.java b/src/test/java/com/jozufozu/flywheel/lib/task/PlanSimplificationTest.java index 3747d45af..e70b83c81 100644 --- a/src/test/java/com/jozufozu/flywheel/lib/task/PlanSimplificationTest.java +++ b/src/test/java/com/jozufozu/flywheel/lib/task/PlanSimplificationTest.java @@ -4,7 +4,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.jozufozu.flywheel.api.task.Plan; -import com.jozufozu.flywheel.util.Unit; +import com.jozufozu.flywheel.lib.util.Unit; public class PlanSimplificationTest {