Instanced entities stage 1

This commit is contained in:
JozsefA 2021-06-07 18:12:46 -07:00
parent 285b8f98cf
commit 9cc03a81d7
12 changed files with 237 additions and 82 deletions

View file

@ -1,12 +1,18 @@
package com.jozufozu.flywheel.backend;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
import net.minecraft.util.ResourceLocation;
public interface IShaderContext<P extends GlProgram> {
P getProgram(ResourceLocation loc);
default P getProgram(ResourceLocation loc) {
return this.getProgramSupplier(loc).get();
}
Supplier<P> getProgramSupplier(ResourceLocation loc);
/**
* Load all programs associated with this context. This might be just one, if the context is very specialized.

View file

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import javax.annotation.Nullable;
@ -30,8 +31,8 @@ public abstract class ShaderContext<P extends GlProgram> implements IShaderConte
}
@Override
public P getProgram(ResourceLocation spec) {
return programs.get(spec).get();
public Supplier<P> getProgramSupplier(ResourceLocation spec) {
return programs.get(spec);
}
public Program loadAndLink(ProgramSpec spec, @Nullable ProgramState state) {

View file

@ -4,20 +4,15 @@ import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL15;
public abstract class MappedBuffer implements AutoCloseable {
public abstract class MappedBuffer extends VecBuffer implements AutoCloseable {
protected boolean mapped;
protected final GlBuffer owner;
protected ByteBuffer internal;
public MappedBuffer(GlBuffer owner) {
this.owner = owner;
}
public void setInternal(ByteBuffer internal) {
this.internal = internal;
}
protected abstract void checkAndMap();
/**
@ -38,20 +33,13 @@ public abstract class MappedBuffer implements AutoCloseable {
public MappedBuffer putFloatArray(float[] floats) {
checkAndMap();
for (float f : floats) {
internal.putFloat(f);
}
// internal.asFloatBuffer().put(floats);
// internal.position(internal.position() + floats.length * 4);
super.putFloatArray(floats);
return this;
}
public MappedBuffer putByteArray(byte[] bytes) {
checkAndMap();
internal.put(bytes);
super.putByteArray(bytes);
return this;
}
@ -62,75 +50,61 @@ public abstract class MappedBuffer implements AutoCloseable {
*/
public MappedBuffer position(int p) {
checkAndMap();
internal.position(p);
super.position(p);
return this;
}
public MappedBuffer putFloat(float f) {
checkAndMap();
internal.putFloat(f);
super.putFloat(f);
return this;
}
public MappedBuffer putInt(int i) {
checkAndMap();
internal.putInt(i);
super.putInt(i);
return this;
}
public MappedBuffer put(byte b) {
checkAndMap();
internal.put(b);
super.put(b);
return this;
}
public MappedBuffer put(ByteBuffer b) {
checkAndMap();
internal.put(b);
super.put(b);
return this;
}
public MappedBuffer putVec4(float x, float y, float z, float w) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
internal.putFloat(w);
super.putVec4(x, y, z, w);
return this;
}
public MappedBuffer putVec3(float x, float y, float z) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
super.putVec3(x, y, z);
return this;
}
public MappedBuffer putVec2(float x, float y) {
checkAndMap();
internal.putFloat(x);
internal.putFloat(y);
super.putVec2(x, y);
return this;
}
public MappedBuffer putVec3(byte x, byte y, byte z) {
checkAndMap();
internal.put(x);
internal.put(y);
internal.put(z);
super.putVec3(x, y, z);
return this;
}
public MappedBuffer putVec2(byte x, byte y) {
checkAndMap();
internal.put(x);
internal.put(y);
super.putVec2(x, y);
return this;
}
}

View file

@ -0,0 +1,116 @@
package com.jozufozu.flywheel.backend.gl.buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class VecBuffer {
protected ByteBuffer internal;
public VecBuffer() {
}
public VecBuffer(ByteBuffer internal) {
this.internal = internal;
}
public static VecBuffer allocate(int bytes) {
ByteBuffer buffer = ByteBuffer.allocate(bytes);
buffer.order(ByteOrder.nativeOrder());
return new VecBuffer(buffer);
}
protected void setInternal(ByteBuffer internal) {
this.internal = internal;
}
public ByteBuffer unwrap() {
return internal;
}
public VecBuffer rewind() {
internal.rewind();
return this;
}
public VecBuffer putFloatArray(float[] floats) {
for (float f : floats) {
internal.putFloat(f);
}
// internal.asFloatBuffer().put(floats);
// internal.position(internal.position() + floats.length * 4);
return this;
}
public VecBuffer putByteArray(byte[] bytes) {
internal.put(bytes);
return this;
}
/**
* Position this buffer relative to the 0-index in GPU memory.
*
* @return This buffer.
*/
public VecBuffer position(int p) {
internal.position(p);
return this;
}
public VecBuffer putFloat(float f) {
internal.putFloat(f);
return this;
}
public VecBuffer putInt(int i) {
internal.putInt(i);
return this;
}
public VecBuffer put(byte b) {
internal.put(b);
return this;
}
public VecBuffer put(ByteBuffer b) {
internal.put(b);
return this;
}
public VecBuffer putVec4(float x, float y, float z, float w) {
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
internal.putFloat(w);
return this;
}
public VecBuffer putVec3(float x, float y, float z) {
internal.putFloat(x);
internal.putFloat(y);
internal.putFloat(z);
return this;
}
public VecBuffer putVec2(float x, float y) {
internal.putFloat(x);
internal.putFloat(y);
return this;
}
public VecBuffer putVec3(byte x, byte y, byte z) {
internal.put(x);
internal.put(y);
internal.put(z);
return this;
}
public VecBuffer putVec2(byte x, byte y) {
internal.put(x);
internal.put(y);
return this;
}
}

View file

@ -54,6 +54,10 @@ public class InstanceMaterial<D extends InstanceData> {
modelFormat = this.spec.getModelFormat();
}
public boolean nothingToRender() {
return models.size() > 0 && models.asMap().values().stream().allMatch(Instancer::empty);
}
public void delete() {
models.invalidateAll();
}

View file

@ -80,6 +80,10 @@ public class Instancer<D extends InstanceData> {
return instanceData;
}
public boolean empty() {
return !anyToUpdate && !anyToRemove && glInstanceCount == 0;
}
/**
* Clear all instance data without freeing resources.
*/

View file

@ -13,6 +13,7 @@ import com.jozufozu.flywheel.core.shader.IProgramCallback;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.util.WeakHashSet;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.util.ResourceLocation;
@ -25,25 +26,28 @@ public class MaterialManager<P extends WorldProgram> {
public static int MAX_ORIGIN_DISTANCE = 100;
protected final ArrayList<MaterialRenderer<P>> renderers;
protected final Map<ResourceLocation, InstanceMaterial<?>> materials;
protected final WorldContext<P> context;
protected final Map<MaterialSpec<?>, InstanceMaterial<?>> atlasMaterials;
protected final ArrayList<MaterialRenderer<P>> atlasRenderers;
protected final Map<ResourceLocation, ArrayList<MaterialRenderer<P>>> renderers;
protected final Map<ResourceLocation, Map<MaterialSpec<?>, InstanceMaterial<?>>> materials;
private BlockPos originCoordinate = BlockPos.ZERO;
private final WeakHashSet<OriginShiftListener> listeners;
public MaterialManager(WorldContext<P> context) {
this.context = context;
this.atlasMaterials = new HashMap<>();
this.atlasRenderers = new ArrayList<>(Backend.getInstance().allMaterials().size());
this.materials = new HashMap<>();
this.renderers = new ArrayList<>(Backend.getInstance().allMaterials().size());
this.renderers = new HashMap<>();
this.listeners = new WeakHashSet<>();
for (MaterialSpec<?> spec : Backend.getInstance().allMaterials()) {
InstanceMaterial<?> material = new InstanceMaterial<>(this::getOriginCoordinate, spec);
materials.put(spec.name, material);
MaterialRenderer<P> renderer = new MaterialRenderer<>(context.getProgram(spec.getProgramName()), material);
renderers.add(renderer);
}
}
/**
@ -72,20 +76,47 @@ public class MaterialManager<P extends WorldProgram> {
translate.multiplyBackward(viewProjection);
for (MaterialRenderer<P> material : renderers) {
for (MaterialRenderer<P> material : atlasRenderers) {
material.render(layer, translate, camX, camY, camZ, callback);
}
for (Map.Entry<ResourceLocation, ArrayList<MaterialRenderer<P>>> entry : renderers.entrySet()) {
Minecraft.getInstance().textureManager.bindTexture(entry.getKey());
for (MaterialRenderer<P> materialRenderer : entry.getValue()) {
materialRenderer.render(layer, translate, camX, camY, camZ, callback);
}
}
}
public void delete() {
for (InstanceMaterial<?> material : materials.values()) {
material.delete();
}
atlasMaterials.values().forEach(InstanceMaterial::delete);
materials.values().stream().flatMap(m -> m.values().stream()).forEach(InstanceMaterial::delete);
}
@SuppressWarnings("unchecked")
public <D extends InstanceData> InstanceMaterial<D> getMaterial(MaterialSpec<D> materialType) {
return (InstanceMaterial<D>) materials.get(materialType.name);
return (InstanceMaterial<D>) this.atlasMaterials.computeIfAbsent(materialType, type -> {
InstanceMaterial<?> material = new InstanceMaterial<>(this::getOriginCoordinate, type);
this.atlasRenderers.add(new MaterialRenderer<>(context.getProgramSupplier(type.getProgramName()), material));
return material;
});
}
@SuppressWarnings("unchecked")
public <D extends InstanceData> InstanceMaterial<D> getMaterial(MaterialSpec<D> materialType, ResourceLocation texture) {
return (InstanceMaterial<D>) materials.computeIfAbsent(texture, $ -> new HashMap<>())
.computeIfAbsent(materialType, type -> {
InstanceMaterial<?> material = new InstanceMaterial<>(this::getOriginCoordinate, type);
this.renderers.computeIfAbsent(texture, $ -> new ArrayList<>())
.add(new MaterialRenderer<>(context.getProgramSupplier(type.getProgramName()), material));
return material;
});
}
public InstanceMaterial<ModelData> getTransformMaterial() {
@ -117,7 +148,8 @@ public class MaterialManager<P extends WorldProgram> {
originCoordinate = new BlockPos(cX, cY, cZ);
materials.values().forEach(InstanceMaterial::clear);
materials.values().stream().flatMap(m -> m.values().stream()).forEach(InstanceMaterial::clear);
atlasMaterials.values().forEach(InstanceMaterial::clear);
listeners.forEach(OriginShiftListener::onOriginShift);
}
}

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.backend.instancing;
import java.util.function.Supplier;
import com.jozufozu.flywheel.core.shader.IProgramCallback;
import com.jozufozu.flywheel.core.shader.WorldProgram;
@ -8,17 +10,21 @@ import net.minecraft.util.math.vector.Matrix4f;
public class MaterialRenderer<P extends WorldProgram> {
private final P program;
private final Supplier<P> program;
private final InstanceMaterial<?> material;
public MaterialRenderer(P program, InstanceMaterial<?> material) {
this.program = program;
public MaterialRenderer(Supplier<P> programSupplier, InstanceMaterial<?> material) {
this.program = programSupplier;
this.material = material;
}
public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, IProgramCallback<P> setup) {
if (!(layer == RenderType.getCutoutMipped())) return;
if (material.nothingToRender()) return;
P program = this.program.get();
program.bind();
program.uploadViewProjection(viewProjection);
program.uploadCameraPos(camX, camY, camZ);

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import net.minecraft.inventory.container.PlayerContainer;
import net.minecraft.util.ResourceLocation;
public class MaterialSpec<D extends InstanceData> {
@ -12,13 +13,19 @@ public class MaterialSpec<D extends InstanceData> {
private final VertexFormat modelFormat;
private final VertexFormat instanceFormat;
private final IInstanceFactory<D> instanceFactory;
private final ResourceLocation texture;
public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, IInstanceFactory<D> instanceFactory) {
this(name, programSpec, modelFormat, instanceFormat, PlayerContainer.BLOCK_ATLAS_TEXTURE, instanceFactory);
}
public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, ResourceLocation texture, IInstanceFactory<D> instanceFactory) {
this.name = name;
this.programSpec = programSpec;
this.modelFormat = modelFormat;
this.instanceFormat = instanceFormat;
this.instanceFactory = instanceFactory;
this.texture = texture;
}
public ResourceLocation getProgramName() {

View file

@ -1,5 +1,7 @@
package com.jozufozu.flywheel.core.shader;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
/**
@ -8,7 +10,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
*
* @param <P>
*/
public interface IMultiProgram<P extends GlProgram> {
public interface IMultiProgram<P extends GlProgram> extends Supplier<P> {
/**
* Get the shader program most suited for the current game state.

View file

@ -1,8 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement.glue;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.instancing.ITickableInstance;
import com.jozufozu.flywheel.backend.instancing.Instancer;
import com.jozufozu.flywheel.backend.instancing.MaterialManager;
@ -14,23 +12,28 @@ import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.instancing.ConditionalInstance;
import com.jozufozu.flywheel.core.materials.OrientedData;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Quaternion;
import net.minecraft.util.math.vector.Vector3d;
public class GlueInstance extends EntityInstance<SuperGlueEntity> implements ITickableInstance {
private static final ResourceLocation TEXTURE = new ResourceLocation(Create.ID, "textures/entity/super_glue/slime.png");
private final Quaternion rotation;
protected ConditionalInstance<OrientedData> model;
public GlueInstance(MaterialManager<?> renderer, SuperGlueEntity entity) {
super(renderer, entity);
Instancer<OrientedData> instancer = renderer.getMaterial(Materials.ORIENTED)
public GlueInstance(MaterialManager<?> materialManager, SuperGlueEntity entity) {
super(materialManager, entity);
Instancer<OrientedData> instancer = materialManager.getMaterial(Materials.ORIENTED, TEXTURE)
.get(entity.getType(), GlueInstance::supplyModel);
Direction face = entity.getFacingDirection();
@ -55,6 +58,7 @@ public class GlueInstance extends EntityInstance<SuperGlueEntity> implements ITi
private void positionModel(OrientedData model) {
model.setPosition(getInstancePosition())
.setPivot(0, 0, 0)
.setRotation(rotation)
.setSkyLight(15)
.setBlockLight(15);
@ -93,24 +97,23 @@ public class GlueInstance extends EntityInstance<SuperGlueEntity> implements ITi
Vector3d a4 = plane.add(start);
Vector3d b4 = plane.add(end);
ByteBuffer buffer = ByteBuffer.allocate(Formats.UNLIT_MODEL.getStride() * 8);
buffer.order(ByteOrder.nativeOrder());
VecBuffer buffer = VecBuffer.allocate(Formats.UNLIT_MODEL.getStride() * 8);
// x, y, z,nx, ny,nz, u, v
// pos normal uv
// inside quad
buffer.putFloat((float) a1.x).putFloat((float) a1.y).putFloat((float) a1.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(1f).putFloat(0f);
buffer.putFloat((float) a2.x).putFloat((float) a2.y).putFloat((float) a2.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(1f).putFloat(1f);
buffer.putFloat((float) a3.x).putFloat((float) a3.y).putFloat((float) a3.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(0f).putFloat(1f);
buffer.putFloat((float) a4.x).putFloat((float) a4.y).putFloat((float) a4.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(0f).putFloat(0f);
buffer.putVec3((float) a1.x, (float) a1.y, (float) a1.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 0f);
buffer.putVec3((float) a2.x, (float) a2.y, (float) a2.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 1f);
buffer.putVec3((float) a3.x, (float) a3.y, (float) a3.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 1f);
buffer.putVec3((float) a4.x, (float) a4.y, (float) a4.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 0f);
// outside quad
buffer.putFloat((float) b4.x).putFloat((float) b4.y).putFloat((float) b4.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(0f).putFloat(0f);
buffer.putFloat((float) b3.x).putFloat((float) b3.y).putFloat((float) b3.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(0f).putFloat(1f);
buffer.putFloat((float) b2.x).putFloat((float) b2.y).putFloat((float) b2.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(1f).putFloat(1f);
buffer.putFloat((float) b1.x).putFloat((float) b1.y).putFloat((float) b1.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(1f).putFloat(0f);
buffer.putVec3((float) b4.x, (float) b4.y, (float) b4.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 0f);
buffer.putVec3((float) b3.x, (float) b3.y, (float) b3.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 1f);
buffer.putVec3((float) b2.x, (float) b2.y, (float) b2.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 1f);
buffer.putVec3((float) b1.x, (float) b1.y, (float) b1.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 0f);
buffer.rewind();
return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer, 8);
return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer.unwrap(), 8);
}
}

View file

@ -15,7 +15,7 @@ public class ContraptionMaterialManager extends MaterialManager<ContraptionProgr
@Override
public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, IProgramCallback<ContraptionProgram> callback) {
for (MaterialRenderer<ContraptionProgram> material : renderers) {
for (MaterialRenderer<ContraptionProgram> material : atlasRenderers) {
material.render(layer, viewProjection, camX, camY, camZ, callback);
}
}