Event system, sort of untangle backend

This commit is contained in:
JozsefA 2021-06-04 15:56:46 -07:00
parent bef6d77a59
commit 9bac709dfd
39 changed files with 541 additions and 414 deletions

View file

@ -1,19 +1,10 @@
package com.jozufozu.flywheel.backend;
import static org.lwjgl.opengl.GL20.GL_TEXTURE0;
import static org.lwjgl.opengl.GL20.GL_TEXTURE4;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL20.glActiveTexture;
import static org.lwjgl.opengl.GL20.glBindTexture;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.Vector;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -23,56 +14,27 @@ import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
import com.jozufozu.flywheel.backend.instancing.TileInstanceManager;
import com.jozufozu.flywheel.core.CrumblingInstanceManager;
import com.jozufozu.flywheel.core.QuadConverter;
import com.jozufozu.flywheel.core.WorldContext;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
import com.jozufozu.flywheel.util.WorldAttached;
import com.simibubi.create.foundation.config.AllConfigs;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.DestroyBlockProgress;
import net.minecraft.client.renderer.RenderType;
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;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourceManager;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.LazyValue;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
public class Backend {
public static final Logger log = LogManager.getLogger(Backend.class);
public static final ShaderLoader shaderLoader = new ShaderLoader();
public static final FlywheelListeners listeners = new FlywheelListeners();
public static final ShaderSources SHADER_SOURCES = new ShaderSources();
public static GLCapabilities capabilities;
public static GlCompat compat;
public static WorldAttached<TileInstanceManager> tileInstanceManager = new WorldAttached<>(world -> new TileInstanceManager(WorldContext.INSTANCE.getMaterialManager(world)));
public static LazyValue<Vector<CrumblingInstanceManager>> blockBreaking = new LazyValue<>(() -> {
Vector<CrumblingInstanceManager> renderers = new Vector<>(10);
for (int i = 0; i < 10; i++) {
renderers.add(new CrumblingInstanceManager());
}
return renderers;
});
private static Matrix4f projectionMatrix = new Matrix4f();
private static boolean instancedArrays;
private static boolean enabled;
@ -84,26 +46,6 @@ public class Backend {
static {
register(WorldContext.INSTANCE);
register(WorldContext.CRUMBLING);
listeners.refreshListener(world -> {
if (canUseInstancing() && world != null) {
TileInstanceManager tileRenderer = Backend.tileInstanceManager.get(world);
tileRenderer.invalidate();
world.loadedTileEntityList.forEach(tileRenderer::add);
}
QuadConverter quadConverter = QuadConverter.getNullable();
if (quadConverter != null) quadConverter.free();
});
listeners.setupFrameListener((world, stack, info, gameRenderer, lightTexture) -> {
WorldContext.INSTANCE.materialManager.get(world)
.checkAndShiftOrigin(info);
Backend.tileInstanceManager.get(world)
.beginFrame(info);
});
listeners.renderLayerListener(Backend::renderLayer);
}
public Backend() {
@ -165,7 +107,7 @@ public class Backend {
/**
* Used to avoid calling Flywheel functions on (fake) worlds that don't specifically support it.
*/
public static boolean isFlywheelWorld(World world) {
public static boolean isFlywheelWorld(IWorld world) {
return (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) || world == Minecraft.getInstance().world;
}
@ -197,8 +139,10 @@ public class Backend {
IResourceManager manager = mc.getResourceManager();
if (manager instanceof IReloadableResourceManager) {
((IReloadableResourceManager) manager).addReloadListener(shaderLoader);
((IReloadableResourceManager) manager).addReloadListener(SHADER_SOURCES);
}
OptifineHandler.init();
}
public static void refresh() {
@ -213,84 +157,6 @@ public class Backend {
enabled = AllConfigs.CLIENT.experimentalRendering.get() && !OptifineHandler.usingShaders();
}
public static void tick() {
Minecraft mc = Minecraft.getInstance();
ClientWorld world = mc.world;
TileInstanceManager instancer = tileInstanceManager.get(world);
Entity renderViewEntity = mc.renderViewEntity;
instancer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
}
public static void renderLayer(ClientWorld world, RenderType layer, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!canUseInstancing(world)) return;
MaterialManager<WorldProgram> materialManager = WorldContext.INSTANCE.getMaterialManager(world);
layer.startDrawing();
materialManager.render(layer, viewProjection, cameraX, cameraY, cameraZ);
layer.endDrawing();
}
private static final RenderType CRUMBLING = ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(0);
public static void renderBreaking(ClientWorld world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!canUseInstancing(world)) return;
WorldRenderer worldRenderer = Minecraft.getInstance().worldRenderer;
Long2ObjectMap<SortedSet<DestroyBlockProgress>> breakingProgressions = worldRenderer.blockBreakingProgressions;
if (breakingProgressions.isEmpty()) return;
Vector<CrumblingInstanceManager> renderers = blockBreaking.getValue();
BitSet bitSet = new BitSet(10);
for (Long2ObjectMap.Entry<SortedSet<DestroyBlockProgress>> entry : breakingProgressions.long2ObjectEntrySet()) {
BlockPos breakingPos = BlockPos.fromLong(entry.getLongKey());
SortedSet<DestroyBlockProgress> progresses = entry.getValue();
if (progresses != null && !progresses.isEmpty()) {
int blockDamage = progresses.last().getPartialBlockDamage();
bitSet.set(blockDamage);
renderers.get(blockDamage).add(world.getTileEntity(breakingPos));
}
}
TextureManager textureManager = Minecraft.getInstance().textureManager;
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(PlayerContainer.BLOCK_ATLAS_TEXTURE).getGlTextureId());
glActiveTexture(GL_TEXTURE4);
CRUMBLING.startDrawing();
bitSet.stream().forEach(i -> {
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(i));
CrumblingInstanceManager renderer = renderers.get(i);
renderer.beginFrame(info);
if (breaking != null) {
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
renderer.materialManager.render(RenderType.getCutoutMipped(), viewProjection, cameraX, cameraY, cameraZ);
}
renderer.invalidate();
});
CRUMBLING.endDrawing();
glActiveTexture(GL_TEXTURE0);
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(0));
if (breaking != null)
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
}
public static void enqueueUpdate(TileEntity te) {
tileInstanceManager.get(te.getWorld()).queueUpdate(te);
}
public static void reloadWorldRenderers() {
RenderWork.enqueue(Minecraft.getInstance().worldRenderer::loadRenderers);
}

View file

@ -1,65 +0,0 @@
package com.jozufozu.flywheel.backend;
import java.util.ArrayList;
import java.util.List;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.vector.Matrix4f;
public class FlywheelListeners {
private final List<SetupFrame> setupFrameListeners = new ArrayList<>();
private final List<RenderLayer> renderLayerListeners = new ArrayList<>();
private final List<Refresh> refreshListeners = new ArrayList<>();
public void setupFrameListener(SetupFrame setupFrame) {
setupFrameListeners.add(setupFrame);
}
public void renderLayerListener(RenderLayer renderLayer) {
renderLayerListeners.add(renderLayer);
}
public void refreshListener(Refresh refresh) {
refreshListeners.add(refresh);
}
public void setupFrame(ClientWorld world, MatrixStack stack, ActiveRenderInfo info, GameRenderer gameRenderer, LightTexture lightTexture) {
for (SetupFrame listener : setupFrameListeners) {
listener.setupFrame(world, stack, info, gameRenderer, lightTexture);
}
}
public void renderLayer(ClientWorld world, RenderType type, Matrix4f stack, double camX, double camY, double camZ) {
for (RenderLayer listener : renderLayerListeners) {
listener.renderLayer(world, type, stack, camX, camY, camZ);
}
}
public void refresh(ClientWorld world) {
for (Refresh listener : refreshListeners) {
listener.refresh(world);
}
}
@FunctionalInterface
public interface SetupFrame {
void setupFrame(ClientWorld world, MatrixStack stack, ActiveRenderInfo info, GameRenderer gameRenderer, LightTexture lightTexture);
}
@FunctionalInterface
public interface RenderLayer {
void renderLayer(ClientWorld world, RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ);
}
@FunctionalInterface
public interface Refresh {
void refresh(ClientWorld world);
}
}

View file

@ -3,10 +3,18 @@ package com.jozufozu.flywheel.backend;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class RenderWork {
private static final Queue<Runnable> runs = new ConcurrentLinkedQueue<>();
public static void runAll() {
@SubscribeEvent(priority = EventPriority.LOWEST)
public static void onRenderWorldLast(RenderWorldLastEvent event) {
while (!runs.isEmpty()) {
runs.remove().run();
}

View file

@ -20,18 +20,19 @@ public abstract class ShaderContext<P extends GlProgram> {
protected ShaderTransformer transformer = new ShaderTransformer();
public ShaderContext() { }
public ShaderContext() {
}
// TODO: Untangle the loading functions
/**
* Load all programs associated with this context. This might be just one, if the context is very specialized.
*/
public abstract void load(ShaderLoader loader);
public abstract void load(ShaderSources loader);
protected abstract IMultiProgram<P> loadSpecInternal(ShaderLoader loader, ProgramSpec spec);
protected abstract IMultiProgram<P> loadSpecInternal(ShaderSources loader, ProgramSpec spec);
public void loadProgramFromSpec(ShaderLoader loader, ProgramSpec programSpec) {
public void loadProgramFromSpec(ShaderSources loader, ProgramSpec programSpec) {
try {
programs.put(programSpec.name, loadSpecInternal(loader, programSpec));
@ -43,7 +44,7 @@ public abstract class ShaderContext<P extends GlProgram> {
}
}
public Program loadProgram(ShaderLoader loader, ProgramSpec spec, Collection<String> defines) {
public Program loadProgram(ShaderSources loader, ProgramSpec spec, Collection<String> defines) {
Shader vertexFile = loader.source(spec.vert, ShaderType.VERTEX);
Shader fragmentFile = loader.source(spec.frag, ShaderType.FRAGMENT);

View file

@ -12,14 +12,9 @@ import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
@ -52,14 +47,11 @@ import net.minecraftforge.resource.ISelectiveResourceReloadListener;
import net.minecraftforge.resource.VanillaResourceType;
@ParametersAreNonnullByDefault
public class ShaderLoader implements ISelectiveResourceReloadListener {
public class ShaderSources implements ISelectiveResourceReloadListener {
public static final String SHADER_DIR = "flywheel/shaders/";
public static final String PROGRAM_DIR = "flywheel/programs/";
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
// #flwinclude <"valid_namespace:valid/path_to_file.glsl">
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
private final Map<ResourceLocation, String> shaderSource = new HashMap<>();
private boolean shouldCrash;
@ -161,7 +153,7 @@ public class ShaderLoader implements ISelectiveResourceReloadListener {
}
public Shader source(ResourceLocation name, ShaderType type) {
return new Shader(type, name, getShaderSource(name));
return new Shader(this, type, name, getShaderSource(name));
}
public Program loadProgram(ResourceLocation name, Shader... shaders) {
@ -201,38 +193,6 @@ public class ShaderLoader implements ISelectiveResourceReloadListener {
}
}
public void processIncludes(Shader shader) {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(shader.name);
String includesInjected = includeRecursive(shader.getSource(), seen).collect(Collectors.joining("\n"));
shader.setSource(includesInjected);
}
private Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
return lines(source).flatMap(line -> {
Matcher matcher = includePattern.matcher(line);
if (matcher.find()) {
String includeName = matcher.group(1);
ResourceLocation include = new ResourceLocation(includeName);
if (seen.add(include)) {
try {
return includeRecursive(getShaderSource(include), seen);
} catch (ShaderLoadingException e) {
throw new ShaderLoadingException("could not resolve import: " + e.getMessage());
}
}
}
return Stream.of(line);
});
}
public static Stream<String> lines(String s) {
return new BufferedReader(new StringReader(s)).lines();
}

View file

@ -49,8 +49,8 @@ public class InstanceMaterial<D extends InstanceData> {
this.models = CacheBuilder.newBuilder()
.removalListener(notification -> {
Instancer<?> model = (Instancer<?>) notification.getValue();
RenderWork.enqueue(model::delete);
Instancer<?> instancer = (Instancer<?>) notification.getValue();
RenderWork.enqueue(instancer::delete);
})
.build();
modelFormat = this.spec.getModelFormat();

View file

@ -0,0 +1,160 @@
package com.jozufozu.flywheel.backend.instancing;
import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL11.glBindTexture;
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
import static org.lwjgl.opengl.GL13.GL_TEXTURE4;
import static org.lwjgl.opengl.GL13.glActiveTexture;
import java.util.BitSet;
import java.util.SortedSet;
import java.util.Vector;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.core.CrumblingInstanceManager;
import com.jozufozu.flywheel.core.WorldContext;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.WorldAttached;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.DestroyBlockProgress;
import net.minecraft.client.renderer.RenderType;
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;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.LazyValue;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.IWorld;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class InstancedRenderDispatcher {
private static final RenderType CRUMBLING = ModelBakery.BLOCK_DESTRUCTION_RENDER_LAYERS.get(0);
private static final WorldAttached<TileInstanceManager> tileInstanceManager = new WorldAttached<>(world -> new TileInstanceManager(WorldContext.INSTANCE.getMaterialManager(world)));
public static LazyValue<Vector<CrumblingInstanceManager>> blockBreaking = new LazyValue<>(() -> {
Vector<CrumblingInstanceManager> renderers = new Vector<>(10);
for (int i = 0; i < 10; i++) {
renderers.add(new CrumblingInstanceManager());
}
return renderers;
});
@Nonnull
public static TileInstanceManager get(IWorld world) {
return tileInstanceManager.get(world);
}
public static void tick() {
Minecraft mc = Minecraft.getInstance();
ClientWorld world = mc.world;
TileInstanceManager instancer = get(world);
Entity renderViewEntity = mc.renderViewEntity;
instancer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
}
public static void enqueueUpdate(TileEntity te) {
get(te.getWorld()).queueUpdate(te);
}
@SubscribeEvent
public static void onBeginFrame(BeginFrameEvent event) {
WorldContext.INSTANCE.getMaterialManager(event.getWorld())
.checkAndShiftOrigin(event.getInfo());
get(event.getWorld())
.beginFrame(event.getInfo());
}
@SubscribeEvent
public static void renderLayer(RenderLayerEvent event) {
ClientWorld world = event.getWorld();
if (!Backend.canUseInstancing(world)) return;
MaterialManager<WorldProgram> materialManager = WorldContext.INSTANCE.getMaterialManager(world);
event.type.startDrawing();
materialManager.render(event.type, event.viewProjection, event.camX, event.camY, event.camZ);
event.type.endDrawing();
}
@SubscribeEvent
public static void onReloadRenderers(ReloadRenderersEvent event) {
ClientWorld world = event.getWorld();
if (Backend.canUseInstancing() && world != null) {
WorldContext.INSTANCE.getMaterialManager(world).delete();
TileInstanceManager tileRenderer = get(world);
tileRenderer.invalidate();
world.loadedTileEntityList.forEach(tileRenderer::add);
}
}
public static void renderBreaking(ClientWorld world, Matrix4f viewProjection, double cameraX, double cameraY, double cameraZ) {
if (!Backend.canUseInstancing(world)) return;
WorldRenderer worldRenderer = Minecraft.getInstance().worldRenderer;
Long2ObjectMap<SortedSet<DestroyBlockProgress>> breakingProgressions = worldRenderer.blockBreakingProgressions;
if (breakingProgressions.isEmpty()) return;
Vector<CrumblingInstanceManager> renderers = blockBreaking.getValue();
BitSet bitSet = new BitSet(10);
for (Long2ObjectMap.Entry<SortedSet<DestroyBlockProgress>> entry : breakingProgressions.long2ObjectEntrySet()) {
BlockPos breakingPos = BlockPos.fromLong(entry.getLongKey());
SortedSet<DestroyBlockProgress> progresses = entry.getValue();
if (progresses != null && !progresses.isEmpty()) {
int blockDamage = progresses.last().getPartialBlockDamage();
bitSet.set(blockDamage);
renderers.get(blockDamage).add(world.getTileEntity(breakingPos));
}
}
TextureManager textureManager = Minecraft.getInstance().textureManager;
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(PlayerContainer.BLOCK_ATLAS_TEXTURE).getGlTextureId());
glActiveTexture(GL_TEXTURE4);
CRUMBLING.startDrawing();
bitSet.stream().forEach(i -> {
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(i));
CrumblingInstanceManager renderer = renderers.get(i);
renderer.beginFrame(info);
if (breaking != null) {
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
renderer.materialManager.render(RenderType.getCutoutMipped(), viewProjection, cameraX, cameraY, cameraZ);
}
renderer.invalidate();
});
CRUMBLING.endDrawing();
glActiveTexture(GL_TEXTURE0);
Texture breaking = textureManager.getTexture(ModelBakery.BLOCK_DESTRUCTION_STAGE_TEXTURES.get(0));
if (breaking != null)
glBindTexture(GL_TEXTURE_2D, breaking.getGlTextureId());
}
}

View file

@ -9,6 +9,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
@ -24,8 +25,8 @@ public class TileInstanceManager implements MaterialManager.OriginShiftListener
protected final ConcurrentHashMap.KeySetView<TileEntity, Boolean> queuedUpdates;
protected final Map<TileEntity, TileEntityInstance<?>> instances;
protected final Map<TileEntity, ITickableInstance> tickableInstances;
protected final Map<TileEntity, IDynamicInstance> dynamicInstances;
protected final Object2ObjectOpenHashMap<TileEntity, ITickableInstance> tickableInstances;
protected final Object2ObjectOpenHashMap<TileEntity, IDynamicInstance> dynamicInstances;
protected int frame;
protected int tick;
@ -34,10 +35,11 @@ public class TileInstanceManager implements MaterialManager.OriginShiftListener
this.materialManager = materialManager;
this.queuedUpdates = ConcurrentHashMap.newKeySet(64);
this.queuedAdditions = new ArrayList<>(64);
this.dynamicInstances = new HashMap<>();
this.tickableInstances = new HashMap<>();
this.instances = new HashMap<>();
this.dynamicInstances = new Object2ObjectOpenHashMap<>();
this.tickableInstances = new Object2ObjectOpenHashMap<>();
materialManager.onOriginShift(this);
}
@ -89,10 +91,11 @@ public class TileInstanceManager implements MaterialManager.OriginShiftListener
int cZ = (int) info.getProjectedView().z;
if (dynamicInstances.size() > 0) {
for (IDynamicInstance dyn : dynamicInstances.values()) {
if (!dyn.decreaseFramerateWithDistance() || shouldTick(dyn.getWorldPosition(), lookX, lookY, lookZ, cX, cY, cZ))
dynamicInstances.object2ObjectEntrySet().fastForEach(e -> {
IDynamicInstance dyn = e.getValue();
if (!dyn.decreaseFramerateWithDistance() || shouldFrameUpdate(dyn.getWorldPosition(), lookX, lookY, lookZ, cX, cY, cZ))
dyn.beginFrame();
}
});
}
}
@ -184,14 +187,15 @@ public class TileInstanceManager implements MaterialManager.OriginShiftListener
}
}
protected boolean shouldTick(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
int dX = worldPos.getX() - cX;
int dY = worldPos.getY() - cY;
int dZ = worldPos.getZ() - cZ;
float dot = (dX + lookX * 2) * lookX + (dY + lookY * 2) * lookY + (dZ + lookZ * 2) * lookZ;
if (dot < 0) return false; // is it more than 2 blocks behind the camera?
// is it more than 2 blocks behind the camera?
int dist = 2;
float dot = (dX + lookX * dist) * lookX + (dY + lookY * dist) * lookY + (dZ + lookZ * dist) * lookZ;
if (dot < 0) return false;
return (frame % getUpdateDivisor(dX, dY, dZ)) == 0;
}

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.backend.loading;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
@ -22,7 +22,7 @@ public class InstancedArraysTemplate extends ProgramTemplate {
public static final ResourceLocation vert = new ResourceLocation(Flywheel.ID, "template/instanced/instanced.vert");
public static final ResourceLocation frag = new ResourceLocation(Flywheel.ID, "template/instanced/instanced.frag");
public InstancedArraysTemplate(ShaderLoader loader) {
public InstancedArraysTemplate(ShaderSources loader) {
super(loader);
templates.put(ShaderType.VERTEX, new ShaderTemplate(requiredVert, loader.getShaderSource(vert)));

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.backend.loading;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
@ -19,7 +19,7 @@ public class ModelTemplate extends ProgramTemplate {
public static final ResourceLocation vert = new ResourceLocation(Flywheel.ID, "template/model/model.vert");
public static final ResourceLocation frag = new ResourceLocation(Flywheel.ID, "template/model/model.frag");
public ModelTemplate(ShaderLoader loader) {
public ModelTemplate(ShaderSources loader) {
super(loader);
templates.put(ShaderType.VERTEX, new ShaderTemplate(requiredVert, loader.getShaderSource(vert)));

View file

@ -3,15 +3,15 @@ package com.jozufozu.flywheel.backend.loading;
import java.util.EnumMap;
import java.util.Map;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
public abstract class ProgramTemplate implements IProcessingStage {
protected final ShaderLoader loader;
protected final ShaderSources loader;
protected Map<ShaderType, ShaderTemplate> templates = new EnumMap<>(ShaderType.class);
public ProgramTemplate(ShaderLoader loader) {
public ProgramTemplate(ShaderSources loader) {
this.loader = loader;
}

View file

@ -1,32 +1,43 @@
package com.jozufozu.flywheel.backend.loading;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class Shader {
// #flwinclude <"valid_namespace:valid/path_to_file.glsl">
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
public static final Pattern versionDetector = Pattern.compile("#version[^\\n]*");
private static final Pattern decorator = Pattern.compile("#\\[([\\w_]*)]");
public final ResourceLocation name;
public ShaderType type;
private String source;
private final ShaderSources loader;
private boolean parsed = false;
final List<TaggedStruct> structs = new ArrayList<>(3);
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
public Shader(ShaderType type, ResourceLocation name, String source) {
public Shader(ShaderSources loader, ShaderType type, ResourceLocation name, String source) {
this.loader = loader;
this.type = type;
this.name = name;
this.source = source;
@ -91,4 +102,39 @@ public class Shader {
this.source = strippedSrc.toString();
}
public void processIncludes() {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(name);
source = includeRecursive(source, seen).collect(Collectors.joining("\n"));
}
private Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
return lines(source).flatMap(line -> {
Matcher matcher = includePattern.matcher(line);
if (matcher.find()) {
String includeName = matcher.group(1);
ResourceLocation include = new ResourceLocation(includeName);
if (seen.add(include)) {
try {
return includeRecursive(loader.getShaderSource(include), seen);
} catch (ShaderLoadingException e) {
throw new ShaderLoadingException("could not resolve import: " + e.getMessage());
}
}
}
return Stream.of(line);
});
}
public static Stream<String> lines(String s) {
return new BufferedReader(new StringReader(s)).lines();
}
}

View file

@ -11,7 +11,7 @@ public class CrumblingInstanceManager extends TileInstanceManager {
}
@Override
protected boolean shouldTick(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
return true;
}
}

View file

@ -15,10 +15,16 @@ import com.jozufozu.flywheel.backend.gl.GlNumericType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
/**
* A class to manage EBOs that index quads as triangles.
*/
@Mod.EventBusSubscriber
public class QuadConverter {
public static final int STARTING_CAPACITY = 42;
@ -158,4 +164,10 @@ public class QuadConverter {
return GlNumericType.UINT;
}
// make sure this gets reset first so it has a chance to repopulate
@SubscribeEvent(priority = EventPriority.HIGHEST)
public static void onRendererReload(ReloadRenderersEvent event) {
if (INSTANCE != null) INSTANCE.free();
}
}

View file

@ -11,7 +11,7 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.ResourceUtil;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
@ -43,7 +43,7 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
protected Supplier<Stream<ResourceLocation>> specStream;
protected TemplateFactory templateFactory;
public final WorldAttached<MaterialManager<P>> materialManager = new WorldAttached<>($ -> new MaterialManager<>(this));
private final WorldAttached<MaterialManager<P>> materialManager = new WorldAttached<>($ -> new MaterialManager<>(this));
private final Map<ShaderType, ResourceLocation> builtins = new EnumMap<>(ShaderType.class);
private final Map<ShaderType, String> builtinSources = new EnumMap<>(ShaderType.class);
@ -78,13 +78,14 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
}
@Override
protected IMultiProgram<P> loadSpecInternal(ShaderLoader loader, ProgramSpec spec) {
protected IMultiProgram<P> loadSpecInternal(ShaderSources loader, ProgramSpec spec) {
return new StateSensitiveMultiProgram<>(loader, factory, this, spec);
}
protected ProgramTemplate template;
@Override
public void load(ShaderLoader loader) {
public void load(ShaderSources loader) {
programs.values().forEach(IMultiProgram::delete);
programs.clear();
@ -103,10 +104,10 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
template = templateFactory.create(loader);
transformer = new ShaderTransformer()
.pushStage(this::injectBuiltins)
.pushStage(loader::processIncludes)
.pushStage(Shader::processIncludes)
.pushStage(Shader::parseStructs)
.pushStage(template)
.pushStage(loader::processIncludes);
.pushStage(Shader::processIncludes);
specStream.get()
.map(Backend::getSpec)
@ -131,6 +132,6 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
}
public interface TemplateFactory {
ProgramTemplate create(ShaderLoader loader);
ProgramTemplate create(ShaderSources loader);
}
}

View file

@ -5,7 +5,7 @@ import java.util.Collections;
import java.util.List;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.loading.Program;
import com.jozufozu.flywheel.core.shader.spec.IContextCondition;
@ -18,7 +18,7 @@ public class StateSensitiveMultiProgram<P extends GlProgram> implements IMultiPr
List<Pair<IContextCondition, P>> variants;
P fallback;
public StateSensitiveMultiProgram(ShaderLoader loader, ExtensibleGlProgram.Factory<P> factory, ShaderContext<P> context, ProgramSpec p) {
public StateSensitiveMultiProgram(ShaderSources loader, ExtensibleGlProgram.Factory<P> factory, ShaderContext<P> context, ProgramSpec p) {
variants = new ArrayList<>(p.states.size());
for (ProgramState state : p.states) {

View file

@ -0,0 +1,45 @@
package com.jozufozu.flywheel.event;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.world.ClientWorld;
import net.minecraftforge.eventbus.api.Event;
public class BeginFrameEvent extends Event {
private final ClientWorld world;
private final MatrixStack stack;
private final ActiveRenderInfo info;
private final GameRenderer gameRenderer;
private final LightTexture lightTexture;
public BeginFrameEvent(ClientWorld world, MatrixStack stack, ActiveRenderInfo info, GameRenderer gameRenderer, LightTexture lightTexture) {
this.world = world;
this.stack = stack;
this.info = info;
this.gameRenderer = gameRenderer;
this.lightTexture = lightTexture;
}
public ClientWorld getWorld() {
return world;
}
public MatrixStack getStack() {
return stack;
}
public ActiveRenderInfo getInfo() {
return info;
}
public GameRenderer getGameRenderer() {
return gameRenderer;
}
public LightTexture getLightTexture() {
return lightTexture;
}
}

View file

@ -3,9 +3,14 @@ package com.jozufozu.flywheel.event;
import java.util.ArrayList;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.TileInstanceManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.world.IWorld;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@ -29,4 +34,15 @@ public class ForgeEvents {
}
}
}
@SubscribeEvent
public static void onLoadWorld(WorldEvent.Load event) {
IWorld world = event.getWorld();
if (Backend.isFlywheelWorld(world)) {
TileInstanceManager renderer = InstancedRenderDispatcher.get(world);
renderer.invalidate();
((ClientWorld) world).loadedTileEntityList.forEach(renderer::add);
}
}
}

View file

@ -0,0 +1,16 @@
package com.jozufozu.flywheel.event;
import net.minecraft.client.world.ClientWorld;
import net.minecraftforge.eventbus.api.Event;
public class ReloadRenderersEvent extends Event {
private final ClientWorld world;
public ReloadRenderersEvent(ClientWorld world) {
this.world = world;
}
public ClientWorld getWorld() {
return world;
}
}

View file

@ -0,0 +1,48 @@
package com.jozufozu.flywheel.event;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraftforge.eventbus.api.Event;
public class RenderLayerEvent extends Event {
private final ClientWorld world;
public final RenderType type;
public final Matrix4f viewProjection;
public final double camX;
public final double camY;
public final double camZ;
public RenderLayerEvent(ClientWorld world, RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ) {
this.world = world;
this.type = type;
this.viewProjection = viewProjection;
this.camX = camX;
this.camY = camY;
this.camZ = camZ;
}
public ClientWorld getWorld() {
return world;
}
public RenderType getType() {
return type;
}
public Matrix4f getViewProjection() {
return viewProjection;
}
public double getCamX() {
return camX;
}
public double getCamY() {
return camY;
}
public double getCamZ() {
return camZ;
}
}

View file

@ -1,15 +1,33 @@
package com.jozufozu.flywheel.light;
import static org.lwjgl.opengl.GL20.GL_LINEAR;
import static org.lwjgl.opengl.GL20.GL_MIRRORED_REPEAT;
import static org.lwjgl.opengl.GL20.GL_TEXTURE0;
import static org.lwjgl.opengl.GL20.GL_TEXTURE4;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_3D;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_WRAP_R;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_WRAP_S;
import static org.lwjgl.opengl.GL20.GL_TEXTURE_WRAP_T;
import static org.lwjgl.opengl.GL20.GL_UNPACK_ALIGNMENT;
import static org.lwjgl.opengl.GL20.GL_UNPACK_IMAGE_HEIGHT;
import static org.lwjgl.opengl.GL20.GL_UNPACK_ROW_LENGTH;
import static org.lwjgl.opengl.GL20.GL_UNPACK_SKIP_IMAGES;
import static org.lwjgl.opengl.GL20.GL_UNPACK_SKIP_PIXELS;
import static org.lwjgl.opengl.GL20.GL_UNPACK_SKIP_ROWS;
import static org.lwjgl.opengl.GL20.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL20.glActiveTexture;
import static org.lwjgl.opengl.GL20.glPixelStorei;
import static org.lwjgl.opengl.GL20.glTexImage3D;
import static org.lwjgl.opengl.GL20.glTexParameteri;
import static org.lwjgl.opengl.GL20.glTexSubImage3D;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.gl.GlTexture;
import com.jozufozu.flywheel.backend.gl.versioned.RGPixelFormat;
@ -35,20 +53,20 @@ public class LightVolume {
pixelFormat = Backend.compat.pixelFormat;
this.glTexture = new GlTexture(GL20.GL_TEXTURE_3D);
this.glTexture = new GlTexture(GL_TEXTURE_3D);
this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * pixelFormat.byteCount());
// allocate space for the texture
GL20.glActiveTexture(GL20.GL_TEXTURE4);
glActiveTexture(GL_TEXTURE4);
glTexture.bind();
int sizeX = textureVolume.sizeX();
int sizeY = textureVolume.sizeY();
int sizeZ = textureVolume.sizeZ();
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, pixelFormat.internalFormat(), sizeX, sizeY, sizeZ, 0, pixelFormat.format(), GL20.GL_UNSIGNED_BYTE, 0);
glTexImage3D(GL_TEXTURE_3D, 0, pixelFormat.internalFormat(), sizeX, sizeY, sizeZ, 0, pixelFormat.format(), GL_UNSIGNED_BYTE, 0);
glTexture.unbind();
GL20.glActiveTexture(GL20.GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
}
private void setSampleVolume(GridAlignedBB sampleVolume) {
@ -242,32 +260,32 @@ public class LightVolume {
// just in case something goes wrong or we accidentally call this before this volume is properly disposed of.
if (lightData == null || removed) return;
GL13.glActiveTexture(GL20.GL_TEXTURE4);
glActiveTexture(GL_TEXTURE4);
glTexture.bind();
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL20.GL_MIRRORED_REPEAT);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
uploadTexture();
}
private void uploadTexture() {
if (bufferDirty) {
GL20.glPixelStorei(GL20.GL_UNPACK_ROW_LENGTH, 0);
GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_PIXELS, 0);
GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_ROWS, 0);
GL20.glPixelStorei(GL20.GL_UNPACK_SKIP_IMAGES, 0);
GL20.glPixelStorei(GL20.GL_UNPACK_IMAGE_HEIGHT, 0);
GL20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 2);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
int sizeX = textureVolume.sizeX();
int sizeY = textureVolume.sizeY();
int sizeZ = textureVolume.sizeZ();
GL12.glTexSubImage3D(GL12.GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, pixelFormat.format(), GL20.GL_UNSIGNED_BYTE, lightData);
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, pixelFormat.format(), GL_UNSIGNED_BYTE, lightData);
GL20.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 4); // 4 is the default
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
bufferDirty = false;
}
}
@ -278,11 +296,9 @@ public class LightVolume {
public void delete() {
removed = true;
RenderWork.enqueue(() -> {
glTexture.delete();
MemoryUtil.memFree(lightData);
lightData = null;
});
}
private void writeLight(int x, int y, int z, int block, int sky) {

View file

@ -5,11 +5,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.instancing.TileInstanceManager;
import com.jozufozu.flywheel.core.PartialModel;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
@ -52,7 +48,6 @@ import net.minecraft.util.text.TextComponentUtils;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraft.world.IWorld;
import net.minecraftforge.client.event.ModelBakeEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
@ -86,7 +81,6 @@ public class CreateClient {
Backend.init();
CreateFlywheelHandler.init();
OptifineHandler.init();
}
public static void clientInit(FMLClientSetupEvent event) {
@ -207,19 +201,8 @@ public class CreateClient {
}
public static void invalidateRenderers() {
invalidateRenderers(null);
}
public static void invalidateRenderers(@Nullable IWorld world) {
BUFFER_CACHE.invalidate();
if (world != null) {
Backend.tileInstanceManager.get(world)
.invalidate();
} else {
Backend.tileInstanceManager.forEach(TileInstanceManager::invalidate);
}
ContraptionRenderDispatcher.invalidateAll();
}

View file

@ -7,8 +7,8 @@ import java.util.List;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.KineticNetwork;
import com.simibubi.create.content.contraptions.RotationPropagator;
@ -258,7 +258,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
effects.triggerOverStressedEffect();
if (clientPacket)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(this));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
public float getGeneratedSpeed() {
@ -557,7 +557,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
public void requestModelDataUpdate() {
super.requestModelDataUpdate();
if (!this.removed) {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(this));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
}

View file

@ -2,8 +2,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.ch
import java.util.List;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity;
@ -70,7 +70,7 @@ public class StickerTileEntity extends SmartTileEntity implements IInstanceRende
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> playSound(false));
piston.chase(target, .4f, Chaser.LINEAR);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(this));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
public boolean isAttachedToBlock() {

View file

@ -40,7 +40,7 @@ public class ContraptionInstanceManager extends TileInstanceManager {
}
@Override
protected boolean shouldTick(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
protected boolean shouldFrameUpdate(BlockPos worldPos, float lookX, float lookY, float lookZ, int cX, int cY, int cZ) {
return true;
}

View file

@ -18,6 +18,9 @@ import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.loading.ModelTemplate;
import com.jozufozu.flywheel.core.WorldContext;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.CreateClient;
@ -42,7 +45,6 @@ import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockModelShapes;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
@ -50,17 +52,18 @@ import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.common.util.Lazy;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class ContraptionRenderDispatcher {
private static final Lazy<BlockModelRenderer> MODEL_RENDERER = Lazy.of(() -> new BlockModelRenderer(Minecraft.getInstance().getBlockColors()));
private static final Lazy<BlockModelShapes> BLOCK_MODELS = Lazy.of(() -> Minecraft.getInstance().getModelManager().getBlockModelShapes());
@ -92,7 +95,9 @@ public class ContraptionRenderDispatcher {
}
}
public static void beginFrame(ClientWorld world, MatrixStack stack, ActiveRenderInfo info, GameRenderer gameRenderer, LightTexture lightTexture) {
@SubscribeEvent
public static void beginFrame(BeginFrameEvent event) {
ActiveRenderInfo info = event.getInfo();
double camX = info.getProjectedView().x;
double camY = info.getProjectedView().y;
double camZ = info.getProjectedView().z;
@ -101,10 +106,12 @@ public class ContraptionRenderDispatcher {
}
}
public static void renderLayer(ClientWorld world, RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) {
@SubscribeEvent
public static void renderLayer(RenderLayerEvent event) {
removeDeadContraptions();
if (RENDERERS.isEmpty()) return;
RenderType layer = event.getType();
layer.startDrawing();
glEnable(GL_TEXTURE_3D);
@ -114,8 +121,8 @@ public class ContraptionRenderDispatcher {
ContraptionProgram structureShader = STRUCTURE.getProgram(AllProgramSpecs.STRUCTURE);
structureShader.bind();
structureShader.uploadViewProjection(viewProjection);
structureShader.uploadCameraPos(camX, camY, camZ);
structureShader.uploadViewProjection(event.viewProjection);
structureShader.uploadCameraPos(event.camX, event.camY, event.camZ);
for (RenderedContraption renderer : RENDERERS.values()) {
renderer.doRenderLayer(layer, structureShader);
@ -124,7 +131,7 @@ public class ContraptionRenderDispatcher {
if (Backend.canUseInstancing()) {
for (RenderedContraption renderer : RENDERERS.values()) {
renderer.materialManager.render(layer, viewProjection, camX, camY, camZ, renderer::setup);
renderer.materialManager.render(layer, event.viewProjection, event.camX, event.camY, event.camZ, renderer::setup);
}
}
@ -134,6 +141,11 @@ public class ContraptionRenderDispatcher {
glActiveTexture(GL_TEXTURE0);
}
@SubscribeEvent
public static void onRendererReload(ReloadRenderersEvent event) {
invalidateAll();
}
public static void render(AbstractContraptionEntity entity, Contraption contraption,
ContraptionMatrices matrices, IRenderTypeBuffer buffers) {
World world = entity.world;
@ -157,7 +169,7 @@ public class ContraptionRenderDispatcher {
if (contraption == null) {
PlacementSimulationWorld renderWorld = setupRenderWorld(world, c);
contraption = new RenderedContraption(world, renderWorld, c);
contraption = new RenderedContraption(renderWorld, c);
RENDERERS.put(entityId, contraption);
}

View file

@ -58,7 +58,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
private Matrix4f model;
private AxisAlignedBB lightBox;
public RenderedContraption(World world, PlacementSimulationWorld renderWorld, Contraption contraption) {
public RenderedContraption(PlacementSimulationWorld renderWorld, Contraption contraption) {
super(contraption, renderWorld);
this.lighter = contraption.makeLighter();
this.materialManager = new ContraptionMaterialManager(ContraptionRenderDispatcher.TILES);
@ -119,6 +119,7 @@ public class RenderedContraption extends ContraptionWorldHolder {
lighter.lightVolume.delete();
materialManager.delete();
kinetics.invalidate();
}

View file

@ -12,7 +12,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.jozufozu.flywheel.light.ILightUpdateListener;
import com.jozufozu.flywheel.light.LightUpdater;
@ -267,7 +267,7 @@ public class BeltTileEntity extends KineticTileEntity implements ILightUpdateLis
belt.color = Optional.ofNullable(colorIn);
belt.markDirty();
belt.sendData();
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(belt));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(belt));
}
}

View file

@ -9,8 +9,8 @@ import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.funnel.BeltFunnelBlock;
@ -103,7 +103,7 @@ public class BeltTunnelTileEntity extends SmartTileEntity implements IInstanceRe
sides.addAll(flaps.keySet());
super.fromTag(state, compound, clientPacket);
if (clientPacket)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(this));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
public void updateTunnelConnections() {

View file

@ -3,8 +3,8 @@ package com.simibubi.create.content.logistics.block.funnel;
import java.lang.ref.WeakReference;
import java.util.List;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.goggles.IHaveHoveringInformation;
@ -327,7 +327,7 @@ public class FunnelTileEntity extends SmartTileEntity implements IHaveHoveringIn
extractionCooldown = compound.getInt("TransferCooldown");
if (clientPacket)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Backend.enqueueUpdate(this));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this));
}
@Override

View file

@ -3,9 +3,7 @@ package com.simibubi.create.events;
import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.instancing.TileInstanceManager;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllFluids;
@ -110,7 +108,7 @@ public class ClientEvents {
SoundScapes.tick();
AnimationTickHolder.tick();
Backend.tick();
InstancedRenderDispatcher.tick();
ScrollValueHandler.tick();
CreateClient.SCHEMATIC_SENDER.tick();
@ -154,11 +152,8 @@ public class ClientEvents {
public static void onLoadWorld(WorldEvent.Load event) {
IWorld world = event.getWorld();
if (world.isRemote() && world instanceof ClientWorld && !(world instanceof WrappedClientWorld)) {
CreateClient.invalidateRenderers(world);
CreateClient.invalidateRenderers();
AnimationTickHolder.reset();
TileInstanceManager renderer = Backend.tileInstanceManager.get(world);
renderer.invalidate();
((ClientWorld) world).loadedTileEntityList.forEach(renderer::add);
}
/*
@ -173,7 +168,7 @@ public class ClientEvents {
public static void onUnloadWorld(WorldEvent.Unload event) {
if (event.getWorld()
.isRemote()) {
CreateClient.invalidateRenderers(event.getWorld());
CreateClient.invalidateRenderers();
AnimationTickHolder.reset();
}
}
@ -199,8 +194,6 @@ public class ClientEvents {
RenderSystem.enableCull();
ms.pop();
RenderWork.runAll();
}
@SubscribeEvent

View file

@ -2,6 +2,7 @@ package com.simibubi.create.foundation.fluid;
import java.util.function.Function;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.matrix.MatrixStack.Entry;
import com.mojang.blaze3d.vertex.IVertexBuilder;
@ -15,7 +16,6 @@ import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.fluid.Fluid;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.util.Direction;
@ -23,12 +23,14 @@ import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3i;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber
public class FluidRenderer {
// If we draw to BufferBuilder that minecraft provides for RenderType.getTranslucent(), minecraft draws the contents
@ -49,9 +51,10 @@ public class FluidRenderer {
return _builder;
}
public static void renderLayer(ClientWorld world, RenderType type, Matrix4f viewProjection, double camX, double camY, double camZ) {
if (type == RenderType.getTranslucent()) {
type.draw(_builder, 0, 0, 0);
@SubscribeEvent
public static void renderLayer(RenderLayerEvent event) {
if (event.type == RenderType.getTranslucent()) {
event.type.draw(_builder, 0, 0, 0);
}
}

View file

@ -9,6 +9,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockState;
@ -23,6 +27,7 @@ import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
@OnlyIn(Dist.CLIENT)
@Mixin(WorldRenderer.class)
@ -35,7 +40,7 @@ public class RenderHooksMixin {
private void setupFrame(MatrixStack stack, float p_228426_2_, long p_228426_3_, boolean p_228426_5_,
ActiveRenderInfo info, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f p_228426_9_,
CallbackInfo ci) {
Backend.listeners.setupFrame(world, stack, info, gameRenderer, lightTexture);
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(world, stack, info, gameRenderer, lightTexture));
}
/**
@ -54,7 +59,7 @@ public class RenderHooksMixin {
Matrix4f viewProjection = view.copy();
viewProjection.multiplyBackward(Backend.getProjectionMatrix());
Backend.listeners.renderLayer(world, type, viewProjection, camX, camY, camZ);
MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(world, type, viewProjection, camX, camY, camZ));
GL20.glUseProgram(0);
}
@ -63,7 +68,7 @@ public class RenderHooksMixin {
OptifineHandler.refresh();
Backend.refresh();
Backend.listeners.refresh(world);
MinecraftForge.EVENT_BUS.post(new ReloadRenderersEvent(world));
}
@ -86,7 +91,7 @@ public class RenderHooksMixin {
viewProjection.multiplyBackward(Backend.getProjectionMatrix());
Vector3d cameraPos = info.getProjectedView();
Backend.renderBreaking(world, viewProjection, cameraPos.x, cameraPos.y, cameraPos.z);
InstancedRenderDispatcher.renderBreaking(world, viewProjection, cameraPos.x, cameraPos.y, cameraPos.z);
GL20.glUseProgram(0);
}
@ -94,7 +99,7 @@ public class RenderHooksMixin {
@Inject(at = @At("TAIL"), method = "scheduleBlockRerenderIfNeeded")
private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
Backend.tileInstanceManager.get(world)
InstancedRenderDispatcher.get(world)
.update(world.getTileEntity(pos));
}
}

View file

@ -8,7 +8,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.tileentity.TileEntity;
@ -24,7 +24,7 @@ public class TileRemoveMixin {
@Inject(at = @At("TAIL"), method = "remove")
private void onRemove(CallbackInfo ci) {
if (world instanceof ClientWorld)
Backend.tileInstanceManager.get(this.world)
InstancedRenderDispatcher.get(this.world)
.remove((TileEntity) (Object) this);
}
}

View file

@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.backend.instancing.TileInstanceManager;
import net.minecraft.tileentity.TileEntity;
@ -35,7 +35,7 @@ public class TileWorldHookMixin {
@Inject(at = @At("TAIL"), method = "addTileEntity")
private void onAddTile(TileEntity te, CallbackInfoReturnable<Boolean> cir) {
if (isRemote) {
Backend.tileInstanceManager.get(self)
InstancedRenderDispatcher.get(self)
.queueAdd(te);
}
}
@ -46,7 +46,7 @@ public class TileWorldHookMixin {
@Inject(at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", ordinal = 0), method = "tickBlockEntities")
private void onChunkUnload(CallbackInfo ci) {
if (isRemote) {
TileInstanceManager kineticRenderer = Backend.tileInstanceManager.get(self);
TileInstanceManager kineticRenderer = InstancedRenderDispatcher.get(self);
for (TileEntity tile : tileEntitiesToBeRemoved) {
kineticRenderer.remove(tile);
}

View file

@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.light.LightUpdater;
import net.minecraft.client.multiplayer.ClientChunkProvider;
@ -46,7 +46,7 @@ public abstract class LightUpdateMixin extends AbstractChunkProvider {
.getY()) == sectionY)
.map(Map.Entry::getValue)
.forEach(tile -> {
Backend.tileInstanceManager.get(world)
InstancedRenderDispatcher.get(world)
.onLightUpdate(tile);
});
}

View file

@ -5,8 +5,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.light.LightUpdater;
import net.minecraft.client.Minecraft;
@ -36,7 +36,7 @@ public class NetworkLightUpdateMixin {
chunk.getTileEntityMap()
.values()
.forEach(tile -> {
Backend.tileInstanceManager.get(world)
InstancedRenderDispatcher.get(world)
.onLightUpdate(tile);
});
}

View file

@ -2,7 +2,6 @@ package com.simibubi.create.foundation.render;
import com.jozufozu.flywheel.backend.Backend;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.fluid.FluidRenderer;
import com.simibubi.create.foundation.render.effects.EffectsContext;
public class CreateFlywheelHandler {
@ -10,9 +9,5 @@ public class CreateFlywheelHandler {
Backend.register(ContraptionRenderDispatcher.TILES);
Backend.register(ContraptionRenderDispatcher.STRUCTURE);
Backend.register(EffectsContext.INSTANCE);
Backend.listeners.renderLayerListener(ContraptionRenderDispatcher::renderLayer);
Backend.listeners.renderLayerListener(FluidRenderer::renderLayer);
Backend.listeners.setupFrameListener(ContraptionRenderDispatcher::beginFrame);
Backend.listeners.refreshListener($ -> ContraptionRenderDispatcher.invalidateAll());
}
}

View file

@ -4,7 +4,8 @@ import java.util.Collections;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.ShaderSources;
import com.jozufozu.flywheel.backend.loading.Shader;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import com.jozufozu.flywheel.core.shader.IMultiProgram;
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
@ -19,14 +20,14 @@ public class EffectsContext extends ShaderContext<SphereFilterProgram> {
}
@Override
protected IMultiProgram<SphereFilterProgram> loadSpecInternal(ShaderLoader loader, ProgramSpec spec) {
protected IMultiProgram<SphereFilterProgram> loadSpecInternal(ShaderSources loader, ProgramSpec spec) {
return new SphereFilterProgram(loadProgram(loader, spec, Collections.emptyList()));
}
@Override
public void load(ShaderLoader loader) {
public void load(ShaderSources loader) {
transformer = new ShaderTransformer()
.pushStage(loader::processIncludes);
.pushStage(Shader::processIncludes);
loadProgramFromSpec(loader, Backend.getSpec(AllProgramSpecs.CHROMATIC));
}
}