2021-05-02 01:32:09 +02:00
|
|
|
package com.jozufozu.flywheel.backend;
|
2021-02-02 22:11:22 +01:00
|
|
|
|
2021-05-18 23:05:52 +02:00
|
|
|
import java.util.ArrayList;
|
2021-05-05 06:00:55 +02:00
|
|
|
import java.util.Collection;
|
2021-02-18 19:43:22 +01:00
|
|
|
import java.util.HashMap;
|
2021-05-18 23:05:52 +02:00
|
|
|
import java.util.List;
|
2021-02-18 19:43:22 +01:00
|
|
|
import java.util.Map;
|
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
import javax.annotation.Nullable;
|
2021-06-19 07:52:33 +02:00
|
|
|
|
2021-02-18 19:43:22 +01:00
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
|
|
import org.apache.logging.log4j.Logger;
|
2021-03-24 23:48:15 +01:00
|
|
|
import org.lwjgl.opengl.GL;
|
2021-02-18 19:43:22 +01:00
|
|
|
import org.lwjgl.opengl.GLCapabilities;
|
|
|
|
|
2021-05-02 01:32:09 +02:00
|
|
|
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
2021-05-16 01:41:56 +02:00
|
|
|
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
2021-05-05 06:00:55 +02:00
|
|
|
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
|
2021-06-30 21:43:54 +02:00
|
|
|
import com.jozufozu.flywheel.config.FlwConfig;
|
2021-05-31 02:05:41 +02:00
|
|
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
2021-02-18 19:43:22 +01:00
|
|
|
|
2021-02-07 23:15:52 +01:00
|
|
|
import net.minecraft.client.Minecraft;
|
|
|
|
import net.minecraft.util.ResourceLocation;
|
2021-04-09 23:48:44 +02:00
|
|
|
import net.minecraft.util.math.vector.Matrix4f;
|
2021-06-05 00:56:46 +02:00
|
|
|
import net.minecraft.world.IWorld;
|
2021-04-08 19:22:11 +02:00
|
|
|
import net.minecraft.world.World;
|
2021-02-02 22:11:22 +01:00
|
|
|
|
|
|
|
public class Backend {
|
2021-03-24 23:48:15 +01:00
|
|
|
public static final Logger log = LogManager.getLogger(Backend.class);
|
2021-04-09 23:48:44 +02:00
|
|
|
|
2021-06-10 23:34:16 +02:00
|
|
|
protected static final Backend INSTANCE = new Backend();
|
2021-04-09 23:48:44 +02:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public static Backend getInstance() {
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public final Minecraft minecraft;
|
|
|
|
public ShaderSources sources;
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public GLCapabilities capabilities;
|
|
|
|
public GlCompat compat;
|
2021-05-04 06:46:33 +02:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
private Matrix4f projectionMatrix = new Matrix4f();
|
|
|
|
private boolean instancedArrays;
|
|
|
|
private boolean enabled;
|
|
|
|
|
|
|
|
private final List<IShaderContext<?>> contexts = new ArrayList<>();
|
|
|
|
private final Map<ResourceLocation, MaterialSpec<?>> materialRegistry = new HashMap<>();
|
|
|
|
private final Map<ResourceLocation, ProgramSpec> programSpecRegistry = new HashMap<>();
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-06-10 23:34:16 +02:00
|
|
|
protected Backend() {
|
2021-06-07 00:46:16 +02:00
|
|
|
// Can be null when running datagenerators due to the unfortunate time we call this
|
|
|
|
minecraft = Minecraft.getInstance();
|
|
|
|
if (minecraft == null) return;
|
|
|
|
|
|
|
|
sources = new ShaderSources(this);
|
|
|
|
|
|
|
|
OptifineHandler.init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearContexts() {
|
|
|
|
SpecMetaRegistry.clear();
|
2021-07-15 00:35:52 +02:00
|
|
|
programSpecRegistry.clear();
|
2021-06-07 00:46:16 +02:00
|
|
|
contexts.forEach(IShaderContext::delete);
|
2021-07-15 00:35:52 +02:00
|
|
|
contexts.clear();
|
2021-06-07 00:46:16 +02:00
|
|
|
materialRegistry.clear();
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
|
|
|
|
2021-06-04 06:23:06 +02:00
|
|
|
/**
|
|
|
|
* Get a string describing the Flywheel backend. When there are eventually multiple backends
|
|
|
|
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
|
|
|
*/
|
2021-06-07 00:46:16 +02:00
|
|
|
public String getBackendDescriptor() {
|
2021-06-01 22:47:38 +02:00
|
|
|
if (canUseInstancing()) {
|
|
|
|
return "GL33 Instanced Arrays";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canUseVBOs()) {
|
|
|
|
return "VBOs";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Disabled";
|
|
|
|
}
|
|
|
|
|
2021-03-24 23:48:15 +01:00
|
|
|
/**
|
2021-05-04 06:46:33 +02:00
|
|
|
* Register a shader program.
|
2021-03-24 23:48:15 +01:00
|
|
|
*/
|
2021-06-07 00:46:16 +02:00
|
|
|
public ProgramSpec register(ProgramSpec spec) {
|
2021-03-24 23:48:15 +01:00
|
|
|
ResourceLocation name = spec.name;
|
2021-05-05 06:00:55 +02:00
|
|
|
if (programSpecRegistry.containsKey(name)) {
|
2021-03-24 23:48:15 +01:00
|
|
|
throw new IllegalStateException("Program spec '" + name + "' already registered.");
|
|
|
|
}
|
2021-05-05 06:00:55 +02:00
|
|
|
programSpecRegistry.put(name, spec);
|
2021-03-24 23:48:15 +01:00
|
|
|
return spec;
|
|
|
|
}
|
|
|
|
|
2021-05-04 06:46:33 +02:00
|
|
|
/**
|
|
|
|
* Register a shader context.
|
|
|
|
*/
|
2021-06-07 00:46:16 +02:00
|
|
|
public <C extends ShaderContext<?>> C register(C spec) {
|
2021-05-18 23:05:52 +02:00
|
|
|
contexts.add(spec);
|
2021-05-04 06:46:33 +02:00
|
|
|
return spec;
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
|
|
|
|
2021-05-05 06:00:55 +02:00
|
|
|
/**
|
|
|
|
* Register an instancing material.
|
|
|
|
*/
|
2021-06-07 00:46:16 +02:00
|
|
|
public <D extends InstanceData> MaterialSpec<D> register(MaterialSpec<D> spec) {
|
2021-05-05 06:00:55 +02:00
|
|
|
ResourceLocation name = spec.name;
|
|
|
|
if (materialRegistry.containsKey(name)) {
|
|
|
|
throw new IllegalStateException("Material spec '" + name + "' already registered.");
|
|
|
|
}
|
|
|
|
materialRegistry.put(name, spec);
|
2021-06-24 23:20:24 +02:00
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
log.debug("registered material '" + name + "' with vertex size " + spec.getModelFormat()
|
|
|
|
.getStride() + " and instance size " + spec.getInstanceFormat()
|
|
|
|
.getStride());
|
2021-06-24 23:20:24 +02:00
|
|
|
|
2021-05-05 06:00:55 +02:00
|
|
|
return spec;
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public ProgramSpec getSpec(ResourceLocation name) {
|
2021-05-23 02:45:01 +02:00
|
|
|
return programSpecRegistry.get(name);
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean available() {
|
2021-03-24 23:48:15 +01:00
|
|
|
return canUseVBOs();
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean canUseInstancing() {
|
2021-06-01 22:47:38 +02:00
|
|
|
return enabled && instancedArrays;
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean canUseVBOs() {
|
2021-03-24 23:48:15 +01:00
|
|
|
return enabled && gl20();
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean gl33() {
|
2021-03-24 23:48:15 +01:00
|
|
|
return capabilities.OpenGL33;
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean gl20() {
|
2021-03-24 23:48:15 +01:00
|
|
|
return capabilities.OpenGL20;
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public void refresh() {
|
|
|
|
OptifineHandler.refresh();
|
2021-03-24 23:48:15 +01:00
|
|
|
capabilities = GL.createCapabilities();
|
|
|
|
|
2021-04-01 05:53:02 +02:00
|
|
|
compat = new GlCompat(capabilities);
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
instancedArrays = compat.vertexArrayObjectsSupported() && compat.drawInstancedSupported() && compat.instancedArraysSupported();
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
enabled = FlwConfig.get()
|
|
|
|
.enabled() && !OptifineHandler.usingShaders();
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
2021-05-05 06:00:55 +02:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public boolean canUseInstancing(World world) {
|
2021-05-05 06:00:55 +02:00
|
|
|
return canUseInstancing() && isFlywheelWorld(world);
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public Collection<MaterialSpec<?>> allMaterials() {
|
2021-05-05 06:00:55 +02:00
|
|
|
return materialRegistry.values();
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public Collection<ProgramSpec> allPrograms() {
|
2021-05-05 06:00:55 +02:00
|
|
|
return programSpecRegistry.values();
|
|
|
|
}
|
2021-05-05 08:56:50 +02:00
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public Collection<IShaderContext<?>> allContexts() {
|
|
|
|
return contexts;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Matrix4f getProjectionMatrix() {
|
2021-05-05 08:56:50 +02:00
|
|
|
return projectionMatrix;
|
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public void setProjectionMatrix(Matrix4f projectionMatrix) {
|
|
|
|
this.projectionMatrix = projectionMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used to avoid calling Flywheel functions on (fake) worlds that don't specifically support it.
|
|
|
|
*/
|
2021-06-24 10:20:03 +02:00
|
|
|
public static boolean isFlywheelWorld(@Nullable IWorld world) {
|
2021-06-30 21:43:54 +02:00
|
|
|
if (world == null) return false;
|
2021-06-24 10:20:03 +02:00
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
if (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) return true;
|
2021-06-24 10:20:03 +02:00
|
|
|
|
2021-07-15 20:36:24 +02:00
|
|
|
return world == Minecraft.getInstance().level;
|
2021-06-07 00:46:16 +02:00
|
|
|
}
|
|
|
|
|
2021-06-19 07:52:33 +02:00
|
|
|
public static boolean isGameActive() {
|
2021-07-15 20:36:24 +02:00
|
|
|
return !(Minecraft.getInstance().level == null || Minecraft.getInstance().player == null);
|
2021-06-19 07:52:33 +02:00
|
|
|
}
|
|
|
|
|
2021-06-07 00:46:16 +02:00
|
|
|
public static void reloadWorldRenderers() {
|
2021-07-15 20:36:24 +02:00
|
|
|
RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged);
|
2021-05-05 08:56:50 +02:00
|
|
|
}
|
2021-06-19 07:52:33 +02:00
|
|
|
|
2021-06-30 21:43:54 +02:00
|
|
|
public static void init() {
|
|
|
|
}
|
2021-02-02 22:11:22 +01:00
|
|
|
}
|