diff --git a/src/main/java/org/teacon/slides/GifDecoder.java b/src/main/java/org/teacon/slides/GifDecoder.java deleted file mode 100644 index d3206a4..0000000 --- a/src/main/java/org/teacon/slides/GifDecoder.java +++ /dev/null @@ -1,721 +0,0 @@ -package org.teacon.slides; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; - -/** Class GifDecoder - Decodes a GIF file into one or more frames. - * - * Example: - * - *
- * { - * @code - * GifDecoder d = new GifDecoder(); - * d.read("sample.gif"); - * int n = d.getFrameCount(); - * for (int i = 0; i < n; i++) { - * BufferedImage frame = d.getFrame(i); // frame i - * int t = d.getDelay(i); // display duration of frame in milliseconds - * // do something with frame - * } - * } - *- * - * No copyright asserted on the source code of this class. May be used for - * any purpose, however, refer to the Unisys LZW patent for any additional - * restrictions. Please forward any corrections to questions at fmsware.com. - * - * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. - * @version 1.03 November 2003 */ - -public class GifDecoder { - - /** File read status: No errors. */ - public static final int STATUS_OK = 0; - - /** File read status: Error decoding file (may be partially decoded) */ - public static final int STATUS_FORMAT_ERROR = 1; - - /** File read status: Unable to open source. */ - public static final int STATUS_OPEN_ERROR = 2; - - protected BufferedInputStream in; - protected int status; - - protected int width; // full image width - protected int height; // full image height - protected boolean gctFlag; // global color table used - protected int gctSize; // size of global color table - protected int loopCount = 1; // iterations; 0 = repeat forever - - protected int[] gct; // global color table - protected int[] lct; // local color table - protected int[] act; // active color table - - protected int bgIndex; // background color index - protected int bgColor; // background color - protected int lastBgColor; // previous bg color - protected int pixelAspect; // pixel aspect ratio - - protected boolean lctFlag; // local color table flag - protected boolean interlace; // interlace flag - protected int lctSize; // local color table size - - protected int ix, iy, iw, ih; // current image rectangle - protected Rectangle lastRect; // last image rect - protected BufferedImage image; // current frame - protected BufferedImage lastImage; // previous frame - - protected byte[] block = new byte[256]; // current data block - protected int blockSize = 0; // block size - - // last graphic control extension info - protected int dispose = 0; - // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev - protected int lastDispose = 0; - protected boolean transparency = false; // use transparent color - protected int delay = 0; // delay in milliseconds - protected int transIndex; // transparent color index - - protected static final int MaxStackSize = 4096; - // max decoder pixel stack size - - // LZW decoder working arrays - protected short[] prefix; - protected byte[] suffix; - protected byte[] pixelStack; - protected byte[] pixels; - - protected ArrayList frames; // frames read from current file - protected int frameCount; - - static class GifFrame { - public GifFrame(BufferedImage im, int del) { - image = im; - delay = del; - } - - public BufferedImage image; - public int delay; - } - - /** Gets display duration for specified frame. - * - * @param n - * int index of frame - * @return delay in milliseconds */ - public int getDelay(int n) { - // - delay = -1; - if ((n >= 0) && (n < frameCount)) { - delay = ((GifFrame) frames.get(n)).delay; - } - return delay; - } - - /** Gets the number of frames read from file. - * - * @return frame count */ - public int getFrameCount() { - return frameCount; - } - - /** Gets the first (or only) image read. - * - * @return BufferedImage containing first frame, or null if none. */ - public BufferedImage getImage() { - return getFrame(0); - } - - /** Gets the "Netscape" iteration count, if any. - * A count of 0 means repeat indefinitiely. - * - * @return iteration count if one was specified, else 1. */ - public int getLoopCount() { - return loopCount; - } - - /** Creates new frame image from current data (and previous - * frames as specified by their disposition codes). */ - protected void setPixels() { - // expose destination image's pixels as int array - int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); - - // fill in starting image contents based on last image's dispose code - if (lastDispose > 0) { - if (lastDispose == 3) { - // use image before last - int n = frameCount - 2; - if (n > 0) { - lastImage = getFrame(n - 1); - } else { - lastImage = null; - } - } - - if (lastImage != null) { - int[] prev = ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); - System.arraycopy(prev, 0, dest, 0, width * height); - // copy pixels - - if (lastDispose == 2) { - // fill last image rect area with background color - Graphics2D g = image.createGraphics(); - Color c = null; - if (transparency) { - c = new Color(0, 0, 0, 0); // assume background is transparent - } else { - c = new Color(lastBgColor); // use given background color - } - g.setColor(c); - g.setComposite(AlphaComposite.Src); // replace area - g.fill(lastRect); - g.dispose(); - } - } - } - - // copy each source line to the appropriate place in the destination - int pass = 1; - int inc = 8; - int iline = 0; - for (int i = 0; i < ih; i++) { - int line = i; - if (interlace) { - if (iline >= ih) { - pass++; - switch (pass) { - case 2: - iline = 4; - break; - case 3: - iline = 2; - inc = 4; - break; - case 4: - iline = 1; - inc = 2; - } - } - line = iline; - iline += inc; - } - line += iy; - if (line < height) { - int k = line * width; - int dx = k + ix; // start of line in dest - int dlim = dx + iw; // end of dest line - if ((k + width) < dlim) { - dlim = k + width; // past dest edge - } - int sx = i * iw; // start of line in source - while (dx < dlim) { - // map color and insert in destination - int index = (pixels[sx++]) & 0xff; - int c = act[index]; - if (c != 0) { - dest[dx] = c; - } - dx++; - } - } - } - } - - /** Gets the image contents of frame n. - * - * @return BufferedImage representation of frame, or null if n is invalid. */ - public BufferedImage getFrame(int n) { - BufferedImage im = null; - if ((n >= 0) && (n < frameCount)) { - im = ((GifFrame) frames.get(n)).image; - } - return im; - } - - /** Gets image size. - * - * @return GIF image dimensions */ - public Dimension getFrameSize() { - return new Dimension(width, height); - } - - /** Reads GIF image from stream - * - * @param is - * BufferedInputStream containing GIF file. - * @return read status code (0 = no errors) */ - public int read(BufferedInputStream is) { - init(); - if (is != null) { - in = is; - readHeader(); - if (!err()) { - readContents(); - if (frameCount < 0) { - status = STATUS_FORMAT_ERROR; - } - } - } else { - status = STATUS_OPEN_ERROR; - } - try { - is.close(); - } catch (IOException e) { - } - return status; - } - - /** Reads GIF image from stream - * - * @param is - * InputStream containing GIF file. - * @return read status code (0 = no errors) */ - public int read(InputStream is) { - init(); - if (is != null) { - if (!(is instanceof BufferedInputStream)) - is = new BufferedInputStream(is); - in = (BufferedInputStream) is; - readHeader(); - if (!err()) { - readContents(); - if (frameCount < 0) { - status = STATUS_FORMAT_ERROR; - } - } - } else { - status = STATUS_OPEN_ERROR; - } - try { - is.close(); - } catch (IOException e) { - } - return status; - } - - /** Reads GIF file from specified file/URL source - * (URL assumed if name contains ":/" or "file:") - * - * @param name - * String containing source - * @return read status code (0 = no errors) */ - public int read(String name) { - status = STATUS_OK; - try { - name = name.trim().toLowerCase(); - if ((name.indexOf("file:") >= 0) || (name.indexOf(":/") > 0)) { - URL url = new URL(name); - in = new BufferedInputStream(url.openStream()); - } else { - in = new BufferedInputStream(new FileInputStream(name)); - } - status = read(in); - } catch (IOException e) { - status = STATUS_OPEN_ERROR; - } - - return status; - } - - /** Decodes LZW image data into pixel array. - * Adapted from John Cristy's ImageMagick. */ - protected void decodeImageData() { - int NullCode = -1; - int npix = iw * ih; - int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, - data_size, first, top, bi, pi; - - if ((pixels == null) || (pixels.length < npix)) { - pixels = new byte[npix]; // allocate new pixel array - } - if (prefix == null) - prefix = new short[MaxStackSize]; - if (suffix == null) - suffix = new byte[MaxStackSize]; - if (pixelStack == null) - pixelStack = new byte[MaxStackSize + 1]; - - // Initialize GIF data stream decoder. - - data_size = read(); - clear = 1 << data_size; - end_of_information = clear + 1; - available = clear + 2; - old_code = NullCode; - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - for (code = 0; code < clear; code++) { - prefix[code] = 0; - suffix[code] = (byte) code; - } - - // Decode GIF pixel stream. - - datum = bits = count = first = top = pi = bi = 0; - - for (i = 0; i < npix;) { - if (top == 0) { - if (bits < code_size) { - // Load bytes until there are enough bits for a code. - if (count == 0) { - // Read a new data block. - count = readBlock(); - if (count <= 0) - break; - bi = 0; - } - datum += ((block[bi]) & 0xff) << bits; - bits += 8; - bi++; - count--; - continue; - } - - // Get the next code. - - code = datum & code_mask; - datum >>= code_size; - bits -= code_size; - - // Interpret the code - - if ((code > available) || (code == end_of_information)) - break; - if (code == clear) { - // Reset decoder. - code_size = data_size + 1; - code_mask = (1 << code_size) - 1; - available = clear + 2; - old_code = NullCode; - continue; - } - if (old_code == NullCode) { - pixelStack[top++] = suffix[code]; - old_code = code; - first = code; - continue; - } - in_code = code; - if (code == available) { - pixelStack[top++] = (byte) first; - code = old_code; - } - while (code > clear) { - pixelStack[top++] = suffix[code]; - code = prefix[code]; - } - first = (suffix[code]) & 0xff; - - // Add a new string to the string table, - - if (available >= MaxStackSize) { - pixelStack[top++] = (byte) first; - continue; - } - pixelStack[top++] = (byte) first; - prefix[available] = (short) old_code; - suffix[available] = (byte) first; - available++; - if (((available & code_mask) == 0) && (available < MaxStackSize)) { - code_size++; - code_mask += available; - } - old_code = in_code; - } - - // Pop a pixel off the pixel stack. - - top--; - pixels[pi++] = pixelStack[top]; - i++; - } - - for (i = pi; i < npix; i++) { - pixels[i] = 0; // clear missing pixels - } - - } - - /** Returns true if an error was encountered during reading/decoding */ - protected boolean err() { - return status != STATUS_OK; - } - - /** Initializes or re-initializes reader */ - protected void init() { - status = STATUS_OK; - frameCount = 0; - frames = new ArrayList(); - gct = null; - lct = null; - } - - /** Reads a single byte from the input stream. */ - protected int read() { - int curByte = 0; - try { - curByte = in.read(); - } catch (IOException e) { - status = STATUS_FORMAT_ERROR; - } - return curByte; - } - - /** Reads next variable length block from input. - * - * @return number of bytes stored in "buffer" */ - protected int readBlock() { - blockSize = read(); - int n = 0; - if (blockSize > 0) { - try { - int count = 0; - while (n < blockSize) { - count = in.read(block, n, blockSize - n); - if (count == -1) - break; - n += count; - } - } catch (IOException e) { - } - - if (n < blockSize) { - status = STATUS_FORMAT_ERROR; - } - } - return n; - } - - /** Reads color table as 256 RGB integer values - * - * @param ncolors - * int number of colors to read - * @return int array containing 256 colors (packed ARGB with full alpha) */ - protected int[] readColorTable(int ncolors) { - int nbytes = 3 * ncolors; - int[] tab = null; - byte[] c = new byte[nbytes]; - int n = 0; - try { - n = in.read(c); - } catch (IOException e) { - } - if (n < nbytes) { - status = STATUS_FORMAT_ERROR; - } else { - tab = new int[256]; // max size to avoid bounds checks - int i = 0; - int j = 0; - while (i < ncolors) { - int r = (c[j++]) & 0xff; - int g = (c[j++]) & 0xff; - int b = (c[j++]) & 0xff; - tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; - } - } - return tab; - } - - /** Main file parser. Reads GIF content blocks. */ - protected void readContents() { - // read GIF file content blocks - boolean done = false; - while (!(done || err())) { - int code = read(); - switch (code) { - - case 0x2C: // image separator - readImage(); - break; - - case 0x21: // extension - code = read(); - switch (code) { - case 0xf9: // graphics control extension - readGraphicControlExt(); - break; - - case 0xff: // application extension - readBlock(); - String app = ""; - for (int i = 0; i < 11; i++) { - app += (char) block[i]; - } - if (app.equals("NETSCAPE2.0")) { - readNetscapeExt(); - } else - skip(); // don't care - break; - - default: // uninteresting extension - skip(); - } - break; - - case 0x3b: // terminator - done = true; - break; - - case 0x00: // bad byte, but keep going and see what happens - break; - - default: - status = STATUS_FORMAT_ERROR; - } - } - } - - /** Reads Graphics Control Extension values */ - protected void readGraphicControlExt() { - read(); // block size - int packed = read(); // packed fields - dispose = (packed & 0x1c) >> 2; // disposal method - if (dispose == 0) { - dispose = 1; // elect to keep old image if discretionary - } - transparency = (packed & 1) != 0; - delay = readShort() * 10; // delay in milliseconds - transIndex = read(); // transparent color index - read(); // block terminator - } - - /** Reads GIF file header information. */ - protected void readHeader() { - String id = ""; - for (int i = 0; i < 6; i++) { - id += (char) read(); - } - if (!id.startsWith("GIF")) { - status = STATUS_FORMAT_ERROR; - return; - } - - readLSD(); - if (gctFlag && !err()) { - gct = readColorTable(gctSize); - bgColor = gct[bgIndex]; - } - } - - /** Reads next frame image */ - protected void readImage() { - ix = readShort(); // (sub)image position & size - iy = readShort(); - iw = readShort(); - ih = readShort(); - - int packed = read(); - lctFlag = (packed & 0x80) != 0; // 1 - local color table flag - interlace = (packed & 0x40) != 0; // 2 - interlace flag - // 3 - sort flag - // 4-5 - reserved - lctSize = 2 << (packed & 7); // 6-8 - local color table size - - if (lctFlag) { - lct = readColorTable(lctSize); // read table - act = lct; // make local table active - } else { - act = gct; // make global table active - if (bgIndex == transIndex) - bgColor = 0; - } - int save = 0; - if (transparency) { - save = act[transIndex]; - act[transIndex] = 0; // set transparent color if specified - } - - if (act == null) { - status = STATUS_FORMAT_ERROR; // no color table defined - } - - if (err()) - return; - - decodeImageData(); // decode pixel data - skip(); - - if (err()) - return; - - frameCount++; - - // create new image to receive frame data - image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); - - setPixels(); // transfer pixel data to image - - frames.add(new GifFrame(image, delay)); // add image to frame list - - if (transparency) { - act[transIndex] = save; - } - resetFrame(); - - } - - /** Reads Logical Screen Descriptor */ - protected void readLSD() { - - // logical screen size - width = readShort(); - height = readShort(); - - // packed fields - int packed = read(); - gctFlag = (packed & 0x80) != 0; // 1 : global color table flag - // 2-4 : color resolution - // 5 : gct sort flag - gctSize = 2 << (packed & 7); // 6-8 : gct size - - bgIndex = read(); // background color index - pixelAspect = read(); // pixel aspect ratio - } - - /** Reads Netscape extenstion to obtain iteration count */ - protected void readNetscapeExt() { - do { - readBlock(); - if (block[0] == 1) { - // loop count sub-block - int b1 = (block[1]) & 0xff; - int b2 = (block[2]) & 0xff; - loopCount = (b2 << 8) | b1; - } - } while ((blockSize > 0) && !err()); - } - - /** Reads next 16-bit value, LSB first */ - protected int readShort() { - // read 16-bit value, LSB first - return read() | (read() << 8); - } - - /** Resets frame state for reading next image. */ - protected void resetFrame() { - lastDispose = dispose; - lastRect = new Rectangle(ix, iy, iw, ih); - lastImage = image; - lastBgColor = bgColor; - int dispose = 0; - boolean transparency = false; - int delay = 0; - lct = null; - } - - /** Skips variable length blocks up to and including - * next zero length block. */ - protected void skip() { - do { - readBlock(); - } while ((blockSize > 0) && !err()); - } -} diff --git a/src/main/java/org/teacon/slides/projector/ProjectorBlock.java b/src/main/java/org/teacon/slides/projector/ProjectorBlock.java index 6089ba9..3d8a604 100644 --- a/src/main/java/org/teacon/slides/projector/ProjectorBlock.java +++ b/src/main/java/org/teacon/slides/projector/ProjectorBlock.java @@ -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; @@ -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; @@ -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 diff --git a/src/main/java/org/teacon/slides/projector/ProjectorBlockEntity.java b/src/main/java/org/teacon/slides/projector/ProjectorBlockEntity.java index b7e82f1..99827c5 100644 --- a/src/main/java/org/teacon/slides/projector/ProjectorBlockEntity.java +++ b/src/main/java/org/teacon/slides/projector/ProjectorBlockEntity.java @@ -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; @@ -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; @@ -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)); + } } diff --git a/src/main/java/org/teacon/slides/renderer/ProjectorRenderer.java b/src/main/java/org/teacon/slides/renderer/ProjectorRenderer.java index 2247af4..2f5aa25 100644 --- a/src/main/java/org/teacon/slides/renderer/ProjectorRenderer.java +++ b/src/main/java/org/teacon/slides/renderer/ProjectorRenderer.java @@ -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; @@ -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) { @@ -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); @@ -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(); + } } diff --git a/src/main/java/org/teacon/slides/renderer/SlideState.java b/src/main/java/org/teacon/slides/renderer/SlideState.java index 2f277d0..a17fc17 100644 --- a/src/main/java/org/teacon/slides/renderer/SlideState.java +++ b/src/main/java/org/teacon/slides/renderer/SlideState.java @@ -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; @@ -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; @@ -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; @@ -206,29 +201,9 @@ public String toString() { private static CompletableFuture