This commit is contained in:
Coloryr committed 2026-11-08 09:22:20 +08:00
1 parent 4de679b062
commit 8b8cd7b7c9
5 files changed
+264 -174

No files matched your search

@@ -318,7 +318,10 @@ public class AllMusic implements AllMusicBridge {
@SideOnly(Side.CLIENT)
public void onRenderOverlay(final RenderGameOverlayEvent.Pre e) {
if (e.type == RenderGameOverlayEvent.ElementType.PORTAL) {
AllMusicCore.hudUpdate();
// HUD 绘制会改动 GL 状态机,画完必须还原,避免影响原版后续的 HUD / 界面渲染
try (GlState ignored = GlState.push()) {
AllMusicCore.hudUpdate();
}
}
}
@@ -6,11 +6,9 @@ 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 org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.List;
public class CoreRenderTarget extends TextFrameBuffer<String> {
private final boolean isState;
@@ -40,32 +38,35 @@ public class CoreRenderTarget extends TextFrameBuffer<String> {
return;
}
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
// 文字绘制会改纹理、混合、Alpha 测试和颜色,画完还原 GL 状态机
try (GlState ignored = GlState.push()) {
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
for (TextItem<String> entry : texts) {
int displayWidth = maxWidth != -1 ? Math.min(entry.width, maxWidth) : entry.width;
Point2f point = AllMusicHud.getPos(displayWidth, entry.height, x, y, dir);
for (TextItem<String> entry : texts) {
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);
int drawX = (int) point.x;
int drawY = (int) (point.y + entry.y);
int finalColor = applyAlpha(entry.color, alpha);
GL11.glPushMatrix();
GL11.glTranslatef(drawX, drawY, 0);
GL11.glPushMatrix();
GL11.glTranslatef(drawX, drawY, 0);
if (maxWidth != -1 && entry.width > maxWidth) {
int scrollOffset = (int) getOffset(entry, maxWidth);
enableScissor(drawX, drawY, maxWidth, entry.height);
drawString(font, entry, -scrollOffset, 0, finalColor);
if (scrollOffset > 0) {
drawString(font, entry, -scrollOffset + entry.width, 0, finalColor);
if (maxWidth != -1 && entry.width > maxWidth) {
int scrollOffset = (int) getOffset(entry, maxWidth);
enableScissor(drawX, drawY, maxWidth, entry.height);
drawString(font, entry, -scrollOffset, 0, finalColor);
if (scrollOffset > 0) {
drawString(font, entry, -scrollOffset + entry.width, 0, finalColor);
}
disableScissor();
} else {
drawString(font, entry, 0, 0, finalColor);
}
disableScissor();
} else {
drawString(font, entry, 0, 0, finalColor);
}
GL11.glPopMatrix();
GL11.glPopMatrix();
}
}
}
@@ -77,12 +78,15 @@ public class CoreRenderTarget extends TextFrameBuffer<String> {
if (line >= texts.size()) {
return;
}
TextItem<String> entry = texts.get(line);
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
GL11.glPushMatrix();
GL11.glTranslatef((float) x, (float) (y + entry.y), 0);
drawString(font, entry, 0, 0, applyAlpha(entry.color, alpha));
GL11.glPopMatrix();
try (GlState ignored = GlState.push()) {
TextItem<String> entry = texts.get(line);
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
GL11.glPushMatrix();
GL11.glTranslatef(x, y + entry.y, 0);
drawString(font, entry, 0, 0, applyAlpha(entry.color, alpha));
GL11.glPopMatrix();
}
}
@Override
@@ -90,35 +94,38 @@ public class CoreRenderTarget extends TextFrameBuffer<String> {
if (texts.isEmpty()) {
return;
}
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
for (TextItem<String> entry : texts) {
int displayWidth = maxWidth != -1 ? Math.min(entry.width, maxWidth) : entry.width;
Point2f point = AllMusicHud.getPos(displayWidth, entry.height, x, y, dir);
try (GlState ignored = GlState.push()) {
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
int drawX = (int) point.x;
int drawY = (int) (point.y + entry.y);
int finalColor = applyAlpha(entry.color, alpha);
for (TextItem<String> entry : texts) {
int displayWidth = maxWidth != -1 ? Math.min(entry.width, maxWidth) : entry.width;
Point2f point = AllMusicHud.getPos(displayWidth, entry.height, x, y, dir);
GL11.glPushMatrix();
GL11.glTranslatef(drawX, drawY, 0);
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;
float texOffset = maxOffset * state;
int revealWidth = (int) (maxWidth * state);
GL11.glPushMatrix();
GL11.glTranslatef(drawX, drawY, 0);
enableScissor(drawX, drawY, revealWidth, entry.height);
drawString(font, entry, -(int) texOffset, 0, finalColor);
disableScissor();
} else {
int revealWidth = (int) (entry.width * state);
enableScissor(drawX, drawY, revealWidth, entry.height);
drawString(font, entry, 0, 0, finalColor);
disableScissor();
if (maxWidth != -1 && entry.width > maxWidth) {
float maxOffset = entry.width - maxWidth;
float texOffset = maxOffset * state;
int revealWidth = (int) (maxWidth * state);
enableScissor(drawX, drawY, revealWidth, entry.height);
drawString(font, entry, -(int) texOffset, 0, finalColor);
disableScissor();
} else {
int revealWidth = (int) (entry.width * state);
enableScissor(drawX, drawY, revealWidth, entry.height);
drawString(font, entry, 0, 0, finalColor);
disableScissor();
}
GL11.glPopMatrix();
}
GL11.glPopMatrix();
}
}
@@ -141,11 +148,9 @@ public class CoreRenderTarget extends TextFrameBuffer<String> {
private static void enableScissor(int x, int y, int width, int height) {
Minecraft mc = Minecraft.getMinecraft();
int scale = mc.gameSettings.guiScale;
if (scale == 0) {
int k = Math.min(mc.displayWidth, mc.displayHeight);
scale = Math.max(1, k / 320);
}
// 用 ScaledResolution 的缩放系数,自动 GUI 缩放时才能和文字坐标对齐
ScaledResolution resolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
int scale = resolution.getScaleFactor();
int sx = x * scale;
int sy = mc.displayHeight - (y + height) * scale;
int sw = width * scale;
@@ -0,0 +1,63 @@
package com.coloryr.allmusic.client;
import org.lwjgl.opengl.GL11;
/**
* 1.7.10 没有 GlStateManager,HUD 绘制前手动保存 OpenGL 状态机,绘制完原样还原。
* <p>
* 绘制 HUD 会改动纹理绑定、纹理开关、混合开关与混合模式、深度写入、颜色、
* 着色模型、Alpha 测试、裁剪盒、模型视图矩阵、顶点数组和像素存储;不还原会
* 污染原版后续的 HUD / 界面渲染,表现为其他界面变暗、贴图错乱、文字发黑或裁剪残留。
* <p>
* 用法:
* <pre>{@code
* try (GlState ignored = GlState.push()) {
* // 绘制
* }
* }</pre>
*/
public final class GlState implements AutoCloseable {
private boolean restored;
private GlState() {
}
/**
* 保存当前 GL 状态机
*
* @return 用于还原的状态对象
*/
public static GlState push() {
// GL_ALL_ATTRIB_BITS 覆盖纹理、混合、深度、颜色、Alpha 测试、裁剪、光照等全部服务端状态
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
// 顶点数组、像素存储等客户端状态由 glPushClientAttrib 保存
GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS);
// 矩阵栈不在 glPushAttrib 的保存范围里,单独保存模型视图矩阵
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
return new GlState();
}
/**
* 还原 GL 状态机
*/
@Override
public void close() {
if (restored) {
return;
}
restored = true;
// 绘制过程中可能改过矩阵模式,先切回模型视图再出栈
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
// 还原客户端状态(顶点数组、像素存储等)
GL11.glPopClientAttrib();
// 还原 glPushAttrib 保存的全部服务端状态,包括原来的矩阵模式
GL11.glPopAttrib();
}
}
@@ -17,73 +17,88 @@ public class PicRender extends PictureFrameBuffer {
private final DynamicTexture rotateTexture;
public PicRender(int size) {
sourceTexture = new DynamicTexture(size, size);
rotateTexture = new DynamicTexture(size, size);
// 分配材质会改纹理绑定,初始化也按状态机处理
try (GlState ignored = GlState.push()) {
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();
// 上传材质会绑定纹理、改像素存储状态,结束还原
try (GlState ignored = GlState.push()) {
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();
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 dispose() {
// 删除的纹理可能正好是当前绑定的纹理,删完不能把已删除的名字绑回去
int previous = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
int source = sourceTexture.getGlTextureId();
int rotate = rotateTexture.getGlTextureId();
sourceTexture.deleteGlTexture();
rotateTexture.deleteGlTexture();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, previous != source && previous != rotate ? previous : 0);
}
@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);
try (GlState ignored = GlState.push()) {
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);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, rotate ? rotateTexture.getGlTextureId() : sourceTexture.getGlTextureId());
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDepthMask(false);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_ALPHA_TEST);
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);
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);
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.glPopMatrix();
}
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();
}
}
@@ -40,25 +40,18 @@ public class TexRender extends TextureRender {
}
/**
* 开始绘制:绑定材质、设置混合模式
* 开始绘制:绑定材质、设置混合和深度状态
*/
private void beginDraw() {
GL11.glBindTexture(GL11.GL_TEXTURE_2D, sourceTexture.getGlTextureId());
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_ALPHA_TEST);
GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
GL11.glDepthMask(false);
}
/**
* 结束绘制:还原混合模式
*/
private void endDraw() {
GL11.glDisable(GL11.GL_BLEND);
GL11.glDepthMask(true);
}
/**
* 绘制一个四边形
*
@@ -86,57 +79,57 @@ public class TexRender extends TextureRender {
@Override
public void drawPic(float x, float y, float alpha) {
beginDraw();
try (GlState ignored = GlState.push()) {
beginDraw();
float w1 = (float) width / 2;
float h1 = (float) height / 2;
float w1 = (float) width / 2;
float h1 = (float) height / 2;
GL11.glPushMatrix();
GL11.glTranslatef(x + w1, y + h1, 0.0f);
GL11.glPushMatrix();
GL11.glTranslatef(x + w1, y + h1, 0.0f);
drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha);
drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha);
endDraw();
GL11.glPopMatrix();
GL11.glPopMatrix();
}
}
@Override
public void drawPic(float x, float y, float width, float alpha) {
beginDraw();
try (GlState ignored = GlState.push()) {
beginDraw();
float w1 = (float) (this.width / 2) * width;
float h1 = (float) height / 2;
float w1 = (float) (this.width / 2) * width;
float h1 = (float) height / 2;
GL11.glPushMatrix();
GL11.glTranslatef(x + w1, y + h1, 0.0f);
GL11.glPushMatrix();
GL11.glTranslatef(x + w1, y + h1, 0.0f);
// 这里只画材质的 width 比例(进度条)
drawQuad(-w1, -h1, w1, h1, 0, 0, width, 1, alpha);
// 这里只画材质的 width 比例(进度条)
drawQuad(-w1, -h1, w1, h1, 0, 0, width, 1, alpha);
endDraw();
GL11.glPopMatrix();
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);
try (GlState ignored = GlState.push()) {
Point2f point = AllMusicHud.getPos(width, height, x, y, dir);
beginDraw();
beginDraw();
float w1 = width / 2;
float h1 = height / 2;
float w1 = width / 2;
float h1 = height / 2;
GL11.glPushMatrix();
GL11.glTranslatef(point.x + w1, point.y + h1, 0.0f);
GL11.glPushMatrix();
GL11.glTranslatef(point.x + w1, point.y + h1, 0.0f);
// 整张贴图铺满整个四边形,U/V 都必须是 0~1,不能写成 width
drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha);
// 整张贴图铺满整个四边形,U/V 都必须是 0~1,不能写成 width
drawQuad(-w1, -h1, w1, h1, 0, 0, 1, 1, alpha);
endDraw();
GL11.glPopMatrix();
GL11.glPopMatrix();
}
}
public static class Tex extends SimpleTexture {
@@ -145,42 +138,53 @@ public class TexRender extends TextureRender {
}
public void loadTexture(IResourceManager resourceManager, TexRender render) throws IOException {
this.deleteGlTexture();
IResource iresource = null;
InputStream inputstream = null;
int oldTexture = this.getGlTextureId();
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;
try (GlState ignored = GlState.push()) {
this.deleteGlTexture();
IResource iresource = null;
InputStream inputstream = null;
if (iresource.hasMetadata()) {
try {
TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource.getMetadata("texture");
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 (texturemetadatasection != null) {
flag = texturemetadatasection.getTextureBlur();
flag1 = texturemetadatasection.getTextureClamp();
if (iresource.hasMetadata()) {
try {
TextureMetadataSection texturemetadatasection = (TextureMetadataSection) iresource.getMetadata("texture");
if (texturemetadatasection != null) {
flag = texturemetadatasection.getTextureBlur();
flag1 = texturemetadatasection.getTextureClamp();
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
TextureUtil.uploadTextureImageAllocate(this.getGlTextureId(), bufferedimage, flag, flag1);
} finally {
IOUtils.closeQuietly(inputstream);
}
TextureUtil.uploadTextureImageAllocate(this.getGlTextureId(), bufferedimage, flag, flag1);
// HUD 贴图基本都不是 2 的幂(如 bg1.png 238x238),GL_REPEAT 采样会被拉伸/平铺,
// 这里统一改成 CLAMP_TO_EDGE,避免贴图边缘被重复
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.getGlTextureId());
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
} finally {
IOUtils.closeQuietly(inputstream);
}
// HUD 贴图基本都不是 2 的幂(如 bg1.png 238x238),GL_REPEAT 采样会被拉伸/平铺,
// 这里统一改成 CLAMP_TO_EDGE,避免贴图边缘被重复。
// 参数设置放在状态还原之后,避免 glPopAttrib 把新纹理的参数一起还原掉。
int previous = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
if (previous == oldTexture) {
previous = 0;
}
int texture = this.getGlTextureId();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, previous);
}
}
}