Crumbling away

- Fix and improve crumbling rendering
- Rename Batched to BatchedStructType and Instanced to
InstancedStructType
- Normalize flw_vertexNormal in context/common.vert
- Add TODO and FIXME comments
This commit is contained in:
PepperCode1 2022-05-22 14:28:38 -07:00
parent 9886dca1e2
commit 2632cd385c
27 changed files with 138 additions and 292 deletions

View file

@ -2,7 +2,6 @@ package com.jozufozu.flywheel.api.struct;
import com.jozufozu.flywheel.core.model.ModelTransformer;
public interface Batched<S> extends StructType<S> {
public interface BatchedStructType<S> extends StructType<S> {
void transform(S d, ModelTransformer.Params b);
}

View file

@ -3,7 +3,7 @@ package com.jozufozu.flywheel.api.struct;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.source.FileResolution;
public interface Instanced<S> extends StructType<S> {
public interface InstancedStructType<S> extends StructType<S> {
/**
* Create a {@link StructWriter} that will consume instances of S and write them to the given buffer.
*

View file

@ -30,6 +30,7 @@ public class GlShader extends GlObject {
GlCompat.safeShaderSource(handle, source);
GL20.glCompileShader(handle);
// TODO: control this via a JVM flag or other
dumpSource(source, type);
// String log = GL20.glGetShaderInfoLog(handle);

View file

@ -141,19 +141,19 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
if (tick.shouldUpdate(dX, dY, dZ)) instance.tick();
}
public void beginFrame(TaskEngine taskEngine, Camera info) {
public void beginFrame(TaskEngine taskEngine, Camera camera) {
frame.tick();
processQueuedAdditions();
Vector3f look = info.getLookVector();
Vector3f look = camera.getLookVector();
float lookX = look.x();
float lookY = look.y();
float lookZ = look.z();
// integer camera pos
int cX = (int) info.getPosition().x;
int cY = (int) info.getPosition().y;
int cZ = (int) info.getPosition().z;
int cX = (int) camera.getPosition().x;
int cY = (int) camera.getPosition().y;
int cZ = (int) camera.getPosition().z;
ArrayList<DynamicInstance> instances = new ArrayList<>(dynamicInstances.values());
int incr = 500;

View file

@ -5,7 +5,7 @@ import java.util.Map;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
@ -17,7 +17,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
protected final RenderType state;
private final Map<Batched<? extends InstanceData>, CPUInstancerFactory<?>> materials = new HashMap<>();
private final Map<BatchedStructType<? extends InstanceData>, CPUInstancerFactory<?>> materials = new HashMap<>();
private int vertexCount;
private int instanceCount;
@ -28,7 +28,7 @@ public class BatchedMaterialGroup implements MaterialGroup {
@SuppressWarnings("unchecked")
@Override
public <D extends InstanceData> CPUInstancerFactory<D> material(StructType<D> type) {
if (type instanceof Batched<D> batched) {
if (type instanceof BatchedStructType<D> batched) {
return (CPUInstancerFactory<D>) materials.computeIfAbsent(batched, CPUInstancerFactory::new);
} else {
throw new ClassCastException("Cannot use type '" + type + "' with CPU instancing.");

View file

@ -5,7 +5,7 @@ import java.util.List;
import java.util.Map;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
import com.jozufozu.flywheel.backend.instancing.Engine;
@ -21,13 +21,13 @@ import net.minecraft.core.Vec3i;
public class BatchingEngine implements Engine {
private final Map<Batched<? extends InstanceData>, CPUInstancerFactory<?>> factories = new HashMap<>();
private final Map<BatchedStructType<? extends InstanceData>, CPUInstancerFactory<?>> factories = new HashMap<>();
private final BatchDrawingTracker batchTracker = new BatchDrawingTracker();
@SuppressWarnings("unchecked")
@Override
public <D extends InstanceData> CPUInstancerFactory<D> factory(StructType<D> type) {
if (type instanceof Batched<D> batched) {
if (type instanceof BatchedStructType<D> batched) {
return (CPUInstancerFactory<D>) factories.computeIfAbsent(batched, CPUInstancerFactory::new);
} else {
throw new ClassCastException("Cannot use type '" + type + "' with CPU instancing.");

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.backend.instancing.batching;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
@ -14,7 +14,7 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
//
// final ModelTransformer sbb;
public CPUInstancer(Batched<D> type) {
public CPUInstancer(BatchedStructType<D> type) {
super(type::create);
// batchingType = type;
//

View file

@ -6,7 +6,7 @@ import java.util.Map;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.InstancerFactory;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.core.model.ModelSupplier;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
@ -14,9 +14,9 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
public class CPUInstancerFactory<D extends InstanceData> implements InstancerFactory<D> {
protected final Map<ModelSupplier, CPUInstancer<D>> models;
private final Batched<D> type;
private final BatchedStructType<D> type;
public CPUInstancerFactory(Batched<D> type) {
public CPUInstancerFactory(BatchedStructType<D> type) {
this.type = type;
this.models = new HashMap<>();

View file

@ -7,7 +7,7 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
@ -19,7 +19,7 @@ import com.jozufozu.flywheel.core.layout.BufferLayout;
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
final BufferLayout instanceFormat;
final Instanced<D> instancedType;
final InstancedStructType<D> instancedType;
GlBuffer vbo;
int attributeBaseIndex;
@ -27,7 +27,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
boolean anyToUpdate;
public GPUInstancer(Instanced<D> type) {
public GPUInstancer(InstancedStructType<D> type) {
super(type::create);
this.instanceFormat = type.getLayout();
instancedType = type;

View file

@ -12,7 +12,7 @@ import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.InstancerFactory;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.backend.model.MeshPool;
import com.jozufozu.flywheel.core.model.ModelSupplier;
@ -25,14 +25,15 @@ import net.minecraft.client.renderer.RenderType;
public class GPUInstancerFactory<D extends InstanceData> implements InstancerFactory<D> {
protected final Map<ModelSupplier, InstancedModel<D>> models = new HashMap<>();
protected final Instanced<D> type;
protected final InstancedStructType<D> type;
protected final List<InstancedModel<D>> uninitialized = new ArrayList<>();
protected final Multimap<RenderType, Material> materials = HashMultimap.create();
protected final Multimap<Material, Renderable> renderables = ArrayListMultimap.create();
// FIXME: these should not be public
public final Multimap<RenderType, Material> materials = HashMultimap.create();
public final Multimap<Material, Renderable> renderables = ArrayListMultimap.create();
public GPUInstancerFactory(Instanced<D> type) {
public GPUInstancerFactory(InstancedStructType<D> type) {
this.type = type;
}

View file

@ -10,7 +10,7 @@ import org.jetbrains.annotations.NotNull;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
@ -44,7 +44,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
protected final ProgramCompiler<P> context;
private MeshPool allocator;
protected final Map<Instanced<? extends InstanceData>, GPUInstancerFactory<?>> factories = new HashMap<>();
protected final Map<InstancedStructType<? extends InstanceData>, GPUInstancerFactory<?>> factories = new HashMap<>();
protected final Set<RenderType> toRender = new HashSet<>();
@ -62,7 +62,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
@NotNull
@Override
public <D extends InstanceData> GPUInstancerFactory<D> factory(StructType<D> type) {
if (type instanceof Instanced<D> instanced) {
if (type instanceof InstancedStructType<D> instanced) {
return (GPUInstancerFactory<D>) factories.computeIfAbsent(instanced, GPUInstancerFactory::new);
} else {
throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing.");
@ -108,8 +108,8 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
Textures.bindActiveTextures();
CoreShaderInfo coreShaderInfo = getCoreShaderInfo();
for (Map.Entry<Instanced<? extends InstanceData>, GPUInstancerFactory<?>> entry : factories.entrySet()) {
Instanced<? extends InstanceData> instanceType = entry.getKey();
for (Map.Entry<InstancedStructType<? extends InstanceData>, GPUInstancerFactory<?>> entry : factories.entrySet()) {
InstancedStructType<? extends InstanceData> instanceType = entry.getKey();
GPUInstancerFactory<?> factory = entry.getValue();
var materials = factory.materials.get(type);
@ -146,7 +146,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
return coreShaderInfo;
}
protected P setup(Instanced<?> instanceType, Material material, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
protected P setup(InstancedStructType<?> instanceType, Material material, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
float alphaDiscard = coreShaderInfo.alphaDiscard();
if (alphaDiscard == 0) {
alphaDiscard = 0.0001f;
@ -201,7 +201,6 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
}
allocator.flush();
}
private void checkOriginDistance(Camera info) {

View file

@ -69,6 +69,7 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramCompil
@Override
protected P _create(Context ctx) {
// TODO: try-catch here to prevent crashing if shaders failed to compile
return new ProgramAssembler(ctx.instanceShader().getFileLoc())
.attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.vertexType(), ctx.instanceShader().getFile(), ctx.vertexMaterialShader().getFile(), ctx.ctx())))
.attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.fragmentMaterialShader().getFile(), ctx.alphaDiscard(), ctx.fogType(), ctx.ctx())))

View file

@ -1,48 +0,0 @@
package com.jozufozu.flywheel.core.crumbling;
import java.util.HashMap;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.mixin.atlas.SheetDataAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.resources.ResourceLocation;
/**
* Track width and height of all created texture atlases.
*
* @see com.jozufozu.flywheel.mixin.atlas.AtlasDataMixin
*/
public class AtlasInfo {
private static final Map<ResourceLocation, SheetSize> sheetData = new HashMap<>();
@Nullable
public static TextureAtlas getAtlas(ResourceLocation name) {
AbstractTexture texture = Minecraft.getInstance().getTextureManager().getTexture(name);
if (texture instanceof TextureAtlas atlas)
return atlas;
else
return null;
}
@Nullable
public static SheetSize getSheetSize(@Nullable ResourceLocation loc) {
return sheetData.get(loc);
}
/**
* FOR USE IN MIXIN
*/
public static void _setAtlasData(ResourceLocation atlas, SheetDataAccessor accessor) {
sheetData.put(atlas, new SheetSize(accessor.flywheel$getWidth(), accessor.flywheel$getHeight()));
}
public record SheetSize(int width, int height) {
}
}

View file

@ -1,42 +1,18 @@
package com.jozufozu.flywheel.core.crumbling;
import static org.lwjgl.opengl.GL20.glUniform2f;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.InventoryMenu;
public class CrumblingProgram extends WorldProgram {
protected final int uTextureScale;
protected int uCrumbling;
protected int uCrumblingTex;
public CrumblingProgram(ResourceLocation name, int handle) {
super(name, handle);
uTextureScale = getUniformLocation("uTextureScale");
}
@Override
protected void registerSamplers() {
super.registerSamplers();
uCrumbling = setSamplerBinding("uCrumbling", 4);
uCrumblingTex = setSamplerBinding("uCrumblingTex", 0);
}
public void setTextureScale(float x, float y) {
glUniform2f(uTextureScale, x, y);
}
public void setAtlasSize(int width, int height) {
TextureAtlas blockAtlas = AtlasInfo.getAtlas(InventoryMenu.BLOCK_ATLAS);
if (blockAtlas == null) return;
TextureAtlasSprite sprite = blockAtlas.getSprite(ModelBakery.BREAKING_LOCATIONS.get(0));
setTextureScale(width / (float) sprite.getWidth(), height / (float) sprite.getHeight());
}
}

View file

@ -6,13 +6,15 @@ import java.util.Map;
import java.util.SortedSet;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.GPUInstancerFactory;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.Renderable;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
import com.jozufozu.flywheel.core.RenderContext;
@ -20,101 +22,110 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
import com.jozufozu.flywheel.util.Lazy;
import com.jozufozu.flywheel.util.Textures;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
// TODO: merge directly into InstancingEngine for efficiency
/**
* Responsible for rendering the block breaking overlay for instanced block entities.
* Responsible for rendering the crumbling overlay for instanced block entities.
*/
@Mod.EventBusSubscriber(Dist.CLIENT)
public class CrumblingRenderer {
static RenderType _currentLayer;
private static Lazy<State> STATE;
static {
_init();
}
public static void renderBreaking(ClientLevel level, PoseStack stack, double x, double y, double z, Matrix4f viewProjection) {
public static void renderCrumbling(LevelRenderer levelRenderer, ClientLevel level, PoseStack poseStack, Camera camera, Matrix4f projectionMatrix) {
if (!Backend.canUseInstancing(level)) return;
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(level);
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(levelRenderer, level);
if (activeStages.isEmpty()) return;
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
Matrix4f viewProjection = poseStack.last()
.pose()
.copy();
viewProjection.multiplyBackward(projectionMatrix);
State state = STATE.get();
var instanceManager = state.instanceManager;
var engine = state.instancerManager;
TextureManager textureManager = Minecraft.getInstance().getTextureManager();
Camera info = Minecraft.getInstance().gameRenderer.getMainCamera();
renderCrumblingInner(activeStages, instanceManager, engine, level, poseStack, camera, viewProjection);
restoreState.restore();
}
private static void renderCrumblingInner(Int2ObjectMap<List<BlockEntity>> activeStages, InstanceManager<BlockEntity> instanceManager, CrumblingEngine engine, ClientLevel level, PoseStack stack, Camera camera, Matrix4f viewProjection) {
Vec3 cameraPos = camera.getPosition();
RenderContext ctx = new RenderContext(level, stack, viewProjection, null, cameraPos.x, cameraPos.y, cameraPos.z);
for (Int2ObjectMap.Entry<List<BlockEntity>> stage : activeStages.int2ObjectEntrySet()) {
_currentLayer = ModelBakery.DESTROY_TYPES.get(stage.getIntKey());
RenderType currentLayer = ModelBakery.DESTROY_TYPES.get(stage.getIntKey());
// something about when we call this means that the textures are not ready for use on the first frame they should appear
if (_currentLayer != null) {
if (currentLayer != null) {
engine.currentLayer = currentLayer;
stage.getValue().forEach(instanceManager::add);
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, info);
engine.beginFrame(info);
var ctx = new RenderContext(level, stack, viewProjection, null, x, y, z);
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, camera);
engine.beginFrame(camera);
engine.renderAllRemaining(SerialTaskEngine.INSTANCE, ctx);
instanceManager.invalidate();
}
}
GlTextureUnit.T0.makeActive();
AbstractTexture breaking = textureManager.getTexture(ModelBakery.BREAKING_LOCATIONS.get(0));
if (breaking != null) RenderSystem.bindTexture(breaking.getId());
}
/**
* Associate each breaking stage with a list of all block entities at that stage.
*/
private static Int2ObjectMap<List<BlockEntity>> getActiveStageBlockEntities(ClientLevel world) {
private static Int2ObjectMap<List<BlockEntity>> getActiveStageBlockEntities(LevelRenderer levelRenderer, ClientLevel level) {
Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress = ((LevelRendererAccessor) levelRenderer).flywheel$getDestructionProgress();
if (destructionProgress.isEmpty()) {
return Int2ObjectMaps.emptyMap();
}
Int2ObjectMap<List<BlockEntity>> breakingEntities = new Int2ObjectArrayMap<>();
BlockPos.MutableBlockPos breakingPos = new BlockPos.MutableBlockPos();
for (Long2ObjectMap.Entry<SortedSet<BlockDestructionProgress>> entry : ((LevelRendererAccessor) Minecraft.getInstance().levelRenderer).flywheel$getDestructionProgress()
.long2ObjectEntrySet()) {
BlockPos breakingPos = BlockPos.of(entry.getLongKey());
for (Long2ObjectMap.Entry<SortedSet<BlockDestructionProgress>> entry : destructionProgress.long2ObjectEntrySet()) {
breakingPos.set(entry.getLongKey());
SortedSet<BlockDestructionProgress> progresses = entry.getValue();
if (progresses != null && !progresses.isEmpty()) {
int blockDamage = progresses.last()
int progress = progresses.last()
.getProgress();
if (progress >= 0) {
BlockEntity blockEntity = level.getBlockEntity(breakingPos);
BlockEntity blockEntity = world.getBlockEntity(breakingPos);
if (blockEntity != null) {
List<BlockEntity> blockEntities = breakingEntities.computeIfAbsent(blockDamage, $ -> new ArrayList<>());
blockEntities.add(blockEntity);
if (blockEntity != null) {
List<BlockEntity> blockEntities = breakingEntities.computeIfAbsent(progress, $ -> new ArrayList<>());
blockEntities.add(blockEntity);
}
}
}
}
@ -156,6 +167,7 @@ public class CrumblingRenderer {
}
private static class CrumblingEngine extends InstancingEngine<CrumblingProgram> {
private RenderType currentLayer;
public CrumblingEngine() {
super(Contexts.CRUMBLING);
@ -163,42 +175,32 @@ public class CrumblingRenderer {
@Override
protected void render(RenderType type, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
type.setupRenderState();
int renderTex = RenderSystem.getShaderTexture(0);
AtlasInfo.SheetSize sheetSize = AtlasInfo.getSheetSize(Textures.getShaderTexture(0));
int width;
int height;
if (sheetSize != null) {
width = sheetSize.width();
height = sheetSize.height();
} else {
width = height = 256;
if (!type.affectsCrumbling()) {
return;
}
type.clearRenderState();
CrumblingRenderer._currentLayer.setupRenderState();
int breakingTex = RenderSystem.getShaderTexture(0);
RenderSystem.setShaderTexture(0, renderTex);
RenderSystem.setShaderTexture(4, breakingTex);
currentLayer.setupRenderState();
Textures.bindActiveTextures();
CoreShaderInfo coreShaderInfo = getCoreShaderInfo();
for (Map.Entry<Instanced<? extends InstanceData>, GPUInstancerFactory<?>> entry : factories.entrySet()) {
//CrumblingProgram program = setup(entry.getKey(), coreShaderInfo, camX, camY, camZ, viewProjection, level);
for (Map.Entry<InstancedStructType<? extends InstanceData>, GPUInstancerFactory<?>> entry : factories.entrySet()) {
InstancedStructType<? extends InstanceData> instanceType = entry.getKey();
GPUInstancerFactory<?> factory = entry.getValue();
//program.setAtlasSize(width, height);
var materials = factory.materials.get(type);
for (Material material : materials) {
var toRender = factory.renderables.get(material);
toRender.removeIf(Renderable::shouldRemove);
//entry.getValue().getAllRenderables().forEach(Renderable::draw);
if (!toRender.isEmpty()) {
setup(instanceType, material, coreShaderInfo, camX, camY, camZ, viewProjection, level);
toRender.forEach(Renderable::render);
}
}
}
CrumblingRenderer._currentLayer.clearRenderState();
currentLayer.clearRenderState();
}
}
}

View file

@ -40,6 +40,7 @@ public class WorldProgram extends GlProgram {
uLightMap = setSamplerBinding("uLightMap", 2);
}
// TODO: create uniform registry
public void uploadUniforms(double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
fog.uploadUniforms();
uploadTime(AnimationTickHolder.getRenderTime());

View file

@ -246,6 +246,7 @@ public class SourceFile {
String fileName = file.get();
if (importedFiles.add(fileName)) {
// FIXME: creating imports after the first resource reload crashes the game
var checked = Import.create(errorReporter, use, file);
if (checked != null) {
imports.add(checked);

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.core.structs.model;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
@ -10,7 +10,7 @@ import com.jozufozu.flywheel.core.model.ModelTransformer;
import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.structs.InstanceShaders;
public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
public class ModelType implements InstancedStructType<ModelData>, BatchedStructType<ModelData> {
public static final BufferLayout FORMAT = BufferLayout.builder()
.addItems(CommonItems.LIGHT, CommonItems.RGBA)

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.core.structs.oriented;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.BatchedStructType;
import com.jozufozu.flywheel.api.struct.InstancedStructType;
import com.jozufozu.flywheel.api.struct.StructWriter;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.core.layout.BufferLayout;
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.core.source.FileResolution;
import com.jozufozu.flywheel.core.structs.InstanceShaders;
import com.mojang.math.Quaternion;
public class OrientedType implements Instanced<OrientedData>, Batched<OrientedData> {
public class OrientedType implements InstancedStructType<OrientedData>, BatchedStructType<OrientedData> {
public static final BufferLayout FORMAT = BufferLayout.builder()
.addItems(CommonItems.LIGHT, CommonItems.RGBA)

View file

@ -4,6 +4,7 @@ import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@ -15,7 +16,6 @@ import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f;
@ -74,22 +74,10 @@ public class LevelRendererMixin {
MinecraftForge.EVENT_BUS.post(new ReloadRenderersEvent(level));
}
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;checkPoseStack(Lcom/mojang/blaze3d/vertex/PoseStack;)V", ordinal = 2 // after the game renders the breaking overlay normally
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderBuffers;crumblingBufferSource()Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;", ordinal = 2, shift = Shift.BY, by = 2 // after the game renders the breaking overlay normally
), method = "renderLevel")
private void renderBlockBreaking(PoseStack stack, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, Camera info, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f p_228426_9_, CallbackInfo ci) {
if (!Backend.isOn()) return;
Vec3 cameraPos = info.getPosition();
Matrix4f viewProjection = stack.last()
.pose()
.copy();
viewProjection.multiplyBackward(RenderSystem.getProjectionMatrix());
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
CrumblingRenderer.renderBreaking(level, stack, cameraPos.x, cameraPos.y, cameraPos.z, viewProjection);
restoreState.restore();
private void renderBlockBreaking(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
CrumblingRenderer.renderCrumbling((LevelRenderer) (Object) this, level, poseStack, camera, projectionMatrix);
}
// Instancing

View file

@ -1,20 +0,0 @@
package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.util.Textures;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.resources.ResourceLocation;
@Mixin(RenderSystem.class)
public class RenderTexturesMixin {
@Inject(method = "_setShaderTexture(ILnet/minecraft/resources/ResourceLocation;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/AbstractTexture;getId()I"))
private static void storeTextureLoc(int pShaderTexture, ResourceLocation pTextureId, CallbackInfo ci) {
Textures._setShaderTexture(pShaderTexture, pTextureId);
}
}

View file

@ -1,28 +0,0 @@
package com.jozufozu.flywheel.mixin.atlas;
import java.util.stream.Stream;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.jozufozu.flywheel.core.crumbling.AtlasInfo;
import net.minecraft.client.renderer.texture.TextureAtlas;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.util.profiling.ProfilerFiller;
@Mixin(TextureAtlas.class)
public abstract class AtlasDataMixin {
@Shadow
public abstract ResourceLocation location();
@Inject(method = "prepareToStitch", at = @At("RETURN"))
public void stealAtlasData(ResourceManager resourceManager, Stream<ResourceLocation> locationStream, ProfilerFiller profiler, int mipMapLevels, CallbackInfoReturnable<TextureAtlas.Preparations> cir) {
AtlasInfo._setAtlasData(location(), (SheetDataAccessor) cir.getReturnValue());
}
}

View file

@ -1,17 +0,0 @@
package com.jozufozu.flywheel.mixin.atlas;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.renderer.texture.TextureAtlas;
@Mixin(TextureAtlas.Preparations.class)
public interface SheetDataAccessor {
@Accessor("width")
int flywheel$getWidth();
@Accessor("height")
int flywheel$getHeight();
}

View file

@ -1,33 +1,12 @@
package com.jozufozu.flywheel.util;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.opengl.GL32;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.resources.ResourceLocation;
/**
* Helper class to keep track of what texture atlases are bound to what texture units.
*
* <p>
* Works with {@link com.jozufozu.flywheel.mixin.RenderTexturesMixin}.
* </p>
*/
public class Textures {
private static final ResourceLocation[] shaderTextures = new ResourceLocation[12];
@Nullable
public static ResourceLocation getShaderTexture(int pShaderTexture) {
return shaderTextures[pShaderTexture];
}
public static void _setShaderTexture(int pShaderTexture, ResourceLocation pTextureId) {
shaderTextures[pShaderTexture] = pTextureId;
}
/**
* Call this after calling {@link RenderType#setupRenderState()}.
*/

View file

@ -6,11 +6,12 @@ uniform vec3 uCameraPos;
uniform int uFogShape;
void flw_contextVertex() {
flw_distance = fog_distance(flw_vertexPos.xyz, uCameraPos, uFogShape);
gl_Position = uViewProjection * flw_vertexPos;
// TODO: remove this
#ifdef DEBUG_NORMAL
flw_vertexColor = vec4(flw_vertexNormal, 1.0);
#endif
flw_distance = fog_distance(flw_vertexPos.xyz, uCameraPos, uFogShape);
gl_Position = uViewProjection * flw_vertexPos;
flw_vertexNormal = normalize(flw_vertexNormal);
}

View file

@ -3,18 +3,31 @@
uniform vec2 uFogRange;
uniform vec4 uFogColor;
uniform vec2 uTextureScale;
uniform sampler2D uBlockAtlas;
uniform sampler2D uCrumbling;
uniform sampler2D uCrumblingTex;
out vec4 fragColor;
vec2 flattenedPos(vec3 pos, vec3 normal) {
pos -= floor(pos) + vec3(0.5);
float sinYRot = -normal.x;
float sqLength = normal.x * normal.x + normal.z * normal.z;
if (sqLength > 0) {
sinYRot /= sqrt(sqLength);
sinYRot = clamp(sinYRot, -1, 1);
}
vec3 tangent = vec3(sqrt(1 - sinYRot * sinYRot) * (normal.z < 0 ? -1 : 1), 0, sinYRot);
vec3 bitangent = cross(tangent, normal);
mat3 tbn = mat3(tangent, bitangent, normal);
// transpose is the same as inverse for orthonormal matrices
return (transpose(tbn) * pos).xy + vec2(0.5);
}
void flw_contextFragment() {
vec4 texColor = texture(uBlockAtlas, flw_vertexTexCoord);
vec4 crumblingColor = texture(uCrumbling, flw_vertexTexCoord * uTextureScale);
crumblingColor.a *= texColor.a;
vec4 color = flw_vertexColor * vec4(crumblingColor.rgb, crumblingColor.a);
vec4 color = texture(uCrumblingTex, flattenedPos(flw_vertexPos.xyz, flw_vertexNormal));
#ifdef ALPHA_DISCARD
if (color.a < ALPHA_DISCARD) {

View file

@ -22,10 +22,7 @@
"LevelRendererMixin",
"MultiBufferSourceMixin",
"PausedPartialTickAccessor",
"RenderTexturesMixin",
"RenderTypeMixin",
"atlas.AtlasDataMixin",
"atlas.SheetDataAccessor",
"light.LightUpdateMixin",
"light.NetworkLightUpdateMixin",
"matrix.Matrix3fMixin",