Instanced Minecarts

- Rotations in PartBuilder
 - BlockModels are always UNLIT_MODEL format
This commit is contained in:
Jozufozu 2021-08-25 12:53:43 -07:00
parent 68ca281ee8
commit 86dbed66af
5 changed files with 255 additions and 33 deletions

View file

@ -4,7 +4,6 @@ import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.Instancer;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.model.BlockModel;
import com.jozufozu.flywheel.core.model.IModel;
@ -26,7 +25,7 @@ public interface InstanceMaterial<D extends InstanceData> {
Instancer<D> model(Object key, Supplier<IModel> modelSupplier);
default Instancer<D> getModel(PartialModel partial, BlockState referenceState) {
return model(partial, () -> new BlockModel(Formats.UNLIT_MODEL, partial.get(), referenceState));
return model(partial, () -> new BlockModel(partial.get(), referenceState));
}
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir) {
@ -34,10 +33,10 @@ public interface InstanceMaterial<D extends InstanceData> {
}
default Instancer<D> getModel(PartialModel partial, BlockState referenceState, Direction dir, Supplier<MatrixStack> modelTransform) {
return model(Pair.of(dir, partial), () -> new BlockModel(Formats.UNLIT_MODEL, partial.get(), referenceState, modelTransform.get()));
return model(Pair.of(dir, partial), () -> new BlockModel(partial.get(), referenceState, modelTransform.get()));
}
default Instancer<D> getModel(BlockState toRender) {
return model(toRender, () -> new BlockModel(Formats.UNLIT_MODEL, toRender));
return model(toRender, () -> new BlockModel(toRender));
}
}

View file

@ -6,8 +6,7 @@ import org.lwjgl.opengl.GL11;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.core.QuadConverter;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.util.BufferBuilderReader;
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
import com.mojang.blaze3d.matrix.MatrixStack;
@ -31,26 +30,23 @@ public class BlockModel implements IModel {
private final BufferBuilderReader reader;
private final VertexFormat modelFormat;
public BlockModel(VertexFormat modelFormat, BlockState state) {
this(modelFormat, Minecraft.getInstance()
public BlockModel(BlockState state) {
this(Minecraft.getInstance()
.getBlockRenderer()
.getBlockModel(state), state);
}
public BlockModel(VertexFormat modelFormat, IBakedModel model, BlockState referenceState) {
this(modelFormat, model, referenceState, IDENTITY);
public BlockModel(IBakedModel model, BlockState referenceState) {
this(model, referenceState, IDENTITY);
}
public BlockModel(VertexFormat modelFormat, IBakedModel model, BlockState referenceState, MatrixStack ms) {
this.modelFormat = modelFormat;
public BlockModel(IBakedModel model, BlockState referenceState, MatrixStack ms) {
reader = new BufferBuilderReader(getBufferBuilder(model, referenceState, ms));
}
@Override
public VertexFormat format() {
return modelFormat;
return Formats.UNLIT_MODEL;
}
@Override

View file

@ -11,6 +11,8 @@ import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction;
import net.minecraft.util.math.vector.Matrix3f;
import net.minecraft.util.math.vector.Quaternion;
import net.minecraft.util.math.vector.Vector3f;
public class PartBuilder {
@ -62,6 +64,11 @@ public class PartBuilder {
boolean invertYZ;
boolean useRotation;
float rotationX;
float rotationY;
float rotationZ;
final PartBuilder partBuilder;
CuboidBuilder(PartBuilder partBuilder) {
@ -96,6 +103,36 @@ public class PartBuilder {
return this;
}
public CuboidBuilder shift(float x, float y, float z) {
posX1 = posX1 - x;
posY1 = posY1 - y;
posZ1 = posZ1 - z;
posX2 = posX2 - x;
posY2 = posY2 - y;
posZ2 = posZ2 - z;
return this;
}
public CuboidBuilder rotate(float x, float y, float z) {
useRotation = true;
this.rotationX = x;
this.rotationY = y;
this.rotationZ = z;
return this;
}
public CuboidBuilder rotateX(float x) {
useRotation = true;
this.rotationX = x;
return this;
}
public CuboidBuilder rotateY(float y) {
useRotation = true;
this.rotationY = y;
return this;
}
public CuboidBuilder sprite(TextureAtlasSprite sprite) {
this.sprite = sprite;
return this;
@ -130,6 +167,7 @@ public class PartBuilder {
float posY2 = this.posY2 / 16f;
float posZ2 = this.posZ2 / 16f;
Vector3f lll = new Vector3f(posX1, posY1, posZ1);
Vector3f hll = new Vector3f(posX2, posY1, posZ1);
Vector3f hhl = new Vector3f(posX2, posY2, posZ1);
@ -138,6 +176,32 @@ public class PartBuilder {
Vector3f hlh = new Vector3f(posX2, posY1, posZ2);
Vector3f hhh = new Vector3f(posX2, posY2, posZ2);
Vector3f lhh = new Vector3f(posX1, posY2, posZ2);
Vector3f down = Direction.DOWN.step();
Vector3f up = Direction.UP.step();
Vector3f west = Direction.WEST.step();
Vector3f north = Direction.NORTH.step();
Vector3f east = Direction.EAST.step();
Vector3f south = Direction.SOUTH.step();
if (useRotation) {
Matrix3f matrix3f = new Matrix3f(new Quaternion(rotationX, rotationY, rotationZ, false));
lll.transform(matrix3f);
hll.transform(matrix3f);
hhl.transform(matrix3f);
lhl.transform(matrix3f);
llh.transform(matrix3f);
hlh.transform(matrix3f);
hhh.transform(matrix3f);
lhh.transform(matrix3f);
down.transform(matrix3f);
up.transform(matrix3f);
west.transform(matrix3f);
north.transform(matrix3f);
east.transform(matrix3f);
south.transform(matrix3f);
}
float f4 = getU((float)textureOffsetU);
float f5 = getU((float)textureOffsetU + sizeZ);
float f6 = getU((float)textureOffsetU + sizeZ + sizeX);
@ -149,27 +213,24 @@ public class PartBuilder {
float f12 = getV((float)textureOffsetV + sizeZ + sizeY);
if (invertYZ) {
quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, Direction.DOWN);
quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, Direction.UP);
quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, Direction.WEST);
quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, Direction.NORTH);
quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, Direction.EAST);
quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, Direction.SOUTH);
quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f6, f11, f7, f10, down);
quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f5, f10, f6, f11, up);
quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f5, f12, f4, f11, west);
quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f9, f12, f8, f11, north);
quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f8, f12, f6, f11, east);
quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f6, f12, f5, f11, south);
} else {
quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, Direction.DOWN);
quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, Direction.UP);
quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, Direction.WEST);
quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, Direction.NORTH);
quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, Direction.EAST);
quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, Direction.SOUTH);
quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, down);
quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, up);
quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, west);
quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, north);
quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, east);
quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, south);
}
}
public void quad(VecBuffer buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Direction dir) {
Vector3f normal = dir.step();
public void quad(VecBuffer buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, Vector3f normal) {
buffer.putVec3(vertices[0].x(), vertices[0].y(), vertices[0].z()).putVec3(nb(normal.x()), nb(normal.y()), nb(normal.z())).putVec2(maxU, minV);
buffer.putVec3(vertices[1].x(), vertices[1].y(), vertices[1].z()).putVec3(nb(normal.x()), nb(normal.y()), nb(normal.z())).putVec2(minU, minV);
buffer.putVec3(vertices[2].x(), vertices[2].y(), vertices[2].z()).putVec3(nb(normal.x()), nb(normal.y()), nb(normal.z())).putVec2(minU, maxV);
@ -181,14 +242,14 @@ public class PartBuilder {
if (sprite != null)
return sprite.getU(u * 16 / partBuilder.sizeU);
else
return u;
return u / partBuilder.sizeU;
}
public float getV(float v) {
if (sprite != null)
return sprite.getV(v * 16 / partBuilder.sizeV);
else
return v;
return v / partBuilder.sizeV;
}
}

View file

@ -0,0 +1,155 @@
package com.jozufozu.flywheel.vanilla;
import com.jozufozu.flywheel.backend.instancing.IDynamicInstance;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import com.jozufozu.flywheel.backend.material.MaterialManager;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.backend.state.TextureRenderState;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.materials.ModelData;
import com.jozufozu.flywheel.core.model.BlockModel;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.core.model.ModelPart;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.entity.item.minecart.AbstractMinecartEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3f;
public class MinecartInstance<T extends AbstractMinecartEntity> extends EntityInstance<T> implements IDynamicInstance {
private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png");
MatrixTransformStack stack = new MatrixTransformStack();
private final ModelData body;
private final ModelData contents;
public MinecartInstance(MaterialManager materialManager, T entity) {
super(materialManager, entity);
contents = getContents();
body = getBody();
}
@Override
public void beginFrame() {
stack.setIdentity();
float pt = AnimationTickHolder.getPartialTicks();
stack.translate(
MathHelper.lerp(pt, entity.xOld, entity.getX()),
MathHelper.lerp(pt, entity.yOld, entity.getY()),
MathHelper.lerp(pt, entity.zOld, entity.getZ())
);
float yaw = MathHelper.lerp(pt, entity.yRotO, entity.yRot);
long i = (long)entity.getId() * 493286711L;
i = i * i * 4392167121L + i * 98761L;
float f = (((float)(i >> 16 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F;
float f1 = (((float)(i >> 20 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F;
float f2 = (((float)(i >> 24 & 7L) + 0.5F) / 8 - 0.5F) * 0.004F;
stack.translate(f, f1, f2);
stack.nudge(entity.getId());
double d0 = MathHelper.lerp(pt, entity.xOld, entity.getX());
double d1 = MathHelper.lerp(pt, entity.yOld, entity.getY());
double d2 = MathHelper.lerp(pt, entity.zOld, entity.getZ());
Vector3d vector3d = entity.getPos(d0, d1, d2);
float f3 = MathHelper.lerp(pt, entity.xRotO, entity.xRot);
if (vector3d != null) {
Vector3d vector3d1 = entity.getPosOffs(d0, d1, d2, 0.3F);
Vector3d vector3d2 = entity.getPosOffs(d0, d1, d2, -0.3F);
if (vector3d1 == null) {
vector3d1 = vector3d;
}
if (vector3d2 == null) {
vector3d2 = vector3d;
}
stack.translate(vector3d.x - d0, (vector3d1.y + vector3d2.y) / 2.0D - d1, vector3d.z - d2);
Vector3d vector3d3 = vector3d2.add(-vector3d1.x, -vector3d1.y, -vector3d1.z);
if (vector3d3.length() != 0.0D) {
vector3d3 = vector3d3.normalize();
yaw = (float)(Math.atan2(vector3d3.z, vector3d3.x) * 180.0D / Math.PI);
f3 = (float)(Math.atan(vector3d3.y) * 73.0D);
}
}
stack.translate(0.0D, 0.375D, 0.0D);
stack.multiply(Vector3f.YP.rotationDegrees(180 - yaw));
stack.multiply(Vector3f.ZP.rotationDegrees(-f3));
float f5 = (float)entity.getHurtTime() - pt;
float f6 = entity.getDamage() - pt;
if (f6 < 0) {
f6 = 0;
}
if (f5 > 0) {
stack.multiply(Vector3f.XP.rotationDegrees(MathHelper.sin(f5) * f5 * f6 / 10 * (float)entity.getHurtDir()));
}
int j = entity.getDisplayOffset();
if (contents != null) {
stack.push();
stack.scale(0.75F);
stack.translate(-0.5D, (float)(j - 8) / 16, 0.5D);
stack.multiply(Vector3f.YP.rotationDegrees(90));
contents.setTransform(stack.unwrap());
stack.pop();
}
body.setTransform(stack.unwrap());
}
@Override
public void updateLight() {
if (contents == null)
relight(getWorldPosition(), body);
else
relight(getWorldPosition(), body, contents);
}
@Override
public void remove() {
body.delete();
if (contents != null) contents.delete();
}
private ModelData getContents() {
BlockState blockstate = entity.getDisplayBlockState();
if (blockstate.getRenderShape() == BlockRenderType.INVISIBLE)
return null;
return materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(blockstate)
.createInstance();
}
private ModelData getBody() {
return materialManager.solid(TextureRenderState.get(MINECART_LOCATION))
.material(Materials.TRANSFORMED)
.model(entity.getType(), this::getBodyModel)
.createInstance();
}
private IModel getBodyModel() {
int y = -3;
return ModelPart.builder(64, 32)
.cuboid().invertYZ().start(-10, -8, -y).size(20, 16, 2).textureOffset(0, 10).rotateX(((float)Math.PI / 2F)).endCuboid()
.cuboid().invertYZ().start(-8, y, -10).size(16, 8, 2).rotateY(((float)Math.PI * 1.5F)).endCuboid()
.cuboid().invertYZ().start(-8, y, -10).size(16, 8, 2).rotateY(((float)Math.PI / 2F)).endCuboid()
.cuboid().invertYZ().start(-8, y, -8).size(16, 8, 2).rotateY((float)Math.PI).endCuboid()
.cuboid().invertYZ().start(-8, y, -8).size(16, 8, 2).endCuboid()
.build();
}
}

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.vanilla;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import net.minecraft.entity.EntityType;
import net.minecraft.tileentity.TileEntityType;
/**
@ -46,5 +47,15 @@ public class VanillaInstances {
r.tile(TileEntityType.SHULKER_BOX)
.setSkipRender(true)
.factory(ShulkerBoxInstance::new);
r.entity(EntityType.MINECART)
.setSkipRender(true)
.factory(MinecartInstance::new);
r.entity(EntityType.HOPPER_MINECART)
.setSkipRender(true)
.factory(MinecartInstance::new);
r.entity(EntityType.FURNACE_MINECART)
.setSkipRender(true)
.factory(MinecartInstance::new);
}
}