mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
What a view!
- Add entity view vectors to BoundingBoxComponent. - Add "centerline" material, similar to wireframe. - Add SmartRecycler to create recyclers based on a parameter.
This commit is contained in:
parent
b0bc3d3145
commit
31148ae9b5
6 changed files with 91 additions and 24 deletions
|
@ -12,6 +12,8 @@ public final class StandardMaterialShaders {
|
|||
|
||||
public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag")));
|
||||
|
||||
public static final MaterialShaders CENTERLINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/centerline.vert"), Flywheel.rl("material/centerline.frag")));
|
||||
|
||||
private StandardMaterialShaders() {
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.jozufozu.flywheel.lib.visual;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
|
||||
public class SmartRecycler<K, I extends Instance> {
|
||||
private final Function<K, I> factory;
|
||||
private final Map<K, InstanceRecycler<I>> recyclers = new HashMap<>();
|
||||
|
||||
public SmartRecycler(Function<K, I> factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public void resetCount() {
|
||||
recyclers.values()
|
||||
.forEach(InstanceRecycler::resetCount);
|
||||
}
|
||||
|
||||
public I get(K key) {
|
||||
return recyclers.computeIfAbsent(key, k -> new InstanceRecycler<>(() -> factory.apply(k)))
|
||||
.get();
|
||||
}
|
||||
|
||||
public void discardExtra() {
|
||||
recyclers.values()
|
||||
.forEach(InstanceRecycler::discardExtra);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
recyclers.values()
|
||||
.forEach(InstanceRecycler::delete);
|
||||
recyclers.clear();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.lib.visual.components;
|
||||
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector4f;
|
||||
import org.joml.Vector4fc;
|
||||
|
||||
|
@ -16,7 +17,7 @@ import com.jozufozu.flywheel.lib.math.MoreMath;
|
|||
import com.jozufozu.flywheel.lib.model.QuadMesh;
|
||||
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
|
||||
import com.jozufozu.flywheel.lib.visual.EntityComponent;
|
||||
import com.jozufozu.flywheel.lib.visual.InstanceRecycler;
|
||||
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
@ -25,30 +26,38 @@ import net.minecraft.world.entity.Entity;
|
|||
import net.minecraft.world.entity.LivingEntity;
|
||||
|
||||
public class BoundingBoxComponent implements EntityComponent {
|
||||
private static final Material MATERIAL = SimpleMaterial.builder()
|
||||
private static final Material WIREFRAME = SimpleMaterial.builder()
|
||||
.shaders(StandardMaterialShaders.WIREFRAME)
|
||||
.backfaceCulling(false)
|
||||
.build();
|
||||
private static final Model MODEL = new SingleMeshModel(BoundingBoxMesh.INSTANCE, MATERIAL);
|
||||
|
||||
private static final Material CENTERLINE = SimpleMaterial.builder()
|
||||
.shaders(StandardMaterialShaders.CENTERLINE)
|
||||
.backfaceCulling(false)
|
||||
.build();
|
||||
private static final Model BOX = new SingleMeshModel(BoundingBoxMesh.INSTANCE, WIREFRAME);
|
||||
|
||||
// Should we try a single quad oriented to face the camera instead?
|
||||
private static final Model LINE = new SingleMeshModel(BoundingBoxMesh.INSTANCE, CENTERLINE);
|
||||
|
||||
private final VisualizationContext context;
|
||||
private final Entity entity;
|
||||
|
||||
private boolean showEyeBox;
|
||||
|
||||
private final InstanceRecycler<TransformedInstance> recycler;
|
||||
private final SmartRecycler<Model, TransformedInstance> recycler;
|
||||
|
||||
public BoundingBoxComponent(VisualizationContext context, Entity entity) {
|
||||
this.context = context;
|
||||
this.entity = entity;
|
||||
this.showEyeBox = entity instanceof LivingEntity;
|
||||
|
||||
this.recycler = new InstanceRecycler<>(this::createInstance);
|
||||
this.recycler = new SmartRecycler<>(this::createInstance);
|
||||
}
|
||||
|
||||
private TransformedInstance createInstance() {
|
||||
private TransformedInstance createInstance(Model model) {
|
||||
TransformedInstance instance = context.instancerProvider()
|
||||
.instancer(InstanceTypes.TRANSFORMED, MODEL)
|
||||
.instancer(InstanceTypes.TRANSFORMED, model)
|
||||
.createInstance();
|
||||
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
|
||||
instance.setChanged();
|
||||
|
@ -76,22 +85,33 @@ public class BoundingBoxComponent implements EntityComponent {
|
|||
var bbWidth = entity.getBbWidth();
|
||||
var bbHeight = entity.getBbHeight();
|
||||
var bbWidthHalf = bbWidth * 0.5;
|
||||
recycler.get()
|
||||
recycler.get(BOX)
|
||||
.loadIdentity()
|
||||
.translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf)
|
||||
.scale(bbWidth, bbHeight, bbWidth)
|
||||
.setChanged();
|
||||
|
||||
// TODO: multipart entities and view vectors
|
||||
// TODO: multipart entities, but forge seems to have an
|
||||
// injection for them so we'll need platform specific code.
|
||||
|
||||
if (showEyeBox) {
|
||||
recycler.get()
|
||||
recycler.get(BOX)
|
||||
.loadIdentity()
|
||||
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
|
||||
.scale(bbWidth, 0.02f, bbWidth)
|
||||
.setColor(255, 0, 0)
|
||||
.setChanged();
|
||||
}
|
||||
|
||||
var viewVector = entity.getViewVector(context.partialTick());
|
||||
|
||||
recycler.get(LINE)
|
||||
.loadIdentity()
|
||||
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
|
||||
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
|
||||
.scale(0.02f, 2f, 0.02f)
|
||||
.setColor(0, 0, 255)
|
||||
.setChanged();
|
||||
}
|
||||
|
||||
recycler.discardExtra();
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.joml.Vector4f;
|
|||
import org.joml.Vector4fc;
|
||||
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||
|
@ -15,7 +16,7 @@ import com.jozufozu.flywheel.lib.model.ModelCache;
|
|||
import com.jozufozu.flywheel.lib.model.QuadMesh;
|
||||
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
|
||||
import com.jozufozu.flywheel.lib.visual.EntityComponent;
|
||||
import com.jozufozu.flywheel.lib.visual.InstanceRecycler;
|
||||
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
|
||||
|
@ -42,20 +43,18 @@ public class FireComponent implements EntityComponent {
|
|||
private final Entity entity;
|
||||
private final PoseStack stack = new PoseStack();
|
||||
|
||||
private final InstanceRecycler<TransformedInstance> fire0;
|
||||
private final InstanceRecycler<TransformedInstance> fire1;
|
||||
private final SmartRecycler<Model, TransformedInstance> recycler;
|
||||
|
||||
public FireComponent(VisualizationContext context, Entity entity) {
|
||||
this.context = context;
|
||||
this.entity = entity;
|
||||
|
||||
fire0 = new InstanceRecycler<>(() -> createInstance(ModelBakery.FIRE_0));
|
||||
fire1 = new InstanceRecycler<>(() -> createInstance(ModelBakery.FIRE_1));
|
||||
recycler = new SmartRecycler<>(this::createInstance);
|
||||
}
|
||||
|
||||
private TransformedInstance createInstance(net.minecraft.client.resources.model.Material texture) {
|
||||
private TransformedInstance createInstance(Model model) {
|
||||
TransformedInstance instance = context.instancerProvider()
|
||||
.instancer(InstanceTypes.TRANSFORMED, FIRE_MODELS.get(texture))
|
||||
.instancer(InstanceTypes.TRANSFORMED, model)
|
||||
.createInstance();
|
||||
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
|
||||
instance.setChanged();
|
||||
|
@ -70,15 +69,13 @@ public class FireComponent implements EntityComponent {
|
|||
*/
|
||||
@Override
|
||||
public void beginFrame(VisualFrameContext context) {
|
||||
fire0.resetCount();
|
||||
fire1.resetCount();
|
||||
recycler.resetCount();
|
||||
|
||||
if (entity.displayFireAnimation()) {
|
||||
setupInstances(context);
|
||||
}
|
||||
|
||||
fire0.discardExtra();
|
||||
fire1.discardExtra();
|
||||
recycler.discardExtra();
|
||||
}
|
||||
|
||||
private void setupInstances(VisualFrameContext context) {
|
||||
|
@ -101,7 +98,7 @@ public class FireComponent implements EntityComponent {
|
|||
stack.translate(0.0F, 0.0F, -0.3F + (float) ((int) maxHeight) * 0.02F);
|
||||
|
||||
for (int i = 0; y < maxHeight; ++i) {
|
||||
var instance = (i % 2 == 0 ? this.fire0 : this.fire1).get()
|
||||
var instance = recycler.get(FIRE_MODELS.get(i % 2 == 0 ? ModelBakery.FIRE_0 : ModelBakery.FIRE_1))
|
||||
.setTransform(stack)
|
||||
.scaleX(width)
|
||||
.translate(0, y, z);
|
||||
|
@ -123,8 +120,7 @@ public class FireComponent implements EntityComponent {
|
|||
|
||||
@Override
|
||||
public void delete() {
|
||||
fire0.delete();
|
||||
fire1.delete();
|
||||
recycler.delete();
|
||||
}
|
||||
|
||||
private record FireMesh(TextureAtlasSprite sprite) implements QuadMesh {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
void flw_materialFragment() {
|
||||
float toCenter = abs(flw_vertexTexCoord.s - 0.5);
|
||||
|
||||
// multiply by fwidth to get the width of the edge in screen space
|
||||
if (flw_defaultLineWidth * fwidth(toCenter) < toCenter) {
|
||||
discard;
|
||||
}
|
||||
|
||||
flw_fragColor = flw_vertexColor;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
void flw_materialVertex() {
|
||||
}
|
Loading…
Reference in a new issue