mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-10 12:34:11 +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.Matrix4f;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
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.RenderBuffers;
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
public interface RenderContext {
|
||||
LevelRenderer renderer();
|
||||
|
||||
@ -20,9 +18,9 @@ public interface RenderContext {
|
||||
|
||||
PoseStack stack();
|
||||
|
||||
Matrix4f projection();
|
||||
Matrix4fc projection();
|
||||
|
||||
Matrix4f viewProjection();
|
||||
Matrix4fc viewProjection();
|
||||
|
||||
Camera camera();
|
||||
|
@ -1,13 +1,12 @@
|
||||
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.registry.IdRegistry;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
@BackendImplemented
|
||||
public interface Backend {
|
||||
static IdRegistry<Backend> REGISTRY = FlwApiLink.INSTANCE.createIdRegistry();
|
||||
IdRegistry<Backend> REGISTRY = FlwApiLink.INSTANCE.createIdRegistry();
|
||||
|
||||
/**
|
||||
* 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.ElementType;
|
@ -9,19 +9,19 @@ public final class BackendManager {
|
||||
/**
|
||||
* Get the current backend.
|
||||
*/
|
||||
public static Backend getBackend() {
|
||||
return FlwApiLink.INSTANCE.getBackend();
|
||||
public static Backend currentBackend() {
|
||||
return FlwApiLink.INSTANCE.getCurrentBackend();
|
||||
}
|
||||
|
||||
public static boolean isBackendOn() {
|
||||
return FlwApiLink.INSTANCE.isBackendOn();
|
||||
}
|
||||
|
||||
public static Backend getOffBackend() {
|
||||
public static Backend offBackend() {
|
||||
return FlwApiLink.INSTANCE.getOffBackend();
|
||||
}
|
||||
|
||||
public static Backend getDefaultBackend() {
|
||||
public static Backend defaultBackend() {
|
||||
return FlwApiLink.INSTANCE.getDefaultBackend();
|
||||
}
|
||||
}
|
||||
|
@ -2,52 +2,43 @@ package dev.engine_room.flywheel.api.backend;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import dev.engine_room.flywheel.api.RenderContext;
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
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 it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
|
||||
@BackendImplemented
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
Plan<RenderContext> createFramePlan();
|
||||
|
||||
/**
|
||||
* Render all instances necessary for the given stage.
|
||||
* @param executor The task executor running the frame plan.
|
||||
* @param context The render context for this frame.
|
||||
* @param stage The stage to render.
|
||||
* @return The current render origin.
|
||||
*/
|
||||
void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
Vec3i renderOrigin();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @return The current render origin.
|
||||
*/
|
||||
Vec3i renderOrigin();
|
||||
|
||||
/**
|
||||
* Assign the set of sections that visuals have requested GPU light for.
|
||||
*
|
||||
@ -71,19 +57,70 @@ public interface Engine {
|
||||
*/
|
||||
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.
|
||||
* <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();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
default void delete() {
|
||||
handle().setDeleted();
|
||||
}
|
||||
|
||||
default void setChanged() {
|
||||
handle().setChanged();
|
||||
}
|
||||
|
||||
default void delete() {
|
||||
handle().setDeleted();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package dev.engine_room.flywheel.api.instance;
|
||||
|
||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||
|
||||
@BackendImplemented
|
||||
public interface InstanceHandle {
|
||||
|
@ -11,7 +11,7 @@ import net.minecraft.resources.ResourceLocation;
|
||||
* @param <I> The java representation of the 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.
|
||||
|
@ -2,7 +2,7 @@ package dev.engine_room.flywheel.api.instance;
|
||||
|
||||
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.
|
||||
@ -29,6 +29,17 @@ public interface Instancer<I extends Instance> {
|
||||
*/
|
||||
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.
|
||||
* <br>
|
||||
@ -43,15 +54,4 @@ public interface Instancer<I extends Instance> {
|
||||
* @param instance The instance to steal.
|
||||
*/
|
||||
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;
|
||||
|
||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
|
||||
@BackendImplemented
|
||||
|
@ -22,7 +22,7 @@ public interface FlwApiLink {
|
||||
|
||||
<T> IdRegistry<T> createIdRegistry();
|
||||
|
||||
Backend getBackend();
|
||||
Backend getCurrentBackend();
|
||||
|
||||
boolean isBackendOn();
|
||||
|
||||
|
@ -5,7 +5,7 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface CutoutShader {
|
||||
static Registry<CutoutShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
Registry<CutoutShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation source();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface FogShader {
|
||||
static Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation source();
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
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.
|
||||
*/
|
||||
Vector4fc boundingSphere();
|
||||
|
||||
/**
|
||||
* Free this mesh's resources, memory, etc.
|
||||
*/
|
||||
void delete();
|
||||
}
|
||||
|
@ -27,8 +27,6 @@ public interface Model {
|
||||
*/
|
||||
Vector4fc boundingSphere();
|
||||
|
||||
void delete();
|
||||
|
||||
record ConfiguredMesh(Material material, Mesh mesh) {
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,10 @@ package dev.engine_room.flywheel.api.registry;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
@ -26,13 +25,11 @@ public interface IdRegistry<T> extends Iterable<T> {
|
||||
|
||||
ResourceLocation getIdOrThrow(T object);
|
||||
|
||||
@Unmodifiable
|
||||
@UnmodifiableView
|
||||
Set<ResourceLocation> getAllIds();
|
||||
|
||||
@Unmodifiable
|
||||
@UnmodifiableView
|
||||
Collection<T> getAll();
|
||||
|
||||
void addFreezeCallback(Consumer<IdRegistry<T>> callback);
|
||||
|
||||
boolean isFrozen();
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package dev.engine_room.flywheel.api.registry;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
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);
|
||||
|
||||
@Unmodifiable
|
||||
@UnmodifiableView
|
||||
Set<T> getAll();
|
||||
|
||||
void addFreezeCallback(Consumer<Registry<T>> callback);
|
||||
|
||||
boolean isFrozen();
|
||||
}
|
||||
|
@ -1,64 +1,11 @@
|
||||
package dev.engine_room.flywheel.api.task;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
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.
|
||||
* <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;
|
||||
|
||||
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
|
||||
@ -8,6 +9,8 @@ import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||
* without any built in support for networking.
|
||||
*/
|
||||
public interface Effect {
|
||||
LevelAccessor level();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public sealed interface SectionTrackedVisual extends Visual permits ShaderLightVisual, LightUpdatedVisual {
|
||||
public sealed interface SectionTrackedVisual extends Visual permits LightUpdatedVisual, ShaderLightVisual {
|
||||
/**
|
||||
* Set the section collector object.
|
||||
*
|
||||
|
@ -3,7 +3,7 @@ package dev.engine_room.flywheel.api.visualization;
|
||||
import org.joml.Matrix3fc;
|
||||
import org.joml.Matrix4fc;
|
||||
|
||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||
|
||||
@BackendImplemented
|
||||
public interface VisualEmbedding extends VisualizationContext {
|
||||
|
@ -9,7 +9,7 @@ public interface VisualManager<T> {
|
||||
*
|
||||
* @return The visual count.
|
||||
*/
|
||||
int getVisualCount();
|
||||
int visualCount();
|
||||
|
||||
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;
|
||||
|
||||
import dev.engine_room.flywheel.api.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.backend.BackendImplemented;
|
||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
package dev.engine_room.flywheel.api.visualization;
|
||||
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
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.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.server.level.BlockDestructionProgress;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
@ -27,52 +30,31 @@ public interface VisualizationManager {
|
||||
return FlwApiLink.INSTANCE.getVisualizationManagerOrThrow(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this when you want to run {@link Visual#update}.
|
||||
* @param blockEntity The block entity whose visual you want to update.
|
||||
*/
|
||||
static void queueUpdate(BlockEntity blockEntity) {
|
||||
Level level = blockEntity.getLevel();
|
||||
VisualizationManager manager = get(level);
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
Vec3i renderOrigin();
|
||||
|
||||
manager.getBlockEntities().queueUpdate(blockEntity);
|
||||
}
|
||||
VisualManager<BlockEntity> blockEntities();
|
||||
|
||||
VisualManager<Entity> entities();
|
||||
|
||||
VisualManager<Effect> effects();
|
||||
|
||||
/**
|
||||
* Call this when you want to run {@link Visual#update}.
|
||||
* @param entity The entity whose visual you want to update.
|
||||
* Get the render dispatcher, which can be used to invoke rendering.
|
||||
* <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) {
|
||||
Level level = entity.level();
|
||||
VisualizationManager manager = get(level);
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
RenderDispatcher renderDispatcher();
|
||||
|
||||
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() {
|
||||
ShaderIndices.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.Layout;
|
||||
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.lib.vertex.FullVertexView;
|
||||
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
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.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.core.CompilerStats;
|
||||
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
|
||||
@ -74,7 +74,7 @@ public final class FlwPrograms {
|
||||
@Nullable
|
||||
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_vertex"))
|
||||
.materialSources(ShaderIndices.materialVertex()
|
||||
.materialSources(MaterialShaderIndices.vertexSources()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberMaterialVertexIndex"))
|
||||
@ -84,7 +84,7 @@ public final class FlwPrograms {
|
||||
@Nullable
|
||||
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_fragment"))
|
||||
.materialSources(ShaderIndices.materialFragment()
|
||||
.materialSources(MaterialShaderIndices.fragmentSources()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
|
||||
@ -94,7 +94,7 @@ public final class FlwPrograms {
|
||||
@Nullable
|
||||
private static UberShaderComponent createFogComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||
.materialSources(ShaderIndices.fog()
|
||||
.materialSources(MaterialShaderIndices.fogSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
@ -108,7 +108,7 @@ public final class FlwPrograms {
|
||||
@Nullable
|
||||
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||
.materialSources(ShaderIndices.cutout()
|
||||
.materialSources(MaterialShaderIndices.cutoutSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.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.Instancer;
|
||||
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 final InstanceType<I> type;
|
||||
|
@ -9,11 +9,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
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.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||
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.engine.embed.Environment;
|
||||
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<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Instance> Instancer<I> getInstancer(Environment environment, InstanceType<I> type, Model model, RenderStage stage) {
|
||||
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(environment, type, model, stage), this::createAndDeferInit);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
instancers.clear();
|
||||
initializationQueue.clear();
|
||||
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, visualType), this::createAndDeferInit);
|
||||
}
|
||||
|
||||
public void flush(LightStorage lightStorage) {
|
||||
@ -59,9 +54,9 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
||||
.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);
|
||||
|
||||
@ -80,10 +75,6 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
||||
return out;
|
||||
}
|
||||
|
||||
protected record UninitializedInstancer<N, I extends Instance>(InstancerKey<I> key, N instancer) {
|
||||
|
||||
}
|
||||
|
||||
private static boolean checkAndWarnEmptyModel(Model model) {
|
||||
if (!model.meshes().isEmpty()) {
|
||||
return true;
|
||||
@ -133,4 +124,12 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
||||
}
|
||||
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 dev.engine_room.flywheel.api.RenderContext;
|
||||
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.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
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.VisualType;
|
||||
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.Environment;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
||||
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 net.minecraft.client.Camera;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class EngineImpl implements Engine {
|
||||
private final DrawManager<? extends AbstractInstancer<?>> drawManager;
|
||||
private final int sqrMaxOriginDistance;
|
||||
private final Flag flushFlag = new NamedFlag("flushed");
|
||||
private final EnvironmentStorage environmentStorage;
|
||||
private final LightStorage lightStorage;
|
||||
|
||||
@ -46,32 +43,18 @@ public class EngineImpl implements Engine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisualizationContext createVisualizationContext(RenderStage stage) {
|
||||
return new VisualizationContextImpl(stage);
|
||||
public VisualizationContext createVisualizationContext(VisualType visualType) {
|
||||
return new VisualizationContextImpl(visualType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
return lightStorage.createFramePlan()
|
||||
.then(SyncedPlan.of(this::flush));
|
||||
return lightStorage.createFramePlan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
|
||||
executor.syncUntil(flushFlag::isRaised);
|
||||
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);
|
||||
public Vec3i renderOrigin() {
|
||||
return renderOrigin;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,13 +75,32 @@ public class EngineImpl implements Engine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i renderOrigin() {
|
||||
return renderOrigin;
|
||||
public void lightSections(LongSet sections) {
|
||||
lightStorage.sections(sections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lightSections(LongSet sections) {
|
||||
lightStorage.sections(sections);
|
||||
public void onLightUpdate(SectionPos sectionPos, LightLayer layer) {
|
||||
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
|
||||
@ -107,18 +109,8 @@ public class EngineImpl implements Engine {
|
||||
lightStorage.delete();
|
||||
}
|
||||
|
||||
public <I extends Instance> Instancer<I> instancer(Environment environment, InstanceType<I> type, Model model, RenderStage stage) {
|
||||
return drawManager.getInstancer(environment, type, model, stage);
|
||||
}
|
||||
|
||||
private void flush(RenderContext ctx) {
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
Uniforms.update(ctx);
|
||||
environmentStorage.flush();
|
||||
drawManager.flush(lightStorage);
|
||||
}
|
||||
|
||||
flushFlag.raise();
|
||||
public <I extends Instance> Instancer<I> instancer(Environment environment, InstanceType<I> type, Model model, VisualType visualType) {
|
||||
return drawManager.getInstancer(environment, type, model, visualType);
|
||||
}
|
||||
|
||||
public EnvironmentStorage environmentStorage() {
|
||||
@ -131,11 +123,11 @@ public class EngineImpl implements Engine {
|
||||
|
||||
private class VisualizationContextImpl implements VisualizationContext {
|
||||
private final InstancerProviderImpl instancerProvider;
|
||||
private final RenderStage stage;
|
||||
private final VisualType visualType;
|
||||
|
||||
public VisualizationContextImpl(RenderStage stage) {
|
||||
instancerProvider = new InstancerProviderImpl(EngineImpl.this, stage);
|
||||
this.stage = stage;
|
||||
public VisualizationContextImpl(VisualType visualType) {
|
||||
instancerProvider = new InstancerProviderImpl(EngineImpl.this, visualType);
|
||||
this.visualType = visualType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,7 +142,7 @@ public class EngineImpl implements Engine {
|
||||
|
||||
@Override
|
||||
public VisualEmbedding createEmbedding() {
|
||||
var out = new EmbeddedEnvironment(EngineImpl.this, stage);
|
||||
var out = new EmbeddedEnvironment(EngineImpl.this, visualType);
|
||||
environmentStorage.track(out);
|
||||
return out;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
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.InstanceType;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
import dev.engine_room.flywheel.api.event.RenderStage;
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||
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;
|
||||
|
||||
public record InstancerProviderImpl(EngineImpl engine, RenderStage renderStage) implements InstancerProvider {
|
||||
public record InstancerProviderImpl(EngineImpl engine, VisualType visualType) implements InstancerProvider {
|
||||
@Override
|
||||
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.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
||||
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.gl.buffer.GlBuffer;
|
||||
import dev.engine_room.flywheel.lib.task.SimplePlan;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
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 net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
@ -53,6 +51,7 @@ public class LightStorage {
|
||||
private final BitSet changed = new BitSet();
|
||||
private boolean needsLutRebuild = false;
|
||||
|
||||
private final LongSet updatedSections = new LongOpenHashSet();
|
||||
@Nullable
|
||||
private LongSet requestedSections;
|
||||
|
||||
@ -72,11 +71,12 @@ public class LightStorage {
|
||||
requestedSections = sections;
|
||||
}
|
||||
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
return SimplePlan.of(() -> {
|
||||
var updatedSections = LightUpdateHolder.get(level)
|
||||
.getAndClearUpdatedSections();
|
||||
public void onLightUpdate(long section) {
|
||||
updatedSections.add(section);
|
||||
}
|
||||
|
||||
public <C> Plan<C> createFramePlan() {
|
||||
return SimplePlan.of(() -> {
|
||||
if (updatedSections.isEmpty() && requestedSections == null) {
|
||||
return;
|
||||
}
|
||||
@ -87,15 +87,15 @@ public class LightStorage {
|
||||
LongSet sectionsToCollect;
|
||||
if (requestedSections == null) {
|
||||
// If none were requested, then we need to collect all sections that received updates.
|
||||
sectionsToCollect = new LongArraySet();
|
||||
sectionsToCollect = new LongOpenHashSet();
|
||||
} else {
|
||||
// If we did receive a new set of requested sections, we only
|
||||
// need to collect the sections that weren't yet tracked.
|
||||
sectionsToCollect = requestedSections;
|
||||
sectionsToCollect = new LongOpenHashSet(requestedSections);
|
||||
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.
|
||||
for (long updatedSection : updatedSections) {
|
||||
// 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?
|
||||
sectionsToCollect.forEach(this::collectSection);
|
||||
|
||||
updatedSections.clear();
|
||||
requestedSections = null;
|
||||
});
|
||||
}
|
||||
@ -130,7 +131,7 @@ public class LightStorage {
|
||||
var entry = it.next();
|
||||
var section = entry.getLongKey();
|
||||
|
||||
if (!this.requestedSections.contains(section)) {
|
||||
if (!requestedSections.contains(section)) {
|
||||
arena.free(entry.getIntValue());
|
||||
needsLutRebuild = true;
|
||||
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.Transparency;
|
||||
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;
|
||||
|
||||
// Materials are unpacked in "flywheel:flywheel/internal/packed_material.glsl"
|
||||
@ -53,13 +53,8 @@ public final class MaterialEncoder {
|
||||
}
|
||||
|
||||
public static int packFogAndCutout(Material material) {
|
||||
var fog = ShaderIndices.fog()
|
||||
.index(material.fog()
|
||||
.source());
|
||||
var cutout = ShaderIndices.cutout()
|
||||
.index(material.cutout()
|
||||
.source());
|
||||
|
||||
var fog = MaterialShaderIndices.fogIndex(material.fog());
|
||||
var cutout = MaterialShaderIndices.cutoutIndex(material.cutout());
|
||||
return fog & 0xFFFF | (cutout & 0xFFFF) << 16;
|
||||
}
|
||||
|
||||
|
@ -9,13 +9,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
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.gl.GlPrimitive;
|
||||
import dev.engine_room.flywheel.backend.gl.array.GlVertexArray;
|
||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import dev.engine_room.flywheel.backend.util.ReferenceCounted;
|
||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||
import dev.engine_room.flywheel.lib.vertex.VertexView;
|
||||
|
||||
public class MeshPool {
|
||||
private final VertexView vertexView;
|
||||
|
@ -6,13 +6,13 @@ import org.joml.Matrix3fc;
|
||||
import org.joml.Matrix4f;
|
||||
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.InstanceType;
|
||||
import dev.engine_room.flywheel.api.instance.Instancer;
|
||||
import dev.engine_room.flywheel.api.instance.InstancerProvider;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
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.engine.EngineImpl;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
@ -20,7 +20,7 @@ import net.minecraft.core.Vec3i;
|
||||
|
||||
public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
||||
private final EngineImpl engine;
|
||||
private final RenderStage renderStage;
|
||||
private final VisualType visualType;
|
||||
@Nullable
|
||||
private final EmbeddedEnvironment parent;
|
||||
private final InstancerProvider instancerProvider;
|
||||
@ -32,22 +32,22 @@ public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
||||
|
||||
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.renderStage = renderStage;
|
||||
this.visualType = visualType;
|
||||
this.parent = parent;
|
||||
|
||||
instancerProvider = new InstancerProvider() {
|
||||
@Override
|
||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
||||
// 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) {
|
||||
this(engine, renderStage, null);
|
||||
public EmbeddedEnvironment(EngineImpl engine, VisualType visualType) {
|
||||
this(engine, visualType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,7 +68,7 @@ public class EmbeddedEnvironment implements VisualEmbedding, Environment {
|
||||
|
||||
@Override
|
||||
public VisualEmbedding createEmbedding() {
|
||||
var out = new EmbeddedEnvironment(engine, renderStage, this);
|
||||
var out = new EmbeddedEnvironment(engine, visualType, this);
|
||||
engine.environmentStorage()
|
||||
.track(out);
|
||||
return out;
|
||||
|
@ -14,11 +14,11 @@ import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
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.InstanceType;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
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.IndirectPrograms;
|
||||
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;
|
||||
|
||||
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::material, MaterialRenderState.COMPARATOR);
|
||||
|
||||
@ -42,7 +42,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
private final IndirectBuffers buffers;
|
||||
private final List<IndirectInstancer<I>> instancers = 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 GlProgram cullProgram;
|
||||
@ -145,36 +145,36 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
|
||||
}
|
||||
|
||||
private boolean nothingToDo(RenderStage stage) {
|
||||
return nothingToDo() || !multiDraws.containsKey(stage);
|
||||
private boolean nothingToDo(VisualType visualType) {
|
||||
return nothingToDo() || !multiDraws.containsKey(visualType);
|
||||
}
|
||||
|
||||
private void sortDraws() {
|
||||
multiDraws.clear();
|
||||
// sort by stage, then material
|
||||
// sort by visual type, then material
|
||||
indirectDraws.sort(DRAW_COMPARATOR);
|
||||
|
||||
for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
|
||||
var draw1 = indirectDraws.get(i);
|
||||
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 (i == indirectDraws.size() - 1 || stage1 != indirectDraws.get(i + 1)
|
||||
.stage() || !material1.equals(indirectDraws.get(i + 1)
|
||||
// if the next draw call has a different VisualType or Material, start a new MultiDraw
|
||||
if (i == indirectDraws.size() - 1 || visualType1 != indirectDraws.get(i + 1)
|
||||
.visualType() || !material1.equals(indirectDraws.get(i + 1)
|
||||
.material())) {
|
||||
multiDraws.computeIfAbsent(stage1, s -> new ArrayList<>())
|
||||
multiDraws.computeIfAbsent(visualType1, s -> new ArrayList<>())
|
||||
.add(new MultiDraw(material1, start, i + 1));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasStage(RenderStage stage) {
|
||||
return multiDraws.containsKey(stage);
|
||||
public boolean hasVisualType(VisualType visualType) {
|
||||
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();
|
||||
instancers.add(instancer);
|
||||
|
||||
@ -183,7 +183,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
var entry = meshes.get(i);
|
||||
|
||||
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);
|
||||
instancer.addDraw(draw);
|
||||
}
|
||||
@ -191,8 +191,8 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
needsDrawSort = true;
|
||||
}
|
||||
|
||||
public void submit(RenderStage stage) {
|
||||
if (nothingToDo(stage)) {
|
||||
public void submit(VisualType visualType) {
|
||||
if (nothingToDo(visualType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
|
||||
var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
|
||||
|
||||
for (var multiDraw : multiDraws.get(stage)) {
|
||||
for (var multiDraw : multiDraws.get(visualType)) {
|
||||
glUniform1ui(flwBaseDraw, multiDraw.start);
|
||||
|
||||
MaterialRenderState.setup(multiDraw.material);
|
||||
|
@ -2,9 +2,9 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
||||
|
||||
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.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.MeshPool;
|
||||
|
||||
@ -12,7 +12,7 @@ public class IndirectDraw {
|
||||
private final IndirectInstancer<?> instancer;
|
||||
private final Material material;
|
||||
private final MeshPool.PooledMesh mesh;
|
||||
private final RenderStage stage;
|
||||
private final VisualType visualType;
|
||||
private final int indexOfMeshInModel;
|
||||
|
||||
private final int materialVertexIndex;
|
||||
@ -21,17 +21,17 @@ public class IndirectDraw {
|
||||
private final int packedMaterialProperties;
|
||||
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.material = material;
|
||||
this.mesh = mesh;
|
||||
this.stage = stage;
|
||||
this.visualType = visualType;
|
||||
this.indexOfMeshInModel = indexOfMeshInModel;
|
||||
|
||||
mesh.acquire();
|
||||
|
||||
this.materialVertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
|
||||
this.materialFragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
|
||||
this.materialVertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||
this.materialFragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||
this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
||||
this.packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||
}
|
||||
@ -48,8 +48,8 @@ public class IndirectDraw {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public RenderStage stage() {
|
||||
return stage;
|
||||
public VisualType visualType() {
|
||||
return visualType;
|
||||
}
|
||||
|
||||
public int indexOfMeshInModel() {
|
||||
@ -80,8 +80,8 @@ public class IndirectDraw {
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 20, instancer.modelIndex); // modelIndex
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 24, ShaderIndices.getVertexShaderIndex(materialOverride.shaders())); // materialVertexIndex
|
||||
MemoryUtil.memPutInt(ptr + 28, ShaderIndices.getFragmentShaderIndex(materialOverride.shaders())); // materialFragmentIndex
|
||||
MemoryUtil.memPutInt(ptr + 24, MaterialShaderIndices.vertexIndex(materialOverride.shaders())); // materialVertexIndex
|
||||
MemoryUtil.memPutInt(ptr + 28, MaterialShaderIndices.fragmentIndex(materialOverride.shaders())); // materialFragmentIndex
|
||||
MemoryUtil.memPutInt(ptr + 32, MaterialEncoder.packFogAndCutout(materialOverride)); // packedFogAndCutout
|
||||
MemoryUtil.memPutInt(ptr + 36, MaterialEncoder.packProperties(materialOverride)); // packedMaterialProperties
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.backend.Samplers;
|
||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||
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) {
|
||||
var groupKey = new GroupKey<>(key.type(), key.environment());
|
||||
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()) {
|
||||
if (group.hasStage(stage)) {
|
||||
if (group.hasVisualType(visualType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void renderStage(RenderStage stage) {
|
||||
if (!hasStage(stage)) {
|
||||
public void render(VisualType visualType) {
|
||||
if (!hasVisualType(visualType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
TextureBinder.bindLightAndOverlay();
|
||||
|
||||
vertexArray.bindForDraw();
|
||||
@ -88,7 +88,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||
Uniforms.bindAll();
|
||||
|
||||
for (var group : cullingGroups.values()) {
|
||||
group.submit(stage);
|
||||
group.submit(visualType);
|
||||
}
|
||||
|
||||
MaterialRenderState.reset();
|
||||
|
@ -25,7 +25,7 @@ public class ResizableStorageBuffer extends GlObject {
|
||||
}
|
||||
|
||||
public void ensureCapacity(long capacity) {
|
||||
FlwMemoryTracker._freeGPUMemory(this.capacity);
|
||||
FlwMemoryTracker._freeGpuMemory(this.capacity);
|
||||
|
||||
if (this.capacity > 0) {
|
||||
int oldHandle = handle();
|
||||
@ -42,7 +42,7 @@ public class ResizableStorageBuffer extends GlObject {
|
||||
glNamedBufferStorage(handle(), capacity, 0);
|
||||
}
|
||||
this.capacity = capacity;
|
||||
FlwMemoryTracker._allocGPUMemory(this.capacity);
|
||||
FlwMemoryTracker._allocGpuMemory(this.capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,6 +53,6 @@ public class ResizableStorageBuffer extends GlObject {
|
||||
@Override
|
||||
public void delete() {
|
||||
super.delete();
|
||||
FlwMemoryTracker._freeGPUMemory(capacity);
|
||||
FlwMemoryTracker._freeGpuMemory(capacity);
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class StagingBuffer {
|
||||
|
||||
totalAvailable = capacity;
|
||||
|
||||
FlwMemoryTracker._allocCPUMemory(capacity);
|
||||
FlwMemoryTracker._allocCpuMemory(capacity);
|
||||
|
||||
scatterProgram = programs.getScatterProgram();
|
||||
}
|
||||
@ -220,7 +220,7 @@ public class StagingBuffer {
|
||||
transfers.delete();
|
||||
scatterList.delete();
|
||||
|
||||
FlwMemoryTracker._freeCPUMemory(capacity);
|
||||
FlwMemoryTracker._freeCpuMemory(capacity);
|
||||
}
|
||||
|
||||
private MemoryBlock getScratch(long size) {
|
||||
|
@ -7,11 +7,11 @@ import java.util.Map;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
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.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.ShaderIndices;
|
||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||
import dev.engine_room.flywheel.backend.compile.InstancingPrograms;
|
||||
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<?>> {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* 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.
|
||||
instancedRenderStage.flush();
|
||||
stage.flush();
|
||||
}
|
||||
|
||||
meshPool.flush();
|
||||
@ -85,10 +85,10 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderStage(RenderStage stage) {
|
||||
var drawSet = stages.get(stage);
|
||||
public void render(VisualType visualType) {
|
||||
var stage = stages.get(visualType);
|
||||
|
||||
if (drawSet == null || drawSet.isEmpty()) {
|
||||
if (stage == null || stage.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
TextureBinder.bindLightAndOverlay();
|
||||
light.bind();
|
||||
|
||||
drawSet.draw(instanceTexture, programs);
|
||||
stage.draw(instanceTexture, programs);
|
||||
|
||||
MaterialRenderState.reset();
|
||||
TextureBinder.resetLightAndOverlay();
|
||||
@ -133,7 +133,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
protected <I extends Instance> void initialize(InstancerKey<I> key, InstancedInstancer<?> instancer) {
|
||||
instancer.init();
|
||||
|
||||
InstancedRenderStage instancedRenderStage = stages.computeIfAbsent(key.stage(), $ -> new InstancedRenderStage());
|
||||
InstancedRenderStage stage = stages.computeIfAbsent(key.visualType(), $ -> new InstancedRenderStage());
|
||||
|
||||
var meshes = key.model()
|
||||
.meshes();
|
||||
@ -144,7 +144,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
GroupKey<?> groupKey = new GroupKey<>(key.type(), key.environment());
|
||||
InstancedDraw instancedDraw = new InstancedDraw(instancer, mesh, groupKey, entry.material(), i);
|
||||
|
||||
instancedRenderStage.put(groupKey, instancedDraw);
|
||||
stage.put(groupKey, instancedDraw);
|
||||
instancer.addDrawCall(instancedDraw);
|
||||
}
|
||||
}
|
||||
@ -204,8 +204,8 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
|
||||
public static void uploadMaterialUniform(GlProgram program, Material material) {
|
||||
int uniformLocation = program.getUniformLocation("_flw_packedMaterial");
|
||||
int vertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
|
||||
int fragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
|
||||
int vertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||
int fragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||
int packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
|
||||
int packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||
GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties);
|
||||
|
@ -1,13 +1,14 @@
|
||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||
|
||||
import org.joml.Math;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector2f;
|
||||
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.backend.mixin.LevelRendererAccessor;
|
||||
import dev.engine_room.flywheel.lib.math.MatrixMath;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -63,7 +64,7 @@ public final class FrameUniforms extends UniformWriter {
|
||||
setPrev();
|
||||
|
||||
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
|
||||
.getRenderOrigin();
|
||||
.renderOrigin();
|
||||
var camera = context.camera();
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
var camX = (float) (cameraPos.x - renderOrigin.getX());
|
||||
@ -85,7 +86,7 @@ public final class FrameUniforms extends UniformWriter {
|
||||
}
|
||||
|
||||
if (firstWrite || !frustumPaused || frustumCapture) {
|
||||
MatrixMath.writePackedFrustumPlanes(ptr, VIEW_PROJECTION);
|
||||
writePackedFrustumPlanes(ptr, VIEW_PROJECTION);
|
||||
frustumCapture = false;
|
||||
}
|
||||
|
||||
@ -170,4 +171,118 @@ public final class FrameUniforms extends UniformWriter {
|
||||
Vec3 cameraPos = camera.getPosition();
|
||||
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;
|
||||
|
||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
||||
import dev.engine_room.flywheel.api.RenderContext;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -2,7 +2,7 @@ package dev.engine_room.flywheel.backend.engine.uniform;
|
||||
|
||||
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.mixin.AbstractClientPlayerAccessor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -1,6 +1,6 @@
|
||||
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;
|
||||
|
||||
public final class Uniforms {
|
||||
|
@ -27,10 +27,10 @@ public class GlBuffer extends GlObject {
|
||||
}
|
||||
|
||||
public void upload(long ptr, long size) {
|
||||
FlwMemoryTracker._freeGPUMemory(this.size);
|
||||
FlwMemoryTracker._freeGpuMemory(this.size);
|
||||
Buffer.IMPL.data(handle(), size, ptr, usage.glEnum);
|
||||
this.size = size;
|
||||
FlwMemoryTracker._allocGPUMemory(this.size);
|
||||
FlwMemoryTracker._allocGpuMemory(this.size);
|
||||
}
|
||||
|
||||
public void uploadSpan(long offset, MemoryBlock memoryBlock) {
|
||||
@ -47,6 +47,6 @@ public class GlBuffer extends GlObject {
|
||||
|
||||
protected void deleteInternal(int 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.BitSet;
|
@ -6,7 +6,6 @@
|
||||
"refmap": "backend-flywheel.refmap.json",
|
||||
"client": [
|
||||
"AbstractClientPlayerAccessor",
|
||||
"ClientChunkCacheMixin",
|
||||
"GlStateManagerMixin",
|
||||
"LevelRendererAccessor",
|
||||
"OptionsMixin",
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dev.engine_room.flywheel.lib.backend;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
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.world.level.LevelAccessor;
|
||||
|
||||
public class SimpleBackend implements Backend {
|
||||
public final class SimpleBackend implements Backend {
|
||||
private final Function<LevelAccessor, Engine> engineFactory;
|
||||
private final Supplier<Backend> fallback;
|
||||
private final BooleanSupplier isSupported;
|
||||
@ -45,9 +46,9 @@ public class SimpleBackend implements Backend {
|
||||
return isSupported.getAsBoolean();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public static final class Builder {
|
||||
private Function<LevelAccessor, Engine> engineFactory;
|
||||
private Supplier<Backend> fallback = BackendManager::getOffBackend;
|
||||
private Supplier<Backend> fallback = BackendManager::offBackend;
|
||||
private BooleanSupplier isSupported;
|
||||
|
||||
public Builder engineFactory(Function<LevelAccessor, Engine> engineFactory) {
|
||||
@ -66,6 +67,10 @@ public class SimpleBackend implements Backend {
|
||||
}
|
||||
|
||||
public Backend register(ResourceLocation id) {
|
||||
Objects.requireNonNull(engineFactory);
|
||||
Objects.requireNonNull(fallback);
|
||||
Objects.requireNonNull(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.InstanceType;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.util.FastColor;
|
||||
|
||||
public abstract class ColoredLitInstance extends AbstractInstance implements FlatLit {
|
||||
public byte r = (byte) 0xFF;
|
||||
public byte g = (byte) 0xFF;
|
||||
public byte b = (byte) 0xFF;
|
||||
public byte a = (byte) 0xFF;
|
||||
public byte red = (byte) 0xFF;
|
||||
public byte green = (byte) 0xFF;
|
||||
public byte blue = (byte) 0xFF;
|
||||
public byte alpha = (byte) 0xFF;
|
||||
|
||||
public int overlay = OverlayTexture.NO_OVERLAY;
|
||||
public int light = 0;
|
||||
@ -17,39 +18,34 @@ public abstract class ColoredLitInstance extends AbstractInstance implements Fla
|
||||
super(type, handle);
|
||||
}
|
||||
|
||||
public ColoredLitInstance color(int color) {
|
||||
return color(color, false);
|
||||
public ColoredLitInstance colorArgb(int argb) {
|
||||
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) {
|
||||
byte r = (byte) ((color >> 16) & 0xFF);
|
||||
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 colorRgb(int rgb) {
|
||||
return color(FastColor.ARGB32.red(rgb), FastColor.ARGB32.green(rgb), FastColor.ARGB32.blue(rgb));
|
||||
}
|
||||
|
||||
public ColoredLitInstance color(int r, int g, int b) {
|
||||
return color((byte) r, (byte) g, (byte) b);
|
||||
public ColoredLitInstance color(int red, int green, int blue, int alpha) {
|
||||
return color((byte) red, (byte) green, (byte) blue, (byte) alpha);
|
||||
}
|
||||
|
||||
public ColoredLitInstance color(byte r, byte g, byte b) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
public ColoredLitInstance color(int red, int green, int blue) {
|
||||
return color((byte) red, (byte) green, (byte) blue);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public ColoredLitInstance color(byte r, byte g, byte b, byte a) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
public ColoredLitInstance color(byte red, byte green, byte blue) {
|
||||
this.red = red;
|
||||
this.green = green;
|
||||
this.blue = blue;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -17,15 +17,15 @@ import net.minecraft.client.renderer.LightTexture;
|
||||
public interface FlatLit extends 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
|
||||
*/
|
||||
FlatLit light(int packedLight);
|
||||
|
||||
/**
|
||||
* Set the block and sky light values for this instance.
|
||||
* @param blockLight Block light value
|
||||
* @param skyLight Sky light value
|
||||
* @param blockLight the block light value
|
||||
* @param skyLight the sky light value
|
||||
* @return {@code this} for chaining
|
||||
*/
|
||||
default FlatLit light(int blockLight, int skyLight) {
|
||||
|
@ -20,10 +20,10 @@ public final class InstanceTypes {
|
||||
.matrix("normal", FloatRepr.FLOAT, 3)
|
||||
.build())
|
||||
.writer((ptr, instance) -> {
|
||||
MemoryUtil.memPutByte(ptr, instance.r);
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||
MemoryUtil.memPutByte(ptr, instance.red);
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.green);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.blue);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
|
||||
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
||||
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
||||
ExtraMemoryOps.putMatrix4f(ptr + 12, instance.model);
|
||||
@ -43,10 +43,10 @@ public final class InstanceTypes {
|
||||
.vector("rotation", FloatRepr.FLOAT, 4)
|
||||
.build())
|
||||
.writer((ptr, instance) -> {
|
||||
MemoryUtil.memPutByte(ptr, instance.r);
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.g);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.b);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.a);
|
||||
MemoryUtil.memPutByte(ptr, instance.red);
|
||||
MemoryUtil.memPutByte(ptr + 1, instance.green);
|
||||
MemoryUtil.memPutByte(ptr + 2, instance.blue);
|
||||
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
|
||||
ExtraMemoryOps.put2x16(ptr + 4, instance.overlay);
|
||||
ExtraMemoryOps.put2x16(ptr + 8, instance.light);
|
||||
MemoryUtil.memPutFloat(ptr + 12, instance.posX);
|
||||
|
@ -1,7 +1,8 @@
|
||||
package dev.engine_room.flywheel.lib.instance;
|
||||
|
||||
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.InstanceType;
|
||||
@ -22,72 +23,83 @@ public class OrientedInstance extends ColoredLitInstance implements Rotate<Orien
|
||||
super(type, handle);
|
||||
}
|
||||
|
||||
public OrientedInstance setPosition(float x, float y, float z) {
|
||||
public OrientedInstance position(float x, float y, float z) {
|
||||
posX = x;
|
||||
posY = y;
|
||||
posZ = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedInstance setPosition(Vector3f pos) {
|
||||
return setPosition(pos.x(), pos.y(), pos.z());
|
||||
public OrientedInstance position(Vector3fc pos) {
|
||||
return position(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedInstance setPosition(Vec3i pos) {
|
||||
return setPosition(pos.getX(), pos.getY(), pos.getZ());
|
||||
public OrientedInstance position(Vec3i pos) {
|
||||
return position(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public OrientedInstance setPosition(Vec3 pos) {
|
||||
return setPosition((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||
public OrientedInstance position(Vec3 pos) {
|
||||
return position((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||
}
|
||||
|
||||
public OrientedInstance resetPosition() {
|
||||
return setPosition(0, 0, 0);
|
||||
public OrientedInstance zeroPosition() {
|
||||
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;
|
||||
posY += y;
|
||||
posZ += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedInstance setPivot(float x, float y, float z) {
|
||||
public OrientedInstance pivot(float x, float y, float z) {
|
||||
pivotX = x;
|
||||
pivotY = y;
|
||||
pivotZ = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedInstance setPivot(Vector3f pos) {
|
||||
return setPivot(pos.x(), pos.y(), pos.z());
|
||||
public OrientedInstance pivot(Vector3fc pos) {
|
||||
return pivot(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public OrientedInstance setPivot(Vec3i pos) {
|
||||
return setPivot(pos.getX(), pos.getY(), pos.getZ());
|
||||
public OrientedInstance pivot(Vec3i pos) {
|
||||
return pivot(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public OrientedInstance setPivot(Vec3 pos) {
|
||||
return setPivot((float) pos.x(), (float) pos.y(), (float) pos.z());
|
||||
public OrientedInstance pivot(Vec3 pos) {
|
||||
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);
|
||||
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);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrientedInstance resetRotation() {
|
||||
public OrientedInstance identityRotation() {
|
||||
rotation.identity();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrientedInstance rotate(Quaternionf quaternion) {
|
||||
public OrientedInstance rotate(Quaternionfc quaternion) {
|
||||
rotation.mul(quaternion);
|
||||
return this;
|
||||
}
|
||||
|
@ -4,14 +4,13 @@ import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
|
||||
public class ShadowInstance extends AbstractInstance {
|
||||
|
||||
public float x, y, z;
|
||||
public float entityX, entityZ;
|
||||
public float sizeX, sizeZ;
|
||||
public float alpha;
|
||||
public float radius;
|
||||
|
||||
public ShadowInstance(InstanceType<?> type, InstanceHandle handle) {
|
||||
public ShadowInstance(InstanceType<? extends ShadowInstance> type, InstanceHandle 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 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 Layout layout;
|
||||
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);
|
||||
}
|
||||
|
||||
public static class Builder<I extends Instance> {
|
||||
public static final class Builder<I extends Instance> {
|
||||
private final Factory<I> factory;
|
||||
private Layout layout;
|
||||
private InstanceWriter<I> writer;
|
||||
|
@ -1,8 +1,10 @@
|
||||
package dev.engine_room.flywheel.lib.instance;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix3fc;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.joml.Quaternionfc;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
@ -12,7 +14,6 @@ import dev.engine_room.flywheel.lib.transform.Transform;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class TransformedInstance extends ColoredLitInstance implements Transform<TransformedInstance> {
|
||||
|
||||
public final Matrix4f model = new Matrix4f();
|
||||
public final Matrix3f normal = new Matrix3f();
|
||||
|
||||
@ -21,21 +22,34 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedInstance mulPose(Matrix4f pose) {
|
||||
public TransformedInstance mulPose(Matrix4fc pose) {
|
||||
this.model.mul(pose);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedInstance mulNormal(Matrix3f normal) {
|
||||
public TransformedInstance mulNormal(Matrix3fc normal) {
|
||||
this.normal.mul(normal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedInstance rotateAround(Quaternionf quaternion, float x, float y, float z) {
|
||||
this.model.rotateAround(quaternion, x, y, z);
|
||||
this.normal.rotate(quaternion);
|
||||
public TransformedInstance rotateAround(Quaternionfc quaternion, float x, float y, float z) {
|
||||
model.rotateAround(quaternion, x, y, z);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -59,16 +73,9 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedInstance rotate(Quaternionf quaternion) {
|
||||
model.rotate(quaternion);
|
||||
normal.rotate(quaternion);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformedInstance translate(double x, double y, double z) {
|
||||
model.translate((float) x, (float) y, (float) z);
|
||||
public TransformedInstance setTransform(PoseStack.Pose pose) {
|
||||
model.set(pose.pose());
|
||||
normal.set(pose.normal());
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -76,9 +83,9 @@ public class TransformedInstance extends ColoredLitInstance implements Transform
|
||||
return setTransform(stack.last());
|
||||
}
|
||||
|
||||
public TransformedInstance setTransform(PoseStack.Pose pose) {
|
||||
this.model.set(pose.pose());
|
||||
this.normal.set(pose.normal());
|
||||
public TransformedInstance setIdentityTransform() {
|
||||
model.identity();
|
||||
normal.identity();
|
||||
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".
|
||||
* </p>
|
||||
*/
|
||||
public TransformedInstance setEmptyTransform() {
|
||||
public TransformedInstance setZeroTransform() {
|
||||
model.zero();
|
||||
normal.zero();
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransformedInstance loadIdentity() {
|
||||
model.identity();
|
||||
normal.identity();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.engine_room.flywheel.lib.internal;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.DependencyInjection;
|
||||
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 net.minecraft.client.renderer.block.BlockRenderDispatcher;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public interface FlwLibXplat {
|
||||
FlwLibXplat INSTANCE = DependencyInjection.load(FlwLibXplat.class, "dev.engine_room.flywheel.impl.FlwLibXplatImpl");
|
||||
|
||||
@UnknownNullability
|
||||
BakedModel getBakedModel(ModelManager modelManager, ResourceLocation location);
|
||||
|
||||
BlockRenderDispatcher createVanillaBlockRenderDispatcher();
|
||||
|
||||
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.material.CutoutShader;
|
||||
|
||||
public class CutoutShaders {
|
||||
public final class CutoutShaders {
|
||||
/**
|
||||
* 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.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 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")));
|
||||
|
@ -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.Transparency;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class Materials {
|
||||
private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png");
|
||||
|
||||
public static final Material CHUNK_SOLID_SHADED = SimpleMaterial.builder()
|
||||
public static final Material SOLID_BLOCK = SimpleMaterial.builder()
|
||||
.build();
|
||||
public static final Material CHUNK_SOLID_UNSHADED = SimpleMaterial.builder()
|
||||
public static final Material SOLID_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder()
|
||||
public static final Material CUTOUT_MIPPED_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.HALF)
|
||||
.build();
|
||||
public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder()
|
||||
public static final Material CUTOUT_MIPPED_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.HALF)
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder()
|
||||
public static final Material CUTOUT_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.ONE_TENTH)
|
||||
.mipmap(false)
|
||||
.build();
|
||||
public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder()
|
||||
public static final Material CUTOUT_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.ONE_TENTH)
|
||||
.mipmap(false)
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
public static final Material CHUNK_TRANSLUCENT_SHADED = SimpleMaterial.builder()
|
||||
public static final Material TRANSLUCENT_BLOCK = SimpleMaterial.builder()
|
||||
.transparency(Transparency.TRANSLUCENT)
|
||||
.build();
|
||||
public static final Material CHUNK_TRANSLUCENT_UNSHADED = SimpleMaterial.builder()
|
||||
public static final Material TRANSLUCENT_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||
.transparency(Transparency.TRANSLUCENT)
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder()
|
||||
public static final Material TRIPWIRE_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.ONE_TENTH)
|
||||
.transparency(Transparency.TRANSLUCENT)
|
||||
.build();
|
||||
public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder()
|
||||
public static final Material TRIPWIRE_UNSHADED_BLOCK = SimpleMaterial.builder()
|
||||
.cutout(CutoutShaders.ONE_TENTH)
|
||||
.transparency(Transparency.TRANSLUCENT)
|
||||
.diffuse(false)
|
||||
.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() {
|
||||
}
|
||||
}
|
||||
|
@ -3,5 +3,5 @@ package dev.engine_room.flywheel.lib.material;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
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 org.joml.Math;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public final class MatrixMath {
|
||||
private MatrixMath() {
|
||||
@ -34,131 +32,4 @@ public final class MatrixMath {
|
||||
public static float transformNormalZ(Matrix3f matrix, float x, float y, float 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
void assertAllocated() {
|
||||
if (freed) {
|
||||
throw new IllegalStateException("Operation called on freed MemoryBlock!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long ptr() {
|
||||
assertAllocated();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
assertAllocated();
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -35,27 +43,32 @@ non-sealed abstract class AbstractMemoryBlockImpl implements MemoryBlock {
|
||||
|
||||
@Override
|
||||
public void copyTo(MemoryBlock block) {
|
||||
assertAllocated();
|
||||
long bytes = Math.min(size, block.size());
|
||||
copyTo(block.ptr(), bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(long ptr, long bytes) {
|
||||
assertAllocated();
|
||||
MemoryUtil.memCopy(this.ptr, ptr, bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyTo(long ptr) {
|
||||
assertAllocated();
|
||||
copyTo(ptr, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
assertAllocated();
|
||||
MemoryUtil.memSet(ptr, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer asBuffer() {
|
||||
assertAllocated();
|
||||
int intSize = (int) size;
|
||||
if (intSize != size) {
|
||||
throw new UnsupportedOperationException("Cannot create buffer with long capacity!");
|
||||
@ -64,12 +77,13 @@ non-sealed abstract class AbstractMemoryBlockImpl implements MemoryBlock {
|
||||
}
|
||||
|
||||
void freeInner() {
|
||||
FlwMemoryTracker._freeCPUMemory(size);
|
||||
FlwMemoryTracker._freeCpuMemory(size);
|
||||
freed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
assertAllocated();
|
||||
FlwMemoryTracker.free(ptr);
|
||||
freeInner();
|
||||
}
|
||||
|
@ -31,8 +31,9 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
|
||||
@Override
|
||||
public MemoryBlock realloc(long size) {
|
||||
assertAllocated();
|
||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner, 1);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
freeInner();
|
||||
return block;
|
||||
}
|
||||
@ -54,13 +55,13 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
|
||||
static MemoryBlock malloc(long size) {
|
||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER, 2);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
|
||||
static MemoryBlock calloc(long num, long size) {
|
||||
MemoryBlock block = new DebugMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER, 2);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ class DebugMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
FlwLibLink.INSTANCE.getLogger().warn(builder.toString());
|
||||
|
||||
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;
|
||||
|
||||
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 GPU_MEMORY = new AtomicLong(0);
|
||||
|
||||
@ -32,38 +30,38 @@ public final class FlwMemoryTracker {
|
||||
}
|
||||
|
||||
public static long realloc(long ptr, long size) {
|
||||
ptr = MemoryUtil.nmemRealloc(ptr, size);
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
long newPtr = MemoryUtil.nmemRealloc(ptr, size);
|
||||
if (newPtr == MemoryUtil.NULL) {
|
||||
throw new OutOfMemoryError("Failed to reallocate " + size + " bytes for address " + StringUtil.formatAddress(ptr));
|
||||
}
|
||||
return ptr;
|
||||
return newPtr;
|
||||
}
|
||||
|
||||
public static void free(long ptr) {
|
||||
MemoryUtil.nmemFree(ptr);
|
||||
}
|
||||
|
||||
public static void _allocCPUMemory(long size) {
|
||||
public static void _allocCpuMemory(long size) {
|
||||
CPU_MEMORY.getAndAdd(size);
|
||||
}
|
||||
|
||||
public static void _freeCPUMemory(long size) {
|
||||
public static void _freeCpuMemory(long size) {
|
||||
CPU_MEMORY.getAndAdd(-size);
|
||||
}
|
||||
|
||||
public static void _allocGPUMemory(long size) {
|
||||
public static void _allocGpuMemory(long size) {
|
||||
GPU_MEMORY.getAndAdd(size);
|
||||
}
|
||||
|
||||
public static void _freeGPUMemory(long size) {
|
||||
public static void _freeGpuMemory(long size) {
|
||||
GPU_MEMORY.getAndAdd(-size);
|
||||
}
|
||||
|
||||
public static long getCPUMemory() {
|
||||
public static long getCpuMemory() {
|
||||
return CPU_MEMORY.get();
|
||||
}
|
||||
|
||||
public static long getGPUMemory() {
|
||||
public static long getGpuMemory() {
|
||||
return GPU_MEMORY.get();
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public sealed interface MemoryBlock permits AbstractMemoryBlockImpl {
|
||||
void free();
|
||||
|
||||
static MemoryBlock malloc(long size) {
|
||||
if (FlwMemoryTracker.DEBUG_MEMORY_SAFETY) {
|
||||
if (MemoryBlockImpl.DEBUG_MEMORY_SAFETY) {
|
||||
return DebugMemoryBlockImpl.malloc(size);
|
||||
} else {
|
||||
return MemoryBlockImpl.malloc(size);
|
||||
@ -38,7 +38,7 @@ public sealed interface MemoryBlock permits AbstractMemoryBlockImpl {
|
||||
}
|
||||
|
||||
static MemoryBlock calloc(long num, long size) {
|
||||
if (FlwMemoryTracker.DEBUG_MEMORY_SAFETY) {
|
||||
if (MemoryBlockImpl.DEBUG_MEMORY_SAFETY) {
|
||||
return DebugMemoryBlockImpl.calloc(num, size);
|
||||
} else {
|
||||
return MemoryBlockImpl.calloc(num, size);
|
||||
|
@ -1,6 +1,8 @@
|
||||
package dev.engine_room.flywheel.lib.memory;
|
||||
|
||||
class MemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
static final boolean DEBUG_MEMORY_SAFETY = System.getProperty("flw.debugMemorySafety") != null;
|
||||
|
||||
MemoryBlockImpl(long ptr, long size) {
|
||||
super(ptr, size);
|
||||
}
|
||||
@ -12,21 +14,22 @@ class MemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
|
||||
@Override
|
||||
public MemoryBlock realloc(long size) {
|
||||
assertAllocated();
|
||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
freeInner();
|
||||
return block;
|
||||
}
|
||||
|
||||
static MemoryBlock malloc(long size) {
|
||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.malloc(size), size);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
|
||||
static MemoryBlock calloc(long num, long size) {
|
||||
MemoryBlock block = new MemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
@ -28,21 +28,22 @@ class TrackedMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
|
||||
@Override
|
||||
public MemoryBlock realloc(long size) {
|
||||
assertAllocated();
|
||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.realloc(ptr, size), size, cleaner);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
freeInner();
|
||||
return block;
|
||||
}
|
||||
|
||||
static MemoryBlock malloc(long size) {
|
||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.malloc(size), size, CLEANER);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
|
||||
static MemoryBlock calloc(long num, long size) {
|
||||
MemoryBlock block = new TrackedMemoryBlockImpl(FlwMemoryTracker.calloc(num, size), num * size, CLEANER);
|
||||
FlwMemoryTracker._allocCPUMemory(block.size());
|
||||
FlwMemoryTracker._allocCpuMemory(block.size());
|
||||
return block;
|
||||
}
|
||||
|
||||
@ -61,7 +62,7 @@ class TrackedMemoryBlockImpl extends AbstractMemoryBlockImpl {
|
||||
public void run() {
|
||||
if (!freed) {
|
||||
FlwMemoryTracker.free(ptr);
|
||||
FlwMemoryTracker._freeCPUMemory(size);
|
||||
FlwMemoryTracker._freeCpuMemory(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dev.engine_room.flywheel.lib.model;
|
||||
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
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.Model;
|
||||
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.StandardMaterialShaders;
|
||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||
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.texture.OverlayTexture;
|
||||
|
||||
public class LineModelBuilder {
|
||||
public static final Material MATERIAL = SimpleMaterial.builder()
|
||||
public final class LineModelBuilder {
|
||||
private static final Material MATERIAL = SimpleMaterial.builder()
|
||||
.shaders(StandardMaterialShaders.LINE)
|
||||
.backfaceCulling(false)
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
private final VertexView vertices;
|
||||
private MemoryBlock block;
|
||||
@UnknownNullability
|
||||
private VertexView vertexView;
|
||||
@UnknownNullability
|
||||
private MemoryBlock data;
|
||||
private int vertexCount = 0;
|
||||
|
||||
private LineModelBuilder(int segmentCount) {
|
||||
this.vertices = new FullVertexView();
|
||||
this.block = MemoryBlock.malloc(segmentCount * 4 * FullVertexView.STRIDE);
|
||||
vertices.ptr(block.ptr());
|
||||
}
|
||||
|
||||
public static LineModelBuilder withCapacity(int segmentCount) {
|
||||
return new LineModelBuilder(segmentCount);
|
||||
public LineModelBuilder(int segmentCount) {
|
||||
vertexView = new FullVertexView();
|
||||
data = MemoryBlock.mallocTracked(segmentCount * 4 * vertexView.stride());
|
||||
vertexView.ptr(data.ptr());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
vertices.x(vertexCount + i, x1);
|
||||
vertices.y(vertexCount + i, y1);
|
||||
vertices.z(vertexCount + i, z1);
|
||||
vertexView.x(vertexCount + i, x1);
|
||||
vertexView.y(vertexCount + i, y1);
|
||||
vertexView.z(vertexCount + i, z1);
|
||||
|
||||
vertices.x(vertexCount + 2 + i, x2);
|
||||
vertices.y(vertexCount + 2 + i, y2);
|
||||
vertices.z(vertexCount + 2 + i, z2);
|
||||
vertexView.x(vertexCount + 2 + i, x2);
|
||||
vertexView.y(vertexCount + 2 + i, y2);
|
||||
vertexView.z(vertexCount + 2 + i, z2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vertices.r(vertexCount + i, 1);
|
||||
vertices.g(vertexCount + i, 1);
|
||||
vertices.b(vertexCount + i, 1);
|
||||
vertices.a(vertexCount + i, 1);
|
||||
vertices.u(vertexCount + i, 0);
|
||||
vertices.v(vertexCount + i, 0);
|
||||
vertices.light(vertexCount + i, LightTexture.FULL_BRIGHT);
|
||||
vertices.normalX(vertexCount + i, normalX);
|
||||
vertices.normalY(vertexCount + i, normalY);
|
||||
vertices.normalZ(vertexCount + i, normalZ);
|
||||
vertexView.r(vertexCount + i, 1);
|
||||
vertexView.g(vertexCount + i, 1);
|
||||
vertexView.b(vertexCount + i, 1);
|
||||
vertexView.a(vertexCount + i, 1);
|
||||
vertexView.u(vertexCount + i, 0);
|
||||
vertexView.v(vertexCount + i, 0);
|
||||
vertexView.overlay(vertexCount + i, OverlayTexture.NO_OVERLAY);
|
||||
vertexView.light(vertexCount + i, LightTexture.FULL_BRIGHT);
|
||||
vertexView.normalX(vertexCount + i, normalX);
|
||||
vertexView.normalY(vertexCount + i, normalY);
|
||||
vertexView.normalZ(vertexCount + i, normalZ);
|
||||
}
|
||||
|
||||
vertexCount += 4;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
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
|
||||
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) {
|
||||
if (vertexCount * FullVertexView.STRIDE > block.size()) {
|
||||
this.block = block.realloc(vertexCount * FullVertexView.STRIDE);
|
||||
vertices.ptr(block.ptr());
|
||||
if (data == null) {
|
||||
vertexView = new FullVertexView();
|
||||
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 {
|
||||
public static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
|
||||
private static class LineMesh implements Mesh {
|
||||
private static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
|
||||
int numVertices = 2 * count / 3;
|
||||
int baseVertex = 0;
|
||||
while (baseVertex < numVertices) {
|
||||
@ -113,26 +122,22 @@ public class LineModelBuilder {
|
||||
ptr += 24;
|
||||
}
|
||||
};
|
||||
private final int vertexCount;
|
||||
private final VertexView vertexView;
|
||||
private final MemoryBlock data;
|
||||
private final VertexList vertexList;
|
||||
private final Vector4f boundingSphere;
|
||||
|
||||
public LineMesh(int vertexCount, VertexView vertexView, MemoryBlock data, Vector4f boundingSphere) {
|
||||
this.vertexCount = vertexCount;
|
||||
this.vertexView = vertexView;
|
||||
this.data = data;
|
||||
public LineMesh(VertexList vertexList, Vector4f boundingSphere) {
|
||||
this.vertexList = vertexList;
|
||||
this.boundingSphere = boundingSphere;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vertexCount() {
|
||||
return vertexCount;
|
||||
return vertexList.vertexCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(MutableVertexList vertexList) {
|
||||
vertexView.writeAll(vertexList);
|
||||
vertexList.writeAll(vertexList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -142,17 +147,12 @@ public class LineModelBuilder {
|
||||
|
||||
@Override
|
||||
public int indexCount() {
|
||||
return vertexCount / 2 * 3;
|
||||
return vertexCount() / 2 * 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector4fc boundingSphere() {
|
||||
return boundingSphere;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
data.free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
package dev.engine_room.flywheel.lib.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.lib.util.FlwUtil;
|
||||
|
||||
public class ModelCache<T> {
|
||||
private static final List<ModelCache<?>> ALL = new ArrayList<>();
|
||||
public final class ModelCache<T> {
|
||||
private static final Set<ModelCache<?>> ALL = FlwUtil.createWeakHashSet();
|
||||
private final Function<T, Model> factory;
|
||||
private final Map<T, Model> map = new ConcurrentHashMap<>();
|
||||
|
||||
@ -28,7 +28,6 @@ public class ModelCache<T> {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
map.values().forEach(Model::delete);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
package dev.engine_room.flywheel.lib.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.lib.util.FlwUtil;
|
||||
|
||||
public class ModelHolder {
|
||||
private static final List<ModelHolder> ALL = new ArrayList<>();
|
||||
public final class ModelHolder {
|
||||
private static final Set<ModelHolder> ALL = FlwUtil.createWeakHashSet();
|
||||
private final Supplier<Model> factory;
|
||||
@Nullable
|
||||
private volatile Model model;
|
||||
@ -45,7 +45,6 @@ public class ModelHolder {
|
||||
synchronized (this) {
|
||||
model = this.model;
|
||||
if (model != null) {
|
||||
model.delete();
|
||||
this.model = null;
|
||||
}
|
||||
}
|
||||
|
@ -31,19 +31,19 @@ public final class ModelUtil {
|
||||
@Nullable
|
||||
public static Material getMaterial(RenderType chunkRenderType, boolean shaded) {
|
||||
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()) {
|
||||
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()) {
|
||||
return shaded ? Materials.CHUNK_CUTOUT_SHADED : Materials.CHUNK_CUTOUT_UNSHADED;
|
||||
return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK;
|
||||
}
|
||||
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()) {
|
||||
return shaded ? Materials.CHUNK_TRIPWIRE_SHADED : Materials.CHUNK_TRIPWIRE_UNSHADED;
|
||||
return shaded ? Materials.TRIPWIRE_BLOCK : Materials.TRIPWIRE_UNSHADED_BLOCK;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
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();
|
||||
|
||||
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() {
|
||||
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() {
|
||||
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 dev.engine_room.flywheel.api.vertex.VertexView;
|
||||
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.VertexView;
|
||||
|
||||
final class 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();
|
||||
int vertexCount = drawState.vertexCount();
|
||||
long srcStride = drawState.format().getVertexSize();
|
||||
@ -25,7 +25,7 @@ final class MeshHelper {
|
||||
long dstStride = vertexView.stride();
|
||||
|
||||
ByteBuffer src = buffer.vertexBuffer();
|
||||
MemoryBlock dst = MemoryBlock.malloc((long) vertexCount * dstStride);
|
||||
MemoryBlock dst = MemoryBlock.mallocTracked((long) vertexCount * dstStride);
|
||||
long srcPtr = MemoryUtil.memAddress(src);
|
||||
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
|
||||
@ -42,6 +42,6 @@ final class MeshHelper {
|
||||
vertexView.ptr(dstPtr);
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
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.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.
|
||||
* <br>
|
||||
* 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>
|
||||
* Once Minecraft has finished baking all models, all PartialModels will have their bakedModel fields populated.
|
||||
*/
|
||||
public class PartialModel {
|
||||
static final List<PartialModel> ALL = new ArrayList<>();
|
||||
static boolean tooLate = false;
|
||||
public final class PartialModel {
|
||||
static final ConcurrentMap<ResourceLocation, PartialModel> ALL = new MapMaker().weakValues().makeMap();
|
||||
static boolean populateOnInit = false;
|
||||
|
||||
protected final ResourceLocation modelLocation;
|
||||
protected 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 final ResourceLocation modelLocation;
|
||||
@UnknownNullability
|
||||
BakedModel bakedModel;
|
||||
|
||||
private PartialModel(ResourceLocation modelLocation) {
|
||||
this.modelLocation = modelLocation;
|
||||
|
||||
synchronized (ALL) {
|
||||
ALL.add(this);
|
||||
if (populateOnInit) {
|
||||
bakedModel = FlwLibXplat.INSTANCE.getBakedModel(Minecraft.getInstance().getModelManager(), modelLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceLocation getLocation() {
|
||||
return modelLocation;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return getLocation()
|
||||
.toString();
|
||||
public static PartialModel of(ResourceLocation modelLocation) {
|
||||
return ALL.computeIfAbsent(modelLocation, PartialModel::new);
|
||||
}
|
||||
|
||||
@UnknownNullability
|
||||
public BakedModel get() {
|
||||
return bakedModel;
|
||||
}
|
||||
|
||||
protected void set(BakedModel bakedModel) {
|
||||
this.bakedModel = bakedModel;
|
||||
public ResourceLocation modelLocation() {
|
||||
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.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.VertexView;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.geom.EntityModelSet;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
@ -29,10 +30,14 @@ public final class ModelPartConverter {
|
||||
poseStack = objects.identityPoseStack;
|
||||
}
|
||||
VertexWriter vertexWriter = objects.vertexWriter;
|
||||
|
||||
vertexWriter.setTextureMapper(textureMapper);
|
||||
modelPart.render(poseStack, vertexWriter, LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY);
|
||||
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) {
|
||||
|
@ -6,7 +6,7 @@ import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
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.model.part.ModelPartConverter.TextureMapper;
|
||||
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) {
|
||||
if (!filledNormal) {
|
||||
long ptr = vertexPtr();
|
||||
MemoryUtil.memPutByte(ptr + 20, RenderMath.nb(x));
|
||||
MemoryUtil.memPutByte(ptr + 21, RenderMath.nb(y));
|
||||
MemoryUtil.memPutByte(ptr + 22, RenderMath.nb(z));
|
||||
MemoryUtil.memPutByte(ptr + 20, DataPacker.packNormI8(x));
|
||||
MemoryUtil.memPutByte(ptr + 21, DataPacker.packNormI8(y));
|
||||
MemoryUtil.memPutByte(ptr + 22, DataPacker.packNormI8(z));
|
||||
filledNormal = true;
|
||||
}
|
||||
return this;
|
||||
@ -124,7 +124,7 @@ class VertexWriter implements VertexConsumer {
|
||||
}
|
||||
|
||||
public MemoryBlock copyDataAndReset() {
|
||||
MemoryBlock dataCopy = MemoryBlock.malloc(vertexCount * STRIDE);
|
||||
MemoryBlock dataCopy = MemoryBlock.mallocTracked(vertexCount * STRIDE);
|
||||
data.copyTo(dataCopy);
|
||||
|
||||
vertexCount = 0;
|
||||
|
@ -4,7 +4,7 @@ import dev.engine_room.flywheel.api.task.Plan;
|
||||
import dev.engine_room.flywheel.api.task.TaskExecutor;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
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;
|
||||
|
||||
public final class Distribute {
|
||||
private Distribute() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
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>(
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package dev.engine_room.flywheel.lib.task;
|
||||
|
||||
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.lib.task.functional.ConsumerWithContext;
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package dev.engine_room.flywheel.lib.task;
|
||||
|
||||
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.lib.task.functional.ConsumerWithContext;
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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 Plan<C> onTrue = 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