ShaderContexts

- A huge step towards more arbitrary shader usage
 - Need to work on registration of the different parts
 - Things are unorganized
This commit is contained in:
JozsefA 2021-05-03 21:46:33 -07:00
parent fcbab5b820
commit bc5630e593
28 changed files with 349 additions and 230 deletions

View file

@ -8,9 +8,10 @@ import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GLCapabilities;
import com.jozufozu.flywheel.backend.core.ContraptionContext;
import com.jozufozu.flywheel.backend.core.EffectsContext;
import com.jozufozu.flywheel.backend.core.WorldContext;
import com.jozufozu.flywheel.backend.effects.EffectsHandler;
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.versioned.GlCompat;
import com.jozufozu.flywheel.backend.instancing.IFlywheelWorld;
@ -38,28 +39,41 @@ public class Backend {
private static boolean instancingAvailable;
private static boolean enabled;
static final Map<ResourceLocation, ProgramSpec<?>> registry = new HashMap<>();
static final Map<ProgramSpec<?>, IMultiProgram<?>> programs = new HashMap<>();
static final Map<ResourceLocation, ShaderContext<?>> contexts = new HashMap<>();
static final Map<ResourceLocation, ProgramSpec> specRegistry = new HashMap<>();
static {
register(WorldContext.INSTANCE);
register(ContraptionContext.INSTANCE);
register(EffectsContext.INSTANCE);
}
public Backend() {
throw new IllegalStateException();
}
/**
* Register a shader program. TODO: replace with forge registry?
* Register a shader program.
*/
public static <P extends GlProgram, S extends ProgramSpec<P>> S register(S spec) {
public static ProgramSpec register(ProgramSpec spec) {
ResourceLocation name = spec.name;
if (registry.containsKey(name)) {
if (specRegistry.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
registry.put(name, spec);
specRegistry.put(name, spec);
return spec;
}
@SuppressWarnings("unchecked")
public static <P extends GlProgram, S extends ProgramSpec<P>> P getProgram(S spec) {
return (P) programs.get(spec).get();
/**
* Register a shader context.
*/
public static ShaderContext<?> register(ShaderContext<?> spec) {
ResourceLocation name = spec.getRoot();
if (contexts.containsKey(name)) {
throw new IllegalStateException("Program spec '" + name + "' already registered.");
}
contexts.put(name, spec);
return spec;
}
public static boolean isFlywheelWorld(World world) {

View file

@ -1,10 +1,21 @@
package com.jozufozu.flywheel.backend;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.jozufozu.flywheel.backend.core.OrientedModel;
import com.jozufozu.flywheel.backend.core.TransformedModel;
import com.jozufozu.flywheel.backend.instancing.MaterialFactory;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.foundation.render.KineticRenderer;
import com.simibubi.create.content.contraptions.base.KineticRenderMaterials;
import com.simibubi.create.content.contraptions.base.RotatingModel;
import com.simibubi.create.content.contraptions.components.actors.ActorModel;
import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel;
import com.simibubi.create.content.logistics.block.FlapModel;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import com.simibubi.create.foundation.utility.WorldAttached;
import net.minecraft.client.Minecraft;
@ -17,8 +28,23 @@ import net.minecraft.world.World;
public class FastRenderDispatcher {
public static Map<MaterialType<?>, MaterialFactory> materials = new HashMap<>();
static {
registerMaterials();
}
public static WorldAttached<ConcurrentHashMap.KeySetView<TileEntity, Boolean>> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet);
public static void registerMaterials() {
materials.put(MaterialTypes.TRANSFORMED, new MaterialFactory(AllProgramSpecs.MODEL, TransformedModel::new));
materials.put(MaterialTypes.ORIENTED, new MaterialFactory(AllProgramSpecs.ORIENTED, OrientedModel::new));
materials.put(KineticRenderMaterials.BELTS, new MaterialFactory(AllProgramSpecs.BELT, BeltInstancedModel::new));
materials.put(KineticRenderMaterials.ROTATING, new MaterialFactory(AllProgramSpecs.ROTATING, RotatingModel::new));
materials.put(KineticRenderMaterials.FLAPS, new MaterialFactory(AllProgramSpecs.FLAPS, FlapModel::new));
materials.put(KineticRenderMaterials.ACTORS, new MaterialFactory(AllProgramSpecs.C_ACTOR, ActorModel::new));
}
public static void enqueueUpdate(TileEntity te) {
queuedUpdates.get(te.getWorld()).add(te);
}
@ -27,7 +53,7 @@ public class FastRenderDispatcher {
Minecraft mc = Minecraft.getInstance();
ClientWorld world = mc.world;
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
BasicInstancedTileRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
Entity renderViewEntity = mc.renderViewEntity;
kineticRenderer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
@ -61,7 +87,7 @@ public class FastRenderDispatcher {
if (!Backend.canUseInstancing()) return;
ClientWorld world = Minecraft.getInstance().world;
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
BasicInstancedTileRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
layer.startDrawing();

View file

@ -0,0 +1,10 @@
package com.jozufozu.flywheel.backend;
import net.minecraft.util.ResourceLocation;
public class ResourceUtil {
public static ResourceLocation subPath(ResourceLocation root, String subPath) {
return new ResourceLocation(root.getNamespace(), root.getPath() + subPath);
}
}

View file

@ -0,0 +1,54 @@
package com.jozufozu.flywheel.backend;
import java.util.HashMap;
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.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public abstract class ShaderContext<P extends GlProgram> {
public final Map<ProgramSpec, IMultiProgram<P>> programs = new HashMap<>();
public final ResourceLocation root;
public ShaderContext(ResourceLocation root) {
this.root = root;
}
public abstract ShaderSpecLoader<P> getLoader();
public void load(ShaderLoader loader) {
programs.values().forEach(IMultiProgram::delete);
programs.clear();
for (ProgramSpec programSpec : Backend.specRegistry.values()) {
loadProgramFromSpec(loader, programSpec);
}
}
public void loadProgramFromSpec(ShaderLoader loader, ProgramSpec programSpec) {
programs.put(programSpec, getLoader().create(loader, this, programSpec));
Backend.log.debug("Loaded program {}", programSpec.name);
}
public String preProcess(ShaderLoader loader, String shaderSrc, ShaderType type) {
return shaderSrc;
}
public P getProgram(ProgramSpec spec) {
return programs.get(spec).get();
}
public ResourceLocation getRoot() {
return root;
}
}

View file

@ -28,7 +28,6 @@ import com.google.common.collect.Lists;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
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.ShaderType;
@ -46,10 +45,9 @@ public class ShaderLoader {
// #flwinclude <"valid_namespace:valid/path_to_file.glsl">
private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">");
private static final Pattern builtinPattern = Pattern.compile("#flwbuiltins");
private static boolean debugDumpFile = true;
final Map<ResourceLocation, String> shaderSource = new HashMap<>();
private final Map<ResourceLocation, String> shaderSource = new HashMap<>();
void onResourceManagerReload(IResourceManager manager, Predicate<IResourceType> predicate) {
if (predicate.test(VanillaResourceType.SHADERS)) {
@ -60,9 +58,9 @@ public class ShaderLoader {
shaderSource.clear();
loadShaderSources(manager);
Backend.programs.values().forEach(IMultiProgram::delete);
Backend.programs.clear();
Backend.registry.values().forEach(this::loadProgramFromSpec);
for (ShaderContext<?> context : Backend.contexts.values()) {
context.load(this);
}
Backend.log.info("Loaded all shader programs.");
@ -72,6 +70,10 @@ public class ShaderLoader {
}
}
public String getShaderSource(ResourceLocation loc) {
return shaderSource.get(loc);
}
private void loadShaderSources(IResourceManager manager) {
Collection<ResourceLocation> allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> {
for (String ext : EXTENSIONS) {
@ -96,27 +98,20 @@ public class ShaderLoader {
}
}
private <P extends GlProgram, S extends ProgramSpec<P>> void loadProgramFromSpec(S programSpec) {
Backend.programs.put(programSpec, programSpec.finalizer.create(this, programSpec));
Backend.log.debug("Loaded program {}", programSpec.name);
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ProgramSpec programSpec) {
return loadProgram(ctx, programSpec, programSpec.defines);
}
public GlProgram.Builder loadProgram(ProgramSpec<?> programSpec) {
return loadProgram(programSpec, programSpec.defines);
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ProgramSpec programSpec, ShaderConstants defines) {
return loadProgram(ctx, programSpec.name, programSpec.vert, programSpec.frag, programSpec.attributes, defines);
}
public GlProgram.Builder loadProgram(ProgramSpec<?> programSpec, ShaderConstants defines) {
return loadProgram(programSpec.name, programSpec.vert, programSpec.frag, programSpec.attributes, defines);
}
public GlProgram.Builder loadProgram(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, Collection<IVertexAttrib> attribs, ShaderConstants defines) {
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ResourceLocation name, ResourceLocation vert, ResourceLocation frag, Collection<IVertexAttrib> attribs, ShaderConstants defines) {
GlShader vsh = null;
GlShader fsh = null;
try {
vsh = loadShader(vert, ShaderType.VERTEX, defines);
fsh = loadShader(frag, ShaderType.FRAGMENT, defines);
vsh = loadShader(ctx, vert, ShaderType.VERTEX, defines);
fsh = loadShader(ctx, frag, ShaderType.FRAGMENT, defines);
return GlProgram.builder(name)
.attachShader(vsh)
@ -129,10 +124,10 @@ public class ShaderLoader {
}
}
public GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) {
public GlShader loadShader(ShaderContext<?> ctx, ResourceLocation name, ShaderType type, ShaderConstants defines) {
String source = shaderSource.get(name);
source = expandBuiltins(source, type);
source = ctx.preProcess(this, source, type);
source = processIncludes(source, name);
if (defines != null)
@ -149,33 +144,6 @@ public class ShaderLoader {
return new GlShader(type, name, source);
}
private String expandBuiltins(String source, ShaderType type) {
return lines(source).flatMap(line -> {
Matcher matcher = builtinPattern.matcher(line);
if (matcher.find()) {
ResourceLocation builtins;
switch (type) {
case FRAGMENT:
builtins = new ResourceLocation("create", "std/builtin.frag");
break;
case VERTEX:
builtins = new ResourceLocation("create", "std/builtin.vert");
break;
default:
builtins = null;
}
String includeSource = shaderSource.get(builtins);
return lines(includeSource);
}
return Stream.of(line);
}).collect(Collectors.joining("\n"));
}
private String processIncludes(String source, ResourceLocation baseName) {
HashSet<ResourceLocation> seen = new HashSet<>();
seen.add(baseName);

View file

@ -2,11 +2,8 @@ package com.jozufozu.flywheel.backend.core;
import java.util.ArrayList;
import com.jozufozu.flywheel.backend.MaterialTypes;
import com.jozufozu.flywheel.backend.gl.shader.ShaderCallback;
import com.jozufozu.flywheel.backend.instancing.InstancedTileRenderer;
import com.jozufozu.flywheel.backend.instancing.RenderMaterial;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.RenderType;
@ -20,11 +17,8 @@ public class BasicInstancedTileRenderer extends InstancedTileRenderer<BasicProgr
public BlockPos originCoordinate = BlockPos.ZERO;
@Override
public void registerMaterials() {
materials.put(MaterialTypes.TRANSFORMED,
new RenderMaterial<>(this, AllProgramSpecs.MODEL, TransformedModel::new));
materials.put(MaterialTypes.ORIENTED, new RenderMaterial<>(this, AllProgramSpecs.ORIENTED, OrientedModel::new));
public BasicInstancedTileRenderer() {
super(WorldContext.INSTANCE);
}
@Override

View file

@ -0,0 +1,17 @@
package com.jozufozu.flywheel.backend.core;
import com.jozufozu.flywheel.backend.gl.shader.FogSensitiveProgram;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionProgram;
import net.minecraft.util.ResourceLocation;
public class ContraptionContext extends WorldContext<ContraptionProgram> {
public static final ContraptionContext INSTANCE = new ContraptionContext();
public ContraptionContext() {
super(new ResourceLocation("create", "contraption"), new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new));
}
}

View file

@ -0,0 +1,32 @@
package com.jozufozu.flywheel.backend.core;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
import com.jozufozu.flywheel.backend.effects.SphereFilterProgram;
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.gl.shader.SingleProgram;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import net.minecraft.util.ResourceLocation;
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);
}
@Override
public void load(ShaderLoader loader) {
loadProgramFromSpec(loader, AllProgramSpecs.CHROMATIC);
}
@Override
public ShaderSpecLoader<SphereFilterProgram> getLoader() {
return loader;
}
}

View file

@ -0,0 +1,76 @@
package com.jozufozu.flywheel.backend.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.jozufozu.flywheel.backend.ResourceUtil;
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.ShaderSpecLoader;
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
import net.minecraft.util.ResourceLocation;
public class WorldContext<P extends BasicProgram> extends ShaderContext<P> {
private static final Pattern builtinPattern = Pattern.compile("#flwbuiltins");
public static final WorldContext<BasicProgram> INSTANCE = new WorldContext<>(new ResourceLocation("create", "std"), new FogSensitiveProgram.SpecLoader<>(BasicProgram::new));
private final ShaderSpecLoader<P> loader;
public final ResourceLocation frag;
public final ResourceLocation vert;
public WorldContext(ResourceLocation root, ShaderSpecLoader<P> loader) {
super(root);
this.frag = ResourceUtil.subPath(root, "/builtin.frag");
this.vert = ResourceUtil.subPath(root, "/builtin.vert");
this.loader = loader;
}
@Override
public String preProcess(ShaderLoader loader, String shaderSrc, ShaderType type) {
return ShaderLoader.lines(shaderSrc).flatMap(line -> {
Matcher matcher = builtinPattern.matcher(line);
if (matcher.find()) {
ResourceLocation builtins;
switch (type) {
case FRAGMENT:
builtins = frag;
break;
case VERTEX:
builtins = vert;
break;
default:
builtins = null;
}
String includeSource = loader.getShaderSource(builtins);
return ShaderLoader.lines(includeSource);
}
return Stream.of(line);
}).collect(Collectors.joining("\n"));
}
public ResourceLocation getFrag() {
return frag;
}
public ResourceLocation getVert() {
return vert;
}
@Override
public ShaderSpecLoader<P> getLoader() {
return loader;
}
}

View file

@ -9,6 +9,7 @@ import org.lwjgl.opengl.GL30;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.RenderUtil;
import com.jozufozu.flywheel.backend.core.EffectsContext;
import com.jozufozu.flywheel.backend.gl.GlBuffer;
import com.jozufozu.flywheel.backend.gl.GlPrimitiveType;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
@ -95,7 +96,7 @@ public class EffectsHandler {
Backend.compat.fbo.bindFramebuffer(FramebufferConstants.FRAME_BUFFER, framebuffer.framebufferObject);
GL11.glClear(GL30.GL_COLOR_BUFFER_BIT);
SphereFilterProgram program = Backend.getProgram(AllProgramSpecs.CHROMATIC);
SphereFilterProgram program = EffectsContext.INSTANCE.getProgram(AllProgramSpecs.CHROMATIC);
program.bind();
program.bindColorTexture(mainBuffer.getColorAttachment());

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.gl.shader;
import java.util.EnumMap;
import java.util.Map;
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;
@ -36,7 +37,7 @@ public class FogSensitiveProgram<P extends GlProgram> implements IMultiProgram<P
}
@Override
public IMultiProgram<P> create(ShaderLoader loader, ProgramSpec<P> spec) {
public IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec) {
Map<GlFogMode, P> programs = new EnumMap<>(GlFogMode.class);
for (GlFogMode fogMode : GlFogMode.values()) {
@ -44,7 +45,7 @@ public class FogSensitiveProgram<P extends GlProgram> implements IMultiProgram<P
defines.defineAll(fogMode.getDefines());
GlProgram.Builder builder = loader.loadProgram(spec, defines);
GlProgram.Builder builder = loader.loadProgram(ctx, spec, defines);
programs.put(fogMode, fogProgramLoader.create(builder.name, builder.program, fogMode.getFogFactory()));
}

View file

@ -4,11 +4,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
import com.simibubi.create.Create;
import net.minecraft.util.ResourceLocation;
public class ProgramSpec<P extends GlProgram> {
public class ProgramSpec {
public final ResourceLocation name;
public final ResourceLocation vert;
@ -18,63 +17,54 @@ public class ProgramSpec<P extends GlProgram> {
public final ArrayList<IVertexAttrib> attributes;
public final ShaderSpecLoader<P> finalizer;
public static <P extends GlProgram> Builder<P> builder(String name, ShaderSpecLoader<P> factory) {
return builder(new ResourceLocation(Create.ID, name), factory);
public static Builder builder(ResourceLocation name) {
return new Builder(name);
}
public static <P extends GlProgram> Builder<P> builder(ResourceLocation name, ShaderSpecLoader<P> factory) {
return new Builder<>(name, factory);
}
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, ShaderConstants defines, ArrayList<IVertexAttrib> attributes, ShaderSpecLoader<P> finalizer) {
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, ShaderConstants defines, ArrayList<IVertexAttrib> attributes) {
this.name = name;
this.vert = vert;
this.frag = frag;
this.defines = defines;
this.attributes = attributes;
this.finalizer = finalizer;
}
public static class Builder<P extends GlProgram> {
public static class Builder {
private ResourceLocation vert;
private ResourceLocation frag;
private ShaderConstants defines = ShaderConstants.EMPTY;
private final ShaderSpecLoader<P> loader;
private final ResourceLocation name;
private final ArrayList<IVertexAttrib> attributes;
public Builder(ResourceLocation name, ShaderSpecLoader<P> factory) {
public Builder(ResourceLocation name) {
this.name = name;
this.loader = factory;
attributes = new ArrayList<>();
}
public Builder<P> setVert(ResourceLocation vert) {
public Builder setVert(ResourceLocation vert) {
this.vert = vert;
return this;
}
public Builder<P> setFrag(ResourceLocation frag) {
public Builder setFrag(ResourceLocation frag) {
this.frag = frag;
return this;
}
public Builder<P> setDefines(ShaderConstants defines) {
public Builder setDefines(ShaderConstants defines) {
this.defines = defines;
return this;
}
public <A extends Enum<A> & IVertexAttrib> Builder<P> addAttributes(Class<A> attributeEnum) {
public <A extends Enum<A> & IVertexAttrib> Builder addAttributes(Class<A> attributeEnum) {
attributes.addAll(Arrays.asList(attributeEnum.getEnumConstants()));
return this;
}
public ProgramSpec<P> createProgramSpec() {
return new ProgramSpec<>(name, vert, frag, defines, attributes, loader);
public ProgramSpec createProgramSpec() {
return new ProgramSpec(name, vert, frag, defines, attributes);
}
}

View file

@ -1,7 +1,8 @@
package com.jozufozu.flywheel.backend.gl.shader;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.ShaderLoader;
public interface ShaderSpecLoader<P extends GlProgram> {
IMultiProgram<P> create(ShaderLoader loader, ProgramSpec<P> spec);
IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec);
}

View file

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

View file

@ -7,8 +7,10 @@ import java.util.Map;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.FastRenderDispatcher;
import com.jozufozu.flywheel.backend.MaterialType;
import com.jozufozu.flywheel.backend.MaterialTypes;
import com.jozufozu.flywheel.backend.ShaderContext;
import com.jozufozu.flywheel.backend.core.BasicProgram;
import com.jozufozu.flywheel.backend.core.ModelData;
import com.jozufozu.flywheel.backend.core.OrientedData;
@ -32,19 +34,21 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
protected Map<TileEntity, ITickableInstance> tickableInstances = new HashMap<>();
protected Map<TileEntity, IDynamicInstance> dynamicInstances = new HashMap<>();
public final ShaderContext<P> context;
protected Map<MaterialType<?>, RenderMaterial<P, ?>> materials = new HashMap<>();
protected int frame;
protected int tick;
protected InstancedTileRenderer() {
registerMaterials();
protected InstancedTileRenderer(ShaderContext<P> context) {
this.context = context;
FastRenderDispatcher.materials.forEach((key, value) -> materials.put(key, value.create(this)));
}
public abstract BlockPos getOriginCoordinate();
public abstract void registerMaterials();
public void tick(double cameraX, double cameraY, double cameraZ) {
tick++;

View file

@ -0,0 +1,19 @@
package com.jozufozu.flywheel.backend.instancing;
import com.jozufozu.flywheel.backend.core.BasicProgram;
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
public class MaterialFactory {
ProgramSpec programSpec;
ModelFactory<?> modelFactory;
public MaterialFactory(ProgramSpec programSpec, ModelFactory<?> modelFactory) {
this.programSpec = programSpec;
this.modelFactory = modelFactory;
}
public <P extends BasicProgram> RenderMaterial<P, ?> create(InstancedTileRenderer<P> renderer) {
return new RenderMaterial<>(renderer, programSpec, modelFactory);
}
}

View file

@ -9,7 +9,6 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.FastRenderDispatcher;
import com.jozufozu.flywheel.backend.RenderUtil;
import com.jozufozu.flywheel.backend.core.BasicProgram;
@ -30,20 +29,20 @@ import net.minecraft.util.math.vector.Matrix4f;
public class RenderMaterial<P extends BasicProgram, MODEL extends InstancedModel<?>> {
protected final InstancedTileRenderer<?> renderer;
protected final InstancedTileRenderer<P> renderer;
protected final Cache<Object, MODEL> models;
protected final ModelFactory<MODEL> factory;
protected final ProgramSpec<P> programSpec;
protected final ProgramSpec programSpec;
protected final Predicate<RenderType> layerPredicate;
/**
* Creates a material that renders in the default layer (CUTOUT_MIPPED)
*/
public RenderMaterial(InstancedTileRenderer<?> renderer, ProgramSpec<P> programSpec, ModelFactory<MODEL> factory) {
public RenderMaterial(InstancedTileRenderer<P> renderer, ProgramSpec programSpec, ModelFactory<MODEL> factory) {
this(renderer, programSpec, factory, type -> type == RenderType.getCutoutMipped());
}
public RenderMaterial(InstancedTileRenderer<?> renderer, ProgramSpec<P> programSpec, ModelFactory<MODEL> factory, Predicate<RenderType> layerPredicate) {
public RenderMaterial(InstancedTileRenderer<P> renderer, ProgramSpec programSpec, ModelFactory<MODEL> factory, Predicate<RenderType> layerPredicate) {
this.renderer = renderer;
this.models = CacheBuilder.newBuilder()
.removalListener(notification -> ((InstancedModel<?>) notification.getValue()).delete())
@ -62,7 +61,7 @@ public class RenderMaterial<P extends BasicProgram, MODEL extends InstancedModel
}
public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, ShaderCallback<P> setup) {
P program = Backend.getProgram(programSpec);
P program = renderer.context.getProgram(programSpec);
program.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode());
if (setup != null) setup.call(program);

View file

@ -9,6 +9,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.jozufozu.flywheel.backend.core.PartialModel;
import com.jozufozu.flywheel.backend.instancing.InstancedTileRenderer;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
@ -27,7 +28,6 @@ import com.simibubi.create.foundation.item.CustomRenderedItems;
import com.simibubi.create.foundation.ponder.content.PonderIndex;
import com.simibubi.create.foundation.ponder.elements.WorldSectionElement;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import com.simibubi.create.foundation.render.KineticRenderer;
import com.simibubi.create.foundation.render.SuperByteBufferCache;
import com.simibubi.create.foundation.utility.WorldAttached;
import com.simibubi.create.foundation.utility.ghost.GhostBlocks;
@ -65,7 +65,7 @@ public class CreateClient {
public static SchematicHandler schematicHandler;
public static SchematicAndQuillHandler schematicAndQuillHandler;
public static SuperByteBufferCache bufferCache;
public static WorldAttached<KineticRenderer> kineticRenderer;
public static WorldAttached<BasicInstancedTileRenderer> kineticRenderer;
public static final Outliner outliner = new Outliner();
public static GhostBlocks ghostBlocks;
@ -88,7 +88,7 @@ public class CreateClient {
public static void clientInit(FMLClientSetupEvent event) {
AllProgramSpecs.init();
kineticRenderer = new WorldAttached<>(KineticRenderer::new);
kineticRenderer = new WorldAttached<>(BasicInstancedTileRenderer::new);
schematicSender = new ClientSchematicLoader();
schematicHandler = new SchematicHandler();

View file

@ -7,22 +7,15 @@ import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.backend.MaterialTypes;
import com.jozufozu.flywheel.backend.core.OrientedModel;
import com.jozufozu.flywheel.backend.core.TransformedModel;
import com.jozufozu.flywheel.backend.core.ContraptionContext;
import com.jozufozu.flywheel.backend.instancing.InstancedModel;
import com.jozufozu.flywheel.backend.instancing.InstancedTileRenderer;
import com.jozufozu.flywheel.backend.instancing.RenderMaterial;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.content.contraptions.base.KineticRenderMaterials;
import com.simibubi.create.content.contraptions.base.RotatingModel;
import com.simibubi.create.content.contraptions.components.actors.ActorData;
import com.simibubi.create.content.contraptions.components.actors.ActorModel;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel;
import com.simibubi.create.content.logistics.block.FlapModel;
import com.simibubi.create.foundation.render.AllProgramSpecs;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.util.math.BlockPos;
@ -35,19 +28,9 @@ public class ContraptionKineticRenderer extends InstancedTileRenderer<Contraptio
private final WeakReference<RenderedContraption> contraption;
ContraptionKineticRenderer(RenderedContraption contraption) {
this.contraption = new WeakReference<>(contraption);
}
@Override
public void registerMaterials() {
materials.put(MaterialTypes.TRANSFORMED, new RenderMaterial<>(this, AllProgramSpecs.C_MODEL, TransformedModel::new));
materials.put(MaterialTypes.ORIENTED, new RenderMaterial<>(this, AllProgramSpecs.C_ORIENTED, OrientedModel::new));
materials.put(KineticRenderMaterials.BELTS, new RenderMaterial<>(this, AllProgramSpecs.C_BELT, BeltInstancedModel::new));
materials.put(KineticRenderMaterials.ROTATING, new RenderMaterial<>(this, AllProgramSpecs.C_ROTATING, RotatingModel::new));
materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.C_FLAPS, FlapModel::new));
materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.C_ACTOR, ActorModel::new));
}
super(ContraptionContext.INSTANCE);
this.contraption = new WeakReference<>(contraption);
}
public void tick() {
actors.forEach(ActorInstance::tick);

View file

@ -10,6 +10,7 @@ import org.lwjgl.opengl.GL40;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.FastRenderDispatcher;
import com.jozufozu.flywheel.backend.core.ContraptionContext;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.CreateClient;
@ -81,12 +82,12 @@ public class ContraptionRenderDispatcher {
GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4
if (Backend.canUseVBOs()) {
ContraptionProgram structureShader = Backend.getProgram(AllProgramSpecs.C_STRUCTURE);
structureShader.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode());
for (RenderedContraption renderer : renderers.values()) {
renderer.doRenderLayer(layer, structureShader);
}
}
ContraptionProgram structureShader = ContraptionContext.INSTANCE.getProgram(AllProgramSpecs.C_STRUCTURE);
structureShader.bind(viewProjection, camX, camY, camZ, FastRenderDispatcher.getDebugMode());
for (RenderedContraption renderer : renderers.values()) {
renderer.doRenderLayer(layer, structureShader);
}
}
if (Backend.canUseInstancing()) {
for (RenderedContraption renderer : renderers.values()) {

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.jozufozu.flywheel.backend.FastRenderDispatcher;
import com.jozufozu.flywheel.backend.RenderWork;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.simibubi.create.AllFluids;
@ -36,7 +37,6 @@ import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.networking.LeftClickPacket;
import com.simibubi.create.foundation.ponder.PonderTooltipHandler;
import com.simibubi.create.foundation.render.KineticRenderer;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.sound.SoundScapes;
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
@ -144,7 +144,7 @@ public class ClientEvents {
if (world.isRemote() && world instanceof ClientWorld && !(world instanceof WrappedClientWorld)) {
CreateClient.invalidateRenderers(world);
AnimationTickHolder.reset();
KineticRenderer renderer = CreateClient.kineticRenderer.get(world);
BasicInstancedTileRenderer renderer = CreateClient.kineticRenderer.get(world);
renderer.invalidate();
((ClientWorld) world).loadedTileEntityList.forEach(renderer::add);
}

View file

@ -10,11 +10,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.FastRenderDispatcher;
import com.jozufozu.flywheel.backend.OptifineHandler;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.render.KineticRenderer;
import net.minecraft.block.BlockState;
import net.minecraft.client.renderer.ActiveRenderInfo;
@ -96,7 +96,7 @@ public class RenderHooksMixin {
Backend.refresh();
if (Backend.canUseInstancing() && world != null) {
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
BasicInstancedTileRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
kineticRenderer.invalidate();
world.loadedTileEntityList.forEach(kineticRenderer::add);
}

View file

@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.render.KineticRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
@ -46,7 +46,7 @@ public class TileWorldHookMixin {
@Inject(at = @At(value = "INVOKE", target = "Ljava/util/Set;clear()V", ordinal = 0), method = "tickBlockEntities")
private void onChunkUnload(CallbackInfo ci) {
if (isRemote) {
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(self);
BasicInstancedTileRenderer kineticRenderer = CreateClient.kineticRenderer.get(self);
for (TileEntity tile : tileEntitiesToBeRemoved) {
kineticRenderer.remove(tile);
}

View file

@ -3,21 +3,16 @@ package com.simibubi.create.foundation.render;
import static com.jozufozu.flywheel.backend.Backend.register;
import com.jozufozu.flywheel.backend.core.BasicAttributes;
import com.jozufozu.flywheel.backend.core.BasicProgram;
import com.jozufozu.flywheel.backend.core.ModelAttributes;
import com.jozufozu.flywheel.backend.core.OrientedAttributes;
import com.jozufozu.flywheel.backend.core.TransformAttributes;
import com.jozufozu.flywheel.backend.effects.SphereFilterProgram;
import com.jozufozu.flywheel.backend.gl.shader.FogSensitiveProgram;
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
import com.jozufozu.flywheel.backend.gl.shader.ShaderConstants;
import com.jozufozu.flywheel.backend.gl.shader.SingleProgram;
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.components.structureMovement.render.ContraptionProgram;
import com.simibubi.create.content.contraptions.relays.belt.BeltAttributes;
import com.simibubi.create.content.logistics.block.FlapAttributes;
@ -28,7 +23,7 @@ public class AllProgramSpecs {
// noop, make sure the static field are loaded.
}
public static final ProgramSpec<SphereFilterProgram> CHROMATIC = register(ProgramSpec.builder("chromatic", new SingleProgram.SpecLoader<>(SphereFilterProgram::new))
public static final ProgramSpec CHROMATIC = register(builder("chromatic")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
@ -36,7 +31,7 @@ public class AllProgramSpecs {
.setFrag(Locations.EFFECT_FRAG)
.createProgramSpec());
public static final ProgramSpec<BasicProgram> MODEL = register(ProgramSpec.builder("model", new FogSensitiveProgram.SpecLoader<>(BasicProgram::new))
public static final ProgramSpec MODEL = register(builder("model")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
@ -44,7 +39,7 @@ public class AllProgramSpecs {
.setFrag(Locations.BLOCK)
.createProgramSpec());
public static final ProgramSpec<BasicProgram> ORIENTED = register(ProgramSpec.builder("oriented", new FogSensitiveProgram.SpecLoader<>(BasicProgram::new))
public static final ProgramSpec ORIENTED = register(builder("oriented")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(OrientedAttributes.class)
@ -52,7 +47,7 @@ public class AllProgramSpecs {
.setFrag(Locations.BLOCK)
.createProgramSpec());
public static final ProgramSpec<BasicProgram> ROTATING = register(ProgramSpec.builder("rotating", new FogSensitiveProgram.SpecLoader<>(BasicProgram::new))
public static final ProgramSpec ROTATING = register(builder("rotating")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
@ -61,7 +56,7 @@ public class AllProgramSpecs {
.setFrag(Locations.BLOCK)
.createProgramSpec());
public static final ProgramSpec<BasicProgram> BELT = register(ProgramSpec.builder("belt", new FogSensitiveProgram.SpecLoader<>(BasicProgram::new))
public static final ProgramSpec BELT = register(builder("belt")
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
@ -70,60 +65,19 @@ public class AllProgramSpecs {
.setFrag(Locations.BLOCK)
.createProgramSpec());
public static final ProgramSpec<BasicProgram> FLAPS = register(ProgramSpec.builder("flap", new FogSensitiveProgram.SpecLoader<>(BasicProgram::new))
public static final ProgramSpec FLAPS = register(builder("flap")
.addAttributes(ModelAttributes.class)
.addAttributes(FlapAttributes.class)
.setVert(Locations.FLAP)
.setFrag(Locations.BLOCK)
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_STRUCTURE = register(ProgramSpec.builder("contraption_structure", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
public static final ProgramSpec C_STRUCTURE = register(builder("contraption_structure")
.addAttributes(ContraptionAttributes.class)
.setVert(Locations.CONTRAPTION_STRUCTURE)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_MODEL = register(ProgramSpec.builder("contraption_model", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(TransformAttributes.class)
.setVert(Locations.MODEL_VERT)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_ORIENTED = register(ProgramSpec.builder("contraption_oriented", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(OrientedAttributes.class)
.setVert(Locations.ORIENTED)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_ROTATING = register(ProgramSpec.builder("contraption_rotating", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(RotatingAttributes.class)
.setVert(Locations.ROTATING)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_BELT = register(ProgramSpec.builder("contraption_belt", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
.addAttributes(ModelAttributes.class)
.addAttributes(BasicAttributes.class)
.addAttributes(KineticAttributes.class)
.addAttributes(BeltAttributes.class)
.setVert(Locations.BELT)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_FLAPS = register(ProgramSpec.builder("contraption_flap", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
.addAttributes(ModelAttributes.class)
.addAttributes(FlapAttributes.class)
.setVert(Locations.FLAP)
.setFrag(Locations.BLOCK)
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static final ProgramSpec<ContraptionProgram> C_ACTOR = register(ProgramSpec.builder("contraption_actor", new FogSensitiveProgram.SpecLoader<>(ContraptionProgram::new))
public static final ProgramSpec C_ACTOR = register(builder("contraption_actor")
.addAttributes(ModelAttributes.class)
.addAttributes(ActorVertexAttributes.class)
.setVert(Locations.CONTRAPTION_ACTOR)
@ -131,6 +85,9 @@ public class AllProgramSpecs {
.setDefines(ShaderConstants.define("CONTRAPTION"))
.createProgramSpec());
public static ProgramSpec.Builder builder(String name) {
return ProgramSpec.builder(new ResourceLocation(Create.ID, name));
}
public static class Locations {
public static final ResourceLocation BLOCK = loc("block.frag");

View file

@ -1,22 +0,0 @@
package com.simibubi.create.foundation.render;
import com.jozufozu.flywheel.backend.core.BasicInstancedTileRenderer;
import com.jozufozu.flywheel.backend.instancing.RenderMaterial;
import com.simibubi.create.content.contraptions.base.KineticRenderMaterials;
import com.simibubi.create.content.contraptions.base.RotatingModel;
import com.simibubi.create.content.contraptions.relays.belt.BeltInstancedModel;
import com.simibubi.create.content.logistics.block.FlapModel;
public class KineticRenderer extends BasicInstancedTileRenderer {
@Override
public void registerMaterials() {
super.registerMaterials();
materials.put(KineticRenderMaterials.BELTS,
new RenderMaterial<>(this, AllProgramSpecs.BELT, BeltInstancedModel::new));
materials.put(KineticRenderMaterials.ROTATING,
new RenderMaterial<>(this, AllProgramSpecs.ROTATING, RotatingModel::new));
materials.put(KineticRenderMaterials.FLAPS, new RenderMaterial<>(this, AllProgramSpecs.FLAPS, FlapModel::new));
}
}

View file

@ -1,3 +1,5 @@
#flwinclude <"create:std/fog.glsl">
varying vec3 BoxCoord;
uniform sampler3D uLightVolume;

View file

@ -1,9 +1,5 @@
#flwinclude <"create:std/fog.glsl">
#if defined(CONTRAPTION)
#flwinclude <"create:contraption/builtin.frag">
#else
void FLWFinalizeColor(vec4 color) {
#if defined(USE_FOG)
float a = color.a;
@ -18,4 +14,3 @@ vec4 FLWLight(vec2 lightCoords, sampler2D lightMap) {
vec2 lm = lightCoords * 0.9375 + 0.03125;
return texture2D(lightMap, lm);
}
#endif

View file

@ -1,6 +1,3 @@
#if defined(CONTRAPTION)
#flwinclude <"create:contraption/builtin.vert">
#else
#if defined(USE_FOG)
varying float FragDistance;
@ -15,4 +12,3 @@ void FLWFinalizeWorldPos(inout vec4 worldPos, vec3 cameraPos) {
void FLWFinalizeNormal(inout vec3 normal) {
// noop
}
#endif