mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-12 21:43:56 +01:00
Formalize most public API (#253)
* Start on general API formalization * More API improvements - Add Engine#onLightUpdate; remove LightUpdateHolder and backend/ClientChunkCacheMixin - Add Effect#level - Add VisualizationHelper#queueAdd and #queueRemove for Effects - Fix PartialModel not assigning bakedModel field when populating on init - Fix PartialModel.ALL using weak keys instead of weak values - Make Simple*Visualizer and corresponding inner Builder classes final - Restore FlatLit#light overload that accepts block and sky light values separately - Add AbstractBlockEntityVisual#relight overloads that accept Iterator and Iterable - Reorganize classes in impl.vizualization * TaskExecutor simplification - Move TaskExecutor#sync* methods to TaskExecutorImpl - Move Flag and RaisePlan to impl - Remove TaskExecutor#scheduleForMainThread and #isMainThread methods - Remove SyncedPlan - Add Engine#setupRender - Remove TaskExecutor parameters from Engine#render* methods - Convert Engine$CrumblingBlock into an interface - Unmark RenderContext as NonExtendable to allow fulfilling the purpose described in the doc of VisualizationManager#renderDispatcher * Remove registry freeze callbacks - Lazily initialize MaterialShaderIndices - Rename MaterialShaders#*Shader to #*Source - Move BackendImplemented to api.backend package
This commit is contained in:
parent
cc0ad90242
commit
eb2ba12a98
@ -1,7 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.api.event;
|
package dev.engine_room.flywheel.api;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.joml.Matrix4fc;
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
@ -10,7 +9,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
|||||||
import net.minecraft.client.renderer.LevelRenderer;
|
import net.minecraft.client.renderer.LevelRenderer;
|
||||||
import net.minecraft.client.renderer.RenderBuffers;
|
import net.minecraft.client.renderer.RenderBuffers;
|
||||||
|
|
||||||
@ApiStatus.NonExtendable
|
|
||||||
public interface RenderContext {
|
public interface RenderContext {
|
||||||
LevelRenderer renderer();
|
LevelRenderer renderer();
|
||||||
|
|
||||||
@ -20,9 +18,9 @@ public interface RenderContext {
|
|||||||
|
|
||||||
PoseStack stack();
|
PoseStack stack();
|
||||||
|
|
||||||
Matrix4f projection();
|
Matrix4fc projection();
|
||||||
|
|
||||||
Matrix4f viewProjection();
|
Matrix4fc viewProjection();
|
||||||
|
|
||||||
Camera camera();
|
Camera camera();
|
||||||
|
|
@ -1,13 +1,12 @@
|
|||||||
package dev.engine_room.flywheel.api.backend;
|
package dev.engine_room.flywheel.api.backend;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
|
||||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||||
import dev.engine_room.flywheel.api.registry.IdRegistry;
|
import dev.engine_room.flywheel.api.registry.IdRegistry;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
public interface Backend {
|
public interface Backend {
|
||||||
static IdRegistry<Backend> REGISTRY = FlwApiLink.INSTANCE.createIdRegistry();
|
IdRegistry<Backend> REGISTRY = FlwApiLink.INSTANCE.createIdRegistry();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new engine instance.
|
* Create a new engine instance.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package dev.engine_room.flywheel.api;
|
package dev.engine_room.flywheel.api.backend;
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
@ -9,19 +9,19 @@ public final class BackendManager {
|
|||||||
/**
|
/**
|
||||||
* Get the current backend.
|
* Get the current backend.
|
||||||
*/
|
*/
|
||||||
public static Backend getBackend() {
|
public static Backend currentBackend() {
|
||||||
return FlwApiLink.INSTANCE.getBackend();
|
return FlwApiLink.INSTANCE.getCurrentBackend();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBackendOn() {
|
public static boolean isBackendOn() {
|
||||||
return FlwApiLink.INSTANCE.isBackendOn();
|
return FlwApiLink.INSTANCE.isBackendOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Backend getOffBackend() {
|
public static Backend offBackend() {
|
||||||
return FlwApiLink.INSTANCE.getOffBackend();
|
return FlwApiLink.INSTANCE.getOffBackend();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Backend getDefaultBackend() {
|
public static Backend defaultBackend() {
|
||||||
return FlwApiLink.INSTANCE.getDefaultBackend();
|
return FlwApiLink.INSTANCE.getDefaultBackend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,52 +2,43 @@ package dev.engine_room.flywheel.api.backend;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
import org.jetbrains.annotations.Range;
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.task.Plan;
|
import dev.engine_room.flywheel.api.task.Plan;
|
||||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.world.level.LightLayer;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
public interface Engine {
|
public interface Engine {
|
||||||
/**
|
/**
|
||||||
* Create a visualization context that will render to the given stage.
|
* Create a visualization context that will be used to create visuals of the given type.
|
||||||
*
|
*
|
||||||
* @param stage The stage to render to.
|
* @param visualType The type of visual.
|
||||||
* @return A new visualization context.
|
* @return A new visualization context.
|
||||||
*/
|
*/
|
||||||
VisualizationContext createVisualizationContext(RenderStage stage);
|
VisualizationContext createVisualizationContext(VisualType visualType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a plan that will be executed every frame.
|
* Create a plan that will start execution after the start of the level render and
|
||||||
|
* finish execution before {@link #setupRender} is called.
|
||||||
|
*
|
||||||
* @return A new plan.
|
* @return A new plan.
|
||||||
*/
|
*/
|
||||||
Plan<RenderContext> createFramePlan();
|
Plan<RenderContext> createFramePlan();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render all instances necessary for the given stage.
|
* @return The current render origin.
|
||||||
* @param executor The task executor running the frame plan.
|
|
||||||
* @param context The render context for this frame.
|
|
||||||
* @param stage The stage to render.
|
|
||||||
*/
|
*/
|
||||||
void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage);
|
Vec3i renderOrigin();
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the given instances as a crumbling overlay.
|
|
||||||
* <br>
|
|
||||||
* This is guaranteed to be called between the first and last calls to {@link #renderStage} for the current frame.
|
|
||||||
*
|
|
||||||
* @param executor The task executor running the frame plan.
|
|
||||||
* @param context The render context for this frame.
|
|
||||||
* @param crumblingBlocks The instances to render. This list is never empty.
|
|
||||||
*/
|
|
||||||
void renderCrumbling(TaskExecutor executor, RenderContext context, List<CrumblingBlock> crumblingBlocks);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain the render origin to be within a certain distance from the camera in all directions,
|
* Maintain the render origin to be within a certain distance from the camera in all directions,
|
||||||
@ -57,11 +48,6 @@ public interface Engine {
|
|||||||
*/
|
*/
|
||||||
boolean updateRenderOrigin(Camera camera);
|
boolean updateRenderOrigin(Camera camera);
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The current render origin.
|
|
||||||
*/
|
|
||||||
Vec3i renderOrigin();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the set of sections that visuals have requested GPU light for.
|
* Assign the set of sections that visuals have requested GPU light for.
|
||||||
*
|
*
|
||||||
@ -71,19 +57,70 @@ public interface Engine {
|
|||||||
*/
|
*/
|
||||||
void lightSections(LongSet sections);
|
void lightSections(LongSet sections);
|
||||||
|
|
||||||
|
void onLightUpdate(SectionPos sectionPos, LightLayer layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up rendering for the current level render.
|
||||||
|
*
|
||||||
|
* <p>This method is guaranteed to be called after
|
||||||
|
* {@linkplain #createFramePlan() the frame plan} has finished execution and before
|
||||||
|
* {@link #render} and {@link #renderCrumbling} are called. This method is guaranteed to
|
||||||
|
* be called on the render thread.
|
||||||
|
*
|
||||||
|
* @param context The context for the current level render.
|
||||||
|
*/
|
||||||
|
void setupRender(RenderContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render all instances necessary for the given visual type.
|
||||||
|
*
|
||||||
|
* <p>This method is guaranteed to be called after {@link #setupRender} for the current
|
||||||
|
* level render. This method is guaranteed to be called on the render thread.
|
||||||
|
*
|
||||||
|
* @param context The context for the current level render.
|
||||||
|
* @param visualType The type of visual.
|
||||||
|
*/
|
||||||
|
void render(RenderContext context, VisualType visualType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given instances as a crumbling overlay.
|
||||||
|
*
|
||||||
|
* <p>This method is guaranteed to be called after {@link #setupRender} for the current
|
||||||
|
* level render. This method is guaranteed to be called on the render thread.
|
||||||
|
*
|
||||||
|
* @param context The context for the current level render.
|
||||||
|
* @param crumblingBlocks The instances to render. This list is never empty.
|
||||||
|
*/
|
||||||
|
void renderCrumbling(RenderContext context, List<CrumblingBlock> crumblingBlocks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free all resources associated with this engine.
|
* Free all resources associated with this engine.
|
||||||
* <br>
|
*
|
||||||
* This engine will not be used again after this method is called.
|
* <p>This engine will not be used again after this method is called.
|
||||||
|
*
|
||||||
|
* <p>This method is guaranteed to be called on the render thread.
|
||||||
*/
|
*/
|
||||||
void delete();
|
void delete();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A block to be rendered as a crumbling overlay.
|
* A block to be rendered as a crumbling overlay.
|
||||||
* @param progress The progress of the crumbling animation in the range [0, 10).
|
|
||||||
* @param pos The position of the block.
|
|
||||||
* @param instances The instances associated with the BE at this position.
|
|
||||||
*/
|
*/
|
||||||
record CrumblingBlock(int progress, BlockPos pos, List<Instance> instances) {
|
@ApiStatus.NonExtendable
|
||||||
|
interface CrumblingBlock {
|
||||||
|
/**
|
||||||
|
* The position of the block.
|
||||||
|
*/
|
||||||
|
BlockPos pos();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The progress of the crumbling animation in the range [0, 10).
|
||||||
|
*/
|
||||||
|
@Range(from = 0, to = 9)
|
||||||
|
int progress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The instances associated with the block entity visual at this position.
|
||||||
|
*/
|
||||||
|
List<Instance> instances();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.api.event;
|
|
||||||
|
|
||||||
public enum RenderStage {
|
|
||||||
AFTER_ENTITIES,
|
|
||||||
AFTER_BLOCK_ENTITIES,
|
|
||||||
AFTER_TRANSLUCENT_TERRAIN,
|
|
||||||
AFTER_PARTICLES,
|
|
||||||
AFTER_WEATHER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this stage the last one to be rendered in the frame?
|
|
||||||
*
|
|
||||||
* @return {@code true} if no other RenderStages will be dispatched this frame.
|
|
||||||
*/
|
|
||||||
public boolean isLast() {
|
|
||||||
return this == values()[values().length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this stage the first one to be rendered in the frame?
|
|
||||||
*
|
|
||||||
* @return {@code true} if this is the first RenderStage to be dispatched this frame.
|
|
||||||
*/
|
|
||||||
public boolean isFirst() {
|
|
||||||
return this == values()[0];
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,11 +5,11 @@ public interface Instance {
|
|||||||
|
|
||||||
InstanceHandle handle();
|
InstanceHandle handle();
|
||||||
|
|
||||||
default void delete() {
|
|
||||||
handle().setDeleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
default void setChanged() {
|
default void setChanged() {
|
||||||
handle().setChanged();
|
handle().setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void delete() {
|
||||||
|
handle().setDeleted();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.api.instance;
|
package dev.engine_room.flywheel.api.instance;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
public interface InstanceHandle {
|
public interface InstanceHandle {
|
||||||
|
@ -11,7 +11,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
* @param <I> The java representation of the instance.
|
* @param <I> The java representation of the instance.
|
||||||
*/
|
*/
|
||||||
public interface InstanceType<I extends Instance> {
|
public interface InstanceType<I extends Instance> {
|
||||||
static Registry<InstanceType<?>> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
Registry<InstanceType<?>> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param handle A handle that allows you to mark the instance as dirty or deleted.
|
* @param handle A handle that allows you to mark the instance as dirty or deleted.
|
||||||
|
@ -2,7 +2,7 @@ package dev.engine_room.flywheel.api.instance;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instancer is how you interact with an instanced model.
|
* An instancer is how you interact with an instanced model.
|
||||||
@ -29,6 +29,17 @@ public interface Instancer<I extends Instance> {
|
|||||||
*/
|
*/
|
||||||
I createInstance();
|
I createInstance();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate arr with new instances of this model.
|
||||||
|
*
|
||||||
|
* @param arr An array to fill.
|
||||||
|
*/
|
||||||
|
default void createInstances(I[] arr) {
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = createInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Steal an instance from another instancer.
|
* Steal an instance from another instancer.
|
||||||
* <br>
|
* <br>
|
||||||
@ -43,15 +54,4 @@ public interface Instancer<I extends Instance> {
|
|||||||
* @param instance The instance to steal.
|
* @param instance The instance to steal.
|
||||||
*/
|
*/
|
||||||
void stealInstance(@Nullable I instance);
|
void stealInstance(@Nullable I instance);
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate arr with new instances of this model.
|
|
||||||
*
|
|
||||||
* @param arr An array to fill.
|
|
||||||
*/
|
|
||||||
default void createInstances(I[] arr) {
|
|
||||||
for (int i = 0; i < arr.length; i++) {
|
|
||||||
arr[i] = createInstance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.api.instance;
|
package dev.engine_room.flywheel.api.instance;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
|
@ -22,7 +22,7 @@ public interface FlwApiLink {
|
|||||||
|
|
||||||
<T> IdRegistry<T> createIdRegistry();
|
<T> IdRegistry<T> createIdRegistry();
|
||||||
|
|
||||||
Backend getBackend();
|
Backend getCurrentBackend();
|
||||||
|
|
||||||
boolean isBackendOn();
|
boolean isBackendOn();
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public interface CutoutShader {
|
public interface CutoutShader {
|
||||||
static Registry<CutoutShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
Registry<CutoutShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||||
|
|
||||||
ResourceLocation source();
|
ResourceLocation source();
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public interface FogShader {
|
public interface FogShader {
|
||||||
static Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||||
|
|
||||||
ResourceLocation source();
|
ResourceLocation source();
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public interface MaterialShaders {
|
public interface MaterialShaders {
|
||||||
static Registry<MaterialShaders> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
Registry<MaterialShaders> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||||
|
|
||||||
ResourceLocation vertexShader();
|
ResourceLocation vertexSource();
|
||||||
|
|
||||||
ResourceLocation fragmentShader();
|
ResourceLocation fragmentSource();
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,4 @@ public interface Mesh {
|
|||||||
* @return A vec4 view.
|
* @return A vec4 view.
|
||||||
*/
|
*/
|
||||||
Vector4fc boundingSphere();
|
Vector4fc boundingSphere();
|
||||||
|
|
||||||
/**
|
|
||||||
* Free this mesh's resources, memory, etc.
|
|
||||||
*/
|
|
||||||
void delete();
|
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,6 @@ public interface Model {
|
|||||||
*/
|
*/
|
||||||
Vector4fc boundingSphere();
|
Vector4fc boundingSphere();
|
||||||
|
|
||||||
void delete();
|
|
||||||
|
|
||||||
record ConfiguredMesh(Material material, Mesh mesh) {
|
record ConfiguredMesh(Material material, Mesh mesh) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@ package dev.engine_room.flywheel.api.registry;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
@ -26,13 +25,11 @@ public interface IdRegistry<T> extends Iterable<T> {
|
|||||||
|
|
||||||
ResourceLocation getIdOrThrow(T object);
|
ResourceLocation getIdOrThrow(T object);
|
||||||
|
|
||||||
@Unmodifiable
|
@UnmodifiableView
|
||||||
Set<ResourceLocation> getAllIds();
|
Set<ResourceLocation> getAllIds();
|
||||||
|
|
||||||
@Unmodifiable
|
@UnmodifiableView
|
||||||
Collection<T> getAll();
|
Collection<T> getAll();
|
||||||
|
|
||||||
void addFreezeCallback(Consumer<IdRegistry<T>> callback);
|
|
||||||
|
|
||||||
boolean isFrozen();
|
boolean isFrozen();
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package dev.engine_room.flywheel.api.registry;
|
package dev.engine_room.flywheel.api.registry;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
@ApiStatus.NonExtendable
|
@ApiStatus.NonExtendable
|
||||||
public interface Registry<T> extends Iterable<T> {
|
public interface Registry<T> extends Iterable<T> {
|
||||||
@ -12,10 +11,8 @@ public interface Registry<T> extends Iterable<T> {
|
|||||||
|
|
||||||
<S extends T> S registerAndGet(S object);
|
<S extends T> S registerAndGet(S object);
|
||||||
|
|
||||||
@Unmodifiable
|
@UnmodifiableView
|
||||||
Set<T> getAll();
|
Set<T> getAll();
|
||||||
|
|
||||||
void addFreezeCallback(Consumer<Registry<T>> callback);
|
|
||||||
|
|
||||||
boolean isFrozen();
|
boolean isFrozen();
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,11 @@
|
|||||||
package dev.engine_room.flywheel.api.task;
|
package dev.engine_room.flywheel.api.task;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.BooleanSupplier;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
@ApiStatus.NonExtendable
|
@ApiStatus.NonExtendable
|
||||||
public interface TaskExecutor extends Executor {
|
public interface TaskExecutor extends Executor {
|
||||||
/**
|
|
||||||
* Wait for <em>all</em> running tasks to finish.
|
|
||||||
* <br>
|
|
||||||
* This is useful as a nuclear option, but most of the time you should
|
|
||||||
* try to use {@link #syncUntil(BooleanSupplier) syncUntil}.
|
|
||||||
*/
|
|
||||||
void syncPoint();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for running tasks, until the given condition is met
|
|
||||||
* ({@link BooleanSupplier#getAsBoolean()} returns {@code true}).
|
|
||||||
* <br>
|
|
||||||
* This method is equivalent to {@code syncWhile(() -> !cond.getAsBoolean())}.
|
|
||||||
*
|
|
||||||
* @param cond The condition to wait for.
|
|
||||||
* @return {@code true} if the condition is met. {@code false} if
|
|
||||||
* this executor runs out of tasks before the condition is met.
|
|
||||||
*/
|
|
||||||
boolean syncUntil(BooleanSupplier cond);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for running tasks, so long as the given condition is met
|
|
||||||
* ({@link BooleanSupplier#getAsBoolean()} returns {@code true}).
|
|
||||||
* <br>
|
|
||||||
* If this method is called on the
|
|
||||||
* <br>
|
|
||||||
* This method is equivalent to {@code syncUntil(() -> !cond.getAsBoolean())}.
|
|
||||||
*
|
|
||||||
* @param cond The condition sync on.
|
|
||||||
* @return {@code true} if the condition is no longer met. {@code false} if
|
|
||||||
* this executor runs out of tasks while the condition is still met.
|
|
||||||
*/
|
|
||||||
boolean syncWhile(BooleanSupplier cond);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedule a task to be run on the main thread.
|
|
||||||
* <br>
|
|
||||||
* This method may be called from any thread (including the main thread),
|
|
||||||
* but the runnable will <em>only</em> be executed once somebody calls
|
|
||||||
* either {@link #syncPoint()} or {@link #syncUntil(BooleanSupplier)}
|
|
||||||
* on this task executor's main thread.
|
|
||||||
* @param runnable The task to run.
|
|
||||||
*/
|
|
||||||
void scheduleForMainThread(Runnable runnable);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether the current thread is this task executor's main thread.
|
|
||||||
*
|
|
||||||
* @return {@code true} if the current thread is the main thread.
|
|
||||||
*/
|
|
||||||
boolean isMainThread();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for the number of threads this executor uses.
|
* Check for the number of threads this executor uses.
|
||||||
* <br>
|
* <br>
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.api.vertex;
|
|
||||||
|
|
||||||
public interface VertexView extends MutableVertexList {
|
|
||||||
long ptr();
|
|
||||||
|
|
||||||
void ptr(long ptr);
|
|
||||||
|
|
||||||
void vertexCount(int vertexCount);
|
|
||||||
|
|
||||||
long stride();
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
package dev.engine_room.flywheel.api.visual;
|
package dev.engine_room.flywheel.api.visual;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An effect is not attached to any formal game object, but allows you to hook into
|
* An effect is not attached to any formal game object, but allows you to hook into
|
||||||
@ -8,6 +9,8 @@ import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
|||||||
* without any built in support for networking.
|
* without any built in support for networking.
|
||||||
*/
|
*/
|
||||||
public interface Effect {
|
public interface Effect {
|
||||||
|
LevelAccessor level();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a visual that will be keyed by this effect object.
|
* Create a visual that will be keyed by this effect object.
|
||||||
*
|
*
|
||||||
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
|
||||||
public sealed interface SectionTrackedVisual extends Visual permits ShaderLightVisual, LightUpdatedVisual {
|
public sealed interface SectionTrackedVisual extends Visual permits LightUpdatedVisual, ShaderLightVisual {
|
||||||
/**
|
/**
|
||||||
* Set the section collector object.
|
* Set the section collector object.
|
||||||
*
|
*
|
||||||
|
@ -3,7 +3,7 @@ package dev.engine_room.flywheel.api.visualization;
|
|||||||
import org.joml.Matrix3fc;
|
import org.joml.Matrix3fc;
|
||||||
import org.joml.Matrix4fc;
|
import org.joml.Matrix4fc;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
public interface VisualEmbedding extends VisualizationContext {
|
public interface VisualEmbedding extends VisualizationContext {
|
||||||
|
@ -9,7 +9,7 @@ public interface VisualManager<T> {
|
|||||||
*
|
*
|
||||||
* @return The visual count.
|
* @return The visual count.
|
||||||
*/
|
*/
|
||||||
int getVisualCount();
|
int visualCount();
|
||||||
|
|
||||||
void queueAdd(T obj);
|
void queueAdd(T obj);
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package dev.engine_room.flywheel.api.visualization;
|
||||||
|
|
||||||
|
public enum VisualType {
|
||||||
|
BLOCK_ENTITY,
|
||||||
|
ENTITY,
|
||||||
|
EFFECT;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.api.visualization;
|
package dev.engine_room.flywheel.api.visualization;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
package dev.engine_room.flywheel.api.visualization;
|
package dev.engine_room.flywheel.api.visualization;
|
||||||
|
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||||
import dev.engine_room.flywheel.api.visual.Effect;
|
import dev.engine_room.flywheel.api.visual.Effect;
|
||||||
import dev.engine_room.flywheel.api.visual.Visual;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.server.level.BlockDestructionProgress;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
@ -27,52 +30,31 @@ public interface VisualizationManager {
|
|||||||
return FlwApiLink.INSTANCE.getVisualizationManagerOrThrow(level);
|
return FlwApiLink.INSTANCE.getVisualizationManagerOrThrow(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
Vec3i renderOrigin();
|
||||||
* 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);
|
VisualManager<BlockEntity> blockEntities();
|
||||||
}
|
|
||||||
|
VisualManager<Entity> entities();
|
||||||
|
|
||||||
|
VisualManager<Effect> effects();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this when you want to run {@link Visual#update}.
|
* Get the render dispatcher, which can be used to invoke rendering.
|
||||||
* @param entity The entity whose visual you want to update.
|
* <b>This should only be used by mods which heavily rewrite rendering to restore compatibility with Flywheel
|
||||||
|
* without mixins.</b>
|
||||||
*/
|
*/
|
||||||
static void queueUpdate(Entity entity) {
|
RenderDispatcher renderDispatcher();
|
||||||
Level level = entity.level();
|
|
||||||
VisualizationManager manager = get(level);
|
|
||||||
if (manager == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.getEntities().queueUpdate(entity);
|
@ApiStatus.NonExtendable
|
||||||
|
interface RenderDispatcher {
|
||||||
|
void onStartLevelRender(RenderContext ctx);
|
||||||
|
|
||||||
|
void afterBlockEntities(RenderContext ctx);
|
||||||
|
|
||||||
|
void afterEntities(RenderContext ctx);
|
||||||
|
|
||||||
|
void beforeCrumbling(RenderContext ctx, Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress);
|
||||||
|
|
||||||
|
void afterParticles(RenderContext ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<BlockEntity> getBlockEntities();
|
|
||||||
|
|
||||||
VisualManager<Entity> getEntities();
|
|
||||||
|
|
||||||
VisualManager<Effect> getEffects();
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ public final class FlwBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
ShaderIndices.init();
|
|
||||||
Backends.init();
|
Backends.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ import dev.engine_room.flywheel.api.Flywheel;
|
|||||||
import dev.engine_room.flywheel.api.layout.FloatRepr;
|
import dev.engine_room.flywheel.api.layout.FloatRepr;
|
||||||
import dev.engine_room.flywheel.api.layout.Layout;
|
import dev.engine_room.flywheel.api.layout.Layout;
|
||||||
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
|
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
|
||||||
import dev.engine_room.flywheel.api.vertex.VertexView;
|
|
||||||
import dev.engine_room.flywheel.backend.gl.array.VertexAttribute;
|
import dev.engine_room.flywheel.backend.gl.array.VertexAttribute;
|
||||||
import dev.engine_room.flywheel.lib.vertex.FullVertexView;
|
import dev.engine_room.flywheel.lib.vertex.FullVertexView;
|
||||||
|
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public final class InternalVertex {
|
public final class InternalVertex {
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.backend;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.lib.util.LevelAttached;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores the set of updates light sections for LightStorage to poll in its frame plan.
|
|
||||||
*/
|
|
||||||
public class LightUpdateHolder {
|
|
||||||
private static final LevelAttached<LightUpdateHolder> HOLDERS = new LevelAttached<>(level -> new LightUpdateHolder());
|
|
||||||
|
|
||||||
private final LongSet updatedSections = new LongOpenHashSet();
|
|
||||||
|
|
||||||
private LightUpdateHolder() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LightUpdateHolder get(LevelAccessor level) {
|
|
||||||
return HOLDERS.get(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LongSet getAndClearUpdatedSections() {
|
|
||||||
if (updatedSections.isEmpty()) {
|
|
||||||
return LongSet.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
var out = new LongArraySet(updatedSections);
|
|
||||||
updatedSections.clear();
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(long section) {
|
|
||||||
updatedSections.add(section);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,135 @@
|
|||||||
|
package dev.engine_room.flywheel.backend;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||||
|
import dev.engine_room.flywheel.api.material.FogShader;
|
||||||
|
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||||
|
import dev.engine_room.flywheel.api.registry.Registry;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public final class MaterialShaderIndices {
|
||||||
|
@Nullable
|
||||||
|
private static Index vertexSources;
|
||||||
|
@Nullable
|
||||||
|
private static Index fragmentSources;
|
||||||
|
@Nullable
|
||||||
|
private static Index fogSources;
|
||||||
|
@Nullable
|
||||||
|
private static Index cutoutSources;
|
||||||
|
|
||||||
|
private MaterialShaderIndices() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Index vertexSources() {
|
||||||
|
if (vertexSources == null) {
|
||||||
|
vertexSources = indexFromRegistry(MaterialShaders.REGISTRY, MaterialShaders::vertexSource);
|
||||||
|
}
|
||||||
|
return vertexSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Index fragmentSources() {
|
||||||
|
if (fragmentSources == null) {
|
||||||
|
fragmentSources = indexFromRegistry(MaterialShaders.REGISTRY, MaterialShaders::fragmentSource);
|
||||||
|
}
|
||||||
|
return fragmentSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Index fogSources() {
|
||||||
|
if (fogSources == null) {
|
||||||
|
fogSources = indexFromRegistry(FogShader.REGISTRY, FogShader::source);
|
||||||
|
}
|
||||||
|
return fogSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Index cutoutSources() {
|
||||||
|
if (cutoutSources == null) {
|
||||||
|
cutoutSources = indexFromRegistry(CutoutShader.REGISTRY, CutoutShader::source);
|
||||||
|
}
|
||||||
|
return cutoutSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int vertexIndex(MaterialShaders shaders) {
|
||||||
|
return vertexSources().index(shaders.vertexSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int fragmentIndex(MaterialShaders shaders) {
|
||||||
|
return fragmentSources().index(shaders.fragmentSource());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int fogIndex(FogShader fogShader) {
|
||||||
|
return fogSources().index(fogShader.source());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int cutoutIndex(CutoutShader cutoutShader) {
|
||||||
|
return cutoutSources().index(cutoutShader.source());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Index indexFromRegistry(Registry<T> registry, Function<T, ResourceLocation> sourceFunc) {
|
||||||
|
if (!registry.isFrozen()) {
|
||||||
|
throw new IllegalStateException("Cannot create index from registry that is not frozen!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new IndexBuilder();
|
||||||
|
|
||||||
|
for (T object : registry) {
|
||||||
|
builder.add(sourceFunc.apply(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Index {
|
||||||
|
private final Object2IntMap<ResourceLocation> sources2Index;
|
||||||
|
private final ObjectList<ResourceLocation> sources;
|
||||||
|
|
||||||
|
private Index(IndexBuilder builder) {
|
||||||
|
this.sources2Index = new Object2IntOpenHashMap<>(builder.sources2Index);
|
||||||
|
this.sources = new ObjectArrayList<>(builder.sources);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int index(ResourceLocation source) {
|
||||||
|
return sources2Index.getInt(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation get(int index) {
|
||||||
|
return sources.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unmodifiable
|
||||||
|
public List<ResourceLocation> all() {
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class IndexBuilder {
|
||||||
|
private final Object2IntMap<ResourceLocation> sources2Index;
|
||||||
|
private final ObjectList<ResourceLocation> sources;
|
||||||
|
private int index = 0;
|
||||||
|
|
||||||
|
public IndexBuilder() {
|
||||||
|
sources2Index = new Object2IntOpenHashMap<>();
|
||||||
|
sources2Index.defaultReturnValue(-1);
|
||||||
|
sources = new ObjectArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(ResourceLocation source) {
|
||||||
|
if (sources2Index.putIfAbsent(source, index) == -1) {
|
||||||
|
sources.add(source);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Index build() {
|
||||||
|
return new Index(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,170 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.backend;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
|
||||||
import dev.engine_room.flywheel.api.material.FogShader;
|
|
||||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
|
||||||
import dev.engine_room.flywheel.api.registry.Registry;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectLists;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
public final class ShaderIndices {
|
|
||||||
@Nullable
|
|
||||||
private static Index vertexShaders;
|
|
||||||
@Nullable
|
|
||||||
private static Index fragmentShaders;
|
|
||||||
@Nullable
|
|
||||||
private static Index fogShaders;
|
|
||||||
@Nullable
|
|
||||||
private static Index cutoutShaders;
|
|
||||||
|
|
||||||
private ShaderIndices() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Index materialVertex() {
|
|
||||||
if (vertexShaders == null) {
|
|
||||||
throw new IllegalStateException("Not initialized!");
|
|
||||||
}
|
|
||||||
return vertexShaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Index materialFragment() {
|
|
||||||
if (fragmentShaders == null) {
|
|
||||||
throw new IllegalStateException("Not initialized!");
|
|
||||||
}
|
|
||||||
return fragmentShaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Index fog() {
|
|
||||||
if (fogShaders == null) {
|
|
||||||
throw new IllegalStateException("Not initialized!");
|
|
||||||
}
|
|
||||||
return fogShaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Index cutout() {
|
|
||||||
if (cutoutShaders == null) {
|
|
||||||
throw new IllegalStateException("Not initialized!");
|
|
||||||
}
|
|
||||||
return cutoutShaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getVertexShaderIndex(MaterialShaders shaders) {
|
|
||||||
return materialVertex().index(shaders.vertexShader());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFragmentShaderIndex(MaterialShaders shaders) {
|
|
||||||
return materialFragment().index(shaders.fragmentShader());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getFogShaderIndex(FogShader fogShader) {
|
|
||||||
return fog().index(fogShader.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getCutoutShaderIndex(CutoutShader cutoutShader) {
|
|
||||||
return cutout().index(cutoutShader.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initMaterialShaders(Registry<MaterialShaders> registry) {
|
|
||||||
int amount = registry.getAll()
|
|
||||||
.size();
|
|
||||||
|
|
||||||
var vertexShaders = new IndexBuilder(amount);
|
|
||||||
var fragmentShaders = new IndexBuilder(amount);
|
|
||||||
|
|
||||||
for (MaterialShaders shaders : registry) {
|
|
||||||
vertexShaders.add(shaders.vertexShader());
|
|
||||||
fragmentShaders.add(shaders.fragmentShader());
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIndices.vertexShaders = vertexShaders.build();
|
|
||||||
ShaderIndices.fragmentShaders = fragmentShaders.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initFogShaders(Registry<FogShader> registry) {
|
|
||||||
int amount = registry.getAll()
|
|
||||||
.size();
|
|
||||||
|
|
||||||
var fog = new IndexBuilder(amount);
|
|
||||||
|
|
||||||
for (FogShader shaders : registry) {
|
|
||||||
fog.add(shaders.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIndices.fogShaders = fog.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initCutoutShaders(Registry<CutoutShader> registry) {
|
|
||||||
int amount = registry.getAll()
|
|
||||||
.size();
|
|
||||||
|
|
||||||
var cutout = new IndexBuilder(amount);
|
|
||||||
|
|
||||||
for (CutoutShader shaders : registry) {
|
|
||||||
cutout.add(shaders.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIndices.cutoutShaders = cutout.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init() {
|
|
||||||
MaterialShaders.REGISTRY.addFreezeCallback(ShaderIndices::initMaterialShaders);
|
|
||||||
FogShader.REGISTRY.addFreezeCallback(ShaderIndices::initFogShaders);
|
|
||||||
CutoutShader.REGISTRY.addFreezeCallback(ShaderIndices::initCutoutShaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Index {
|
|
||||||
private final Object2IntMap<ResourceLocation> shaders2Index;
|
|
||||||
private final ObjectList<ResourceLocation> shaders;
|
|
||||||
|
|
||||||
private Index(IndexBuilder builder) {
|
|
||||||
this.shaders2Index = Object2IntMaps.unmodifiable(builder.shaders2Index);
|
|
||||||
this.shaders = ObjectLists.unmodifiable(builder.shaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int index(ResourceLocation shader) {
|
|
||||||
return shaders2Index.getInt(shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unmodifiable
|
|
||||||
public List<ResourceLocation> all() {
|
|
||||||
return shaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceLocation get(int index) {
|
|
||||||
return shaders.get(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class IndexBuilder {
|
|
||||||
private int index;
|
|
||||||
private final Object2IntMap<ResourceLocation> shaders2Index;
|
|
||||||
private final ObjectList<ResourceLocation> shaders;
|
|
||||||
|
|
||||||
public IndexBuilder(int amount) {
|
|
||||||
shaders2Index = new Object2IntOpenHashMap<>();
|
|
||||||
shaders2Index.defaultReturnValue(-1);
|
|
||||||
shaders = new ObjectArrayList<>(amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(ResourceLocation shader) {
|
|
||||||
if (shaders2Index.putIfAbsent(shader, index) == -1) {
|
|
||||||
shaders.add(shader);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Index build() {
|
|
||||||
return new Index(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,7 +10,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
|
|
||||||
import dev.engine_room.flywheel.api.Flywheel;
|
import dev.engine_room.flywheel.api.Flywheel;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.backend.ShaderIndices;
|
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||||
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
|
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
|
||||||
import dev.engine_room.flywheel.backend.compile.core.CompilerStats;
|
import dev.engine_room.flywheel.backend.compile.core.CompilerStats;
|
||||||
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
|
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
|
||||||
@ -74,7 +74,7 @@ public final class FlwPrograms {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loader) {
|
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loader) {
|
||||||
return UberShaderComponent.builder(Flywheel.rl("material_vertex"))
|
return UberShaderComponent.builder(Flywheel.rl("material_vertex"))
|
||||||
.materialSources(ShaderIndices.materialVertex()
|
.materialSources(MaterialShaderIndices.vertexSources()
|
||||||
.all())
|
.all())
|
||||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||||
.switchOn(GlslExpr.variable("_flw_uberMaterialVertexIndex"))
|
.switchOn(GlslExpr.variable("_flw_uberMaterialVertexIndex"))
|
||||||
@ -84,7 +84,7 @@ public final class FlwPrograms {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loader) {
|
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loader) {
|
||||||
return UberShaderComponent.builder(Flywheel.rl("material_fragment"))
|
return UberShaderComponent.builder(Flywheel.rl("material_fragment"))
|
||||||
.materialSources(ShaderIndices.materialFragment()
|
.materialSources(MaterialShaderIndices.fragmentSources()
|
||||||
.all())
|
.all())
|
||||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||||
.switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
|
.switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
|
||||||
@ -94,7 +94,7 @@ public final class FlwPrograms {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static UberShaderComponent createFogComponent(SourceLoader loader) {
|
private static UberShaderComponent createFogComponent(SourceLoader loader) {
|
||||||
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||||
.materialSources(ShaderIndices.fog()
|
.materialSources(MaterialShaderIndices.fogSources()
|
||||||
.all())
|
.all())
|
||||||
.adapt(FnSignature.create()
|
.adapt(FnSignature.create()
|
||||||
.returnType("vec4")
|
.returnType("vec4")
|
||||||
@ -108,7 +108,7 @@ public final class FlwPrograms {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
|
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
|
||||||
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||||
.materialSources(ShaderIndices.cutout()
|
.materialSources(MaterialShaderIndices.cutoutSources()
|
||||||
.all())
|
.all())
|
||||||
.adapt(FnSignature.create()
|
.adapt(FnSignature.create()
|
||||||
.returnType("bool")
|
.returnType("bool")
|
||||||
|
@ -8,7 +8,7 @@ import dev.engine_room.flywheel.api.instance.Instance;
|
|||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
import dev.engine_room.flywheel.lib.util.AtomicBitSet;
|
import dev.engine_room.flywheel.backend.util.AtomicBitSet;
|
||||||
|
|
||||||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
||||||
public final InstanceType<I> type;
|
public final InstanceType<I> type;
|
||||||
|
@ -9,11 +9,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.backend.Engine;
|
import dev.engine_room.flywheel.api.backend.Engine;
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
import dev.engine_room.flywheel.lib.util.Pair;
|
import dev.engine_room.flywheel.lib.util.Pair;
|
||||||
@ -36,13 +36,8 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||||||
protected final Queue<UninitializedInstancer<N, ?>> initializationQueue = new ConcurrentLinkedQueue<>();
|
protected final Queue<UninitializedInstancer<N, ?>> initializationQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <I extends Instance> Instancer<I> getInstancer(Environment environment, InstanceType<I> type, Model model, RenderStage stage) {
|
public <I extends Instance> Instancer<I> getInstancer(Environment environment, InstanceType<I> type, Model model, VisualType visualType) {
|
||||||
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(environment, type, model, stage), this::createAndDeferInit);
|
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(environment, type, model, visualType), this::createAndDeferInit);
|
||||||
}
|
|
||||||
|
|
||||||
public void delete() {
|
|
||||||
instancers.clear();
|
|
||||||
initializationQueue.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush(LightStorage lightStorage) {
|
public void flush(LightStorage lightStorage) {
|
||||||
@ -59,9 +54,9 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||||||
.forEach(AbstractInstancer::clear);
|
.forEach(AbstractInstancer::clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void renderCrumbling(List<Engine.CrumblingBlock> crumblingBlocks);
|
public abstract void render(VisualType visualType);
|
||||||
|
|
||||||
public abstract void renderStage(RenderStage stage);
|
public abstract void renderCrumbling(List<Engine.CrumblingBlock> crumblingBlocks);
|
||||||
|
|
||||||
protected abstract <I extends Instance> N create(InstancerKey<I> type);
|
protected abstract <I extends Instance> N create(InstancerKey<I> type);
|
||||||
|
|
||||||
@ -80,10 +75,6 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected record UninitializedInstancer<N, I extends Instance>(InstancerKey<I> key, N instancer) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkAndWarnEmptyModel(Model model) {
|
private static boolean checkAndWarnEmptyModel(Model model) {
|
||||||
if (!model.meshes().isEmpty()) {
|
if (!model.meshes().isEmpty()) {
|
||||||
return true;
|
return true;
|
||||||
@ -133,4 +124,12 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||||||
}
|
}
|
||||||
return byType;
|
return byType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
instancers.clear();
|
||||||
|
initializationQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected record UninitializedInstancer<N, I extends Instance>(InstancerKey<I> key, N instancer) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,37 +2,34 @@ package dev.engine_room.flywheel.backend.engine;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.api.backend.Engine;
|
import dev.engine_room.flywheel.api.backend.Engine;
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
import dev.engine_room.flywheel.api.task.Plan;
|
import dev.engine_room.flywheel.api.task.Plan;
|
||||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage;
|
import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage;
|
||||||
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
||||||
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
|
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
|
||||||
import dev.engine_room.flywheel.lib.task.Flag;
|
|
||||||
import dev.engine_room.flywheel.lib.task.NamedFlag;
|
|
||||||
import dev.engine_room.flywheel.lib.task.SyncedPlan;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class EngineImpl implements Engine {
|
public class EngineImpl implements Engine {
|
||||||
private final DrawManager<? extends AbstractInstancer<?>> drawManager;
|
private final DrawManager<? extends AbstractInstancer<?>> drawManager;
|
||||||
private final int sqrMaxOriginDistance;
|
private final int sqrMaxOriginDistance;
|
||||||
private final Flag flushFlag = new NamedFlag("flushed");
|
|
||||||
private final EnvironmentStorage environmentStorage;
|
private final EnvironmentStorage environmentStorage;
|
||||||
private final LightStorage lightStorage;
|
private final LightStorage lightStorage;
|
||||||
|
|
||||||
@ -46,32 +43,18 @@ public class EngineImpl implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VisualizationContext createVisualizationContext(RenderStage stage) {
|
public VisualizationContext createVisualizationContext(VisualType visualType) {
|
||||||
return new VisualizationContextImpl(stage);
|
return new VisualizationContextImpl(visualType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Plan<RenderContext> createFramePlan() {
|
public Plan<RenderContext> createFramePlan() {
|
||||||
return lightStorage.createFramePlan()
|
return lightStorage.createFramePlan();
|
||||||
.then(SyncedPlan.of(this::flush));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
|
public Vec3i renderOrigin() {
|
||||||
executor.syncUntil(flushFlag::isRaised);
|
return renderOrigin;
|
||||||
if (stage.isLast()) {
|
|
||||||
flushFlag.lower();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawManager.renderStage(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderCrumbling(TaskExecutor executor, RenderContext context, List<CrumblingBlock> crumblingBlocks) {
|
|
||||||
// Need to wait for flush before we can inspect instancer state.
|
|
||||||
executor.syncUntil(flushFlag::isRaised);
|
|
||||||
|
|
||||||
drawManager.renderCrumbling(crumblingBlocks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -92,13 +75,32 @@ public class EngineImpl implements Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3i renderOrigin() {
|
public void lightSections(LongSet sections) {
|
||||||
return renderOrigin;
|
lightStorage.sections(sections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lightSections(LongSet sections) {
|
public void onLightUpdate(SectionPos sectionPos, LightLayer layer) {
|
||||||
lightStorage.sections(sections);
|
lightStorage.onLightUpdate(sectionPos.asLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupRender(RenderContext context) {
|
||||||
|
try (var state = GlStateTracker.getRestoreState()) {
|
||||||
|
Uniforms.update(context);
|
||||||
|
environmentStorage.flush();
|
||||||
|
drawManager.flush(lightStorage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(RenderContext context, VisualType visualType) {
|
||||||
|
drawManager.render(visualType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderCrumbling(RenderContext context, List<CrumblingBlock> crumblingBlocks) {
|
||||||
|
drawManager.renderCrumbling(crumblingBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -107,18 +109,8 @@ public class EngineImpl implements Engine {
|
|||||||
lightStorage.delete();
|
lightStorage.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <I extends Instance> Instancer<I> instancer(Environment environment, InstanceType<I> type, Model model, RenderStage stage) {
|
public <I extends Instance> Instancer<I> instancer(Environment environment, InstanceType<I> type, Model model, VisualType visualType) {
|
||||||
return drawManager.getInstancer(environment, type, model, stage);
|
return drawManager.getInstancer(environment, type, model, visualType);
|
||||||
}
|
|
||||||
|
|
||||||
private void flush(RenderContext ctx) {
|
|
||||||
try (var state = GlStateTracker.getRestoreState()) {
|
|
||||||
Uniforms.update(ctx);
|
|
||||||
environmentStorage.flush();
|
|
||||||
drawManager.flush(lightStorage);
|
|
||||||
}
|
|
||||||
|
|
||||||
flushFlag.raise();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnvironmentStorage environmentStorage() {
|
public EnvironmentStorage environmentStorage() {
|
||||||
@ -131,11 +123,11 @@ public class EngineImpl implements Engine {
|
|||||||
|
|
||||||
private class VisualizationContextImpl implements VisualizationContext {
|
private class VisualizationContextImpl implements VisualizationContext {
|
||||||
private final InstancerProviderImpl instancerProvider;
|
private final InstancerProviderImpl instancerProvider;
|
||||||
private final RenderStage stage;
|
private final VisualType visualType;
|
||||||
|
|
||||||
public VisualizationContextImpl(RenderStage stage) {
|
public VisualizationContextImpl(VisualType visualType) {
|
||||||
instancerProvider = new InstancerProviderImpl(EngineImpl.this, stage);
|
instancerProvider = new InstancerProviderImpl(EngineImpl.this, visualType);
|
||||||
this.stage = stage;
|
this.visualType = visualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -150,7 +142,7 @@ public class EngineImpl implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VisualEmbedding createEmbedding() {
|
public VisualEmbedding createEmbedding() {
|
||||||
var out = new EmbeddedEnvironment(EngineImpl.this, stage);
|
var out = new EmbeddedEnvironment(EngineImpl.this, visualType);
|
||||||
environmentStorage.track(out);
|
environmentStorage.track(out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package dev.engine_room.flywheel.backend.engine;
|
package dev.engine_room.flywheel.backend.engine;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
public record InstancerKey<I extends Instance>(Environment environment, InstanceType<I> type, Model model,
|
public record InstancerKey<I extends Instance>(Environment environment, InstanceType<I> type, Model model,
|
||||||
RenderStage stage) {
|
VisualType visualType) {
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package dev.engine_room.flywheel.backend.engine;
|
package dev.engine_room.flywheel.backend.engine;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.GlobalEnvironment;
|
import dev.engine_room.flywheel.backend.engine.embed.GlobalEnvironment;
|
||||||
|
|
||||||
public record InstancerProviderImpl(EngineImpl engine, RenderStage renderStage) implements InstancerProvider {
|
public record InstancerProviderImpl(EngineImpl engine, VisualType visualType) implements InstancerProvider {
|
||||||
@Override
|
@Override
|
||||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
||||||
return engine.instancer(GlobalEnvironment.INSTANCE, type, model, renderStage);
|
return engine.instancer(GlobalEnvironment.INSTANCE, type, model, visualType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,16 +5,14 @@ import java.util.BitSet;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
|
||||||
import dev.engine_room.flywheel.api.task.Plan;
|
import dev.engine_room.flywheel.api.task.Plan;
|
||||||
import dev.engine_room.flywheel.backend.LightUpdateHolder;
|
|
||||||
import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer;
|
import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer;
|
||||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import dev.engine_room.flywheel.lib.task.SimplePlan;
|
import dev.engine_room.flywheel.lib.task.SimplePlan;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
@ -53,6 +51,7 @@ public class LightStorage {
|
|||||||
private final BitSet changed = new BitSet();
|
private final BitSet changed = new BitSet();
|
||||||
private boolean needsLutRebuild = false;
|
private boolean needsLutRebuild = false;
|
||||||
|
|
||||||
|
private final LongSet updatedSections = new LongOpenHashSet();
|
||||||
@Nullable
|
@Nullable
|
||||||
private LongSet requestedSections;
|
private LongSet requestedSections;
|
||||||
|
|
||||||
@ -72,11 +71,12 @@ public class LightStorage {
|
|||||||
requestedSections = sections;
|
requestedSections = sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plan<RenderContext> createFramePlan() {
|
public void onLightUpdate(long section) {
|
||||||
return SimplePlan.of(() -> {
|
updatedSections.add(section);
|
||||||
var updatedSections = LightUpdateHolder.get(level)
|
}
|
||||||
.getAndClearUpdatedSections();
|
|
||||||
|
|
||||||
|
public <C> Plan<C> createFramePlan() {
|
||||||
|
return SimplePlan.of(() -> {
|
||||||
if (updatedSections.isEmpty() && requestedSections == null) {
|
if (updatedSections.isEmpty() && requestedSections == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,15 +87,15 @@ public class LightStorage {
|
|||||||
LongSet sectionsToCollect;
|
LongSet sectionsToCollect;
|
||||||
if (requestedSections == null) {
|
if (requestedSections == null) {
|
||||||
// If none were requested, then we need to collect all sections that received updates.
|
// If none were requested, then we need to collect all sections that received updates.
|
||||||
sectionsToCollect = new LongArraySet();
|
sectionsToCollect = new LongOpenHashSet();
|
||||||
} else {
|
} else {
|
||||||
// If we did receive a new set of requested sections, we only
|
// If we did receive a new set of requested sections, we only
|
||||||
// need to collect the sections that weren't yet tracked.
|
// need to collect the sections that weren't yet tracked.
|
||||||
sectionsToCollect = requestedSections;
|
sectionsToCollect = new LongOpenHashSet(requestedSections);
|
||||||
sectionsToCollect.removeAll(section2ArenaIndex.keySet());
|
sectionsToCollect.removeAll(section2ArenaIndex.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// updatedSections contains all sections than received light updates,
|
// updatedSections contains all sections that received light updates,
|
||||||
// but we only care about its intersection with our tracked sections.
|
// but we only care about its intersection with our tracked sections.
|
||||||
for (long updatedSection : updatedSections) {
|
for (long updatedSection : updatedSections) {
|
||||||
// Since sections contain the border light of their neighbors, we need to collect the neighbors as well.
|
// Since sections contain the border light of their neighbors, we need to collect the neighbors as well.
|
||||||
@ -115,6 +115,7 @@ public class LightStorage {
|
|||||||
// TODO: Should this be done in parallel?
|
// TODO: Should this be done in parallel?
|
||||||
sectionsToCollect.forEach(this::collectSection);
|
sectionsToCollect.forEach(this::collectSection);
|
||||||
|
|
||||||
|
updatedSections.clear();
|
||||||
requestedSections = null;
|
requestedSections = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -130,7 +131,7 @@ public class LightStorage {
|
|||||||
var entry = it.next();
|
var entry = it.next();
|
||||||
var section = entry.getLongKey();
|
var section = entry.getLongKey();
|
||||||
|
|
||||||
if (!this.requestedSections.contains(section)) {
|
if (!requestedSections.contains(section)) {
|
||||||
arena.free(entry.getIntValue());
|
arena.free(entry.getIntValue());
|
||||||
needsLutRebuild = true;
|
needsLutRebuild = true;
|
||||||
it.remove();
|
it.remove();
|
||||||
|
@ -4,7 +4,7 @@ import dev.engine_room.flywheel.api.material.DepthTest;
|
|||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
import dev.engine_room.flywheel.api.material.Transparency;
|
import dev.engine_room.flywheel.api.material.Transparency;
|
||||||
import dev.engine_room.flywheel.api.material.WriteMask;
|
import dev.engine_room.flywheel.api.material.WriteMask;
|
||||||
import dev.engine_room.flywheel.backend.ShaderIndices;
|
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
// Materials are unpacked in "flywheel:flywheel/internal/packed_material.glsl"
|
// Materials are unpacked in "flywheel:flywheel/internal/packed_material.glsl"
|
||||||
@ -53,13 +53,8 @@ public final class MaterialEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int packFogAndCutout(Material material) {
|
public static int packFogAndCutout(Material material) {
|
||||||
var fog = ShaderIndices.fog()
|
var fog = MaterialShaderIndices.fogIndex(material.fog());
|
||||||
.index(material.fog()
|
var cutout = MaterialShaderIndices.cutoutIndex(material.cutout());
|
||||||
.source());
|
|
||||||
var cutout = ShaderIndices.cutout()
|
|
||||||
.index(material.cutout()
|
|
||||||
.source());
|
|
||||||
|
|
||||||
return fog & 0xFFFF | (cutout & 0xFFFF) << 16;
|
return fog & 0xFFFF | (cutout & 0xFFFF) << 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,13 +9,13 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.model.Mesh;
|
import dev.engine_room.flywheel.api.model.Mesh;
|
||||||
import dev.engine_room.flywheel.api.vertex.VertexView;
|
|
||||||
import dev.engine_room.flywheel.backend.InternalVertex;
|
import dev.engine_room.flywheel.backend.InternalVertex;
|
||||||
import dev.engine_room.flywheel.backend.gl.GlPrimitive;
|
import dev.engine_room.flywheel.backend.gl.GlPrimitive;
|
||||||
import dev.engine_room.flywheel.backend.gl.array.GlVertexArray;
|
import dev.engine_room.flywheel.backend.gl.array.GlVertexArray;
|
||||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import dev.engine_room.flywheel.backend.util.ReferenceCounted;
|
import dev.engine_room.flywheel.backend.util.ReferenceCounted;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
|
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||||
|
|
||||||
public class MeshPool {
|
public class MeshPool {
|
||||||
private final VertexView vertexView;
|
private final VertexView vertexView;
|
||||||
|
@ -6,13 +6,13 @@ import org.joml.Matrix3fc;
|
|||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Matrix4fc;
|
import org.joml.Matrix4fc;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||||
import dev.engine_room.flywheel.backend.engine.EngineImpl;
|
import dev.engine_room.flywheel.backend.engine.EngineImpl;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
@ -20,7 +20,7 @@ import net.minecraft.core.Vec3i;
|
|||||||
|
|
||||||
public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
||||||
private final EngineImpl engine;
|
private final EngineImpl engine;
|
||||||
private final RenderStage renderStage;
|
private final VisualType visualType;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final EmbeddedEnvironment parent;
|
private final EmbeddedEnvironment parent;
|
||||||
private final InstancerProvider instancerProvider;
|
private final InstancerProvider instancerProvider;
|
||||||
@ -32,22 +32,22 @@ public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
|||||||
|
|
||||||
private boolean deleted = false;
|
private boolean deleted = false;
|
||||||
|
|
||||||
public EmbeddedEnvironment(EngineImpl engine, RenderStage renderStage, @Nullable EmbeddedEnvironment parent) {
|
public EmbeddedEnvironment(EngineImpl engine, VisualType visualType, @Nullable EmbeddedEnvironment parent) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.renderStage = renderStage;
|
this.visualType = visualType;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
instancerProvider = new InstancerProvider() {
|
instancerProvider = new InstancerProvider() {
|
||||||
@Override
|
@Override
|
||||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
||||||
// Kinda cursed usage of anonymous classes here, but it does the job.
|
// Kinda cursed usage of anonymous classes here, but it does the job.
|
||||||
return engine.instancer(EmbeddedEnvironment.this, type, model, renderStage);
|
return engine.instancer(EmbeddedEnvironment.this, type, model, visualType);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) {
|
public EmbeddedEnvironment(EngineImpl engine, VisualType visualType) {
|
||||||
this(engine, renderStage, null);
|
this(engine, visualType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,7 +68,7 @@ public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VisualEmbedding createEmbedding() {
|
public VisualEmbedding createEmbedding() {
|
||||||
var out = new EmbeddedEnvironment(engine, renderStage, this);
|
var out = new EmbeddedEnvironment(engine, visualType, this);
|
||||||
engine.environmentStorage()
|
engine.environmentStorage()
|
||||||
.track(out);
|
.track(out);
|
||||||
return out;
|
return out;
|
||||||
|
@ -14,11 +14,11 @@ import java.util.EnumMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
|
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
|
||||||
@ -30,7 +30,7 @@ import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
|||||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||||
|
|
||||||
public class IndirectCullingGroup<I extends Instance> {
|
public class IndirectCullingGroup<I extends Instance> {
|
||||||
private static final Comparator<IndirectDraw> DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::stage)
|
private static final Comparator<IndirectDraw> DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::visualType)
|
||||||
.thenComparing(IndirectDraw::indexOfMeshInModel)
|
.thenComparing(IndirectDraw::indexOfMeshInModel)
|
||||||
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR);
|
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
private final IndirectBuffers buffers;
|
private final IndirectBuffers buffers;
|
||||||
private final List<IndirectInstancer<I>> instancers = new ArrayList<>();
|
private final List<IndirectInstancer<I>> instancers = new ArrayList<>();
|
||||||
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
|
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
|
||||||
private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class);
|
private final Map<VisualType, List<MultiDraw>> multiDraws = new EnumMap<>(VisualType.class);
|
||||||
|
|
||||||
private final IndirectPrograms programs;
|
private final IndirectPrograms programs;
|
||||||
private final GlProgram cullProgram;
|
private final GlProgram cullProgram;
|
||||||
@ -145,36 +145,36 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
|
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean nothingToDo(RenderStage stage) {
|
private boolean nothingToDo(VisualType visualType) {
|
||||||
return nothingToDo() || !multiDraws.containsKey(stage);
|
return nothingToDo() || !multiDraws.containsKey(visualType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sortDraws() {
|
private void sortDraws() {
|
||||||
multiDraws.clear();
|
multiDraws.clear();
|
||||||
// sort by stage, then material
|
// sort by visual type, then material
|
||||||
indirectDraws.sort(DRAW_COMPARATOR);
|
indirectDraws.sort(DRAW_COMPARATOR);
|
||||||
|
|
||||||
for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
|
for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
|
||||||
var draw1 = indirectDraws.get(i);
|
var draw1 = indirectDraws.get(i);
|
||||||
var material1 = draw1.material();
|
var material1 = draw1.material();
|
||||||
var stage1 = draw1.stage();
|
var visualType1 = draw1.visualType();
|
||||||
|
|
||||||
// if the next draw call has a different RenderStage or Material, start a new MultiDraw
|
// if the next draw call has a different VisualType or Material, start a new MultiDraw
|
||||||
if (i == indirectDraws.size() - 1 || stage1 != indirectDraws.get(i + 1)
|
if (i == indirectDraws.size() - 1 || visualType1 != indirectDraws.get(i + 1)
|
||||||
.stage() || !material1.equals(indirectDraws.get(i + 1)
|
.visualType() || !material1.equals(indirectDraws.get(i + 1)
|
||||||
.material())) {
|
.material())) {
|
||||||
multiDraws.computeIfAbsent(stage1, s -> new ArrayList<>())
|
multiDraws.computeIfAbsent(visualType1, s -> new ArrayList<>())
|
||||||
.add(new MultiDraw(material1, start, i + 1));
|
.add(new MultiDraw(material1, start, i + 1));
|
||||||
start = i + 1;
|
start = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStage(RenderStage stage) {
|
public boolean hasVisualType(VisualType visualType) {
|
||||||
return multiDraws.containsKey(stage);
|
return multiDraws.containsKey(visualType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(IndirectInstancer<I> instancer, Model model, RenderStage stage, MeshPool meshPool) {
|
public void add(IndirectInstancer<I> instancer, Model model, VisualType visualType, MeshPool meshPool) {
|
||||||
instancer.modelIndex = instancers.size();
|
instancer.modelIndex = instancers.size();
|
||||||
instancers.add(instancer);
|
instancers.add(instancer);
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
var entry = meshes.get(i);
|
var entry = meshes.get(i);
|
||||||
|
|
||||||
MeshPool.PooledMesh mesh = meshPool.alloc(entry.mesh());
|
MeshPool.PooledMesh mesh = meshPool.alloc(entry.mesh());
|
||||||
var draw = new IndirectDraw(instancer, entry.material(), mesh, stage, i);
|
var draw = new IndirectDraw(instancer, entry.material(), mesh, visualType, i);
|
||||||
indirectDraws.add(draw);
|
indirectDraws.add(draw);
|
||||||
instancer.addDraw(draw);
|
instancer.addDraw(draw);
|
||||||
}
|
}
|
||||||
@ -191,8 +191,8 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
needsDrawSort = true;
|
needsDrawSort = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit(RenderStage stage) {
|
public void submit(VisualType visualType) {
|
||||||
if (nothingToDo(stage)) {
|
if (nothingToDo(visualType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||||||
|
|
||||||
var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
|
var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
|
||||||
|
|
||||||
for (var multiDraw : multiDraws.get(stage)) {
|
for (var multiDraw : multiDraws.get(visualType)) {
|
||||||
glUniform1ui(flwBaseDraw, multiDraw.start);
|
glUniform1ui(flwBaseDraw, multiDraw.start);
|
||||||
|
|
||||||
MaterialRenderState.setup(multiDraw.material);
|
MaterialRenderState.setup(multiDraw.material);
|
||||||
|
@ -2,9 +2,9 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
|||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
import dev.engine_room.flywheel.backend.ShaderIndices;
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
|
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||||
import dev.engine_room.flywheel.backend.engine.MaterialEncoder;
|
import dev.engine_room.flywheel.backend.engine.MaterialEncoder;
|
||||||
import dev.engine_room.flywheel.backend.engine.MeshPool;
|
import dev.engine_room.flywheel.backend.engine.MeshPool;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ public class IndirectDraw {
|
|||||||
private final IndirectInstancer<?> instancer;
|
private final IndirectInstancer<?> instancer;
|
||||||
private final Material material;
|
private final Material material;
|
||||||
private final MeshPool.PooledMesh mesh;
|
private final MeshPool.PooledMesh mesh;
|
||||||
private final RenderStage stage;
|
private final VisualType visualType;
|
||||||
private final int indexOfMeshInModel;
|
private final int indexOfMeshInModel;
|
||||||
|
|
||||||
private final int materialVertexIndex;
|
private final int materialVertexIndex;
|
||||||
@ -21,17 +21,17 @@ public class IndirectDraw {
|
|||||||
private final int packedMaterialProperties;
|
private final int packedMaterialProperties;
|
||||||
private boolean deleted;
|
private boolean deleted;
|
||||||
|
|
||||||
public IndirectDraw(IndirectInstancer<?> instancer, Material material, MeshPool.PooledMesh mesh, RenderStage stage, int indexOfMeshInModel) {
|
public IndirectDraw(IndirectInstancer<?> instancer, Material material, MeshPool.PooledMesh mesh, VisualType visualType, int indexOfMeshInModel) {
|
||||||
this.instancer = instancer;
|
this.instancer = instancer;
|
||||||
this.material = material;
|
this.material = material;
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.stage = stage;
|
this.visualType = visualType;
|
||||||
this.indexOfMeshInModel = indexOfMeshInModel;
|
this.indexOfMeshInModel = indexOfMeshInModel;
|
||||||
|
|
||||||
mesh.acquire();
|
mesh.acquire();
|
||||||
|
|
||||||
this.materialVertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
|
this.materialVertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||||
this.materialFragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
|
this.materialFragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||||
this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
||||||
this.packedMaterialProperties = MaterialEncoder.packProperties(material);
|
this.packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||||
}
|
}
|
||||||
@ -48,8 +48,8 @@ public class IndirectDraw {
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderStage stage() {
|
public VisualType visualType() {
|
||||||
return stage;
|
return visualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int indexOfMeshInModel() {
|
public int indexOfMeshInModel() {
|
||||||
@ -80,8 +80,8 @@ public class IndirectDraw {
|
|||||||
|
|
||||||
MemoryUtil.memPutInt(ptr + 20, instancer.modelIndex); // modelIndex
|
MemoryUtil.memPutInt(ptr + 20, instancer.modelIndex); // modelIndex
|
||||||
|
|
||||||
MemoryUtil.memPutInt(ptr + 24, ShaderIndices.getVertexShaderIndex(materialOverride.shaders())); // materialVertexIndex
|
MemoryUtil.memPutInt(ptr + 24, MaterialShaderIndices.vertexIndex(materialOverride.shaders())); // materialVertexIndex
|
||||||
MemoryUtil.memPutInt(ptr + 28, ShaderIndices.getFragmentShaderIndex(materialOverride.shaders())); // materialFragmentIndex
|
MemoryUtil.memPutInt(ptr + 28, MaterialShaderIndices.fragmentIndex(materialOverride.shaders())); // materialFragmentIndex
|
||||||
MemoryUtil.memPutInt(ptr + 32, MaterialEncoder.packFogAndCutout(materialOverride)); // packedFogAndCutout
|
MemoryUtil.memPutInt(ptr + 32, MaterialEncoder.packFogAndCutout(materialOverride)); // packedFogAndCutout
|
||||||
MemoryUtil.memPutInt(ptr + 36, MaterialEncoder.packProperties(materialOverride)); // packedMaterialProperties
|
MemoryUtil.memPutInt(ptr + 36, MaterialEncoder.packProperties(materialOverride)); // packedMaterialProperties
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.backend.Engine;
|
import dev.engine_room.flywheel.api.backend.Engine;
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.Samplers;
|
import dev.engine_room.flywheel.backend.Samplers;
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
@ -63,24 +63,24 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||||||
protected <I extends Instance> void initialize(InstancerKey<I> key, IndirectInstancer<?> instancer) {
|
protected <I extends Instance> void initialize(InstancerKey<I> key, IndirectInstancer<?> instancer) {
|
||||||
var groupKey = new GroupKey<>(key.type(), key.environment());
|
var groupKey = new GroupKey<>(key.type(), key.environment());
|
||||||
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(groupKey, t -> new IndirectCullingGroup<>(t.instanceType(), t.environment(), programs));
|
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(groupKey, t -> new IndirectCullingGroup<>(t.instanceType(), t.environment(), programs));
|
||||||
group.add((IndirectInstancer<I>) instancer, key.model(), key.stage(), meshPool);
|
group.add((IndirectInstancer<I>) instancer, key.model(), key.visualType(), meshPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStage(RenderStage stage) {
|
public boolean hasVisualType(VisualType visualType) {
|
||||||
for (var group : cullingGroups.values()) {
|
for (var group : cullingGroups.values()) {
|
||||||
if (group.hasStage(stage)) {
|
if (group.hasVisualType(visualType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderStage(RenderStage stage) {
|
public void render(VisualType visualType) {
|
||||||
if (!hasStage(stage)) {
|
if (!hasVisualType(visualType)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
try (var state = GlStateTracker.getRestoreState()) {
|
||||||
TextureBinder.bindLightAndOverlay();
|
TextureBinder.bindLightAndOverlay();
|
||||||
|
|
||||||
vertexArray.bindForDraw();
|
vertexArray.bindForDraw();
|
||||||
@ -88,7 +88,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||||||
Uniforms.bindAll();
|
Uniforms.bindAll();
|
||||||
|
|
||||||
for (var group : cullingGroups.values()) {
|
for (var group : cullingGroups.values()) {
|
||||||
group.submit(stage);
|
group.submit(visualType);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialRenderState.reset();
|
MaterialRenderState.reset();
|
||||||
|
@ -25,7 +25,7 @@ public class ResizableStorageBuffer extends GlObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void ensureCapacity(long capacity) {
|
public void ensureCapacity(long capacity) {
|
||||||
FlwMemoryTracker._freeGPUMemory(this.capacity);
|
FlwMemoryTracker._freeGpuMemory(this.capacity);
|
||||||
|
|
||||||
if (this.capacity > 0) {
|
if (this.capacity > 0) {
|
||||||
int oldHandle = handle();
|
int oldHandle = handle();
|
||||||
@ -42,7 +42,7 @@ public class ResizableStorageBuffer extends GlObject {
|
|||||||
glNamedBufferStorage(handle(), capacity, 0);
|
glNamedBufferStorage(handle(), capacity, 0);
|
||||||
}
|
}
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
FlwMemoryTracker._allocGPUMemory(this.capacity);
|
FlwMemoryTracker._allocGpuMemory(this.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,6 +53,6 @@ public class ResizableStorageBuffer extends GlObject {
|
|||||||
@Override
|
@Override
|
||||||
public void delete() {
|
public void delete() {
|
||||||
super.delete();
|
super.delete();
|
||||||
FlwMemoryTracker._freeGPUMemory(capacity);
|
FlwMemoryTracker._freeGpuMemory(capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public class StagingBuffer {
|
|||||||
|
|
||||||
totalAvailable = capacity;
|
totalAvailable = capacity;
|
||||||
|
|
||||||
FlwMemoryTracker._allocCPUMemory(capacity);
|
FlwMemoryTracker._allocCpuMemory(capacity);
|
||||||
|
|
||||||
scatterProgram = programs.getScatterProgram();
|
scatterProgram = programs.getScatterProgram();
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ public class StagingBuffer {
|
|||||||
transfers.delete();
|
transfers.delete();
|
||||||
scatterList.delete();
|
scatterList.delete();
|
||||||
|
|
||||||
FlwMemoryTracker._freeCPUMemory(capacity);
|
FlwMemoryTracker._freeCpuMemory(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemoryBlock getScratch(long size) {
|
private MemoryBlock getScratch(long size) {
|
||||||
|
@ -7,11 +7,11 @@ import java.util.Map;
|
|||||||
import org.lwjgl.opengl.GL32;
|
import org.lwjgl.opengl.GL32;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.backend.Engine;
|
import dev.engine_room.flywheel.api.backend.Engine;
|
||||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
|
||||||
import dev.engine_room.flywheel.api.instance.Instance;
|
import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
|
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||||
import dev.engine_room.flywheel.backend.Samplers;
|
import dev.engine_room.flywheel.backend.Samplers;
|
||||||
import dev.engine_room.flywheel.backend.ShaderIndices;
|
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||||
import dev.engine_room.flywheel.backend.compile.InstancingPrograms;
|
import dev.engine_room.flywheel.backend.compile.InstancingPrograms;
|
||||||
import dev.engine_room.flywheel.backend.engine.CommonCrumbling;
|
import dev.engine_room.flywheel.backend.engine.CommonCrumbling;
|
||||||
@ -33,9 +33,9 @@ import net.minecraft.client.resources.model.ModelBakery;
|
|||||||
|
|
||||||
public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||||
/**
|
/**
|
||||||
* The set of draw calls to make in each {@link RenderStage}.
|
* The set of draw calls to make for each {@link VisualType}.
|
||||||
*/
|
*/
|
||||||
private final Map<RenderStage, InstancedRenderStage> stages = new EnumMap<>(RenderStage.class);
|
private final Map<VisualType, InstancedRenderStage> stages = new EnumMap<>(VisualType.class);
|
||||||
private final InstancingPrograms programs;
|
private final InstancingPrograms programs;
|
||||||
/**
|
/**
|
||||||
* A map of vertex types to their mesh pools.
|
* A map of vertex types to their mesh pools.
|
||||||
@ -74,9 +74,9 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (InstancedRenderStage instancedRenderStage : stages.values()) {
|
for (InstancedRenderStage stage : stages.values()) {
|
||||||
// Remove the draw calls for any instancers we deleted.
|
// Remove the draw calls for any instancers we deleted.
|
||||||
instancedRenderStage.flush();
|
stage.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
meshPool.flush();
|
meshPool.flush();
|
||||||
@ -85,10 +85,10 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderStage(RenderStage stage) {
|
public void render(VisualType visualType) {
|
||||||
var drawSet = stages.get(stage);
|
var stage = stages.get(visualType);
|
||||||
|
|
||||||
if (drawSet == null || drawSet.isEmpty()) {
|
if (stage == null || stage.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
TextureBinder.bindLightAndOverlay();
|
TextureBinder.bindLightAndOverlay();
|
||||||
light.bind();
|
light.bind();
|
||||||
|
|
||||||
drawSet.draw(instanceTexture, programs);
|
stage.draw(instanceTexture, programs);
|
||||||
|
|
||||||
MaterialRenderState.reset();
|
MaterialRenderState.reset();
|
||||||
TextureBinder.resetLightAndOverlay();
|
TextureBinder.resetLightAndOverlay();
|
||||||
@ -133,7 +133,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
protected <I extends Instance> void initialize(InstancerKey<I> key, InstancedInstancer<?> instancer) {
|
protected <I extends Instance> void initialize(InstancerKey<I> key, InstancedInstancer<?> instancer) {
|
||||||
instancer.init();
|
instancer.init();
|
||||||
|
|
||||||
InstancedRenderStage instancedRenderStage = stages.computeIfAbsent(key.stage(), $ -> new InstancedRenderStage());
|
InstancedRenderStage stage = stages.computeIfAbsent(key.visualType(), $ -> new InstancedRenderStage());
|
||||||
|
|
||||||
var meshes = key.model()
|
var meshes = key.model()
|
||||||
.meshes();
|
.meshes();
|
||||||
@ -144,7 +144,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
GroupKey<?> groupKey = new GroupKey<>(key.type(), key.environment());
|
GroupKey<?> groupKey = new GroupKey<>(key.type(), key.environment());
|
||||||
InstancedDraw instancedDraw = new InstancedDraw(instancer, mesh, groupKey, entry.material(), i);
|
InstancedDraw instancedDraw = new InstancedDraw(instancer, mesh, groupKey, entry.material(), i);
|
||||||
|
|
||||||
instancedRenderStage.put(groupKey, instancedDraw);
|
stage.put(groupKey, instancedDraw);
|
||||||
instancer.addDrawCall(instancedDraw);
|
instancer.addDrawCall(instancedDraw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,8 +204,8 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||||||
|
|
||||||
public static void uploadMaterialUniform(GlProgram program, Material material) {
|
public static void uploadMaterialUniform(GlProgram program, Material material) {
|
||||||
int uniformLocation = program.getUniformLocation("_flw_packedMaterial");
|
int uniformLocation = program.getUniformLocation("_flw_packedMaterial");
|
||||||
int vertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
|
int vertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||||
int fragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
|
int fragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||||
int packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
int packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
||||||
int packedMaterialProperties = MaterialEncoder.packProperties(material);
|
int packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||||
GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties);
|
GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties);
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||||
|
|
||||||
|
import org.joml.Math;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||||
import dev.engine_room.flywheel.backend.mixin.LevelRendererAccessor;
|
import dev.engine_room.flywheel.backend.mixin.LevelRendererAccessor;
|
||||||
import dev.engine_room.flywheel.lib.math.MatrixMath;
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@ -63,7 +64,7 @@ public final class FrameUniforms extends UniformWriter {
|
|||||||
setPrev();
|
setPrev();
|
||||||
|
|
||||||
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
|
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
|
||||||
.getRenderOrigin();
|
.renderOrigin();
|
||||||
var camera = context.camera();
|
var camera = context.camera();
|
||||||
Vec3 cameraPos = camera.getPosition();
|
Vec3 cameraPos = camera.getPosition();
|
||||||
var camX = (float) (cameraPos.x - renderOrigin.getX());
|
var camX = (float) (cameraPos.x - renderOrigin.getX());
|
||||||
@ -85,7 +86,7 @@ public final class FrameUniforms extends UniformWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (firstWrite || !frustumPaused || frustumCapture) {
|
if (firstWrite || !frustumPaused || frustumCapture) {
|
||||||
MatrixMath.writePackedFrustumPlanes(ptr, VIEW_PROJECTION);
|
writePackedFrustumPlanes(ptr, VIEW_PROJECTION);
|
||||||
frustumCapture = false;
|
frustumCapture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,4 +171,118 @@ public final class FrameUniforms extends UniformWriter {
|
|||||||
Vec3 cameraPos = camera.getPosition();
|
Vec3 cameraPos = camera.getPosition();
|
||||||
return writeInFluidAndBlock(ptr, level, blockPos, cameraPos);
|
return writeInFluidAndBlock(ptr, level, blockPos, cameraPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the frustum planes of the given projection matrix to the given buffer.<p>
|
||||||
|
* Uses a different format that is friendly towards an optimized instruction-parallel
|
||||||
|
* implementation of sphere-frustum intersection.<p>
|
||||||
|
* The format is as follows:<p>
|
||||||
|
* {@code vec4(nxX, pxX, nyX, pyX)}<br>
|
||||||
|
* {@code vec4(nxY, pxY, nyY, pyY)}<br>
|
||||||
|
* {@code vec4(nxZ, pxZ, nyZ, pyZ)}<br>
|
||||||
|
* {@code vec4(nxW, pxW, nyW, pyW)}<br>
|
||||||
|
* {@code vec2(nzX, pzX)}<br>
|
||||||
|
* {@code vec2(nzY, pzY)}<br>
|
||||||
|
* {@code vec2(nzZ, pzZ)}<br>
|
||||||
|
* {@code vec2(nzW, pzW)}<br>
|
||||||
|
* <p>
|
||||||
|
* Writes 96 bytes to the buffer.
|
||||||
|
*
|
||||||
|
* @param ptr The buffer to write the planes to.
|
||||||
|
* @param m The projection matrix to compute the frustum planes for.
|
||||||
|
*/
|
||||||
|
private static void writePackedFrustumPlanes(long ptr, Matrix4f m) {
|
||||||
|
float nxX, nxY, nxZ, nxW;
|
||||||
|
float pxX, pxY, pxZ, pxW;
|
||||||
|
float nyX, nyY, nyZ, nyW;
|
||||||
|
float pyX, pyY, pyZ, pyW;
|
||||||
|
float nzX, nzY, nzZ, nzW;
|
||||||
|
float pzX, pzY, pzZ, pzW;
|
||||||
|
|
||||||
|
float invl;
|
||||||
|
nxX = m.m03() + m.m00();
|
||||||
|
nxY = m.m13() + m.m10();
|
||||||
|
nxZ = m.m23() + m.m20();
|
||||||
|
nxW = m.m33() + m.m30();
|
||||||
|
invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ);
|
||||||
|
nxX *= invl;
|
||||||
|
nxY *= invl;
|
||||||
|
nxZ *= invl;
|
||||||
|
nxW *= invl;
|
||||||
|
|
||||||
|
pxX = m.m03() - m.m00();
|
||||||
|
pxY = m.m13() - m.m10();
|
||||||
|
pxZ = m.m23() - m.m20();
|
||||||
|
pxW = m.m33() - m.m30();
|
||||||
|
invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ);
|
||||||
|
pxX *= invl;
|
||||||
|
pxY *= invl;
|
||||||
|
pxZ *= invl;
|
||||||
|
pxW *= invl;
|
||||||
|
|
||||||
|
nyX = m.m03() + m.m01();
|
||||||
|
nyY = m.m13() + m.m11();
|
||||||
|
nyZ = m.m23() + m.m21();
|
||||||
|
nyW = m.m33() + m.m31();
|
||||||
|
invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ);
|
||||||
|
nyX *= invl;
|
||||||
|
nyY *= invl;
|
||||||
|
nyZ *= invl;
|
||||||
|
nyW *= invl;
|
||||||
|
|
||||||
|
pyX = m.m03() - m.m01();
|
||||||
|
pyY = m.m13() - m.m11();
|
||||||
|
pyZ = m.m23() - m.m21();
|
||||||
|
pyW = m.m33() - m.m31();
|
||||||
|
invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ);
|
||||||
|
pyX *= invl;
|
||||||
|
pyY *= invl;
|
||||||
|
pyZ *= invl;
|
||||||
|
pyW *= invl;
|
||||||
|
|
||||||
|
nzX = m.m03() + m.m02();
|
||||||
|
nzY = m.m13() + m.m12();
|
||||||
|
nzZ = m.m23() + m.m22();
|
||||||
|
nzW = m.m33() + m.m32();
|
||||||
|
invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ);
|
||||||
|
nzX *= invl;
|
||||||
|
nzY *= invl;
|
||||||
|
nzZ *= invl;
|
||||||
|
nzW *= invl;
|
||||||
|
|
||||||
|
pzX = m.m03() - m.m02();
|
||||||
|
pzY = m.m13() - m.m12();
|
||||||
|
pzZ = m.m23() - m.m22();
|
||||||
|
pzW = m.m33() - m.m32();
|
||||||
|
invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ);
|
||||||
|
pzX *= invl;
|
||||||
|
pzY *= invl;
|
||||||
|
pzZ *= invl;
|
||||||
|
pzW *= invl;
|
||||||
|
|
||||||
|
MemoryUtil.memPutFloat(ptr, nxX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 4, pxX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 8, nyX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 12, pyX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 16, nxY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 20, pxY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 24, nyY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 28, pyY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 32, nxZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 36, pxZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 40, nyZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 44, pyZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 48, nxW);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 52, pxW);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 56, nyW);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 60, pyW);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 64, nzX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 68, pzX);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 72, nzY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 76, pzY);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 80, nzZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 84, pzZ);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 88, nzW);
|
||||||
|
MemoryUtil.memPutFloat(ptr + 92, pzW);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
@ -2,7 +2,7 @@ package dev.engine_room.flywheel.backend.engine.uniform;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.backend.FlwBackendXplat;
|
import dev.engine_room.flywheel.backend.FlwBackendXplat;
|
||||||
import dev.engine_room.flywheel.backend.mixin.AbstractClientPlayerAccessor;
|
import dev.engine_room.flywheel.backend.mixin.AbstractClientPlayerAccessor;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
import dev.engine_room.flywheel.api.RenderContext;
|
||||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
|
||||||
public final class Uniforms {
|
public final class Uniforms {
|
||||||
|
@ -27,10 +27,10 @@ public class GlBuffer extends GlObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void upload(long ptr, long size) {
|
public void upload(long ptr, long size) {
|
||||||
FlwMemoryTracker._freeGPUMemory(this.size);
|
FlwMemoryTracker._freeGpuMemory(this.size);
|
||||||
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
FlwMemoryTracker._allocGPUMemory(this.size);
|
FlwMemoryTracker._allocGpuMemory(this.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
||||||
@ -47,6 +47,6 @@ public class GlBuffer extends GlObject {
|
|||||||
|
|
||||||
protected void deleteInternal(int handle) {
|
protected void deleteInternal(int handle) {
|
||||||
GlStateManager._glDeleteBuffers(handle);
|
GlStateManager._glDeleteBuffers(handle);
|
||||||
FlwMemoryTracker._freeGPUMemory(size);
|
FlwMemoryTracker._freeGpuMemory(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.backend.mixin;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.LightUpdateHolder;
|
|
||||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
import net.minecraft.core.SectionPos;
|
|
||||||
import net.minecraft.world.level.LightLayer;
|
|
||||||
|
|
||||||
@Mixin(ClientChunkCache.class)
|
|
||||||
abstract class ClientChunkCacheMixin {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
ClientLevel level;
|
|
||||||
|
|
||||||
@Inject(method = "onLightUpdate", at = @At("HEAD"))
|
|
||||||
private void flywheel$backend$onLightUpdate(LightLayer layer, SectionPos pos, CallbackInfo ci) {
|
|
||||||
// This is duplicated from code in impl, but I'm not sure that it
|
|
||||||
// makes sense to be generically passed to backends.
|
|
||||||
LightUpdateHolder.get(level)
|
|
||||||
.add(pos.asLong());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package dev.engine_room.flywheel.lib.util;
|
package dev.engine_room.flywheel.backend.util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
@ -6,7 +6,6 @@
|
|||||||
"refmap": "backend-flywheel.refmap.json",
|
"refmap": "backend-flywheel.refmap.json",
|
||||||
"client": [
|
"client": [
|
||||||
"AbstractClientPlayerAccessor",
|
"AbstractClientPlayerAccessor",
|
||||||
"ClientChunkCacheMixin",
|
|
||||||
"GlStateManagerMixin",
|
"GlStateManagerMixin",
|
||||||
"LevelRendererAccessor",
|
"LevelRendererAccessor",
|
||||||
"OptionsMixin",
|
"OptionsMixin",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.lib.backend;
|
package dev.engine_room.flywheel.lib.backend;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -10,7 +11,7 @@ import dev.engine_room.flywheel.api.backend.Engine;
|
|||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
|
||||||
public class SimpleBackend implements Backend {
|
public final class SimpleBackend implements Backend {
|
||||||
private final Function<LevelAccessor, Engine> engineFactory;
|
private final Function<LevelAccessor, Engine> engineFactory;
|
||||||
private final Supplier<Backend> fallback;
|
private final Supplier<Backend> fallback;
|
||||||
private final BooleanSupplier isSupported;
|
private final BooleanSupplier isSupported;
|
||||||
@ -45,9 +46,9 @@ public class SimpleBackend implements Backend {
|
|||||||
return isSupported.getAsBoolean();
|
return isSupported.getAsBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static final class Builder {
|
||||||
private Function<LevelAccessor, Engine> engineFactory;
|
private Function<LevelAccessor, Engine> engineFactory;
|
||||||
private Supplier<Backend> fallback = BackendManager::getOffBackend;
|
private Supplier<Backend> fallback = BackendManager::offBackend;
|
||||||
private BooleanSupplier isSupported;
|
private BooleanSupplier isSupported;
|
||||||
|
|
||||||
public Builder engineFactory(Function<LevelAccessor, Engine> engineFactory) {
|
public Builder engineFactory(Function<LevelAccessor, Engine> engineFactory) {
|
||||||
@ -66,6 +67,10 @@ public class SimpleBackend implements Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Backend register(ResourceLocation id) {
|
public Backend register(ResourceLocation id) {
|
||||||
|
Objects.requireNonNull(engineFactory);
|
||||||
|
Objects.requireNonNull(fallback);
|
||||||
|
Objects.requireNonNull(isSupported);
|
||||||
|
|
||||||
return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineFactory, fallback, isSupported));
|
return Backend.REGISTRY.registerAndGet(id, new SimpleBackend(engineFactory, fallback, isSupported));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,13 @@ package dev.engine_room.flywheel.lib.instance;
|
|||||||
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
|
|
||||||
public abstract class ColoredLitInstance extends AbstractInstance implements FlatLit {
|
public abstract class ColoredLitInstance extends AbstractInstance implements FlatLit {
|
||||||
public byte r = (byte) 0xFF;
|
public byte red = (byte) 0xFF;
|
||||||
public byte g = (byte) 0xFF;
|
public byte green = (byte) 0xFF;
|
||||||
public byte b = (byte) 0xFF;
|
public byte blue = (byte) 0xFF;
|
||||||
public byte a = (byte) 0xFF;
|
public byte alpha = (byte) 0xFF;
|
||||||
|
|
||||||
public int overlay = OverlayTexture.NO_OVERLAY;
|
public int overlay = OverlayTexture.NO_OVERLAY;
|
||||||
public int light = 0;
|
public int light = 0;
|
||||||
@ -17,39 +18,34 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
|
|||||||
super(type, handle);
|
super(type, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColoredLitInstance color(int color) {
|
public ColoredLitInstance colorArgb(int argb) {
|
||||||
return color(color, false);
|
return color(FastColor.ARGB32.red(argb), FastColor.ARGB32.green(argb), FastColor.ARGB32.blue(argb), FastColor.ARGB32.alpha(argb));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColoredLitInstance color(int color, boolean alpha) {
|
public ColoredLitInstance colorRgb(int rgb) {
|
||||||
byte r = (byte) ((color >> 16) & 0xFF);
|
return color(FastColor.ARGB32.red(rgb), FastColor.ARGB32.green(rgb), FastColor.ARGB32.blue(rgb));
|
||||||
byte g = (byte) ((color >> 8) & 0xFF);
|
|
||||||
byte b = (byte) (color & 0xFF);
|
|
||||||
|
|
||||||
if (alpha) {
|
|
||||||
byte a = (byte) ((color >> 24) & 0xFF);
|
|
||||||
return color(r, g, b, a);
|
|
||||||
} else {
|
|
||||||
return color(r, g, b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColoredLitInstance color(int r, int g, int b) {
|
public ColoredLitInstance color(int red, int green, int blue, int alpha) {
|
||||||
return color((byte) r, (byte) g, (byte) b);
|
return color((byte) red, (byte) green, (byte) blue, (byte) alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColoredLitInstance color(byte r, byte g, byte b) {
|
public ColoredLitInstance color(int red, int green, int blue) {
|
||||||
this.r = r;
|
return color((byte) red, (byte) green, (byte) blue);
|
||||||
this.g = g;
|
}
|
||||||
this.b = b;
|
|
||||||
|
public ColoredLitInstance color(byte red, byte green, byte blue, byte alpha) {
|
||||||
|
this.red = red;
|
||||||
|
this.green = green;
|
||||||
|
this.blue = blue;
|
||||||
|
this.alpha = alpha;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ColoredLitInstance color(byte r, byte g, byte b, byte a) {
|
public ColoredLitInstance color(byte red, byte green, byte blue) {
|
||||||
this.r = r;
|
this.red = red;
|
||||||
this.g = g;
|
this.green = green;
|
||||||
this.b = b;
|
this.blue = blue;
|
||||||
this.a = a;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,15 +17,15 @@ import net.minecraft.client.renderer.LightTexture;
|
|||||||
public interface FlatLit extends Instance {
|
public interface FlatLit extends Instance {
|
||||||
/**
|
/**
|
||||||
* Set the packed light value for this instance.
|
* Set the packed light value for this instance.
|
||||||
* @param packedLight Packed block and sky light per {@link LightTexture#pack(int, int)}
|
* @param packedLight the packed light per {@link LightTexture#pack(int, int)}
|
||||||
* @return {@code this} for chaining
|
* @return {@code this} for chaining
|
||||||
*/
|
*/
|
||||||
FlatLit light(int packedLight);
|
FlatLit light(int packedLight);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the block and sky light values for this instance.
|
* Set the block and sky light values for this instance.
|
||||||
* @param blockLight Block light value
|
* @param blockLight the block light value
|
||||||
* @param skyLight Sky light value
|
* @param skyLight the sky light value
|
||||||
* @return {@code this} for chaining
|
* @return {@code this} for chaining
|
||||||
*/
|
*/
|
||||||
default FlatLit light(int blockLight, int skyLight) {
|
default FlatLit light(int blockLight, int skyLight) {
|
||||||
|
@ -20,10 +20,10 @@ public final class InstanceTypes {
|
|||||||
.matrix("normal", FloatRepr.FLOAT, 3)
|
.matrix("normal", FloatRepr.FLOAT, 3)
|
||||||
.build())
|
.build())
|
||||||
.writer((ptr, instance) -> {
|
.writer((ptr, instance) -> {
|
||||||
MemoryUtil.memPutByte(ptr, instance.r);
|
MemoryUtil.memPutByte(ptr, instance.red);
|
||||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
MemoryUtil.memPutByte(ptr + 1, instance.green);
|
||||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
MemoryUtil.memPutByte(ptr + 2, instance.blue);
|
||||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
|
||||||
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
||||||
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
||||||
ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model);
|
ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model);
|
||||||
@ -43,10 +43,10 @@ public final class InstanceTypes {
|
|||||||
.vector("rotation", FloatRepr.FLOAT, 4)
|
.vector("rotation", FloatRepr.FLOAT, 4)
|
||||||
.build())
|
.build())
|
||||||
.writer((ptr, instance) -> {
|
.writer((ptr, instance) -> {
|
||||||
MemoryUtil.memPutByte(ptr, instance.r);
|
MemoryUtil.memPutByte(ptr, instance.red);
|
||||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
MemoryUtil.memPutByte(ptr + 1, instance.green);
|
||||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
MemoryUtil.memPutByte(ptr + 2, instance.blue);
|
||||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
|
||||||
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
||||||
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
||||||
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package dev.engine_room.flywheel.lib.instance;
|
package dev.engine_room.flywheel.lib.instance;
|
||||||
|
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Quaternionf;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Quaternionfc;
|
||||||
|
import org.joml.Vector3fc;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
@ -22,72 +23,83 @@ public class OrientedInstance extends ColoredLitInstance implements Rotate<Orien
|
|||||||
super(type, handle);
|
super(type, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPosition(float x, float y, float z) {
|
public OrientedInstance position(float x, float y, float z) {
|
||||||
posX = x;
|
posX = x;
|
||||||
posY = y;
|
posY = y;
|
||||||
posZ = z;
|
posZ = z;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPosition(Vector3f pos) {
|
public OrientedInstance position(Vector3fc pos) {
|
||||||
return setPosition(pos.x(), pos.y(), pos.z());
|
return position(pos.x(), pos.y(), pos.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPosition(Vec3i pos) {
|
public OrientedInstance position(Vec3i pos) {
|
||||||
return setPosition(pos.getX(), pos.getY(), pos.getZ());
|
return position(pos.getX(), pos.getY(), pos.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPosition(Vec3 pos) {
|
public OrientedInstance position(Vec3 pos) {
|
||||||
return setPosition((float) pos.x(), (float) pos.y(), (float) pos.z());
|
return position((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance resetPosition() {
|
public OrientedInstance zeroPosition() {
|
||||||
return setPosition(0, 0, 0);
|
return position(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance nudgePosition(float x, float y, float z) {
|
public OrientedInstance translatePosition(float x, float y, float z) {
|
||||||
posX += x;
|
posX += x;
|
||||||
posY += y;
|
posY += y;
|
||||||
posZ += z;
|
posZ += z;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPivot(float x, float y, float z) {
|
public OrientedInstance pivot(float x, float y, float z) {
|
||||||
pivotX = x;
|
pivotX = x;
|
||||||
pivotY = y;
|
pivotY = y;
|
||||||
pivotZ = z;
|
pivotZ = z;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPivot(Vector3f pos) {
|
public OrientedInstance pivot(Vector3fc pos) {
|
||||||
return setPivot(pos.x(), pos.y(), pos.z());
|
return pivot(pos.x(), pos.y(), pos.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPivot(Vec3i pos) {
|
public OrientedInstance pivot(Vec3i pos) {
|
||||||
return setPivot(pos.getX(), pos.getY(), pos.getZ());
|
return pivot(pos.getX(), pos.getY(), pos.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setPivot(Vec3 pos) {
|
public OrientedInstance pivot(Vec3 pos) {
|
||||||
return setPivot((float) pos.x(), (float) pos.y(), (float) pos.z());
|
return pivot((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setRotation(Quaternionf q) {
|
public OrientedInstance centerPivot() {
|
||||||
|
return pivot(0.5f, 0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrientedInstance translatePivot(float x, float y, float z) {
|
||||||
|
pivotX += x;
|
||||||
|
pivotY += y;
|
||||||
|
pivotZ += z;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrientedInstance rotation(Quaternionfc q) {
|
||||||
rotation.set(q);
|
rotation.set(q);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance setRotation(float x, float y, float z, float w) {
|
public OrientedInstance rotation(float x, float y, float z, float w) {
|
||||||
rotation.set(x, y, z, w);
|
rotation.set(x, y, z, w);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrientedInstance resetRotation() {
|
public OrientedInstance identityRotation() {
|
||||||
rotation.identity();
|
rotation.identity();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OrientedInstance rotate(Quaternionf quaternion) {
|
public OrientedInstance rotate(Quaternionfc quaternion) {
|
||||||
rotation.mul(quaternion);
|
rotation.mul(quaternion);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@ import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
|||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
|
|
||||||
public class ShadowInstance extends AbstractInstance {
|
public class ShadowInstance extends AbstractInstance {
|
||||||
|
|
||||||
public float x, y, z;
|
public float x, y, z;
|
||||||
public float entityX, entityZ;
|
public float entityX, entityZ;
|
||||||
public float sizeX, sizeZ;
|
public float sizeX, sizeZ;
|
||||||
public float alpha;
|
public float alpha;
|
||||||
public float radius;
|
public float radius;
|
||||||
|
|
||||||
public ShadowInstance(InstanceType<?> type, InstanceHandle handle) {
|
public ShadowInstance(InstanceType<? extends ShadowInstance> type, InstanceHandle handle) {
|
||||||
super(type, handle);
|
super(type, handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import dev.engine_room.flywheel.api.instance.InstanceWriter;
|
|||||||
import dev.engine_room.flywheel.api.layout.Layout;
|
import dev.engine_room.flywheel.api.layout.Layout;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public class SimpleInstanceType<I extends Instance> implements InstanceType<I> {
|
public final class SimpleInstanceType<I extends Instance> implements InstanceType<I> {
|
||||||
private final Factory<I> factory;
|
private final Factory<I> factory;
|
||||||
private final Layout layout;
|
private final Layout layout;
|
||||||
private final InstanceWriter<I> writer;
|
private final InstanceWriter<I> writer;
|
||||||
@ -58,7 +58,7 @@ public class SimpleInstanceType<I extends Instance> implements InstanceType<I> {
|
|||||||
I create(InstanceType<I> type, InstanceHandle handle);
|
I create(InstanceType<I> type, InstanceHandle handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder<I extends Instance> {
|
public static final class Builder<I extends Instance> {
|
||||||
private final Factory<I> factory;
|
private final Factory<I> factory;
|
||||||
private Layout layout;
|
private Layout layout;
|
||||||
private InstanceWriter<I> writer;
|
private InstanceWriter<I> writer;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package dev.engine_room.flywheel.lib.instance;
|
package dev.engine_room.flywheel.lib.instance;
|
||||||
|
|
||||||
import org.joml.Matrix3f;
|
import org.joml.Matrix3f;
|
||||||
|
import org.joml.Matrix3fc;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Quaternionf;
|
import org.joml.Matrix4fc;
|
||||||
|
import org.joml.Quaternionfc;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
@ -12,7 +14,6 @@ import dev.engine_room.flywheel.lib.transform.Transform;
|
|||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
public class TransformedInstance extends ColoredLitInstance implements Transform<TransformedInstance> {
|
public class TransformedInstance extends ColoredLitInstance implements Transform<TransformedInstance> {
|
||||||
|
|
||||||
public final Matrix4f model = new Matrix4f();
|
public final Matrix4f model = new Matrix4f();
|
||||||
public final Matrix3f normal = new Matrix3f();
|
public final Matrix3f normal = new Matrix3f();
|
||||||
|
|
||||||
@ -21,21 +22,34 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransformedInstance mulPose(Matrix4f pose) {
|
public TransformedInstance mulPose(Matrix4fc pose) {
|
||||||
this.model.mul(pose);
|
this.model.mul(pose);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransformedInstance mulNormal(Matrix3f normal) {
|
public TransformedInstance mulNormal(Matrix3fc normal) {
|
||||||
this.normal.mul(normal);
|
this.normal.mul(normal);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransformedInstance rotateAround(Quaternionf quaternion, float x, float y, float z) {
|
public TransformedInstance rotateAround(Quaternionfc quaternion, float x, float y, float z) {
|
||||||
this.model.rotateAround(quaternion, x, y, z);
|
model.rotateAround(quaternion, x, y, z);
|
||||||
this.normal.rotate(quaternion);
|
normal.rotate(quaternion);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransformedInstance translate(float x, float y, float z) {
|
||||||
|
model.translate(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransformedInstance rotate(Quaternionfc quaternion) {
|
||||||
|
model.rotate(quaternion);
|
||||||
|
normal.rotate(quaternion);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,16 +73,9 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public TransformedInstance setTransform(PoseStack.Pose pose) {
|
||||||
public TransformedInstance rotate(Quaternionf quaternion) {
|
model.set(pose.pose());
|
||||||
model.rotate(quaternion);
|
normal.set(pose.normal());
|
||||||
normal.rotate(quaternion);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransformedInstance translate(double x, double y, double z) {
|
|
||||||
model.translate((float) x, (float) y, (float) z);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,9 +83,9 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
|||||||
return setTransform(stack.last());
|
return setTransform(stack.last());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransformedInstance setTransform(PoseStack.Pose pose) {
|
public TransformedInstance setIdentityTransform() {
|
||||||
this.model.set(pose.pose());
|
model.identity();
|
||||||
this.normal.set(pose.normal());
|
normal.identity();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,15 +96,9 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
|||||||
* This will allow the GPU to quickly discard all geometry for this instance, effectively "turning it off".
|
* This will allow the GPU to quickly discard all geometry for this instance, effectively "turning it off".
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public TransformedInstance setEmptyTransform() {
|
public TransformedInstance setZeroTransform() {
|
||||||
model.zero();
|
model.zero();
|
||||||
normal.zero();
|
normal.zero();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransformedInstance loadIdentity() {
|
|
||||||
model.identity();
|
|
||||||
normal.identity();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dev.engine_room.flywheel.lib.internal;
|
package dev.engine_room.flywheel.lib.internal;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.internal.DependencyInjection;
|
import dev.engine_room.flywheel.api.internal.DependencyInjection;
|
||||||
import dev.engine_room.flywheel.lib.model.baked.BakedModelBuilder;
|
import dev.engine_room.flywheel.lib.model.baked.BakedModelBuilder;
|
||||||
@ -9,13 +10,18 @@ import dev.engine_room.flywheel.lib.model.baked.MultiBlockModelBuilder;
|
|||||||
import dev.engine_room.flywheel.lib.util.ShadersModHandler;
|
import dev.engine_room.flywheel.lib.util.ShadersModHandler;
|
||||||
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
|
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
public interface FlwLibXplat {
|
public interface FlwLibXplat {
|
||||||
FlwLibXplat INSTANCE = DependencyInjection.load(FlwLibXplat.class, "dev.engine_room.flywheel.impl.FlwLibXplatImpl");
|
FlwLibXplat INSTANCE = DependencyInjection.load(FlwLibXplat.class, "dev.engine_room.flywheel.impl.FlwLibXplatImpl");
|
||||||
|
|
||||||
|
@UnknownNullability
|
||||||
|
BakedModel getBakedModel(ModelManager modelManager, ResourceLocation location);
|
||||||
|
|
||||||
BlockRenderDispatcher createVanillaBlockRenderDispatcher();
|
BlockRenderDispatcher createVanillaBlockRenderDispatcher();
|
||||||
|
|
||||||
BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel);
|
BakedModelBuilder createBakedModelBuilder(BakedModel bakedModel);
|
||||||
|
@ -5,7 +5,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
import dev.engine_room.flywheel.api.Flywheel;
|
import dev.engine_room.flywheel.api.Flywheel;
|
||||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||||
|
|
||||||
public class CutoutShaders {
|
public final class CutoutShaders {
|
||||||
/**
|
/**
|
||||||
* Do not discard any fragments based on alpha.
|
* Do not discard any fragments based on alpha.
|
||||||
*/
|
*/
|
||||||
|
@ -5,7 +5,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
import dev.engine_room.flywheel.api.Flywheel;
|
import dev.engine_room.flywheel.api.Flywheel;
|
||||||
import dev.engine_room.flywheel.api.material.FogShader;
|
import dev.engine_room.flywheel.api.material.FogShader;
|
||||||
|
|
||||||
public class FogShaders {
|
public final class FogShaders {
|
||||||
public static final FogShader NONE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/none.glsl")));
|
public static final FogShader NONE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/none.glsl")));
|
||||||
public static final FogShader LINEAR = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear.glsl")));
|
public static final FogShader LINEAR = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear.glsl")));
|
||||||
public static final FogShader LINEAR_FADE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl")));
|
public static final FogShader LINEAR_FADE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl")));
|
||||||
|
@ -2,73 +2,50 @@ package dev.engine_room.flywheel.lib.material;
|
|||||||
|
|
||||||
import dev.engine_room.flywheel.api.material.Material;
|
import dev.engine_room.flywheel.api.material.Material;
|
||||||
import dev.engine_room.flywheel.api.material.Transparency;
|
import dev.engine_room.flywheel.api.material.Transparency;
|
||||||
import net.minecraft.client.renderer.Sheets;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
public final class Materials {
|
public final class Materials {
|
||||||
private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png");
|
public static final Material SOLID_BLOCK = SimpleMaterial.builder()
|
||||||
|
|
||||||
public static final Material CHUNK_SOLID_SHADED = SimpleMaterial.builder()
|
|
||||||
.build();
|
.build();
|
||||||
public static final Material CHUNK_SOLID_UNSHADED = SimpleMaterial.builder()
|
public static final Material SOLID_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder()
|
public static final Material CUTOUT_MIPPED_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.HALF)
|
.cutout(CutoutShaders.HALF)
|
||||||
.build();
|
.build();
|
||||||
public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder()
|
public static final Material CUTOUT_MIPPED_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.HALF)
|
.cutout(CutoutShaders.HALF)
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder()
|
public static final Material CUTOUT_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
.cutout(CutoutShaders.ONE_TENTH)
|
||||||
.mipmap(false)
|
.mipmap(false)
|
||||||
.build();
|
.build();
|
||||||
public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder()
|
public static final Material CUTOUT_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
.cutout(CutoutShaders.ONE_TENTH)
|
||||||
.mipmap(false)
|
.mipmap(false)
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final Material CHUNK_TRANSLUCENT_SHADED = SimpleMaterial.builder()
|
public static final Material TRANSLUCENT_BLOCK = SimpleMaterial.builder()
|
||||||
.transparency(Transparency.TRANSLUCENT)
|
.transparency(Transparency.TRANSLUCENT)
|
||||||
.build();
|
.build();
|
||||||
public static final Material CHUNK_TRANSLUCENT_UNSHADED = SimpleMaterial.builder()
|
public static final Material TRANSLUCENT_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||||
.transparency(Transparency.TRANSLUCENT)
|
.transparency(Transparency.TRANSLUCENT)
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder()
|
public static final Material TRIPWIRE_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
.cutout(CutoutShaders.ONE_TENTH)
|
||||||
.transparency(Transparency.TRANSLUCENT)
|
.transparency(Transparency.TRANSLUCENT)
|
||||||
.build();
|
.build();
|
||||||
public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder()
|
public static final Material TRIPWIRE_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
.cutout(CutoutShaders.ONE_TENTH)
|
||||||
.transparency(Transparency.TRANSLUCENT)
|
.transparency(Transparency.TRANSLUCENT)
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static final Material CHEST = SimpleMaterial.builder()
|
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
|
||||||
.texture(Sheets.CHEST_SHEET)
|
|
||||||
.mipmap(false)
|
|
||||||
.build();
|
|
||||||
public static final Material SHULKER = SimpleMaterial.builder()
|
|
||||||
.cutout(CutoutShaders.ONE_TENTH)
|
|
||||||
.texture(Sheets.SHULKER_SHEET)
|
|
||||||
.mipmap(false)
|
|
||||||
.backfaceCulling(false)
|
|
||||||
.build();
|
|
||||||
public static final Material BELL = SimpleMaterial.builder()
|
|
||||||
.mipmap(false)
|
|
||||||
.build();
|
|
||||||
public static final Material MINECART = SimpleMaterial.builder()
|
|
||||||
.texture(MINECART_LOCATION)
|
|
||||||
.mipmap(false)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private Materials() {
|
private Materials() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@ package dev.engine_room.flywheel.lib.material;
|
|||||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public record SimpleMaterialShaders(ResourceLocation vertexShader, ResourceLocation fragmentShader) implements MaterialShaders {
|
public record SimpleMaterialShaders(ResourceLocation vertexSource, ResourceLocation fragmentSource) implements MaterialShaders {
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package dev.engine_room.flywheel.lib.math;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
public final class DataPacker {
|
||||||
|
private DataPacker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pack a float as an unsigned, normalized byte.
|
||||||
|
*/
|
||||||
|
public static byte packNormU8(float f) {
|
||||||
|
return (byte) (int) (Mth.clamp(f, 0.0f, 1.0f) * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack an unsigned, normalized byte to a float.
|
||||||
|
*/
|
||||||
|
public static float unpackNormU8(byte b) {
|
||||||
|
return (float) (Byte.toUnsignedInt(b)) / 255f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pack a float as a signed, normalized byte.
|
||||||
|
*/
|
||||||
|
public static byte packNormI8(float f) {
|
||||||
|
return (byte) (Mth.clamp(f, -1.0f, 1.0f) * 127);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack a signed, normalized byte to a float.
|
||||||
|
*/
|
||||||
|
public static float unpackNormI8(byte b) {
|
||||||
|
return (float) b / 127f;
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,8 @@ package dev.engine_room.flywheel.lib.math;
|
|||||||
|
|
||||||
import static org.joml.Math.fma;
|
import static org.joml.Math.fma;
|
||||||
|
|
||||||
import org.joml.Math;
|
|
||||||
import org.joml.Matrix3f;
|
import org.joml.Matrix3f;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
public final class MatrixMath {
|
public final class MatrixMath {
|
||||||
private MatrixMath() {
|
private MatrixMath() {
|
||||||
@ -34,131 +32,4 @@ public final class MatrixMath {
|
|||||||
public static float transformNormalZ(Matrix3f matrix, float x, float y, float z) {
|
public static float transformNormalZ(Matrix3f matrix, float x, float y, float z) {
|
||||||
return fma(matrix.m02(), x, fma(matrix.m12(), y, matrix.m22() * z));
|
return fma(matrix.m02(), x, fma(matrix.m12(), y, matrix.m22() * z));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the greatest scale factor across all axes from the given matrix.
|
|
||||||
*
|
|
||||||
* @param matrix The matrix to extract the scale from.
|
|
||||||
* @return The greatest scale factor across all axes.
|
|
||||||
*/
|
|
||||||
public static float extractScale(Matrix4f matrix) {
|
|
||||||
float scaleSqrX = matrix.m00() * matrix.m00() + matrix.m01() * matrix.m01() + matrix.m02() * matrix.m02();
|
|
||||||
float scaleSqrY = matrix.m10() * matrix.m10() + matrix.m11() * matrix.m11() + matrix.m12() * matrix.m12();
|
|
||||||
float scaleSqrZ = matrix.m20() * matrix.m20() + matrix.m21() * matrix.m21() + matrix.m22() * matrix.m22();
|
|
||||||
return Math.sqrt(Math.max(Math.max(scaleSqrX, scaleSqrY), scaleSqrZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes the frustum planes of the given projection matrix to the given buffer.<p>
|
|
||||||
* Uses a different format that is friendly towards an optimized instruction-parallel
|
|
||||||
* implementation of sphere-frustum intersection.<p>
|
|
||||||
* The format is as follows:<p>
|
|
||||||
* {@code vec4(nxX, pxX, nyX, pyX)}<br>
|
|
||||||
* {@code vec4(nxY, pxY, nyY, pyY)}<br>
|
|
||||||
* {@code vec4(nxZ, pxZ, nyZ, pyZ)}<br>
|
|
||||||
* {@code vec4(nxW, pxW, nyW, pyW)}<br>
|
|
||||||
* {@code vec2(nzX, pzX)}<br>
|
|
||||||
* {@code vec2(nzY, pzY)}<br>
|
|
||||||
* {@code vec2(nzZ, pzZ)}<br>
|
|
||||||
* {@code vec2(nzW, pzW)}<br>
|
|
||||||
* <p>
|
|
||||||
* Writes 96 bytes to the buffer.
|
|
||||||
*
|
|
||||||
* @param ptr The buffer to write the planes to.
|
|
||||||
* @param m The projection matrix to compute the frustum planes for.
|
|
||||||
*/
|
|
||||||
public static void writePackedFrustumPlanes(long ptr, Matrix4f m) {
|
|
||||||
float nxX, nxY, nxZ, nxW;
|
|
||||||
float pxX, pxY, pxZ, pxW;
|
|
||||||
float nyX, nyY, nyZ, nyW;
|
|
||||||
float pyX, pyY, pyZ, pyW;
|
|
||||||
float nzX, nzY, nzZ, nzW;
|
|
||||||
float pzX, pzY, pzZ, pzW;
|
|
||||||
|
|
||||||
float invl;
|
|
||||||
nxX = m.m03() + m.m00();
|
|
||||||
nxY = m.m13() + m.m10();
|
|
||||||
nxZ = m.m23() + m.m20();
|
|
||||||
nxW = m.m33() + m.m30();
|
|
||||||
invl = Math.invsqrt(nxX * nxX + nxY * nxY + nxZ * nxZ);
|
|
||||||
nxX *= invl;
|
|
||||||
nxY *= invl;
|
|
||||||
nxZ *= invl;
|
|
||||||
nxW *= invl;
|
|
||||||
|
|
||||||
pxX = m.m03() - m.m00();
|
|
||||||
pxY = m.m13() - m.m10();
|
|
||||||
pxZ = m.m23() - m.m20();
|
|
||||||
pxW = m.m33() - m.m30();
|
|
||||||
invl = Math.invsqrt(pxX * pxX + pxY * pxY + pxZ * pxZ);
|
|
||||||
pxX *= invl;
|
|
||||||
pxY *= invl;
|
|
||||||
pxZ *= invl;
|
|
||||||
pxW *= invl;
|
|
||||||
|
|
||||||
nyX = m.m03() + m.m01();
|
|
||||||
nyY = m.m13() + m.m11();
|
|
||||||
nyZ = m.m23() + m.m21();
|
|
||||||
nyW = m.m33() + m.m31();
|
|
||||||
invl = Math.invsqrt(nyX * nyX + nyY * nyY + nyZ * nyZ);
|
|
||||||
nyX *= invl;
|
|
||||||
nyY *= invl;
|
|
||||||
nyZ *= invl;
|
|
||||||
nyW *= invl;
|
|
||||||
|
|
||||||
pyX = m.m03() - m.m01();
|
|
||||||
pyY = m.m13() - m.m11();
|
|
||||||
pyZ = m.m23() - m.m21();
|
|
||||||
pyW = m.m33() - m.m31();
|
|
||||||
invl = Math.invsqrt(pyX * pyX + pyY * pyY + pyZ * pyZ);
|
|
||||||
pyX *= invl;
|
|
||||||
pyY *= invl;
|
|
||||||
pyZ *= invl;
|
|
||||||
pyW *= invl;
|
|
||||||
|
|
||||||
nzX = m.m03() + m.m02();
|
|
||||||
nzY = m.m13() + m.m12();
|
|
||||||
nzZ = m.m23() + m.m22();
|
|
||||||
nzW = m.m33() + m.m32();
|
|
||||||
invl = Math.invsqrt(nzX * nzX + nzY * nzY + nzZ * nzZ);
|
|
||||||
nzX *= invl;
|
|
||||||
nzY *= invl;
|
|
||||||
nzZ *= invl;
|
|
||||||
nzW *= invl;
|
|
||||||
|
|
||||||
pzX = m.m03() - m.m02();
|
|
||||||
pzY = m.m13() - m.m12();
|
|
||||||
pzZ = m.m23() - m.m22();
|
|
||||||
pzW = m.m33() - m.m32();
|
|
||||||
invl = Math.invsqrt(pzX * pzX + pzY * pzY + pzZ * pzZ);
|
|
||||||
pzX *= invl;
|
|
||||||
pzY *= invl;
|
|
||||||
pzZ *= invl;
|
|
||||||
pzW *= invl;
|
|
||||||
|
|
||||||
MemoryUtil.memPutFloat(ptr, nxX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 4, pxX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 8, nyX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 12, pyX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 16, nxY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 20, pxY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 24, nyY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 28, pyY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 32, nxZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 36, pxZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 40, nyZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 44, pyZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 48, nxW);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 52, pxW);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 56, nyW);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 60, pyW);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 64, nzX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 68, pzX);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 72, nzY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 76, pzY);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 80, nzZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 84, pzZ);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 88, nzW);
|
|
||||||
MemoryUtil.memPutFloat(ptr + 92, pzW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -29,47 +29,6 @@ public final class MoreMath {
|
|||||||
return (numerator + denominator - 1) / denominator;
|
return (numerator + denominator - 1) / denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int numDigits(int number) {
|
|
||||||
// cursed but allegedly the fastest algorithm, taken from https://www.baeldung.com/java-number-of-digits-in-int
|
|
||||||
if (number < 100000) {
|
|
||||||
if (number < 100) {
|
|
||||||
if (number < 10) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (number < 1000) {
|
|
||||||
return 3;
|
|
||||||
} else {
|
|
||||||
if (number < 10000) {
|
|
||||||
return 4;
|
|
||||||
} else {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (number < 10000000) {
|
|
||||||
if (number < 1000000) {
|
|
||||||
return 6;
|
|
||||||
} else {
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (number < 100000000) {
|
|
||||||
return 8;
|
|
||||||
} else {
|
|
||||||
if (number < 1000000000) {
|
|
||||||
return 9;
|
|
||||||
} else {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long ceilLong(double d) {
|
public static long ceilLong(double d) {
|
||||||
return (long) Math.ceil(d);
|
return (long) Math.ceil(d);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.lib.math;
|
|
||||||
|
|
||||||
public final class RenderMath {
|
|
||||||
private RenderMath() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a signed byte into a signed, normalized float.
|
|
||||||
*/
|
|
||||||
public static float f(byte b) {
|
|
||||||
return b / 127f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a signed, normalized float into a signed byte.
|
|
||||||
*/
|
|
||||||
public static byte nb(float f) {
|
|
||||||
return (byte) (f * 127);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an unsigned byte into an unsigned, normalized float.
|
|
||||||
*/
|
|
||||||
public static float uf(byte b) {
|
|
||||||
return (float) (Byte.toUnsignedInt(b)) / 255f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an unsigned, normalized float into an unsigned byte.
|
|
||||||
*/
|
|
||||||
public static byte unb(float f) {
|
|
||||||
return (byte) (int) (f * 255);
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,13 +18,21 @@ non-sealed abstract class AbstractMemoryBlockImpl implements MemoryBlock {
|
|||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void assertAllocated() {
|
||||||
|
if (freed) {
|
||||||
|
throw new IllegalStateException("Operation called on freed MemoryBlock!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long ptr() {
|
public long ptr() {
|
||||||
|
assertAllocated();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long size() {
|
public long size() {
|
||||||
|
assertAllocated();
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,27 +43,32 @@ non-sealed abstract class AbstractMemoryBlockImpl implements MemoryBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyTo(MemoryBlock block) {
|
public void copyTo(MemoryBlock block) {
|
||||||
|
assertAllocated();
|
||||||
long bytes = Math.min(size, block.size());
|
long bytes = Math.min(size, block.size());
|
||||||
copyTo(block.ptr(), bytes);
|
copyTo(block.ptr(), bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyTo(long ptr, long bytes) {
|
public void copyTo(long ptr, long bytes) {
|
||||||
|
assertAllocated();
|
||||||
MemoryUtil.memCopy(this.ptr, ptr, bytes);
|
MemoryUtil.memCopy(this.ptr, ptr, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void copyTo(long ptr) {
|
public void copyTo(long ptr) {
|
||||||
|
assertAllocated();
|
||||||
copyTo(ptr, size);
|
copyTo(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
assertAllocated();
|
||||||
MemoryUtil.memSet(ptr, 0, size);
|
MemoryUtil.memSet(ptr, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer asBuffer() {
|
public ByteBuffer asBuffer() {
|
||||||
|
assertAllocated();
|
||||||
int intSize = (int) size;
|
int intSize = (int) size;
|
||||||
if (intSize != size) {
|
if (intSize != size) {
|
||||||
throw new UnsupportedOperationException("Cannot create buffer with long capacity!");
|
throw new UnsupportedOperationException("Cannot create buffer with long capacity!");
|
||||||
@ -64,12 +77,13 @@ non-sealed abstract class AbstractMemoryBlockImpl implements MemoryBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void freeInner() {
|
void freeInner() {
|
||||||
FlwMemoryTracker._freeCPUMemory(size);
|
FlwMemoryTracker._freeCpuMemory(size);
|
||||||
freed = true;
|
freed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void free() {
|
public void free() {
|
||||||
|
assertAllocated();
|
||||||
FlwMemoryTracker.free(ptr);
|
FlwMemoryTracker.free(ptr);
|
||||||
freeInner();
|
freeInner();
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,9 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock realloc(long size) {
|
public MemoryBlock realloc(long size) {
|
||||||
|
assertAllocated();
|
||||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner, 1);
|
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner, 1);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
freeInner();
|
freeInner();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
@ -54,13 +55,13 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
|
|
||||||
static MemoryBlock malloc(long size) {
|
static MemoryBlock malloc(long size) {
|
||||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER, 2);
|
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER, 2);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock calloc(long num, long size) {
|
static MemoryBlock calloc(long num, long size) {
|
||||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER, 2);
|
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER, 2);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +95,7 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
FlwLibLink.INSTANCE.getLogger().warn(builder.toString());
|
FlwLibLink.INSTANCE.getLogger().warn(builder.toString());
|
||||||
|
|
||||||
FlwMemoryTracker.free(ptr);
|
FlwMemoryTracker.free(ptr);
|
||||||
FlwMemoryTracker._freeCPUMemory(size);
|
FlwMemoryTracker._freeCpuMemory(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
import dev.engine_room.flywheel.lib.util.StringUtil;
|
import dev.engine_room.flywheel.lib.util.StringUtil;
|
||||||
|
|
||||||
public final class FlwMemoryTracker {
|
public final class FlwMemoryTracker {
|
||||||
public static final boolean DEBUG_MEMORY_SAFETY = System.getProperty("flw.debugMemorySafety") != null;
|
|
||||||
|
|
||||||
private static final AtomicLong CPU_MEMORY = new AtomicLong(0);
|
private static final AtomicLong CPU_MEMORY = new AtomicLong(0);
|
||||||
private static final AtomicLong GPU_MEMORY = new AtomicLong(0);
|
private static final AtomicLong GPU_MEMORY = new AtomicLong(0);
|
||||||
|
|
||||||
@ -32,38 +30,38 @@ public final class FlwMemoryTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static long realloc(long ptr, long size) {
|
public static long realloc(long ptr, long size) {
|
||||||
ptr = MemoryUtil.nmemRealloc(ptr, size);
|
long newPtr = MemoryUtil.nmemRealloc(ptr, size);
|
||||||
if (ptr == MemoryUtil.NULL) {
|
if (newPtr == MemoryUtil.NULL) {
|
||||||
throw new OutOfMemoryError("Failed to reallocate " + size + " bytes for address " + StringUtil.formatAddress(ptr));
|
throw new OutOfMemoryError("Failed to reallocate " + size + " bytes for address " + StringUtil.formatAddress(ptr));
|
||||||
}
|
}
|
||||||
return ptr;
|
return newPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void free(long ptr) {
|
public static void free(long ptr) {
|
||||||
MemoryUtil.nmemFree(ptr);
|
MemoryUtil.nmemFree(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void _allocCPUMemory(long size) {
|
public static void _allocCpuMemory(long size) {
|
||||||
CPU_MEMORY.getAndAdd(size);
|
CPU_MEMORY.getAndAdd(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void _freeCPUMemory(long size) {
|
public static void _freeCpuMemory(long size) {
|
||||||
CPU_MEMORY.getAndAdd(-size);
|
CPU_MEMORY.getAndAdd(-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void _allocGPUMemory(long size) {
|
public static void _allocGpuMemory(long size) {
|
||||||
GPU_MEMORY.getAndAdd(size);
|
GPU_MEMORY.getAndAdd(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void _freeGPUMemory(long size) {
|
public static void _freeGpuMemory(long size) {
|
||||||
GPU_MEMORY.getAndAdd(-size);
|
GPU_MEMORY.getAndAdd(-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getCPUMemory() {
|
public static long getCpuMemory() {
|
||||||
return CPU_MEMORY.get();
|
return CPU_MEMORY.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getGPUMemory() {
|
public static long getGpuMemory() {
|
||||||
return GPU_MEMORY.get();
|
return GPU_MEMORY.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public sealed interface MemoryBlock permits AbstractMemoryBlockImpl {
|
|||||||
void free();
|
void free();
|
||||||
|
|
||||||
static MemoryBlock malloc(long size) {
|
static MemoryBlock malloc(long size) {
|
||||||
if (FlwMemoryTracker.DEBUG_MEMORY_SAFETY) {
|
if (MemoryBlockImpl.DEBUG_MEMORY_SAFETY) {
|
||||||
return DebugMemoryBlockImpl.malloc(size);
|
return DebugMemoryBlockImpl.malloc(size);
|
||||||
} else {
|
} else {
|
||||||
return MemoryBlockImpl.malloc(size);
|
return MemoryBlockImpl.malloc(size);
|
||||||
@ -38,7 +38,7 @@ public sealed interface MemoryBlock permits AbstractMemoryBlockImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock calloc(long num, long size) {
|
static MemoryBlock calloc(long num, long size) {
|
||||||
if (FlwMemoryTracker.DEBUG_MEMORY_SAFETY) {
|
if (MemoryBlockImpl.DEBUG_MEMORY_SAFETY) {
|
||||||
return DebugMemoryBlockImpl.calloc(num, size);
|
return DebugMemoryBlockImpl.calloc(num, size);
|
||||||
} else {
|
} else {
|
||||||
return MemoryBlockImpl.calloc(num, size);
|
return MemoryBlockImpl.calloc(num, size);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package dev.engine_room.flywheel.lib.memory;
|
package dev.engine_room.flywheel.lib.memory;
|
||||||
|
|
||||||
class MemoryBlockImpl extends AbstractMemoryBlockImpl {
|
class MemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||||
|
static final boolean DEBUG_MEMORY_SAFETY = System.getProperty("flw.debugMemorySafety") != null;
|
||||||
|
|
||||||
MemoryBlockImpl(long ptr, long size) {
|
MemoryBlockImpl(long ptr, long size) {
|
||||||
super(ptr, size);
|
super(ptr, size);
|
||||||
}
|
}
|
||||||
@ -12,21 +14,22 @@ class MemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock realloc(long size) {
|
public MemoryBlock realloc(long size) {
|
||||||
|
assertAllocated();
|
||||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size);
|
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
freeInner();
|
freeInner();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock malloc(long size) {
|
static MemoryBlock malloc(long size) {
|
||||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.malloc(size), size);
|
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.malloc(size), size);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock calloc(long num, long size) {
|
static MemoryBlock calloc(long num, long size) {
|
||||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size);
|
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,21 +28,22 @@ class TrackedMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryBlock realloc(long size) {
|
public MemoryBlock realloc(long size) {
|
||||||
|
assertAllocated();
|
||||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner);
|
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
freeInner();
|
freeInner();
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock malloc(long size) {
|
static MemoryBlock malloc(long size) {
|
||||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER);
|
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryBlock calloc(long num, long size) {
|
static MemoryBlock calloc(long num, long size) {
|
||||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER);
|
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER);
|
||||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ class TrackedMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (!freed) {
|
if (!freed) {
|
||||||
FlwMemoryTracker.free(ptr);
|
FlwMemoryTracker.free(ptr);
|
||||||
FlwMemoryTracker._freeCPUMemory(size);
|
FlwMemoryTracker._freeCpuMemory(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.engine_room.flywheel.lib.model;
|
package dev.engine_room.flywheel.lib.model;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
import org.joml.Vector4f;
|
import org.joml.Vector4f;
|
||||||
import org.joml.Vector4fc;
|
import org.joml.Vector4fc;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
@ -9,32 +10,32 @@ import dev.engine_room.flywheel.api.model.IndexSequence;
|
|||||||
import dev.engine_room.flywheel.api.model.Mesh;
|
import dev.engine_room.flywheel.api.model.Mesh;
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
||||||
import dev.engine_room.flywheel.api.vertex.VertexView;
|
import dev.engine_room.flywheel.api.vertex.VertexList;
|
||||||
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
|
import dev.engine_room.flywheel.lib.material.SimpleMaterial;
|
||||||
import dev.engine_room.flywheel.lib.material.StandardMaterialShaders;
|
import dev.engine_room.flywheel.lib.material.StandardMaterialShaders;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
import dev.engine_room.flywheel.lib.vertex.FullVertexView;
|
import dev.engine_room.flywheel.lib.vertex.FullVertexView;
|
||||||
|
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
|
||||||
public class LineModelBuilder {
|
public final class LineModelBuilder {
|
||||||
public static final Material MATERIAL = SimpleMaterial.builder()
|
private static final Material MATERIAL = SimpleMaterial.builder()
|
||||||
.shaders(StandardMaterialShaders.LINE)
|
.shaders(StandardMaterialShaders.LINE)
|
||||||
.backfaceCulling(false)
|
.backfaceCulling(false)
|
||||||
.diffuse(false)
|
.diffuse(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private final VertexView vertices;
|
@UnknownNullability
|
||||||
private MemoryBlock block;
|
private VertexView vertexView;
|
||||||
|
@UnknownNullability
|
||||||
|
private MemoryBlock data;
|
||||||
private int vertexCount = 0;
|
private int vertexCount = 0;
|
||||||
|
|
||||||
private LineModelBuilder(int segmentCount) {
|
public LineModelBuilder(int segmentCount) {
|
||||||
this.vertices = new FullVertexView();
|
vertexView = new FullVertexView();
|
||||||
this.block = MemoryBlock.malloc(segmentCount * 4 * FullVertexView.STRIDE);
|
data = MemoryBlock.mallocTracked(segmentCount * 4 * vertexView.stride());
|
||||||
vertices.ptr(block.ptr());
|
vertexView.ptr(data.ptr());
|
||||||
}
|
|
||||||
|
|
||||||
public static LineModelBuilder withCapacity(int segmentCount) {
|
|
||||||
return new LineModelBuilder(segmentCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LineModelBuilder line(float x1, float y1, float z1, float x2, float y2, float z2) {
|
public LineModelBuilder line(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||||
@ -50,53 +51,61 @@ public class LineModelBuilder {
|
|||||||
float normalZ = dz / length;
|
float normalZ = dz / length;
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
vertices.x(vertexCount + i, x1);
|
vertexView.x(vertexCount + i, x1);
|
||||||
vertices.y(vertexCount + i, y1);
|
vertexView.y(vertexCount + i, y1);
|
||||||
vertices.z(vertexCount + i, z1);
|
vertexView.z(vertexCount + i, z1);
|
||||||
|
|
||||||
vertices.x(vertexCount + 2 + i, x2);
|
vertexView.x(vertexCount + 2 + i, x2);
|
||||||
vertices.y(vertexCount + 2 + i, y2);
|
vertexView.y(vertexCount + 2 + i, y2);
|
||||||
vertices.z(vertexCount + 2 + i, z2);
|
vertexView.z(vertexCount + 2 + i, z2);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
vertices.r(vertexCount + i, 1);
|
vertexView.r(vertexCount + i, 1);
|
||||||
vertices.g(vertexCount + i, 1);
|
vertexView.g(vertexCount + i, 1);
|
||||||
vertices.b(vertexCount + i, 1);
|
vertexView.b(vertexCount + i, 1);
|
||||||
vertices.a(vertexCount + i, 1);
|
vertexView.a(vertexCount + i, 1);
|
||||||
vertices.u(vertexCount + i, 0);
|
vertexView.u(vertexCount + i, 0);
|
||||||
vertices.v(vertexCount + i, 0);
|
vertexView.v(vertexCount + i, 0);
|
||||||
vertices.light(vertexCount + i, LightTexture.FULL_BRIGHT);
|
vertexView.overlay(vertexCount + i, OverlayTexture.NO_OVERLAY);
|
||||||
vertices.normalX(vertexCount + i, normalX);
|
vertexView.light(vertexCount + i, LightTexture.FULL_BRIGHT);
|
||||||
vertices.normalY(vertexCount + i, normalY);
|
vertexView.normalX(vertexCount + i, normalX);
|
||||||
vertices.normalZ(vertexCount + i, normalZ);
|
vertexView.normalY(vertexCount + i, normalY);
|
||||||
|
vertexView.normalZ(vertexCount + i, normalZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexCount += 4;
|
vertexCount += 4;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Model build() {
|
public Model build() {
|
||||||
vertices.vertexCount(vertexCount);
|
vertexView.vertexCount(vertexCount);
|
||||||
|
|
||||||
var boundingSphere = ModelUtil.computeBoundingSphere(vertices);
|
var boundingSphere = ModelUtil.computeBoundingSphere(vertexView);
|
||||||
boundingSphere.w += 0.1f; // make the bounding sphere a little bigger to account for line width
|
boundingSphere.w += 0.1f; // make the bounding sphere a little bigger to account for line width
|
||||||
|
var mesh = new LineMesh(vertexView, boundingSphere);
|
||||||
|
var model = new SingleMeshModel(mesh, MATERIAL);
|
||||||
|
|
||||||
var mesh = new LineMesh(vertexCount, vertices, block, boundingSphere);
|
vertexView = null;
|
||||||
|
data = null;
|
||||||
|
vertexCount = 0;
|
||||||
|
|
||||||
return new SingleMeshModel(mesh, MATERIAL);
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureCapacity(int vertexCount) {
|
private void ensureCapacity(int vertexCount) {
|
||||||
if (vertexCount * FullVertexView.STRIDE > block.size()) {
|
if (data == null) {
|
||||||
this.block = block.realloc(vertexCount * FullVertexView.STRIDE);
|
vertexView = new FullVertexView();
|
||||||
vertices.ptr(block.ptr());
|
data = MemoryBlock.mallocTracked(vertexCount * vertexView.stride());
|
||||||
|
vertexView.ptr(data.ptr());
|
||||||
|
} else if (vertexCount * vertexView.stride() > data.size()) {
|
||||||
|
data = data.realloc(vertexCount * vertexView.stride());
|
||||||
|
vertexView.ptr(data.ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LineMesh implements Mesh {
|
private static class LineMesh implements Mesh {
|
||||||
public static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
|
private static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
|
||||||
int numVertices = 2 * count / 3;
|
int numVertices = 2 * count / 3;
|
||||||
int baseVertex = 0;
|
int baseVertex = 0;
|
||||||
while (baseVertex < numVertices) {
|
while (baseVertex < numVertices) {
|
||||||
@ -113,26 +122,22 @@ public class LineModelBuilder {
|
|||||||
ptr += 24;
|
ptr += 24;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final int vertexCount;
|
private final VertexList vertexList;
|
||||||
private final VertexView vertexView;
|
|
||||||
private final MemoryBlock data;
|
|
||||||
private final Vector4f boundingSphere;
|
private final Vector4f boundingSphere;
|
||||||
|
|
||||||
public LineMesh(int vertexCount, VertexView vertexView, MemoryBlock data, Vector4f boundingSphere) {
|
public LineMesh(VertexList vertexList, Vector4f boundingSphere) {
|
||||||
this.vertexCount = vertexCount;
|
this.vertexList = vertexList;
|
||||||
this.vertexView = vertexView;
|
|
||||||
this.data = data;
|
|
||||||
this.boundingSphere = boundingSphere;
|
this.boundingSphere = boundingSphere;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int vertexCount() {
|
public int vertexCount() {
|
||||||
return vertexCount;
|
return vertexList.vertexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(MutableVertexList vertexList) {
|
public void write(MutableVertexList vertexList) {
|
||||||
vertexView.writeAll(vertexList);
|
vertexList.writeAll(vertexList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -142,17 +147,12 @@ public class LineModelBuilder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int indexCount() {
|
public int indexCount() {
|
||||||
return vertexCount / 2 * 3;
|
return vertexCount() / 2 * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector4fc boundingSphere() {
|
public Vector4fc boundingSphere() {
|
||||||
return boundingSphere;
|
return boundingSphere;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
data.free();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
package dev.engine_room.flywheel.lib.model;
|
package dev.engine_room.flywheel.lib.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.lib.util.FlwUtil;
|
||||||
|
|
||||||
public class ModelCache<T> {
|
public final class ModelCache<T> {
|
||||||
private static final List<ModelCache<?>> ALL = new ArrayList<>();
|
private static final Set<ModelCache<?>> ALL = FlwUtil.createWeakHashSet();
|
||||||
private final Function<T, Model> factory;
|
private final Function<T, Model> factory;
|
||||||
private final Map<T, Model> map = new ConcurrentHashMap<>();
|
private final Map<T, Model> map = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@ -28,7 +28,6 @@ public class ModelCache<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
map.values().forEach(Model::delete);
|
|
||||||
map.clear();
|
map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package dev.engine_room.flywheel.lib.model;
|
package dev.engine_room.flywheel.lib.model;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Set;
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.model.Model;
|
import dev.engine_room.flywheel.api.model.Model;
|
||||||
|
import dev.engine_room.flywheel.lib.util.FlwUtil;
|
||||||
|
|
||||||
public class ModelHolder {
|
public final class ModelHolder {
|
||||||
private static final List<ModelHolder> ALL = new ArrayList<>();
|
private static final Set<ModelHolder> ALL = FlwUtil.createWeakHashSet();
|
||||||
private final Supplier<Model> factory;
|
private final Supplier<Model> factory;
|
||||||
@Nullable
|
@Nullable
|
||||||
private volatile Model model;
|
private volatile Model model;
|
||||||
@ -45,7 +45,6 @@ public class ModelHolder {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
model = this.model;
|
model = this.model;
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
model.delete();
|
|
||||||
this.model = null;
|
this.model = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,19 @@ public final class ModelUtil {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public static Material getMaterial(RenderType chunkRenderType, boolean shaded) {
|
public static Material getMaterial(RenderType chunkRenderType, boolean shaded) {
|
||||||
if (chunkRenderType == RenderType.solid()) {
|
if (chunkRenderType == RenderType.solid()) {
|
||||||
return shaded ? Materials.CHUNK_SOLID_SHADED : Materials.CHUNK_SOLID_UNSHADED;
|
return shaded ? Materials.SOLID_BLOCK : Materials.SOLID_UNSHADED_BLOCK;
|
||||||
}
|
}
|
||||||
if (chunkRenderType == RenderType.cutoutMipped()) {
|
if (chunkRenderType == RenderType.cutoutMipped()) {
|
||||||
return shaded ? Materials.CHUNK_CUTOUT_MIPPED_SHADED : Materials.CHUNK_CUTOUT_MIPPED_UNSHADED;
|
return shaded ? Materials.CUTOUT_MIPPED_BLOCK : Materials.CUTOUT_MIPPED_UNSHADED_BLOCK;
|
||||||
}
|
}
|
||||||
if (chunkRenderType == RenderType.cutout()) {
|
if (chunkRenderType == RenderType.cutout()) {
|
||||||
return shaded ? Materials.CHUNK_CUTOUT_SHADED : Materials.CHUNK_CUTOUT_UNSHADED;
|
return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK;
|
||||||
}
|
}
|
||||||
if (chunkRenderType == RenderType.translucent()) {
|
if (chunkRenderType == RenderType.translucent()) {
|
||||||
return shaded ? Materials.CHUNK_TRANSLUCENT_SHADED : Materials.CHUNK_TRANSLUCENT_UNSHADED;
|
return shaded ? Materials.TRANSLUCENT_BLOCK : Materials.TRANSLUCENT_UNSHADED_BLOCK;
|
||||||
}
|
}
|
||||||
if (chunkRenderType == RenderType.tripwire()) {
|
if (chunkRenderType == RenderType.tripwire()) {
|
||||||
return shaded ? Materials.CHUNK_TRIPWIRE_SHADED : Materials.CHUNK_TRIPWIRE_UNSHADED;
|
return shaded ? Materials.TRIPWIRE_BLOCK : Materials.TRIPWIRE_UNSHADED_BLOCK;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
|
|
||||||
import dev.engine_room.flywheel.api.model.IndexSequence;
|
import dev.engine_room.flywheel.api.model.IndexSequence;
|
||||||
|
|
||||||
public class QuadIndexSequence implements IndexSequence {
|
public final class QuadIndexSequence implements IndexSequence {
|
||||||
public static final QuadIndexSequence INSTANCE = new QuadIndexSequence();
|
public static final QuadIndexSequence INSTANCE = new QuadIndexSequence();
|
||||||
|
|
||||||
private QuadIndexSequence() {
|
private QuadIndexSequence() {
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
package dev.engine_room.flywheel.lib.model;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.joml.Vector4f;
|
|
||||||
import org.joml.Vector4fc;
|
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
|
||||||
import dev.engine_room.flywheel.api.vertex.VertexView;
|
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
|
||||||
|
|
||||||
public class SimpleMesh implements QuadMesh {
|
|
||||||
private final int vertexCount;
|
|
||||||
private final VertexView vertexView;
|
|
||||||
private final Vector4f boundingSphere;
|
|
||||||
private final MemoryBlock data;
|
|
||||||
@Nullable
|
|
||||||
private final String descriptor;
|
|
||||||
|
|
||||||
public SimpleMesh(VertexView vertexView, MemoryBlock data, @Nullable String descriptor) {
|
|
||||||
this.vertexView = vertexView;
|
|
||||||
this.data = data;
|
|
||||||
this.descriptor = descriptor;
|
|
||||||
|
|
||||||
int bytes = (int) data.size();
|
|
||||||
int stride = (int) this.vertexView.stride();
|
|
||||||
if (bytes % stride != 0) {
|
|
||||||
throw new IllegalArgumentException("MemoryBlock contains non-whole amount of vertices!");
|
|
||||||
}
|
|
||||||
vertexCount = bytes / stride;
|
|
||||||
|
|
||||||
this.vertexView.ptr(data.ptr());
|
|
||||||
this.vertexView.vertexCount(vertexCount);
|
|
||||||
|
|
||||||
boundingSphere = ModelUtil.computeBoundingSphere(vertexView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SimpleMesh(VertexView vertexView, MemoryBlock data) {
|
|
||||||
this(vertexView, data, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int vertexCount() {
|
|
||||||
return vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(MutableVertexList dst) {
|
|
||||||
vertexView.writeAll(dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vector4fc boundingSphere() {
|
|
||||||
return boundingSphere;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
data.free();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SimpleMesh{" + "vertexCount=" + vertexCount + ",descriptor={" + descriptor + "}" + "}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,11 +24,4 @@ public class SimpleModel implements Model {
|
|||||||
public Vector4fc boundingSphere() {
|
public Vector4fc boundingSphere() {
|
||||||
return boundingSphere;
|
return boundingSphere;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
for (ConfiguredMesh mesh : meshes) {
|
|
||||||
mesh.mesh().delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package dev.engine_room.flywheel.lib.model;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.joml.Vector4fc;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
||||||
|
import dev.engine_room.flywheel.api.vertex.VertexList;
|
||||||
|
|
||||||
|
public final class SimpleQuadMesh implements QuadMesh {
|
||||||
|
private final VertexList vertexList;
|
||||||
|
private final Vector4f boundingSphere;
|
||||||
|
@Nullable
|
||||||
|
private final String descriptor;
|
||||||
|
|
||||||
|
public SimpleQuadMesh(VertexList vertexList, @Nullable String descriptor) {
|
||||||
|
this.vertexList = vertexList;
|
||||||
|
boundingSphere = ModelUtil.computeBoundingSphere(vertexList);
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleQuadMesh(VertexList vertexList) {
|
||||||
|
this(vertexList, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int vertexCount() {
|
||||||
|
return vertexList.vertexCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(MutableVertexList dst) {
|
||||||
|
vertexList.writeAll(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4fc boundingSphere() {
|
||||||
|
return boundingSphere;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SimpleQuadMesh{" + "vertexCount=" + vertexCount() + ",descriptor={" + descriptor + "}" + "}";
|
||||||
|
}
|
||||||
|
}
|
@ -28,9 +28,4 @@ public class SingleMeshModel implements Model {
|
|||||||
public Vector4fc boundingSphere() {
|
public Vector4fc boundingSphere() {
|
||||||
return mesh.boundingSphere();
|
return mesh.boundingSphere();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
mesh.delete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,16 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
|
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.vertex.VertexView;
|
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
import dev.engine_room.flywheel.lib.model.SimpleMesh;
|
import dev.engine_room.flywheel.lib.model.SimpleQuadMesh;
|
||||||
import dev.engine_room.flywheel.lib.vertex.NoOverlayVertexView;
|
import dev.engine_room.flywheel.lib.vertex.NoOverlayVertexView;
|
||||||
|
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||||
|
|
||||||
final class MeshHelper {
|
final class MeshHelper {
|
||||||
private MeshHelper() {
|
private MeshHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SimpleMesh blockVerticesToMesh(BufferBuilder.RenderedBuffer buffer, @Nullable String meshDescriptor) {
|
public static SimpleQuadMesh blockVerticesToMesh(BufferBuilder.RenderedBuffer buffer, @Nullable String meshDescriptor) {
|
||||||
BufferBuilder.DrawState drawState = buffer.drawState();
|
BufferBuilder.DrawState drawState = buffer.drawState();
|
||||||
int vertexCount = drawState.vertexCount();
|
int vertexCount = drawState.vertexCount();
|
||||||
long srcStride = drawState.format().getVertexSize();
|
long srcStride = drawState.format().getVertexSize();
|
||||||
@ -25,7 +25,7 @@ final class MeshHelper {
|
|||||||
long dstStride = vertexView.stride();
|
long dstStride = vertexView.stride();
|
||||||
|
|
||||||
ByteBuffer src = buffer.vertexBuffer();
|
ByteBuffer src = buffer.vertexBuffer();
|
||||||
MemoryBlock dst = MemoryBlock.malloc((long) vertexCount * dstStride);
|
MemoryBlock dst = MemoryBlock.mallocTracked((long) vertexCount * dstStride);
|
||||||
long srcPtr = MemoryUtil.memAddress(src);
|
long srcPtr = MemoryUtil.memAddress(src);
|
||||||
long dstPtr = dst.ptr();
|
long dstPtr = dst.ptr();
|
||||||
// The first 31 bytes of each vertex in a block vertex buffer are guaranteed to contain the same data in the
|
// The first 31 bytes of each vertex in a block vertex buffer are guaranteed to contain the same data in the
|
||||||
@ -42,6 +42,6 @@ final class MeshHelper {
|
|||||||
vertexView.ptr(dstPtr);
|
vertexView.ptr(dstPtr);
|
||||||
vertexView.vertexCount(vertexCount);
|
vertexView.vertexCount(vertexCount);
|
||||||
|
|
||||||
return new SimpleMesh(vertexView, dst, meshDescriptor);
|
return new SimpleQuadMesh(vertexView, meshDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package dev.engine_room.flywheel.lib.model.baked;
|
||||||
|
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
public class OriginBlockAndTintGetter extends VirtualBlockGetter {
|
||||||
|
@Nullable
|
||||||
|
protected BlockEntity originBlockEntity;
|
||||||
|
protected BlockState originBlockState = Blocks.AIR.defaultBlockState();
|
||||||
|
|
||||||
|
public OriginBlockAndTintGetter(ToIntFunction<BlockPos> blockLightFunc, ToIntFunction<BlockPos> skyLightFunc) {
|
||||||
|
super(blockLightFunc, skyLightFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void originBlockEntity(@Nullable BlockEntity blockEntity) {
|
||||||
|
originBlockEntity = blockEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void originBlockState(BlockState state) {
|
||||||
|
originBlockState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||||
|
if (pos.equals(BlockPos.ZERO)) {
|
||||||
|
return originBlockEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getBlockState(BlockPos pos) {
|
||||||
|
if (pos.equals(BlockPos.ZERO)) {
|
||||||
|
return originBlockState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinBuildHeight() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,13 @@
|
|||||||
package dev.engine_room.flywheel.lib.model.baked;
|
package dev.engine_room.flywheel.lib.model.baked;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.UnknownNullability;
|
||||||
|
|
||||||
|
import com.google.common.collect.MapMaker;
|
||||||
|
|
||||||
|
import dev.engine_room.flywheel.lib.internal.FlwLibXplat;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
@ -10,44 +15,35 @@ import net.minecraft.resources.ResourceLocation;
|
|||||||
* A helper class for loading and accessing JSON models not directly used by any blocks or items.
|
* A helper class for loading and accessing JSON models not directly used by any blocks or items.
|
||||||
* <br>
|
* <br>
|
||||||
* Creating a PartialModel will make Minecraft automatically load the associated modelLocation.
|
* Creating a PartialModel will make Minecraft automatically load the associated modelLocation.
|
||||||
* PartialModels must be initialized before the initial resource reload, otherwise an error will be thrown.
|
|
||||||
* It is recommended to do this in the client mod initializer on Fabric and the mod class constructor on Forge.
|
|
||||||
* <br>
|
* <br>
|
||||||
* Once Minecraft has finished baking all models, all PartialModels will have their bakedModel fields populated.
|
* Once Minecraft has finished baking all models, all PartialModels will have their bakedModel fields populated.
|
||||||
*/
|
*/
|
||||||
public class PartialModel {
|
public final class PartialModel {
|
||||||
static final List<PartialModel> ALL = new ArrayList<>();
|
static final ConcurrentMap<ResourceLocation, PartialModel> ALL = new MapMaker().weakValues().makeMap();
|
||||||
static boolean tooLate = false;
|
static boolean populateOnInit = false;
|
||||||
|
|
||||||
protected final ResourceLocation modelLocation;
|
private final ResourceLocation modelLocation;
|
||||||
protected BakedModel bakedModel;
|
@UnknownNullability
|
||||||
|
BakedModel bakedModel;
|
||||||
public PartialModel(ResourceLocation modelLocation) {
|
|
||||||
if (tooLate) {
|
|
||||||
throw new RuntimeException("Attempted to create PartialModel with location '" + modelLocation + "' after start of initial resource reload!");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private PartialModel(ResourceLocation modelLocation) {
|
||||||
this.modelLocation = modelLocation;
|
this.modelLocation = modelLocation;
|
||||||
|
|
||||||
synchronized (ALL) {
|
if (populateOnInit) {
|
||||||
ALL.add(this);
|
bakedModel = FlwLibXplat.INSTANCE.getBakedModel(Minecraft.getInstance().getModelManager(), modelLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceLocation getLocation() {
|
public static PartialModel of(ResourceLocation modelLocation) {
|
||||||
return modelLocation;
|
return ALL.computeIfAbsent(modelLocation, PartialModel::new);
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return getLocation()
|
|
||||||
.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UnknownNullability
|
||||||
public BakedModel get() {
|
public BakedModel get() {
|
||||||
return bakedModel;
|
return bakedModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void set(BakedModel bakedModel) {
|
public ResourceLocation modelLocation() {
|
||||||
this.bakedModel = bakedModel;
|
return modelLocation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||||||
|
|
||||||
import dev.engine_room.flywheel.api.model.Mesh;
|
import dev.engine_room.flywheel.api.model.Mesh;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
import dev.engine_room.flywheel.lib.model.SimpleMesh;
|
import dev.engine_room.flywheel.lib.model.SimpleQuadMesh;
|
||||||
import dev.engine_room.flywheel.lib.vertex.PosTexNormalVertexView;
|
import dev.engine_room.flywheel.lib.vertex.PosTexNormalVertexView;
|
||||||
|
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.model.geom.EntityModelSet;
|
import net.minecraft.client.model.geom.EntityModelSet;
|
||||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||||
@ -29,10 +30,14 @@ public final class ModelPartConverter {
|
|||||||
poseStack = objects.identityPoseStack;
|
poseStack = objects.identityPoseStack;
|
||||||
}
|
}
|
||||||
VertexWriter vertexWriter = objects.vertexWriter;
|
VertexWriter vertexWriter = objects.vertexWriter;
|
||||||
|
|
||||||
vertexWriter.setTextureMapper(textureMapper);
|
vertexWriter.setTextureMapper(textureMapper);
|
||||||
modelPart.render(poseStack, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY);
|
modelPart.render(poseStack, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY);
|
||||||
MemoryBlock data = vertexWriter.copyDataAndReset();
|
MemoryBlock data = vertexWriter.copyDataAndReset();
|
||||||
return new SimpleMesh(new PosTexNormalVertexView(), data, "source=ModelPartConverter");
|
|
||||||
|
VertexView vertexView = new PosTexNormalVertexView();
|
||||||
|
vertexView.load(data);
|
||||||
|
return new SimpleQuadMesh(vertexView, "source=ModelPartConverter");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Mesh convert(ModelLayerLocation layer, @Nullable TextureAtlasSprite sprite, String... childPath) {
|
public static Mesh convert(ModelLayerLocation layer, @Nullable TextureAtlasSprite sprite, String... childPath) {
|
||||||
|
@ -6,7 +6,7 @@ import org.lwjgl.system.MemoryUtil;
|
|||||||
|
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.lib.math.RenderMath;
|
import dev.engine_room.flywheel.lib.math.DataPacker;
|
||||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||||
import dev.engine_room.flywheel.lib.model.part.ModelPartConverter.TextureMapper;
|
import dev.engine_room.flywheel.lib.model.part.ModelPartConverter.TextureMapper;
|
||||||
import dev.engine_room.flywheel.lib.vertex.PosTexNormalVertexView;
|
import dev.engine_room.flywheel.lib.vertex.PosTexNormalVertexView;
|
||||||
@ -85,9 +85,9 @@ class VertexWriter implements VertexConsumer {
|
|||||||
public VertexConsumer normal(float x, float y, float z) {
|
public VertexConsumer normal(float x, float y, float z) {
|
||||||
if (!filledNormal) {
|
if (!filledNormal) {
|
||||||
long ptr = vertexPtr();
|
long ptr = vertexPtr();
|
||||||
MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(x));
|
MemoryUtil.memPutByte(ptr + 20, DataPacker.packNormI8(x));
|
||||||
MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(y));
|
MemoryUtil.memPutByte(ptr + 21, DataPacker.packNormI8(y));
|
||||||
MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(z));
|
MemoryUtil.memPutByte(ptr + 22, DataPacker.packNormI8(z));
|
||||||
filledNormal = true;
|
filledNormal = true;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -124,7 +124,7 @@ class VertexWriter implements VertexConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MemoryBlock copyDataAndReset() {
|
public MemoryBlock copyDataAndReset() {
|
||||||
MemoryBlock dataCopy = MemoryBlock.malloc(vertexCount * STRIDE);
|
MemoryBlock dataCopy = MemoryBlock.mallocTracked(vertexCount * STRIDE);
|
||||||
data.copyTo(dataCopy);
|
data.copyTo(dataCopy);
|
||||||
|
|
||||||
vertexCount = 0;
|
vertexCount = 0;
|
||||||
|
@ -4,7 +4,7 @@ import dev.engine_room.flywheel.api.task.Plan;
|
|||||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
||||||
|
|
||||||
public record BarrierPlan<C>(Plan<C> first, Plan<C> second) implements SimplyComposedPlan<C> {
|
public record BarrierPlan<C>(Plan<C> first, Plan<C> second) implements SimplyComposedPlan<C> {
|
||||||
public static <C> Plan<C> of(Plan<C> first, Plan<C> second) {
|
public static <C> BarrierPlan<C> of(Plan<C> first, Plan<C> second) {
|
||||||
return new BarrierPlan<>(first, second);
|
return new BarrierPlan<>(first, second);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,5 +12,4 @@ public record BarrierPlan<C>(Plan<C> first, Plan<C> second) implements SimplyCom
|
|||||||
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
|
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
|
||||||
first.execute(taskExecutor, context, () -> second.execute(taskExecutor, context, onCompletion));
|
first.execute(taskExecutor, context, () -> second.execute(taskExecutor, context, onCompletion));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ import dev.engine_room.flywheel.api.task.TaskExecutor;
|
|||||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||||
|
|
||||||
public final class Distribute {
|
public final class Distribute {
|
||||||
|
private Distribute() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Distribute the given list of tasks across the threads of the task executor.
|
* Distribute the given list of tasks across the threads of the task executor.
|
||||||
*
|
*
|
||||||
@ -184,7 +187,4 @@ public final class Distribute {
|
|||||||
public static int sliceSize(TaskExecutor taskExecutor, int totalSize, int denominator) {
|
public static int sliceSize(TaskExecutor taskExecutor, int totalSize, int denominator) {
|
||||||
return MoreMath.ceilingDiv(totalSize, taskExecutor.threadCount() * denominator);
|
return MoreMath.ceilingDiv(totalSize, taskExecutor.threadCount() * denominator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Distribute() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
|||||||
*/
|
*/
|
||||||
public record DynamicNestedPlan<C>(
|
public record DynamicNestedPlan<C>(
|
||||||
SupplierWithContext<C, Collection<? extends Plan<C>>> plans) implements SimplyComposedPlan<C> {
|
SupplierWithContext<C, Collection<? extends Plan<C>>> plans) implements SimplyComposedPlan<C> {
|
||||||
public static <C> Plan<C> of(SupplierWithContext.Ignored<C, Collection<? extends Plan<C>>> supplier) {
|
public static <C> DynamicNestedPlan<C> of(SupplierWithContext.Ignored<C, Collection<? extends Plan<C>>> supplier) {
|
||||||
return new DynamicNestedPlan<>(supplier);
|
return new DynamicNestedPlan<>(supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <C> Plan<C> of(SupplierWithContext<C, Collection<? extends Plan<C>>> supplier) {
|
public static <C> DynamicNestedPlan<C> of(SupplierWithContext<C, Collection<? extends Plan<C>>> supplier) {
|
||||||
return new DynamicNestedPlan<>(supplier);
|
return new DynamicNestedPlan<>(supplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package dev.engine_room.flywheel.lib.task;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.task.Plan;
|
|
||||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
||||||
import dev.engine_room.flywheel.lib.task.functional.ConsumerWithContext;
|
import dev.engine_room.flywheel.lib.task.functional.ConsumerWithContext;
|
||||||
import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
||||||
@ -19,19 +18,19 @@ import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
|||||||
*/
|
*/
|
||||||
public record ForEachPlan<T, C>(SupplierWithContext<C, List<T>> listSupplier,
|
public record ForEachPlan<T, C>(SupplierWithContext<C, List<T>> listSupplier,
|
||||||
ConsumerWithContext<T, C> action) implements SimplyComposedPlan<C> {
|
ConsumerWithContext<T, C> action) implements SimplyComposedPlan<C> {
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext<T, C> forEach) {
|
public static <T, C> ForEachPlan<T, C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext<T, C> forEach) {
|
||||||
return new ForEachPlan<>(iterable, forEach);
|
return new ForEachPlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext.Ignored<T, C> forEach) {
|
public static <T, C> ForEachPlan<T, C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext.Ignored<T, C> forEach) {
|
||||||
return new ForEachPlan<>(iterable, forEach);
|
return new ForEachPlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext<T, C> forEach) {
|
public static <T, C> ForEachPlan<T, C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext<T, C> forEach) {
|
||||||
return new ForEachPlan<>(iterable, forEach);
|
return new ForEachPlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext.Ignored<T, C> forEach) {
|
public static <T, C> ForEachPlan<T, C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext.Ignored<T, C> forEach) {
|
||||||
return new ForEachPlan<>(iterable, forEach);
|
return new ForEachPlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package dev.engine_room.flywheel.lib.task;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.task.Plan;
|
|
||||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
||||||
import dev.engine_room.flywheel.lib.task.functional.ConsumerWithContext;
|
import dev.engine_room.flywheel.lib.task.functional.ConsumerWithContext;
|
||||||
import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
||||||
@ -19,19 +18,19 @@ import dev.engine_room.flywheel.lib.task.functional.SupplierWithContext;
|
|||||||
*/
|
*/
|
||||||
public record ForEachSlicePlan<T, C>(SupplierWithContext<C, List<T>> listSupplier,
|
public record ForEachSlicePlan<T, C>(SupplierWithContext<C, List<T>> listSupplier,
|
||||||
ConsumerWithContext<List<T>, C> action) implements SimplyComposedPlan<C> {
|
ConsumerWithContext<List<T>, C> action) implements SimplyComposedPlan<C> {
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext<List<T>, C> forEach) {
|
public static <T, C> ForEachSlicePlan<T, C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext<List<T>, C> forEach) {
|
||||||
return new ForEachSlicePlan<>(iterable, forEach);
|
return new ForEachSlicePlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext.Ignored<List<T>, C> forEach) {
|
public static <T, C> ForEachSlicePlan<T, C> of(SupplierWithContext<C, List<T>> iterable, ConsumerWithContext.Ignored<List<T>, C> forEach) {
|
||||||
return new ForEachSlicePlan<>(iterable, forEach);
|
return new ForEachSlicePlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext<List<T>, C> forEach) {
|
public static <T, C> ForEachSlicePlan<T, C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext<List<T>, C> forEach) {
|
||||||
return new ForEachSlicePlan<>(iterable, forEach);
|
return new ForEachSlicePlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, C> Plan<C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext.Ignored<List<T>, C> forEach) {
|
public static <T, C> ForEachSlicePlan<T, C> of(SupplierWithContext.Ignored<C, List<T>> iterable, ConsumerWithContext.Ignored<List<T>, C> forEach) {
|
||||||
return new ForEachSlicePlan<>(iterable, forEach);
|
return new ForEachSlicePlan<>(iterable, forEach);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public record IfElsePlan<C>(BooleanSupplierWithContext<C> condition, Plan<C> onT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder<C> {
|
public static final class Builder<C> {
|
||||||
private final BooleanSupplierWithContext<C> condition;
|
private final BooleanSupplierWithContext<C> condition;
|
||||||
private Plan<C> onTrue = UnitPlan.of();
|
private Plan<C> onTrue = UnitPlan.of();
|
||||||
private Plan<C> onFalse = UnitPlan.of();
|
private Plan<C> onFalse = UnitPlan.of();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user