Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.systems.RenderSystem;
import foundry.veil.Veil;
import foundry.veil.VeilClient;
import foundry.veil.api.client.editor.EditorManager;
import foundry.veil.api.client.editor.Inspector;
import foundry.veil.api.client.render.dynamicbuffer.DynamicBufferType;
import foundry.veil.api.client.render.framebuffer.FramebufferManager;
import foundry.veil.api.client.render.light.renderer.LightRenderer;
Expand All @@ -14,14 +12,14 @@
import foundry.veil.api.client.render.shader.ShaderManager;
import foundry.veil.api.client.render.shader.ShaderModificationManager;
import foundry.veil.api.client.render.shader.ShaderPreDefinitions;
import foundry.veil.api.event.VeilRegisterInspectorsEvent;
import foundry.veil.api.flare.FlareEffectManager;
import foundry.veil.api.quasar.particle.ParticleSystemManager;
import foundry.veil.impl.client.render.dynamicbuffer.DynamicBufferManager;
import foundry.veil.impl.client.render.dynamicbuffer.VanillaShaderCompiler;
import foundry.veil.impl.client.render.pipeline.VeilBloomRenderer;
import foundry.veil.impl.client.render.pipeline.VeilFirstPersonRenderer;
import foundry.veil.impl.client.render.rendertype.DynamicRenderTypeManager;
import foundry.veil.impl.client.render.shader.injection.ShaderInjectionManager;
import foundry.veil.mixin.pipeline.accessor.PipelineReloadableResourceManagerAccessor;
import net.minecraft.ChatFormatting;
import net.minecraft.resources.ResourceLocation;
Expand Down Expand Up @@ -55,6 +53,7 @@ public class VeilRenderer implements ResourceManagerReloadListener {
private final VanillaShaderCompiler vanillaShaderCompiler;
private final DynamicBufferManager dynamicBufferManager;
private final ShaderModificationManager shaderModificationManager;
private final ShaderInjectionManager shaderInjectionManager;
private final ShaderPreDefinitions shaderPreDefinitions;
private final ShaderManager shaderManager;
private final FramebufferManager framebufferManager;
Expand All @@ -73,6 +72,7 @@ public VeilRenderer(ReloadableResourceManager resourceManager, Window window) {
this.dynamicBufferManager = new DynamicBufferManager(window.getWidth(), window.getHeight());
this.shaderPreDefinitions = new ShaderPreDefinitions();
this.shaderModificationManager = new ShaderModificationManager();
this.shaderInjectionManager = new ShaderInjectionManager();
this.shaderManager = new ShaderManager(ShaderManager.PROGRAM_SET, this.shaderPreDefinitions, this.dynamicBufferManager);
this.framebufferManager = new FramebufferManager();
this.postProcessingManager = new PostProcessingManager();
Expand All @@ -87,7 +87,7 @@ public VeilRenderer(ReloadableResourceManager resourceManager, Window window) {
List<PreparableReloadListener> listeners = ((PipelineReloadableResourceManagerAccessor) resourceManager).getListeners();

// This must finish loading before the game renderer so modifications can apply on load
listeners.add(0, this.shaderModificationManager);
listeners.add(0, this.shaderInjectionManager);
// This must be before vanilla shaders so vanilla shaders can be replaced
listeners.add(1, this.shaderManager);
resourceManager.registerReloadListener(this.framebufferManager);
Expand Down Expand Up @@ -183,10 +183,20 @@ public DynamicBufferManager getDynamicBufferManger() {
/**
* @return The manager for all custom shader modifications
*/
@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
@Deprecated(forRemoval = true)
public ShaderModificationManager getShaderModificationManager() {
return this.shaderModificationManager;
}

/**
* @return The manager for all shader injections
*/
@ApiStatus.Internal
public ShaderInjectionManager getShaderInjectionManager() {
return this.shaderInjectionManager;
}

/**
* @return The set of shader pre-definitions. Changes are automatically synced the next frame
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private void addProcessors(ShaderProcessorList processorList, ResourceProvider p
processorList.addPreprocessor(new ShaderBufferProcessor());
processorList.addPreprocessor(new ShaderBindingProcessor());
processorList.addPreprocessor(new ShaderVersionProcessor(), false);
processorList.addPreprocessor(new ShaderModifyProcessor(), false);
processorList.addPreprocessor(new ShaderInjectProcessor(), false);
processorList.addPreprocessor(new DynamicBufferProcessor(), false);
processorList.addPreprocessor(new ShaderFeatureProcessor(), false);
VeilClient.clientPlatform().onRegisterShaderPreProcessors(provider, processorList);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,182 +1,39 @@
package foundry.veil.api.client.render.shader;

import foundry.veil.Veil;
import foundry.veil.impl.client.render.shader.modifier.*;
import foundry.veil.impl.client.render.shader.injection.ShaderInjectionManager;
import io.github.ocelot.glslprocessor.api.node.GlslTree;
import net.minecraft.resources.FileToIdConverter;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceProvider;
import net.minecraft.server.packs.resources.SimplePreparableReloadListener;
import net.minecraft.util.StringUtil;
import net.minecraft.util.profiling.ProfilerFiller;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.Reader;
import java.util.*;
import java.util.regex.Pattern;

/**
* Manages modifications for both vanilla and Veil shader files.
*
* @author Ocelot
* @deprecated Use {@link ShaderInjectionManager} instead.
*/
@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
@Deprecated(forRemoval = true)
public class ShaderModificationManager extends SimplePreparableReloadListener<ShaderModificationManager.Preparations> {

public static final FileToIdConverter MODIFIER_LISTER = new FileToIdConverter("pinwheel/shader_modifiers", ".txt");
private static final Map<String, String> NEXT_STAGES = Map.of(
"vsh", "gsh",
"gsh", "fsh"
);
private static final Pattern OUT_PATTERN = Pattern.compile("out ");

private Map<ResourceLocation, List<ShaderModification>> shaders;
private Map<ShaderModification, ResourceLocation> names;

public ShaderModificationManager() {
this.shaders = Collections.emptyMap();
this.names = Collections.emptyMap();
}

/**
* Applies all shader modifiers to the specified shader source.
*
* @param shaderId The id of the shader to get modifiers for
* @param tree The shader source tree
* @param flags Additional flags for applying modifiers
* @see ShaderModification
*/
public void applyModifiers(ResourceLocation shaderId, GlslTree tree, int flags) {
Collection<ShaderModification> modifiers = this.getModifiers(shaderId);
if (modifiers.isEmpty()) {
return;
}

try {
VeilJobParameters parameters = new VeilJobParameters(this, shaderId, flags);
for (ShaderModification modifier : modifiers) {
modifier.inject(tree, parameters);
}
} catch (Exception e) {
Veil.LOGGER.error("Failed to transform shader: {}", shaderId, e);
}
}

/**
* Retrieves all modifiers for the specified shader.
*
* @param shaderId The shader to get all modifiers for
* @return The modifiers applied to the specified shader
*/
public List<ShaderModification> getModifiers(ResourceLocation shaderId) {
return this.shaders.getOrDefault(shaderId, Collections.emptyList());
}

/**
* Retrieves the id of the specified modifier.
*
* @param modification The modification to get the id of
* @return The id of that modification or <code>null</code> if unregistered
*/
public @Nullable ResourceLocation getModifierId(ShaderModification modification) {
return this.names.get(modification);
}

private @Nullable ResourceLocation getNextStage(ResourceLocation shader, ResourceProvider resourceProvider) {
String[] parts = shader.getPath().split("\\.");
String extension = parts[parts.length - 1].toLowerCase(Locale.ROOT);

while (extension != null) {
extension = NEXT_STAGES.get(extension);

ResourceLocation nextShader = ResourceLocation.fromNamespaceAndPath(shader.getNamespace(), shader.getPath().substring(0, shader.getPath().length() - 3) + extension);
if (resourceProvider.getResource(nextShader).isPresent()) {
return nextShader;
}
}
return null;
}

@Override
protected @NotNull Preparations prepare(@NotNull ResourceManager resourceManager, @NotNull ProfilerFiller profilerFiller) {
Map<ResourceLocation, List<ShaderModification>> modifiers = new HashMap<>();
Map<ShaderModification, ResourceLocation> names = new HashMap<>();

for (Map.Entry<ResourceLocation, Resource> entry : MODIFIER_LISTER.listMatchingResources(resourceManager).entrySet()) {
ResourceLocation file = entry.getKey();
ResourceLocation id = MODIFIER_LISTER.fileToId(file);

try {
String[] parts = id.getPath().split("/", 2);
if (parts.length < 2) {
Veil.LOGGER.warn("Ignoring shader modifier {}. Expected format to be located in shader_modifiers/domain/shader_path.vsh.txt", file);
continue;
}

ResourceLocation shaderId = ResourceLocation.fromNamespaceAndPath(parts[0], parts[1]);
try (Reader reader = entry.getValue().openAsReader()) {
ShaderModification modification = ShaderModification.parse(IOUtils.toString(reader), shaderId.getPath().endsWith(".vsh"));
List<ShaderModification> modifications = modifiers.computeIfAbsent(shaderId, name -> new LinkedList<>());

if (modification instanceof ReplaceShaderModification) {
// TODO This doesn't respect priority
modifications.clear();
}
if (modifications.size() != 1 || !(modifications.getFirst() instanceof ReplaceShaderModification)) {
modifications.add(modification);
}
names.put(modification, id);
}
} catch (Exception e) {
Veil.LOGGER.error("Couldn't parse data file {} from {}", id, file, e);
}
}

// Inject inputs to next shader stage
for (Map.Entry<ResourceLocation, List<ShaderModification>> entry : new HashMap<>(modifiers).entrySet()) {
ResourceLocation nextStage = null;

for (ShaderModification modification : entry.getValue()) {
if (!(modification instanceof SimpleShaderModification simpleMod)) {
continue;
}

String output = simpleMod.getOutput();
if (StringUtil.isNullOrEmpty(output)) {
continue;
}

if (nextStage == null) {
nextStage = this.getNextStage(entry.getKey(), resourceManager);
}
if (nextStage == null) {
// No need to inject in into next shader
break;
}

InputShaderModification input = new InputShaderModification(simpleMod.priority(), OUT_PATTERN.matcher(simpleMod.fillPlaceholders(simpleMod.getOutput())).replaceAll("in "));
modifiers.computeIfAbsent(nextStage, unused -> new LinkedList<>()).add(input);
names.put(input, names.get(simpleMod));
}
}
modifiers.values().forEach(modifications -> modifications.sort(Comparator.comparingInt(ShaderModification::priority).thenComparing(names::get)));

return new Preparations(modifiers, names);
return new Preparations();
}

@Override
protected void apply(@NotNull Preparations preparations, @NotNull ResourceManager resourceManager, @NotNull ProfilerFiller profilerFiller) {
this.shaders = Collections.unmodifiableMap(preparations.shaders);
this.names = Collections.unmodifiableMap(preparations.names);
Veil.LOGGER.info("Loaded {} shader modifications", this.names.size());
}

/**
* @deprecated Use {@link ShaderInjectionManager} instead.
*/
@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
@Deprecated(forRemoval = true)
@ApiStatus.Internal
public record Preparations(Map<ResourceLocation, List<ShaderModification>> shaders,
Map<ShaderModification, ResourceLocation> names) {
public record Preparations() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package foundry.veil.api.client.render.shader.processor;

import foundry.veil.Veil;
import foundry.veil.api.client.render.VeilRenderSystem;
import foundry.veil.impl.client.render.shader.injection.ShaderInjectionManager;
import foundry.veil.impl.client.render.shader.injection.util.ShaderInjection;
import io.github.ocelot.glslprocessor.api.GlslSyntaxException;
import io.github.ocelot.glslprocessor.api.node.GlslTree;
import io.github.ocelot.glslprocessor.lib.anarres.cpp.LexerException;
import net.minecraft.resources.ResourceLocation;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Injects shader modifications into shader source files.
*
* @author Ocelot
* @author Vowxky
*/
public class ShaderInjectProcessor implements ShaderPreProcessor {

private final ShaderInjectionManager shaderInjectionManager;
private final Set<ResourceLocation> appliedModifications;

public ShaderInjectProcessor() {
this.shaderInjectionManager = VeilRenderSystem.renderer().getShaderInjectionManager();
this.appliedModifications = new HashSet<>();
}

@Override
public void prepare() {
this.appliedModifications.clear();
}

@Override
public void modify(Context ctx, GlslTree tree) throws IOException, GlslSyntaxException, LexerException {
ResourceLocation name = ctx.name();
if (name == null || !this.appliedModifications.add(name)) {
return;
}

boolean applyVersion = ctx.isSourceFile();
for (ResourceLocation include : ctx.shaderImporter().addedImports()) {
this.applyModifiers(include, tree, applyVersion);
}
this.applyModifiers(name, tree, applyVersion);
}

private void applyModifiers(ResourceLocation shaderId, GlslTree tree, boolean applyVersion) {
List<ShaderInjection> modifiers = this.shaderInjectionManager.getModifiers(shaderId);
if (modifiers.isEmpty()) {
return;
}
try {
for (ShaderInjection modifier : modifiers) {
modifier.inject(tree, applyVersion);
}
} catch (Exception e) {
Veil.LOGGER.error("Failed to transform shader: {}", shaderId, e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package foundry.veil.api.client.render.shader.processor;

import foundry.veil.api.client.render.VeilRenderSystem;
import foundry.veil.api.client.render.shader.ShaderModificationManager;
import foundry.veil.impl.client.render.shader.modifier.VeilJobParameters;
import foundry.veil.impl.client.render.shader.injection.ShaderInjectionManager;
import io.github.ocelot.glslprocessor.api.GlslSyntaxException;
import io.github.ocelot.glslprocessor.api.node.GlslTree;
import io.github.ocelot.glslprocessor.lib.anarres.cpp.LexerException;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.ApiStatus;

import java.io.IOException;
import java.util.HashSet;
Expand All @@ -16,14 +16,17 @@
* Modifies shader sources with the shader modification system.
*
* @author Ocelot
* @deprecated Use {@link ShaderInjectProcessor} instead.
*/
@ApiStatus.ScheduledForRemoval(inVersion = "5.0.0")
@Deprecated(forRemoval = true)
public class ShaderModifyProcessor implements ShaderPreProcessor {

private final ShaderModificationManager shaderModificationManager;
private final ShaderInjectionManager shaderInjectionManager;
private final Set<ResourceLocation> appliedModifications;

public ShaderModifyProcessor() {
this.shaderModificationManager = VeilRenderSystem.renderer().getShaderModificationManager();
this.shaderInjectionManager = VeilRenderSystem.renderer().getShaderInjectionManager();
this.appliedModifications = new HashSet<>();
}

Expand All @@ -38,10 +41,10 @@ public void modify(Context ctx, GlslTree tree) throws IOException, GlslSyntaxExc
if (name == null || !this.appliedModifications.add(name)) {
return;
}
int flags = ctx.isSourceFile() ? VeilJobParameters.APPLY_VERSION | VeilJobParameters.ALLOW_OUT : 0;
for (ResourceLocation include : ctx.shaderImporter().addedImports()) { // Run include modifiers first
this.shaderModificationManager.applyModifiers(include, tree, flags);
boolean applyVersion = ctx.isSourceFile();
for (ResourceLocation include : ctx.shaderImporter().addedImports()) {
this.shaderInjectionManager.applyModifiers(include, tree, applyVersion);
}
this.shaderModificationManager.applyModifiers(name, tree, flags);
this.shaderInjectionManager.applyModifiers(name, tree, applyVersion);
}
}
Loading
Loading