Skip to content

Commit

Permalink
GIF rework + render bounding box (#15)
Browse files Browse the repository at this point in the history
* Gif support + rework frame texture
* Drop onlyin markers
* Stop client animation when the game is paused
* Update .gitignore
* gif limited + boundingBox
* Update GifTexture.java
* clean up
* clean up
* use previous parms
* use STB for gif + maintain mem
* clean up
* Add a method for transforming to slide space

Co-authored-by: Yanbing Zhao <[email protected]>
  • Loading branch information
Yefancy and ustc-zzzz authored Jul 24, 2022
1 parent be7bb30 commit 9000b4d
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 871 deletions.
721 changes: 0 additions & 721 deletions src/main/java/org/teacon/slides/GifDecoder.java

This file was deleted.

19 changes: 9 additions & 10 deletions src/main/java/org/teacon/slides/projector/ProjectorBlock.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.teacon.slides.projector;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.*;
import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector4f;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.StringRepresentable;
Expand All @@ -23,11 +24,8 @@
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Arrays;
import java.util.Locale;
Expand Down Expand Up @@ -205,11 +203,12 @@ public void transform(Vector4f vector) {
vector.transform(mMatrix);
}

@OnlyIn(Dist.CLIENT)
public void transform(PoseStack pStack) {
PoseStack.Pose last = pStack.last();
last.pose().multiply(mMatrix);
last.normal().mul(mNormal);
public void transform(Matrix4f poseMatrix) {
poseMatrix.multiply(mMatrix);
}

public void transform(Matrix3f normalMatrix) {
normalMatrix.mul(mNormal);
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package org.teacon.slides.projector;

import com.mojang.math.Matrix3f;
import com.mojang.math.Matrix4f;
import com.mojang.math.Vector3f;
import com.mojang.math.Vector4f;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
Expand All @@ -13,6 +18,8 @@
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import net.minecraftforge.network.NetworkHooks;
import org.teacon.slides.Registries;
import org.teacon.slides.renderer.ProjectorWorldRender;
Expand Down Expand Up @@ -140,4 +147,45 @@ public CompoundTag getUpdateTag() {
public void handleUpdateTag(CompoundTag tag) {
load(tag);
}

@Override
public AABB getRenderBoundingBox() {
Matrix3f normal = Matrix3f.createScaleMatrix(1, 1, 1); // identity
Matrix4f pose = Matrix4f.createScaleMatrix(1, 1, 1); // identity
this.transformToSlideSpace(pose, normal);

Vector3f nHalf = new Vector3f(0, 0.5f, 0);
Vector4f v00 = new Vector4f(0, 0, 0, 1);
Vector4f v01 = new Vector4f(1, 0, 1, 1);
nHalf.transform(normal);
v00.transform(pose);
v01.transform(pose);

AABB base = new AABB(v00.x(), v00.y(), v00.z(), v01.x(), v01.y(), v01.z());
return base.move(this.getBlockPos()).inflate(nHalf.x(), nHalf.y(), nHalf.z());
}

public void transformToSlideSpace(Matrix4f pose, Matrix3f normal) {
BlockState state = getBlockState();
// get direction
Direction direction = state.getValue(BlockStateProperties.FACING);
// get internal rotation
ProjectorBlock.InternalRotation rotation = state.getValue(ProjectorBlock.ROTATION);
// matrix 1: translation to block center
pose.multiplyWithTranslation(0.5f, 0.5f, 0.5f);
// matrix 2: rotation
pose.multiply(direction.getRotation());
normal.mul(direction.getRotation());
// matrix 3: translation to block surface
pose.multiplyWithTranslation(0.0f, 0.5f, 0.0f);
// matrix 4: internal rotation
rotation.transform(pose);
rotation.transform(normal);
// matrix 5: translation for slide
pose.multiplyWithTranslation(-0.5F, 0.0F, 0.5F - mHeight);
// matrix 6: offset for slide
pose.multiplyWithTranslation(mOffsetX, -mOffsetZ, mOffsetY);
// matrix 7: scaling
pose.multiply(Matrix4f.createScaleMatrix(mWidth, 1.0F, mHeight));
}
}
98 changes: 75 additions & 23 deletions src/main/java/org/teacon/slides/renderer/ProjectorRenderer.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package org.teacon.slides.renderer;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Matrix4f;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.AABB;
import org.teacon.slides.projector.ProjectorBlock;
import org.teacon.slides.projector.ProjectorBlockEntity;

Expand All @@ -30,6 +34,10 @@ public ProjectorRenderer onCreate(@SuppressWarnings("unused") @Nonnull BlockEnti
@Override
public void render(ProjectorBlockEntity tile, float partialTick, PoseStack pStack,
MultiBufferSource source, int packedLight, int packedOverlay) {

// render bounding box for DEBUG
// renderBoundingBox(pStack, tile);

// always update slide state
final Slide slide = SlideState.getSlide(tile.mLocation);
if (slide == null) {
Expand All @@ -40,32 +48,15 @@ public void render(ProjectorBlockEntity tile, float partialTick, PoseStack pStac
if ((color & 0xFF000000) == 0) {
return;
}
ProjectorBlock.InternalRotation rotation = tile.getBlockState().getValue(ProjectorBlock.ROTATION);
final boolean flipped = rotation.isFlipped();

pStack.pushPose();

final float width = tile.mWidth, height = tile.mHeight;

Direction facing = tile.getBlockState().getValue(BlockStateProperties.FACING);
// matrix 1: translation to block center
pStack.translate(0.5, 0.5, 0.5);
// matrix 2: rotation
pStack.mulPose(facing.getRotation());
// matrix 3: translation to block surface
pStack.translate(0.0, 0.5, 0.0);
// matrix 4: internal rotation
rotation.transform(pStack);
// matrix 5: translation for slide
pStack.translate(-0.5F, 0.0F, 0.5F - height);
// matrix 6: offset for slide
pStack.translate(tile.mOffsetX, -tile.mOffsetZ, tile.mOffsetY);
// matrix 7: scaling
pStack.scale(width, 1.0F, height);

PoseStack.Pose last = pStack.last();
tile.transformToSlideSpace(last.pose(), last.normal());

final boolean flipped = tile.getBlockState().getValue(ProjectorBlock.ROTATION).isFlipped();

slide.render(source, last.pose(), last.normal(), width, height, color, LightTexture.FULL_BRIGHT,
slide.render(source, last.pose(), last.normal(), tile.mWidth, tile.mHeight, color, LightTexture.FULL_BRIGHT,
OverlayTexture.NO_OVERLAY, flipped || tile.mDoubleSided, !flipped || tile.mDoubleSided,
SlideState.getAnimationTick(), partialTick);

Expand All @@ -83,4 +74,65 @@ public boolean shouldRenderOffScreen(ProjectorBlockEntity tile) {
public int getViewDistance() {
return 256;
}

public static void renderBoundingBox(PoseStack matrixStack, ProjectorBlockEntity tile) {
AABB box = tile.getRenderBoundingBox();
BlockPos pos = tile.getBlockPos();
Tesselator tessellator = Tesselator.getInstance();
BufferBuilder buffer = tessellator.getBuilder();
RenderSystem.setShader(GameRenderer::getPositionColorShader);
buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR);
RenderSystem.depthMask(false);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
matrixStack.pushPose();

matrixStack.translate(-pos.getX(), -pos.getY(), -pos.getZ());

float minX = (float) box.minX;
float minY = (float) box.minY;
float minZ = (float) box.minZ;
float maxX = (float) box.maxX;
float maxY = (float) box.maxY;
float maxZ = (float) box.maxZ;

Matrix4f mat = matrixStack.last().pose();
float b = 1;
buffer.vertex(mat, minX, minY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();

buffer.vertex(mat, maxX, minY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();

b = 0.5f;
buffer.vertex(mat, minX, minY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, minY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();

b = 1;
buffer.vertex(mat, minX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();

b = 0.8f;
buffer.vertex(mat, minX, minY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, minZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, minY, minZ).color(0, 0, b, 0.5f).endVertex();

buffer.vertex(mat, minX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, minY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, maxX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();
buffer.vertex(mat, minX, maxY, maxZ).color(0, 0, b, 0.5f).endVertex();

tessellator.end();
RenderSystem.depthMask(true);
matrixStack.popPose();
}
}
31 changes: 3 additions & 28 deletions src/main/java/org/teacon/slides/renderer/SlideState.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.teacon.slides.renderer;

import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
Expand All @@ -13,8 +12,6 @@
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL46C;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryUtil;
import org.teacon.slides.GifDecoder;
import org.teacon.slides.SlideShow;
import org.teacon.slides.cache.ImageCache;
import org.teacon.slides.texture.FrameTexture;
Expand All @@ -28,10 +25,8 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -206,29 +201,9 @@ public String toString() {
private static CompletableFuture<FrameTexture> createTexture(byte[] data) {
return CompletableFuture.supplyAsync(() -> {
if (isGif(data)) {
try (ByteArrayInputStream stream = new ByteArrayInputStream(data)) {
GifDecoder gif = new GifDecoder();
int status = gif.read(stream);
if (status == GifDecoder.STATUS_OK) {
return new GifTexture(gif, sMaxAnisotropic);
} else {
SlideShow.LOGGER.error("Failed to decode gif: {}", status);
}
} catch (IOException exception) {
SlideShow.LOGGER.error("Failed to read gif", exception);
}
}
// copy to native memory
ByteBuffer buffer = MemoryUtil.memAlloc(data.length)
.put(data)
.rewind();
// specify null to use image intrinsic format
try (NativeImage image = NativeImage.read(null, buffer)) {
return new NativeImageTexture(image, sMaxAnisotropic);
} catch (Throwable t) {
throw new CompletionException(t);
} finally {
MemoryUtil.memFree(buffer);
return new GifTexture(data, sMaxAnisotropic);
} else {
return new NativeImageTexture(data, sMaxAnisotropic);
}
}, RENDER_EXECUTOR);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/teacon/slides/texture/FrameTexture.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.teacon.slides.texture;

public sealed interface FrameTexture permits NativeImageTexture, GifTexture {
public sealed interface FrameTexture permits GifTexture, NativeImageTexture {

int currentTextureID(long tick, float partialTick);

Expand Down
Loading

0 comments on commit 9000b4d

Please sign in to comment.