2021-05-02 01:32:09 +02:00
|
|
|
package com.jozufozu.flywheel.backend;
|
2021-02-02 22:11:22 +01:00
|
|
|
|
2021-05-07 03:38:05 +02:00
|
|
|
import static org.lwjgl.opengl.GL11.GL_REPEAT;
|
|
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
|
|
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
|
|
|
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
|
|
|
|
import static org.lwjgl.opengl.GL11.glBindTexture;
|
|
|
|
import static org.lwjgl.opengl.GL11.glTexParameteri;
|
|
|
|
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
|
|
|
import static org.lwjgl.opengl.GL13.glActiveTexture;
|
|
|
|
|
2021-05-05 06:00:55 +02:00
|
|
|
import java.util.Collection;
|
2021-02-18 19:43:22 +01:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
2021-05-07 03:38:05 +02:00
|
|
|
import java.util.SortedSet;
|
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-07 03:38:05 +02:00
|
|
|
import com.jozufozu.flywheel.backend.core.BasicProgram;
|
|
|
|
import com.jozufozu.flywheel.backend.core.CrumblingProgram;
|
2021-05-04 06:46:33 +02:00
|
|
|
import com.jozufozu.flywheel.backend.core.EffectsContext;
|
|
|
|
import com.jozufozu.flywheel.backend.core.WorldContext;
|
2021-05-07 03:38:05 +02:00
|
|
|
import com.jozufozu.flywheel.backend.core.WorldTileRenderer;
|
2021-05-02 01:32:09 +02:00
|
|
|
import com.jozufozu.flywheel.backend.effects.EffectsHandler;
|
2021-05-05 06:00:55 +02:00
|
|
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
2021-05-02 01:32:09 +02:00
|
|
|
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
|
|
|
|
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
|
|
|
import com.jozufozu.flywheel.backend.instancing.IFlywheelWorld;
|
2021-05-05 06:00:55 +02:00
|
|
|
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
|
|
|
|
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
|
2021-05-07 03:38:05 +02:00
|
|
|
import com.mojang.blaze3d.platform.GlStateManager;
|
|
|
|
import com.mojang.blaze3d.systems.RenderSystem;
|
2021-05-05 06:00:55 +02:00
|
|
|
import com.simibubi.create.content.contraptions.KineticDebugger;
|
2021-02-09 06:17:25 +01:00
|
|
|
import com.simibubi.create.foundation.config.AllConfigs;
|
2021-05-05 06:00:55 +02:00
|
|
|
import com.simibubi.create.foundation.utility.WorldAttached;
|
2021-02-18 19:43:22 +01:00
|
|
|
|
2021-05-07 03:38:05 +02:00
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
2021-02-07 23:15:52 +01:00
|
|
|
import net.minecraft.client.Minecraft;
|
2021-05-07 03:38:05 +02:00
|
|
|
import net.minecraft.client.renderer.DestroyBlockProgress;
|
2021-05-05 06:00:55 +02:00
|
|
|
import net.minecraft.client.renderer.RenderType;
|
2021-05-07 03:38:05 +02:00
|
|
|
import net.minecraft.client.renderer.WorldRenderer;
|
|
|
|
import net.minecraft.client.renderer.model.ModelBakery;
|
|
|
|
import net.minecraft.client.renderer.texture.Texture;
|
|
|
|
import net.minecraft.client.renderer.texture.TextureManager;
|
2021-05-05 06:00:55 +02:00
|
|
|
import net.minecraft.client.world.ClientWorld;
|
|
|
|
import net.minecraft.entity.Entity;
|
2021-05-07 03:38:05 +02:00
|
|
|
import net.minecraft.inventory.container.PlayerContainer;
|
2021-02-07 23:15:52 +01:00
|
|
|
import net.minecraft.resources.IReloadableResourceManager;
|
|
|
|
import net.minecraft.resources.IResourceManager;
|
2021-05-05 06:00:55 +02:00
|
|
|
import net.minecraft.tileentity.TileEntity;
|
2021-02-07 23:15:52 +01:00
|
|
|
import net.minecraft.util.ResourceLocation;
|
2021-05-07 03:38:05 +02:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2021-04-09 23:48:44 +02:00
|
|
|
import net.minecraft.util.math.vector.Matrix4f;
|
2021-04-08 19:22:11 +02:00
|
|
|
import net.minecraft.world.World;
|
2021-02-07 23:15:52 +01:00
|
|
|
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
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
|
|
|
|
|
|
|
public static final ShaderLoader shaderLoader = new ShaderLoader();
|
2021-05-05 08:56:50 +02:00
|
|
|
public static final FlywheelListeners listeners = new FlywheelListeners();
|
2021-04-09 23:48:44 +02:00
|
|
|
|
2021-03-24 23:48:15 +01:00
|
|
|
public static GLCapabilities capabilities;
|
2021-04-01 05:53:02 +02:00
|
|
|
public static GlCompat compat;
|
2021-03-24 23:48:15 +01:00
|
|
|
|
2021-05-05 08:56:50 +02:00
|
|
|
public static EffectsHandler effects;
|
2021-05-07 03:38:05 +02:00
|
|
|
public static WorldAttached<WorldTileRenderer<BasicProgram>> tileRenderer = new WorldAttached<>(() -> new WorldTileRenderer<>(WorldContext.INSTANCE));
|
|
|
|
public static WorldAttached<WorldTileRenderer<CrumblingProgram>> blockBreaking = new WorldAttached<>(() -> new WorldTileRenderer<>(WorldContext.CRUMBLING));
|
2021-05-05 08:56:50 +02:00
|
|
|
|
|
|
|
private static Matrix4f projectionMatrix = new Matrix4f();
|
2021-03-24 23:48:15 +01:00
|
|
|
private static boolean instancingAvailable;
|
|
|
|
private static boolean enabled;
|
|
|
|
|
2021-05-05 08:56:50 +02:00
|
|
|
static final Map<ResourceLocation, MaterialSpec<?>> materialRegistry = new HashMap<>();
|
2021-05-04 06:46:33 +02:00
|
|
|
static final Map<ResourceLocation, ShaderContext<?>> contexts = new HashMap<>();
|
2021-05-05 06:00:55 +02:00
|
|
|
static final Map<ResourceLocation, ProgramSpec> programSpecRegistry = new HashMap<>();
|
2021-05-04 06:46:33 +02:00
|
|
|
|
|
|
|
static {
|
|
|
|
register(WorldContext.INSTANCE);
|
2021-05-07 03:38:05 +02:00
|
|
|
register(WorldContext.CRUMBLING);
|
2021-05-04 06:46:33 +02:00
|
|
|
register(EffectsContext.INSTANCE);
|
2021-05-05 08:56:50 +02:00
|
|
|
|
|
|
|
listeners.refreshListener(world -> {
|
|
|
|
if (canUseInstancing() && world != null) {
|
2021-05-07 03:38:05 +02:00
|
|
|
WorldTileRenderer<BasicProgram> tileRenderer = Backend.tileRenderer.get(world);
|
2021-05-05 08:56:50 +02:00
|
|
|
tileRenderer.invalidate();
|
|
|
|
world.loadedTileEntityList.forEach(tileRenderer::add);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
listeners.setupFrameListener((world, stack, info, gameRenderer, lightTexture) -> {
|
|
|
|
Backend.tileRenderer.get(world)
|
|
|
|
.beginFrame(info);
|
|
|
|
});
|
|
|
|
|
|
|
|
listeners.renderLayerListener(Backend::renderLayer);
|
2021-05-04 06:46:33 +02:00
|
|
|
}
|
2021-03-24 23:48:15 +01:00
|
|
|
|
|
|
|
public Backend() {
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-05-04 06:46:33 +02:00
|
|
|
* Register a shader program.
|
2021-03-24 23:48:15 +01:00
|
|
|
*/
|
2021-05-04 06:46:33 +02:00
|
|
|
public static 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-05-05 06:00:55 +02:00
|
|
|
public static <P extends GlProgram> ShaderContext<P> register(ShaderContext<P> spec) {
|
2021-05-04 06:46:33 +02:00
|
|
|
ResourceLocation name = spec.getRoot();
|
|
|
|
if (contexts.containsKey(name)) {
|
|
|
|
throw new IllegalStateException("Program spec '" + name + "' already registered.");
|
|
|
|
}
|
|
|
|
contexts.put(name, spec);
|
|
|
|
return spec;
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
|
|
|
|
2021-05-05 06:00:55 +02:00
|
|
|
/**
|
|
|
|
* Register an instancing material.
|
|
|
|
*/
|
|
|
|
public static <M extends InstancedModel<?>> MaterialSpec<M> register(MaterialSpec<M> spec) {
|
|
|
|
ResourceLocation name = spec.name;
|
|
|
|
if (materialRegistry.containsKey(name)) {
|
|
|
|
throw new IllegalStateException("Material spec '" + name + "' already registered.");
|
|
|
|
}
|
|
|
|
materialRegistry.put(name, spec);
|
|
|
|
return spec;
|
|
|
|
}
|
|
|
|
|
2021-03-24 23:48:15 +01:00
|
|
|
public static boolean isFlywheelWorld(World world) {
|
|
|
|
return world == Minecraft.getInstance().world || (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel());
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean available() {
|
|
|
|
return canUseVBOs();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean canUseInstancing() {
|
|
|
|
return enabled && instancingAvailable;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean canUseVBOs() {
|
|
|
|
return enabled && gl20();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean gl33() {
|
|
|
|
return capabilities.OpenGL33;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean gl20() {
|
|
|
|
return capabilities.OpenGL20;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void init() {
|
|
|
|
// Can be null when running datagenerators due to the unfortunate time we call this
|
|
|
|
Minecraft mc = Minecraft.getInstance();
|
|
|
|
if (mc == null) return;
|
|
|
|
|
|
|
|
IResourceManager manager = mc.getResourceManager();
|
|
|
|
|
|
|
|
if (manager instanceof IReloadableResourceManager) {
|
2021-04-09 23:48:44 +02:00
|
|
|
ISelectiveResourceReloadListener listener = shaderLoader::onResourceManagerReload;
|
2021-03-24 23:48:15 +01:00
|
|
|
((IReloadableResourceManager) manager).addReloadListener(listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void refresh() {
|
|
|
|
capabilities = GL.createCapabilities();
|
|
|
|
|
2021-04-01 05:53:02 +02:00
|
|
|
compat = new GlCompat(capabilities);
|
2021-03-24 23:48:15 +01:00
|
|
|
|
|
|
|
instancingAvailable = compat.vertexArrayObjectsSupported() &&
|
|
|
|
compat.drawInstancedSupported() &&
|
|
|
|
compat.instancedArraysSupported();
|
|
|
|
|
|
|
|
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
|
2021-04-13 01:00:13 +02:00
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
if (effects != null) effects.delete();
|
|
|
|
effects = new EffectsHandler();
|
|
|
|
}
|
2021-03-24 23:48:15 +01:00
|
|
|
}
|
2021-05-05 06:00:55 +02:00
|
|
|
|
|
|
|
public static void tick() {
|
|
|
|
Minecraft mc = Minecraft.getInstance();
|
|
|
|
ClientWorld world = mc.world;
|
|
|
|
|
2021-05-07 03:38:05 +02:00
|
|
|
WorldTileRenderer<BasicProgram> instancer = tileRenderer.get(world);
|
2021-05-05 06:00:55 +02:00
|
|
|
|
|
|
|
Entity renderViewEntity = mc.renderViewEntity;
|
2021-05-05 08:56:50 +02:00
|
|
|
instancer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
|
2021-05-05 06:00:55 +02:00
|
|
|
}
|
|
|
|
|
2021-05-05 08:56:50 +02:00
|
|
|
public static void renderLayer(ClientWorld world, RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
|
|
|
|
if (!canUseInstancing(world)) return;
|
2021-05-07 03:38:05 +02:00
|
|
|
WorldTileRenderer<BasicProgram> renderer = tileRenderer.get(world);
|
|
|
|
if (renderer == null) return;
|
2021-05-05 06:00:55 +02:00
|
|
|
|
|
|
|
layer.startDrawing();
|
|
|
|
|
2021-05-07 03:38:05 +02:00
|
|
|
renderer.render(layer, viewProjection, cameraX, cameraY, cameraZ);
|
2021-05-05 06:00:55 +02:00
|
|
|
|
|
|
|
layer.endDrawing();
|
|
|
|
}
|
|
|
|
|
2021-05-07 03:38:05 +02:00
|
|
|
public static void renderBreaking(ClientWorld world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
|
|
|
|
if (!canUseInstancing(world)) return;
|
|
|
|
WorldTileRenderer<CrumblingProgram> renderer = blockBreaking.get(world);
|
|
|
|
if (renderer == null) return;
|
|
|
|
|
|
|
|
WorldRenderer worldRenderer = Minecraft.getInstance().worldRenderer;
|
|
|
|
Long2ObjectMap<SortedSet<DestroyBlockProgress>> breakingProgressions = worldRenderer.blockBreakingProgressions;
|
|
|
|
|
|
|
|
if (breakingProgressions.isEmpty()) return;
|
|
|
|
|
|
|
|
for (Long2ObjectMap.Entry<SortedSet<DestroyBlockProgress>> entry : breakingProgressions.long2ObjectEntrySet()) {
|
|
|
|
BlockPos breakingPos = BlockPos.fromLong(entry.getLongKey());
|
|
|
|
|
|
|
|
SortedSet<DestroyBlockProgress> sortedset1 = entry.getValue();
|
|
|
|
if (sortedset1 != null && !sortedset1.isEmpty()) {
|
|
|
|
renderer.add(world.getTileEntity(breakingPos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer.beginFrame(Minecraft.getInstance().gameRenderer.getActiveRenderInfo());
|
|
|
|
|
|
|
|
RenderType layer = RenderType.getCutoutMipped();
|
|
|
|
|
|
|
|
layer.startDrawing();
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
|
|
|
TextureManager textureManager = Minecraft.getInstance().textureManager;
|
|
|
|
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(5));
|
|
|
|
|
|
|
|
if (breaking != null) {
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
|
|
|
|
RenderSystem.enableBlend();
|
|
|
|
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
|
|
|
|
|
|
|
|
RenderSystem.enableAlphaTest();
|
|
|
|
RenderSystem.alphaFunc(516, 0.003921569F);
|
|
|
|
|
|
|
|
RenderSystem.polygonOffset(-1.0F, -10.0F);
|
|
|
|
RenderSystem.enablePolygonOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer.render(layer, viewProjection, cameraX, cameraY, cameraZ, program -> program.setTextureScale(64, 64));
|
|
|
|
|
|
|
|
if (breaking != null) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(PlayerContainer.BLOCK_ATLAS_TEXTURE).getGlTextureId());
|
|
|
|
|
|
|
|
RenderSystem.disableBlend();
|
|
|
|
RenderSystem.defaultBlendFunc();
|
|
|
|
|
|
|
|
RenderSystem.polygonOffset(0.0F, 0.0F);
|
|
|
|
RenderSystem.disablePolygonOffset();
|
|
|
|
}
|
|
|
|
|
|
|
|
layer.endDrawing();
|
|
|
|
|
|
|
|
renderer.invalidate();
|
|
|
|
}
|
|
|
|
|
2021-05-05 06:00:55 +02:00
|
|
|
public static void enqueueUpdate(TileEntity te) {
|
2021-05-05 08:56:50 +02:00
|
|
|
tileRenderer.get(te.getWorld()).queueUpdate(te);
|
2021-05-05 06:00:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void reloadWorldRenderers() {
|
|
|
|
RenderWork.enqueue(Minecraft.getInstance().worldRenderer::loadRenderers);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean canUseInstancing(World world) {
|
|
|
|
return canUseInstancing() && isFlywheelWorld(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TODO: Remove in favor of separate debug programs specified by the SpecLoader/IMultiProgram
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
public static int getDebugMode() {
|
|
|
|
return KineticDebugger.isActive() ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Collection<MaterialSpec<?>> allMaterials() {
|
|
|
|
return materialRegistry.values();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Collection<ProgramSpec> allPrograms() {
|
|
|
|
return programSpecRegistry.values();
|
|
|
|
}
|
2021-05-05 08:56:50 +02:00
|
|
|
|
|
|
|
public static Matrix4f getProjectionMatrix() {
|
|
|
|
return projectionMatrix;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setProjectionMatrix(Matrix4f projectionMatrix) {
|
|
|
|
Backend.projectionMatrix = projectionMatrix;
|
|
|
|
}
|
2021-02-02 22:11:22 +01:00
|
|
|
}
|