package net.shadowfacts.cacao.util import com.mojang.blaze3d.platform.GlStateManager import net.minecraft.client.MinecraftClient import net.minecraft.client.gui.DrawableHelper import net.minecraft.client.render.Tessellator import net.minecraft.client.render.VertexFormats import net.minecraft.client.sound.PositionedSoundInstance import net.minecraft.sound.SoundEvent import net.shadowfacts.cacao.geometry.Rect import org.lwjgl.opengl.GL11 /** * Helper methods for rendering using Minecraft's utilities from Cacao views. * For unit testing, all drawing and OpenGL interaction can be disabled by setting the `cacao.drawing.disabled` JVM property to `true`. * * @author shadowfacts */ object RenderHelper { val disabled = (System.getProperty("cacao.drawing.disabled") ?: "false").toBoolean() // TODO: find a better place for this fun playSound(event: SoundEvent) { if (disabled) return MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(event, 1f)) } /** * Draws a solid [rect] filled with the given [color]. */ fun fill(rect: Rect, color: Color) { if (disabled) return DrawableHelper.fill(rect.left.toInt(), rect.top.toInt(), rect.right.toInt(), rect.bottom.toInt(), color.argb) } /** * Binds and draws the given [texture] filling the [rect]. */ fun draw(rect: Rect, texture: Texture) { if (disabled) return color(1f, 1f, 1f, 1f) MinecraftClient.getInstance().textureManager.bindTexture(texture.location) draw(rect.left, rect.top, texture.u, texture.v, rect.width, rect.height, texture.width, texture.height) } /** * Draws the bound texture with the given screen and texture position and size. */ fun draw(x: Double, y: Double, u: Int, v: Int, width: Double, height: Double, textureWidth: Int, textureHeight: Int) { if (disabled) return val uStart = u.toDouble() / textureWidth val uEnd = (u + width) / textureWidth val vStart = v.toDouble() / textureHeight val vEnd = (v + height) / textureHeight innerBlit(x, x + width, y, y + height, 0.0, uStart, uEnd, vStart, vEnd) } // Copied from net.minecraft.client.gui.DrawableHelper private fun innerBlit(xStart: Double, xEnd: Double, yStart: Double, yEnd: Double, z: Double, uStart: Double, uEnd: Double, vStart: Double, vEnd: Double) { val tessellator = Tessellator.getInstance() val buffer = tessellator.bufferBuilder buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_UV) buffer.vertex(xStart, yEnd, z).texture(uStart, vEnd).next() buffer.vertex(xEnd, yEnd, z).texture(uEnd, vEnd).next() buffer.vertex(xEnd, yStart, z).texture(uEnd, vStart).next() buffer.vertex(xStart, yStart, z).texture(uStart, vStart).next() tessellator.draw() } /** * @see org.lwjgl.opengl.GL11.glPushMatrix */ fun pushMatrix() { if (disabled) return GlStateManager.pushMatrix() } /** * @see org.lwjgl.opengl.GL11.glPopMatrix */ fun popMatrix() { if (disabled) return GlStateManager.popMatrix() } /** * @see org.lwjgl.opengl.GL11.glTranslated */ fun translate(x: Double, y: Double, z: Double = 0.0) { if (disabled) return GlStateManager.translated(x, y, z) } /** * @see org.lwjgl.opengl.GL11.glColor4f */ fun color(r: Float, g: Float, b: Float, alpha: Float) { if (disabled) return GlStateManager.color4f(r, g, b, alpha) } }