diff --git a/build.gradle.kts b/build.gradle.kts index 17338254..2cc74a28 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -51,6 +51,7 @@ allprojects { afterEvaluate { if (plugins.hasPlugin("com.gtnewhorizons.retrofuturagradle")) return@afterEvaluate + if (plugins.hasPlugin("fabric-loom")) return@afterEvaluate val rfgObfAttr = Attribute.of("com.gtnewhorizons.retrofuturagradle.obfuscation", String::class.java) val rfgDeobfAttr = Attribute.of("rfgDeobfuscatorTransformed", Boolean::class.javaObjectType) diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index de056218..7487575c 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -6,6 +6,7 @@ import com.coloryr.allmusic.client.core.render.PictureFrameBuffer; import com.coloryr.allmusic.client.core.render.TextFrameBuffer; import com.coloryr.allmusic.client.core.render.TextureRender; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.loader.api.FabricLoader; @@ -30,6 +31,14 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { public static final Logger LOGGER = LogManager.getLogger("AllMusic Client"); + /** 当前帧的 PoseStack,由 GuiShow mixin 注入 */ + public static PoseStack context; + + /** 由 HUD 渲染 mixin 调用,缓存当前帧的 PoseStack */ + public static void update(PoseStack matrices) { + context = matrices; + } + public int getScreenWidth() { return Minecraft.getInstance().getWindow().getGuiScaledWidth(); } @@ -69,7 +78,7 @@ public class AllMusicClient implements ClientModInitializer, AllMusicBridge { @Override public TextFrameBuffer makeTextRender(String name) { - return new CoreRenderTarget(); + return new CoreRenderTarget(name); } @Override diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java index ff97da04..75a27682 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java @@ -4,322 +4,198 @@ import com.coloryr.allmusic.client.core.AllMusicHud; import com.coloryr.allmusic.client.core.Point2f; import com.coloryr.allmusic.client.core.render.TextFrameBuffer; import com.coloryr.allmusic.codec.HudPosType; -import com.mojang.blaze3d.pipeline.RenderTarget; import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.*; -import com.mojang.math.Matrix4f; +import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; -import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.network.chat.Component; import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL30; + +import java.util.ArrayList; +import java.util.List; public class CoreRenderTarget extends TextFrameBuffer { - private static final RenderBuffers renderBuffers = new RenderBuffers(); + private static class TextEntry { + final Component component; + final int y; + final int color; + final boolean shadow; + final int width; + final int height; - private final RenderTarget target; + TextEntry(Component component, int y, int color, boolean shadow, int width, int height) { + this.component = component; + this.y = y; + this.color = color; + this.shadow = shadow; + this.width = width; + this.height = height; + } + } - public CoreRenderTarget() { - target = new RenderTarget(800, 200, false, false); - target.setClearColor(0.0f, 0.0f, 0.0f, 0.0f); + private final List entries = new ArrayList<>(); + private final boolean isState; + + public CoreRenderTarget(String name) { + isState = name.equals("state"); } @Override public void resize(int width, int height) { - Window window = Minecraft.getInstance().getWindow(); - - nowWidth = (int) (width * window.getGuiScale()); - nowHeight = (int) (height * window.getGuiScale()); - - if (nowWidth > target.width || nowHeight > target.height) { - target.resize(nowWidth, nowHeight, false); - } + nowWidth = width; + nowHeight = height; } @Override public void use() { isDraw = true; - clear(); - target.clear(false); - target.bindWrite(true); - - Window window = Minecraft.getInstance().getWindow(); - - RenderSystem.ortho(0.0F, (float) (target.width / window.getGuiScale()), - (float) (target.height / window.getGuiScale()), 0.0F, 1000.0F, 21000.0F); + entries.clear(); } @Override public void unUse() { isDraw = false; - - Window window = Minecraft.getInstance().getWindow(); - - RenderSystem.ortho(0.0F, (double) window.getWidth() / window.getGuiScale(), (double) window.getHeight() / window.getGuiScale(), 0.0F, 1000.0F, 3000.0F); - - RenderTarget main = Minecraft.getInstance().getMainRenderTarget(); - main.bindWrite(true); } @Override public void drawText(String text, int y, int color, boolean shadow) { - Window window = Minecraft.getInstance().getWindow(); - - Font font = Minecraft.getInstance().font; + color = (color & 0x00FFFFFF) | 0xFF000000; Component component = MiniMessage.parse(text); - - if (font.width(component) == 0) { + Font font = Minecraft.getInstance().font; + int width = font.width(component); + if (width == 0) { return; } - int width; - - if (shadow) { - width = font.drawShadow(new PoseStack(), component, 0, 0, color); - } else { - width = font.draw(new PoseStack(), component, 0, 0, color); + int height = font.lineHeight + (shadow ? 1 : 0); + if (isState) { + y = 0; } - - RenderSystem.disableDepthTest(); - renderBuffers.bufferSource().endBatch(); - RenderSystem.enableDepthTest(); - - TextItem item = new TextItem(width, font.lineHeight + (shadow ? 1 : 0), y, (float) window.getGuiScale()); - texts.add(item); - } - - /** - * 渲染贴图的一部分到屏幕指定位置 - * - * @param alpha 透明度 - * @param x 屏幕X坐标(左上角) - * @param y 屏幕Y坐标(左上角) - * @param width 需要渲染的宽度 - * @param height 需要渲染的高度 - * @param texX 贴图左上角X坐标 - * @param texY 贴图左上角Y坐标 - * @param scale 贴图缩放 - */ - private void draw(float alpha, float x, float y, float width, float height, float texX, float texY, float scale) { - RenderSystem.bindTexture(target.getColorTextureId()); - RenderSystem.enableTexture(); - RenderSystem.depthMask(false); - RenderSystem.enableBlend(); - RenderSystem.depthFunc(GL30.GL_ALWAYS); - - float w = (width / 2); - float h = (height / 2); - - Matrix4f matrix = Matrix4f.createTranslateMatrix(x + w, y + h, 0); - - float x0 = -w; - float x1 = w; - float y0 = -h; - float y1 = h; - float z = 0; - - // 计算贴图区域UV - float u0 = texX * scale / target.width; - float v0 = 1 - (texY * scale / target.height); - float u1 = (texX + width) * scale / target.width; - float v1 = 1 - ((texY + height) * scale / target.height); - - BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); - bufferBuilder.vertex(matrix, x0, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v1).endVertex(); - bufferBuilder.vertex(matrix, x1, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v1).endVertex(); - bufferBuilder.vertex(matrix, x1, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v0).endVertex(); - bufferBuilder.vertex(matrix, x0, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v0).endVertex(); - bufferBuilder.end(); - BufferUploader.end(bufferBuilder); - - RenderSystem.disableBlend(); - RenderSystem.depthMask(true); - - target.unbindRead(); - } - - public void drawLoop(float alpha, float x, float y, - float texX, float texY, - float textWidth, float textHeight, - int maxWidth, float offsetX, float scale) { - - // 如果宽度不大于最大宽度,直接全部渲染 - if (maxWidth == -1 || textWidth <= maxWidth) { - draw(alpha, x, y, textWidth, textHeight, texX, texY, scale); - return; - } - - if (textWidth - offsetX < maxWidth) { - float nowWith = textWidth - offsetX; - draw(alpha, x, y, nowWith, textHeight, offsetX, texY, scale); - draw(alpha, x + nowWith, y, maxWidth - nowWith, textHeight, 0, texY, scale); - } else { - draw(alpha, x, y, maxWidth, textHeight, offsetX, texY, scale); - } - } - - /** - * 居中百分比显示(根据百分比选择显示贴图的中间部分) - * - * @param alpha 透明度 - * @param startX 起始X坐标(屏幕左上角) - * @param startY 起始Y坐标(屏幕左上角) - * @param texX 贴图左上角X - * @param texY 贴图左上角Y - * @param texWidth 贴图总宽度 - * @param texHeight 贴图高度 - * @param maxWidth 最大渲染宽度 - * @param percent 百分比(0.0-1.0),0%显示左边,100%显示右边 - */ - public void drawByPercent(float alpha, float startX, float startY, - float texX, float texY, - float texWidth, float texHeight, - int maxWidth, float percent, float scale) { - - // 限制百分比范围 - percent = Math.min(1.0f, Math.max(0.0f, percent)); - - // 如果贴图宽度小于等于最大宽度,直接全部显示 - if (texWidth <= maxWidth) { - draw(alpha, startX, startY, (int) (texWidth * percent), texHeight, texX, texY, scale); - return; - } - - // 计算贴图的起始位置(根据百分比) - float maxOffset = texWidth - maxWidth; - int texOffset = (int) (maxOffset * percent); - - // 渲染 - draw(alpha, startX, startY, maxWidth, texHeight, texX + texOffset, texY, scale); - } - - /** - * 正向百分比显示(从左开始显示,右边空白) - * - * @param alpha 透明度 - * @param startX 起始X坐标(屏幕左上角) - * @param startY 起始Y坐标(屏幕左上角) - * @param texX 贴图左上角X - * @param texY 贴图左上角Y - * @param texWidth 贴图总宽度 - * @param texHeight 贴图高度 - * @param maxWidth 最大渲染宽度 - * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示前面40%的内容 - */ - public void drawByForwardPercent(float alpha, int startX, int startY, - int texX, int texY, - int texWidth, int texHeight, - int maxWidth, float percent, float scale) { - - // 限制百分比范围 - percent = Math.min(1.0f, Math.max(0.0f, percent)); - - // 如果要显示的内容为0,直接返回 - if (percent <= 0) { - return; - } - - // 计算要显示的内容宽度 - int contentWidth = (int) (texWidth * percent); - - // 实际渲染宽度 - int renderWidth = Math.min(contentWidth, maxWidth); - - // 屏幕偏移为0(靠左显示) - int screenOffset = 0; - - // 贴图偏移为0(从左边开始) - int texOffset = 0; - - // 渲染 - draw(alpha, startX + screenOffset, startY, - renderWidth, texHeight, - texX + texOffset, texY, scale); - } - - /** - * 反向百分比显示(从右开始显示,左边空白) - * - * @param alpha 透明度 - * @param startX 起始X坐标(屏幕左上角) - * @param startY 起始Y坐标(屏幕左上角) - * @param texX 贴图左上角X - * @param texY 贴图左上角Y - * @param texWidth 贴图总宽度 - * @param texHeight 贴图高度 - * @param maxWidth 最大渲染宽度 - * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示后面40%的内容 - */ - public void drawByReversePercent(float alpha, int startX, int startY, - int texX, int texY, - int texWidth, int texHeight, - int maxWidth, float percent, float scale) { - // 限制百分比范围 - percent = Math.min(1.0f, Math.max(0.0f, percent)); - - // 如果要显示的内容为0,直接返回 - if (percent <= 0) { - return; - } - - // 计算要显示的内容宽度 - int contentWidth = (int) (texWidth * percent); - - // 实际渲染宽度 - int renderWidth = Math.min(contentWidth, maxWidth); - - // 屏幕偏移(靠右显示) - int screenOffset = maxWidth - renderWidth; - - // 贴图偏移(显示后面部分) - int texOffset = texWidth - contentWidth; - - // 渲染 - draw(alpha, startX + screenOffset, startY, - renderWidth, texHeight, - texX + texOffset, texY, scale); + entries.add(new TextEntry(component, y, color, shadow, width, height)); + texts.add(new TextItem(width, height, y, 1.0f)); } @Override public void draw(float alpha, int x, int y, int maxWidth, HudPosType dir) { - for (TextItem item : texts) { - Point2f point = AllMusicHud.getPos(Math.min(maxWidth, item.textWidth), item.textHeight, x, y, dir); + if (texts.isEmpty()) { + return; + } - drawLoop(alpha, point.x, point.y + item.y, 0, item.y, item.textWidth, item.textHeight, maxWidth, getOffset(item) % item.textWidth, item.scale); + PoseStack matrices = AllMusicClient.context; + if (matrices == null) return; + Font font = Minecraft.getInstance().font; + + for (TextEntry entry : entries) { + int displayWidth = maxWidth != -1 ? Math.min(entry.width, maxWidth) : entry.width; + Point2f point = AllMusicHud.getPos(displayWidth, entry.height, x, y, dir); + + int drawX = (int) point.x; + int drawY = (int) (point.y + entry.y); + int finalColor = applyAlpha(entry.color, alpha); + + if (maxWidth != -1 && entry.width > maxWidth) { + int scrollOffset = (int) (offsetX % entry.width); + enableScissor(drawX, drawY, maxWidth, entry.height); + drawString(font, matrices, entry, drawX - scrollOffset, drawY, finalColor); + if (scrollOffset > 0) { + drawString(font, matrices, entry, drawX - scrollOffset + entry.width, drawY, finalColor); + } + disableScissor(); + } else { + drawString(font, matrices, entry, drawX, drawY, finalColor); + } } } @Override public void drawLine(float x, float y, float alpha, int line) { - if (line >= texts.size()) { + if (texts.isEmpty()) { return; } - TextItem item = texts.get(line); - draw(alpha, x, y, item.textWidth, item.textHeight, 0, item.y, item.scale); + if (line >= texts.size() || line >= entries.size()) { + return; + } + PoseStack matrices = AllMusicClient.context; + if (matrices == null) return; + Font font = Minecraft.getInstance().font; + TextEntry entry = entries.get(line); + drawString(font, matrices, entry, + (int) x, (int) (y + entry.y), + applyAlpha(entry.color, alpha)); } @Override public Point2f getLine(int line) { - if (line >= texts.size()) { + if (line >= texts.size() || line >= entries.size()) { return new Point2f(0, 0); } - TextItem item = texts.get(line); - return new Point2f(item.textWidth, item.textHeight); + TextEntry entry = entries.get(line); + return new Point2f(entry.width, entry.height); } - @Override public void drawWithState(float alpha, int x, int y, int maxWidth, float state, HudPosType dir) { - for (TextItem item : texts) { - Point2f point = AllMusicHud.getPos(Math.min(maxWidth, item.textWidth), item.textHeight, x, y, dir); - - drawByPercent(alpha, point.x, point.y + item.y, 0, item.y, item.textWidth, item.textHeight, maxWidth, state, item.scale); + if (texts.isEmpty()) { + return; } + PoseStack matrices = AllMusicClient.context; + if (matrices == null) return; + Font font = Minecraft.getInstance().font; - target.unbindRead(); + for (TextEntry entry : entries) { + int displayWidth = maxWidth != -1 ? Math.min(entry.width, maxWidth) : entry.width; + Point2f point = AllMusicHud.getPos(displayWidth, entry.height, x, y, dir); + + int drawX = (int) point.x; + int drawY = (int) (point.y + entry.y); + int finalColor = applyAlpha(entry.color, alpha); + + if (maxWidth != -1 && entry.width > maxWidth) { + float maxOffset = entry.width - maxWidth; + int texOffset = (int) (maxOffset * state); + int revealWidth = (int) (maxWidth * state); + + enableScissor(drawX, drawY, revealWidth, entry.height); + drawString(font, matrices, entry, drawX - texOffset, drawY, finalColor); + disableScissor(); + } else { + int revealWidth = (int) (entry.width * state); + enableScissor(drawX, drawY, revealWidth, entry.height); + drawString(font, matrices, entry, drawX, drawY, finalColor); + disableScissor(); + } + } + } + + private static void drawString(Font font, PoseStack matrices, TextEntry entry, + int x, int y, int color) { + if (entry.shadow) { + font.drawShadow(matrices, entry.component, x, y, color); + } else { + font.draw(matrices, entry.component, x, (float) y, color); + } + } + + private static void enableScissor(int x, int y, int width, int height) { + Window window = Minecraft.getInstance().getWindow(); + double scale = window.getGuiScale(); + int sx = (int) (x * scale); + int sy = (int) (window.getHeight() - (y + height) * scale); + int sw = (int) (width * scale); + int sh = (int) (height * scale); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + GL11.glScissor(sx, sy, sw, sh); + } + + private static void disableScissor() { + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + + private static int applyAlpha(int color, float alpha) { + int a = (int) (alpha * 255); + if (a < 0) a = 0; + if (a > 255) a = 255; + return (color & 0x00FFFFFF) | (a << 24); } } diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/PicRender.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/PicRender.java index 0e96c180..799ba0ae 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/PicRender.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/PicRender.java @@ -12,8 +12,8 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.math.Matrix4f; import com.mojang.math.Quaternion; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.texture.DynamicTexture; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; import java.io.ByteArrayInputStream; @@ -48,12 +48,8 @@ public class PicRender extends PictureFrameBuffer { public void draw(boolean rotate, int size, float x, float y, int ang, HudPosType dir, float alpha) { Point2f point = AllMusicHud.getPos(size, size, x, y, dir); - RenderSystem.bindTexture(rotate ? rotateTexture.getId() : sourceTexture.getId()); - RenderSystem.enableTexture(); - RenderSystem.depthMask(false); - RenderSystem.enableBlend(); - RenderSystem.depthFunc(GL30.GL_ALWAYS); - + RenderSystem.setShaderTexture(0, rotate ? rotateTexture.getId() : sourceTexture.getId()); + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); RenderSystem.depthMask(false); RenderSystem.enableBlend(); RenderSystem.depthFunc(GL30.GL_ALWAYS); @@ -79,7 +75,7 @@ public class PicRender extends PictureFrameBuffer { float v1 = 1; BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_COLOR_TEX); bufferBuilder.vertex(matrix, x0, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v0).endVertex(); diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/TexRender.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/TexRender.java index 37bdc0aa..ad798b68 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/TexRender.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/TexRender.java @@ -13,11 +13,11 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.math.Matrix4f; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.texture.SimpleTexture; import net.minecraft.client.resources.metadata.texture.TextureMetadataSection; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; import java.io.IOException; @@ -42,8 +42,8 @@ public class TexRender extends TextureRender { @Override public void drawPic(float x, float y, float alpha) { - RenderSystem.bindTexture(sourceTexture.getId()); - RenderSystem.enableTexture(); + RenderSystem.setShaderTexture(0, sourceTexture.getId()); + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); RenderSystem.depthMask(false); RenderSystem.enableBlend(); RenderSystem.depthFunc(GL30.GL_ALWAYS); @@ -64,7 +64,7 @@ public class TexRender extends TextureRender { float v1 = 1; BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_COLOR_TEX); bufferBuilder.vertex(matrix, x0, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v0).endVertex(); @@ -78,8 +78,8 @@ public class TexRender extends TextureRender { @Override public void drawPic(float x, float y, float width, float alpha) { - RenderSystem.bindTexture(sourceTexture.getId()); - RenderSystem.enableTexture(); + RenderSystem.setShaderTexture(0, sourceTexture.getId()); + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); RenderSystem.depthMask(false); RenderSystem.enableBlend(); RenderSystem.depthFunc(GL30.GL_ALWAYS); @@ -100,7 +100,7 @@ public class TexRender extends TextureRender { float v1 = 1; BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_COLOR_TEX); bufferBuilder.vertex(matrix, x0, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v0).endVertex(); @@ -117,8 +117,8 @@ public class TexRender extends TextureRender { public void drawPic(float x, float y, float width, float height, HudPosType dir, float alpha) { Point2f point = AllMusicHud.getPos(width, height, x, y, dir); - RenderSystem.bindTexture(sourceTexture.getId()); - RenderSystem.enableTexture(); + RenderSystem.setShaderTexture(0, sourceTexture.getId()); + RenderSystem.setShader(GameRenderer::getPositionColorTexShader); RenderSystem.depthMask(false); RenderSystem.enableBlend(); RenderSystem.depthFunc(GL30.GL_ALWAYS); @@ -134,12 +134,12 @@ public class TexRender extends TextureRender { float y1 = h1; float z = 0; float u0 = 0; - float u1 = width; + float u1 = 1; float v0 = 0; float v1 = 1; BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); - bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + bufferBuilder.begin(7, DefaultVertexFormat.POSITION_COLOR_TEX); bufferBuilder.vertex(matrix, x0, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u0, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y1, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v1).endVertex(); bufferBuilder.vertex(matrix, x1, y0, z).color(1.0f, 1.0f, 1.0f, alpha).uv(u1, v0).endVertex(); diff --git a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/mixins/GuiShow.java b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/mixins/GuiShow.java index 2fd5c336..377d050f 100644 --- a/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/mixins/GuiShow.java +++ b/client/fabric_1_16_5/src/main/java/com/coloryr/allmusic/client/mixins/GuiShow.java @@ -1,6 +1,8 @@ package com.coloryr.allmusic.client.mixins; +import com.coloryr.allmusic.client.AllMusicClient; import com.coloryr.allmusic.client.core.AllMusicCore; +import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.client.gui.Gui; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -10,7 +12,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Gui.class) public class GuiShow { @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;getArmor(I)Lnet/minecraft/world/item/ItemStack;")) - public void Gui(CallbackInfo info) { + public void Gui(PoseStack poseStack, float partialTick, CallbackInfo info) { + AllMusicClient.update(poseStack); AllMusicCore.hudUpdate(); } -} \ No newline at end of file +} diff --git a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java index 93f7236a..863ea33e 100644 --- a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java +++ b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/AllMusicClient.java @@ -57,10 +57,9 @@ public class AllMusicClient implements AllMusicBridge { evt.getModConfigurationDirectory().mkdirs(); } AllMusicCore.init(evt.getModConfigurationDirectory().toPath(), this); - AllMusicCore.glInit(); MinecraftForge.EVENT_BUS.register(this); try { - Class server = Class.forName("com.coloryr.allmusic.server.AllMusicForge"); + Class server = Class.forName("com.coloryr.allmusic.server.AllMusicServer"); Field m = server.getField("channel"); FMLEventChannel channel = (FMLEventChannel) m.get(null); channel.register(this); diff --git a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java index 5059a568..709b3cf5 100644 --- a/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java +++ b/client/forge_1_12_2/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java @@ -185,6 +185,93 @@ public class CoreRenderTarget extends TextFrameBuffer { draw(alpha, startX, startY, maxWidth, texHeight, texX + texOffset, texY, scale); } + /** + * 正向百分比显示(从左开始显示,右边空白) + * + * @param alpha 透明度 + * @param startX 起始X坐标(屏幕左上角) + * @param startY 起始Y坐标(屏幕左上角) + * @param texX 贴图左上角X + * @param texY 贴图左上角Y + * @param texWidth 贴图总宽度 + * @param texHeight 贴图高度 + * @param maxWidth 最大渲染宽度 + * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示前面40%的内容 + */ + public void drawByForwardPercent(float alpha, int startX, int startY, + int texX, int texY, + int texWidth, int texHeight, + int maxWidth, float percent, float scale) { + + // 限制百分比范围 + percent = Math.min(1.0f, Math.max(0.0f, percent)); + + // 如果要显示的内容为0,直接返回 + if (percent <= 0) { + return; + } + + // 计算要显示的内容宽度 + int contentWidth = (int) (texWidth * percent); + + // 实际渲染宽度 + int renderWidth = Math.min(contentWidth, maxWidth); + + // 屏幕偏移为0(靠左显示) + int screenOffset = 0; + + // 贴图偏移为0(从左边开始) + int texOffset = 0; + + // 渲染 + draw(alpha, startX + screenOffset, startY, + renderWidth, texHeight, + texX + texOffset, texY, scale); + } + + /** + * 反向百分比显示(从右开始显示,左边空白) + * + * @param alpha 透明度 + * @param startX 起始X坐标(屏幕左上角) + * @param startY 起始Y坐标(屏幕左上角) + * @param texX 贴图左上角X + * @param texY 贴图左上角Y + * @param texWidth 贴图总宽度 + * @param texHeight 贴图高度 + * @param maxWidth 最大渲染宽度 + * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示后面40%的内容 + */ + public void drawByReversePercent(float alpha, int startX, int startY, + int texX, int texY, + int texWidth, int texHeight, + int maxWidth, float percent, float scale) { + // 限制百分比范围 + percent = Math.min(1.0f, Math.max(0.0f, percent)); + + // 如果要显示的内容为0,直接返回 + if (percent <= 0) { + return; + } + + // 计算要显示的内容宽度 + int contentWidth = (int) (texWidth * percent); + + // 实际渲染宽度 + int renderWidth = Math.min(contentWidth, maxWidth); + + // 屏幕偏移(靠右显示) + int screenOffset = maxWidth - renderWidth; + + // 贴图偏移(显示后面部分) + int texOffset = texWidth - contentWidth; + + // 渲染 + draw(alpha, startX + screenOffset, startY, + renderWidth, texHeight, + texX + texOffset, texY, scale); + } + @Override public void draw(float alpha, int x, int y, int maxWidth, HudPosType dir) { for (TextItem item : texts) { diff --git a/client/forge_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java b/client/forge_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java index ff97da04..dae7470e 100644 --- a/client/forge_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java +++ b/client/forge_1_16_5/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java @@ -75,13 +75,11 @@ public class CoreRenderTarget extends TextFrameBuffer { return; } - int width; - - if (shadow) { - width = font.drawShadow(new PoseStack(), component, 0, 0, color); - } else { - width = font.draw(new PoseStack(), component, 0, 0, color); - } + // 使用 drawInBatch 将文字渲染到 CoreRenderTarget 自己的 buffer, + // 而不是 Font 内部的 buffer。这样 endBatch() 才能正确 flush 到当前 RenderTarget(FBO)。 + int width = font.drawInBatch(component, 0, y, color, shadow, + new Matrix4f(), renderBuffers.bufferSource(), + false, 0, 15728880); RenderSystem.disableDepthTest(); renderBuffers.bufferSource().endBatch(); @@ -122,10 +120,11 @@ public class CoreRenderTarget extends TextFrameBuffer { float z = 0; // 计算贴图区域UV + // 注意:1.16.5 的 FBO 纹理不需要 Y 轴翻转,纹理原点在左上角 float u0 = texX * scale / target.width; - float v0 = 1 - (texY * scale / target.height); + float v0 = texY * scale / target.height; float u1 = (texX + width) * scale / target.width; - float v1 = 1 - ((texY + height) * scale / target.height); + float v1 = (texY + height) * scale / target.height; BufferBuilder bufferBuilder = Tesselator.getInstance().getBuilder(); bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/AllMusic.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/AllMusic.java index a87250c4..b0000cc4 100644 --- a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/AllMusic.java +++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/AllMusic.java @@ -1,15 +1,21 @@ package com.coloryr.allmusic.client; +import java.io.ByteArrayOutputStream; import java.io.File; -import java.nio.ByteBuffer; +import java.io.InputStream; import java.util.List; import com.coloryr.allmusic.client.core.AllMusicBridge; import com.coloryr.allmusic.client.core.AllMusicCore; +import com.coloryr.allmusic.client.core.render.PictureFrameBuffer; +import com.coloryr.allmusic.client.core.render.TextFrameBuffer; +import com.coloryr.allmusic.client.core.render.TextureRender; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.SoundCategory; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.resources.IResource; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.sound.PlaySoundEvent17; import net.minecraftforge.common.MinecraftForge; @@ -67,7 +73,7 @@ public class AllMusic implements AllMusicBridge { List list = sound1.allMusic_Client$getStreamingChannels(); ChannelLWJGLOpenAL channel = (ChannelLWJGLOpenAL) list.get(list.size() - 1); AllMusicCore.init(new File("config").toPath(), this, channel.ALSource); - AllMusicCore.glInit(); + AllMusicCore.renderInit(); } @Mod.EventHandler @@ -108,11 +114,6 @@ public class AllMusic implements AllMusicBridge { AllMusicCore.onServerQuit(); } - @Override - public Object genTexture(int size) { - return AllMusicCore.genGLTexture(size); - } - public int getScreenWidth() { Minecraft mc = Minecraft.getMinecraft(); ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); @@ -133,17 +134,59 @@ public class AllMusic implements AllMusicBridge { return Minecraft.getMinecraft().fontRenderer.FONT_HEIGHT; } - @Override - public void updateTexture(Object tex, int size, ByteBuffer byteBuffer) { - AllMusicCore.updateGLTexture((int) tex, size, byteBuffer); - } - @Override public void stopPlayMusic() { Minecraft.getMinecraft().getSoundHandler().stopSounds(); Minecraft.getMinecraft().getSoundHandler().stopSounds(); } + @Override + public TextFrameBuffer makeTextRender(String name) { + return new CoreRenderTarget(); + } + + @Override + public TextureRender makeTextureRender(String file) { + return new TexRender(file); + } + + @Override + public PictureFrameBuffer makePictureRender(int size) { + return new PicRender(size); + } + + @Override + public String readText(String file) { + try { + IResource resource = Minecraft.getMinecraft().getResourceManager() + .getResource(new ResourceLocation("allmusic_client", file)); + InputStream inputStream = resource.getInputStream(); + ByteArrayOutputStream result = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) != -1) { + result.write(buffer, 0, length); + } + inputStream.close(); + return result.toString("UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + public InputStream readFile(String file) { + try { + IResource resource = Minecraft.getMinecraft().getResourceManager() + .getResource(new ResourceLocation("allmusic_client", file)); + return resource.getInputStream(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + @SubscribeEvent @SideOnly(Side.CLIENT) public void onClientPacket(final FMLNetworkEvent.ClientCustomPacketEvent evt) { diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java new file mode 100644 index 00000000..6ee73771 --- /dev/null +++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/CoreRenderTarget.java @@ -0,0 +1,303 @@ +package com.coloryr.allmusic.client; + +import com.coloryr.allmusic.client.core.AllMusicHud; +import com.coloryr.allmusic.client.core.Point2f; +import com.coloryr.allmusic.client.core.render.TextFrameBuffer; +import com.coloryr.allmusic.codec.HudPosType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.shader.Framebuffer; +import org.lwjgl.opengl.GL11; + +public class CoreRenderTarget extends TextFrameBuffer { + private final Framebuffer target; + + public CoreRenderTarget() { + target = new Framebuffer(800, 200, false); + target.setFramebufferColor(0.0f, 0.0f, 0.0f, 0.0f); + } + + @Override + public void resize(int width, int height) { + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + + nowWidth = (width * scaledresolution.getScaledWidth()); + nowHeight = (height * scaledresolution.getScaledHeight()); + + if (nowWidth > target.framebufferWidth || nowHeight > target.framebufferHeight) { + target.createFramebuffer(nowWidth, nowHeight); + } + } + + @Override + public void use() { + isDraw = true; + + clear(); + target.framebufferClear(); + target.bindFramebuffer(true); + } + + @Override + public void unUse() { + isDraw = false; + + Minecraft minecraft = Minecraft.getMinecraft(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true); + } + + @Override + public void drawText(String text, int y, int color, boolean shadow) { + Minecraft minecraft = Minecraft.getMinecraft(); + + ScaledResolution scaledresolution = new ScaledResolution(minecraft, minecraft.displayWidth, minecraft.displayHeight); + + FontRenderer font = minecraft.fontRenderer; + + int width; + + if (shadow) { + width = font.drawStringWithShadow(text, 0, 0, color); + } else { + width = font.drawString(text, 0, 0, color); + } + + TextItem item = new TextItem(width, font.FONT_HEIGHT + (shadow ? 1 : 0), y, (float) scaledresolution.getScaledWidth()); + texts.add(item); + } + + /** + * 渲染贴图的一部分到屏幕指定位置 + * + * @param alpha 透明度 + * @param x 屏幕X坐标(左上角) + * @param y 屏幕Y坐标(左上角) + * @param width 需要渲染的宽度 + * @param height 需要渲染的高度 + * @param texX 贴图左上角X坐标 + * @param texY 贴图左上角Y坐标 + * @param scale 贴图缩放 + */ + private void draw(float alpha, float x, float y, float width, float height, float texX, float texY, float scale) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, target.framebufferTexture); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + + float w = (width / 2); + float h = (height / 2); + + GL11.glPushMatrix(); + GL11.glTranslatef(x + w, y + h, 0.0f); + + float x0 = -w; + float x1 = w; + float y0 = -h; + float y1 = h; + float z = 0; + + // 计算贴图区域UV + float u0 = texX * scale / target.framebufferWidth; + float v0 = 1 - (texY * scale / target.framebufferHeight); + float u1 = (texX + width) * scale / target.framebufferWidth; + float v1 = 1 - ((texY + height) * scale / target.framebufferHeight); + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, z, u0, v1); + tessellator.addVertexWithUV(x1, y1, z, u1, v1); + tessellator.addVertexWithUV(x1, y0, z, u1, v0); + tessellator.addVertexWithUV(x0, y0, z, u0, v0); + tessellator.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + + GL11.glPopMatrix(); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0); + } + + public void drawLoop(float alpha, float x, float y, + float texX, float texY, + float textWidth, float textHeight, + int maxWidth, float offsetX, float scale) { + + // 如果宽度不大于最大宽度,直接全部渲染 + if (maxWidth == -1 || textWidth <= maxWidth) { + draw(alpha, x, y, textWidth, textHeight, texX, texY, scale); + return; + } + + if (textWidth - offsetX < maxWidth) { + float nowWith = textWidth - offsetX; + draw(alpha, x, y, nowWith, textHeight, offsetX, texY, scale); + draw(alpha, x + nowWith, y, maxWidth - nowWith, textHeight, 0, texY, scale); + } else { + draw(alpha, x, y, maxWidth, textHeight, offsetX, texY, scale); + } + } + + /** + * 居中百分比显示(根据百分比选择显示贴图的中间部分) + * + * @param alpha 透明度 + * @param startX 起始X坐标(屏幕左上角) + * @param startY 起始Y坐标(屏幕左上角) + * @param texX 贴图左上角X + * @param texY 贴图左上角Y + * @param texWidth 贴图总宽度 + * @param texHeight 贴图高度 + * @param maxWidth 最大渲染宽度 + * @param percent 百分比(0.0-1.0),0%显示左边,100%显示右边 + */ + public void drawByPercent(float alpha, float startX, float startY, + float texX, float texY, + float texWidth, float texHeight, + int maxWidth, float percent, float scale) { + + // 限制百分比范围 + percent = Math.min(1.0f, Math.max(0.0f, percent)); + + // 如果贴图宽度小于等于最大宽度,直接全部显示 + if (texWidth <= maxWidth) { + draw(alpha, startX, startY, (int) (texWidth * percent), texHeight, texX, texY, scale); + return; + } + + // 计算贴图的起始位置(根据百分比) + float maxOffset = texWidth - maxWidth; + int texOffset = (int) (maxOffset * percent); + + // 渲染 + draw(alpha, startX, startY, maxWidth, texHeight, texX + texOffset, texY, scale); + } + + /** + * 正向百分比显示(从左开始显示,右边空白) + * + * @param alpha 透明度 + * @param startX 起始X坐标(屏幕左上角) + * @param startY 起始Y坐标(屏幕左上角) + * @param texX 贴图左上角X + * @param texY 贴图左上角Y + * @param texWidth 贴图总宽度 + * @param texHeight 贴图高度 + * @param maxWidth 最大渲染宽度 + * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示前面40%的内容 + */ + public void drawByForwardPercent(float alpha, int startX, int startY, + int texX, int texY, + int texWidth, int texHeight, + int maxWidth, float percent, float scale) { + + // 限制百分比范围 + percent = Math.min(1.0f, Math.max(0.0f, percent)); + + // 如果要显示的内容为0,直接返回 + if (percent <= 0) { + return; + } + + // 计算要显示的内容宽度 + int contentWidth = (int) (texWidth * percent); + + // 实际渲染宽度 + int renderWidth = Math.min(contentWidth, maxWidth); + + // 屏幕偏移为0(靠左显示) + int screenOffset = 0; + + // 贴图偏移为0(从左边开始) + int texOffset = 0; + + // 渲染 + draw(alpha, startX + screenOffset, startY, + renderWidth, texHeight, + texX + texOffset, texY, scale); + } + + /** + * 反向百分比显示(从右开始显示,左边空白) + * + * @param alpha 透明度 + * @param startX 起始X坐标(屏幕左上角) + * @param startY 起始Y坐标(屏幕左上角) + * @param texX 贴图左上角X + * @param texY 贴图左上角Y + * @param texWidth 贴图总宽度 + * @param texHeight 贴图高度 + * @param maxWidth 最大渲染宽度 + * @param percent 百分比(0.0-1.0),表示显示的内容比例,例如0.4表示显示后面40%的内容 + */ + public void drawByReversePercent(float alpha, int startX, int startY, + int texX, int texY, + int texWidth, int texHeight, + int maxWidth, float percent, float scale) { + // 限制百分比范围 + percent = Math.min(1.0f, Math.max(0.0f, percent)); + + // 如果要显示的内容为0,直接返回 + if (percent <= 0) { + return; + } + + // 计算要显示的内容宽度 + int contentWidth = (int) (texWidth * percent); + + // 实际渲染宽度 + int renderWidth = Math.min(contentWidth, maxWidth); + + // 屏幕偏移(靠右显示) + int screenOffset = maxWidth - renderWidth; + + // 贴图偏移(显示后面部分) + int texOffset = texWidth - contentWidth; + + // 渲染 + draw(alpha, startX + screenOffset, startY, + renderWidth, texHeight, + texX + texOffset, texY, scale); + } + + @Override + public void draw(float alpha, int x, int y, int maxWidth, HudPosType dir) { + for (TextItem item : texts) { + Point2f point = AllMusicHud.getPos(Math.min(maxWidth, item.textWidth), item.textHeight, x, y, dir); + + drawLoop(alpha, point.x, point.y + item.y, 0, item.y, item.textWidth, item.textHeight, maxWidth, getOffset(item) % item.textWidth, item.scale); + } + } + + @Override + public void drawLine(float x, float y, float alpha, int line) { + if (line >= texts.size()) { + return; + } + TextItem item = texts.get(line); + draw(alpha, x, y, item.textWidth, item.textHeight, 0, item.y, item.scale); + } + + @Override + public Point2f getLine(int line) { + if (line >= texts.size()) { + return new Point2f(0, 0); + } + TextItem item = texts.get(line); + return new Point2f(item.textWidth, item.textHeight); + } + + + @Override + public void drawWithState(float alpha, int x, int y, int maxWidth, float state, HudPosType dir) { + for (TextItem item : texts) { + Point2f point = AllMusicHud.getPos(Math.min(maxWidth, item.textWidth), item.textHeight, x, y, dir); + + drawByPercent(alpha, point.x, point.y + item.y, 0, item.y, item.textWidth, item.textHeight, maxWidth, state, item.scale); + } + } +} diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java new file mode 100644 index 00000000..ffd142bf --- /dev/null +++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/PicRender.java @@ -0,0 +1,83 @@ +package com.coloryr.allmusic.client; + +import com.coloryr.allmusic.client.core.AllMusicHud; +import com.coloryr.allmusic.client.core.Point2f; +import com.coloryr.allmusic.client.core.render.PictureFrameBuffer; +import com.coloryr.allmusic.codec.HudPosType; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.DynamicTexture; +import org.lwjgl.opengl.GL11; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; + +public class PicRender extends PictureFrameBuffer { + private final DynamicTexture sourceTexture; + private final DynamicTexture rotateTexture; + + public PicRender(int size) { + sourceTexture = new DynamicTexture(size, size); + rotateTexture = new DynamicTexture(size, size); + } + + @Override + public void update(byte[] source, byte[] rotate) { + try { + ByteArrayInputStream stream = new ByteArrayInputStream(source); + BufferedImage image = ImageIO.read(stream); + image.getRGB(0, 0, image.getWidth(), image.getHeight(), sourceTexture.getTextureData(), 0, image.getWidth()); + sourceTexture.updateDynamicTexture(); + + stream = new ByteArrayInputStream(rotate); + image = ImageIO.read(stream); + image.getRGB(0, 0, image.getWidth(), image.getHeight(), rotateTexture.getTextureData(), 0, image.getWidth()); + rotateTexture.updateDynamicTexture(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void draw(boolean rotate, int size, float x, float y, int ang, HudPosType dir, float alpha) { + Point2f point = AllMusicHud.getPos(size, size, x, y, dir); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, rotate ? rotateTexture.getGlTextureId() : sourceTexture.getGlTextureId()); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + GL11.glShadeModel(GL11.GL_SMOOTH); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + int a = size / 2; + GL11.glPushMatrix(); + GL11.glTranslatef(point.x + a, point.y + a, 0.0f); + + if (ang > 0) { + GL11.glRotatef(ang, 0, 0, 1f); + } + + int x0 = -a; + int x1 = a; + int y0 = -a; + int y1 = a; + int z = 0; + float u0 = 0; + float u1 = 1; + float v0 = 0; + float v1 = 1; + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, z, u0, v1); + tessellator.addVertexWithUV(x1, y1, z, u1, v1); + tessellator.addVertexWithUV(x1, y0, z, u1, v0); + tessellator.addVertexWithUV(x0, y0, z, u0, v0); + tessellator.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + + GL11.glPopMatrix(); + } +} diff --git a/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java new file mode 100644 index 00000000..d1fd53d8 --- /dev/null +++ b/client/forge_1_7_10/src/main/java/com/coloryr/allmusic/client/TexRender.java @@ -0,0 +1,192 @@ +package com.coloryr.allmusic.client; + +import com.coloryr.allmusic.client.core.AllMusicHud; +import com.coloryr.allmusic.client.core.Point2f; +import com.coloryr.allmusic.client.core.render.TextureRender; +import com.coloryr.allmusic.codec.HudPosType; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.SimpleTexture; +import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.data.TextureMetadataSection; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.IOUtils; +import org.lwjgl.opengl.GL11; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; + +public class TexRender extends TextureRender { + private final Tex sourceTexture; + + public TexRender(String texture) { + super(texture); + + ResourceLocation location = new ResourceLocation("allmusic_client", texture); + + sourceTexture = new Tex(location); + + try { + IResourceManager resourceManager = Minecraft.getMinecraft().getResourceManager(); + sourceTexture.loadTexture(resourceManager, this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void drawPic(float x, float y, float alpha) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + + float w1 = (float) width / 2; + float h1 = (float) height / 2; + + GL11.glPushMatrix(); + GL11.glTranslatef(x + w1, y + h1, 0.0f); + + float x0 = -w1; + float x1 = w1; + float y0 = -h1; + float y1 = h1; + float z = 0; + float u0 = 0; + float u1 = 1; + float v0 = 0; + float v1 = 1; + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, z, u0, v1); + tessellator.addVertexWithUV(x1, y1, z, u1, v1); + tessellator.addVertexWithUV(x1, y0, z, u1, v0); + tessellator.addVertexWithUV(x0, y0, z, u0, v0); + tessellator.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + + GL11.glPopMatrix(); + } + + @Override + public void drawPic(float x, float y, float width, float alpha) { + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + + float w1 = (float) (this.width / 2) * width; + float h1 = (float) height / 2; + + GL11.glPushMatrix(); + GL11.glTranslatef(x + w1, y + h1, 0.0f); + + float x0 = -w1; + float x1 = w1; + float y0 = -h1; + float y1 = h1; + float z = 0; + float u0 = 0; + float u1 = width; + float v0 = 0; + float v1 = 1; + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, z, u0, v1); + tessellator.addVertexWithUV(x1, y1, z, u1, v1); + tessellator.addVertexWithUV(x1, y0, z, u1, v0); + tessellator.addVertexWithUV(x0, y0, z, u0, v0); + tessellator.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + + GL11.glPopMatrix(); + } + + @Override + public void drawPic(float x, float y, float width, float height, HudPosType dir, float alpha) { + Point2f point = AllMusicHud.getPos(width, height, x, y, dir); + + GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId()); + GL11.glDepthMask(false); + GL11.glEnable(GL11.GL_BLEND); + + float w1 = width / 2; + float h1 = height / 2; + + GL11.glPushMatrix(); + GL11.glTranslatef(point.x + w1, point.y + h1, 0.0f); + + float x0 = -w1; + float x1 = w1; + float y0 = -h1; + float y1 = h1; + float z = 0; + float u0 = 0; + float u1 = width; + float v0 = 0; + float v1 = 1; + + Tessellator tessellator = Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(1.0f, 1.0f, 1.0f, alpha); + tessellator.addVertexWithUV(x0, y1, z, u0, v1); + tessellator.addVertexWithUV(x1, y1, z, u1, v1); + tessellator.addVertexWithUV(x1, y0, z, u1, v0); + tessellator.addVertexWithUV(x0, y0, z, u0, v0); + tessellator.draw(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glDepthMask(true); + + GL11.glPopMatrix(); + } + + public static class Tex extends SimpleTexture { + public Tex(ResourceLocation resourceLocation) { + super(resourceLocation); + } + + public void loadTexture(IResourceManager resourceManager, TexRender render) throws IOException { + this.deleteGlTexture(); + IResource iresource = null; + InputStream inputstream = null; + + try { + iresource = resourceManager.getResource(this.textureLocation); + inputstream = iresource.getInputStream(); + BufferedImage bufferedimage = ImageIO.read(inputstream); + render.width = bufferedimage.getWidth(); + render.height = bufferedimage.getHeight(); + boolean flag = false; + boolean flag1 = false; + + if (iresource.hasMetadata()) { + try { + TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource.getMetadata("texture"); + + if (texturemetadatasection != null) { + flag = texturemetadatasection.getTextureBlur(); + flag1 = texturemetadatasection.getTextureClamp(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + TextureUtil.uploadTextureImageAllocate(this.getGlTextureId(), bufferedimage, flag, flag1); + } finally { + IOUtils.closeQuietly(inputstream); + } + } + } +} diff --git a/onejar/build.gradle.kts b/onejar/build.gradle.kts index e69de29b..4be5bb45 100644 --- a/onejar/build.gradle.kts +++ b/onejar/build.gradle.kts @@ -0,0 +1,40 @@ +subprojects { + val shadowImplementation by configurations.getting + + dependencies { + shadowImplementation(project(":client")) + shadowImplementation(project(":codec")) + shadowImplementation(project(":server")) + } + + tasks { + shadowJar { + configurations = listOf(project.configurations.shadow.get()) + } + } +} + +dependencies { + shadowImplementation(project(":codec")) + + shadowImplementation("org.apache.httpcomponents.client5:httpclient5:${Versions.httpclient5}") + shadowImplementation("org.apache.httpcomponents.core5:httpcore5:${Versions.httpcore5}") + shadowImplementation("org.apache.httpcomponents.core5:httpcore5-h2:${Versions.httpcore5_h2}") + + compileOnly("com.google.code.gson:gson:${Versions.gson}") + compileOnly("net.kyori:adventure-text-minimessage:${Versions.minimessage}") + compileOnly("org.lwjgl.lwjgl:lwjgl:2.9.3") + compileOnly("org.apache.logging.log4j:log4j-core:2.25.4") +} + +tasks.register("buildOnJar") { + group = "build" + dependsOn(rootProject.subprojects.filter { it.path.startsWith(":onejar:") } + .map { it.tasks.named("build") }) +} + +tasks { + clean { + delete("$projectDir/../build") + } +} \ No newline at end of file diff --git a/onejar/fabric_1_16_5/build.gradle.kts b/onejar/fabric_1_16_5/build.gradle.kts new file mode 100644 index 00000000..a116bef3 --- /dev/null +++ b/onejar/fabric_1_16_5/build.gradle.kts @@ -0,0 +1,67 @@ +plugins { + id("fabric-loom") version Versions.fabricLoom +} + +// 直接引用 client 和 server 模块的源码目录,无需手动复制 +val clientSourceDir = project(":client:fabric_1_16_5").projectDir.resolve("src/main/java") +val serverSourceDir = project(":server:fabric_1_16_5").projectDir.resolve("src/main/java") +val clientResDir = project(":client:fabric_1_16_5").projectDir.resolve("src/main/resources") +val serverResDir = project(":server:fabric_1_16_5").projectDir.resolve("src/main/resources") + +sourceSets { + main { + java { + setSrcDirs(listOf(clientSourceDir, serverSourceDir)) + } + resources { + setSrcDirs(listOf( + file("src/main/resources"), // onejar 自己的合并资源(fabric.mod.json) + clientResDir, + serverResDir + )) + } + } +} + +dependencies { + minecraft("com.mojang:minecraft:1.16.5") + mappings(loom.officialMojangMappings()) + modCompileOnly("net.fabricmc:fabric-loader:0.18.5") + + modCompileOnly("net.fabricmc.fabric-api:fabric-api:0.42.0+1.16") + + modImplementation(include("net.kyori:examination-api:1.3.0")!!) + modImplementation(include("net.kyori:examination-string:1.3.0")!!) + modImplementation(include("net.kyori:adventure-platform-api:4.0.0")!!) + modImplementation(include("net.kyori:adventure-text-serializer-gson:4.9.3")!!) + modImplementation(include("net.kyori:adventure-text-serializer-legacy:4.9.3")!!) + modImplementation(include("net.kyori:adventure-text-serializer-plain:4.9.3")!!) + modImplementation(include("net.kyori:adventure-text-minimessage:4.26.1")!!) + modImplementation(include("net.kyori:adventure-api:4.26.1")!!) + modImplementation(include("net.kyori:adventure-key:4.26.1")!!) +} + +tasks { + processResources { + // onejar 自己的 fabric.mod.json 优先(排在 srcDirs 第一位), + // client/server 的 fabric.mod.json 作为重复项被排除 + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + filesMatching("fabric.mod.json") { + expand( + "version" to project.version + ) + } + } + + remapJar { + inputFile.set(shadowJar.get().archiveFile) + + archiveFileName.set("[fabric-1.16.5]AllMusic-${project.version}.jar") + destinationDirectory.set(file("${parent!!.projectDir}/../build")) + } + + build { + dependsOn(remapJar) + } +} diff --git a/onejar/fabric_1_16_5/src/main/resources/assets/allmusic/icon.png b/onejar/fabric_1_16_5/src/main/resources/assets/allmusic/icon.png new file mode 100644 index 00000000..b2b5fa79 Binary files /dev/null and b/onejar/fabric_1_16_5/src/main/resources/assets/allmusic/icon.png differ diff --git a/onejar/fabric_1_16_5/src/main/resources/fabric.mod.json b/onejar/fabric_1_16_5/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..b8b93195 --- /dev/null +++ b/onejar/fabric_1_16_5/src/main/resources/fabric.mod.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": 1, + "id": "allmusic_client", + "version": "${version}", + "name": "AllMusic Client", + "description": "AllMusic Client Mod", + "authors": [ + "Color_yr" + ], + "contact": { + "homepage": "https://github.com/Coloryr/AllMusic", + "sources": "https://github.com/Coloryr/AllMusic" + }, + "license": "GPL-3.0", + "icon": "assets/allmusic/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "com.coloryr.allmusic.server.AllMusicServer", + "com.coloryr.allmusic.server.adventure.impl.AdventureCommon" + ], + "preLaunch": [ + "com.coloryr.allmusic.server.adventure.impl.AdventurePrelaunch" + ], + "client": [ + "com.coloryr.allmusic.client.AllMusicClient" + ] + }, + "mixins": [ + "allmusic_client.mixins.json", + "allmusic_server.mixins.json", + "adventure-platform-fabric.accessor.mixins.json", + "adventure-platform-fabric.mixins.json" + ], + "depends": { + "fabricloader": ">=0.15.11", + "fabric": "*", + "minecraft": ">=1.16" + }, + "suggests": {} +} diff --git a/server/fabric_1_16_5/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java b/server/fabric_1_16_5/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java index 8e1e39fb..e58c8a6d 100644 --- a/server/fabric_1_16_5/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java +++ b/server/fabric_1_16_5/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java @@ -2,7 +2,7 @@ package com.coloryr.allmusic.server; import com.coloryr.allmusic.server.adventure.FabricServerAudiences; import com.coloryr.allmusic.server.core.AllMusic; -import net.fabricmc.api.DedicatedServerModInitializer; +import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.minecraft.resources.ResourceLocation; @@ -12,14 +12,14 @@ import org.apache.logging.log4j.Logger; import java.io.File; -public class AllMusicServer implements DedicatedServerModInitializer { +public class AllMusicServer implements ModInitializer { public static final Logger LOGGER = LogManager.getLogger("AllMusic Server"); public static final ResourceLocation ID = new ResourceLocation("allmusic", "channel"); public static MinecraftServer server; public static FabricServerAudiences audiences; @Override - public void onInitializeServer() { + public void onInitialize() { AllMusic.log = new LogFabric(); AllMusic.side = new SideFabric(); diff --git a/server/fabric_1_16_5/src/main/resources/fabric.mod.json b/server/fabric_1_16_5/src/main/resources/fabric.mod.json index 71914bce..0c02766e 100644 --- a/server/fabric_1_16_5/src/main/resources/fabric.mod.json +++ b/server/fabric_1_16_5/src/main/resources/fabric.mod.json @@ -15,10 +15,8 @@ "icon": "assets/allmusic_server/icon.png", "environment": "*", "entrypoints": { - "server": [ - "com.coloryr.allmusic.server.AllMusicServer" - ], "main": [ + "com.coloryr.allmusic.server.AllMusicServer", "com.coloryr.allmusic.server.adventure.impl.AdventureCommon" ], "preLaunch": [ diff --git a/server/forge_1_12_2/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java b/server/forge_1_12_2/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java index 61667244..c7cd6f68 100644 --- a/server/forge_1_12_2/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java +++ b/server/forge_1_12_2/src/main/java/com/coloryr/allmusic/server/AllMusicServer.java @@ -4,7 +4,7 @@ import com.coloryr.allmusic.server.core.AllMusic; import com.coloryr.allmusic.server.core.music.PlayMusic; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.minecraft.command.ServerCommandManager; + import net.minecraft.server.MinecraftServer; import net.minecraft.util.text.ITextComponent; import net.minecraftforge.common.MinecraftForge; @@ -56,8 +56,7 @@ public class AllMusicServer { public void onServerStarting(FMLServerStartingEvent event) { server = event.getServer(); - ServerCommandManager commandManager = (ServerCommandManager) server.commandManager; - commandManager.registerCommand(new CommandForge()); + event.registerServerCommand(new CommandForge()); } @Mod.EventHandler diff --git a/server/src/main/java/com/coloryr/allmusic/server/core/AllMusic.java b/server/src/main/java/com/coloryr/allmusic/server/core/AllMusic.java index cf2072ec..eced95b0 100644 --- a/server/src/main/java/com/coloryr/allmusic/server/core/AllMusic.java +++ b/server/src/main/java/com/coloryr/allmusic/server/core/AllMusic.java @@ -364,6 +364,9 @@ public class AllMusic { * @param player 用户名 */ public static void joinPlay(String player) { + if (AllMusic.side == null) { + return; + } AllMusic.side.runTask(() -> joinPlayNow(player), AllMusic.config.joinDelay); } diff --git a/settings.gradle.kts b/settings.gradle.kts index bc0bc12f..01c5b8dc 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ rootProject.name = "AllMusic" include(":codec") include(":client") + include(":client:fabric_1_16_5") include(":client:fabric_1_20_1") include(":client:fabric_1_21") @@ -13,10 +14,12 @@ include(":client:fabric_1_21_8") include(":client:fabric_1_21_11") include(":client:fabric_26_1") include(":client:fabric_26_2") -//include(":client:forge_1_7_10") -//include(":client:forge_1_12_2") + +include(":client:forge_1_7_10") +include(":client:forge_1_12_2") include(":client:forge_1_16_5") include(":client:forge_1_20_1") + include(":client:neoforge_1_21") include(":client:neoforge_1_21_3") include(":client:neoforge_1_21_4") @@ -54,6 +57,8 @@ include(":server:velocity") include(":onejar") +include(":onejar:fabric_1_16_5") + pluginManagement { repositories { mavenCentral() @@ -64,4 +69,4 @@ pluginManagement { maven("https://maven.architectury.dev/") maven("https://nexus.gtnewhorizons.com/repository/public/") } -} \ No newline at end of file +}