mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 23:47:09 +01:00
Turn it up to 11
- Consolidate context shaders into the common shaders, guarded by ifdefs - Make ContextShaders into an enum - Cache shaders by name instead of SourceComponents so the defines for contexts actually get compiled - Move all embedding stuff into backend.embed - Cannibalize GPULightVolume into an api better suited for environments - Separate light storage from 3d texture management - Add #delete to Environment - Add light volume debug mode
This commit is contained in:
parent
5d142d2f13
commit
b90b80c8b0
35 changed files with 509 additions and 373 deletions
|
@ -5,6 +5,8 @@ import org.joml.Matrix4fc;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
|
||||||
@BackendImplemented
|
@BackendImplemented
|
||||||
public interface VisualEmbedding extends VisualizationContext {
|
public interface VisualEmbedding extends VisualizationContext {
|
||||||
/**
|
/**
|
||||||
|
@ -14,4 +16,36 @@ public interface VisualEmbedding extends VisualizationContext {
|
||||||
* @param normal The normal matrix.
|
* @param normal The normal matrix.
|
||||||
*/
|
*/
|
||||||
void transforms(Matrix4fc pose, Matrix3fc normal);
|
void transforms(Matrix4fc pose, Matrix3fc normal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect light information from the given level for the given box.
|
||||||
|
*
|
||||||
|
* <p>Call this method on as many or as few boxes as you need to
|
||||||
|
* encompass all child visuals of this embedding.</p>
|
||||||
|
*
|
||||||
|
* <p>After this method is called, instances rendered from this
|
||||||
|
* embedding within the given box will be lit as if they were in
|
||||||
|
* the given level.</p>
|
||||||
|
*
|
||||||
|
* @param level The level to collect light information from.
|
||||||
|
* @param minX The minimum x coordinate of the box.
|
||||||
|
* @param minY The minimum y coordinate of the box.
|
||||||
|
* @param minZ The minimum z coordinate of the box.
|
||||||
|
* @param sizeX The size of the box in the x direction.
|
||||||
|
* @param sizeY The size of the box in the y direction.
|
||||||
|
* @param sizeZ The size of the box in the z direction.
|
||||||
|
*/
|
||||||
|
void light(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset any collected lighting information for the given box.
|
||||||
|
*
|
||||||
|
* @param minX The minimum x coordinate of the box.
|
||||||
|
* @param minY The minimum y coordinate of the box.
|
||||||
|
* @param minZ The minimum z coordinate of the box.
|
||||||
|
* @param sizeX The size of the box in the x direction.
|
||||||
|
* @param sizeY The size of the box in the y direction.
|
||||||
|
* @param sizeZ The size of the box in the z direction.
|
||||||
|
*/
|
||||||
|
void invalidateLight(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,4 +8,5 @@ public class Samplers {
|
||||||
public static final GlTextureUnit LIGHT = GlTextureUnit.T2;
|
public static final GlTextureUnit LIGHT = GlTextureUnit.T2;
|
||||||
public static final GlTextureUnit CRUMBLING = GlTextureUnit.T3;
|
public static final GlTextureUnit CRUMBLING = GlTextureUnit.T3;
|
||||||
public static final GlTextureUnit INSTANCE_BUFFER = GlTextureUnit.T4;
|
public static final GlTextureUnit INSTANCE_BUFFER = GlTextureUnit.T4;
|
||||||
|
public static final GlTextureUnit EMBEDDED_LIGHT = GlTextureUnit.T5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +1,40 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Locale;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.Samplers;
|
||||||
|
import com.jozufozu.flywheel.backend.compile.core.Compilation;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
public enum ContextShader {
|
||||||
|
DEFAULT(null, $ -> {
|
||||||
|
}),
|
||||||
|
CRUMBLING("_FLW_CRUMBLING", program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING)),
|
||||||
|
EMBEDDED("_FLW_EMBEDDED", program -> program.setSamplerBinding("_flw_lightVolume", Samplers.EMBEDDED_LIGHT));
|
||||||
|
|
||||||
public record ContextShader(ResourceLocation vertexShader, ResourceLocation fragmentShader,
|
@Nullable
|
||||||
Consumer<GlProgram> onLink) {
|
private final String define;
|
||||||
public static Builder builder() {
|
private final Consumer<GlProgram> onLink;
|
||||||
return new Builder();
|
|
||||||
|
ContextShader(@Nullable String define, Consumer<GlProgram> onLink) {
|
||||||
|
this.define = define;
|
||||||
|
this.onLink = onLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public void onLink(GlProgram program) {
|
||||||
@Nullable
|
onLink.accept(program);
|
||||||
private ResourceLocation vertexShader;
|
}
|
||||||
@Nullable
|
|
||||||
private ResourceLocation fragmentShader;
|
|
||||||
@Nullable
|
|
||||||
private Consumer<GlProgram> onLink;
|
|
||||||
|
|
||||||
public Builder vertexShader(ResourceLocation shader) {
|
public void onCompile(Compilation comp) {
|
||||||
this.vertexShader = shader;
|
if (define != null) {
|
||||||
return this;
|
comp.define(define);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Builder fragmentShader(ResourceLocation shader) {
|
public String nameLowerCase() {
|
||||||
this.fragmentShader = shader;
|
return name().toLowerCase(Locale.ROOT);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder onLink(Consumer<GlProgram> onLink) {
|
|
||||||
this.onLink = onLink;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContextShader build() {
|
|
||||||
Objects.requireNonNull(vertexShader);
|
|
||||||
Objects.requireNonNull(fragmentShader);
|
|
||||||
Objects.requireNonNull(onLink);
|
|
||||||
return new ContextShader(vertexShader, fragmentShader, onLink);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
|
||||||
import com.jozufozu.flywheel.api.internal.InternalFlywheelApi;
|
|
||||||
import com.jozufozu.flywheel.api.registry.Registry;
|
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
|
|
||||||
import com.jozufozu.flywheel.backend.Samplers;
|
|
||||||
|
|
||||||
public class ContextShaders {
|
|
||||||
public static final Registry<ContextShader> REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry();
|
|
||||||
public static final ContextShader DEFAULT = REGISTRY.registerAndGet(ContextShader.builder()
|
|
||||||
.vertexShader(Flywheel.rl("internal/context/default.vert"))
|
|
||||||
.fragmentShader(Flywheel.rl("internal/context/default.frag"))
|
|
||||||
.onLink($ -> {
|
|
||||||
})
|
|
||||||
.build());
|
|
||||||
public static final ContextShader CRUMBLING = REGISTRY.registerAndGet(ContextShader.builder()
|
|
||||||
.vertexShader(Flywheel.rl("internal/context/crumbling.vert"))
|
|
||||||
.fragmentShader(Flywheel.rl("internal/context/crumbling.frag"))
|
|
||||||
.onLink(program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING))
|
|
||||||
.build());
|
|
||||||
public static final ContextShader EMBEDDED = REGISTRY.registerAndGet(ContextShader.builder()
|
|
||||||
.vertexShader(Flywheel.rl("internal/context/embedded.vert"))
|
|
||||||
.fragmentShader(Flywheel.rl("internal/context/embedded.frag"))
|
|
||||||
.onLink($ -> {
|
|
||||||
})
|
|
||||||
.build());
|
|
||||||
|
|
||||||
public static ContextShader forEmbedding(@Nullable VisualEmbedding level) {
|
|
||||||
if (level == null) {
|
|
||||||
return DEFAULT;
|
|
||||||
} else {
|
|
||||||
return EMBEDDED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -57,7 +57,7 @@ public final class FlwPrograms {
|
||||||
|
|
||||||
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
|
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
|
||||||
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
|
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
|
||||||
for (ContextShader contextShader : ContextShaders.REGISTRY) {
|
for (ContextShader contextShader : ContextShader.values()) {
|
||||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||||
builder.add(new PipelineProgramKey(instanceType, contextShader));
|
builder.add(new PipelineProgramKey(instanceType, contextShader));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,12 @@ public class PipelineCompiler {
|
||||||
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
||||||
.vertexShader());
|
.vertexShader());
|
||||||
|
|
||||||
var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader()
|
var context = key.contextShader()
|
||||||
.vertexShader());
|
.nameLowerCase();
|
||||||
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
|
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
|
||||||
})
|
})
|
||||||
|
.onCompile((key, comp) -> key.contextShader()
|
||||||
|
.onCompile(comp))
|
||||||
.withResource(pipeline.vertexApiImpl())
|
.withResource(pipeline.vertexApiImpl())
|
||||||
.withResource(InternalVertex.LAYOUT_SHADER)
|
.withResource(InternalVertex.LAYOUT_SHADER)
|
||||||
.withComponent(key -> pipeline.assembler()
|
.withComponent(key -> pipeline.assembler()
|
||||||
|
@ -33,23 +35,18 @@ public class PipelineCompiler {
|
||||||
.withComponents(vertexComponents)
|
.withComponents(vertexComponents)
|
||||||
.withResource(key -> key.instanceType()
|
.withResource(key -> key.instanceType()
|
||||||
.vertexShader())
|
.vertexShader())
|
||||||
.withResource(key -> key.contextShader()
|
|
||||||
.vertexShader())
|
|
||||||
.withResource(pipeline.vertexMain()))
|
.withResource(pipeline.vertexMain()))
|
||||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||||
.nameMapper(key -> {
|
.nameMapper(key -> {
|
||||||
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
var context = key.contextShader()
|
||||||
.vertexShader());
|
.nameLowerCase();
|
||||||
|
return "pipeline/" + pipeline.compilerMarker() + "/" + context;
|
||||||
var context = ResourceUtil.toDebugFileNameNoExtension(key.contextShader()
|
|
||||||
.fragmentShader());
|
|
||||||
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
|
|
||||||
})
|
})
|
||||||
.enableExtension("GL_ARB_conservative_depth")
|
.enableExtension("GL_ARB_conservative_depth")
|
||||||
|
.onCompile((key, comp) -> key.contextShader()
|
||||||
|
.onCompile(comp))
|
||||||
.withResource(pipeline.fragmentApiImpl())
|
.withResource(pipeline.fragmentApiImpl())
|
||||||
.withComponents(fragmentComponents)
|
.withComponents(fragmentComponents)
|
||||||
.withResource(key -> key.contextShader()
|
|
||||||
.fragmentShader())
|
|
||||||
.withResource(pipeline.fragmentMain()))
|
.withResource(pipeline.fragmentMain()))
|
||||||
.preLink((key, program) -> {
|
.preLink((key, program) -> {
|
||||||
program.bindAttribLocation("_flw_a_pos", 0);
|
program.bindAttribLocation("_flw_a_pos", 0);
|
||||||
|
@ -71,8 +68,7 @@ public class PipelineCompiler {
|
||||||
pipeline.onLink()
|
pipeline.onLink()
|
||||||
.accept(program);
|
.accept(program);
|
||||||
key.contextShader()
|
key.contextShader()
|
||||||
.onLink()
|
.onLink(program);
|
||||||
.accept(program);
|
|
||||||
|
|
||||||
GlProgram.unbind();
|
GlProgram.unbind();
|
||||||
})
|
})
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class Compile<K> {
|
||||||
private final GlslVersion glslVersion;
|
private final GlslVersion glslVersion;
|
||||||
private final ShaderType shaderType;
|
private final ShaderType shaderType;
|
||||||
private final List<BiFunction<K, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
private final List<BiFunction<K, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
||||||
private Consumer<Compilation> compilationCallbacks = $ -> {
|
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
||||||
};
|
};
|
||||||
private Function<K, String> nameMapper = Object::toString;
|
private Function<K, String> nameMapper = Object::toString;
|
||||||
|
|
||||||
|
@ -146,17 +146,17 @@ public class Compile<K> {
|
||||||
return withResource($ -> resourceLocation);
|
return withResource($ -> resourceLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> onCompile(Consumer<Compilation> cb) {
|
public ShaderCompiler<K> onCompile(BiConsumer<K, Compilation> cb) {
|
||||||
compilationCallbacks = compilationCallbacks.andThen(cb);
|
compilationCallbacks = compilationCallbacks.andThen(cb);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> define(String def, int value) {
|
public ShaderCompiler<K> define(String def, int value) {
|
||||||
return onCompile(ctx -> ctx.define(def, String.valueOf(value)));
|
return onCompile(($, ctx) -> ctx.define(def, String.valueOf(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderCompiler<K> enableExtension(String extension) {
|
public ShaderCompiler<K> enableExtension(String extension) {
|
||||||
return onCompile(ctx -> ctx.enableExtension(extension));
|
return onCompile(($, ctx) -> ctx.enableExtension(extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -175,7 +175,8 @@ public class Compile<K> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), compilationCallbacks, components);
|
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
||||||
|
return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), cb, components);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class ShaderCache {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
|
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
|
||||||
var key = new ShaderKey(glslVersion, shaderType, sourceComponents);
|
var key = new ShaderKey(glslVersion, shaderType, name);
|
||||||
var cached = inner.get(key);
|
var cached = inner.get(key);
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
return cached.unwrap();
|
return cached.unwrap();
|
||||||
|
@ -69,6 +69,6 @@ public class ShaderCache {
|
||||||
included.addAll(component.included());
|
included.addAll(component.included());
|
||||||
}
|
}
|
||||||
|
|
||||||
private record ShaderKey(GlslVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
|
private record ShaderKey(GlslVersion glslVersion, ShaderType shaderType, String name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
|
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.Instancer;
|
import com.jozufozu.flywheel.api.instance.Instancer;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
import com.jozufozu.flywheel.lib.util.AtomicBitset;
|
import com.jozufozu.flywheel.lib.util.AtomicBitset;
|
||||||
|
|
||||||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
public record InstancerKey<I extends Instance>(Environment environment, InstanceType<I> type, Model model,
|
public record InstancerKey<I extends Instance>(Environment environment, InstanceType<I> type, Model model,
|
||||||
RenderStage stage) {
|
RenderStage stage) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.Instancer;
|
import com.jozufozu.flywheel.api.instance.Instancer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.GlobalEnvironment;
|
||||||
|
|
||||||
public record InstancerProviderImpl(AbstractEngine engine, RenderStage renderStage) implements InstancerProvider {
|
public record InstancerProviderImpl(AbstractEngine engine, RenderStage renderStage) implements InstancerProvider {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,10 @@ import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.Instancer;
|
import com.jozufozu.flywheel.api.instance.Instancer;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
||||||
|
|
||||||
public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||||
/**
|
/**
|
||||||
|
@ -19,6 +23,7 @@ public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||||
* This map is populated as instancers are requested and contains both initialized and uninitialized instancers.
|
* This map is populated as instancers are requested and contains both initialized and uninitialized instancers.
|
||||||
*/
|
*/
|
||||||
protected final Map<InstancerKey<?>, N> instancers = new ConcurrentHashMap<>();
|
protected final Map<InstancerKey<?>, N> instancers = new ConcurrentHashMap<>();
|
||||||
|
protected final ReferenceSet<Environment> environments = new ReferenceLinkedOpenHashSet<>();
|
||||||
/**
|
/**
|
||||||
* A list of instancers that have not yet been initialized.
|
* A list of instancers that have not yet been initialized.
|
||||||
* <br>
|
* <br>
|
||||||
|
@ -32,6 +37,12 @@ public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete() {
|
public void delete() {
|
||||||
|
// FIXME: The ownership of environments is a bit weird. Their resources are created and destroyed by the engine,
|
||||||
|
// but the engine doesn't own the things themselves. This makes it hard for the engine to know when to delete
|
||||||
|
// environments. For now, we just delete all environments when the engine is deleted, but this is not ideal.
|
||||||
|
environments.forEach(Environment::delete);
|
||||||
|
environments.clear();
|
||||||
|
|
||||||
instancers.clear();
|
instancers.clear();
|
||||||
initializationQueue.clear();
|
initializationQueue.clear();
|
||||||
}
|
}
|
||||||
|
@ -57,6 +68,8 @@ public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||||
private N createAndDeferInit(InstancerKey<?> key) {
|
private N createAndDeferInit(InstancerKey<?> key) {
|
||||||
var out = create(key);
|
var out = create(key);
|
||||||
|
|
||||||
|
environments.add(key.environment());
|
||||||
|
|
||||||
// Only queue the instancer for initialization if it has anything to render.
|
// Only queue the instancer for initialization if it has anything to render.
|
||||||
if (checkAndWarnEmptyModel(key.model())) {
|
if (checkAndWarnEmptyModel(key.model())) {
|
||||||
// Thread safety: this method is called atomically from within computeIfAbsent,
|
// Thread safety: this method is called atomically from within computeIfAbsent,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.engine;
|
package com.jozufozu.flywheel.backend.engine.embed;
|
||||||
|
|
||||||
import org.joml.Matrix3f;
|
import org.joml.Matrix3f;
|
||||||
import org.joml.Matrix3fc;
|
import org.joml.Matrix3fc;
|
||||||
|
@ -12,16 +12,21 @@ import com.jozufozu.flywheel.api.instance.Instancer;
|
||||||
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
|
import com.jozufozu.flywheel.api.visualization.VisualEmbedding;
|
||||||
|
import com.jozufozu.flywheel.backend.Samplers;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShaders;
|
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
|
||||||
public class EmbeddedEnvironment implements Environment, VisualEmbedding {
|
public class EmbeddedEnvironment implements Environment, VisualEmbedding {
|
||||||
private final Matrix4f pose = new Matrix4f();
|
private final Matrix4f pose = new Matrix4f();
|
||||||
private final Matrix3f normal = new Matrix3f();
|
private final Matrix3f normal = new Matrix3f();
|
||||||
|
|
||||||
|
private final EmbeddedLightVolume lightVolume = new EmbeddedLightVolume();
|
||||||
|
private final EmbeddedLightTexture lightTexture = new EmbeddedLightTexture();
|
||||||
|
|
||||||
private final InstancerProvider instancerProvider;
|
private final InstancerProvider instancerProvider;
|
||||||
private final AbstractEngine engine;
|
private final AbstractEngine engine;
|
||||||
private final RenderStage renderStage;
|
private final RenderStage renderStage;
|
||||||
|
@ -45,15 +50,39 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
|
||||||
this.normal.set(normal);
|
this.normal.set(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void light(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
lightVolume.collect(level, minX, minY, minZ, sizeX, sizeY, sizeZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateLight(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
lightVolume.invalidate(minX, minY, minZ, sizeX, sizeY, sizeZ);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContextShader contextShader() {
|
public ContextShader contextShader() {
|
||||||
return ContextShaders.EMBEDDED;
|
return ContextShader.EMBEDDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupDraw(GlProgram drawProgram) {
|
public void setupDraw(GlProgram drawProgram) {
|
||||||
drawProgram.setVec3("_flw_oneOverLightBoxSize", 1, 1, 1);
|
if (!lightVolume.empty()) {
|
||||||
drawProgram.setVec3("_flw_lightVolumeMin", 0, 0, 0);
|
Samplers.EMBEDDED_LIGHT.makeActive();
|
||||||
|
|
||||||
|
lightTexture.bind();
|
||||||
|
|
||||||
|
lightTexture.ensureCapacity(lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
|
||||||
|
|
||||||
|
lightTexture.upload(lightVolume.ptr(), lightVolume.sizeX, lightVolume.sizeY, lightVolume.sizeZ);
|
||||||
|
|
||||||
|
float oneOverSizeX = 1f / (float) lightTexture.sizeX;
|
||||||
|
float oneOverSizeY = 1f / (float) lightTexture.sizeY;
|
||||||
|
float oneOverSizeZ = 1f / (float) lightTexture.sizeZ;
|
||||||
|
|
||||||
|
drawProgram.setVec3("_flw_oneOverLightBoxSize", oneOverSizeX, oneOverSizeY, oneOverSizeZ);
|
||||||
|
drawProgram.setVec3("_flw_lightVolumeMin", lightVolume.minX, lightVolume.minY, lightVolume.minZ);
|
||||||
|
}
|
||||||
drawProgram.setMat4("_flw_model", pose);
|
drawProgram.setMat4("_flw_model", pose);
|
||||||
drawProgram.setMat3("_flw_normal", normal);
|
drawProgram.setMat3("_flw_normal", normal);
|
||||||
}
|
}
|
||||||
|
@ -78,4 +107,10 @@ public class EmbeddedEnvironment implements Environment, VisualEmbedding {
|
||||||
public VisualEmbedding createEmbedding() {
|
public VisualEmbedding createEmbedding() {
|
||||||
return new EmbeddedEnvironment(engine, renderStage);
|
return new EmbeddedEnvironment(engine, renderStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
lightVolume.delete();
|
||||||
|
lightTexture.delete();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package com.jozufozu.flywheel.backend.engine.embed;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_LINEAR;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNPACK_ROW_LENGTH;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_PIXELS;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_ROWS;
|
||||||
|
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
||||||
|
import static org.lwjgl.opengl.GL11.glPixelStorei;
|
||||||
|
import static org.lwjgl.opengl.GL11.glTexParameteri;
|
||||||
|
import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
|
||||||
|
import static org.lwjgl.opengl.GL12.GL_TEXTURE_WRAP_R;
|
||||||
|
import static org.lwjgl.opengl.GL12.GL_UNPACK_IMAGE_HEIGHT;
|
||||||
|
import static org.lwjgl.opengl.GL12.GL_UNPACK_SKIP_IMAGES;
|
||||||
|
import static org.lwjgl.opengl.GL12.glTexImage3D;
|
||||||
|
import static org.lwjgl.opengl.GL12.glTexSubImage3D;
|
||||||
|
import static org.lwjgl.opengl.GL14.GL_MIRRORED_REPEAT;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GlTexture;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
|
public class EmbeddedLightTexture {
|
||||||
|
@Nullable
|
||||||
|
private GlTexture texture;
|
||||||
|
|
||||||
|
public int sizeX;
|
||||||
|
public int sizeY;
|
||||||
|
public int sizeZ;
|
||||||
|
|
||||||
|
public void bind() {
|
||||||
|
|
||||||
|
texture().bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GlTexture texture() {
|
||||||
|
if (texture == null) {
|
||||||
|
texture = new GlTexture(GL_TEXTURE_3D);
|
||||||
|
}
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ensureCapacity(int sizeX, int sizeY, int sizeZ) {
|
||||||
|
sizeX = Mth.smallestEncompassingPowerOfTwo(sizeX);
|
||||||
|
sizeY = Mth.smallestEncompassingPowerOfTwo(sizeY);
|
||||||
|
sizeZ = Mth.smallestEncompassingPowerOfTwo(sizeZ);
|
||||||
|
|
||||||
|
if (sizeX > this.sizeX || sizeY > this.sizeY || sizeZ > this.sizeZ) {
|
||||||
|
this.sizeX = sizeX;
|
||||||
|
this.sizeY = sizeY;
|
||||||
|
this.sizeZ = sizeZ;
|
||||||
|
|
||||||
|
glTexImage3D(GL_TEXTURE_3D, 0, GL30.GL_RG8, sizeX, sizeY, sizeZ, 0, GL30.GL_RG, GL_UNSIGNED_BYTE, 0);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upload(long ptr, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, (int) EmbeddedLightVolume.STRIDE);
|
||||||
|
|
||||||
|
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, ptr);
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
if (texture != null) {
|
||||||
|
texture.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
package com.jozufozu.flywheel.backend.engine.embed;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.level.BlockAndTintGetter;
|
||||||
|
import net.minecraft.world.level.LightLayer;
|
||||||
|
|
||||||
|
public class EmbeddedLightVolume {
|
||||||
|
public static final long STRIDE = Short.BYTES;
|
||||||
|
public int minX;
|
||||||
|
public int minY;
|
||||||
|
public int minZ;
|
||||||
|
public int sizeX;
|
||||||
|
public int sizeY;
|
||||||
|
public int sizeZ;
|
||||||
|
private final BlockPos.MutableBlockPos scratchPos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected MemoryBlock block;
|
||||||
|
protected boolean dirty;
|
||||||
|
|
||||||
|
public boolean empty() {
|
||||||
|
return block == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collect(BlockAndTintGetter level, int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
maybeExpandForBox(minX, minY, minZ, sizeX, sizeY, sizeZ);
|
||||||
|
|
||||||
|
for (int z = minZ; z < minZ + sizeZ; z++) {
|
||||||
|
for (int y = minY; y < minY + sizeY; y++) {
|
||||||
|
for (int x = minX; x < minX + sizeX; x++) {
|
||||||
|
paintLight(level, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidate(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
// TODO: shrink the volume
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintLight(BlockAndTintGetter level, int x, int y, int z) {
|
||||||
|
scratchPos.set(x, y, z);
|
||||||
|
|
||||||
|
int block = level.getBrightness(LightLayer.BLOCK, scratchPos);
|
||||||
|
int sky = level.getBrightness(LightLayer.SKY, scratchPos);
|
||||||
|
|
||||||
|
long ptr = worldPosToPtr(x, y, z);
|
||||||
|
MemoryUtil.memPutShort(ptr, (short) ((block << 4) | sky << 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeExpandForBox(int minX, int minY, int minZ, int sizeX, int sizeY, int sizeZ) {
|
||||||
|
if (block == null) {
|
||||||
|
this.minX = minX;
|
||||||
|
this.minY = minY;
|
||||||
|
this.minZ = minZ;
|
||||||
|
this.sizeX = sizeX;
|
||||||
|
this.sizeY = sizeY;
|
||||||
|
this.sizeZ = sizeZ;
|
||||||
|
|
||||||
|
int volume = sizeX * sizeY * sizeZ;
|
||||||
|
|
||||||
|
block = MemoryBlock.malloc(volume * STRIDE);
|
||||||
|
block.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newMinX = Math.min(this.minX, minX);
|
||||||
|
int newMinY = Math.min(this.minY, minY);
|
||||||
|
int newMinZ = Math.min(this.minZ, minZ);
|
||||||
|
|
||||||
|
int newSizeX = Math.max(this.minX + this.sizeX, minX + sizeX) - newMinX;
|
||||||
|
int newSizeY = Math.max(this.minY + this.sizeY, minY + sizeY) - newMinY;
|
||||||
|
int newSizeZ = Math.max(this.minZ + this.sizeZ, minZ + sizeZ) - newMinZ;
|
||||||
|
|
||||||
|
if (newMinX == this.minX && newMinY == this.minY && newMinZ == this.minZ && newSizeX == this.sizeX && newSizeY == this.sizeY && newSizeZ == this.sizeZ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int newVolume = newSizeX * newSizeY * newSizeZ;
|
||||||
|
|
||||||
|
MemoryBlock newBlock = MemoryBlock.malloc(newVolume * STRIDE);
|
||||||
|
newBlock.clear();
|
||||||
|
|
||||||
|
int xOff = newMinX - this.minX;
|
||||||
|
int yOff = newMinY - this.minY;
|
||||||
|
int zOff = newMinZ - this.minZ;
|
||||||
|
|
||||||
|
for (int z = 0; z < this.sizeZ; z++) {
|
||||||
|
for (int y = 0; y < this.sizeY; y++) {
|
||||||
|
for (int x = 0; x < this.sizeX; x++) {
|
||||||
|
long oldPtr = boxPosToPtr(x, y, z);
|
||||||
|
long newPtr = newBlock.ptr() + x + xOff + (newSizeX * (y + yOff + (z + zOff) * newSizeY)) * STRIDE;
|
||||||
|
|
||||||
|
MemoryUtil.memPutShort(newPtr, MemoryUtil.memGetShort(oldPtr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.minX = newMinX;
|
||||||
|
this.minY = newMinY;
|
||||||
|
this.minZ = newMinZ;
|
||||||
|
this.sizeX = newSizeX;
|
||||||
|
this.sizeY = newSizeY;
|
||||||
|
this.sizeZ = newSizeZ;
|
||||||
|
|
||||||
|
block.free();
|
||||||
|
block = newBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long worldPosToPtr(int x, int y, int z) {
|
||||||
|
return block.ptr() + worldPosToPtrOffset(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long boxPosToPtr(int x, int y, int z) {
|
||||||
|
return block.ptr() + boxPosToPtrOffset(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long worldPosToPtrOffset(int x, int y, int z) {
|
||||||
|
return boxPosToPtrOffset(x - minX, y - minY, z - minZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long boxPosToPtrOffset(int x, int y, int z) {
|
||||||
|
return (x + sizeX * (y + z * sizeY)) * STRIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
if (block != null) {
|
||||||
|
block.free();
|
||||||
|
block = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void markDirty() {
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ptr() {
|
||||||
|
return block.ptr();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.engine;
|
package com.jozufozu.flywheel.backend.engine.embed;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
@ -9,4 +9,6 @@ public interface Environment {
|
||||||
void setupDraw(GlProgram drawProgram);
|
void setupDraw(GlProgram drawProgram);
|
||||||
|
|
||||||
void setupCull(GlProgram cullProgram);
|
void setupCull(GlProgram cullProgram);
|
||||||
|
|
||||||
|
void delete();
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.engine;
|
package com.jozufozu.flywheel.backend.engine.embed;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShaders;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
|
||||||
public class GlobalEnvironment implements Environment {
|
public class GlobalEnvironment implements Environment {
|
||||||
|
@ -12,7 +11,7 @@ public class GlobalEnvironment implements Environment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContextShader contextShader() {
|
public ContextShader contextShader() {
|
||||||
return ContextShaders.DEFAULT;
|
return ContextShader.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,4 +23,9 @@ public class GlobalEnvironment implements Environment {
|
||||||
public void setupCull(GlProgram cullProgram) {
|
public void setupCull(GlProgram cullProgram) {
|
||||||
cullProgram.setBool("_flw_useEmbeddedModel", false);
|
cullProgram.setBool("_flw_useEmbeddedModel", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -23,9 +23,9 @@ import com.jozufozu.flywheel.api.material.Material;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
||||||
import com.jozufozu.flywheel.backend.engine.Environment;
|
|
||||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||||
import com.jozufozu.flywheel.backend.engine.MeshPool;
|
import com.jozufozu.flywheel.backend.engine.MeshPool;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||||
import com.jozufozu.flywheel.backend.gl.Driver;
|
import com.jozufozu.flywheel.backend.gl.Driver;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||||
|
|
|
@ -16,16 +16,16 @@ import com.jozufozu.flywheel.api.event.RenderStage;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.backend.Samplers;
|
import com.jozufozu.flywheel.backend.Samplers;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShaders;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
||||||
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
|
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
|
||||||
import com.jozufozu.flywheel.backend.engine.Environment;
|
|
||||||
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
||||||
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
||||||
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
||||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||||
import com.jozufozu.flywheel.backend.engine.MeshPool;
|
import com.jozufozu.flywheel.backend.engine.MeshPool;
|
||||||
import com.jozufozu.flywheel.backend.engine.TextureBinder;
|
import com.jozufozu.flywheel.backend.engine.TextureBinder;
|
||||||
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||||
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
||||||
|
@ -164,7 +164,7 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||||
|
|
||||||
// Set up the crumbling program buffers. Nothing changes here between draws.
|
// Set up the crumbling program buffers. Nothing changes here between draws.
|
||||||
var program = cullingGroups.get(instanceTypeEntry.getKey())
|
var program = cullingGroups.get(instanceTypeEntry.getKey())
|
||||||
.bindWithContextShader(ContextShaders.CRUMBLING);
|
.bindWithContextShader(ContextShader.CRUMBLING);
|
||||||
|
|
||||||
program.setSamplerBinding("crumblingTex", Samplers.CRUMBLING);
|
program.setSamplerBinding("crumblingTex", Samplers.CRUMBLING);
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
||||||
import com.jozufozu.flywheel.api.model.Model;
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||||
import com.jozufozu.flywheel.backend.engine.Environment;
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I> {
|
public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||||
private final long objectStride;
|
private final long objectStride;
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
import com.jozufozu.flywheel.backend.Samplers;
|
import com.jozufozu.flywheel.backend.Samplers;
|
||||||
import com.jozufozu.flywheel.backend.ShaderIndices;
|
import com.jozufozu.flywheel.backend.ShaderIndices;
|
||||||
import com.jozufozu.flywheel.backend.compile.ContextShaders;
|
import com.jozufozu.flywheel.backend.compile.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
|
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
|
||||||
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
|
import com.jozufozu.flywheel.backend.engine.CommonCrumbling;
|
||||||
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
||||||
|
@ -203,7 +203,7 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
|
||||||
|
|
||||||
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, shader.material());
|
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, shader.material());
|
||||||
|
|
||||||
var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING);
|
var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING);
|
||||||
program.bind();
|
program.bind();
|
||||||
|
|
||||||
uploadMaterialUniform(program, crumblingMaterial);
|
uploadMaterialUniform(program, crumblingMaterial);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
||||||
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||||
import com.jozufozu.flywheel.backend.engine.Environment;
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
import com.jozufozu.flywheel.backend.gl.TextureBuffer;
|
import com.jozufozu.flywheel.backend.gl.TextureBuffer;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.backend.engine.instancing;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
import com.jozufozu.flywheel.backend.engine.Environment;
|
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||||
|
|
||||||
public record ShaderState(Material material, InstanceType<?> instanceType, Environment environment) {
|
public record ShaderState(Material material, InstanceType<?> instanceType, Environment environment) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,4 @@ public class GlTexture extends GlObject {
|
||||||
GL20.glBindTexture(textureType, 0);
|
GL20.glBindTexture(textureType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParameteri(int parameter, int value) {
|
|
||||||
GL20.glTexParameteri(textureType, parameter, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,5 @@ public enum DebugMode {
|
||||||
INSTANCE_ID,
|
INSTANCE_ID,
|
||||||
LIGHT,
|
LIGHT,
|
||||||
OVERLAY,
|
OVERLAY,
|
||||||
|
LIGHT_VOLUME,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,133 +0,0 @@
|
||||||
package com.jozufozu.flywheel.lib.light;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_LINEAR;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_S;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TEXTURE_WRAP_T;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNPACK_ALIGNMENT;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNPACK_ROW_LENGTH;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_PIXELS;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNPACK_SKIP_ROWS;
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
|
|
||||||
import static org.lwjgl.opengl.GL11.glPixelStorei;
|
|
||||||
import static org.lwjgl.opengl.GL12.GL_TEXTURE_3D;
|
|
||||||
import static org.lwjgl.opengl.GL12.GL_TEXTURE_WRAP_R;
|
|
||||||
import static org.lwjgl.opengl.GL12.GL_UNPACK_IMAGE_HEIGHT;
|
|
||||||
import static org.lwjgl.opengl.GL12.GL_UNPACK_SKIP_IMAGES;
|
|
||||||
import static org.lwjgl.opengl.GL12.glTexImage3D;
|
|
||||||
import static org.lwjgl.opengl.GL12.glTexSubImage3D;
|
|
||||||
import static org.lwjgl.opengl.GL14.GL_MIRRORED_REPEAT;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL30;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlTexture;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
|
||||||
import com.jozufozu.flywheel.lib.box.Box;
|
|
||||||
import com.jozufozu.flywheel.lib.box.MutableBox;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.BlockAndTintGetter;
|
|
||||||
|
|
||||||
public class GPULightVolume extends LightVolume {
|
|
||||||
|
|
||||||
protected final MutableBox sampleVolume = new MutableBox();
|
|
||||||
private final GlTexture glTexture;
|
|
||||||
|
|
||||||
private final GlTextureUnit textureUnit = GlTextureUnit.T4;
|
|
||||||
protected boolean bufferDirty;
|
|
||||||
|
|
||||||
public GPULightVolume(BlockAndTintGetter level, Box sampleVolume) {
|
|
||||||
super(level, sampleVolume);
|
|
||||||
this.sampleVolume.assign(sampleVolume);
|
|
||||||
|
|
||||||
glTexture = new GlTexture(GL_TEXTURE_3D);
|
|
||||||
|
|
||||||
GlTextureUnit oldState = GlTextureUnit.getActive();
|
|
||||||
|
|
||||||
// allocate space for the texture
|
|
||||||
textureUnit.makeActive();
|
|
||||||
glTexture.bind();
|
|
||||||
|
|
||||||
int sizeX = box.sizeX();
|
|
||||||
int sizeY = box.sizeY();
|
|
||||||
int sizeZ = box.sizeZ();
|
|
||||||
glTexImage3D(GL_TEXTURE_3D, 0, GL30.GL_RG8, sizeX, sizeY, sizeZ, 0, GL30.GL_RG, GL_UNSIGNED_BYTE, 0);
|
|
||||||
|
|
||||||
glTexture.setParameteri(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexture.setParameteri(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexture.setParameteri(GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
|
|
||||||
glTexture.setParameteri(GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
|
|
||||||
glTexture.setParameteri(GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
|
|
||||||
|
|
||||||
glTexture.unbind();
|
|
||||||
oldState.makeActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setBox(Box box) {
|
|
||||||
this.box.assign(box);
|
|
||||||
this.box.nextPowerOf2Centered();
|
|
||||||
// called during super ctor
|
|
||||||
if (sampleVolume != null) this.sampleVolume.assign(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bind() {
|
|
||||||
// just in case something goes wrong, or we accidentally call this before this volume is properly disposed of.
|
|
||||||
if (lightData == null || lightData.size() == 0) return;
|
|
||||||
|
|
||||||
textureUnit.makeActive();
|
|
||||||
glTexture.bind();
|
|
||||||
|
|
||||||
uploadTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void uploadTexture() {
|
|
||||||
if (bufferDirty) {
|
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
|
||||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
|
|
||||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
|
|
||||||
glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
|
|
||||||
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); // we use 2 bytes per texel
|
|
||||||
int sizeX = box.sizeX();
|
|
||||||
int sizeY = box.sizeY();
|
|
||||||
int sizeZ = box.sizeZ();
|
|
||||||
|
|
||||||
glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, sizeX, sizeY, sizeZ, GL30.GL_RG, GL_UNSIGNED_BYTE, lightData.ptr());
|
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4 is the default
|
|
||||||
bufferDirty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unbind() {
|
|
||||||
glTexture.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
super.delete();
|
|
||||||
glTexture.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(Box newSampleVolume) {
|
|
||||||
if (lightData == null) return;
|
|
||||||
|
|
||||||
if (box.contains(newSampleVolume)) {
|
|
||||||
sampleVolume.assign(newSampleVolume);
|
|
||||||
initialize();
|
|
||||||
} else {
|
|
||||||
super.move(newSampleVolume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Box getVolume() {
|
|
||||||
return sampleVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void markDirty() {
|
|
||||||
this.bufferDirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,19 +6,42 @@
|
||||||
layout (depth_greater) out float gl_FragDepth;
|
layout (depth_greater) out float gl_FragDepth;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
out vec4 _flw_outputColor;
|
#ifdef _FLW_CRUMBLING
|
||||||
|
uniform sampler2D _flw_crumblingTex;
|
||||||
|
|
||||||
|
in vec2 _flw_crumblingTexCoord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _FLW_EMBEDDED
|
||||||
|
uniform sampler3D _flw_lightVolume;
|
||||||
|
|
||||||
|
in vec3 _flw_lightVolumeCoord;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
in vec4 _flw_debugColor;
|
in vec4 _flw_debugColor;
|
||||||
|
|
||||||
|
out vec4 _flw_outputColor;
|
||||||
|
|
||||||
void _flw_main() {
|
void _flw_main() {
|
||||||
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
|
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
|
||||||
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
flw_fragColor = flw_vertexColor * flw_sampleColor;
|
||||||
flw_fragOverlay = flw_vertexOverlay;
|
flw_fragOverlay = flw_vertexOverlay;
|
||||||
flw_fragLight = flw_vertexLight;
|
flw_fragLight = flw_vertexLight;
|
||||||
|
|
||||||
flw_beginFragment();
|
#ifdef _FLW_EMBEDDED
|
||||||
|
flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
|
||||||
|
#endif
|
||||||
|
|
||||||
flw_materialFragment();
|
flw_materialFragment();
|
||||||
flw_endFragment();
|
|
||||||
|
#ifdef _FLW_CRUMBLING
|
||||||
|
vec4 crumblingSampleColor = texture(_flw_crumblingTex, _flw_crumblingTexCoord);
|
||||||
|
|
||||||
|
// Make the crumbling overlay transparent when the fragment color after the material shader is transparent.
|
||||||
|
flw_fragColor.rgb = crumblingSampleColor.rgb;
|
||||||
|
flw_fragColor.a *= crumblingSampleColor.a;
|
||||||
|
#endif
|
||||||
|
|
||||||
vec4 color = flw_fragColor;
|
vec4 color = flw_fragColor;
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,97 @@ vec4 _flw_id2Color(in uint id) {
|
||||||
|
|
||||||
out vec4 _flw_debugColor;
|
out vec4 _flw_debugColor;
|
||||||
|
|
||||||
|
#ifdef _FLW_CRUMBLING
|
||||||
|
out vec2 _flw_crumblingTexCoord;
|
||||||
|
|
||||||
|
const int DOWN = 0;
|
||||||
|
const int UP = 1;
|
||||||
|
const int NORTH = 2;
|
||||||
|
const int SOUTH = 3;
|
||||||
|
const int WEST = 4;
|
||||||
|
const int EAST = 5;
|
||||||
|
|
||||||
|
// based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
|
||||||
|
int getNearestFacing(vec3 normal) {
|
||||||
|
float maxAlignment = -2;
|
||||||
|
int face = 2;
|
||||||
|
|
||||||
|
// Calculate the alignment of the normal vector with each axis.
|
||||||
|
// Note that `-dot(normal, axis) == dot(normal, -axis)`.
|
||||||
|
vec3 alignment = vec3(
|
||||||
|
dot(normal, vec3(1., 0., 0.)),
|
||||||
|
dot(normal, vec3(0., 1., 0.)),
|
||||||
|
dot(normal, vec3(0., 0., 1.))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-alignment.y > maxAlignment) {
|
||||||
|
maxAlignment = -alignment.y;
|
||||||
|
face = DOWN;
|
||||||
|
}
|
||||||
|
if (alignment.y > maxAlignment) {
|
||||||
|
maxAlignment = alignment.y;
|
||||||
|
face = UP;
|
||||||
|
}
|
||||||
|
if (-alignment.z > maxAlignment) {
|
||||||
|
maxAlignment = -alignment.z;
|
||||||
|
face = NORTH;
|
||||||
|
}
|
||||||
|
if (alignment.z > maxAlignment) {
|
||||||
|
maxAlignment = alignment.z;
|
||||||
|
face = SOUTH;
|
||||||
|
}
|
||||||
|
if (-alignment.x > maxAlignment) {
|
||||||
|
maxAlignment = -alignment.x;
|
||||||
|
face = WEST;
|
||||||
|
}
|
||||||
|
if (alignment.x > maxAlignment) {
|
||||||
|
maxAlignment = alignment.x;
|
||||||
|
face = EAST;
|
||||||
|
}
|
||||||
|
|
||||||
|
return face;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getCrumblingTexCoord() {
|
||||||
|
switch (getNearestFacing(flw_vertexNormal)) {
|
||||||
|
case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z);
|
||||||
|
case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z);
|
||||||
|
case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
||||||
|
case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y);
|
||||||
|
case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y);
|
||||||
|
case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to north
|
||||||
|
return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _FLW_EMBEDDED
|
||||||
|
uniform vec3 _flw_oneOverLightBoxSize;
|
||||||
|
uniform vec3 _flw_lightVolumeMin;
|
||||||
|
uniform mat4 _flw_model;
|
||||||
|
uniform mat3 _flw_normal;
|
||||||
|
|
||||||
|
out vec3 _flw_lightVolumeCoord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
||||||
_flw_layoutVertex();
|
_flw_layoutVertex();
|
||||||
flw_beginVertex();
|
|
||||||
flw_instanceVertex(instance);
|
flw_instanceVertex(instance);
|
||||||
flw_materialVertex();
|
flw_materialVertex();
|
||||||
flw_endVertex();
|
|
||||||
|
#ifdef _FLW_CRUMBLING
|
||||||
|
_flw_crumblingTexCoord = getCrumblingTexCoord();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _FLW_EMBEDDED
|
||||||
|
flw_vertexPos = _flw_model * flw_vertexPos;
|
||||||
|
flw_vertexNormal = _flw_normal * flw_vertexNormal;
|
||||||
|
|
||||||
|
_flw_lightVolumeCoord = (flw_vertexPos.xyz - _flw_lightVolumeMin) * _flw_oneOverLightBoxSize;
|
||||||
|
#endif
|
||||||
|
|
||||||
flw_vertexNormal = normalize(flw_vertexNormal);
|
flw_vertexNormal = normalize(flw_vertexNormal);
|
||||||
|
|
||||||
|
@ -52,5 +137,10 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
||||||
case 4u:
|
case 4u:
|
||||||
_flw_debugColor = vec4(flw_vertexOverlay / 16., 0., 1.);
|
_flw_debugColor = vec4(flw_vertexOverlay / 16., 0., 1.);
|
||||||
break;
|
break;
|
||||||
|
#ifdef _FLW_LIGHT_VOLUME
|
||||||
|
case 5u:
|
||||||
|
_flw_debugColor = vec4(_flw_lightVolumeCoord, 1.);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
uniform sampler2D _flw_crumblingTex;
|
|
||||||
|
|
||||||
in vec2 crumblingTexCoord;
|
|
||||||
|
|
||||||
vec4 crumblingSampleColor;
|
|
||||||
|
|
||||||
void flw_beginFragment() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endFragment() {
|
|
||||||
crumblingSampleColor = texture(_flw_crumblingTex, crumblingTexCoord);
|
|
||||||
|
|
||||||
// Make the crumbling overlay transparent when the fragment color after the material shader is transparent.
|
|
||||||
flw_fragColor.rgb = crumblingSampleColor.rgb;
|
|
||||||
flw_fragColor.a *= crumblingSampleColor.a;
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
out vec2 crumblingTexCoord;
|
|
||||||
|
|
||||||
const int DOWN = 0;
|
|
||||||
const int UP = 1;
|
|
||||||
const int NORTH = 2;
|
|
||||||
const int SOUTH = 3;
|
|
||||||
const int WEST = 4;
|
|
||||||
const int EAST = 5;
|
|
||||||
|
|
||||||
// based on net.minecraftforge.client.ForgeHooksClient.getNearestStable
|
|
||||||
int getNearestFacing(vec3 normal) {
|
|
||||||
float maxAlignment = -2;
|
|
||||||
int face = 2;
|
|
||||||
|
|
||||||
// Calculate the alignment of the normal vector with each axis.
|
|
||||||
// Note that `-dot(normal, axis) == dot(normal, -axis)`.
|
|
||||||
vec3 alignment = vec3(
|
|
||||||
dot(normal, vec3(1., 0., 0.)),
|
|
||||||
dot(normal, vec3(0., 1., 0.)),
|
|
||||||
dot(normal, vec3(0., 0., 1.))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (-alignment.y > maxAlignment) {
|
|
||||||
maxAlignment = -alignment.y;
|
|
||||||
face = DOWN;
|
|
||||||
}
|
|
||||||
if (alignment.y > maxAlignment) {
|
|
||||||
maxAlignment = alignment.y;
|
|
||||||
face = UP;
|
|
||||||
}
|
|
||||||
if (-alignment.z > maxAlignment) {
|
|
||||||
maxAlignment = -alignment.z;
|
|
||||||
face = NORTH;
|
|
||||||
}
|
|
||||||
if (alignment.z > maxAlignment) {
|
|
||||||
maxAlignment = alignment.z;
|
|
||||||
face = SOUTH;
|
|
||||||
}
|
|
||||||
if (-alignment.x > maxAlignment) {
|
|
||||||
maxAlignment = -alignment.x;
|
|
||||||
face = WEST;
|
|
||||||
}
|
|
||||||
if (alignment.x > maxAlignment) {
|
|
||||||
maxAlignment = alignment.x;
|
|
||||||
face = EAST;
|
|
||||||
}
|
|
||||||
|
|
||||||
return face;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 getCrumblingTexCoord() {
|
|
||||||
switch (getNearestFacing(flw_vertexNormal)) {
|
|
||||||
case DOWN: return vec2(flw_vertexPos.x, -flw_vertexPos.z);
|
|
||||||
case UP: return vec2(flw_vertexPos.x, flw_vertexPos.z);
|
|
||||||
case NORTH: return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
|
||||||
case SOUTH: return vec2(flw_vertexPos.x, -flw_vertexPos.y);
|
|
||||||
case WEST: return vec2(-flw_vertexPos.z, -flw_vertexPos.y);
|
|
||||||
case EAST: return vec2(flw_vertexPos.z, -flw_vertexPos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// default to north
|
|
||||||
return vec2(-flw_vertexPos.x, -flw_vertexPos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_beginVertex() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endVertex() {
|
|
||||||
crumblingTexCoord = getCrumblingTexCoord();
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
void flw_beginFragment() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endFragment() {
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
void flw_beginVertex() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endVertex() {
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
uniform sampler3D _flw_lightVolume;
|
|
||||||
|
|
||||||
in vec3 _flw_lightVolumeCoord;
|
|
||||||
|
|
||||||
void flw_beginFragment() {
|
|
||||||
flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endFragment() {
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
uniform vec3 _flw_oneOverLightBoxSize;
|
|
||||||
uniform vec3 _flw_lightVolumeMin;
|
|
||||||
uniform mat4 _flw_model;
|
|
||||||
uniform mat3 _flw_normal;
|
|
||||||
|
|
||||||
out vec3 _flw_lightVolumeCoord;
|
|
||||||
|
|
||||||
void flw_beginVertex() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void flw_endVertex() {
|
|
||||||
_flw_lightVolumeCoord = (flw_vertexPos.xyz - _flw_lightVolumeMin) * _flw_oneOverLightBoxSize;
|
|
||||||
|
|
||||||
flw_vertexPos = _flw_model * flw_vertexPos;
|
|
||||||
flw_vertexNormal = _flw_normal * flw_vertexNormal;
|
|
||||||
}
|
|
Loading…
Reference in a new issue