mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-03 19:06:27 +01:00
TaskEngine and batching changes
- Rename TaskEngine to TaskExecutor - Make TaskExecutor extend Executor - Simplify ParallelTaskExecutor - Move WorkGroup code to separate class - Fix CPUInstancers being updated too late - Do not unnecessarily clear memory when preparing DrawBuffer - Simplify BatchingDrawTracker and DrawBufferSet by storing RenderType in DrawBuffer - Move all additional Mojang matrix operations to MatrixUtil and expose fields using accessors - Remove Color - Remove WeakHashSet
This commit is contained in:
parent
6add6c43b1
commit
95bd36b90d
42 changed files with 665 additions and 1166 deletions
|
@ -4,7 +4,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
import org.slf4j.Logger;
|
||||
|
||||
import com.jozufozu.flywheel.api.FlywheelLevel;
|
||||
import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.ParallelTaskExecutor;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.core.BackendTypes;
|
||||
import com.mojang.logging.LogUtils;
|
||||
|
@ -20,7 +20,7 @@ public class Backend {
|
|||
|
||||
private static BackendType TYPE;
|
||||
|
||||
private static ParallelTaskEngine EXECUTOR;
|
||||
private static ParallelTaskExecutor EXECUTOR;
|
||||
|
||||
private static final Loader LOADER = new Loader();
|
||||
|
||||
|
@ -35,9 +35,9 @@ public class Backend {
|
|||
* Get a thread pool for running Flywheel related work in parallel.
|
||||
* @return A global Flywheel thread pool.
|
||||
*/
|
||||
public static ParallelTaskEngine getTaskEngine() {
|
||||
public static ParallelTaskExecutor getTaskExecutor() {
|
||||
if (EXECUTOR == null) {
|
||||
EXECUTOR = new ParallelTaskEngine("Flywheel");
|
||||
EXECUTOR = new ParallelTaskExecutor("Flywheel");
|
||||
EXECUTOR.startWorkers();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ public abstract class InstanceManager<T> {
|
|||
* Queued updates are processed.
|
||||
* </p>
|
||||
*/
|
||||
public void tick(TaskEngine taskEngine, double cameraX, double cameraY, double cameraZ) {
|
||||
public void tick(TaskExecutor executor, double cameraX, double cameraY, double cameraZ) {
|
||||
tick.tick();
|
||||
processQueuedUpdates();
|
||||
|
||||
|
@ -84,7 +84,7 @@ public abstract class InstanceManager<T> {
|
|||
int cZ = (int) cameraZ;
|
||||
|
||||
var instances = getStorage().getInstancesForTicking();
|
||||
distributeWork(taskEngine, instances, instance -> tickInstance(instance, cX, cY, cZ));
|
||||
distributeWork(executor, instances, instance -> tickInstance(instance, cX, cY, cZ));
|
||||
}
|
||||
|
||||
protected void tickInstance(TickableInstance instance, int cX, int cY, int cZ) {
|
||||
|
@ -106,7 +106,7 @@ public abstract class InstanceManager<T> {
|
|||
instance.tick();
|
||||
}
|
||||
|
||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||
public void beginFrame(TaskExecutor executor, RenderContext context) {
|
||||
frame.tick();
|
||||
processQueuedAdditions();
|
||||
|
||||
|
@ -118,22 +118,22 @@ public abstract class InstanceManager<T> {
|
|||
FrustumIntersection culler = context.culler();
|
||||
|
||||
var instances = getStorage().getInstancesForUpdate();
|
||||
distributeWork(taskEngine, instances, instance -> updateInstance(instance, culler, cX, cY, cZ));
|
||||
distributeWork(executor, instances, instance -> updateInstance(instance, culler, cX, cY, cZ));
|
||||
}
|
||||
|
||||
private static <I> void distributeWork(TaskEngine taskEngine, List<I> instances, Consumer<I> action) {
|
||||
private static <I> void distributeWork(TaskExecutor executor, List<I> instances, Consumer<I> action) {
|
||||
final int size = instances.size();
|
||||
final int threadCount = taskEngine.getThreadCount();
|
||||
final int threadCount = executor.getThreadCount();
|
||||
|
||||
if (threadCount == 1) {
|
||||
taskEngine.submit(() -> instances.forEach(action));
|
||||
executor.execute(() -> instances.forEach(action));
|
||||
} else {
|
||||
final int stride = Math.max(size / (threadCount * 2), 1);
|
||||
for (int start = 0; start < size; start += stride) {
|
||||
int end = Math.min(start + stride, size);
|
||||
|
||||
var sub = instances.subList(start, end);
|
||||
taskEngine.submit(() -> sub.forEach(action));
|
||||
executor.execute(() -> sub.forEach(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class InstanceWorld implements AutoCloseable {
|
|||
protected final InstanceManager<Entity> entities;
|
||||
protected final InstanceManager<BlockEntity> blockEntities;
|
||||
|
||||
public final ParallelTaskEngine taskEngine;
|
||||
public final ParallelTaskExecutor taskExecutor;
|
||||
private final InstanceManager<Effect> effects;
|
||||
|
||||
public static InstanceWorld create(LevelAccessor level) {
|
||||
|
@ -51,7 +51,7 @@ public class InstanceWorld implements AutoCloseable {
|
|||
this.entities = entities;
|
||||
this.blockEntities = blockEntities;
|
||||
this.effects = effects;
|
||||
this.taskEngine = Backend.getTaskEngine();
|
||||
this.taskExecutor = Backend.getTaskExecutor();
|
||||
}
|
||||
|
||||
public InstanceManager<Entity> getEntities() {
|
||||
|
@ -87,15 +87,15 @@ public class InstanceWorld implements AutoCloseable {
|
|||
RenderContext context = event.getContext();
|
||||
boolean shifted = engine.maintainOriginCoordinate(context.camera());
|
||||
|
||||
taskEngine.syncPoint();
|
||||
taskExecutor.syncPoint();
|
||||
|
||||
if (!shifted) {
|
||||
blockEntities.beginFrame(taskEngine, context);
|
||||
entities.beginFrame(taskEngine, context);
|
||||
effects.beginFrame(taskEngine, context);
|
||||
blockEntities.beginFrame(taskExecutor, context);
|
||||
entities.beginFrame(taskExecutor, context);
|
||||
effects.beginFrame(taskExecutor, context);
|
||||
}
|
||||
|
||||
engine.beginFrame(taskEngine, context);
|
||||
engine.beginFrame(taskExecutor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,17 +117,17 @@ public class InstanceWorld implements AutoCloseable {
|
|||
double y = renderViewEntity.getY();
|
||||
double z = renderViewEntity.getZ();
|
||||
|
||||
blockEntities.tick(taskEngine, x, y, z);
|
||||
entities.tick(taskEngine, x, y, z);
|
||||
effects.tick(taskEngine, x, y, z);
|
||||
blockEntities.tick(taskExecutor, x, y, z);
|
||||
entities.tick(taskExecutor, x, y, z);
|
||||
effects.tick(taskExecutor, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw all instances for the given stage.
|
||||
*/
|
||||
public void renderStage(RenderContext context, RenderStage stage) {
|
||||
taskEngine.syncPoint();
|
||||
engine.renderStage(taskEngine, context, stage);
|
||||
taskExecutor.syncPoint();
|
||||
engine.renderStage(taskExecutor, context, stage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,283 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.instancing.batching.WaitGroup;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
// https://github.com/CaffeineMC/sodium-fabric/blob/5d364ed5ba63f9067fcf72a078ca310bff4db3e9/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java
|
||||
public class ParallelTaskEngine implements TaskEngine {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("BatchExecutor");
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* If set to false, the engine will shut down.
|
||||
*/
|
||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||
private final WaitGroup wg = new WaitGroup();
|
||||
|
||||
private final Deque<Runnable> syncTasks = new ConcurrentLinkedDeque<>();
|
||||
private final Deque<Runnable> jobQueue = new ConcurrentLinkedDeque<>();
|
||||
private final List<Thread> threads = new ArrayList<>();
|
||||
|
||||
private final Object jobNotifier = new Object();
|
||||
|
||||
private final int threadCount;
|
||||
|
||||
public ParallelTaskEngine(String name) {
|
||||
this.name = name;
|
||||
threadCount = getOptimalThreadCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThreadCount() {
|
||||
return threadCount;
|
||||
}
|
||||
|
||||
public WorkGroupBuilder group(String name) {
|
||||
return new WorkGroupBuilder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a number of work-stealing threads to process results in the build queue. If the builder is already
|
||||
* running, this method does nothing and exits.
|
||||
*/
|
||||
public void startWorkers() {
|
||||
if (this.running.getAndSet(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.threads.isEmpty()) {
|
||||
throw new IllegalStateException("Threads are still alive while in the STOPPED state");
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.threadCount; i++) {
|
||||
|
||||
Thread thread = new Thread(new WorkerRunnable(), name + " " + i);
|
||||
thread.setPriority(Math.max(0, Thread.NORM_PRIORITY - 2));
|
||||
thread.start();
|
||||
|
||||
this.threads.add(thread);
|
||||
}
|
||||
|
||||
LOGGER.info("Started {} worker threads", this.threads.size());
|
||||
}
|
||||
|
||||
public void stopWorkers() {
|
||||
if (!this.running.getAndSet(false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.threads.isEmpty()) {
|
||||
throw new IllegalStateException("No threads are alive but the executor is in the RUNNING state");
|
||||
}
|
||||
|
||||
synchronized (this.jobNotifier) {
|
||||
this.jobNotifier.notifyAll();
|
||||
}
|
||||
|
||||
try {
|
||||
for (Thread thread : this.threads) {
|
||||
thread.join();
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
this.threads.clear();
|
||||
|
||||
this.jobQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a task to the pool.
|
||||
*/
|
||||
@Override
|
||||
public void submit(@NotNull Runnable command) {
|
||||
this.jobQueue.add(command);
|
||||
this.wg.add(1);
|
||||
|
||||
synchronized (this.jobNotifier) {
|
||||
this.jobNotifier.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for all running jobs to finish.
|
||||
*/
|
||||
@Override
|
||||
public void syncPoint() {
|
||||
Runnable job;
|
||||
|
||||
// Finish everyone else's work...
|
||||
while ((job = this.jobQueue.pollLast()) != null) {
|
||||
processTask(job);
|
||||
}
|
||||
|
||||
// and wait for any stragglers.
|
||||
try {
|
||||
this.wg.await();
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
||||
while ((job = this.syncTasks.pollLast()) != null) {
|
||||
job.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Runnable getNextTask() {
|
||||
Runnable job = this.jobQueue.pollFirst();
|
||||
|
||||
if (job == null) {
|
||||
synchronized (ParallelTaskEngine.this.jobNotifier) {
|
||||
try {
|
||||
ParallelTaskEngine.this.jobNotifier.wait();
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
// TODO: job context
|
||||
private void processTask(Runnable job) {
|
||||
try {
|
||||
job.run();
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error running job", e);
|
||||
} finally {
|
||||
ParallelTaskEngine.this.wg.done();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "optimal" number of threads to be used for chunk build tasks. This will always return at least one
|
||||
* thread.
|
||||
*/
|
||||
private static int getOptimalThreadCount() {
|
||||
return Mth.clamp(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10);
|
||||
}
|
||||
|
||||
private static int getMaxThreadCount() {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
private class WorkerRunnable implements Runnable {
|
||||
|
||||
private final AtomicBoolean running = ParallelTaskEngine.this.running;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Run until the chunk builder shuts down
|
||||
while (this.running.get()) {
|
||||
Runnable job = ParallelTaskEngine.this.getNextTask();
|
||||
|
||||
if (job == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ParallelTaskEngine.this.processTask(job);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class WorkGroupBuilder {
|
||||
final String name;
|
||||
|
||||
@Nullable
|
||||
Runnable finalizer;
|
||||
|
||||
Stream<Runnable> tasks;
|
||||
|
||||
public WorkGroupBuilder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public <T> WorkGroupBuilder addTasks(Stream<T> iterable, Consumer<T> consumer) {
|
||||
return addTasks(iterable.map(it -> () -> consumer.accept(it)));
|
||||
}
|
||||
|
||||
public WorkGroupBuilder addTasks(Stream<Runnable> tasks) {
|
||||
if (this.tasks == null) {
|
||||
this.tasks = tasks;
|
||||
} else {
|
||||
this.tasks = Stream.concat(this.tasks, tasks);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public WorkGroupBuilder onComplete(Runnable runnable) {
|
||||
this.finalizer = runnable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void submit() {
|
||||
if (this.tasks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkGroup workGroup = new WorkGroup(name, finalizer);
|
||||
|
||||
tasks.map(task -> new WorkGroupTask(workGroup, task)).forEach(ParallelTaskEngine.this::submit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class WorkGroupTask implements Runnable {
|
||||
|
||||
private final WorkGroup parent;
|
||||
private final Runnable wrapped;
|
||||
|
||||
public WorkGroupTask(WorkGroup parent, Runnable wrapped) {
|
||||
this.parent = parent;
|
||||
this.wrapped = wrapped;
|
||||
|
||||
this.parent.running.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.wrapped.run();
|
||||
|
||||
this.parent.oneDown();
|
||||
}
|
||||
}
|
||||
|
||||
private class WorkGroup {
|
||||
final String name;
|
||||
|
||||
final Runnable finalizer;
|
||||
|
||||
final AtomicInteger running = new AtomicInteger(0);
|
||||
|
||||
public WorkGroup(String name, @Nullable Runnable finalizer) {
|
||||
this.name = name;
|
||||
this.finalizer = finalizer;
|
||||
}
|
||||
|
||||
public void oneDown() {
|
||||
if (finalizer != null) {
|
||||
if (running.decrementAndGet() == 0) {
|
||||
ParallelTaskEngine.this.syncTasks.add(finalizer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.mojang.logging.LogUtils;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
// https://github.com/CaffeineMC/sodium-fabric/blob/5d364ed5ba63f9067fcf72a078ca310bff4db3e9/src/main/java/me/jellysquid/mods/sodium/client/render/chunk/compile/ChunkBuilder.java
|
||||
// https://stackoverflow.com/questions/29655531
|
||||
public class ParallelTaskExecutor implements TaskExecutor {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private final String name;
|
||||
private final int threadCount;
|
||||
|
||||
/**
|
||||
* If set to false, the executor will shut down.
|
||||
*/
|
||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||
/**
|
||||
* Synchronized via {@link #tasksCompletedNotifier}.
|
||||
*/
|
||||
private int incompleteTaskCounter = 0;
|
||||
|
||||
private final List<WorkerThread> threads = new ArrayList<>();
|
||||
private final Deque<Runnable> taskQueue = new ConcurrentLinkedDeque<>();
|
||||
|
||||
private final Object taskNotifier = new Object();
|
||||
private final Object tasksCompletedNotifier = new Object();
|
||||
|
||||
public ParallelTaskExecutor(String name) {
|
||||
this.name = name;
|
||||
threadCount = getOptimalThreadCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThreadCount() {
|
||||
return threadCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawns a number of work-stealing threads to process results in the task queue. If the executor is already
|
||||
* running, this method does nothing and exits.
|
||||
*/
|
||||
public void startWorkers() {
|
||||
if (running.getAndSet(true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!threads.isEmpty()) {
|
||||
throw new IllegalStateException("Threads are still alive while in the STOPPED state");
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
WorkerThread thread = new WorkerThread(name + " Task Executor #" + i);
|
||||
thread.setPriority(Mth.clamp(Thread.NORM_PRIORITY - 2, Thread.MIN_PRIORITY, Thread.MAX_PRIORITY));
|
||||
thread.start();
|
||||
|
||||
threads.add(thread);
|
||||
}
|
||||
|
||||
LOGGER.info("Started {} worker threads", threads.size());
|
||||
}
|
||||
|
||||
public void stopWorkers() {
|
||||
if (!running.getAndSet(false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (threads.isEmpty()) {
|
||||
throw new IllegalStateException("No threads are alive but the executor is in the RUNNING state");
|
||||
}
|
||||
|
||||
LOGGER.info("Stopping worker threads");
|
||||
|
||||
// Notify all worker threads to wake up, where they will then terminate
|
||||
synchronized (taskNotifier) {
|
||||
taskNotifier.notifyAll();
|
||||
}
|
||||
|
||||
// Wait for every remaining thread to terminate
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
thread.join();
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
threads.clear();
|
||||
taskQueue.clear();
|
||||
synchronized (tasksCompletedNotifier) {
|
||||
incompleteTaskCounter = 0;
|
||||
tasksCompletedNotifier.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
if (!running.get()) {
|
||||
throw new IllegalStateException("Executor is stopped");
|
||||
}
|
||||
|
||||
taskQueue.add(task);
|
||||
|
||||
synchronized (tasksCompletedNotifier) {
|
||||
incompleteTaskCounter++;
|
||||
}
|
||||
|
||||
synchronized (taskNotifier) {
|
||||
taskNotifier.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for all running tasks to finish.
|
||||
*/
|
||||
@Override
|
||||
public void syncPoint() {
|
||||
Runnable task;
|
||||
|
||||
// Finish everyone else's work...
|
||||
while ((task = taskQueue.pollLast()) != null) {
|
||||
processTask(task);
|
||||
}
|
||||
|
||||
// and wait for any stragglers.
|
||||
synchronized (tasksCompletedNotifier) {
|
||||
while (incompleteTaskCounter > 0) {
|
||||
try {
|
||||
tasksCompletedNotifier.wait();
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Runnable getNextTask() {
|
||||
Runnable task = taskQueue.pollFirst();
|
||||
|
||||
if (task == null) {
|
||||
synchronized (taskNotifier) {
|
||||
try {
|
||||
taskNotifier.wait();
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
// TODO: task context
|
||||
private void processTask(Runnable task) {
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error running task", e);
|
||||
} finally {
|
||||
synchronized (tasksCompletedNotifier) {
|
||||
if (--incompleteTaskCounter == 0) {
|
||||
tasksCompletedNotifier.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "optimal" number of threads to be used for tasks. This will always return at least one thread.
|
||||
*/
|
||||
private static int getOptimalThreadCount() {
|
||||
return Mth.clamp(Math.max(getMaxThreadCount() / 3, getMaxThreadCount() - 6), 1, 10);
|
||||
}
|
||||
|
||||
private static int getMaxThreadCount() {
|
||||
return Runtime.getRuntime().availableProcessors();
|
||||
}
|
||||
|
||||
private class WorkerThread extends Thread {
|
||||
private final AtomicBoolean running = ParallelTaskExecutor.this.running;
|
||||
|
||||
public WorkerThread(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Run until the executor shuts down
|
||||
while (running.get()) {
|
||||
Runnable task = getNextTask();
|
||||
|
||||
if (task == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
processTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,9 @@ import net.minecraft.client.Camera;
|
|||
|
||||
public interface RenderDispatcher {
|
||||
|
||||
void beginFrame(TaskEngine taskEngine, RenderContext context);
|
||||
void beginFrame(TaskExecutor executor, RenderContext context);
|
||||
|
||||
void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage);
|
||||
void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage);
|
||||
|
||||
/**
|
||||
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions,
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SerialTaskEngine implements TaskEngine {
|
||||
|
||||
public static final SerialTaskEngine INSTANCE = new SerialTaskEngine();
|
||||
|
||||
private SerialTaskEngine() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(@NotNull Runnable command) {
|
||||
command.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncPoint() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThreadCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
public class SerialTaskExecutor implements TaskExecutor {
|
||||
public static final SerialTaskExecutor INSTANCE = new SerialTaskExecutor();
|
||||
|
||||
private SerialTaskExecutor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
task.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncPoint() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThreadCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface TaskEngine {
|
||||
void submit(@NotNull Runnable command);
|
||||
|
||||
/**
|
||||
* Wait for all running jobs to finish.
|
||||
*/
|
||||
void syncPoint();
|
||||
|
||||
int getThreadCount();
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public interface TaskExecutor extends Executor {
|
||||
/**
|
||||
* Wait for all running tasks to finish.
|
||||
*/
|
||||
void syncPoint();
|
||||
|
||||
int getThreadCount();
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class WorkGroup {
|
||||
public static void run(Iterator<Runnable> tasks, Executor executor) {
|
||||
tasks.forEachRemaining(executor::execute);
|
||||
}
|
||||
|
||||
public static void run(Iterator<Runnable> tasks, @Nullable Runnable finalizer, Executor executor) {
|
||||
if (finalizer == null) {
|
||||
run(tasks, executor);
|
||||
return;
|
||||
}
|
||||
|
||||
AtomicInteger incompleteTaskCounter = new AtomicInteger(0);
|
||||
tasks.forEachRemaining(task -> {
|
||||
incompleteTaskCounter.incrementAndGet();
|
||||
executor.execute(() -> {
|
||||
task.run();
|
||||
if (incompleteTaskCounter.decrementAndGet() == 0) {
|
||||
executor.execute(finalizer);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
@Nullable
|
||||
private Runnable finalizer;
|
||||
private Stream<Runnable> tasks;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public <T> Builder addTasks(Stream<T> iterable, Consumer<T> consumer) {
|
||||
return addTasks(iterable.map(it -> () -> consumer.accept(it)));
|
||||
}
|
||||
|
||||
public Builder addTasks(Stream<Runnable> tasks) {
|
||||
if (this.tasks == null) {
|
||||
this.tasks = tasks;
|
||||
} else {
|
||||
this.tasks = Stream.concat(this.tasks, tasks);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onComplete(Runnable runnable) {
|
||||
this.finalizer = runnable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void execute(Executor executor) {
|
||||
if (tasks == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
run(tasks.iterator(), finalizer, executor);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.jozufozu.flywheel.api.RenderStage;
|
||||
|
@ -12,7 +13,15 @@ import com.mojang.blaze3d.vertex.BufferBuilder;
|
|||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class BatchingDrawTracker {
|
||||
private final Set<RenderType> activeTypes = new HashSet<>();
|
||||
private static final RenderStage[] RENDER_STAGES = RenderStage.values();
|
||||
|
||||
private final Map<RenderStage, Set<DrawBuffer>> activeBuffers = new EnumMap<>(RenderStage.class);
|
||||
{
|
||||
for (RenderStage stage : RENDER_STAGES) {
|
||||
activeBuffers.put(stage, new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
private final BufferBuilder scratch;
|
||||
|
||||
public BatchingDrawTracker() {
|
||||
|
@ -22,22 +31,9 @@ public class BatchingDrawTracker {
|
|||
}
|
||||
|
||||
public DrawBuffer getBuffer(RenderType renderType, RenderStage stage) {
|
||||
return getBufferSet(renderType).getBuffer(stage);
|
||||
}
|
||||
|
||||
public DrawBufferSet getBufferSet(RenderType renderType) {
|
||||
activeTypes.add(renderType);
|
||||
return RenderTypeExtension.getDrawBufferSet(renderType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw and reset all DrawBuffers for the given RenderType.
|
||||
* @param renderType The RenderType to draw.
|
||||
*/
|
||||
public void draw(RenderType renderType) {
|
||||
_draw(renderType);
|
||||
|
||||
activeTypes.remove(renderType);
|
||||
DrawBuffer buffer = RenderTypeExtension.getDrawBufferSet(renderType).getBuffer(stage);
|
||||
activeBuffers.get(stage).add(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,59 +41,44 @@ public class BatchingDrawTracker {
|
|||
* @param stage The RenderStage to draw.
|
||||
*/
|
||||
public void draw(RenderStage stage) {
|
||||
Iterator<RenderType> iterator = activeTypes.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
RenderType renderType = iterator.next();
|
||||
DrawBufferSet bufferSet = RenderTypeExtension.getDrawBufferSet(renderType);
|
||||
DrawBuffer buffer = bufferSet.deactivateBuffer(stage);
|
||||
if (buffer == null) {
|
||||
continue;
|
||||
}
|
||||
if (bufferSet.getActiveStagesView().isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
_draw(buffer, renderType);
|
||||
Set<DrawBuffer> buffers = activeBuffers.get(stage);
|
||||
for (DrawBuffer buffer : buffers) {
|
||||
_draw(buffer);
|
||||
buffer.reset();
|
||||
}
|
||||
buffers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw and reset all active DrawBuffers.
|
||||
*/
|
||||
public void drawAll() {
|
||||
for (RenderType renderType : activeTypes) {
|
||||
_draw(renderType);
|
||||
}
|
||||
|
||||
activeTypes.clear();
|
||||
}
|
||||
|
||||
private void _draw(RenderType renderType) {
|
||||
DrawBufferSet bufferSet = RenderTypeExtension.getDrawBufferSet(renderType);
|
||||
for (RenderStage stage : bufferSet.getActiveStagesView()) {
|
||||
DrawBuffer buffer = bufferSet.deactivateBuffer(stage);
|
||||
_draw(buffer, renderType);
|
||||
for (Set<DrawBuffer> buffers : activeBuffers.values()) {
|
||||
for (DrawBuffer buffer : buffers) {
|
||||
_draw(buffer);
|
||||
buffer.reset();
|
||||
}
|
||||
buffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void _draw(DrawBuffer buffer, RenderType renderType) {
|
||||
private void _draw(DrawBuffer buffer) {
|
||||
if (buffer.hasVertices()) {
|
||||
BufferBuilderExtension scratch = (BufferBuilderExtension) this.scratch;
|
||||
buffer.inject(scratch);
|
||||
renderType.end(this.scratch, 0, 0, 0);
|
||||
buffer.getRenderType().end(this.scratch, 0, 0, 0);
|
||||
}
|
||||
|
||||
buffer.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all active DrawBuffers.
|
||||
*/
|
||||
public void reset() {
|
||||
for (RenderType type : activeTypes) {
|
||||
RenderTypeExtension.getDrawBufferSet(type)
|
||||
.reset();
|
||||
for (Set<DrawBuffer> buffers : activeBuffers.values()) {
|
||||
for (DrawBuffer buffer : buffers) {
|
||||
buffer.reset();
|
||||
}
|
||||
buffers.clear();
|
||||
}
|
||||
|
||||
activeTypes.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.jozufozu.flywheel.api.instancer.Instancer;
|
|||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskExecutor;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
@ -30,19 +30,19 @@ public class BatchingEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||
public void beginFrame(TaskExecutor executor, RenderContext context) {
|
||||
transformManager.flush();
|
||||
|
||||
Vec3 cameraPos = context.camera().getPosition();
|
||||
var stack = FlwUtil.copyPoseStack(context.stack());
|
||||
stack.translate(-cameraPos.x, -cameraPos.y, -cameraPos.z);
|
||||
|
||||
// TODO: async task engine barriers
|
||||
taskEngine.syncPoint();
|
||||
submitTasks(taskEngine, stack.last(), context.level());
|
||||
// TODO: async task executor barriers
|
||||
executor.syncPoint();
|
||||
submitTasks(executor, stack.last(), context.level());
|
||||
}
|
||||
|
||||
public void submitTasks(TaskEngine taskEngine, PoseStack.Pose matrices, ClientLevel level) {
|
||||
public void submitTasks(TaskExecutor executor, PoseStack.Pose matrices, ClientLevel level) {
|
||||
for (var transformSetEntry : transformManager.getTransformSetsView().entrySet()) {
|
||||
var stage = transformSetEntry.getKey();
|
||||
var transformSet = transformSetEntry.getValue();
|
||||
|
@ -53,6 +53,7 @@ public class BatchingEngine implements Engine {
|
|||
|
||||
int vertices = 0;
|
||||
for (var transformCall : transformCalls) {
|
||||
transformCall.setup();
|
||||
vertices += transformCall.getTotalVertexCount();
|
||||
}
|
||||
|
||||
|
@ -65,7 +66,7 @@ public class BatchingEngine implements Engine {
|
|||
|
||||
int startVertex = 0;
|
||||
for (var transformCall : transformCalls) {
|
||||
transformCall.submitTasks(taskEngine, buffer, startVertex, matrices, level);
|
||||
transformCall.submitTasks(executor, buffer, startVertex, matrices, level);
|
||||
startVertex += transformCall.getTotalVertexCount();
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ public class BatchingEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) {
|
||||
public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
|
||||
drawTracker.draw(stage);
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class BatchingTransformManager {
|
|||
public static class TransformSet implements Iterable<Map.Entry<RenderType, Collection<TransformCall<?>>>> {
|
||||
public static final TransformSet EMPTY = new TransformSet(ImmutableListMultimap.of());
|
||||
|
||||
final ListMultimap<RenderType, TransformCall<?>> transformCalls;
|
||||
private final ListMultimap<RenderType, TransformCall<?>> transformCalls;
|
||||
|
||||
public TransformSet(RenderStage renderStage) {
|
||||
transformCalls = ArrayListMultimap.create();
|
||||
|
|
|
@ -10,7 +10,7 @@ public class CPUInstancer<D extends InstancedPart> extends AbstractInstancer<D>
|
|||
super(type);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
void update() {
|
||||
if (anyToRemove) {
|
||||
data.removeIf(InstancedPart::isRemoved);
|
||||
anyToRemove = false;
|
||||
|
|
|
@ -11,6 +11,8 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
|||
import com.jozufozu.flywheel.extension.BufferBuilderExtension;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* A byte buffer that can be used to draw vertices through multiple {@link ReusableVertexList}s.
|
||||
*
|
||||
|
@ -19,6 +21,7 @@ import com.mojang.blaze3d.vertex.VertexFormat;
|
|||
public class DrawBuffer {
|
||||
private static final List<DrawBuffer> ALL = new ArrayList<>();
|
||||
|
||||
private final RenderType renderType;
|
||||
private final VertexFormat format;
|
||||
private final int stride;
|
||||
private final VertexListProvider provider;
|
||||
|
@ -29,7 +32,8 @@ public class DrawBuffer {
|
|||
private boolean prepared;
|
||||
private int vertexCount;
|
||||
|
||||
DrawBuffer(VertexFormat format, int stride, VertexListProvider provider) {
|
||||
DrawBuffer(RenderType renderType, VertexFormat format, int stride, VertexListProvider provider) {
|
||||
this.renderType = renderType;
|
||||
this.format = format;
|
||||
this.stride = stride;
|
||||
this.provider = provider;
|
||||
|
@ -62,7 +66,6 @@ public class DrawBuffer {
|
|||
buffer = memory.asBuffer();
|
||||
}
|
||||
|
||||
memory.clear();
|
||||
prepared = true;
|
||||
}
|
||||
|
||||
|
@ -90,6 +93,10 @@ public class DrawBuffer {
|
|||
bufferBuilder.flywheel$injectForRender(buffer, format, vertexCount);
|
||||
}
|
||||
|
||||
public RenderType getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public VertexFormat getVertexFormat() {
|
||||
return format;
|
||||
}
|
||||
|
|
|
@ -1,66 +1,33 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.RenderStage;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexListProvider;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class DrawBufferSet {
|
||||
private final RenderType renderType;
|
||||
private final VertexFormat format;
|
||||
private final int stride;
|
||||
private final VertexListProvider provider;
|
||||
|
||||
private final Map<RenderStage, DrawBuffer> buffers = new EnumMap<>(RenderStage.class);
|
||||
private final Set<RenderStage> activeStages = EnumSet.noneOf(RenderStage.class);
|
||||
private final Set<RenderStage> activeStagesView = Collections.unmodifiableSet(activeStages);
|
||||
|
||||
@ApiStatus.Internal
|
||||
public DrawBufferSet(VertexFormat format) {
|
||||
this.format = format;
|
||||
public DrawBufferSet(RenderType renderType) {
|
||||
this.renderType = renderType;
|
||||
format = renderType.format();
|
||||
stride = format.getVertexSize();
|
||||
provider = VertexListProvider.get(format);
|
||||
}
|
||||
|
||||
public Set<RenderStage> getActiveStagesView() {
|
||||
return activeStagesView;
|
||||
}
|
||||
|
||||
public DrawBuffer getBuffer(RenderStage stage) {
|
||||
activeStages.add(stage);
|
||||
return buffers.computeIfAbsent(stage, $ -> createBuffer());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DrawBuffer deactivateBuffer(RenderStage stage) {
|
||||
if (activeStages.remove(stage)) {
|
||||
return buffers.get(stage);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reset(RenderStage stage) {
|
||||
if (activeStages.remove(stage)) {
|
||||
buffers.get(stage).reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (RenderStage stage : activeStages) {
|
||||
buffers.get(stage).reset();
|
||||
}
|
||||
|
||||
activeStages.clear();
|
||||
}
|
||||
|
||||
private DrawBuffer createBuffer() {
|
||||
return new DrawBuffer(format, stride, provider);
|
||||
return buffers.computeIfAbsent(stage, $ -> new DrawBuffer(renderType, format, stride, provider));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import com.jozufozu.flywheel.api.material.Material;
|
|||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.ReusableVertexList;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskExecutor;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix3f;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -37,9 +37,11 @@ public class TransformCall<D extends InstancedPart> {
|
|||
return meshVertexCount * instancer.getInstanceCount();
|
||||
}
|
||||
|
||||
void submitTasks(TaskEngine pool, DrawBuffer buffer, int startVertex, PoseStack.Pose matrices, ClientLevel level) {
|
||||
instancer.setup();
|
||||
void setup() {
|
||||
instancer.update();
|
||||
}
|
||||
|
||||
void submitTasks(TaskExecutor executor, DrawBuffer buffer, int startVertex, PoseStack.Pose matrices, ClientLevel level) {
|
||||
int instances = instancer.getInstanceCount();
|
||||
|
||||
while (instances > 0) {
|
||||
|
@ -51,7 +53,7 @@ public class TransformCall<D extends InstancedPart> {
|
|||
ReusableVertexList sub = buffer.slice(startVertex, vertexCount);
|
||||
startVertex += vertexCount;
|
||||
|
||||
pool.submit(() -> transformRange(sub, start, end, matrices, level));
|
||||
executor.execute(() -> transformRange(sub, start, end, matrices, level));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,10 +84,10 @@ public class TransformCall<D extends InstancedPart> {
|
|||
vertexList.ptr(anchorPtr);
|
||||
vertexList.vertexCount(totalVertexCount);
|
||||
material.getVertexTransformer().transform(vertexList, level);
|
||||
applyPoseStack(vertexList, matrices);
|
||||
applyMatrices(vertexList, matrices);
|
||||
}
|
||||
|
||||
private static void applyPoseStack(MutableVertexList vertexList, PoseStack.Pose matrices) {
|
||||
private static void applyMatrices(MutableVertexList vertexList, PoseStack.Pose matrices) {
|
||||
Vector4f pos = new Vector4f();
|
||||
Vector3f normal = new Vector3f();
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
// https://stackoverflow.com/questions/29655531
|
||||
public class WaitGroup {
|
||||
|
||||
private final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
public synchronized void add(int i) {
|
||||
if (i == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == 1) {
|
||||
this.counter.incrementAndGet();
|
||||
} else {
|
||||
this.counter.addAndGet(i);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void done() {
|
||||
if (this.counter.decrementAndGet() == 0) {
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void await() throws InterruptedException {
|
||||
while (this.counter.get() > 0) {
|
||||
this.wait();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
|
@ -14,10 +15,10 @@ import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
|||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskExecutor;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
|
@ -34,7 +35,7 @@ public class IndirectEngine implements Engine {
|
|||
/**
|
||||
* The set of instance managers that are attached to this engine.
|
||||
*/
|
||||
private final WeakHashSet<InstanceManager<?>> instanceManagers = new WeakHashSet<>();
|
||||
private final Set<InstanceManager<?>> instanceManagers = FlwUtil.createWeakHashSet();
|
||||
|
||||
protected final ContextShader context;
|
||||
protected final int sqrMaxOriginDistance;
|
||||
|
@ -52,14 +53,14 @@ public class IndirectEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||
public void beginFrame(TaskExecutor executor, RenderContext context) {
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
drawManager.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) {
|
||||
public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
setup();
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class InstancingDrawManager {
|
|||
|
||||
public static final DrawSet EMPTY = new DrawSet(ImmutableListMultimap.of());
|
||||
|
||||
final ListMultimap<ShaderState, DrawCall> drawCalls;
|
||||
private final ListMultimap<ShaderState, DrawCall> drawCalls;
|
||||
|
||||
public DrawSet(RenderStage renderStage) {
|
||||
drawCalls = ArrayListMultimap.create();
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
|
@ -15,12 +16,12 @@ import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
|||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskExecutor;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
|
@ -37,7 +38,7 @@ public class InstancingEngine implements Engine {
|
|||
/**
|
||||
* The set of instance managers that are attached to this engine.
|
||||
*/
|
||||
private final WeakHashSet<InstanceManager<?>> instanceManagers = new WeakHashSet<>();
|
||||
private final Set<InstanceManager<?>> instanceManagers = FlwUtil.createWeakHashSet();
|
||||
|
||||
protected final ContextShader context;
|
||||
protected final int sqrMaxOriginDistance;
|
||||
|
@ -55,14 +56,14 @@ public class InstancingEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(TaskEngine taskEngine, RenderContext context) {
|
||||
public void beginFrame(TaskExecutor executor, RenderContext context) {
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
drawManager.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderStage(TaskEngine taskEngine, RenderContext context, RenderStage stage) {
|
||||
public void renderStage(TaskExecutor executor, RenderContext context, RenderStage stage) {
|
||||
var drawSet = drawManager.get(stage);
|
||||
|
||||
if (drawSet.isEmpty()) {
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.core;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.extension.Matrix4fExtension;
|
||||
import com.jozufozu.flywheel.util.MatrixUtil;
|
||||
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -23,7 +23,7 @@ public record RenderContext(LevelRenderer renderer, ClientLevel level, PoseStack
|
|||
}
|
||||
|
||||
public static FrustumIntersection createCuller(Matrix4f viewProjection, float camX, float camY, float camZ) {
|
||||
com.jozufozu.flywheel.util.joml.Matrix4f proj = Matrix4fExtension.clone(viewProjection);
|
||||
com.jozufozu.flywheel.util.joml.Matrix4f proj = MatrixUtil.toJoml(viewProjection);
|
||||
|
||||
proj.translate(camX, camY, camZ);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public interface Mesh {
|
|||
|
||||
/**
|
||||
* Write this mesh into a vertex list. Vertices with index {@literal <}0 or {@literal >=}{@link #getVertexCount()} will not be
|
||||
* modified.
|
||||
* read or modified.
|
||||
* @param vertexList The vertex list to which data is written to.
|
||||
*/
|
||||
void write(MutableVertexList vertexList);
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.jozufozu.flywheel.core.structs;
|
|||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.util.Color;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
||||
|
@ -39,15 +38,6 @@ public abstract class ColoredLitPart extends InstancedPart implements FlatLit<Co
|
|||
return LightTexture.pack(this.blockLight, this.skyLight);
|
||||
}
|
||||
|
||||
public ColoredLitPart setColor(Color color) {
|
||||
this.r = (byte) color.getRed();
|
||||
this.g = (byte) color.getGreen();
|
||||
this.b = (byte) color.getBlue();
|
||||
this.a = (byte) color.getAlpha();
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ColoredLitPart setColor(int color) {
|
||||
return setColor(color, false);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.structs.transformed;
|
||||
|
||||
import com.jozufozu.flywheel.core.structs.ColoredLitWriter;
|
||||
import com.jozufozu.flywheel.extension.MatrixWrite;
|
||||
import com.jozufozu.flywheel.util.MatrixUtil;
|
||||
|
||||
public class TransformedWriter extends ColoredLitWriter<TransformedPart> {
|
||||
public static final TransformedWriter INSTANCE = new TransformedWriter();
|
||||
|
@ -9,8 +9,8 @@ public class TransformedWriter extends ColoredLitWriter<TransformedPart> {
|
|||
@Override
|
||||
public void write(final long ptr, final TransformedPart d) {
|
||||
super.write(ptr, d);
|
||||
MatrixWrite.writeUnsafe(d.model, ptr + 8);
|
||||
MatrixWrite.writeUnsafe(d.normal, ptr + 72);
|
||||
MatrixUtil.writeUnsafe(d.model, ptr + 8);
|
||||
MatrixUtil.writeUnsafe(d.normal, ptr + 72);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import com.jozufozu.flywheel.core.Components;
|
|||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
import com.jozufozu.flywheel.extension.MatrixWrite;
|
||||
import com.jozufozu.flywheel.util.MatrixUtil;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
@ -52,7 +52,7 @@ public class ViewProvider extends UniformProvider {
|
|||
var vp = context.viewProjection().copy();
|
||||
vp.multiplyWithTranslation(-camX, -camY, -camZ);
|
||||
|
||||
MatrixWrite.writeUnsafe(vp, ptr);
|
||||
MatrixUtil.writeUnsafe(vp, ptr);
|
||||
MemoryUtil.memPutFloat(ptr + 64, camX);
|
||||
MemoryUtil.memPutFloat(ptr + 68, camY);
|
||||
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package com.jozufozu.flywheel.extension;
|
||||
|
||||
import com.jozufozu.flywheel.util.joml.Matrix3f;
|
||||
|
||||
public interface Matrix3fExtension {
|
||||
|
||||
Matrix3f flywheel$store(Matrix3f matrix);
|
||||
|
||||
static Matrix3f clone(com.mojang.math.Matrix3f moj) {
|
||||
return ((Matrix3fExtension)(Object) moj).flywheel$store(new Matrix3f());
|
||||
}
|
||||
|
||||
static void store(com.mojang.math.Matrix3f moj, Matrix3f joml) {
|
||||
((Matrix3fExtension)(Object) moj).flywheel$store(joml);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package com.jozufozu.flywheel.extension;
|
||||
|
||||
import com.jozufozu.flywheel.util.joml.Matrix4f;
|
||||
|
||||
public interface Matrix4fExtension {
|
||||
|
||||
Matrix4f flywheel$store(Matrix4f matrix);
|
||||
|
||||
static Matrix4f clone(com.mojang.math.Matrix4f moj) {
|
||||
return ((Matrix4fExtension)(Object) moj).flywheel$store(new Matrix4f());
|
||||
}
|
||||
|
||||
static void store(com.mojang.math.Matrix4f moj, Matrix4f joml) {
|
||||
((Matrix4fExtension)(Object) moj).flywheel$store(joml);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package com.jozufozu.flywheel.extension;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.mojang.math.Matrix3f;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
/**
|
||||
* @see com.jozufozu.flywheel.mixin.matrix.Matrix3fMixin
|
||||
* @see com.jozufozu.flywheel.mixin.matrix.Matrix4fMixin
|
||||
*/
|
||||
public interface MatrixWrite {
|
||||
|
||||
/**
|
||||
* Write the contents of this object into sequential memory starting at the given address.
|
||||
*/
|
||||
void flywheel$writeUnsafe(long ptr);
|
||||
|
||||
void flywheel$write(ByteBuffer buf);
|
||||
|
||||
static void write(Matrix4f matrix, ByteBuffer buf) {
|
||||
((MatrixWrite) (Object) matrix).flywheel$write(buf);
|
||||
}
|
||||
|
||||
static void writeUnsafe(Matrix4f matrix, long ptr) {
|
||||
((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr);
|
||||
}
|
||||
|
||||
static void writeUnsafe(Matrix3f matrix, long ptr) {
|
||||
((MatrixWrite) (Object) matrix).flywheel$writeUnsafe(ptr);
|
||||
}
|
||||
}
|
|
@ -6,8 +6,9 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.jozufozu.flywheel.backend.instancing.ParallelTaskExecutor;
|
||||
import com.jozufozu.flywheel.backend.instancing.WorkGroup;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
import com.jozufozu.flywheel.util.WorldAttached;
|
||||
import com.jozufozu.flywheel.util.box.GridAlignedBB;
|
||||
import com.jozufozu.flywheel.util.box.ImmutableBox;
|
||||
|
@ -27,7 +28,7 @@ import net.minecraft.world.level.LightLayer;
|
|||
public class LightUpdater {
|
||||
|
||||
private static final WorldAttached<LightUpdater> LEVELS = new WorldAttached<>(LightUpdater::new);
|
||||
private final ParallelTaskEngine taskEngine;
|
||||
private final ParallelTaskExecutor taskExecutor;
|
||||
|
||||
public static LightUpdater get(LevelAccessor level) {
|
||||
if (LightUpdated.receivesLightUpdates(level)) {
|
||||
|
@ -41,12 +42,12 @@ public class LightUpdater {
|
|||
|
||||
private final LevelAccessor level;
|
||||
|
||||
private final WeakHashSet<TickingLightListener> tickingLightListeners = new WeakHashSet<>();
|
||||
private final Set<TickingLightListener> tickingLightListeners = FlwUtil.createWeakHashSet();
|
||||
private final WeakContainmentMultiMap<LightListener> sections = new WeakContainmentMultiMap<>();
|
||||
private final WeakContainmentMultiMap<LightListener> chunks = new WeakContainmentMultiMap<>();
|
||||
|
||||
public LightUpdater(LevelAccessor level) {
|
||||
taskEngine = Backend.getTaskEngine();
|
||||
taskExecutor = Backend.getTaskExecutor();
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
|
@ -66,14 +67,14 @@ public class LightUpdater {
|
|||
private void tickParallel() {
|
||||
Queue<LightListener> listeners = new ConcurrentLinkedQueue<>();
|
||||
|
||||
taskEngine.group("LightUpdater")
|
||||
WorkGroup.builder()
|
||||
.addTasks(tickingLightListeners.stream(), listener -> {
|
||||
if (listener.tickLightListener()) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
})
|
||||
.onComplete(() -> listeners.forEach(this::addListener))
|
||||
.submit();
|
||||
.execute(taskExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.Set;
|
|||
import java.util.WeakHashMap;
|
||||
import java.util.function.LongConsumer;
|
||||
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
|
@ -15,7 +15,7 @@ import it.unimi.dsi.fastutil.longs.LongSet;
|
|||
|
||||
public class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
||||
|
||||
private final Long2ObjectMap<WeakHashSet<T>> forward;
|
||||
private final Long2ObjectMap<Set<T>> forward;
|
||||
private final WeakHashMap<T, LongSet> reverse;
|
||||
|
||||
public WeakContainmentMultiMap() {
|
||||
|
@ -38,7 +38,7 @@ public class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
|||
LongSet containmentSet = reverse.computeIfAbsent(listener, $ -> new LongRBTreeSet());
|
||||
|
||||
containmentSet.forEach((LongConsumer) l -> {
|
||||
WeakHashSet<T> listeners = forward.get(l);
|
||||
Set<T> listeners = forward.get(l);
|
||||
|
||||
if (listeners != null) listeners.remove(listener);
|
||||
});
|
||||
|
@ -53,7 +53,7 @@ public class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
|||
}
|
||||
|
||||
public void put(long sectionPos, T listener) {
|
||||
forward.computeIfAbsent(sectionPos, $ -> new WeakHashSet<>()).add(listener);
|
||||
forward.computeIfAbsent(sectionPos, $ -> FlwUtil.createWeakHashSet()).add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +62,7 @@ public class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
|||
|
||||
if (containmentSet != null) {
|
||||
containmentSet.forEach((LongConsumer) l -> {
|
||||
WeakHashSet<T> listeners = forward.get(l);
|
||||
Set<T> listeners = forward.get(l);
|
||||
|
||||
if (listeners != null) listeners.remove(o);
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ public class RenderTypeMixin implements RenderTypeExtension {
|
|||
@NotNull
|
||||
public DrawBufferSet flywheel$getDrawBufferSet() {
|
||||
if (flywheel$drawBufferSet == null) {
|
||||
flywheel$drawBufferSet = new DrawBufferSet(((RenderType) (Object) this).format());
|
||||
flywheel$drawBufferSet = new DrawBufferSet((RenderType) (Object) this);
|
||||
}
|
||||
return flywheel$drawBufferSet;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import com.mojang.math.Matrix3f;
|
||||
|
||||
@Mixin(Matrix3f.class)
|
||||
public interface Matrix3fAccessor {
|
||||
@Accessor("m00")
|
||||
float flywheel$m00();
|
||||
|
||||
@Accessor("m01")
|
||||
float flywheel$m01();
|
||||
|
||||
@Accessor("m02")
|
||||
float flywheel$m02();
|
||||
|
||||
@Accessor("m10")
|
||||
float flywheel$m10();
|
||||
|
||||
@Accessor("m11")
|
||||
float flywheel$m11();
|
||||
|
||||
@Accessor("m12")
|
||||
float flywheel$m12();
|
||||
|
||||
@Accessor("m20")
|
||||
float flywheel$m20();
|
||||
|
||||
@Accessor("m21")
|
||||
float flywheel$m21();
|
||||
|
||||
@Accessor("m22")
|
||||
float flywheel$m22();
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import com.jozufozu.flywheel.extension.Matrix3fExtension;
|
||||
import com.jozufozu.flywheel.extension.MatrixWrite;
|
||||
import com.mojang.math.Matrix3f;
|
||||
|
||||
@Mixin(Matrix3f.class)
|
||||
public abstract class Matrix3fMixin implements MatrixWrite, Matrix3fExtension {
|
||||
@Shadow protected float m00;
|
||||
@Shadow protected float m01;
|
||||
@Shadow protected float m02;
|
||||
@Shadow protected float m10;
|
||||
@Shadow protected float m11;
|
||||
@Shadow protected float m12;
|
||||
@Shadow protected float m20;
|
||||
@Shadow protected float m21;
|
||||
@Shadow protected float m22;
|
||||
|
||||
@Override
|
||||
public void flywheel$writeUnsafe(long ptr) {
|
||||
MemoryUtil.memPutFloat(ptr, m00);
|
||||
MemoryUtil.memPutFloat(ptr + 4, m10);
|
||||
MemoryUtil.memPutFloat(ptr + 8, m20);
|
||||
MemoryUtil.memPutFloat(ptr + 12, m01);
|
||||
MemoryUtil.memPutFloat(ptr + 16, m11);
|
||||
MemoryUtil.memPutFloat(ptr + 20, m21);
|
||||
MemoryUtil.memPutFloat(ptr + 24, m02);
|
||||
MemoryUtil.memPutFloat(ptr + 28, m12);
|
||||
MemoryUtil.memPutFloat(ptr + 32, m22);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flywheel$write(ByteBuffer buffer) {
|
||||
buffer.putFloat(m00);
|
||||
buffer.putFloat(m10);
|
||||
buffer.putFloat(m20);
|
||||
buffer.putFloat(m01);
|
||||
buffer.putFloat(m11);
|
||||
buffer.putFloat(m21);
|
||||
buffer.putFloat(m02);
|
||||
buffer.putFloat(m12);
|
||||
buffer.putFloat(m22);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.jozufozu.flywheel.util.joml.Matrix3f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix3f matrix) {
|
||||
return matrix.set(m00, m10, m20, m01, m11, m21, m02, m12, m22);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
@Mixin(Matrix4f.class)
|
||||
public interface Matrix4fAccessor {
|
||||
@Accessor("m00")
|
||||
float flywheel$m00();
|
||||
|
||||
@Accessor("m01")
|
||||
float flywheel$m01();
|
||||
|
||||
@Accessor("m02")
|
||||
float flywheel$m02();
|
||||
|
||||
@Accessor("m03")
|
||||
float flywheel$m03();
|
||||
|
||||
@Accessor("m10")
|
||||
float flywheel$m10();
|
||||
|
||||
@Accessor("m11")
|
||||
float flywheel$m11();
|
||||
|
||||
@Accessor("m12")
|
||||
float flywheel$m12();
|
||||
|
||||
@Accessor("m13")
|
||||
float flywheel$m13();
|
||||
|
||||
@Accessor("m20")
|
||||
float flywheel$m20();
|
||||
|
||||
@Accessor("m21")
|
||||
float flywheel$m21();
|
||||
|
||||
@Accessor("m22")
|
||||
float flywheel$m22();
|
||||
|
||||
@Accessor("m23")
|
||||
float flywheel$m23();
|
||||
|
||||
@Accessor("m30")
|
||||
float flywheel$m30();
|
||||
|
||||
@Accessor("m31")
|
||||
float flywheel$m31();
|
||||
|
||||
@Accessor("m32")
|
||||
float flywheel$m32();
|
||||
|
||||
@Accessor("m33")
|
||||
float flywheel$m33();
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import com.jozufozu.flywheel.extension.Matrix4fExtension;
|
||||
import com.jozufozu.flywheel.extension.MatrixWrite;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
@Mixin(Matrix4f.class)
|
||||
public abstract class Matrix4fMixin implements MatrixWrite, Matrix4fExtension {
|
||||
@Shadow protected float m00;
|
||||
@Shadow protected float m01;
|
||||
@Shadow protected float m02;
|
||||
@Shadow protected float m03;
|
||||
@Shadow protected float m10;
|
||||
@Shadow protected float m11;
|
||||
@Shadow protected float m12;
|
||||
@Shadow protected float m13;
|
||||
@Shadow protected float m20;
|
||||
@Shadow protected float m21;
|
||||
@Shadow protected float m22;
|
||||
@Shadow protected float m23;
|
||||
@Shadow protected float m30;
|
||||
@Shadow protected float m31;
|
||||
@Shadow protected float m32;
|
||||
@Shadow protected float m33;
|
||||
|
||||
@Override
|
||||
public void flywheel$writeUnsafe(long ptr) {
|
||||
MemoryUtil.memPutFloat(ptr, m00);
|
||||
MemoryUtil.memPutFloat(ptr + 4, m10);
|
||||
MemoryUtil.memPutFloat(ptr + 8, m20);
|
||||
MemoryUtil.memPutFloat(ptr + 12, m30);
|
||||
MemoryUtil.memPutFloat(ptr + 16, m01);
|
||||
MemoryUtil.memPutFloat(ptr + 20, m11);
|
||||
MemoryUtil.memPutFloat(ptr + 24, m21);
|
||||
MemoryUtil.memPutFloat(ptr + 28, m31);
|
||||
MemoryUtil.memPutFloat(ptr + 32, m02);
|
||||
MemoryUtil.memPutFloat(ptr + 36, m12);
|
||||
MemoryUtil.memPutFloat(ptr + 40, m22);
|
||||
MemoryUtil.memPutFloat(ptr + 44, m32);
|
||||
MemoryUtil.memPutFloat(ptr + 48, m03);
|
||||
MemoryUtil.memPutFloat(ptr + 52, m13);
|
||||
MemoryUtil.memPutFloat(ptr + 56, m23);
|
||||
MemoryUtil.memPutFloat(ptr + 60, m33);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flywheel$write(ByteBuffer buf) {
|
||||
buf.putFloat(m00);
|
||||
buf.putFloat(m10);
|
||||
buf.putFloat(m20);
|
||||
buf.putFloat(m30);
|
||||
buf.putFloat(m01);
|
||||
buf.putFloat(m11);
|
||||
buf.putFloat(m21);
|
||||
buf.putFloat(m31);
|
||||
buf.putFloat(m02);
|
||||
buf.putFloat(m12);
|
||||
buf.putFloat(m22);
|
||||
buf.putFloat(m32);
|
||||
buf.putFloat(m03);
|
||||
buf.putFloat(m13);
|
||||
buf.putFloat(m23);
|
||||
buf.putFloat(m33);
|
||||
}
|
||||
|
||||
@Override
|
||||
public com.jozufozu.flywheel.util.joml.Matrix4f flywheel$store(com.jozufozu.flywheel.util.joml.Matrix4f matrix) {
|
||||
return matrix.set(
|
||||
m00, m10, m20, m30,
|
||||
m01, m11, m21, m31,
|
||||
m02, m12, m22, m32,
|
||||
m03, m13, m23, m33);
|
||||
}
|
||||
}
|
|
@ -1,309 +0,0 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
@SuppressWarnings("PointlessBitwiseExpression")
|
||||
public class Color {
|
||||
public final static Color TRANSPARENT_BLACK = new Color(0, 0, 0, 0).setImmutable();
|
||||
public final static Color BLACK = new Color(0, 0, 0).setImmutable();
|
||||
public final static Color WHITE = new Color(255, 255, 255).setImmutable();
|
||||
public final static Color RED = new Color(255, 0, 0).setImmutable();
|
||||
public final static Color GREEN = new Color(0, 255, 0).setImmutable();
|
||||
public final static Color SPRING_GREEN = new Color(0, 255, 187).setImmutable();
|
||||
|
||||
protected boolean mutable = true;
|
||||
protected int value;
|
||||
|
||||
public Color(int r, int g, int b) {
|
||||
this(r, g, b, 0xff);
|
||||
}
|
||||
|
||||
public Color(int r, int g, int b, int a) {
|
||||
value = ((a & 0xff) << 24) |
|
||||
((r & 0xff) << 16) |
|
||||
((g & 0xff) << 8) |
|
||||
((b & 0xff) << 0);
|
||||
}
|
||||
|
||||
public Color(float r, float g, float b, float a) {
|
||||
this(
|
||||
(int) (0.5 + 0xff * Mth.clamp(r, 0, 1)),
|
||||
(int) (0.5 + 0xff * Mth.clamp(g, 0, 1)),
|
||||
(int) (0.5 + 0xff * Mth.clamp(b, 0, 1)),
|
||||
(int) (0.5 + 0xff * Mth.clamp(a, 0, 1))
|
||||
);
|
||||
}
|
||||
|
||||
public Color(int rgba) {
|
||||
value = rgba;
|
||||
}
|
||||
|
||||
public Color(int rgb, boolean hasAlpha) {
|
||||
if (hasAlpha) {
|
||||
value = rgb;
|
||||
} else {
|
||||
value = rgb | 0xff_000000;
|
||||
}
|
||||
}
|
||||
|
||||
public Color copy() {
|
||||
return copy(true);
|
||||
}
|
||||
|
||||
public Color copy(boolean mutable) {
|
||||
if (mutable)
|
||||
return new Color(value);
|
||||
else
|
||||
return new Color(value).setImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this color as immutable. Attempting to mutate this color in the future
|
||||
* will instead cause a copy to be created that can me modified.
|
||||
*/
|
||||
public Color setImmutable() {
|
||||
this.mutable = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the red component in the range 0-255.
|
||||
* @see #getRGB
|
||||
*/
|
||||
public int getRed() {
|
||||
return (getRGB() >> 16) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the green component in the range 0-255.
|
||||
* @see #getRGB
|
||||
*/
|
||||
public int getGreen() {
|
||||
return (getRGB() >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blue component in the range 0-255.
|
||||
* @see #getRGB
|
||||
*/
|
||||
public int getBlue() {
|
||||
return (getRGB() >> 0) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the alpha component in the range 0-255.
|
||||
* @see #getRGB
|
||||
*/
|
||||
public int getAlpha() {
|
||||
return (getRGB() >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the red component in the range 0-1f.
|
||||
*/
|
||||
public float getRedAsFloat() {
|
||||
return getRed() / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the green component in the range 0-1f.
|
||||
*/
|
||||
public float getGreenAsFloat() {
|
||||
return getGreen() / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blue component in the range 0-1f.
|
||||
*/
|
||||
public float getBlueAsFloat() {
|
||||
return getBlue() / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the alpha component in the range 0-1f.
|
||||
*/
|
||||
public float getAlphaAsFloat() {
|
||||
return getAlpha() / 255f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RGB value representing this color
|
||||
* (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are blue).
|
||||
* @return the RGB value of the color
|
||||
*/
|
||||
public int getRGB() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Vec3 asVector() {
|
||||
return new Vec3(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
|
||||
}
|
||||
|
||||
public Vector3f asVectorF() {
|
||||
return new Vector3f(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat());
|
||||
}
|
||||
|
||||
public Color setRed(int r) {
|
||||
return ensureMutable().setRedUnchecked(r);
|
||||
}
|
||||
|
||||
public Color setGreen(int g) {
|
||||
return ensureMutable().setGreenUnchecked(g);
|
||||
}
|
||||
|
||||
public Color setBlue(int b) {
|
||||
return ensureMutable().setBlueUnchecked(b);
|
||||
}
|
||||
|
||||
public Color setAlpha(int a) {
|
||||
return ensureMutable().setAlphaUnchecked(a);
|
||||
}
|
||||
|
||||
public Color setRed(float r) {
|
||||
return ensureMutable().setRedUnchecked((int) (0xff * Mth.clamp(r, 0, 1)));
|
||||
}
|
||||
|
||||
public Color setGreen(float g) {
|
||||
return ensureMutable().setGreenUnchecked((int) (0xff * Mth.clamp(g, 0, 1)));
|
||||
}
|
||||
|
||||
public Color setBlue(float b) {
|
||||
return ensureMutable().setBlueUnchecked((int) (0xff * Mth.clamp(b, 0, 1)));
|
||||
}
|
||||
|
||||
public Color setAlpha(float a) {
|
||||
return ensureMutable().setAlphaUnchecked((int) (0xff * Mth.clamp(a, 0, 1)));
|
||||
}
|
||||
|
||||
public Color scaleAlpha(float factor) {
|
||||
return ensureMutable().setAlphaUnchecked((int) (getAlpha() * Mth.clamp(factor, 0, 1)));
|
||||
}
|
||||
|
||||
public Color mixWith(Color other, float weight) {
|
||||
return ensureMutable()
|
||||
.setRedUnchecked((int) (getRed() + (other.getRed() - getRed()) * weight))
|
||||
.setGreenUnchecked((int) (getGreen() + (other.getGreen() - getGreen()) * weight))
|
||||
.setBlueUnchecked((int) (getBlue() + (other.getBlue() - getBlue()) * weight))
|
||||
.setAlphaUnchecked((int) (getAlpha() + (other.getAlpha() - getAlpha()) * weight));
|
||||
}
|
||||
|
||||
public Color darker() {
|
||||
int a = getAlpha();
|
||||
return ensureMutable().mixWith(BLACK, .25f).setAlphaUnchecked(a);
|
||||
}
|
||||
|
||||
public Color brighter() {
|
||||
int a = getAlpha();
|
||||
return ensureMutable().mixWith(WHITE, .25f).setAlphaUnchecked(a);
|
||||
}
|
||||
|
||||
public Color setValue(int value) {
|
||||
return ensureMutable().setValueUnchecked(value);
|
||||
}
|
||||
|
||||
public Color modifyValue(UnaryOperator<Integer> function) {
|
||||
int newValue = function.apply(value);
|
||||
if (newValue == value)
|
||||
return this;
|
||||
|
||||
return ensureMutable().setValueUnchecked(newValue);
|
||||
}
|
||||
|
||||
// ********* //
|
||||
|
||||
protected Color ensureMutable() {
|
||||
if (this.mutable)
|
||||
return this;
|
||||
|
||||
return new Color(this.value);
|
||||
}
|
||||
|
||||
protected Color setRedUnchecked(int r) {
|
||||
this.value = (this.value & 0xff_00ffff) | ((r & 0xff) << 16);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Color setGreenUnchecked(int g) {
|
||||
this.value = (this.value & 0xff_ff00ff) | ((g & 0xff) << 8);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Color setBlueUnchecked(int b) {
|
||||
this.value = (this.value & 0xff_ffff00) | ((b & 0xff) << 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Color setAlphaUnchecked(int a) {
|
||||
this.value = (this.value & 0x00_ffffff) | ((a & 0xff) << 24);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected Color setValueUnchecked(int value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
// ********* //
|
||||
|
||||
public static Color mixColors(@NotNull Color c1, @NotNull Color c2, float w) {
|
||||
return new Color(
|
||||
(int) (c1.getRed() + (c2.getRed() - c1.getRed()) * w),
|
||||
(int) (c1.getGreen() + (c2.getGreen() - c1.getGreen()) * w),
|
||||
(int) (c1.getBlue() + (c2.getBlue() - c1.getBlue()) * w),
|
||||
(int) (c1.getAlpha() + (c2.getAlpha() - c1.getAlpha()) * w)
|
||||
);
|
||||
}
|
||||
|
||||
public static int mixColors(int color1, int color2, float w) {
|
||||
int a1 = (color1 >> 24);
|
||||
int r1 = (color1 >> 16) & 0xFF;
|
||||
int g1 = (color1 >> 8) & 0xFF;
|
||||
int b1 = color1 & 0xFF;
|
||||
int a2 = (color2 >> 24);
|
||||
int r2 = (color2 >> 16) & 0xFF;
|
||||
int g2 = (color2 >> 8) & 0xFF;
|
||||
int b2 = color2 & 0xFF;
|
||||
|
||||
return
|
||||
((int) (a1 + (a2 - a1) * w) << 24) +
|
||||
((int) (r1 + (r2 - r1) * w) << 16) +
|
||||
((int) (g1 + (g2 - g1) * w) << 8) +
|
||||
((int) (b1 + (b2 - b1) * w) << 0);
|
||||
}
|
||||
|
||||
public static Color rainbowColor(int timeStep) {
|
||||
int localTimeStep = Math.abs(timeStep) % 1536;
|
||||
int timeStepInPhase = localTimeStep % 256;
|
||||
int phaseBlue = localTimeStep / 256;
|
||||
int red = colorInPhase(phaseBlue + 4, timeStepInPhase);
|
||||
int green = colorInPhase(phaseBlue + 2, timeStepInPhase);
|
||||
int blue = colorInPhase(phaseBlue, timeStepInPhase);
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
private static int colorInPhase(int phase, int progress) {
|
||||
phase = phase % 6;
|
||||
if (phase <= 1)
|
||||
return 0;
|
||||
if (phase == 2)
|
||||
return progress;
|
||||
if (phase <= 4)
|
||||
return 255;
|
||||
else
|
||||
return 255 - progress;
|
||||
}
|
||||
|
||||
public static Color generateFromLong(long l) {
|
||||
return rainbowColor(Hashing.crc32().hashLong(l).asInt())
|
||||
.mixWith(WHITE, 0.5f);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.mixin.BlockEntityRenderDispatcherAccessor;
|
||||
|
@ -81,4 +84,8 @@ public class FlwUtil {
|
|||
public static <R> Stream<R> mapValues(Map<?, R> map) {
|
||||
return map.values().stream();
|
||||
}
|
||||
|
||||
public static <T> Set<T> createWeakHashSet() {
|
||||
return Collections.newSetFromMap(new WeakHashMap<>());
|
||||
}
|
||||
}
|
||||
|
|
116
src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java
Normal file
116
src/main/java/com/jozufozu/flywheel/util/MatrixUtil.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.mixin.matrix.Matrix3fAccessor;
|
||||
import com.jozufozu.flywheel.mixin.matrix.Matrix4fAccessor;
|
||||
import com.mojang.math.Matrix3f;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
public class MatrixUtil {
|
||||
public static void write(Matrix4f matrix, ByteBuffer buf) {
|
||||
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
|
||||
buf.putFloat(m.flywheel$m00());
|
||||
buf.putFloat(m.flywheel$m10());
|
||||
buf.putFloat(m.flywheel$m20());
|
||||
buf.putFloat(m.flywheel$m30());
|
||||
buf.putFloat(m.flywheel$m01());
|
||||
buf.putFloat(m.flywheel$m11());
|
||||
buf.putFloat(m.flywheel$m21());
|
||||
buf.putFloat(m.flywheel$m31());
|
||||
buf.putFloat(m.flywheel$m02());
|
||||
buf.putFloat(m.flywheel$m12());
|
||||
buf.putFloat(m.flywheel$m22());
|
||||
buf.putFloat(m.flywheel$m32());
|
||||
buf.putFloat(m.flywheel$m03());
|
||||
buf.putFloat(m.flywheel$m13());
|
||||
buf.putFloat(m.flywheel$m23());
|
||||
buf.putFloat(m.flywheel$m33());
|
||||
}
|
||||
|
||||
public static void writeUnsafe(Matrix4f matrix, long ptr) {
|
||||
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
|
||||
MemoryUtil.memPutFloat(ptr, m.flywheel$m00());
|
||||
MemoryUtil.memPutFloat(ptr + 4, m.flywheel$m10());
|
||||
MemoryUtil.memPutFloat(ptr + 8, m.flywheel$m20());
|
||||
MemoryUtil.memPutFloat(ptr + 12, m.flywheel$m30());
|
||||
MemoryUtil.memPutFloat(ptr + 16, m.flywheel$m01());
|
||||
MemoryUtil.memPutFloat(ptr + 20, m.flywheel$m11());
|
||||
MemoryUtil.memPutFloat(ptr + 24, m.flywheel$m21());
|
||||
MemoryUtil.memPutFloat(ptr + 28, m.flywheel$m31());
|
||||
MemoryUtil.memPutFloat(ptr + 32, m.flywheel$m02());
|
||||
MemoryUtil.memPutFloat(ptr + 36, m.flywheel$m12());
|
||||
MemoryUtil.memPutFloat(ptr + 40, m.flywheel$m22());
|
||||
MemoryUtil.memPutFloat(ptr + 44, m.flywheel$m32());
|
||||
MemoryUtil.memPutFloat(ptr + 48, m.flywheel$m03());
|
||||
MemoryUtil.memPutFloat(ptr + 52, m.flywheel$m13());
|
||||
MemoryUtil.memPutFloat(ptr + 56, m.flywheel$m23());
|
||||
MemoryUtil.memPutFloat(ptr + 60, m.flywheel$m33());
|
||||
}
|
||||
|
||||
public static void write(Matrix3f matrix, ByteBuffer buf) {
|
||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||
buf.putFloat(m.flywheel$m00());
|
||||
buf.putFloat(m.flywheel$m10());
|
||||
buf.putFloat(m.flywheel$m20());
|
||||
buf.putFloat(m.flywheel$m01());
|
||||
buf.putFloat(m.flywheel$m11());
|
||||
buf.putFloat(m.flywheel$m21());
|
||||
buf.putFloat(m.flywheel$m02());
|
||||
buf.putFloat(m.flywheel$m12());
|
||||
buf.putFloat(m.flywheel$m22());
|
||||
}
|
||||
|
||||
public static void store(Matrix4f matrix, com.jozufozu.flywheel.util.joml.Matrix4f jomlMatrix) {
|
||||
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
|
||||
jomlMatrix.set(
|
||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(),
|
||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m31(),
|
||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22(), m.flywheel$m32(),
|
||||
m.flywheel$m03(), m.flywheel$m13(), m.flywheel$m23(), m.flywheel$m33()
|
||||
);
|
||||
}
|
||||
|
||||
public static com.jozufozu.flywheel.util.joml.Matrix4f toJoml(Matrix4f matrix) {
|
||||
Matrix4fAccessor m = (Matrix4fAccessor) (Object) matrix;
|
||||
return new com.jozufozu.flywheel.util.joml.Matrix4f(
|
||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(), m.flywheel$m30(),
|
||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(), m.flywheel$m31(),
|
||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22(), m.flywheel$m32(),
|
||||
m.flywheel$m03(), m.flywheel$m13(), m.flywheel$m23(), m.flywheel$m33()
|
||||
);
|
||||
}
|
||||
|
||||
public static void writeUnsafe(Matrix3f matrix, long ptr) {
|
||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||
MemoryUtil.memPutFloat(ptr, m.flywheel$m00());
|
||||
MemoryUtil.memPutFloat(ptr + 4, m.flywheel$m10());
|
||||
MemoryUtil.memPutFloat(ptr + 8, m.flywheel$m20());
|
||||
MemoryUtil.memPutFloat(ptr + 12, m.flywheel$m01());
|
||||
MemoryUtil.memPutFloat(ptr + 16, m.flywheel$m11());
|
||||
MemoryUtil.memPutFloat(ptr + 20, m.flywheel$m21());
|
||||
MemoryUtil.memPutFloat(ptr + 24, m.flywheel$m02());
|
||||
MemoryUtil.memPutFloat(ptr + 28, m.flywheel$m12());
|
||||
MemoryUtil.memPutFloat(ptr + 32, m.flywheel$m22());
|
||||
}
|
||||
|
||||
public static void store(Matrix3f matrix, com.jozufozu.flywheel.util.joml.Matrix3f jomlMatrix) {
|
||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||
jomlMatrix.set(
|
||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
|
||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(),
|
||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22()
|
||||
);
|
||||
}
|
||||
|
||||
public static com.jozufozu.flywheel.util.joml.Matrix3f toJoml(Matrix3f matrix) {
|
||||
Matrix3fAccessor m = (Matrix3fAccessor) (Object) matrix;
|
||||
return new com.jozufozu.flywheel.util.joml.Matrix3f(
|
||||
m.flywheel$m00(), m.flywheel$m10(), m.flywheel$m20(),
|
||||
m.flywheel$m01(), m.flywheel$m11(), m.flywheel$m21(),
|
||||
m.flywheel$m02(), m.flywheel$m12(), m.flywheel$m22()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.minecraft.util.Unit;
|
||||
|
||||
public class WeakHashSet<T> extends AbstractSet<T> {
|
||||
|
||||
WeakHashMap<T, Unit> map;
|
||||
|
||||
public WeakHashSet() {
|
||||
map = new WeakHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new set containing the elements in the specified
|
||||
* collection. The <tt>HashMap</tt> is created with default load factor
|
||||
* (0.75) and an initial capacity sufficient to contain the elements in
|
||||
* the specified collection.
|
||||
*
|
||||
* @param c the collection whose elements are to be placed into this set
|
||||
* @throws NullPointerException if the specified collection is null
|
||||
*/
|
||||
public WeakHashSet(Collection<? extends T> c) {
|
||||
map = new WeakHashMap<>(Math.max((int) (c.size() / .75f) + 1, 16));
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
|
||||
* the specified initial capacity and the specified load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the hash map
|
||||
* @param loadFactor the load factor of the hash map
|
||||
* @throws IllegalArgumentException if the initial capacity is less
|
||||
* than zero, or if the load factor is nonpositive
|
||||
*/
|
||||
public WeakHashSet(int initialCapacity, float loadFactor) {
|
||||
map = new WeakHashMap<>(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
|
||||
* the specified initial capacity and default load factor (0.75).
|
||||
*
|
||||
* @param initialCapacity the initial capacity of the hash table
|
||||
* @throws IllegalArgumentException if the initial capacity is less
|
||||
* than zero
|
||||
*/
|
||||
public WeakHashSet(int initialCapacity) {
|
||||
map = new WeakHashMap<>(initialCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return map.keySet()
|
||||
.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(T t) {
|
||||
return map.put(t, Unit.INSTANCE) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return map.remove(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return map.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return map.keySet()
|
||||
.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return stream().allMatch(map::containsKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends T> c) {
|
||||
boolean out = false;
|
||||
for (T t : c) {
|
||||
out |= add(t);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
}
|
|
@ -25,8 +25,8 @@
|
|||
"VertexFormatMixin",
|
||||
"light.LightUpdateMixin",
|
||||
"light.NetworkLightUpdateMixin",
|
||||
"matrix.Matrix3fMixin",
|
||||
"matrix.Matrix4fMixin",
|
||||
"matrix.Matrix3fAccessor",
|
||||
"matrix.Matrix4fAccessor",
|
||||
"matrix.PoseStackMixin"
|
||||
],
|
||||
"injectors": {
|
||||
|
|
Loading…
Reference in a new issue