Skip to content

Commit

Permalink
feat: attach sonar drawing to the mod
Browse files Browse the repository at this point in the history
  • Loading branch information
mzdun committed Oct 6, 2024
1 parent 919de95 commit ce72ea5
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,47 @@

import com.midnightbits.scanner.sonar.Sonar;
import com.midnightbits.scanner.sonar.graphics.AbstractAnimatorHost;
import com.midnightbits.scanner.sonar.graphics.GraphicContext;
import com.midnightbits.scanner.sonar.graphics.Shimmers;
import com.midnightbits.scanner.utils.Clock;

import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;

import java.util.ArrayList;
import java.util.List;

public class FabricAnimationHost extends AbstractAnimatorHost {
public static final FabricAnimationHost INSTANCE = new FabricAnimationHost();
private Sonar source;

public void initialize(Sonar source) {
this.source = source;
ClientTickEvents.START_WORLD_TICK.register((client) -> {
ClientTickEvents.END_CLIENT_TICK.register((client) -> {
this.tick(Clock.currentTimeMillis());
});
WorldRenderEvents.LAST.register(this::renderLevel);
}

@Override
public void tick(long now) {
super.tick(now);
this.source.removeOldEchoes();
}

private static final class GatherShimmers implements GraphicContext {
List<Shimmers> cloud = new ArrayList<>();

@Override
public void drawScan(List<Shimmers> shimmers) {
this.cloud.addAll(shimmers);
}
};

private void renderLevel(WorldRenderContext context) {
final var shimmers = new GatherShimmers();
this.run(shimmers);
Pixel.renderLevel(context, source.echoes(), shimmers.cloud);
}
}
54 changes: 54 additions & 0 deletions fabric/any/src/main/java/com/midnightbits/scanner/fabric/Mesh.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.midnightbits.scanner.fabric;

import com.midnightbits.scanner.rt.math.V3i;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

class Mesh {
public static void cleanPixels(Collection<Pixel> pixels) {
final Map<V3i, Pixel> vertices = new HashMap<>();

for (final var pixel : pixels) {
final var control = vertices.get(pixel.position());
if (control != null && control != pixel) {
pixel.sides = 0;
return;
}

vertices.put(pixel.position(), pixel);
}

final var positions = Set.copyOf(vertices.keySet());
for (final var pos: positions) {
final var pixel = vertices.get(pos);
if (pixel == null) { continue; }

final var x0 = vertices.get(pixel.position().add(-1, 0, 0));
final var x1 = vertices.get(pixel.position().add(1, 0, 0));
final var y0 = vertices.get(pixel.position().add(0, -1, 0));
final var y1 = vertices.get(pixel.position().add(0, 1, 0));
final var z0 = vertices.get(pixel.position().add(0, 0, -1));
final var z1 = vertices.get(pixel.position().add(0, 0, 1));

cleanSide(pixel, x0, Pixel.SIDE_X0, Pixel.SIDE_X1);
cleanSide(pixel, x1, Pixel.SIDE_X1, Pixel.SIDE_X0);
cleanSide(pixel, y0, Pixel.SIDE_Y0, Pixel.SIDE_Y1);
cleanSide(pixel, y1, Pixel.SIDE_Y1, Pixel.SIDE_Y0);
cleanSide(pixel, z0, Pixel.SIDE_Z0, Pixel.SIDE_Z1);
cleanSide(pixel, z1, Pixel.SIDE_Z1, Pixel.SIDE_Z0);

vertices.remove(pos);
}
}

private static void cleanSide(Pixel pixel, Pixel neighbour, int mySide, int theirSide) {
if (neighbour == null || neighbour.argb != pixel.argb) {
return;
}
pixel.sides &= ~mySide;
neighbour.sides &= ~theirSide;
}
}
164 changes: 164 additions & 0 deletions fabric/any/src/main/java/com/midnightbits/scanner/fabric/Pixel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.midnightbits.scanner.fabric;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.joml.Matrix4f;

import com.midnightbits.scanner.rt.math.V3i;
import com.midnightbits.scanner.sonar.BlockEcho;
import com.midnightbits.scanner.sonar.graphics.Shimmers;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;

import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.client.render.BufferBuilder;
import net.minecraft.client.render.BufferRenderer;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexFormat;
import net.minecraft.client.render.VertexFormats;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.ColorHelper;

public class Pixel {
private record Vertex(int dx, int dy, int dz) {
void apply(BufferBuilder buffer, Matrix4f matrix, int argb) {
buffer.vertex(matrix, dx, dy, dz).color(argb);
}
}

private static final Vertex v000 = new Vertex(0, 0, 0);
private static final Vertex v001 = new Vertex(0, 0, 1);
private static final Vertex v010 = new Vertex(0, 1, 0);
private static final Vertex v011 = new Vertex(0, 1, 1);
private static final Vertex v100 = new Vertex(1, 0, 0);
private static final Vertex v101 = new Vertex(1, 0, 1);
private static final Vertex v110 = new Vertex(1, 1, 0);
private static final Vertex v111 = new Vertex(1, 1, 1);

private static final Vertex[][] triangles = new Vertex[][] {
new Vertex[] { v000, v100, v010, v100, v110, v010 },
new Vertex[] { v001, v101, v000, v101, v100, v000 },
new Vertex[] { v011, v111, v001, v111, v101, v001 },
new Vertex[] { v010, v110, v011, v110, v111, v011 },
new Vertex[] { v001, v000, v011, v000, v010, v011 },
new Vertex[] { v100, v101, v110, v101, v111, v110 },
};

final static int SIDE_X0 = 1 << 4;
final static int SIDE_X1 = 1 << 5;
final static int SIDE_Y0 = 1 << 1;
final static int SIDE_Y1 = 1 << 3;
final static int SIDE_Z0 = 1;
final static int SIDE_Z1 = 1 << 2;
final static int ALL_SIDES = SIDE_X0 | SIDE_X1 | SIDE_Y0 | SIDE_Y1 | SIDE_Z0 | SIDE_Z1;

final V3i position;
final int argb;
int sides = ALL_SIDES;

Pixel(V3i position, int argb) {
this.position = position;
this.argb = argb;
}

public V3i position() {
return position;
}

static Pixel of(BlockEcho echo) {
final var pos = echo.position();
return new Pixel(pos, 0x40000000);
}

void draw(BufferBuilder buffer, MatrixStack stack, Camera camera) {
final var cam = camera.getPos();
final var x = position.getX() - cam.x;
final var y = position.getY() - cam.y;
final var z = position.getZ() - cam.z;
stack.push();
stack.translate(x, y, z);
final var m = stack.peek().getPositionMatrix();

for (var side = 0; side < triangles.length; ++side) {
final var flag = 1 << side;
if ((sides & flag) == 0) {
continue;
}

final var wall = triangles[side];
for (final var vertex : wall) {
vertex.apply(buffer, m, argb);
}
}

stack.pop();
}

public static void renderLevel(WorldRenderContext context, Iterable<BlockEcho> echoes, List<Shimmers> shimmers) {
final var frustum = context.frustum();
assert frustum != null;

final var allPixels = StreamSupport
.stream(echoes.spliterator(), false)
.map(Pixel::of)
.collect(Collectors.toSet());

for (final var shimmer : shimmers) {
final var alpha = (int) (shimmer.alpha() * 255.0 / 8.0 + .5);
int argbWalls = ColorHelper.Argb.withAlpha(alpha, 0x8080FF);

for (final var pos : shimmer.blocks()) {
allPixels.add(new Pixel(pos, argbWalls));
}
}

Mesh.cleanPixels(allPixels);

final var visiblePixels = allPixels
.stream()
.filter((pixel) -> {
if ((pixel.sides & Pixel.ALL_SIDES) == 0) {
return false;
}
final var pos = pixel.position();
final var box = new Box(pos.getX(), pos.getY(), pos.getZ(), (pos.getX() + 1), (pos.getY() + 1),
(pos.getZ() + 1));
return frustum.isVisible(box);
})
.collect(Collectors.toSet());

if (visiblePixels.isEmpty() && shimmers.isEmpty()) {
return;
}

final var camera = context.camera();
final var stack = context.matrixStack();
assert stack != null;

RenderSystem.disableDepthTest();
RenderSystem.enableBlend();
RenderSystem.blendFunc(
GlStateManager.SrcFactor.SRC_ALPHA,
GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
RenderSystem.setShader(GameRenderer::getPositionColorProgram);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);

final var tessellator = Tessellator.getInstance();
final var buffer = tessellator.begin(VertexFormat.DrawMode.TRIANGLES, VertexFormats.POSITION_COLOR);

for (final var pixel : visiblePixels) {
pixel.draw(buffer, stack, camera);
}

final var end = buffer.endNullable();
if (end != null)
BufferRenderer.drawWithGlobalProgram(end);

RenderSystem.enableDepthTest();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import java.util.function.Predicate;

public class SlicePacer implements Sonar.SlicePacer {
public static final long DURATION = 100;
public static final long DURATION = 10;

private static class Scan {
final Predicate<Long> callback;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

public class WaveAnimator implements ScanWaveConsumer {
private static final TimeFunction TIME = TimeFunction.LINEAR;
private static final long DURATION = 300;
private static final long DURATION = 3 * SlicePacer.DURATION;
private static final double TRANSPARENT = 0.0;
private static final double OPAQUE = 1.0;

Expand Down

0 comments on commit ce72ea5

Please sign in to comment.