LWJGL 2-始终显示3D字体的前面

时间:2019-05-26 21:52:01

标签: java lwjgl

我试图始终向用户显示3D字体的正面。我在旋转相机时尝试旋转字体,但是无法使其正常工作。

我目前有这个: enter image description here

我正在尝试这样做(字体始终朝前): enter image description here

TrueTypeFont.java

package com.displee.render.font;

import lombok.AllArgsConstructor;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * A TrueType font implementation originally for Slick, edited for Bobjob's Engine
 * @original author James Chambers (Jimmy)
 * @original author Jeremy Adams (elias4444)
 * @original author Kevin Glass (kevglass)
 * @original author Peter Korzuszek (genail)
 * @new version edited by David Aaron Muhar (bobjob)
 */
public class TrueTypeFont {

    public final static int ALIGN_LEFT = 0, ALIGN_RIGHT = 1, ALIGN_CENTER = 2;
    /**
     * Array that holds necessary information about the font characters
     */
    private IntObject[] charArray = new IntObject[256];

    /**
     * Map of user defined font characters (Character <-> IntObject)
     */
    private Map customChars = new HashMap();

    /**
     * Boolean flag on whether AntiAliasing is enabled or not
     */
    private boolean antiAlias;

    /**
     * Font's size
     */
    private int fontSize = 0;

    /**
     * Font's height
     */
    private int fontHeight = 0;

    /**
     * Texture used to cache the font 0-255 characters
     */
    private int fontTextureID;

    /**
     * Default font texture width
     */
    private int textureWidth = 512;

    /**
     * Default font texture height
     */
    private int textureHeight = 512;

    /**
     * A reference to Java's AWT Font that we create our font texture from
     */
    private Font font;

    /**
     * The font metrics for our Java AWT font
     */
    private FontMetrics fontMetrics;


    private int correctL = 9, correctR = 8;

    private class IntObject {

        /**
         * Character's width
         */
        public int width;

        /**
         * Character's height
         */
        public int height;

        /**
         * Character's stored x position
         */
        public int storedX;

        /**
         * Character's stored y position
         */
        public int storedY;
    }


    public TrueTypeFont(Font font, boolean antiAlias, char[] additionalChars) {
        this.font = font;
        this.fontSize = font.getSize() + 3;
        this.antiAlias = antiAlias;

        createSet(additionalChars);

        fontHeight -= 1;
        if (fontHeight <= 0) {
            fontHeight = 1;
        }
    }

    public TrueTypeFont(Font font, boolean antiAlias) {
        this(font, antiAlias, null);
    }

    public void setCorrection(boolean on) {
        if (on) {
            correctL = 2;
            correctR = 1;
        } else {
            correctL = 0;
            correctR = 0;
        }
    }

    private BufferedImage getFontImage(char ch) {
        // Create a temporary image to extract the character's size
        BufferedImage tempfontImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) tempfontImage.getGraphics();
        if (antiAlias == true) {
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        g.setFont(font);
        fontMetrics = g.getFontMetrics();
        int charwidth = fontMetrics.charWidth(ch) + 8;

        if (charwidth <= 0) {
            charwidth = 7;
        }
        int charheight = fontMetrics.getHeight() + 3;
        if (charheight <= 0) {
            charheight = fontSize;
        }

        // Create another image holding the character we are creating
        BufferedImage fontImage;
        fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D gt = (Graphics2D) fontImage.getGraphics();
        if (antiAlias == true) {
            gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        gt.setFont(font);

        gt.setColor(Color.WHITE);
        int charx = 3;
        int chary = 1;
        gt.drawString(String.valueOf(ch), (charx), (chary) + fontMetrics.getAscent());
        //fontImage = ImageUtils.flipVertically(fontImage);
        //fontImage = ImageUtils.flipHorizontally(fontImage);
        //fontImage = ImageUtils.flipHorizontallyAndVertically(fontImage);
        return fontImage;

    }

    private void createSet(char[] customCharsArray) {
        // If there are custom chars then I expand the font texture twice
        if (customCharsArray != null && customCharsArray.length > 0) {
            textureWidth *= 2;
        }

        // In any case this should be done in other way. Texture with size 512x512
        // can maintain only 256 characters with resolution of 32x32. The texture
        // size should be calculated dynamicaly by looking at character sizes.

        try {

            BufferedImage imgTemp = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = (Graphics2D) imgTemp.getGraphics();

            g.setColor(new Color(0, 0, 0, 1));
            g.fillRect(0, 0, textureWidth, textureHeight);

            int rowHeight = 0;
            int positionX = 0;
            int positionY = 0;

            int customCharsLength = (customCharsArray != null) ? customCharsArray.length : 0;

            for (int i = 0; i < 256 + customCharsLength; i++) {

                // get 0-255 characters and then custom characters
                char ch = (i < 256) ? (char) i : customCharsArray[i - 256];

                BufferedImage fontImage = getFontImage(ch);

                IntObject newIntObject = new IntObject();

                newIntObject.width = fontImage.getWidth();
                newIntObject.height = fontImage.getHeight();

                if (positionX + newIntObject.width >= textureWidth) {
                    positionX = 0;
                    positionY += rowHeight;
                    rowHeight = 0;
                }

                newIntObject.storedX = positionX;
                newIntObject.storedY = positionY;

                if (newIntObject.height > fontHeight) {
                    fontHeight = newIntObject.height;
                }

                if (newIntObject.height > rowHeight) {
                    rowHeight = newIntObject.height;
                }

                // Draw it here
                g.drawImage(fontImage, positionX, positionY, null);

                positionX += newIntObject.width;

                if (i < 256) { // standard characters
                    charArray[i] = newIntObject;
                } else { // custom characters
                    customChars.put(new Character(ch), newIntObject);
                }

                fontImage = null;
            }

            fontTextureID = loadImage(imgTemp);


            //.getTexture(font.toString(), imgTemp);

        } catch (Exception e) {
            System.err.println("Failed to create font.");
            e.printStackTrace();
        }
    }

    private void drawQuad(float drawX, float drawY, float drawX2, float drawY2, float srcX, float srcY, float srcX2, float srcY2, float z) {
        float DrawWidth = drawX2 - drawX;
        float DrawHeight = drawY2 - drawY;
        float TextureSrcX = srcX / textureWidth;
        float TextureSrcY = srcY / textureHeight;
        float SrcWidth = srcX2 - srcX;
        float SrcHeight = srcY2 - srcY;
        float RenderWidth = (SrcWidth / textureWidth);
        float RenderHeight = (SrcHeight / textureHeight);

        GL11.glTexCoord2f(TextureSrcX, TextureSrcY);
        GL11.glVertex3f(drawX, drawY, z);
        GL11.glTexCoord2f(TextureSrcX, TextureSrcY + RenderHeight);
        GL11.glVertex3f(drawX, drawY + DrawHeight, z);
        GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY + RenderHeight);
        GL11.glVertex3f(drawX + DrawWidth, drawY + DrawHeight, z);
        GL11.glTexCoord2f(TextureSrcX + RenderWidth, TextureSrcY);
        GL11.glVertex3f(drawX + DrawWidth, drawY, z);
    }

    public int getWidth(String whatchars) {
        int totalwidth = 0;
        IntObject intObject = null;
        int currentChar = 0;
        for (int i = 0; i < whatchars.length(); i++) {
            currentChar = whatchars.charAt(i);
            if (currentChar < 256) {
                intObject = charArray[currentChar];
            } else {
                intObject = (IntObject) customChars.get(new Character((char) currentChar));
            }

            if (intObject != null) {
                totalwidth += intObject.width;
            }
        }
        return totalwidth;
    }

    public int getHeight() {
        return fontHeight;
    }


    public int getHeight(String HeightString) {
        return fontHeight;
    }

    public int getLineHeight() {
        return fontHeight;
    }

    public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY) {
        drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, ALIGN_LEFT);
    }

    public void drawString(float x, float y, float z, String whatchars, float scaleX, float scaleY, int format) {
        drawString(x, y, z, whatchars, 0, whatchars.length() - 1, scaleX, scaleY, format);
    }


    public void drawString(float x, float y, float z, String whatchars, int startIndex, int endIndex, float scaleX, float scaleY, int format) {

        IntObject intObject = null;
        int charCurrent;


        int totalwidth = 0;
        int i = startIndex, d, c;
        float startY = 0;


        switch (format) {
            case ALIGN_RIGHT: {
                d = -1;
                c = correctR;

                while (i < endIndex) {
                    if (whatchars.charAt(i) == '\n') {
                        startY -= fontHeight;
                    }
                    i++;
                }
                break;
            }
            case ALIGN_CENTER: {
                for (int l = startIndex; l <= endIndex; l++) {
                    charCurrent = whatchars.charAt(l);
                    if (charCurrent == '\n') {
                        break;
                    }
                    if (charCurrent < 256) {
                        intObject = charArray[charCurrent];
                    } else {
                        intObject = (IntObject) customChars.get(new Character((char) charCurrent));
                    }
                    totalwidth += intObject.width - correctL;
                }
                totalwidth /= -2;
            }
            case ALIGN_LEFT:
            default: {
                d = 1;
                c = correctL;
                break;
            }

        }

        java.util.List<QuadObject> list = new ArrayList<>(endIndex - startIndex);

        while (i >= startIndex && i <= endIndex) {

            charCurrent = whatchars.charAt(i);
            if (charCurrent < 256) {
                intObject = charArray[charCurrent];
            } else {
                intObject = (IntObject) customChars.get(new Character((char) charCurrent));
            }

            if (intObject != null) {
                if (d < 0) {
                    totalwidth += (intObject.width - c) * d;
                }
                if (charCurrent == '\n') {
                    startY -= fontHeight * d;
                    totalwidth = 0;
                    if (format == ALIGN_CENTER) {
                        for (int l = i + 1; l <= endIndex; l++) {
                            charCurrent = whatchars.charAt(l);
                            if (charCurrent == '\n') {
                                break;
                            }
                            if (charCurrent < 256) {
                                intObject = charArray[charCurrent];
                            } else {
                                intObject = (IntObject) customChars.get(new Character((char) charCurrent));
                            }
                            totalwidth += intObject.width - correctL;
                        }
                        totalwidth /= -2;
                    }
                    //if center get next lines total width/2;
                } else {
                    QuadObject quad = new QuadObject((totalwidth + intObject.width) * scaleX + x, startY * scaleY + y, totalwidth * scaleX + x, (startY + intObject.height) * scaleY + y, intObject.storedX + intObject.width, intObject.storedY + intObject.height, intObject.storedX, intObject.storedY, z);
                    list.add(quad);
                    if (d > 0) {
                        totalwidth += (intObject.width - c) * d;
                    }
                }
                i += d;

            }
        }

        float centerX = 0;
        for(QuadObject quad : list) {
            centerX += quad.drawX + (quad.drawX2 - quad.drawX);
        }
        centerX /= 2.0f;
        float centerY = 0;
        for(QuadObject quad : list) {
            centerY += quad.drawY + (quad.drawY2 - quad.drawY);
        }
        centerY /= 2.0f;

        //GL11.glTranslatef( -centerX, -centerY, -z);
        //GL11.glTranslatef(0, 0, -z);
        GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
        GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);
        //GL11.glRotatef(-Test3DFont.rotation.z, 0.0f, 0.0f, 1.0f);
        //GL11.glTranslatef(0, 0, z);
        //GL11.glTranslatef(centerX, centerY, z); // M1 - 2nd translation

        GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
        GL11.glBegin(GL11.GL_QUADS);
        for(QuadObject quad : list) {
            drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
        }
        GL11.glDisable(GL11.GL_TEXTURE_2D);
        GL11.glEnd();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    }

    public static int loadImage(BufferedImage bufferedImage) {
        try {
            short width = (short) bufferedImage.getWidth();
            short height = (short) bufferedImage.getHeight();
            //textureLoader.bpp = bufferedImage.getColorModel().hasAlpha() ? (byte)32 : (byte)24;
            int bpp = (byte) bufferedImage.getColorModel().getPixelSize();
            ByteBuffer byteBuffer;
            DataBuffer db = bufferedImage.getData().getDataBuffer();
            if (db instanceof DataBufferInt) {
                int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData();
                byte newI[] = new byte[intI.length * 4];
                for (int i = 0; i < intI.length; i++) {
                    byte b[] = intToByteArray(intI[i]);
                    int newIndex = i * 4;

                    newI[newIndex] = b[1];
                    newI[newIndex + 1] = b[2];
                    newI[newIndex + 2] = b[3];
                    newI[newIndex + 3] = b[0];
                }

                byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI);
            } else {
                byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData());
            }
            byteBuffer.flip();


            int internalFormat = GL11.GL_RGBA8, format = GL11.GL_RGBA;
            IntBuffer textureId = BufferUtils.createIntBuffer(1);
            ;
            GL11.glGenTextures(textureId);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId.get(0));


            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP);

            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);

            GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);


            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL11.GL_UNSIGNED_BYTE, byteBuffer.order(ByteOrder.nativeOrder()));
            return textureId.get(0);

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }

        return -1;
    }

    public static boolean isSupported(String fontname) {
        Font font[] = getFonts();
        for (int i = font.length - 1; i >= 0; i--) {
            if (font[i].getName().equalsIgnoreCase(fontname)) {
                return true;
            }
        }
        return false;
    }

    public static Font[] getFonts() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
    }

    public static byte[] intToByteArray(int value) {
        return new byte[]{(byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value};
    }

    public void destroy() {
        IntBuffer scratch = BufferUtils.createIntBuffer(1);
        scratch.put(0, fontTextureID);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        GL11.glDeleteTextures(scratch);
    }

    @AllArgsConstructor
    private class QuadObject {
        private float drawX;
        private float drawY;
        private float drawX2;
        private float drawY2;
        private float srcX;
        private float srcY;
        private float srcX2;
        private float srcY2;
        private float z;
    }
}

Test3DFont.java

package com.displee.render.font;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;

import java.awt.*;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;

public class Test3DFont {

    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;

    private static final float FOV = 45f;
    private static final float NEAR = 0.1f;
    private static final float FAR = 1000f;

    private static boolean mousePressed;
    private static Vector3f startCoordinations = new Vector3f();
    private static float scale = 0.05f;

    public static Vector3f rotation = new Vector3f(0, 0, 0);
    private static Vector3f startRotation = new Vector3f();

    private static TrueTypeFont font;

    private static boolean running = true;

    public static void main(String[] args) throws Exception {
        initializeDisplay();
        font = new TrueTypeFont(new Font("serif", Font.PLAIN, 30), true);
        initializeGL();
        while(running) {
            glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
            handleMouse();

            font.drawString(0, 0, 0, "Test", 0.1f, 0.1f);

            loadDefaultRotation();
            setViewport();

            drawGrid();
            Display.sync(60);
            Display.update();

            if (Display.isCloseRequested()) {
                break;
            }
        }
        font.destroy();
        Display.destroy();
    }

    private static void initializeDisplay() throws LWJGLException {
        Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
        Display.create();
        setViewport();
    }

    public static void set2DMode() {
        //GL11.glDisable(GL11.GL_DEPTH_TEST);
        GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPushMatrix();                                     // Store The Projection Matrix
        GL11.glLoadIdentity();                                   // Reset The Projection Matrix
        GL11.glOrtho(0, WIDTH, 0, HEIGHT, -1, 1);                          // Set Up An Ortho Screen
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPushMatrix();                                     // Store The Modelview Matrix
        GL11.glLoadIdentity();                                   // Reset The Modelview Matrix
    }

    public static void set3DMode() {
        GL11.glMatrixMode(GL11.GL_PROJECTION);                        // Select The Projection Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        GL11.glMatrixMode(GL11.GL_MODELVIEW);                         // Select The Modelview Matrix
        GL11.glPopMatrix();                                      // Restore The Old Projection Matrix
        //GL11.glEnable(GL11.GL_DEPTH_TEST);
    }

    private static void setViewport() {
        glViewport(0, 0, WIDTH, HEIGHT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(FOV, (float) WIDTH / (float) HEIGHT, NEAR, FAR);
        glMatrixMode(GL_MODELVIEW);
    }

    private static void initializeGL() {
        glShadeModel(GL_SMOOTH);
        glEnable(GL_NORMALIZE);
        glEnable(GL_BLEND);
        glCullFace(GL_BACK);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    private static void handleMouse() {
        scale += Mouse.getDWheel() > 0 ? 0.005f : Mouse.getDWheel() < 0 ? -0.005f : 0;
        int x = Mouse.getY();
        int y = Mouse.getX();
        if (!mousePressed) {
            mousePressed = Mouse.isButtonDown(0);
            if (mousePressed) {
                startCoordinations.set((float) x, (float) y, 0.0f);
                startRotation = new Vector3f(rotation);
            }
        } else if (!Mouse.isButtonDown(0)) {
            mousePressed = false;
        }
        if (!mousePressed) {
            return;
        }
        float differenceX = x - startCoordinations.x;
        float differenceY = y - startCoordinations.y;
        rotation.set(startRotation.x - (differenceX * 0.5F), startRotation.y + (differenceY * 0.5F), 0);
    }

    private static void loadDefaultRotation() {
        glLoadIdentity();
        Vector3f cameraPosition = new Vector3f();
        glTranslatef(cameraPosition.x, cameraPosition.y, -10);
        glRotatef(rotation.x, 1.0F, 0.0F, 0.0F);
        glRotatef(rotation.y, 0.0F, 1.0F, 0.0F);
        glRotatef(rotation.z, 0.0F, 0.0F, 1.0F);
        glScalef(scale, scale, scale);
    }

    private static void drawGrid() {
        glColor4f(0.7176471f, 0.7176471f, 0.7176471f, 1.0f);
        glBegin(GL_LINES);
        float size = 50;
        float step = 10;
        for (float i = -size; i <= size; i += step) {
            glVertex3f(i, 0, size);
            glVertex3f(i, 0, -size);
            glVertex3f(size, 0, i);
            glVertex3f(-size, 0, i);
        }
        glEnd();
    }

    public static int[] getScreenCoords(double x, double y, double z) {
        FloatBuffer screenCoords = BufferUtils.createFloatBuffer(4);
        IntBuffer viewport = BufferUtils.createIntBuffer(16);
        FloatBuffer modelView = BufferUtils.createFloatBuffer(16);
        FloatBuffer projection = BufferUtils.createFloatBuffer(16);
        GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
        GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
        GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
        boolean result = GLU.gluProject((float) x, (float) y, (float) z, modelView, projection, viewport, screenCoords);
        if (result) {
            return new int[] { (int) screenCoords.get(0), (int) screenCoords.get(1) };
        }
        return null;
    }

}

有人可以帮我吗?我该如何做才能始终看到字体的前面?

更新1: 通过旋转四边形,它几乎可以正常工作。在启用纹理2D之前,我已经在drawString方法中添加了以下代码:

GL11.glRotatef(-Test3DFont.rotation.x, 0.0f, 0.0f, 0.0f);
GL11.glRotatef(-Test3DFont.rotation.y, 0.0f, 1.0f, 0.0f);

我已经更新了代码。当前看起来像这样: enter image description here

1 个答案:

答案 0 :(得分:1)

我最终通过推送一个矩阵并在翻译中使用原始的x,y和z坐标来修复它。我还必须从旋转中减去180,因为这是我的起始旋转。最终得到以下代码:

    GL11.glPushMatrix();
    GL11.glTranslatef(x, y, z);
    GL11.glRotatef(180 - rotation.y, 0.0f, 1.0f, 0.0f);
    GL11.glTranslatef(-x, -y, -z);

    GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureID);
    GL11.glBegin(GL11.GL_QUADS);
    for(QuadObject quad : list) {
        drawQuad(quad.drawX, quad.drawY, quad.drawX2, quad.drawY2, quad.srcX, quad.srcY, quad.srcX2, quad.srcY2, quad.z);
    }
    GL11.glDisable(GL11.GL_TEXTURE_2D);
    GL11.glEnd();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);

    GL11.glPopMatrix();