Move to the template system and overhaul instance attributes

- All material shaders now use the template system.
 - Because of the template system, we can know what attributes a material has, along with how they're formatted.
 - All of the *Attribute enums are effectively inlined, as the context they used to provide is no longer needed.
This commit is contained in:
JozsefA 2021-05-18 14:05:52 -07:00
parent 695fe98d28
commit 55703d8838
67 changed files with 739 additions and 1123 deletions

View file

@ -6,9 +6,11 @@ import static org.lwjgl.opengl.GL20.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL20.glActiveTexture;
import static org.lwjgl.opengl.GL20.glBindTexture;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.Vector;
@ -76,7 +78,7 @@ public class Backend {
private static boolean enabled;
static final Map<ResourceLocation, MaterialSpec<?>> materialRegistry = new HashMap<>();
static final Map<ResourceLocation, ShaderContext<?>> contexts = new HashMap<>();
static final List<ShaderContext<?>> contexts = new ArrayList<>();
static final Map<ResourceLocation, ProgramSpec> programSpecRegistry = new HashMap<>();
static {
@ -119,11 +121,7 @@ public class Backend {
* Register a shader context.
*/
public static <P extends GlProgram> ShaderContext<P> register(ShaderContext<P> spec) {
ResourceLocation name = spec.getRoot();
if (contexts.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
contexts.put(name, spec);
contexts.add(spec);
return spec;
}

View file

@ -6,9 +6,12 @@ import java.util.Map;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.IMultiProgram;
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
import com.jozufozu.flywheel.backend.gl.shader.ShaderConstants;
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.loading.ProcessingStage;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.loading.Program;
import com.jozufozu.flywheel.backend.loading.Shader;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import net.minecraft.util.ResourceLocation;
@ -17,27 +20,49 @@ public abstract class ShaderContext<P extends GlProgram> {
public final Map<ProgramSpec, IMultiProgram<P>> programs = new HashMap<>();
public final ResourceLocation root;
protected final ShaderSpecLoader<P> specLoader;
protected ShaderTransformer transformer = new ShaderTransformer();
public ShaderContext(ResourceLocation root) {
public ShaderContext(ResourceLocation root, ShaderSpecLoader<P> specLoader) {
this.root = root;
this.specLoader = specLoader;
}
public abstract ShaderSpecLoader<P> getLoader();
// TODO: Untangle the loading functions
/**
* Load all programs associated with this context. This might be just one, if the context is very specialized.
*/
public abstract void load(ShaderLoader loader);
public void loadProgramFromSpec(ShaderLoader loader, ProgramSpec programSpec) {
programs.put(programSpec, getLoader().create(loader, this, programSpec));
programs.put(programSpec, specLoader.create(loader, this, programSpec));
Backend.log.debug("Loaded program {}", programSpec.name);
}
public void preProcess(ShaderLoader loader, Shader shader) {
public Program loadProgram(ProgramSpec spec, ShaderConstants defines, ShaderLoader loader) {
if (defines != null)
transformer.pushStage(defines);
Shader vertexFile = loader.source(spec.vert, ShaderType.VERTEX);
Shader fragmentFile = loader.source(spec.frag, ShaderType.FRAGMENT);
transformer.transformSource(vertexFile);
transformer.transformSource(fragmentFile);
Program program = loader.loadProgram(spec.name, vertexFile, fragmentFile);
if (defines != null)
transformer.popStage();
preLink(program);
return program.link();
}
public ProcessingStage loadingStage(ShaderLoader loader) {
return shader -> this.preProcess(loader, shader);
protected void preLink(Program program) {
}
public P getProgram(ProgramSpec spec) {

View file

@ -27,11 +27,10 @@ import org.lwjgl.system.MemoryUtil;
import com.google.common.collect.Lists;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.loading.Program;
import com.jozufozu.flywheel.backend.loading.Shader;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.resources.IResource;
@ -59,26 +58,7 @@ public class ShaderLoader {
shaderSource.clear();
loadShaderSources(manager);
// InstancedArraysTemplate template = new InstancedArraysTemplate(this);
//
// ResourceLocation name = new ResourceLocation("create", "test");
// ResourceLocation vert = new ResourceLocation("create", "model_new.vert");
// ResourceLocation frag = new ResourceLocation("create", "block_new.frag");
//
// ShaderTransformer transformer = new ShaderTransformer()
// .pushStage(WorldContext.INSTANCE.loadingStage(this))
// .pushStage(this::processIncludes)
// .pushStage(template)
// .pushStage(this::processIncludes);
//
// Shader vertexFile = this.source(vert, ShaderType.VERTEX);
// Shader fragmentFile = this.source(frag, ShaderType.FRAGMENT);
//
// GlProgram.Builder builder = loadProgram(name, transformer, vertexFile, fragmentFile);
//
// BasicProgram program = new BasicProgram(builder, GlFogMode.NONE.getFogFactory());
for (ShaderContext<?> context : Backend.contexts.values()) {
for (ShaderContext<?> context : Backend.contexts) {
context.load(this);
}
@ -122,32 +102,30 @@ public class ShaderLoader {
return new Shader(type, name, getShaderSource(name));
}
public GlProgram.Builder loadProgram(ResourceLocation name, ShaderTransformer transformer, Shader... shaders) {
return loadProgram(name, transformer, Lists.newArrayList(shaders));
public Program loadProgram(ResourceLocation name, Shader... shaders) {
return loadProgram(name, Lists.newArrayList(shaders));
}
/**
* Ingests the given shaders, compiling them and linking them together after applying the transformer to the source.
*
* @param name What should we call this program if something goes wrong?
* @param transformer What should we do to the sources before compilation?
* @param shaders What are the different shader stages that should be linked together?
* @return A linked program builder.
* @return A program with all provided shaders attached
*/
public GlProgram.Builder loadProgram(ResourceLocation name, ShaderTransformer transformer, Collection<Shader> shaders) {
public Program loadProgram(ResourceLocation name, Collection<Shader> shaders) {
List<GlShader> compiled = new ArrayList<>(shaders.size());
try {
GlProgram.Builder builder = GlProgram.builder(name);
Program builder = new Program(name);
for (Shader shader : shaders) {
transformer.transformSource(shader);
GlShader sh = new GlShader(shader);
compiled.add(sh);
builder.attachShader(sh);
builder.attachShader(shader, sh);
}
return builder.link();
return builder;
} finally {
compiled.forEach(GlObject::delete);
}
@ -180,7 +158,7 @@ public class ShaderLoader {
ResourceLocation include = new ResourceLocation(includeName);
if (seen.add(include)) {
String includeSource = shaderSource.get(include);
String includeSource = getShaderSource(include);
if (includeSource != null) {
return includeRecursive(includeSource, seen);

View file

@ -5,6 +5,7 @@ import static org.lwjgl.opengl.GL20.glUniform3f;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.ProgramFogMode;
import com.jozufozu.flywheel.backend.loading.Program;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.util.ResourceLocation;
@ -20,7 +21,7 @@ public class BasicProgram extends GlProgram {
protected int uBlockAtlas;
protected int uLightMap;
public BasicProgram(GlProgram.Builder builder, ProgramFogMode.Factory fogFactory) {
public BasicProgram(Program builder, ProgramFogMode.Factory fogFactory) {
this(builder.name, builder.program, fogFactory);
}

View file

@ -2,8 +2,10 @@ package com.jozufozu.flywheel.backend.core;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.ResourceUtil;
@ -11,10 +13,15 @@ import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.shader.FogSensitiveProgram;
import com.jozufozu.flywheel.backend.gl.shader.IMultiProgram;
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
import com.jozufozu.flywheel.backend.loading.InstancedArraysTemplate;
import com.jozufozu.flywheel.backend.loading.Program;
import com.jozufozu.flywheel.backend.loading.ProgramTemplate;
import com.jozufozu.flywheel.backend.loading.Shader;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import net.minecraft.util.ResourceLocation;
@ -23,20 +30,30 @@ public class WorldContext<P extends BasicProgram> extends ShaderContext<P> {
private static final String declaration = "#flwbuiltins";
private static final Pattern builtinPattern = Pattern.compile(declaration);
public static final WorldContext<BasicProgram> INSTANCE = new WorldContext<>(new ResourceLocation("create", "context/std"), new FogSensitiveProgram.SpecLoader<>(BasicProgram::new));
public static final WorldContext<BasicProgram> INSTANCE = new WorldContext<>(new ResourceLocation("create", "context/world"), new FogSensitiveProgram.SpecLoader<>(BasicProgram::new));
public static final WorldContext<CrumblingProgram> CRUMBLING = new WorldContext<>(new ResourceLocation("create", "context/crumbling"), new FogSensitiveProgram.SpecLoader<>(CrumblingProgram::new));
private final ShaderSpecLoader<P> loader;
final Map<ShaderType, ResourceLocation> builtins;
final Map<ShaderType, String> builtinSources;
protected ProgramTemplate template;
protected final Supplier<Stream<ProgramSpec>> specStream;
protected final TemplateFactory templateFactory;
public WorldContext(ResourceLocation root, ShaderSpecLoader<P> loader) {
super(root);
this(root, loader, () -> Backend.allMaterials()
.stream()
.map(MaterialSpec::getProgramSpec), InstancedArraysTemplate::new);
}
public WorldContext(ResourceLocation root, ShaderSpecLoader<P> loader, Supplier<Stream<ProgramSpec>> specStream, TemplateFactory templateFactory) {
super(root, loader);
this.specStream = specStream;
this.templateFactory = templateFactory;
builtins = new EnumMap<>(ShaderType.class);
builtinSources = new EnumMap<>(ShaderType.class);
builtins.put(ShaderType.FRAGMENT, ResourceUtil.subPath(root, "/builtin.frag"));
builtins.put(ShaderType.VERTEX, ResourceUtil.subPath(root, "/builtin.vert"));
this.loader = loader;
}
@Override
@ -44,26 +61,37 @@ public class WorldContext<P extends BasicProgram> extends ShaderContext<P> {
programs.values().forEach(IMultiProgram::delete);
programs.clear();
Backend.allMaterials()
.stream()
.map(MaterialSpec::getProgramSpec)
.forEach(spec -> loadProgramFromSpec(loader, spec));
builtins.forEach((type, resourceLocation) -> builtinSources.put(type, loader.getShaderSource(resourceLocation)));
template = templateFactory.create(loader);
transformer = new ShaderTransformer()
.pushStage(this::injectBuiltins)
.pushStage(loader::processIncludes)
.pushStage(Shader::parseStructs)
.pushStage(template)
.pushStage(loader::processIncludes);
specStream.get().forEach(spec -> loadProgramFromSpec(loader, spec));
}
@Override
public void preProcess(ShaderLoader loader, Shader shader) {
String builtinSrc = loader.getShaderSource(builtins.get(shader.type));
protected void preLink(Program program) {
template.attachAttributes(program);
}
/**
* Replace #flwbuiltins with whatever expansion this context provides for the given shader.
*/
public void injectBuiltins(Shader shader) {
Matcher matcher = builtinPattern.matcher(shader.getSource());
if (matcher.find())
shader.setSource(matcher.replaceFirst(builtinSrc));
shader.setSource(matcher.replaceFirst(builtinSources.get(shader.type)));
else
throw new RuntimeException(String.format("%s shader '%s' is missing %s, cannot use in World Context", shader.type.name, shader.name, declaration));
}
@Override
public ShaderSpecLoader<P> getLoader() {
return loader;
public interface TemplateFactory {
ProgramTemplate create(ShaderLoader loader);
}
}

View file

@ -1,39 +0,0 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
public enum BasicAttributes implements IVertexAttrib {
LIGHT("aLight", CommonAttributes.LIGHT),
COLOR("aColor", CommonAttributes.RGBA),
;
private final String name;
private final IAttribSpec spec;
BasicAttributes(String name, IAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,41 +0,0 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum ModelAttributes implements IVertexAttrib {
VERTEX_POSITION("aPos", CommonAttributes.VEC3),
NORMAL("aNormal", CommonAttributes.NORMAL),
TEXTURE("aTexCoords", CommonAttributes.UV),
;
private final String name;
private final VertexAttribSpec spec;
ModelAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,40 +0,0 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
public enum OrientedAttributes implements IVertexAttrib {
INSTANCE_POS("aInstancePos", CommonAttributes.VEC3),
PIVOT("aPivot", CommonAttributes.VEC3),
ROTATION("aRotation", CommonAttributes.QUATERNION),
;
private final String name;
private final IAttribSpec spec;
OrientedAttributes(String name, IAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,39 +0,0 @@
package com.jozufozu.flywheel.backend.core.materials;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.MatrixAttributes;
public enum TransformAttributes implements IVertexAttrib {
TRANSFORM("aTransform", MatrixAttributes.MAT4),
NORMAL_MAT("aNormalMat", MatrixAttributes.MAT3),
;
private final String name;
private final IAttribSpec spec;
TransformAttributes(String name, IAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,5 +1,12 @@
package com.jozufozu.flywheel.backend.gl;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.lwjgl.opengl.GL11;
import net.minecraftforge.api.distmarker.Dist;
@ -15,6 +22,10 @@ public enum GlPrimitiveType {
UINT(4, "uint", GL11.GL_UNSIGNED_INT),
INT(4, "int", GL11.GL_INT);
private static final GlPrimitiveType[] VALUES = values();
private static final Map<String, GlPrimitiveType> NAME_LOOKUP = Arrays.stream(VALUES)
.collect(Collectors.toMap(GlPrimitiveType::getDisplayName, type -> type));
private final int size;
private final String displayName;
private final int glConstant;
@ -36,4 +47,9 @@ public enum GlPrimitiveType {
public int getGlConstant() {
return this.glConstant;
}
@Nullable
public static GlPrimitiveType byName(String name) {
return name == null ? null : NAME_LOOKUP.get(name.toLowerCase(Locale.ROOT));
}
}

View file

@ -1,12 +0,0 @@
package com.jozufozu.flywheel.backend.gl.attrib;
public interface IVertexAttrib {
String attribName();
IAttribSpec attribSpec();
int getDivisor();
int getBufferIndex();
}

View file

@ -1,21 +1,20 @@
package com.jozufozu.flywheel.backend.gl.attrib;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class VertexFormat {
private final ArrayList<IVertexAttrib> allAttributes;
private final ArrayList<IAttribSpec> allAttributes;
private final int numAttributes;
private final int stride;
public VertexFormat(ArrayList<IVertexAttrib> allAttributes) {
public VertexFormat(ArrayList<IAttribSpec> allAttributes) {
this.allAttributes = allAttributes;
int numAttributes = 0, stride = 0;
for (IVertexAttrib attrib : allAttributes) {
IAttribSpec spec = attrib.attribSpec();
for (IAttribSpec spec : allAttributes) {
numAttributes += spec.getAttributeCount();
stride += spec.getSize();
}
@ -33,8 +32,7 @@ public class VertexFormat {
public void vertexAttribPointers(int index) {
int offset = 0;
for (IVertexAttrib attrib : this.allAttributes) {
IAttribSpec spec = attrib.attribSpec();
for (IAttribSpec spec : this.allAttributes) {
spec.vertexAttribPointer(stride, index, offset);
index += spec.getAttributeCount();
offset += spec.getSize();
@ -45,16 +43,14 @@ public class VertexFormat {
return new Builder();
}
public static class Builder {
private final ArrayList<IVertexAttrib> allAttributes;
private final ArrayList<IAttribSpec> allAttributes = new ArrayList<>();
public Builder() {
allAttributes = new ArrayList<>();
}
public <A extends Enum<A> & IVertexAttrib> Builder addAttributes(Class<A> attribEnum) {
allAttributes.addAll(Arrays.asList(attribEnum.getEnumConstants()));
public Builder addAttributes(IAttribSpec... attributes) {
Collections.addAll(allAttributes, attributes);
return this;
}

View file

@ -38,8 +38,12 @@ public abstract class MappedBuffer implements AutoCloseable {
public MappedBuffer putFloatArray(float[] floats) {
checkAndMap();
internal.asFloatBuffer().put(floats);
internal.position(internal.position() + floats.length * 4);
for (float f : floats) {
internal.putFloat(f);
}
// internal.asFloatBuffer().put(floats);
// internal.position(internal.position() + floats.length * 4);
return this;
}

View file

@ -7,6 +7,7 @@ import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.GlFog;
import com.jozufozu.flywheel.backend.gl.GlFogMode;
import com.jozufozu.flywheel.backend.loading.Program;
import net.minecraft.util.ResourceLocation;
@ -45,7 +46,7 @@ public class FogSensitiveProgram<P extends GlProgram> implements IMultiProgram<P
defines.defineAll(fogMode.getDefines());
GlProgram.Builder builder = spec.loadProgram(ctx, defines, loader);
Program builder = ctx.loadProgram(spec, defines, loader);
programs.put(fogMode, fogProgramLoader.create(builder.name, builder.program, fogMode.getFogFactory()));
}

View file

@ -1,24 +1,13 @@
package com.jozufozu.flywheel.backend.gl.shader;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_TRUE;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glBindAttribLocation;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glDeleteProgram;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glUniform1i;
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
import static org.lwjgl.opengl.GL20.glUseProgram;
import java.util.Collection;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.util.RenderUtil;
import net.minecraft.util.ResourceLocation;
@ -33,10 +22,6 @@ public abstract class GlProgram extends GlObject {
this.name = name;
}
public static Builder builder(ResourceLocation name) {
return new Builder(name);
}
public void bind() {
glUseProgram(handle());
}
@ -88,53 +73,4 @@ public abstract class GlProgram extends GlObject {
glDeleteProgram(handle);
}
public static class Builder {
public final ResourceLocation name;
public final int program;
private int attributeIndex;
public Builder(ResourceLocation name) {
this.name = name;
this.program = glCreateProgram();
}
public Builder attachShader(GlShader shader) {
glAttachShader(this.program, shader.handle());
return this;
}
public <A extends IVertexAttrib> Builder addAttributes(Collection<A> attributes) {
attributes.forEach(this::addAttribute);
return this;
}
public <A extends IVertexAttrib> Builder addAttribute(A attrib) {
glBindAttribLocation(this.program, attributeIndex, attrib.attribName());
attributeIndex += attrib.attribSpec().getAttributeCount();
return this;
}
/**
* Links the attached shaders to this program.
*/
public Builder link() {
glLinkProgram(this.program);
String log = glGetProgramInfoLog(this.program);
if (!log.isEmpty()) {
Backend.log.debug("Program link log for " + this.name + ": " + log);
}
int result = glGetProgrami(this.program, GL_LINK_STATUS);
if (result != GL_TRUE) {
throw new RuntimeException("Shader program linking failed, see log for details");
}
return this;
}
}
}

View file

@ -1,15 +1,5 @@
package com.jozufozu.flywheel.backend.gl.shader;
import java.util.ArrayList;
import java.util.Arrays;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.loading.InstancedArraysTemplate;
import com.jozufozu.flywheel.backend.loading.Shader;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import net.minecraft.util.ResourceLocation;
public class ProgramSpec {
@ -20,37 +10,15 @@ public class ProgramSpec {
public final ShaderConstants defines;
public final ArrayList<IVertexAttrib> attributes;
public static Builder builder(ResourceLocation name) {
return new Builder(name);
}
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, ShaderConstants defines, ArrayList<IVertexAttrib> attributes) {
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, ShaderConstants defines) {
this.name = name;
this.vert = vert;
this.frag = frag;
this.defines = defines;
this.attributes = attributes;
}
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ShaderConstants defines, ShaderLoader loader) {
InstancedArraysTemplate template = new InstancedArraysTemplate(loader);
ShaderTransformer transformer = new ShaderTransformer()
.pushStage(ctx.loadingStage(loader))
// .pushStage(loader::processIncludes)
// .pushStage(template)
.pushStage(loader::processIncludes);
if (defines != null)
transformer.pushStage(defines);
Shader vertexFile = loader.source(vert, ShaderType.VERTEX);
Shader fragmentFile = loader.source(frag, ShaderType.FRAGMENT);
return loader.loadProgram(name, transformer, vertexFile, fragmentFile)
.addAttributes(attributes);
}
public static class Builder {
@ -59,11 +27,9 @@ public class ProgramSpec {
private ShaderConstants defines = ShaderConstants.EMPTY;
private final ResourceLocation name;
private final ArrayList<IVertexAttrib> attributes;
public Builder(ResourceLocation name) {
this.name = name;
attributes = new ArrayList<>();
}
public Builder setVert(ResourceLocation vert) {
@ -81,13 +47,8 @@ public class ProgramSpec {
return this;
}
public <A extends Enum<A> & IVertexAttrib> Builder addAttributes(Class<A> attributeEnum) {
attributes.addAll(Arrays.asList(attributeEnum.getEnumConstants()));
return this;
}
public ProgramSpec createProgramSpec() {
return new ProgramSpec(name, vert, frag, defines, attributes);
public ProgramSpec build() {
return new ProgramSpec(name, vert, frag, defines);
}
}

View file

@ -4,5 +4,12 @@ import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
public interface ShaderSpecLoader<P extends GlProgram> {
/**
* @param loader
* @param ctx
* @param spec
* @return
*/
IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec);
}

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.gl.shader;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.loading.Program;
import net.minecraft.util.ResourceLocation;
@ -31,7 +32,7 @@ public class SingleProgram<P extends GlProgram> implements IMultiProgram<P> {
@Override
public IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec) {
GlProgram.Builder builder = spec.loadProgram(ctx, spec.defines, loader);
Program builder = ctx.loadProgram(spec, spec.defines, loader);
return new SingleProgram<>(factory.create(builder.name, builder.program));
}

View file

@ -6,8 +6,17 @@ import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class InstancedArraysTemplate extends ProgramTemplate {
public static final String[] requiredVert = {"FLWInstanceData", "FLWVertexData", "FLWFragment"};
public static final String[] requiredFrag = {"FLWFragment"};
public static final String vertexData = "VertexData";
public static final String instanceData = "InstanceData";
public static final String fragment = "Fragment";
public static final String vertexPrefix = "a_v_";
public static final String instancePrefix = "a_i_";
public static final String[] requiredVert = new String[]{instanceData, vertexData, fragment};
public static final String[] requiredFrag = {fragment};
public static final ResourceLocation vert = new ResourceLocation("create", "template/instanced/instanced.vert");
public static final ResourceLocation frag = new ResourceLocation("create", "template/instanced/instanced.frag");
@ -18,4 +27,12 @@ public class InstancedArraysTemplate extends ProgramTemplate {
templates.put(ShaderType.VERTEX, new ShaderTemplate(requiredVert, loader.getShaderSource(vert)));
templates.put(ShaderType.FRAGMENT, new ShaderTemplate(requiredFrag, loader.getShaderSource(frag)));
}
@Override
public void attachAttributes(Program builder) {
Shader shader = builder.attached.get(ShaderType.VERTEX);
shader.getTag(vertexData).addPrefixedAttributes(builder, vertexPrefix);
shader.getTag(instanceData).addPrefixedAttributes(builder, instancePrefix);
}
}

View file

@ -0,0 +1,19 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.jozufozu.flywheel.backend.gl.GlPrimitiveType;
public class LayoutTag {
public static final Pattern pattern = Pattern.compile("Layout\\((\\w+)(?:\\s*,\\s*(\\w*))?\\)");
final GlPrimitiveType type;
final boolean normalized;
public LayoutTag(Matcher matcher) {
type = GlPrimitiveType.byName(matcher.group(1));
normalized = Boolean.parseBoolean(matcher.group(2));
}
}

View file

@ -0,0 +1,34 @@
package com.jozufozu.flywheel.backend.loading;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class ModelTemplate extends ProgramTemplate {
public static final String vertexData = "VertexData";
public static final String fragment = "Fragment";
public static final String vertexPrefix = "a_v_";
public static final String[] requiredVert = new String[]{vertexData, fragment};
public static final String[] requiredFrag = {fragment};
public static final ResourceLocation vert = new ResourceLocation("create", "template/model/model.vert");
public static final ResourceLocation frag = new ResourceLocation("create", "template/model/model.frag");
public ModelTemplate(ShaderLoader loader) {
super(loader);
templates.put(ShaderType.VERTEX, new ShaderTemplate(requiredVert, loader.getShaderSource(vert)));
templates.put(ShaderType.FRAGMENT, new ShaderTemplate(requiredFrag, loader.getShaderSource(frag)));
}
@Override
public void attachAttributes(Program builder) {
Shader shader = builder.attached.get(ShaderType.VERTEX);
shader.getTag(vertexData).addPrefixedAttributes(builder, vertexPrefix);
}
}

View file

@ -1,45 +0,0 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.util.ResourceLocation;
public class ParsedShader {
private static final Pattern decorator = Pattern.compile("#\\[([\\w_]*)]");
private static final Pattern taggedStruct = Pattern.compile("#\\[([\\w_]*)]\\s*struct\\s+([\\w\\d_]*)\\s*\\{(\\s*(?:.*;\\s*\\n)+\\s*)}\\s*;");
final ResourceLocation loc;
final String src;
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
public ParsedShader(ResourceLocation loc, String src) {
this.loc = loc;
Matcher structs = taggedStruct.matcher(src);
StringBuffer strippedSrc = new StringBuffer();
while (structs.find()) {
TaggedStruct struct = new TaggedStruct(structs);
structs.appendReplacement(strippedSrc, decorator.matcher(struct.source).replaceFirst(""));
tag2Struct.put(struct.tag, struct);
name2Struct.put(struct.name, struct);
}
structs.appendTail(strippedSrc);
this.src = strippedSrc.toString();
}
public TaggedStruct getTag(String tag) {
return tag2Struct.get(tag);
}
public TaggedStruct getStruct(String name) {
return name2Struct.get(name);
}
}

View file

@ -0,0 +1,69 @@
package com.jozufozu.flywheel.backend.loading;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.GL_TRUE;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glBindAttribLocation;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import java.util.EnumMap;
import java.util.Map;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class Program {
public final ResourceLocation name;
public final int program;
private int attributeIndex;
public final Map<ShaderType, Shader> attached;
public Program(ResourceLocation name) {
this.name = name;
this.program = glCreateProgram();
attached = new EnumMap<>(ShaderType.class);
}
public Program attachShader(Shader shader, GlShader glShader) {
glAttachShader(this.program, glShader.handle());
attached.put(shader.type, shader);
return this;
}
public Program addAttribute(String name, int attributeCount) {
glBindAttribLocation(this.program, attributeIndex, name);
attributeIndex += attributeCount;
return this;
}
/**
* Links the attached shaders to this program.
*/
public Program link() {
glLinkProgram(this.program);
String log = glGetProgramInfoLog(this.program);
if (!log.isEmpty()) {
Backend.log.debug("Program link log for " + this.name + ": " + log);
}
int result = glGetProgrami(this.program, GL_LINK_STATUS);
if (result != GL_TRUE) {
throw new RuntimeException("Shader program linking failed, see log for details");
}
return this;
}
}

View file

@ -6,7 +6,7 @@ import java.util.Map;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
public class ProgramTemplate implements ProcessingStage {
public abstract class ProgramTemplate implements ProcessingStage {
protected final ShaderLoader loader;
protected Map<ShaderType, ShaderTemplate> templates = new EnumMap<>(ShaderType.class);
@ -21,8 +21,10 @@ public class ProgramTemplate implements ProcessingStage {
if (template == null) return;
ParsedShader parsedShader = new ParsedShader(shader.name, shader.getSource());
shader.setSource(template.apply(shader));
}
public void attachAttributes(Program builder) {
shader.setSource(template.apply(parsedShader));
}
}

View file

@ -1,26 +1,32 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class Shader {
private static final Pattern decorator = Pattern.compile("#\\[([\\w_]*)]");
public final ResourceLocation name;
public ShaderType type;
public ResourceLocation name;
private String source;
private boolean parsed = false;
final List<TaggedStruct> structs = new ArrayList<>(3);
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
public Shader(ShaderType type, ResourceLocation name, String source) {
this.type = type;
this.name = name;
this.setSource(source);
}
public static Shader vert(ResourceLocation fileLoc, String source) {
return new Shader(ShaderType.VERTEX, fileLoc, source);
}
public static Shader frag(ResourceLocation fileLoc, String source) {
return new Shader(ShaderType.FRAGMENT, fileLoc, source);
this.source = source;
}
public String getSource() {
@ -30,4 +36,41 @@ public class Shader {
public void setSource(String source) {
this.source = source;
}
public TaggedStruct getTag(String tag) {
checkAndParse();
return tag2Struct.get(tag);
}
public TaggedStruct getStruct(String name) {
checkAndParse();
return name2Struct.get(name);
}
private void checkAndParse() {
if (!parsed) {
parsed = true;
parseStructs();
}
}
public void parseStructs() {
Matcher structMatcher = TaggedStruct.taggedStruct.matcher(source);
StringBuffer strippedSrc = new StringBuffer();
while (structMatcher.find()) {
TaggedStruct struct = new TaggedStruct(structMatcher);
structs.add(struct);
structMatcher.appendReplacement(strippedSrc, decorator.matcher(struct.source).replaceFirst(""));
tag2Struct.put(struct.tag, struct);
name2Struct.put(struct.name, struct);
}
structMatcher.appendTail(strippedSrc);
this.source = strippedSrc.toString();
}
}

View file

@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.loading;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -32,14 +31,14 @@ public class ShaderTemplate {
}
public String apply(ParsedShader shader) {
public String apply(Shader shader) {
return header +
shader.src +
shader.getSource() +
processBody(shader);
}
public String processBody(ParsedShader shader) {
public String processBody(Shader shader) {
String s = body;
List<String> missing = new ArrayList<>();
@ -55,7 +54,7 @@ public class ShaderTemplate {
}
if (!missing.isEmpty()) {
String err = shader.loc + " is missing: " + String.join(", ", missing);
String err = shader.name + " is missing: " + String.join(", ", missing);
throw new RuntimeException(err);
}
@ -65,7 +64,7 @@ public class ShaderTemplate {
return s;
}
private String fillPrefixes(ParsedShader shader, String s) {
private String fillPrefixes(Shader shader, String s) {
Matcher prefixMatches = prefixer.matcher(s);
StringBuffer out = new StringBuffer();
@ -77,13 +76,13 @@ public class ShaderTemplate {
TaggedStruct struct = shader.getStruct(structName);
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, String> field : struct.fields.entrySet()) {
for (TaggedField field : struct.fields) {
builder.append(modifier);
builder.append(' ');
builder.append(field.getValue());
builder.append(field.getType());
builder.append(' ');
builder.append(prefix);
builder.append(field.getKey());
builder.append(field.getName());
builder.append(";\n");
}
@ -93,7 +92,7 @@ public class ShaderTemplate {
return out.toString();
}
private String fillAssigns(ParsedShader shader, String s) {
private String fillAssigns(Shader shader, String s) {
Matcher assignMatches = assigner.matcher(s);
StringBuffer out = new StringBuffer();
@ -105,12 +104,12 @@ public class ShaderTemplate {
TaggedStruct struct = shader.getStruct(structName);
StringBuilder builder = new StringBuilder();
for (String field : struct.fields.keySet()) {
for (TaggedField field : struct.fields) {
builder.append(lhs);
builder.append(field);
builder.append(field.getName());
builder.append(" = ");
builder.append(rhs);
builder.append(field);
builder.append(field.getName());
builder.append(";\n");
}

View file

@ -16,6 +16,11 @@ public class ShaderTransformer {
return this;
}
public ShaderTransformer popStage() {
stages.removeLast();
return this;
}
public ShaderTransformer prependStage(ProcessingStage stage) {
if (stage != null) {
stages.addFirst(stage);

View file

@ -0,0 +1,48 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TaggedField {
public static final Pattern fieldPattern = Pattern.compile("(?:#\\[([^\\n]*)]\\s*)?(\\S+)\\s*(\\S+);");
public String annotation;
public String name;
public String type;
public LayoutTag layout;
public TaggedField(Matcher fieldMatcher) {
annotation = fieldMatcher.group(1);
type = fieldMatcher.group(2);
name = fieldMatcher.group(3);
if (annotation != null) {
Matcher matcher = LayoutTag.pattern.matcher(annotation);
if (matcher.find()) {
layout = new LayoutTag(matcher);
}
}
}
public String getAnnotation() {
return annotation;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
@Override
public String toString() {
return "TaggedField{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
'}';
}
}

View file

@ -1,13 +1,16 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TaggedStruct {
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
// https://regexr.com/5t207
static final Pattern taggedStruct = Pattern.compile("#\\[(\\w*)]\\s*struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;");
int srcStart, srcEnd;
String source;
@ -15,7 +18,8 @@ public class TaggedStruct {
String name;
String body;
Map<String, String> fields = new HashMap<>();
List<TaggedField> fields = new ArrayList<>(4);
Map<String, String> fields2Types = new HashMap<>();
public TaggedStruct(Matcher foundMatcher) {
this.source = foundMatcher.group();
@ -27,10 +31,19 @@ public class TaggedStruct {
name = foundMatcher.group(2);
body = foundMatcher.group(3);
Matcher fielder = fieldPattern.matcher(body);
Matcher fielder = TaggedField.fieldPattern.matcher(body);
while (fielder.find()) {
fields.put(fielder.group(2), fielder.group(1));
fields.add(new TaggedField(fielder));
fields2Types.put(fielder.group(2), fielder.group(1));
}
}
public void addPrefixedAttributes(Program builder, String prefix) {
for (TaggedField field : fields) {
int attributeCount = TypeHelper.getAttributeCount(field.type);
builder.addAttribute(prefix + field.name, attributeCount);
}
}
}

View file

@ -0,0 +1,37 @@
package com.jozufozu.flywheel.backend.loading;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TypeHelper {
public static final Pattern vecType = Pattern.compile("^[biud]?vec([234])$");
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
public static int getElementCount(String type) {
Matcher vec = vecType.matcher(type);
if (vec.find()) return Integer.parseInt(vec.group(1));
Matcher mat = matType.matcher(type);
if (mat.find()) {
int n = Integer.parseInt(mat.group(1));
String m = mat.group(2);
if (m != null) return Integer.parseInt(m) * n;
return n;
}
return 1;
}
public static int getAttributeCount(String type) {
Matcher mat = matType.matcher(type);
if (mat.find()) {
return Integer.parseInt(mat.group(1));
}
return 1;
}
}

View file

@ -1,41 +0,0 @@
package com.simibubi.create.content.contraptions.base;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum KineticAttributes implements IVertexAttrib {
INSTANCE_POSITION("aInstancePos", CommonAttributes.VEC3),
SPEED("aSpeed", CommonAttributes.FLOAT),
OFFSET("aOffset", CommonAttributes.FLOAT),
;
private final String name;
private final VertexAttribSpec spec;
KineticAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 1;
}
@Override
public int getBufferIndex() {
return 1;
}
}

View file

@ -1,39 +0,0 @@
package com.simibubi.create.content.contraptions.base;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum RotatingAttributes implements IVertexAttrib {
AXIS("aAxis", CommonAttributes.NORMAL),
;
private final String name;
private final VertexAttribSpec spec;
RotatingAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 1;
}
@Override
public int getBufferIndex() {
return 1;
}
}

View file

@ -1,45 +0,0 @@
package com.simibubi.create.content.contraptions.components.actors;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum ActorVertexAttributes implements IVertexAttrib {
INSTANCE_POSITION("aInstancePos", CommonAttributes.VEC3),
LIGHT("aModelLight", CommonAttributes.LIGHT),
OFFSET("aOffset", CommonAttributes.FLOAT),
AXIS("aAxis", CommonAttributes.NORMAL),
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
ROTATION_CENTER("aRotationCenter", CommonAttributes.NORMAL),
SPEED("aSpeed", CommonAttributes.FLOAT),
;
private final String name;
private final VertexAttribSpec spec;
ActorVertexAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 1;
}
@Override
public int getBufferIndex() {
return 1;
}
}

View file

@ -1,43 +0,0 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum ContraptionAttributes implements IVertexAttrib {
VERTEX_POSITION("aPos", CommonAttributes.VEC3),
NORMAL("aNormal", CommonAttributes.NORMAL),
TEXTURE("aTexCoords", CommonAttributes.UV),
COLOR("aColor", CommonAttributes.RGBA),
MODEL_LIGHT("aModelLight", CommonAttributes.LIGHT),
;
private final String name;
private final VertexAttribSpec spec;
ContraptionAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,24 +0,0 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.core.WorldContext;
import com.jozufozu.flywheel.backend.gl.shader.FogSensitiveProgram;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import net.minecraft.util.ResourceLocation;
public class ContraptionContext extends WorldContext<ContraptionProgram> {
public static final ContraptionContext INSTANCE = new ContraptionContext();
public ContraptionContext() {
super(new ResourceLocation("create", "context/contraption"), new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new));
}
@Override
public void load(ShaderLoader loader) {
super.load(loader);
loadProgramFromSpec(loader, AllProgramSpecs.STRUCTURE);
}
}

View file

@ -26,7 +26,7 @@ public class ContraptionKineticRenderer extends InstancedTileRenderer<Contraptio
private final WeakReference<RenderedContraption> contraption;
ContraptionKineticRenderer(RenderedContraption contraption) {
super(ContraptionContext.INSTANCE);
super(ContraptionRenderDispatcher.TILES);
this.contraption = new WeakReference<>(contraption);
}

View file

@ -10,10 +10,14 @@ import static org.lwjgl.opengl.GL13.glEnable;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.core.WorldContext;
import com.jozufozu.flywheel.backend.gl.shader.FogSensitiveProgram;
import com.jozufozu.flywheel.backend.loading.ModelTemplate;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.CreateClient;
@ -48,6 +52,7 @@ import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.world.LightType;
@ -59,6 +64,9 @@ import net.minecraftforge.client.model.data.EmptyModelData;
public class ContraptionRenderDispatcher {
public static final Int2ObjectMap<RenderedContraption> renderers = new Int2ObjectOpenHashMap<>();
public static final Compartment<Pair<Contraption, Integer>> CONTRAPTION = new Compartment<>();
private static final ResourceLocation ctxRoot = new ResourceLocation("create", "context/contraption");
public static final WorldContext<ContraptionProgram> STRUCTURE = new WorldContext<>(ctxRoot, new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new), () -> Stream.of(AllProgramSpecs.STRUCTURE), ModelTemplate::new);
public static final WorldContext<ContraptionProgram> TILES = new WorldContext<>(ctxRoot, new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new));
protected static PlacementSimulationWorld renderWorld;
public static void tick() {
@ -90,7 +98,7 @@ public class ContraptionRenderDispatcher {
glActiveTexture(GL_TEXTURE4); // the shaders expect light volumes to be in texture 4
if (Backend.canUseVBOs()) {
ContraptionProgram structureShader = ContraptionContext.INSTANCE.getProgram(AllProgramSpecs.STRUCTURE);
ContraptionProgram structureShader = STRUCTURE.getProgram(AllProgramSpecs.STRUCTURE);
structureShader.bind();
structureShader.uploadViewProjection(viewProjection);

View file

@ -14,6 +14,7 @@ import org.lwjgl.opengl.GL11;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.core.IndexedModel;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.instancing.IInstanceRendered;
import com.jozufozu.flywheel.backend.light.GridAlignedBB;
@ -49,7 +50,11 @@ import net.minecraftforge.client.model.data.EmptyModelData;
public class RenderedContraption {
public static final VertexFormat FORMAT = VertexFormat.builder()
.addAttributes(ContraptionAttributes.class)
.addAttributes(CommonAttributes.VEC3,
CommonAttributes.NORMAL,
CommonAttributes.UV,
CommonAttributes.RGBA,
CommonAttributes.LIGHT)
.build();
private static final BlockModelRenderer MODEL_RENDERER = new BlockModelRenderer(Minecraft.getInstance().getBlockColors());

View file

@ -1,42 +0,0 @@
package com.simibubi.create.content.contraptions.relays.belt;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum BeltAttributes implements IVertexAttrib {
INSTANCE_ROTATION("aInstanceRot", CommonAttributes.QUATERNION),
SOURCE_TEX("aSourceTexture", CommonAttributes.UV),
SCROLL_TEX("aScrollTexture", CommonAttributes.VEC4),
SCROLL_MULT("aScrollMult", CommonAttributes.NORMALIZED_BYTE),
;
private final String name;
private final VertexAttribSpec spec;
BeltAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 1;
}
@Override
public int getBufferIndex() {
return 1;
}
}

View file

@ -1,46 +0,0 @@
package com.simibubi.create.content.logistics.block;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.attrib.VertexAttribSpec;
public enum FlapAttributes implements IVertexAttrib {
INSTANCE_POSITION("aInstancePos",CommonAttributes.VEC3),
LIGHT("aLight", CommonAttributes.LIGHT),
SEGMENT_OFFSET("aSegmentOffset", CommonAttributes.VEC3),
PIVOT("aPivot", CommonAttributes.VEC3),
HORIZONTAL_ANGLE("aHorizontalAngle", CommonAttributes.FLOAT),
INTENSITY("aIntensity", CommonAttributes.FLOAT),
FLAP_SCALE("aFlapScale", CommonAttributes.FLOAT),
FLAPNESS("aFlapness", CommonAttributes.FLOAT),
;
private final String name;
private final VertexAttribSpec spec;
FlapAttributes(String name, VertexAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 1;
}
@Override
public int getBufferIndex() {
return 1;
}
}

View file

@ -1,39 +1,47 @@
package com.simibubi.create.foundation.render;
import com.jozufozu.flywheel.backend.core.materials.BasicAttributes;
import com.jozufozu.flywheel.backend.core.materials.OrientedAttributes;
import com.jozufozu.flywheel.backend.core.materials.TransformAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.MatrixAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.simibubi.create.content.contraptions.base.KineticAttributes;
import com.simibubi.create.content.contraptions.base.RotatingAttributes;
import com.simibubi.create.content.contraptions.components.actors.ActorVertexAttributes;
import com.simibubi.create.content.contraptions.relays.belt.BeltAttributes;
import com.simibubi.create.content.logistics.block.FlapAttributes;
public class AllInstanceFormats {
public static final VertexFormat MODEL = VertexFormat.builder()
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
public static final VertexFormat MODEL = litInstance()
.addAttributes(MatrixAttributes.MAT4,
MatrixAttributes.MAT3)
.build();
public static final VertexFormat ORIENTED = VertexFormat.builder()
.addAttributes(BasicAttributes.class)
.addAttributes(OrientedAttributes.class)
public static final VertexFormat ORIENTED = litInstance()
.addAttributes(CommonAttributes.VEC3, CommonAttributes.VEC3, CommonAttributes.QUATERNION)
.build();
public static VertexFormat ROTATING = VertexFormat.builder()
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(RotatingAttributes.class)
public static VertexFormat ROTATING = kineticInstance()
.addAttributes(CommonAttributes.NORMAL)
.build();
public static VertexFormat BELT = kineticInstance()
.addAttributes(CommonAttributes.QUATERNION, CommonAttributes.UV, CommonAttributes.VEC4,
CommonAttributes.NORMALIZED_BYTE)
.build();
public static VertexFormat ACTOR = VertexFormat.builder()
.addAttributes(ActorVertexAttributes.class)
.build();
public static VertexFormat BELT = VertexFormat.builder()
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(BeltAttributes.class)
.addAttributes(CommonAttributes.VEC3, CommonAttributes.LIGHT, CommonAttributes.FLOAT,
CommonAttributes.NORMAL, CommonAttributes.QUATERNION, CommonAttributes.NORMAL,
CommonAttributes.FLOAT)
.build();
public static VertexFormat FLAP = VertexFormat.builder()
.addAttributes(FlapAttributes.class)
.addAttributes(CommonAttributes.VEC3, CommonAttributes.LIGHT, CommonAttributes.VEC3, CommonAttributes.VEC3,
CommonAttributes.FLOAT, CommonAttributes.FLOAT, CommonAttributes.FLOAT, CommonAttributes.FLOAT)
.build();
private static VertexFormat.Builder litInstance() {
return VertexFormat.builder()
.addAttributes(CommonAttributes.LIGHT, CommonAttributes.RGBA);
}
private static VertexFormat.Builder kineticInstance() {
return litInstance()
.addAttributes(CommonAttributes.VEC3, CommonAttributes.FLOAT, CommonAttributes.FLOAT);
}
}

View file

@ -2,9 +2,9 @@ package com.simibubi.create.foundation.render;
import static com.jozufozu.flywheel.backend.Backend.register;
import com.jozufozu.flywheel.backend.core.materials.ModelAttributes;
import com.jozufozu.flywheel.backend.core.materials.ModelData;
import com.jozufozu.flywheel.backend.core.materials.OrientedData;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
import com.simibubi.create.Create;
@ -20,7 +20,9 @@ public class AllMaterialSpecs {
// noop, make sure the static field are loaded.
}
public static final VertexFormat UNLIT_MODEL = VertexFormat.builder().addAttributes(ModelAttributes.class).build();
public static final VertexFormat UNLIT_MODEL = VertexFormat.builder()
.addAttributes(CommonAttributes.VEC3, CommonAttributes.NORMAL, CommonAttributes.UV)
.build();
public static final MaterialSpec<ModelData> TRANSFORMED = register(new MaterialSpec<>(Locations.MODEL, AllProgramSpecs.MODEL, UNLIT_MODEL, AllInstanceFormats.MODEL, ModelData::new));
public static final MaterialSpec<OrientedData> ORIENTED = register(new MaterialSpec<>(Locations.ORIENTED, AllProgramSpecs.ORIENTED, UNLIT_MODEL, AllInstanceFormats.ORIENTED, OrientedData::new));

View file

@ -2,19 +2,9 @@ package com.simibubi.create.foundation.render;
import static com.jozufozu.flywheel.backend.Backend.register;
import com.jozufozu.flywheel.backend.core.materials.BasicAttributes;
import com.jozufozu.flywheel.backend.core.materials.ModelAttributes;
import com.jozufozu.flywheel.backend.core.materials.OrientedAttributes;
import com.jozufozu.flywheel.backend.core.materials.TransformAttributes;
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
import com.jozufozu.flywheel.backend.gl.shader.ShaderConstants;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.base.KineticAttributes;
import com.simibubi.create.content.contraptions.base.RotatingAttributes;
import com.simibubi.create.content.contraptions.components.actors.ActorVertexAttributes;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionAttributes;
import com.simibubi.create.content.contraptions.relays.belt.BeltAttributes;
import com.simibubi.create.content.logistics.block.FlapAttributes;
import net.minecraft.util.ResourceLocation;
@ -24,66 +14,44 @@ public class AllProgramSpecs {
}
public static final ProgramSpec CHROMATIC = register(builder("chromatic")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
.setVert(Locations.EFFECT_VERT)
.setFrag(Locations.EFFECT_FRAG)
.createProgramSpec());
.build());
public static final ProgramSpec MODEL = register(builder("model")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
.setVert(Locations.MODEL_VERT)
.setFrag(Locations.BLOCK)
.createProgramSpec());
.build());
public static final ProgramSpec ORIENTED = register(builder("oriented")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(OrientedAttributes.class)
.setVert(Locations.ORIENTED)
.setFrag(Locations.BLOCK)
.createProgramSpec());
.build());
public static final ProgramSpec ROTATING = register(builder("rotating")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(RotatingAttributes.class)
.setVert(Locations.ROTATING)
.setFrag(Locations.BLOCK)
.createProgramSpec());
.build());
public static final ProgramSpec BELT = register(builder("belt")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(BeltAttributes.class)
.setVert(Locations.BELT)
.setFrag(Locations.BLOCK)
.createProgramSpec());
.build());
public static final ProgramSpec FLAPS = register(builder("flap")
.addAttributes(ModelAttributes.class)
.addAttributes(FlapAttributes.class)
.setVert(Locations.FLAP)
.setFrag(Locations.BLOCK)
.createProgramSpec());
.build());
public static final ProgramSpec STRUCTURE = register(builder("contraption_structure")
.addAttributes(ContraptionAttributes.class)
.setVert(Locations.CONTRAPTION_STRUCTURE)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
.build());
public static final ProgramSpec ACTOR = register(builder("contraption_actor")
.addAttributes(ModelAttributes.class)
.addAttributes(ActorVertexAttributes.class)
.setVert(Locations.CONTRAPTION_ACTOR)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
.build());
public static ProgramSpec.Builder builder(String name) {
return ProgramSpec.builder(new ResourceLocation(Create.ID, name));

View file

@ -1,14 +1,14 @@
package com.simibubi.create.foundation.render;
import com.jozufozu.flywheel.backend.Backend;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionContext;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.fluid.FluidRenderer;
import com.simibubi.create.foundation.render.effects.EffectsContext;
public class CreateFlywheelHandler {
public static void init() {
Backend.register(ContraptionContext.INSTANCE);
Backend.register(ContraptionRenderDispatcher.TILES);
Backend.register(ContraptionRenderDispatcher.STRUCTURE);
Backend.register(EffectsContext.INSTANCE);
Backend.listeners.renderLayerListener(ContraptionRenderDispatcher::renderLayer);
Backend.listeners.renderLayerListener(FluidRenderer::renderLayer);

View file

@ -2,8 +2,8 @@ package com.simibubi.create.foundation.render.effects;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.gl.shader.SingleProgram;
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import net.minecraft.util.ResourceLocation;
@ -12,20 +12,14 @@ public class EffectsContext extends ShaderContext<SphereFilterProgram> {
public static final EffectsContext INSTANCE = new EffectsContext();
private final SingleProgram.SpecLoader<SphereFilterProgram> loader;
public EffectsContext() {
super(new ResourceLocation("create", "effects"));
loader = new SingleProgram.SpecLoader<>(SphereFilterProgram::new);
super(new ResourceLocation("create", "effects"), new SingleProgram.SpecLoader<>(SphereFilterProgram::new));
}
@Override
public void load(ShaderLoader loader) {
transformer = new ShaderTransformer()
.pushStage(loader::processIncludes);
loadProgramFromSpec(loader, AllProgramSpecs.CHROMATIC);
}
@Override
public ShaderSpecLoader<SphereFilterProgram> getLoader() {
return loader;
}
}

View file

@ -1,38 +0,0 @@
package com.simibubi.create.foundation.render.effects;
import com.jozufozu.flywheel.backend.gl.attrib.CommonAttributes;
import com.jozufozu.flywheel.backend.gl.attrib.IAttribSpec;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
public enum ScreenQuadAttributes implements IVertexAttrib {
INSTANCE_POS("aVertex", CommonAttributes.VEC4),
;
private final String name;
private final IAttribSpec spec;
ScreenQuadAttributes(String name, IAttribSpec spec) {
this.name = name;
this.spec = spec;
}
@Override
public String attribName() {
return name;
}
@Override
public IAttribSpec attribSpec() {
return spec;
}
@Override
public int getDivisor() {
return 0;
}
@Override
public int getBufferIndex() {
return 0;
}
}

View file

@ -1,4 +1,3 @@
#version 110
#define PI 3.1415926538
#flwbuiltins
@ -6,55 +5,45 @@
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Belt {
vec2 light;
vec4 color;
vec3 pos;
float speed;
float offset;
vec4 rotation;
vec2 sourceTexture;
vec4 scrollTexture;
float scrollMult;
};
attribute vec2 aLight;
attribute vec4 aColor;
attribute vec3 aInstancePos;
attribute float aSpeed;
attribute float aOffset;
attribute vec4 aInstanceRot;
attribute vec2 aSourceTexture;
attribute vec4 aScrollTexture;
attribute float aScrollMult;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
void main() {
vec3 rotated = rotateVertexByQuat(aPos - .5, aInstanceRot) + aInstancePos + .5;
BlockFrag FLWMain(Vertex v, Belt instance) {
vec3 rotated = rotateVertexByQuat(v.pos - .5, instance.rotation) + instance.pos + .5;
vec4 worldPos = vec4(rotated, 1.);
vec3 norm = rotateVertexByQuat(aNormal, aInstanceRot);
vec3 norm = rotateVertexByQuat(v.normal, instance.rotation);
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
float scrollSize = aScrollTexture.w - aScrollTexture.y;
float scroll = fract(aSpeed * uTime / (31.5 * 16.) + aOffset) * scrollSize * aScrollMult;
float scrollSize = instance.scrollTexture.w - instance.scrollTexture.y;
float scroll = fract(instance.speed * uTime / (31.5 * 16.) + instance.offset) * scrollSize * instance.scrollMult;
Diffuse = diffuse(norm);
TexCoords = aTexCoords - aSourceTexture + aScrollTexture.xy + vec2(0, scroll);
Light = aLight;
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords - instance.sourceTexture + instance.scrollTexture.xy + vec2(0, scroll);
b.light = instance.light;
#ifdef CONTRAPTION
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#if defined(RAINBOW_DEBUG)
b.color = instance.color;
#else
if (uDebug == 1) {
Color = aColor;
} else if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
b.color = vec4(1.);
#endif
return b;
}

View file

@ -1,16 +1,11 @@
#version 110
#flwbuiltins
varying vec2 TexCoords;
varying vec2 Light;
varying float Diffuse;
varying vec4 Color;
#flwinclude <"create:data/blockfragment.glsl">
void main() {
vec4 tex = FLWBlockTexture(TexCoords);
void FLWMain(BlockFrag r) {
vec4 tex = FLWBlockTexture(r.texCoords);
vec4 color = vec4(tex.rgb * FLWLight(Light).rgb * Diffuse, tex.a) * Color;
vec4 color = vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color;
FLWFinalizeColor(color);
}

View file

@ -1,17 +0,0 @@
#flwbuiltins
#[Fragment]
struct Raster {
vec2 texCoords;
vec4 color;
float diffuse;
vec2 light;
};
void FLWMain(Raster r) {
vec4 tex = FLWBlockTexture(r.texCoords);
vec4 color = vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color;
FLWFinalizeColor(color);
}

View file

@ -1,4 +1,4 @@
#flwinclude <"create:context/std/fog.glsl">
#flwinclude <"create:context/world/fog.glsl">
#flwinclude <"create:core/lightutil.glsl">
varying vec3 BoxCoord;

View file

@ -10,7 +10,6 @@ uniform mat4 uModel;
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
void FLWFinalizeWorldPos(inout vec4 worldPos) {

View file

@ -1,4 +1,4 @@
#flwinclude <"create:context/std/fog.glsl">
#flwinclude <"create:context/world/fog.glsl">
uniform vec2 uTextureScale;
uniform sampler2D uBlockAtlas;

View file

@ -1 +1 @@
#flwinclude <"create:context/std/builtin.vert">
#flwinclude <"create:context/world/builtin.vert">

View file

@ -1,4 +1,4 @@
#flwinclude <"create:context/std/fog.glsl">
#flwinclude <"create:context/world/fog.glsl">
#flwinclude <"create:core/lightutil.glsl">
uniform sampler2D uBlockAtlas;

View file

@ -1,6 +1,5 @@
uniform float uTime;
uniform mat4 uViewProjection;
uniform int uDebug;
uniform vec3 uCameraPos;
#if defined(USE_FOG)

View file

@ -1,4 +1,3 @@
#version 110
#define PI 3.1415926538
#flwbuiltins
@ -6,45 +5,38 @@
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/diffuse.glsl">
// model data
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Actor {
vec3 pos;
vec2 light;
float offset;
vec3 axis;
vec4 rotation;
vec3 rotationCenter;
float speed;
};
// instance data
attribute vec3 aInstancePos;
attribute vec2 aModelLight;
attribute float aOffset;
attribute vec3 aAxis;
attribute vec4 aInstanceRot;
attribute vec3 aRotationCenter;
attribute float aSpeed;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
varying float Diffuse;
varying vec2 TexCoords;
varying vec4 Color;
varying vec2 Light;
void main() {
float degrees = aOffset + uTime * aSpeed / 20.;
BlockFrag FLWMain(Vertex v, Actor instance) {
float degrees = instance.offset + uTime * instance.speed / 20.;
//float angle = fract(degrees / 360.) * PI * 2.;
vec4 kineticRot = quat(aAxis, degrees);
vec3 rotated = rotateVertexByQuat(aPos - aRotationCenter, kineticRot) + aRotationCenter;
vec4 kineticRot = quat(instance.axis, degrees);
vec3 rotated = rotateVertexByQuat(v.pos - instance.rotationCenter, kineticRot) + instance.rotationCenter;
vec4 worldPos = vec4(rotateVertexByQuat(rotated - .5, aInstanceRot) + aInstancePos + .5, 1.);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, kineticRot), aInstanceRot);
vec4 worldPos = vec4(rotateVertexByQuat(rotated - .5, instance.rotation) + instance.pos + .5, 1.);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(v.normal, kineticRot), instance.rotation);
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aModelLight;
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords;
b.light = instance.light;
b.color = vec4(1.);
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
return b;
}

View file

@ -1,34 +1,32 @@
#version 110
#define PI 3.1415926538
#flwbuiltins
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
attribute vec4 aColor;
attribute vec2 aModelLight;
#[VertexData]
struct Vertex {
vec3 pos;
vec3 normal;
vec2 texCoords;
vec4 color;
vec2 modelLight;
};
varying float Diffuse;
varying vec2 TexCoords;
varying vec4 Color;
varying vec2 Light;
#flwinclude <"create:data/blockfragment.glsl">
void main() {
vec4 worldPos = vec4(aPos, 1.);
vec3 norm = aNormal;
BlockFrag FLWMain(Vertex v) {
vec4 worldPos = vec4(v.pos, 1.);
vec3 norm = v.normal;
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Diffuse = diffuse(norm);
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = aColor / diffuse(aNormal);
}
TexCoords = aTexCoords;
Light = aModelLight;
BlockFrag b;
b.diffuse = diffuse(norm);
b.color = v.color / diffuse(v.normal);
b.texCoords = v.texCoords;
b.light = v.modelLight;
return b;
}

View file

@ -0,0 +1,7 @@
#[Fragment]
struct BlockFrag {
vec2 texCoords;
vec4 color;
float diffuse;
vec2 light;
};

View file

@ -0,0 +1,6 @@
#[VertexData]
struct Vertex {
vec3 pos;
vec3 normal;
vec2 texCoords;
};

View file

@ -1,4 +1,3 @@
#version 110
#define PI 3.1415926538
#flwbuiltins
@ -6,62 +5,58 @@
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Flap {
vec3 instancePos;
vec2 light;
vec3 segmentOffset;
vec3 pivot;
float horizontalAngle;
float intensity;
float flapScale;
float flapness;
};
attribute vec3 aInstancePos;
attribute vec2 aLight;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
attribute vec3 aSegmentOffset;
attribute vec3 aPivot;
attribute float aHorizontalAngle;
attribute float aIntensity;
attribute float aFlapScale;
attribute float aFlapness;
// outputs
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
float toRad(float degrees) {
return fract(degrees / 360.) * PI * 2.;
}
float getFlapAngle() {
float absFlap = abs(aFlapness);
float getFlapAngle(float flapness, float intensity, float scale) {
float absFlap = abs(flapness);
float angle = sin((1. - absFlap) * PI * aIntensity) * 30. * aFlapness * aFlapScale;
float angle = sin((1. - absFlap) * PI * intensity) * 30. * flapness * scale;
float halfAngle = angle * 0.5;
float which = step(0., aFlapness);
float degrees = which * halfAngle + (1. - which) * angle; // branchless conditional multiply
float which = step(0., flapness);// 0 if negative, 1 if positive
float degrees = which * halfAngle + (1. - which) * angle;// branchless conditional multiply
return degrees;
}
void main() {
float flapAngle = getFlapAngle();
BlockFrag FLWMain(Vertex v, Flap flap) {
float flapAngle = getFlapAngle(flap.flapness, flap.intensity, flap.flapScale);
vec4 orientation = quat(vec3(0., 1., 0.), -aHorizontalAngle);
vec4 orientation = quat(vec3(0., 1., 0.), -flap.horizontalAngle);
vec4 flapRotation = quat(vec3(1., 0., 0.), flapAngle);
vec3 rotated = rotateVertexByQuat(aPos - aPivot, flapRotation) + aPivot + aSegmentOffset;
rotated = rotateVertexByQuat(rotated - .5, orientation) + aInstancePos + .5;
vec3 rotated = rotateVertexByQuat(v.pos - flap.pivot, flapRotation) + flap.pivot + flap.segmentOffset;
rotated = rotateVertexByQuat(rotated - .5, orientation) + flap.instancePos + .5;
vec4 worldPos = vec4(rotated, 1.);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(aNormal, flapRotation), orientation);
vec3 norm = rotateVertexByQuat(rotateVertexByQuat(v.normal, flapRotation), orientation);
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
Color = vec4(1.);
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords;
b.light = flap.light;
b.color = vec4(1.);
return b;
}

View file

@ -1,35 +1,31 @@
#version 110
#flwbuiltins
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Instance {
vec2 light;
vec4 color;
mat4 transform;
mat3 normalMat;
};
attribute vec2 aLight;
attribute vec4 aColor;
attribute mat4 aTransform;
attribute mat3 aNormalMat;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
BlockFrag FLWMain(Vertex v, Instance i) {
vec4 worldPos = i.transform * vec4(v.pos, 1.);
void main() {
vec4 worldPos = aTransform * vec4(aPos, 1.);
vec3 norm = aNormalMat * aNormal;
vec3 norm = i.normalMat * v.normal;
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
norm = normalize(norm);
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
Color = aColor;
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords;
b.light = i.light;
b.color = i.color;
return b;
}

View file

@ -1,46 +0,0 @@
#flwbuiltins
#flwinclude <"create:core/diffuse.glsl">
#[VertexData]
struct Vertex {
#[Layout(float)]
vec3 pos;
vec3 normal;
vec2 texCoords;
};
#[InstanceData]
struct Instance {
#[Normalized(ushort)]
vec2 light;
#[Normalized(ubyte)]
vec4 color;
mat4 transform;
mat3 normalMat;
};
#[Fragment]
struct Raster {
vec2 texCoords;
vec4 color;
float diffuse;
vec2 light;
};
Raster FLWMain(Vertex v, Instance i) {
vec4 worldPos = i.transform * vec4(v.pos, 1.);
vec3 norm = i.normalMat * v.normal;
norm = normalize(norm);
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Raster r;
r.diffuse = diffuse(norm);
r.texCoords = v.texCoords;
r.light = i.light;
r.color = i.color;
return r;
}

View file

@ -1,36 +1,32 @@
#version 110
#flwbuiltins
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Oriented {
vec2 light;
vec4 color;
vec3 pos;
vec3 pivot;
vec4 rotation;
};
attribute vec2 aLight;
attribute vec4 aColor;
attribute vec3 aInstancePos;
attribute vec3 aPivot;
attribute vec4 aRotation;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
BlockFrag FLWMain(Vertex v, Oriented o) {
vec4 worldPos = vec4(rotateVertexByQuat(v.pos - o.pivot, o.rotation) + o.pivot + o.pos, 1.);
void main() {
vec4 worldPos = vec4(rotateVertexByQuat(aPos - aPivot, aRotation) + aPivot + aInstancePos, 1.);
vec3 norm = rotateVertexByQuat(aNormal, aRotation);
vec3 norm = rotateVertexByQuat(v.normal, o.rotation);
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
Color = aColor;
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords;
b.light = o.light;
b.color = o.color;
return b;
}

View file

@ -1,60 +1,51 @@
#version 110
#define PI 3.1415926538
#flwbuiltins
#flwinclude <"create:core/quaternion.glsl">
#flwinclude <"create:core/matutils.glsl">
#flwinclude <"create:core/diffuse.glsl">
attribute vec3 aPos;
attribute vec3 aNormal;
attribute vec2 aTexCoords;
#[InstanceData]
struct Rotating {
vec2 light;
vec4 color;
vec3 pos;
float speed;
float offset;
vec3 axis;
};
attribute vec2 aLight;
attribute vec4 aColor;
attribute vec3 aInstancePos;
attribute float aSpeed;
attribute float aOffset;
attribute vec3 aAxis;
#flwinclude <"create:data/modelvertex.glsl">
#flwinclude <"create:data/blockfragment.glsl">
varying vec2 TexCoords;
varying vec4 Color;
varying float Diffuse;
varying vec2 Light;
mat4 kineticRotation() {
float degrees = aOffset + uTime * aSpeed * 3./10.;
mat4 kineticRotation(float offset, float speed, vec3 axis) {
float degrees = offset + uTime * speed * 3./10.;
float angle = fract(degrees / 360.) * PI * 2.;
return rotate(aAxis, angle);
return rotate(axis, angle);
}
void main() {
mat4 kineticRotation = kineticRotation();
vec4 worldPos = kineticRotation * vec4(aPos - .5, 1.) + vec4(aInstancePos + .5, 0.);
BlockFrag FLWMain(Vertex v, Rotating instance) {
mat4 kineticRotation = kineticRotation(instance.offset, instance.speed, instance.axis);
vec3 norm = modelToNormal(kineticRotation) * aNormal;
vec4 worldPos = vec4(v.pos - .5, 1.);
worldPos *= kineticRotation;
worldPos += vec4(instance.pos + .5, 0.);
vec3 norm = modelToNormal(kineticRotation) * v.normal;
FLWFinalizeWorldPos(worldPos);
FLWFinalizeNormal(norm);
Diffuse = diffuse(norm);
TexCoords = aTexCoords;
Light = aLight;
BlockFrag b;
b.diffuse = diffuse(norm);
b.texCoords = v.texCoords;
b.light = instance.light;
#ifdef CONTRAPTION
if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
#if defined(RAINBOW_DEBUG)
b.color = instance.color;
#else
if (uDebug == 1) {
Color = aColor;
} else if (uDebug == 2) {
Color = vec4(norm, 1.);
} else {
Color = vec4(1.);
}
b.color = vec4(1.);
#endif
return b;
}

View file

@ -0,0 +1,12 @@
#version 110
#flwbeginbody
#FLWPrefixFields(Fragment, varying, v2f_)
void main() {
Fragment f;
#FLWAssignFields(Fragment, f., v2f_)
FLWMain(f);
}

View file

@ -0,0 +1,15 @@
#version 110
#flwbeginbody
#FLWPrefixFields(VertexData, attribute, a_v_)
#FLWPrefixFields(Fragment, varying, v2f_)
void main() {
VertexData v;
#FLWAssignFields(VertexData, v., a_v_)
Fragment o = FLWMain(v);
#FLWAssignFields(Fragment, v2f_, o.)
}