Reduced to fragments

- Overhaul shader pipeline
  - Remove VertexType#getShaderHeader in favor of vertex-only "layout
shaders"
  - Remove program specs in favor of vertex-only "instance shaders"
  - Add API GLSL headers for vertex and fragment shaders that store
common values
  - Separate context shaders into vertex and fragment shader files
- Improve import handling
  - Ensure imports are not added more than once
  - Change regex for import directives to be more in line with C-style
directives
- Move some classes and GLSL files
This commit is contained in:
PepperCode1 2022-05-15 01:58:33 -07:00
parent 4c7b035f5d
commit a11bf3537b
73 changed files with 476 additions and 700 deletions

View file

@ -13,6 +13,8 @@ import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.StitchedSprite; import com.jozufozu.flywheel.core.StitchedSprite;
import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.compile.ProgramCompiler;
import com.jozufozu.flywheel.core.materials.InstanceShaders;
import com.jozufozu.flywheel.core.vertex.LayoutShaders;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor; import com.jozufozu.flywheel.mixin.PausedPartialTickAccessor;
import com.jozufozu.flywheel.vanilla.VanillaInstances; import com.jozufozu.flywheel.vanilla.VanillaInstances;
@ -73,6 +75,8 @@ public class Flywheel {
forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll); forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
forgeEventBus.addListener(Models::onReload); forgeEventBus.addListener(Models::onReload);
modEventBus.addListener(LayoutShaders::flwInit);
modEventBus.addListener(InstanceShaders::flwInit);
modEventBus.addListener(Contexts::flwInit); modEventBus.addListener(Contexts::flwInit);
modEventBus.addListener(PartialModel::onModelRegistry); modEventBus.addListener(PartialModel::onModelRegistry);
modEventBus.addListener(PartialModel::onModelBake); modEventBus.addListener(PartialModel::onModelBake);

View file

@ -1,8 +1,7 @@
package com.jozufozu.flywheel.api.struct; package com.jozufozu.flywheel.api.struct;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.source.FileResolution;
import net.minecraft.resources.ResourceLocation;
public interface Instanced<S> extends StructType<S> { public interface Instanced<S> extends StructType<S> {
/** /**
@ -12,6 +11,5 @@ public interface Instanced<S> extends StructType<S> {
*/ */
StructWriter<S> getWriter(VecBuffer backing); StructWriter<S> getWriter(VecBuffer backing);
ResourceLocation getProgramSpec(); FileResolution getInstanceShader();
} }

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.api.vertex;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.source.FileResolution;
/** /**
* A vertex type containing metadata about a specific vertex layout. * A vertex type containing metadata about a specific vertex layout.
@ -32,7 +33,7 @@ public interface VertexType {
*/ */
VertexList createReader(ByteBuffer buffer, int vertexCount); VertexList createReader(ByteBuffer buffer, int vertexCount);
String getShaderHeader(); FileResolution getLayoutShader();
default int getStride() { default int getStride() {
return getLayout().getStride(); return getLayout().getStride();

View file

@ -8,11 +8,9 @@ import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine; import com.jozufozu.flywheel.backend.instancing.ParallelTaskEngine;
import com.jozufozu.flywheel.config.BackendType; import com.jozufozu.flywheel.config.BackendType;
import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.core.shader.ProgramSpec;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
@ -53,11 +51,6 @@ public class Backend {
return backendType == null ? "Uninitialized" : backendType.getProperName(); return backendType == null ? "Uninitialized" : backendType.getProperName();
} }
@Nullable
public static ProgramSpec getSpec(ResourceLocation name) {
return loader.get(name);
}
public static void refresh() { public static void refresh() {
backendType = chooseEngine(); backendType = chooseEngine();
} }

View file

@ -1,32 +1,15 @@
package com.jozufozu.flywheel.backend; package com.jozufozu.flywheel.backend;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.core.GameStateRegistry; import com.jozufozu.flywheel.core.GameStateRegistry;
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
import com.jozufozu.flywheel.core.shader.ProgramSpec;
import com.jozufozu.flywheel.core.source.Resolver; import com.jozufozu.flywheel.core.source.Resolver;
import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.ShaderSources;
import com.jozufozu.flywheel.event.GatherContextEvent; import com.jozufozu.flywheel.event.GatherContextEvent;
import com.jozufozu.flywheel.util.ResourceUtil;
import com.jozufozu.flywheel.util.StringUtil;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ReloadableResourceManager; import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener; import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.minecraftforge.fml.ModLoader; import net.minecraftforge.fml.ModLoader;
@ -39,11 +22,6 @@ import net.minecraftforge.fml.ModLoader;
* </p> * </p>
*/ */
public class Loader implements ResourceManagerReloadListener { public class Loader implements ResourceManagerReloadListener {
public static final String PROGRAM_DIR = "flywheel/programs/";
private static final Gson GSON = new GsonBuilder().create();
private final Map<ResourceLocation, ProgramSpec> programs = new HashMap<>();
private boolean firstLoad = true; private boolean firstLoad = true;
Loader() { Loader() {
@ -57,11 +35,6 @@ public class Loader implements ResourceManagerReloadListener {
} }
} }
@Nullable
public ProgramSpec get(ResourceLocation name) {
return programs.get(name);
}
@Override @Override
public void onResourceManagerReload(ResourceManager manager) { public void onResourceManagerReload(ResourceManager manager) {
Backend.refresh(); Backend.refresh();
@ -74,8 +47,6 @@ public class Loader implements ResourceManagerReloadListener {
ShaderSources sources = new ShaderSources(manager); ShaderSources sources = new ShaderSources(manager);
loadProgramSpecs(manager);
Resolver.INSTANCE.run(sources); Resolver.INSTANCE.run(sources);
Backend.LOGGER.info("Loaded all shader sources."); Backend.LOGGER.info("Loaded all shader sources.");
@ -89,35 +60,4 @@ public class Loader implements ResourceManagerReloadListener {
firstLoad = false; firstLoad = false;
} }
private void loadProgramSpecs(ResourceManager manager) {
programs.clear();
Collection<ResourceLocation> programSpecs = manager.listResources(PROGRAM_DIR, s -> s.endsWith(".json"));
for (ResourceLocation location : programSpecs) {
try (Resource file = manager.getResource(location)) {
String s = StringUtil.readToString(file.getInputStream());
ResourceLocation specName = ResourceUtil.trim(location, PROGRAM_DIR, ".json");
DataResult<Pair<ProgramSpec, JsonElement>> result = ProgramSpec.CODEC.decode(JsonOps.INSTANCE, GSON.fromJson(s, JsonElement.class));
ProgramSpec spec = result.get()
.orThrow()
.getFirst();
spec.setName(specName);
if (programs.containsKey(specName)) {
throw new IllegalStateException("Program spec '" + specName + "' already registered.");
}
programs.put(specName, spec);
} catch (Exception e) {
Backend.LOGGER.error("Could not load program " + location, e);
}
}
}
} }

View file

@ -21,10 +21,20 @@ public class GlShader extends GlObject {
GlCompat.safeShaderSource(handle, source); GlCompat.safeShaderSource(handle, source);
GL20.glCompileShader(handle); GL20.glCompileShader(handle);
// File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources");
// dir.mkdirs();
// File file = new File(dir, name.toString().replaceAll("[:/]", "_"));
// try (FileWriter writer = new FileWriter(file)) {
// writer.write(source);
// } catch (Exception e) {
// e.printStackTrace();
// }
// String log = GL20.glGetShaderInfoLog(handle); // String log = GL20.glGetShaderInfoLog(handle);
// //
// if (!log.isEmpty()) { // if (!log.isEmpty()) {
// env.printShaderInfoLog(source, log, this.name); // System.out.println(log);
//// env.printShaderInfoLog(source, log, this.name);
// } // }
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) { if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {

View file

@ -5,7 +5,7 @@ import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance; import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.materials.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.GridAlignedBB;

View file

@ -14,13 +14,14 @@ import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.model.MeshPool; import com.jozufozu.flywheel.backend.model.MeshPool;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.core.CoreShaderInfoMap; import com.jozufozu.flywheel.core.CoreShaderInfoMap;
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo; import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
import com.jozufozu.flywheel.core.GameStateRegistry;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.compile.ProgramCompiler;
import com.jozufozu.flywheel.core.compile.ProgramContext; import com.jozufozu.flywheel.core.compile.ProgramContext;
import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.core.vertex.Formats;
import com.jozufozu.flywheel.util.Textures; import com.jozufozu.flywheel.util.Textures;
import com.jozufozu.flywheel.util.WeakHashSet; import com.jozufozu.flywheel.util.WeakHashSet;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@ -32,7 +33,6 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.ShaderInstance; import net.minecraft.client.renderer.ShaderInstance;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i; import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
public class InstancingEngine<P extends WorldProgram> implements Engine { public class InstancingEngine<P extends WorldProgram> implements Engine {
@ -118,7 +118,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
if (!toRender.isEmpty()) { if (!toRender.isEmpty()) {
Instanced<? extends InstanceData> instanceType = entry.getKey(); Instanced<? extends InstanceData> instanceType = entry.getKey();
setup(instanceType.getProgramSpec(), coreShaderInfo, camX, camY, camZ, viewProjection, level); setup(instanceType, coreShaderInfo, camX, camY, camZ, viewProjection, level);
instanceCount += material.getInstanceCount(); instanceCount += material.getInstanceCount();
vertexCount += material.getVertexCount(); vertexCount += material.getVertexCount();
@ -145,7 +145,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
return coreShaderInfo; return coreShaderInfo;
} }
protected P setup(ResourceLocation programSpec, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) { protected P setup(Instanced<?> instanceType, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
float alphaDiscard = coreShaderInfo.alphaDiscard(); float alphaDiscard = coreShaderInfo.alphaDiscard();
if (alphaDiscard == 0) { if (alphaDiscard == 0) {
alphaDiscard = 0.0001f; alphaDiscard = 0.0001f;
@ -153,7 +153,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
alphaDiscard = 0; alphaDiscard = 0;
} }
P program = context.getProgram(ProgramContext.create(programSpec, Formats.POS_TEX_NORMAL, alphaDiscard, coreShaderInfo.fogType())); P program = context.getProgram(new ProgramContext(Formats.POS_TEX_NORMAL, instanceType.getInstanceShader(), alphaDiscard, coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
program.bind(); program.bind();
program.uploadUniforms(camX, camY, camZ, viewProjection, level); program.uploadUniforms(camX, camY, camZ, viewProjection, level);

View file

@ -20,11 +20,13 @@ public class Contexts {
public static void flwInit(GatherContextEvent event) { public static void flwInit(GatherContextEvent event) {
GameStateRegistry.register(NormalDebugStateProvider.INSTANCE); GameStateRegistry.register(NormalDebugStateProvider.INSTANCE);
FileResolution worldBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".glsl")); FileResolution worldVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".vert"));
FileResolution crumblingBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".glsl")); FileResolution worldFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".frag"));
FileResolution crumblingVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
FileResolution crumblingFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".frag"));
WORLD = ProgramCompiler.create(Templates.INSTANCING, WorldProgram::new, worldBuiltins); WORLD = ProgramCompiler.create(WorldProgram::new, Templates.INSTANCING, Templates.FRAGMENT, worldVertex, worldFragment);
CRUMBLING = ProgramCompiler.create(Templates.INSTANCING, CrumblingProgram::new, crumblingBuiltins); CRUMBLING = ProgramCompiler.create(CrumblingProgram::new, Templates.INSTANCING, Templates.FRAGMENT, crumblingVertex, crumblingFragment);
} }
public static class Names { public static class Names {

View file

@ -1,10 +0,0 @@
package com.jozufozu.flywheel.core;
import com.jozufozu.flywheel.Flywheel;
import net.minecraft.resources.ResourceLocation;
public class Programs {
public static final ResourceLocation TRANSFORMED = Flywheel.rl("model");
public static final ResourceLocation ORIENTED = Flywheel.rl("oriented");
}

View file

@ -12,12 +12,11 @@ public class CompileUtil {
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$"); public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
protected static String generateHeader(GLSLVersion version, ShaderType type) { protected static String generateHeader(GLSLVersion version, ShaderType type) {
return "#version " return "#version " + version + '\n'
+ version
+ '\n'
+ "#extension GL_ARB_explicit_attrib_location : enable\n" + "#extension GL_ARB_explicit_attrib_location : enable\n"
+ "#extension GL_ARB_conservative_depth : enable\n" + "#extension GL_ARB_conservative_depth : enable\n"
+ type.getDefineStatement(); + type.getDefineStatement()
+ '\n';
} }
public static int getElementCount(String type) { public static int getElementCount(String type) {

View file

@ -9,15 +9,14 @@ import com.jozufozu.flywheel.core.shader.ShaderConstants;
import com.jozufozu.flywheel.core.shader.StateSnapshot; import com.jozufozu.flywheel.core.shader.StateSnapshot;
import com.jozufozu.flywheel.core.source.FileIndexImpl; import com.jozufozu.flywheel.core.source.FileIndexImpl;
import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.source.SourceFile;
public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShader> { public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShader> {
private final Template<? extends FragmentData> template; private final Template<? extends FragmentData> template;
private final FileResolution header; private final FileResolution contextShader;
public FragmentCompiler(Template<? extends FragmentData> template, FileResolution header) { public FragmentCompiler(Template<? extends FragmentData> template, FileResolution contextShader) {
this.header = header;
this.template = template; this.template = template;
this.contextShader = contextShader;
} }
@Override @Override
@ -27,16 +26,16 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.FRAGMENT)); finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.FRAGMENT));
key.getShaderConstants().writeInto(finalSource); key.getShaderConstants().writeInto(finalSource);
finalSource.append('\n');
FileIndexImpl index = new FileIndexImpl(); FileIndexImpl index = new FileIndexImpl();
header.getFile().generateFinalSource(index, finalSource); contextShader.getFile().generateFinalSource(index, finalSource);
key.file.generateFinalSource(index, finalSource);
FragmentData appliedTemplate = template.apply(key.file); FragmentData appliedTemplate = template.apply(contextShader.getFile());
finalSource.append(appliedTemplate.generateFooter()); finalSource.append(appliedTemplate.generateFooter());
return new GlShader(key.file.name, ShaderType.FRAGMENT, finalSource.toString()); return new GlShader(contextShader.getFile().name, ShaderType.FRAGMENT, finalSource.toString());
} }
@Override @Override
@ -48,11 +47,6 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
* Represents the conditions under which a shader is compiled. * Represents the conditions under which a shader is compiled.
*/ */
public static final class Context { public static final class Context {
/**
* The file to compile.
*/
private final SourceFile file;
/** /**
* The shader constants to apply. * The shader constants to apply.
*/ */
@ -68,11 +62,10 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
*/ */
private final FogType fogType; private final FogType fogType;
public Context(SourceFile file, StateSnapshot ctx, float alphaDiscard, FogType fogType) { public Context(float alphaDiscard, FogType fogType, StateSnapshot ctx) {
this.file = file;
this.ctx = ctx;
this.alphaDiscard = alphaDiscard; this.alphaDiscard = alphaDiscard;
this.fogType = fogType; this.fogType = fogType;
this.ctx = ctx;
} }
public ShaderConstants getShaderConstants() { public ShaderConstants getShaderConstants() {
@ -91,17 +84,17 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
if (obj == this) return true; if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false; if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (Context) obj; var that = (Context) obj;
return this.file == that.file && Objects.equals(this.ctx, that.ctx) && Float.floatToIntBits(this.alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType; return Objects.equals(this.ctx, that.ctx) && Float.floatToIntBits(this.alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(file, ctx, alphaDiscard, fogType); return Objects.hash(alphaDiscard, fogType, ctx);
} }
@Override @Override
public String toString() { public String toString() {
return "Context[" + "file=" + file + ", " + "ctx=" + ctx + ", " + "alphaDiscard=" + alphaDiscard + ", " + "fogType=" + fogType + ']'; return "Context[" + "alphaDiscard=" + alphaDiscard + ", " + "fogType=" + fogType + ", " + "ctx=" + ctx + ']';
} }
} }

View file

@ -3,85 +3,46 @@ package com.jozufozu.flywheel.core.compile;
import java.util.Optional; import java.util.Optional;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.core.source.SourceFile;
import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.source.error.ErrorReporter;
import com.jozufozu.flywheel.core.source.parse.ShaderFunction; import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
import com.jozufozu.flywheel.core.source.parse.StructField;
import com.jozufozu.flywheel.core.source.parse.Variable; import com.jozufozu.flywheel.core.source.parse.Variable;
import com.jozufozu.flywheel.core.source.span.Span;
public class FragmentTemplateData implements FragmentData { public class FragmentTemplateData implements FragmentData {
public final SourceFile file; public final SourceFile file;
public final Span interpolantName; public final ShaderFunction contextFragment;
public final ShaderStruct interpolant;
public final ShaderFunction fragmentMain;
public FragmentTemplateData(SourceFile file) { public FragmentTemplateData(SourceFile file) {
this.file = file; this.file = file;
Optional<ShaderFunction> maybeFragmentMain = file.findFunction("fragment"); Optional<ShaderFunction> maybeContextFragment = file.findFunction("flw_contextFragment");
if (maybeFragmentMain.isEmpty()) { if (maybeContextFragment.isEmpty()) {
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined"); ErrorReporter.generateMissingFunction(file, "flw_contextFragment", "\"flw_contextFragment\" function not defined");
throw new RuntimeException(); throw new ShaderLoadingException();
} }
fragmentMain = maybeFragmentMain.get(); contextFragment = maybeContextFragment.get();
ImmutableList<Variable> fragmentParameters = fragmentMain.getParameters(); ImmutableList<Variable> params = contextFragment.getParameters();
if (fragmentParameters.size() != 1) { if (params.size() != 0) {
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument"); ErrorReporter.generateSpanError(contextFragment.getArgs(), "\"flw_contextFragment\" function must not have any arguments");
throw new RuntimeException(); throw new ShaderLoadingException();
} }
interpolantName = fragmentMain.getParameters().get(0).type;
Optional<ShaderStruct> maybeInterpolant = file.findStruct(interpolantName);
if (maybeInterpolant.isEmpty()) {
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
throw new RuntimeException();
}
interpolant = maybeInterpolant.get();
} }
@Override @Override
public String generateFooter() { public String generateFooter() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
prefixFields(builder, interpolant, "in", "v2f_");
builder.append(String.format(""" builder.append("""
void main() { void main() {
Fragment o; flw_contextFragment();
o.color = v2f_color;
o.texCoords = v2f_texCoords;
o.light = v2f_light;
o.diffuse = v2f_diffuse;
vec4 color = %s;
FLWFinalizeColor(color);
} }
""", """
fragmentMain.call("o") );
));
return builder.toString(); return builder.toString();
} }
public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) {
ImmutableList<StructField> fields = struct.getFields();
for (StructField field : fields) {
builder.append(qualifier)
.append(' ')
.append(field.type)
.append(' ')
.append(prefix)
.append(field.name)
.append(";\n");
}
}
} }

View file

@ -15,45 +15,30 @@ import com.jozufozu.flywheel.core.source.parse.Variable;
import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.core.source.span.Span;
public class InstancingTemplateData implements VertexData { public class InstancingTemplateData implements VertexData {
public final SourceFile file; public final SourceFile file;
public final ShaderFunction vertexMain; public final ShaderFunction instanceVertex;
public final Span vertexName;
public final Span instanceName; public final Span instanceName;
public final ShaderStruct instance; public final ShaderStruct instance;
public InstancingTemplateData(SourceFile file) { public InstancingTemplateData(SourceFile file) {
this.file = file; this.file = file;
Optional<ShaderFunction> vertexFunc = file.findFunction("vertex"); Optional<ShaderFunction> maybeInstanceVertex = file.findFunction("flw_instanceVertex");
if (vertexFunc.isEmpty()) { if (maybeInstanceVertex.isEmpty()) {
ErrorReporter.generateFileError(file, "could not find \"vertex\" function"); ErrorReporter.generateMissingFunction(file, "flw_instanceVertex", "\"flw_instanceVertex\" function not defined");
throw new ShaderLoadingException(); throw new ShaderLoadingException();
} }
vertexMain = vertexFunc.get(); instanceVertex = maybeInstanceVertex.get();
ImmutableList<Variable> vertexParams = vertexMain.getParameters(); ImmutableList<Variable> params = instanceVertex.getParameters();
if (vertexParams.size() != 2) { if (params.size() != 1) {
ErrorReporter.generateSpanError(vertexMain.getArgs(), "instancing requires vertex function to have 2 arguments"); ErrorReporter.generateSpanError(instanceVertex.getArgs(), "\"flw_contextFragment\" function must have exactly 1 argument");
throw new ShaderLoadingException(); throw new ShaderLoadingException();
} }
Variable vertexParam = vertexParams.get(0); instanceName = params.get(0).type;
vertexName = vertexParam.type;
boolean namedVertex = vertexParam.type
.toString()
.equals("Vertex");
if (!(namedVertex && vertexParam.qualifier == Variable.Qualifier.INOUT)) {
ErrorReporter.generateSpanError(vertexParam.qualifierSpan, "first parameter must be inout Vertex");
throw new ShaderLoadingException();
}
instanceName = vertexParams.get(1).type;
Optional<ShaderStruct> maybeInstance = file.findStruct(instanceName); Optional<ShaderStruct> maybeInstance = file.findStruct(instanceName);
if (maybeInstance.isEmpty()) { if (maybeInstance.isEmpty()) {
@ -80,36 +65,26 @@ public class InstancingTemplateData implements VertexData {
.append(' ') .append(' ')
.append(field.type) .append(field.type)
.append(' ') .append(' ')
.append("a_i_") .append("_flw_a_i_")
.append(field.name) .append(field.name)
.append(";\n"); .append(";\n");
attributeBinding += CompileUtil.getAttributeCount(field.type); attributeBinding += CompileUtil.getAttributeCount(field.type);
} }
template.append('\n');
template.append(String.format(""" template.append(String.format("""
out vec4 v2f_color;
out vec2 v2f_texCoords;
out vec2 v2f_light;
out float v2f_diffuse;
void main() { void main() {
Vertex v = FLWCreateVertex(); flw_layoutVertex();
%s i;
%s
vertex(v, i);
gl_Position = FLWVertex(v);
v.normal = normalize(v.normal);
v2f_color = v.color; %s instance;
v2f_texCoords = v.texCoords; %s
v2f_light = v.light; flw_instanceVertex(instance);
v2f_diffuse = FLWDiffuse(v.normal);
#if defined(DEBUG_NORMAL) flw_contextVertex();
v2f_color = vec4(v.normal, 1.);
#endif
} }
""", """,
instanceName, instanceName,
assignFields(instance, "i.", "a_i_") assignFields(instance, "instance.", "_flw_a_i_")
)); ));
return template.toString(); return template.toString();

View file

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.core.Templates;
import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
@ -33,15 +32,17 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
} }
/** /**
* Creates a program compiler using this template. * Creates a program compiler using provided templates and headers.
* @param template The vertex template to use.
* @param factory A factory to add meaning to compiled programs. * @param factory A factory to add meaning to compiled programs.
* @param header The header file to use for the program. * @param vertexTemplate The vertex template to use.
* @param fragmentTemplate The fragment template to use.
* @param vertexContextShader The context shader to use when compiling vertex shaders.
* @param fragmentContextShader The context shader to use when compiling fragment shaders.
* @param <P> The type of program to compile. * @param <P> The type of program to compile.
* @return A program compiler. * @return A program compiler.
*/ */
public static <T extends VertexData, P extends GlProgram> ProgramCompiler<P> create(Template<T> template, GlProgram.Factory<P> factory, FileResolution header) { public static <V extends VertexData, F extends FragmentData, P extends GlProgram> ProgramCompiler<P> create(GlProgram.Factory<P> factory, Template<V> vertexTemplate, Template<F> fragmentTemplate, FileResolution vertexContextShader, FileResolution fragmentContextShader) {
return new ProgramCompiler<>(factory, new VertexCompiler(template, header), new FragmentCompiler(Templates.FRAGMENT, header)); return new ProgramCompiler<>(factory, new VertexCompiler(vertexTemplate, vertexContextShader), new FragmentCompiler(fragmentTemplate, fragmentContextShader));
} }
/** /**
@ -63,9 +64,9 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
@Override @Override
protected P _create(ProgramContext ctx) { protected P _create(ProgramContext ctx) {
return new ProgramAssembler(ctx.spec.name) return new ProgramAssembler(ctx.instanceShader.getFileLoc())
.attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.spec.getVertexFile(), ctx.ctx, ctx.vertexType))) .attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.vertexType, ctx.instanceShader.getFile(), ctx.ctx)))
.attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.spec.getFragmentFile(), ctx.ctx, ctx.alphaDiscard, ctx.fogType))) .attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.alphaDiscard, ctx.fogType, ctx.ctx)))
.link() .link()
.build(this.factory); .build(this.factory);
} }

View file

@ -3,54 +3,33 @@ package com.jozufozu.flywheel.core.compile;
import java.util.Objects; import java.util.Objects;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo.FogType; import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo.FogType;
import com.jozufozu.flywheel.core.GameStateRegistry;
import com.jozufozu.flywheel.core.shader.ProgramSpec;
import com.jozufozu.flywheel.core.shader.StateSnapshot; import com.jozufozu.flywheel.core.shader.StateSnapshot;
import com.jozufozu.flywheel.core.source.FileResolution;
import net.minecraft.resources.ResourceLocation;
/** /**
* Represents the entire context of a program's usage. * Represents the entire context of a program's usage.
*/ */
public final class ProgramContext { public final class ProgramContext {
/**
* Creates a compilation context for the given program, vertex type and render layer.
*
* @param programName The name of the program to use.
* @param vertexType The vertex type to use.
* @param alphaDiscard The alpha threshold below which pixels are discarded.
* @return A compilation context.
*/
public static ProgramContext create(ResourceLocation programName, VertexType vertexType, float alphaDiscard, FogType fogType) {
ProgramSpec spec = Backend.getSpec(programName);
if (spec == null) { public final VertexType vertexType;
throw new NullPointerException("Cannot compile shader because '" + programName + "' is not recognized."); public final FileResolution instanceShader;
}
return new ProgramContext(spec, alphaDiscard, fogType, vertexType, GameStateRegistry.takeSnapshot());
}
public final ProgramSpec spec;
public final float alphaDiscard; public final float alphaDiscard;
public final FogType fogType; public final FogType fogType;
public final VertexType vertexType;
public final StateSnapshot ctx; public final StateSnapshot ctx;
/** /**
* @param vertexType The vertexType the program should be adapted for.
* @param spec The program to use. * @param spec The program to use.
* @param alphaDiscard Alpha threshold below which pixels are discarded. * @param alphaDiscard Alpha threshold below which pixels are discarded.
* @param fogType Which type of fog should be applied. * @param fogType Which type of fog should be applied.
* @param vertexType The vertexType the program should be adapted for.
* @param ctx A snapshot of the game state. * @param ctx A snapshot of the game state.
*/ */
public ProgramContext(ProgramSpec spec, float alphaDiscard, FogType fogType, VertexType vertexType, StateSnapshot ctx) { public ProgramContext(VertexType vertexType, FileResolution instanceShader, float alphaDiscard, FogType fogType, StateSnapshot ctx) {
this.spec = spec; this.vertexType = vertexType;
this.instanceShader = instanceShader;
this.alphaDiscard = alphaDiscard; this.alphaDiscard = alphaDiscard;
this.fogType = fogType; this.fogType = fogType;
this.vertexType = vertexType;
this.ctx = ctx; this.ctx = ctx;
} }
@ -59,16 +38,16 @@ public final class ProgramContext {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
var that = (ProgramContext) o; var that = (ProgramContext) o;
return spec == that.spec && vertexType == that.vertexType && ctx.equals(that.ctx) && Float.floatToIntBits(alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType; return instanceShader == that.instanceShader && vertexType == that.vertexType && ctx.equals(that.ctx) && Float.floatToIntBits(alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(spec, alphaDiscard, fogType, vertexType, ctx); return Objects.hash(vertexType, instanceShader, alphaDiscard, fogType, ctx);
} }
@Override @Override
public String toString() { public String toString() {
return "ProgramContext{" + "spec=" + spec + ", alphaDiscard=" + alphaDiscard + ", fogType=" + fogType + ", vertexType=" + vertexType + ", ctx=" + ctx + '}'; return "ProgramContext{" + "vertexType=" + vertexType + ", instanceShader=" + instanceShader + ", alphaDiscard=" + alphaDiscard + ", fogType=" + fogType + ", ctx=" + ctx + '}';
} }
} }

View file

@ -12,11 +12,11 @@ import com.jozufozu.flywheel.core.source.SourceFile;
public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> { public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
private final Template<? extends VertexData> template; private final Template<? extends VertexData> template;
private final FileResolution header; private final FileResolution contextShader;
public VertexCompiler(Template<? extends VertexData> template, FileResolution header) { public VertexCompiler(Template<? extends VertexData> template, FileResolution contextShader) {
this.template = template; this.template = template;
this.header = header; this.contextShader = contextShader;
} }
@Override @Override
@ -26,28 +26,21 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX)); finalSource.append(CompileUtil.generateHeader(template.getVersion(), ShaderType.VERTEX));
key.ctx.getShaderConstants().writeInto(finalSource); key.ctx.getShaderConstants().writeInto(finalSource);
finalSource.append('\n');
finalSource.append("""
struct Vertex {
vec3 pos;
vec4 color;
vec2 texCoords;
vec2 light;
vec3 normal;
};
""");
finalSource.append(key.vertexType.getShaderHeader());
FileIndexImpl index = new FileIndexImpl(); FileIndexImpl index = new FileIndexImpl();
header.getFile().generateFinalSource(index, finalSource); FileResolution layoutShader = key.vertexType.getLayoutShader();
layoutShader.getFile().generateFinalSource(index, finalSource);
key.file.generateFinalSource(index, finalSource); contextShader.getFile().generateFinalSource(index, finalSource);
VertexData appliedTemplate = template.apply(key.file); key.instanceShader.generateFinalSource(index, finalSource);
VertexData appliedTemplate = template.apply(key.instanceShader);
finalSource.append(appliedTemplate.generateFooter(index, key.vertexType)); finalSource.append(appliedTemplate.generateFooter(index, key.vertexType));
return new GlShader(key.file.name, ShaderType.VERTEX, finalSource.toString()); return new GlShader(key.instanceShader.name, ShaderType.VERTEX, finalSource.toString());
} }
@Override @Override
@ -57,24 +50,24 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
public static class Context { public static class Context {
/** /**
* The file to compile. * The vertex type to use.
*/ */
private final SourceFile file; private final VertexType vertexType;
/**
* The instance shader source.
*/
private final SourceFile instanceShader;
/** /**
* The shader constants to apply. * The shader constants to apply.
*/ */
private final StateSnapshot ctx; private final StateSnapshot ctx;
/** public Context(VertexType vertexType, SourceFile instanceShader, StateSnapshot ctx) {
* The vertex type to use.
*/
private final VertexType vertexType;
public Context(SourceFile file, StateSnapshot ctx, VertexType vertexType) {
this.file = file;
this.ctx = ctx;
this.vertexType = vertexType; this.vertexType = vertexType;
this.instanceShader = instanceShader;
this.ctx = ctx;
} }
@Override @Override
@ -82,12 +75,12 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
var that = (Context) o; var that = (Context) o;
return file == that.file && vertexType == that.vertexType && ctx.equals(that.ctx); return vertexType == that.vertexType && instanceShader == that.instanceShader && ctx.equals(that.ctx);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(file, ctx, vertexType); return Objects.hash(vertexType, instanceShader, ctx);
} }
} }
} }

View file

@ -14,8 +14,8 @@ import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial; import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine; import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
import com.jozufozu.flywheel.core.Contexts; import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo; import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
import com.jozufozu.flywheel.core.RenderContext;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.mixin.LevelRendererAccessor; import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
import com.jozufozu.flywheel.util.Lazy; import com.jozufozu.flywheel.util.Lazy;
@ -191,7 +191,7 @@ public class CrumblingRenderer {
CoreShaderInfo coreShaderInfo = getCoreShaderInfo(); CoreShaderInfo coreShaderInfo = getCoreShaderInfo();
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) { for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
CrumblingProgram program = setup(entry.getKey().getProgramSpec(), coreShaderInfo, camX, camY, camZ, viewProjection, level); CrumblingProgram program = setup(entry.getKey(), coreShaderInfo, camX, camY, camZ, viewProjection, level);
program.setAtlasSize(width, height); program.setAtlasSize(width, height);

View file

@ -3,8 +3,8 @@ package com.jozufozu.flywheel.core.hardcoded;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.Mesh;
import com.jozufozu.flywheel.core.vertex.Formats;
import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex; import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex;
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
import com.mojang.blaze3d.platform.MemoryTracker; import com.mojang.blaze3d.platform.MemoryTracker;

View file

@ -0,0 +1,24 @@
package com.jozufozu.flywheel.core.materials;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.source.Resolver;
import com.jozufozu.flywheel.event.GatherContextEvent;
import com.jozufozu.flywheel.util.ResourceUtil;
import net.minecraft.resources.ResourceLocation;
public class InstanceShaders {
public static FileResolution MODEL;
public static FileResolution ORIENTED;
public static void flwInit(GatherContextEvent event) {
MODEL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.MODEL, ".vert"));
ORIENTED = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
}
public static class Names {
public static final ResourceLocation MODEL = Flywheel.rl("instance/model");
public static final ResourceLocation ORIENTED = Flywheel.rl("instance/oriented");
}
}

View file

@ -1,22 +1,12 @@
package com.jozufozu.flywheel.core; package com.jozufozu.flywheel.core.materials;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.materials.model.ModelType; import com.jozufozu.flywheel.core.materials.model.ModelType;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.core.materials.oriented.OrientedType; import com.jozufozu.flywheel.core.materials.oriented.OrientedType;
import net.minecraft.resources.ResourceLocation;
public class Materials { public class Materials {
public static final StructType<OrientedData> ORIENTED = new OrientedType();
public static final StructType<ModelData> TRANSFORMED = new ModelType(); public static final StructType<ModelData> TRANSFORMED = new ModelType();
public static final StructType<OrientedData> ORIENTED = new OrientedType();
public static class Names {
public static final ResourceLocation MODEL = Flywheel.rl("model");
public static final ResourceLocation ORIENTED = Flywheel.rl("oriented");
public static final ResourceLocation PASSTHRU = Flywheel.rl("passthru");
}
} }

View file

@ -4,12 +4,11 @@ import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.Programs;
import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.core.materials.InstanceShaders;
import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.core.model.ModelTransformer;
import com.jozufozu.flywheel.core.source.FileResolution;
import net.minecraft.resources.ResourceLocation;
public class ModelType implements Instanced<ModelData>, Batched<ModelData> { public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
@ -34,8 +33,8 @@ public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
} }
@Override @Override
public ResourceLocation getProgramSpec() { public FileResolution getInstanceShader() {
return Programs.TRANSFORMED; return InstanceShaders.MODEL;
} }
@Override @Override

View file

@ -4,14 +4,13 @@ import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.Instanced; import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.StructWriter; import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.Programs;
import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.core.materials.InstanceShaders;
import com.jozufozu.flywheel.core.model.ModelTransformer; import com.jozufozu.flywheel.core.model.ModelTransformer;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.mojang.math.Quaternion; import com.mojang.math.Quaternion;
import net.minecraft.resources.ResourceLocation;
public class OrientedType implements Instanced<OrientedData>, Batched<OrientedData> { public class OrientedType implements Instanced<OrientedData>, Batched<OrientedData> {
public static final BufferLayout FORMAT = BufferLayout.builder() public static final BufferLayout FORMAT = BufferLayout.builder()
@ -35,8 +34,8 @@ public class OrientedType implements Instanced<OrientedData>, Batched<OrientedDa
} }
@Override @Override
public ResourceLocation getProgramSpec() { public FileResolution getInstanceShader() {
return Programs.ORIENTED; return InstanceShaders.ORIENTED;
} }
@Override @Override

View file

@ -1,8 +1,8 @@
package com.jozufozu.flywheel.core.model; package com.jozufozu.flywheel.core.model;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.vertex.Formats;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;

View file

@ -8,7 +8,7 @@ import java.util.Random;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.vertex.Formats;
import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter; import com.jozufozu.flywheel.core.virtual.VirtualEmptyBlockGetter;
import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.DefaultVertexFormat;

View file

@ -1,68 +0,0 @@
package com.jozufozu.flywheel.core.shader;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.source.Resolver;
import com.jozufozu.flywheel.core.source.SourceFile;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.resources.ResourceLocation;
/**
* An object describing a shader program that can be loaded by flywheel.
*
* <p>
* These are defined through json. All ProgramSpecs in {@code assets/modid/flywheel/programs} are parsed and
* processed. One ProgramSpec typically specifies one "material" that can be used in game to render things.
* </p>
* <p>
* All shader source files in {@code assets/modid/flywheel/shaders} are completely loaded and parsed into
* {@link SourceFile SourceFiles}, but not compiled until one of them is
* referenced by a ProgramSpec.
* </p>
*/
public class ProgramSpec {
public static final Codec<ProgramSpec> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ResourceLocation.CODEC.fieldOf("vertex")
.forGetter(ProgramSpec::getSourceLoc),
ResourceLocation.CODEC.fieldOf("fragment")
.forGetter(ProgramSpec::getFragmentLoc))
.apply(instance, ProgramSpec::new));
public ResourceLocation name;
public final FileResolution vertex;
public final FileResolution fragment;
public ProgramSpec(ResourceLocation vertex, ResourceLocation fragment) {
this.vertex = Resolver.INSTANCE.get(vertex);
this.fragment = Resolver.INSTANCE.get(fragment);
}
public void setName(ResourceLocation name) {
this.name = name;
this.vertex.addSpec(name);
this.fragment.addSpec(name);
}
public ResourceLocation getSourceLoc() {
return vertex.getFileLoc();
}
public ResourceLocation getFragmentLoc() {
return fragment.getFileLoc();
}
public SourceFile getVertexFile() {
return vertex.getFile();
}
public SourceFile getFragmentFile() {
return fragment.getFile();
}
@Override
public String toString() {
return name.toString();
}
}

View file

@ -11,6 +11,8 @@ public interface FileIndex {
*/ */
int getFileID(SourceFile sourceFile); int getFileID(SourceFile sourceFile);
boolean exists(SourceFile sourceFile);
SourceFile getFile(int fileID); SourceFile getFile(int fileID);
default Span getLineSpan(int fileId, int lineNo) { default Span getLineSpan(int fileId, int lineNo) {

View file

@ -31,12 +31,16 @@ public class FileIndexImpl implements FileIndex {
return size; return size;
} }
@Override
public boolean exists(SourceFile sourceFile) {
return files.indexOf(sourceFile) != -1;
}
@Override @Override
public SourceFile getFile(int fileId) { public SourceFile getFile(int fileId) {
return files.get(fileId); return files.get(fileId);
} }
public void printShaderInfoLog(String source, String log, ResourceLocation name) { public void printShaderInfoLog(String source, String log, ResourceLocation name) {
List<String> lines = log.lines() List<String> lines = log.lines()
.toList(); .toList();

View file

@ -93,4 +93,9 @@ public class FileResolution {
extraCrashInfoProviders.clear(); extraCrashInfoProviders.clear();
file = null; file = null;
} }
@Override
public String toString() {
return "FileResolution[" + fileLoc + "]";
}
} }

View file

@ -53,7 +53,6 @@ public class ShaderSources implements SourceFinder {
@Override @Override
@Nullable @Nullable
public SourceFile findSource(ResourceLocation name) { public SourceFile findSource(ResourceLocation name) {
return shaderSources.get(name); return shaderSources.get(name);
} }
} }

View file

@ -2,11 +2,12 @@ package com.jozufozu.flywheel.core.source;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -27,10 +28,6 @@ import net.minecraft.resources.ResourceLocation;
* </p> * </p>
*/ */
public class SourceFile { public class SourceFile {
private static final Pattern includePattern = Pattern.compile("#use \"(.*)\"");
// https://regexr.com/60n3d
public static final Pattern functionDeclaration = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
public final ResourceLocation name; public final ResourceLocation name;
@ -141,15 +138,20 @@ public class SourceFile {
for (Import include : imports) { for (Import include : imports) {
SourceFile file = include.getFile(); SourceFile file = include.getFile();
if (file != null) file.generateFinalSource(env, source); if (file != null && !env.exists(file)) {
file.generateFinalSource(env, source);
}
} }
source.append("#line ") source.append("#line ")
.append(0) .append(0)
.append(' ') .append(' ')
.append(env.getFileID(this)) .append(env.getFileID(this))
.append(" // ")
.append(name)
.append('\n'); .append('\n');
source.append(elided); source.append(elided);
source.append('\n');
} }
public String printSource() { public String printSource() {
@ -176,7 +178,7 @@ public class SourceFile {
* Scan the source for function definitions and "parse" them into objects that contain properties of the function. * Scan the source for function definitions and "parse" them into objects that contain properties of the function.
*/ */
private ImmutableMap<String, ShaderFunction> parseFunctions() { private ImmutableMap<String, ShaderFunction> parseFunctions() {
Matcher matcher = functionDeclaration.matcher(source); Matcher matcher = ShaderFunction.functionDeclaration.matcher(source);
Map<String, ShaderFunction> functions = new HashMap<>(); Map<String, ShaderFunction> functions = new HashMap<>();
@ -210,7 +212,7 @@ public class SourceFile {
* Scan the source for function definitions and "parse" them into objects that contain properties of the function. * Scan the source for function definitions and "parse" them into objects that contain properties of the function.
*/ */
private ImmutableMap<String, ShaderStruct> parseStructs() { private ImmutableMap<String, ShaderStruct> parseStructs() {
Matcher matcher = ShaderStruct.struct.matcher(source); Matcher matcher = ShaderStruct.PATTERN.matcher(source);
ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder(); ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder();
while (matcher.find()) { while (matcher.find()) {
@ -232,15 +234,22 @@ public class SourceFile {
* @param elisions * @param elisions
*/ */
private ImmutableList<Import> parseImports(List<Span> elisions) { private ImmutableList<Import> parseImports(List<Span> elisions) {
Matcher uses = includePattern.matcher(source); Matcher uses = Import.PATTERN.matcher(source);
Set<String> importedFiles = new HashSet<>();
List<Import> imports = new ArrayList<>(); List<Import> imports = new ArrayList<>();
while (uses.find()) { while (uses.find()) {
Span use = Span.fromMatcher(this, uses); Span use = Span.fromMatcher(this, uses);
Span file = Span.fromMatcher(this, uses, 1); Span file = Span.fromMatcher(this, uses, 1);
imports.add(new Import(Resolver.INSTANCE, use, file)); String fileName = file.get();
if (importedFiles.add(fileName)) {
Import import1 = Import.create(Resolver.INSTANCE, use, file);
if (import1 != null) {
imports.add(import1);
}
}
elisions.add(use); // we have to trim that later elisions.add(use); // we have to trim that later
} }

View file

@ -25,7 +25,6 @@ public class ErrorReporter {
} }
public static void generateFileError(SourceFile file, String message) { public static void generateFileError(SourceFile file, String message) {
String error = ErrorBuilder.error(message) String error = ErrorBuilder.error(message)
.pointAtFile(file) .pointAtFile(file)
.build(); .build();

View file

@ -1,8 +1,7 @@
package com.jozufozu.flywheel.core.source.parse; package com.jozufozu.flywheel.core.source.parse;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.regex.Pattern;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -12,34 +11,31 @@ import com.jozufozu.flywheel.core.source.SourceFile;
import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.source.error.ErrorReporter;
import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.core.source.span.Span;
import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public class Import extends AbstractShaderElement { public class Import extends AbstractShaderElement {
public static final List<Import> IMPORTS = new ArrayList<>(); public static final Pattern PATTERN = Pattern.compile("^\\s*#\\s*use\\s+\"(.*)\"", Pattern.MULTILINE);
private final Span file;
private final FileResolution resolution; private final FileResolution resolution;
public Import(Resolver resolver, Span self, Span file) { protected Import(Span self, FileResolution resolution, Span file) {
super(self); super(self);
this.file = file; this.resolution = resolution.addSpan(file);
resolution = resolver.get(toRL(file))
.addSpan(file);
IMPORTS.add(this);
} }
private ResourceLocation toRL(Span file) { @Nullable
public static Import create(Resolver resolver, Span self, Span file) {
ResourceLocation fileLocation;
try { try {
return new ResourceLocation(file.get()); fileLocation = new ResourceLocation(file.get());
} catch (RuntimeException error) { } catch (ResourceLocationException e) {
ErrorReporter.generateSpanError(file, "malformed source name"); ErrorReporter.generateSpanError(file, "malformed source location");
return null;
} }
return new ResourceLocation(""); return new Import(self, resolver.get(fileLocation), file);
} }
public FileResolution getResolution() { public FileResolution getResolution() {

View file

@ -9,6 +9,9 @@ import com.jozufozu.flywheel.core.source.span.Span;
public class ShaderFunction extends AbstractShaderElement { public class ShaderFunction extends AbstractShaderElement {
// https://regexr.com/60n3d
public static final Pattern functionDeclaration = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
public static final Pattern argument = Pattern.compile("(?:(inout|in|out) )?(\\w+)\\s+(\\w+)"); public static final Pattern argument = Pattern.compile("(?:(inout|in|out) )?(\\w+)\\s+(\\w+)");
public static final Pattern assignment = Pattern.compile("(\\w+)\\s*="); public static final Pattern assignment = Pattern.compile("(\\w+)\\s*=");

View file

@ -10,7 +10,7 @@ import com.jozufozu.flywheel.core.source.span.Span;
public class ShaderStruct extends AbstractShaderElement { public class ShaderStruct extends AbstractShaderElement {
// https://regexr.com/61rpe // https://regexr.com/61rpe
public static final Pattern struct = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d\\s,;]*)}\\s*;\\s"); public static final Pattern PATTERN = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d\\s,;]*)}\\s*;\\s");
public final Span name; public final Span name;
public final Span body; public final Span body;

View file

@ -7,6 +7,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder; import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
@ -38,24 +39,8 @@ public class BlockVertex implements VertexType {
} }
@Override @Override
public String getShaderHeader() { public FileResolution getLayoutShader() {
return """ return LayoutShaders.BLOCK;
layout (location = 0) in vec3 _flw_v_pos;
layout (location = 1) in vec4 _flw_v_color;
layout (location = 2) in vec2 _flw_v_texCoords;
layout (location = 3) in vec2 _flw_v_light;
layout (location = 4) in vec3 _flw_v_normal;
Vertex FLWCreateVertex() {
Vertex v;
v.pos = _flw_v_pos;
v.color = _flw_v_color;
v.texCoords = _flw_v_texCoords;
v.light = _flw_v_light;
v.normal = _flw_v_normal;
return v;
}
""";
} }
public BlockVertexListUnsafe.Shaded createReader(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) { public BlockVertexListUnsafe.Shaded createReader(ByteBuffer buffer, int vertexCount, int unshadedStartVertex) {

View file

@ -5,7 +5,6 @@ import java.nio.ByteBuffer;
import com.jozufozu.flywheel.api.vertex.ShadedVertexList; import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder; import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
import com.jozufozu.flywheel.util.RenderMath; import com.jozufozu.flywheel.util.RenderMath;
import com.mojang.blaze3d.vertex.BufferBuilder; import com.mojang.blaze3d.vertex.BufferBuilder;

View file

@ -7,7 +7,6 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.vertex.ShadedVertexList; import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.util.RenderMath; import com.jozufozu.flywheel.util.RenderMath;
public class BlockVertexListUnsafe implements VertexList { public class BlockVertexListUnsafe implements VertexList {

View file

@ -1,10 +1,6 @@
package com.jozufozu.flywheel.core; package com.jozufozu.flywheel.core.vertex;
import com.jozufozu.flywheel.core.vertex.BlockVertex;
import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex;
public class Formats { public class Formats {
public static final PosTexNormalVertex POS_TEX_NORMAL = new PosTexNormalVertex();
public static final BlockVertex BLOCK = new BlockVertex(); public static final BlockVertex BLOCK = new BlockVertex();
public static final PosTexNormalVertex POS_TEX_NORMAL = new PosTexNormalVertex();
} }

View file

@ -0,0 +1,24 @@
package com.jozufozu.flywheel.core.vertex;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.source.Resolver;
import com.jozufozu.flywheel.event.GatherContextEvent;
import com.jozufozu.flywheel.util.ResourceUtil;
import net.minecraft.resources.ResourceLocation;
public class LayoutShaders {
public static FileResolution BLOCK;
public static FileResolution POS_TEX_NORMAL;
public static void flwInit(GatherContextEvent event) {
BLOCK = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.BLOCK, ".vert"));
POS_TEX_NORMAL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
}
public static class Names {
public static final ResourceLocation BLOCK = Flywheel.rl("layout/block");
public static final ResourceLocation POS_TEX_NORMAL = Flywheel.rl("layout/pos_tex_normal");
}
}

View file

@ -5,6 +5,7 @@ import java.nio.ByteBuffer;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.layout.BufferLayout; import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.CommonItems; import com.jozufozu.flywheel.core.layout.CommonItems;
import com.jozufozu.flywheel.core.source.FileResolution;
public class PosTexNormalVertex implements VertexType { public class PosTexNormalVertex implements VertexType {
@ -28,21 +29,7 @@ public class PosTexNormalVertex implements VertexType {
} }
@Override @Override
public String getShaderHeader() { public FileResolution getLayoutShader() {
return """ return LayoutShaders.POS_TEX_NORMAL;
layout (location = 0) in vec3 _flw_v_pos;
layout (location = 1) in vec2 _flw_v_texCoords;
layout (location = 2) in vec3 _flw_v_normal;
Vertex FLWCreateVertex() {
Vertex v;
v.pos = _flw_v_pos;
v.color = vec4(1.);
v.texCoords = _flw_v_texCoords;
v.light = vec2(0.);
v.normal = _flw_v_normal;
return v;
}
""";
} }
} }

View file

@ -6,7 +6,6 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.util.RenderMath; import com.jozufozu.flywheel.util.RenderMath;
public class PosTexNormalVertexListUnsafe implements VertexList { public class PosTexNormalVertexListUnsafe implements VertexList {

View file

@ -6,8 +6,8 @@ import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.BasicModelSupplier;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.Materials;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.mojang.math.Quaternion; import com.mojang.math.Quaternion;

View file

@ -9,8 +9,8 @@ import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.BasicModelSupplier;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData; import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;

View file

@ -7,9 +7,9 @@ import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance; import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance; import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.BasicModelSupplier;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.Models; import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.model.Mesh; import com.jozufozu.flywheel.core.model.Mesh;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;

View file

@ -6,8 +6,8 @@ import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance; import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.BasicModelSupplier; import com.jozufozu.flywheel.core.BasicModelSupplier;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.hardcoded.ModelPart; import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.Materials;
import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;

View file

@ -1,4 +0,0 @@
{
"vertex": "flywheel:model.vert",
"fragment": "flywheel:block.frag"
}

View file

@ -1,4 +0,0 @@
{
"vertex": "flywheel:oriented.vert",
"fragment": "flywheel:block.frag"
}

View file

@ -1,4 +0,0 @@
{
"vertex": "flywheel:passthru.vert",
"fragment": "flywheel:block.frag"
}

View file

@ -0,0 +1,12 @@
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
in float flw_distance;
in vec4 flw_var0;
in vec4 flw_var1;
in vec4 flw_var2;
in vec4 flw_var3;

View file

@ -0,0 +1,12 @@
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
out vec4 flw_var0;
out vec4 flw_var1;
out vec4 flw_var2;
out vec4 flw_var3;

View file

@ -1,13 +0,0 @@
struct Fragment {
vec2 texCoords;
vec4 color;
float diffuse;
vec2 light;
};
vec4 fragment(Fragment r) {
vec4 tex = FLWBlockTexture(r.texCoords);
return vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color;
}

View file

@ -0,0 +1,26 @@
#use "flywheel:api/vertex.glsl"
#use "flywheel:util/diffuse.glsl"
#use "flywheel:util/fog.glsl"
uniform mat4 uViewProjection;
uniform vec3 uCameraPos;
uniform int uConstantAmbientLight;
uniform int uFogShape;
out float _flw_diffuse;
void flw_contextVertex() {
flw_vertexNormal = normalize(flw_vertexNormal);
if (uConstantAmbientLight == 1) {
_flw_diffuse = diffuseNether(flw_vertexNormal);
} else {
_flw_diffuse = diffuse(flw_vertexNormal);
}
flw_distance = fog_distance(flw_vertexPos.xyz, uCameraPos, uFogShape);
gl_Position = uViewProjection * flw_vertexPos;
// TODO: remove this
#ifdef DEBUG_NORMAL
flw_vertexColor = vec4(flw_vertexNormal, 1.0);
#endif
}

View file

@ -0,0 +1,34 @@
#use "flywheel:api/fragment.glsl"
#use "flywheel:util/fog.glsl"
uniform vec2 uFogRange;
uniform vec4 uFogColor;
uniform vec2 uTextureScale;
uniform sampler2D uBlockAtlas;
uniform sampler2D uCrumbling;
in float _flw_diffuse;
out vec4 fragColor;
void flw_contextFragment() {
vec4 texColor = texture(uBlockAtlas, flw_vertexTexCoord);
vec4 crumblingColor = texture(uCrumbling, flw_vertexTexCoord * uTextureScale);
crumblingColor.a *= texColor.a;
vec4 color = flw_vertexColor * vec4(crumblingColor.rgb * _flw_diffuse, crumblingColor.a);
#ifdef ALPHA_DISCARD
if (color.a < ALPHA_DISCARD) {
discard;
}
#endif
#ifdef COLOR_FOG
color = linear_fog(color, flw_distance, uFogRange.x, uFogRange.y, uFogColor);
#elif defined(FADE_FOG)
color = linear_fog_fade(color, flw_distance, uFogRange.x, uFogRange.y);
#endif
fragColor = color;
}

View file

@ -1,64 +0,0 @@
#use "flywheel:context/fog.glsl"
uniform float uTime;
uniform mat4 uViewProjection;
uniform vec3 uCameraPos;
uniform int uConstantAmbientLight;
uniform vec2 uTextureScale;
uniform sampler2D uBlockAtlas;
uniform sampler2D uLightMap;
uniform sampler2D uCrumbling;
uniform vec2 uWindowSize;
#ifdef VERTEX_SHADER
#use "flywheel:context/diffuse.glsl"
vec4 FLWVertex(inout Vertex v) {
fragDistance = fog_distance(v.pos, uCameraPos);
return uViewProjection * vec4(v.pos, 1.);
}
float FLWDiffuse(vec3 normal) {
if (uConstantAmbientLight == 1) {
return diffuseNether(normal);
} else {
return diffuse(normal);
}
}
#elif defined(FRAGMENT_SHADER)
out vec4 fragColor;
vec4 FLWBlockTexture(vec2 texCoords) {
vec4 cr = texture(uCrumbling, texCoords * uTextureScale);
float diffuseAlpha = texture(uBlockAtlas, texCoords).a;
cr.a = cr.a * diffuseAlpha;
return cr;
}
vec4 FLWLight(vec2 lightCoords) {
return vec4(1.);
}
void FLWFinalizeColor(vec4 color) {
#ifdef ALPHA_DISCARD
if (color.a < ALPHA_DISCARD) {
discard;
}
#endif
#ifdef COLOR_FOG
color = linear_fog(color);
#elif defined(FADE_FOG)
color = linear_fog_fade(color);
#endif
fragColor = color;
}
#endif

View file

@ -0,0 +1 @@
#use "flywheel:context/common.vert"

View file

@ -1,50 +0,0 @@
uniform vec4 uFogColor;
uniform vec2 uFogRange;
uniform int uFogShape;
#ifdef VERTEX_SHADER
out float fragDistance;
#elif defined(FRAGMENT_SHADER)
in float fragDistance;
#endif
float spherical_distance(vec3 relativePos) {
return length(relativePos);
}
float cylindrical_distance(vec3 relativePos) {
float distXZ = length(relativePos.xz);
float distY = abs(relativePos.y);
return max(distXZ, distY);
}
float fog_distance(vec3 relativePos) {
if (uFogShape == 0) {
return spherical_distance(relativePos);
} else {
return cylindrical_distance(relativePos);
}
}
float fog_distance(vec3 worldPos, vec3 cameraPos) {
return fog_distance(worldPos - cameraPos);
}
vec4 linear_fog(vec4 color) {
if (fragDistance <= uFogRange.x) {
return color;
}
float fogValue = fragDistance < uFogRange.y ? smoothstep(uFogRange.x, uFogRange.y, fragDistance) : 1.0;
return vec4(mix(color.rgb, uFogColor.rgb, fogValue * uFogColor.a), color.a);
}
vec4 linear_fog_fade(vec4 color) {
if (fragDistance <= uFogRange.x) {
return color;
} else if (fragDistance >= uFogRange.y) {
return vec4(0.0);
}
return color * smoothstep(uFogRange.y, uFogRange.x, fragDistance);
}

View file

@ -0,0 +1,39 @@
#use "flywheel:api/fragment.glsl"
#use "flywheel:util/fog.glsl"
// optimize discard usage
#ifdef ALPHA_DISCARD
#ifdef GL_ARB_conservative_depth
layout (depth_greater) out float gl_FragDepth;
#endif
#endif
uniform vec2 uFogRange;
uniform vec4 uFogColor;
uniform sampler2D uBlockAtlas;
uniform sampler2D uLightMap;
in float _flw_diffuse;
out vec4 fragColor;
void flw_contextFragment() {
vec4 texColor = texture(uBlockAtlas, flw_vertexTexCoord);
vec4 lightColor = texture(uLightMap, flw_vertexLight);
vec4 color = flw_vertexColor * vec4(texColor.rgb * lightColor.rgb * _flw_diffuse, texColor.a);
#ifdef ALPHA_DISCARD
if (color.a < ALPHA_DISCARD) {
discard;
}
#endif
#ifdef COLOR_FOG
color = linear_fog(color, flw_distance, uFogRange.x, uFogRange.y, uFogColor);
#elif defined(FADE_FOG)
color = linear_fog_fade(color, flw_distance, uFogRange.x, uFogRange.y);
#endif
fragColor = color;
}

View file

@ -1,68 +0,0 @@
#use "flywheel:context/fog.glsl"
uniform float uTime;
uniform mat4 uViewProjection;
uniform vec3 uCameraPos;
uniform int uConstantAmbientLight;
uniform vec2 uTextureScale;
uniform sampler2D uBlockAtlas;
uniform sampler2D uLightMap;
uniform vec2 uWindowSize;
#ifdef VERTEX_SHADER
#use "flywheel:context/diffuse.glsl"
vec4 FLWVertex(inout Vertex v) {
fragDistance = fog_distance(v.pos, uCameraPos);
return uViewProjection * vec4(v.pos, 1.);
}
float FLWDiffuse(vec3 normal) {
if (uConstantAmbientLight == 1) {
return diffuseNether(normal);
} else {
return diffuse(normal);
}
}
#elif defined(FRAGMENT_SHADER)
#use "flywheel:core/lightutil.glsl"
// optimize discard usage
#ifdef ALPHA_DISCARD
#ifdef GL_ARB_conservative_depth
layout (depth_greater) out float gl_FragDepth;
#endif
#endif
out vec4 fragColor;
vec4 FLWBlockTexture(vec2 texCoords) {
return texture(uBlockAtlas, texCoords);
}
vec4 FLWLight(vec2 lightCoords) {
return texture(uLightMap, shiftLight(lightCoords));
}
void FLWFinalizeColor(vec4 color) {
#ifdef ALPHA_DISCARD
if (color.a < ALPHA_DISCARD) {
discard;
}
#endif
#ifdef COLOR_FOG
color = linear_fog(color);
#elif defined(FADE_FOG)
color = linear_fog_fade(color);
#endif
fragColor = color;
}
#endif

View file

@ -0,0 +1 @@
#use "flywheel:context/common.vert"

View file

@ -0,0 +1,16 @@
#use "flywheel:api/vertex.glsl"
#use "flywheel:util/light.glsl"
struct Instance {
vec2 light;
vec4 color;
mat4 transform;
mat3 normalMat;
};
void flw_instanceVertex(Instance instance) {
flw_vertexPos = instance.transform * flw_vertexPos;
flw_vertexNormal = instance.normalMat * flw_vertexNormal;
flw_vertexColor = instance.color;
flw_vertexLight = shiftLight(instance.light);
}

View file

@ -0,0 +1,18 @@
#use "flywheel:api/vertex.glsl"
#use "flywheel:util/light.glsl"
#use "flywheel:util/quaternion.glsl"
struct Oriented {
vec2 light;
vec4 color;
vec3 pos;
vec3 pivot;
vec4 rotation;
};
void flw_instanceVertex(Oriented oriented) {
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - oriented.pivot, oriented.rotation) + oriented.pivot + oriented.pos, 1.0);
flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, oriented.rotation);
flw_vertexColor = oriented.color;
flw_vertexLight = shiftLight(oriented.light);
}

View file

@ -0,0 +1,16 @@
#use "flywheel:api/vertex.glsl"
#use "flywheel:util/light.glsl"
layout(location = 0) in vec3 _flw_v_pos;
layout(location = 1) in vec4 _flw_v_color;
layout(location = 2) in vec2 _flw_v_texCoord;
layout(location = 3) in vec2 _flw_v_light;
layout(location = 4) in vec3 _flw_v_normal;
void flw_layoutVertex() {
flw_vertexPos = vec4(_flw_v_pos, 1.0);
flw_vertexColor = _flw_v_color;
flw_vertexTexCoord = _flw_v_texCoord;
flw_vertexLight = shiftLight(_flw_v_light);
flw_vertexNormal = _flw_v_normal;
}

View file

@ -0,0 +1,13 @@
#use "flywheel:api/vertex.glsl"
layout(location = 0) in vec3 _flw_v_pos;
layout(location = 1) in vec2 _flw_v_texCoord;
layout(location = 2) in vec3 _flw_v_normal;
void flw_layoutVertex() {
flw_vertexPos = vec4(_flw_v_pos, 1.0);
flw_vertexColor = vec4(1.0);
flw_vertexTexCoord = _flw_v_texCoord;
flw_vertexLight = vec2(0.0);
flw_vertexNormal = _flw_v_normal;
}

View file

@ -1,14 +0,0 @@
struct Instance {
vec2 light;
vec4 color;
mat4 transform;
mat3 normalMat;
};
void vertex(inout Vertex v, Instance i) {
v.pos = (i.transform * vec4(v.pos, 1.)).xyz;
v.normal = i.normalMat * v.normal;
v.color = i.color;
v.light = i.light;
}

View file

@ -1,16 +0,0 @@
#use "flywheel:core/quaternion.glsl"
struct Oriented {
vec2 light;
vec4 color;
vec3 pos;
vec3 pivot;
vec4 rotation;
};
void vertex(inout Vertex v, Oriented o) {
v.pos = rotateVertexByQuat(v.pos - o.pivot, o.rotation) + o.pivot + o.pos;
v.normal = rotateVertexByQuat(v.normal, o.rotation);
v.color = o.color;
v.light = o.light;
}

View file

@ -1,4 +0,0 @@
void vertex(inout Vertex v) {
}

View file

@ -0,0 +1,40 @@
float spherical_distance(vec3 relativePos) {
return length(relativePos);
}
float cylindrical_distance(vec3 relativePos) {
float distXZ = length(relativePos.xz);
float distY = abs(relativePos.y);
return max(distXZ, distY);
}
float fog_distance(vec3 relativePos, int fogShape) {
if (fogShape == 0) {
return spherical_distance(relativePos);
} else {
return cylindrical_distance(relativePos);
}
}
float fog_distance(vec3 worldPos, vec3 cameraPos, int fogShape) {
return fog_distance(worldPos - cameraPos, fogShape);
}
vec4 linear_fog(vec4 color, float distance, float fogStart, float fogEnd, vec4 fogColor) {
if (distance <= fogStart) {
return color;
}
float fogValue = distance < fogEnd ? smoothstep(fogStart, fogEnd, distance) : 1.0;
return vec4(mix(color.rgb, fogColor.rgb, fogValue * fogColor.a), color.a);
}
vec4 linear_fog_fade(vec4 color, float distance, float fogStart, float fogEnd) {
if (distance <= fogStart) {
return color;
} else if (distance >= fogEnd) {
return vec4(0.0);
}
return color * smoothstep(fogEnd, fogStart, distance);
}