processing.lwjgl.PLWJGL.java Source code

Java tutorial

Introduction

Here is the source code for processing.lwjgl.PLWJGL.java

Source

/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
  Part of the Processing project - http://processing.org
    
  Copyright (c) 2011-12 Ben Fry and Casey Reas
    
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
    
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
    
  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package processing.lwjgl;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.PathIterator;
import java.nio.Buffer;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.ARBES2Compatibility;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.glu.GLUtessellator;
import org.lwjgl.util.glu.GLUtessellatorCallbackAdapter;
import org.lwjgl.opengl.PixelFormat;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.event.Event;
import processing.event.KeyEvent;
import processing.event.MouseEvent;
import processing.opengl.PGL;
import processing.opengl.PGraphicsOpenGL;

/**
 * Processing-OpenGL abstraction layer. LWJGL implementation.
 *
 * Some issues:
 * http://lwjgl.org/forum/index.php/topic,4711.0.html
 * http://www.java-gaming.org/topics/cannot-add-mouselistener-to-java-awt-canvas-with-lwjgl-on-windows/24650/view.html
 *
 */
public class PLWJGL extends PGL {
    // ........................................................

    // Public members to access the underlying GL objects and canvas

    /** GLU interface **/
    public static GLU glu;

    /** The canvas where OpenGL rendering takes place */
    public static Canvas canvas;

    // ........................................................

    // Event handling

    /** Poller threads to get the keyboard/mouse events from LWJGL */
    protected static KeyPoller keyPoller;
    protected static MousePoller mousePoller;

    // ........................................................

    // Utility buffers to copy projection/modelview matrices to GL  

    protected FloatBuffer projMatrix;
    protected FloatBuffer mvMatrix;

    // ........................................................

    // Static initialization for some parameters that need to be different for
    // LWJGL

    static {
        MIN_DIRECT_BUFFER_SIZE = 16;
        INDEX_TYPE = GL11.GL_UNSIGNED_SHORT;
    }

    ///////////////////////////////////////////////////////////

    // Initialization, finalization

    public PLWJGL(PGraphicsOpenGL pg) {
        super(pg);
        if (glu == null)
            glu = new GLU();
    }

    public Canvas getCanvas() {
        return canvas;
    }

    protected void setFps(float fps) {
        if (!setFps || targetFps != fps) {
            if (60 < fps) {
                // Disables v-sync
                Display.setVSyncEnabled(false);
                Display.sync((int) fps);
            } else {
                Display.setVSyncEnabled(true);
            }
            targetFps = currentFps = fps;
            setFps = true;
        }
    }

    protected void initSurface(int antialias) {
        if (canvas != null) {
            keyPoller.requestStop();
            mousePoller.requestStop();

            try {
                Display.setParent(null);
            } catch (LWJGLException e) {
                e.printStackTrace();
            }
            Display.destroy();

            pg.parent.remove(canvas);
        }

        canvas = new Canvas();
        canvas.setFocusable(true);
        canvas.requestFocus();
        canvas.setBackground(new Color(pg.backgroundColor, true));
        canvas.setBounds(0, 0, pg.parent.width, pg.parent.height);

        pg.parent.setLayout(new BorderLayout());
        pg.parent.add(canvas, BorderLayout.CENTER);

        try {
            DisplayMode[] modes = Display.getAvailableDisplayModes();
            int bpp = 0;
            for (int i = 0; i < modes.length; i++) {
                bpp = PApplet.max(modes[i].getBitsPerPixel(), bpp);
            }

            PixelFormat format;
            if (USE_FBOLAYER_BY_DEFAULT) {
                format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, REQUESTED_DEPTH_BITS, REQUESTED_STENCIL_BITS,
                        1);
                reqNumSamples = qualityToSamples(antialias);
                fboLayerRequested = true;
            } else {
                format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, REQUESTED_DEPTH_BITS, REQUESTED_STENCIL_BITS,
                        antialias);
                fboLayerRequested = false;
            }

            Display.setDisplayMode(new DisplayMode(pg.parent.width, pg.parent.height));
            int argb = pg.backgroundColor;
            float r = ((argb >> 16) & 0xff) / 255.0f;
            float g = ((argb >> 8) & 0xff) / 255.0f;
            float b = ((argb) & 0xff) / 255.0f;
            Display.setInitialBackground(r, g, b);
            Display.setParent(canvas);
            Display.create(format);

            // Might be useful later to specify the context attributes.
            // http://lwjgl.org/javadoc/org/lwjgl/opengl/ContextAttribs.html
            //      ContextAttribs contextAtrributes = new ContextAttribs(4, 0);
            //      contextAtrributes.withForwardCompatible(true);
            //      contextAtrributes.withProfileCore(true);
            //      Display.create(pixelFormat, contextAtrributes);      
        } catch (LWJGLException e) {
            e.printStackTrace();
        }

        glContext = Display.getDrawable().hashCode();

        registerListeners();

        fboLayerCreated = false;
        fboLayerInUse = false;
        firstFrame = true;
        setFps = false;
    }

    protected void reinitSurface() {
    }

    protected void registerListeners() {
        keyPoller = new KeyPoller(pg.parent);
        keyPoller.start();

        mousePoller = new MousePoller(pg.parent);
        mousePoller.start();
    }

    ///////////////////////////////////////////////////////////

    // Frame rendering

    protected boolean canDraw() {
        return pg.initialized && pg.parent.isDisplayable();
    }

    protected void requestFocus() {
    }

    protected void requestDraw() {
        if (pg.initialized) {
            glThread = Thread.currentThread();
            pg.parent.handleDraw();
            Display.update();
        }
    }

    protected void swapBuffers() {
        try {
            Display.swapBuffers();
        } catch (LWJGLException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void beginGL() {
        if (projMatrix == null) {
            projMatrix = allocateFloatBuffer(16);
        }
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        projMatrix.rewind();
        projMatrix.put(pg.projection.m00);
        projMatrix.put(pg.projection.m10);
        projMatrix.put(pg.projection.m20);
        projMatrix.put(pg.projection.m30);
        projMatrix.put(pg.projection.m01);
        projMatrix.put(pg.projection.m11);
        projMatrix.put(pg.projection.m21);
        projMatrix.put(pg.projection.m31);
        projMatrix.put(pg.projection.m02);
        projMatrix.put(pg.projection.m12);
        projMatrix.put(pg.projection.m22);
        projMatrix.put(pg.projection.m32);
        projMatrix.put(pg.projection.m03);
        projMatrix.put(pg.projection.m13);
        projMatrix.put(pg.projection.m23);
        projMatrix.put(pg.projection.m33);
        projMatrix.rewind();
        GL11.glLoadMatrix(projMatrix);

        if (mvMatrix == null) {
            mvMatrix = allocateFloatBuffer(16);
        }
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        mvMatrix.rewind();
        mvMatrix.put(pg.modelview.m00);
        mvMatrix.put(pg.modelview.m10);
        mvMatrix.put(pg.modelview.m20);
        mvMatrix.put(pg.modelview.m30);
        mvMatrix.put(pg.modelview.m01);
        mvMatrix.put(pg.modelview.m11);
        mvMatrix.put(pg.modelview.m21);
        mvMatrix.put(pg.modelview.m31);
        mvMatrix.put(pg.modelview.m02);
        mvMatrix.put(pg.modelview.m12);
        mvMatrix.put(pg.modelview.m22);
        mvMatrix.put(pg.modelview.m32);
        mvMatrix.put(pg.modelview.m03);
        mvMatrix.put(pg.modelview.m13);
        mvMatrix.put(pg.modelview.m23);
        mvMatrix.put(pg.modelview.m33);
        mvMatrix.rewind();
        GL11.glLoadMatrix(mvMatrix);
    }

    ///////////////////////////////////////////////////////////

    // Utility functions

    protected static ByteBuffer allocateDirectByteBuffer(int size) {
        return BufferUtils.createByteBuffer(size);
    }

    protected static ShortBuffer allocateDirectShortBuffer(int size) {
        return BufferUtils.createShortBuffer(size);
    }

    protected static IntBuffer allocateDirectIntBuffer(int size) {
        return BufferUtils.createIntBuffer(size);
    }

    protected static FloatBuffer allocateDirectFloatBuffer(int size) {
        return BufferUtils.createFloatBuffer(size);
    }

    @Override
    protected int getFontAscent(Object font) {
        FontMetrics metrics = pg.parent.getFontMetrics((Font) font);
        return metrics.getAscent();
    }

    @Override
    protected int getFontDescent(Object font) {
        FontMetrics metrics = pg.parent.getFontMetrics((Font) font);
        return metrics.getDescent();
    }

    @Override
    protected int getTextWidth(Object font, char buffer[], int start, int stop) {
        // maybe should use one of the newer/fancier functions for this?
        int length = stop - start;
        FontMetrics metrics = pg.parent.getFontMetrics((Font) font);
        return metrics.charsWidth(buffer, start, length);
    }

    @Override
    protected Object getDerivedFont(Object font, float size) {
        return ((Font) font).deriveFont(size);
    }

    ///////////////////////////////////////////////////////////

    // LWJGL event handling

    protected class KeyPoller extends Thread {
        protected PApplet parent;
        protected boolean stopRequested;
        protected boolean[] pressedKeys;
        protected char[] charCheys;

        KeyPoller(PApplet parent) {
            this.parent = parent;
            stopRequested = false;
        }

        @Override
        public void run() {
            pressedKeys = new boolean[256];
            charCheys = new char[256];
            Keyboard.enableRepeatEvents(true);
            while (true) {
                if (stopRequested)
                    break;

                Keyboard.poll();
                while (Keyboard.next()) {
                    if (stopRequested)
                        break;

                    long millis = Keyboard.getEventNanoseconds() / 1000000L;
                    char keyChar = Keyboard.getEventCharacter();
                    int keyCode = Keyboard.getEventKey();

                    if (keyCode >= pressedKeys.length)
                        continue;

                    int modifiers = 0;
                    if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
                        modifiers |= Event.SHIFT;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
                        modifiers |= Event.CTRL;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
                        modifiers |= Event.META;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
                        // LWJGL maps the menu key and the alt key to the same value.
                        modifiers |= Event.ALT;
                    }

                    int keyPCode = LWJGLtoAWTCode(keyCode);
                    if (keyChar == 0) {
                        keyChar = PConstants.CODED;
                    }

                    int action = 0;
                    if (Keyboard.getEventKeyState()) {
                        action = KeyEvent.PRESS;
                        KeyEvent ke = new KeyEvent(null, millis, action, modifiers, keyChar, keyPCode);
                        parent.postEvent(ke);
                        pressedKeys[keyCode] = true;
                        charCheys[keyCode] = keyChar;
                        keyPCode = 0;
                        action = KeyEvent.TYPE;
                    } else if (pressedKeys[keyCode]) {
                        keyChar = charCheys[keyCode];
                        pressedKeys[keyCode] = false;
                        action = KeyEvent.RELEASE;
                    }

                    KeyEvent ke = new KeyEvent(null, millis, action, modifiers, keyChar, keyPCode);
                    parent.postEvent(ke);
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void requestStop() {
            stopRequested = true;
        }
    }

    protected class MousePoller extends Thread {
        protected PApplet parent;
        protected boolean stopRequested;
        protected boolean pressed;
        protected boolean inside;
        protected long startedClickTime;
        protected int startedClickButton;

        MousePoller(PApplet parent) {
            this.parent = parent;
            stopRequested = false;
        }

        @Override
        public void run() {
            while (true) {
                if (stopRequested)
                    break;

                Mouse.poll();
                while (Mouse.next()) {
                    if (stopRequested)
                        break;

                    long millis = Mouse.getEventNanoseconds() / 1000000L;

                    int modifiers = 0;
                    if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
                        modifiers |= Event.SHIFT;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
                        modifiers |= Event.CTRL;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) || Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
                        modifiers |= Event.META;
                    }
                    if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) || Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
                        // LWJGL maps the menu key and the alt key to the same value.
                        modifiers |= Event.ALT;
                    }

                    int x = Mouse.getX();
                    int y = parent.height - Mouse.getY();
                    int button = 0;
                    if (Mouse.isButtonDown(0)) {
                        button = PConstants.LEFT;
                    } else if (Mouse.isButtonDown(1)) {
                        button = PConstants.RIGHT;
                    } else if (Mouse.isButtonDown(2)) {
                        button = PConstants.CENTER;
                    }

                    int action = 0;
                    if (button != 0) {
                        if (pressed) {
                            action = MouseEvent.DRAG;
                        } else {
                            action = MouseEvent.PRESS;
                            pressed = true;
                        }
                    } else if (pressed) {
                        action = MouseEvent.RELEASE;
                        pressed = false;
                    } else {
                        action = MouseEvent.MOVE;
                    }

                    if (inside) {
                        if (!Mouse.isInsideWindow()) {
                            inside = false;
                            action = MouseEvent.EXIT;
                        }
                    } else {
                        if (Mouse.isInsideWindow()) {
                            inside = true;
                            action = MouseEvent.ENTER;
                        }
                    }

                    int count = 0;
                    if (Mouse.getEventButtonState()) {
                        startedClickTime = millis;
                        startedClickButton = button;
                    } else {
                        if (action == MouseEvent.RELEASE) {
                            boolean clickDetected = millis - startedClickTime < 500;
                            if (clickDetected) {
                                // post a RELEASE event, in addition to the CLICK event.
                                MouseEvent me = new MouseEvent(null, millis, action, modifiers, x, y, button,
                                        count);
                                parent.postEvent(me);
                                action = MouseEvent.CLICK;
                                count = 1;
                            }
                        }
                    }

                    MouseEvent me = new MouseEvent(null, millis, action, modifiers, x, y, button, count);
                    parent.postEvent(me);
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void requestStop() {
            stopRequested = true;
        }
    }

    // To complete later...
    // http://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html
    // http://processing.org/reference/keyCode.html
    protected int LWJGLtoAWTCode(int code) {
        switch (code) {
        case Keyboard.KEY_0:
            return java.awt.event.KeyEvent.VK_0;
        case Keyboard.KEY_1:
            return java.awt.event.KeyEvent.VK_1;
        case Keyboard.KEY_2:
            return java.awt.event.KeyEvent.VK_2;
        case Keyboard.KEY_3:
            return java.awt.event.KeyEvent.VK_3;
        case Keyboard.KEY_4:
            return java.awt.event.KeyEvent.VK_4;
        case Keyboard.KEY_5:
            return java.awt.event.KeyEvent.VK_5;
        case Keyboard.KEY_6:
            return java.awt.event.KeyEvent.VK_6;
        case Keyboard.KEY_7:
            return java.awt.event.KeyEvent.VK_7;
        case Keyboard.KEY_8:
            return java.awt.event.KeyEvent.VK_8;
        case Keyboard.KEY_9:
            return java.awt.event.KeyEvent.VK_9;
        case Keyboard.KEY_A:
            return java.awt.event.KeyEvent.VK_A;
        case Keyboard.KEY_B:
            return java.awt.event.KeyEvent.VK_B;
        case Keyboard.KEY_C:
            return java.awt.event.KeyEvent.VK_C;
        case Keyboard.KEY_D:
            return java.awt.event.KeyEvent.VK_D;
        case Keyboard.KEY_E:
            return java.awt.event.KeyEvent.VK_E;
        case Keyboard.KEY_F:
            return java.awt.event.KeyEvent.VK_F;
        case Keyboard.KEY_G:
            return java.awt.event.KeyEvent.VK_G;
        case Keyboard.KEY_H:
            return java.awt.event.KeyEvent.VK_H;
        case Keyboard.KEY_I:
            return java.awt.event.KeyEvent.VK_I;
        case Keyboard.KEY_J:
            return java.awt.event.KeyEvent.VK_J;
        case Keyboard.KEY_K:
            return java.awt.event.KeyEvent.VK_K;
        case Keyboard.KEY_L:
            return java.awt.event.KeyEvent.VK_L;
        case Keyboard.KEY_M:
            return java.awt.event.KeyEvent.VK_M;
        case Keyboard.KEY_N:
            return java.awt.event.KeyEvent.VK_N;
        case Keyboard.KEY_O:
            return java.awt.event.KeyEvent.VK_O;
        case Keyboard.KEY_P:
            return java.awt.event.KeyEvent.VK_P;
        case Keyboard.KEY_Q:
            return java.awt.event.KeyEvent.VK_Q;
        case Keyboard.KEY_R:
            return java.awt.event.KeyEvent.VK_R;
        case Keyboard.KEY_S:
            return java.awt.event.KeyEvent.VK_S;
        case Keyboard.KEY_T:
            return java.awt.event.KeyEvent.VK_T;
        case Keyboard.KEY_U:
            return java.awt.event.KeyEvent.VK_U;
        case Keyboard.KEY_V:
            return java.awt.event.KeyEvent.VK_V;
        case Keyboard.KEY_W:
            return java.awt.event.KeyEvent.VK_W;
        case Keyboard.KEY_X:
            return java.awt.event.KeyEvent.VK_X;
        case Keyboard.KEY_Y:
            return java.awt.event.KeyEvent.VK_Y;
        case Keyboard.KEY_Z:
            return java.awt.event.KeyEvent.VK_Z;
        case Keyboard.KEY_ADD:
            return java.awt.event.KeyEvent.VK_ADD;
        case Keyboard.KEY_APOSTROPHE:
            return java.awt.event.KeyEvent.VK_ASTERISK;
        case Keyboard.KEY_AT:
            return java.awt.event.KeyEvent.VK_AT;
        case Keyboard.KEY_BACK:
            return java.awt.event.KeyEvent.VK_BACK_SPACE;
        case Keyboard.KEY_BACKSLASH:
            return java.awt.event.KeyEvent.VK_BACK_SLASH;
        case Keyboard.KEY_CAPITAL:
            return java.awt.event.KeyEvent.VK_CAPS_LOCK;
        case Keyboard.KEY_CIRCUMFLEX:
            return java.awt.event.KeyEvent.VK_CIRCUMFLEX;
        case Keyboard.KEY_COLON:
            return java.awt.event.KeyEvent.VK_COLON;
        case Keyboard.KEY_COMMA:
            return java.awt.event.KeyEvent.VK_COMMA;
        case Keyboard.KEY_CONVERT:
            return java.awt.event.KeyEvent.VK_CONVERT;
        case Keyboard.KEY_DECIMAL:
            return java.awt.event.KeyEvent.VK_DECIMAL;
        case Keyboard.KEY_DELETE:
            return java.awt.event.KeyEvent.VK_DELETE;
        case Keyboard.KEY_DIVIDE:
            return java.awt.event.KeyEvent.VK_DIVIDE;
        case Keyboard.KEY_DOWN:
            return java.awt.event.KeyEvent.VK_DOWN;
        case Keyboard.KEY_END:
            return java.awt.event.KeyEvent.VK_END;
        case Keyboard.KEY_EQUALS:
            return java.awt.event.KeyEvent.VK_EQUALS;
        case Keyboard.KEY_ESCAPE:
            return java.awt.event.KeyEvent.VK_ESCAPE;
        case Keyboard.KEY_F1:
            return java.awt.event.KeyEvent.VK_F1;
        case Keyboard.KEY_F10:
            return java.awt.event.KeyEvent.VK_F10;
        case Keyboard.KEY_F11:
            return java.awt.event.KeyEvent.VK_F11;
        case Keyboard.KEY_F12:
            return java.awt.event.KeyEvent.VK_F12;
        case Keyboard.KEY_F13:
            return java.awt.event.KeyEvent.VK_F13;
        case Keyboard.KEY_F14:
            return java.awt.event.KeyEvent.VK_F14;
        case Keyboard.KEY_F15:
            return java.awt.event.KeyEvent.VK_F15;
        case Keyboard.KEY_F2:
            return java.awt.event.KeyEvent.VK_F2;
        case Keyboard.KEY_F3:
            return java.awt.event.KeyEvent.VK_F3;
        case Keyboard.KEY_F4:
            return java.awt.event.KeyEvent.VK_F4;
        case Keyboard.KEY_F5:
            return java.awt.event.KeyEvent.VK_F5;
        case Keyboard.KEY_F6:
            return java.awt.event.KeyEvent.VK_F6;
        case Keyboard.KEY_F7:
            return java.awt.event.KeyEvent.VK_F7;
        case Keyboard.KEY_F8:
            return java.awt.event.KeyEvent.VK_F8;
        case Keyboard.KEY_F9:
            return java.awt.event.KeyEvent.VK_F9;
        //    case Keyboard.KEY_GRAVE:
        case Keyboard.KEY_HOME:
            return java.awt.event.KeyEvent.VK_HOME;
        case Keyboard.KEY_INSERT:
            return java.awt.event.KeyEvent.VK_INSERT;
        case Keyboard.KEY_LBRACKET:
            return java.awt.event.KeyEvent.VK_BRACELEFT;
        case Keyboard.KEY_LCONTROL:
            return java.awt.event.KeyEvent.VK_CONTROL;
        case Keyboard.KEY_LEFT:
            return java.awt.event.KeyEvent.VK_LEFT;
        case Keyboard.KEY_LMENU:
            return java.awt.event.KeyEvent.VK_ALT;
        case Keyboard.KEY_LMETA:
            return java.awt.event.KeyEvent.VK_META;
        case Keyboard.KEY_LSHIFT:
            return java.awt.event.KeyEvent.VK_SHIFT;
        case Keyboard.KEY_MINUS:
            return java.awt.event.KeyEvent.VK_MINUS;
        case Keyboard.KEY_MULTIPLY:
            return java.awt.event.KeyEvent.VK_MULTIPLY;
        //    case Keyboard.KEY_NEXT:
        case Keyboard.KEY_NUMLOCK:
            return java.awt.event.KeyEvent.VK_NUM_LOCK;
        case Keyboard.KEY_NUMPAD0:
            return java.awt.event.KeyEvent.VK_NUMPAD0;
        case Keyboard.KEY_NUMPAD1:
            return java.awt.event.KeyEvent.VK_NUMPAD1;
        case Keyboard.KEY_NUMPAD2:
            return java.awt.event.KeyEvent.VK_NUMPAD2;
        case Keyboard.KEY_NUMPAD3:
            return java.awt.event.KeyEvent.VK_NUMPAD3;
        case Keyboard.KEY_NUMPAD4:
            return java.awt.event.KeyEvent.VK_NUMPAD4;
        case Keyboard.KEY_NUMPAD5:
            return java.awt.event.KeyEvent.VK_NUMPAD5;
        case Keyboard.KEY_NUMPAD6:
            return java.awt.event.KeyEvent.VK_NUMPAD6;
        case Keyboard.KEY_NUMPAD7:
            return java.awt.event.KeyEvent.VK_NUMPAD7;
        case Keyboard.KEY_NUMPAD8:
            return java.awt.event.KeyEvent.VK_NUMPAD8;
        case Keyboard.KEY_NUMPAD9:
            return java.awt.event.KeyEvent.VK_NUMPAD9;
        //    case Keyboard.KEY_NUMPADCOMMA:
        //    case Keyboard.KEY_NUMPADENTER:
        //    case Keyboard.KEY_NUMPADEQUALS:
        case Keyboard.KEY_PAUSE:
            return java.awt.event.KeyEvent.VK_PAUSE;
        case Keyboard.KEY_PERIOD:
            return java.awt.event.KeyEvent.VK_PERIOD;
        //    case Keyboard.KEY_POWER:
        //    case Keyboard.KEY_PRIOR:
        case Keyboard.KEY_RBRACKET:
            return java.awt.event.KeyEvent.VK_BRACERIGHT;
        case Keyboard.KEY_RCONTROL:
            return java.awt.event.KeyEvent.VK_CONTROL;
        case Keyboard.KEY_RETURN:
            return java.awt.event.KeyEvent.VK_ENTER;
        case Keyboard.KEY_RIGHT:
            return java.awt.event.KeyEvent.VK_RIGHT;
        //    case Keyboard.KEY_RMENU:
        case Keyboard.KEY_RMETA:
            return java.awt.event.KeyEvent.VK_META;
        case Keyboard.KEY_RSHIFT:
            return java.awt.event.KeyEvent.VK_SHIFT;
        //    case Keyboard.KEY_SCROLL:
        case Keyboard.KEY_SEMICOLON:
            return java.awt.event.KeyEvent.VK_SEMICOLON;
        case Keyboard.KEY_SLASH:
            return java.awt.event.KeyEvent.VK_SLASH;
        //    case Keyboard.KEY_SLEEP:
        case Keyboard.KEY_SPACE:
            return java.awt.event.KeyEvent.VK_SPACE;
        case Keyboard.KEY_STOP:
            return java.awt.event.KeyEvent.VK_STOP;
        case Keyboard.KEY_SUBTRACT:
            return java.awt.event.KeyEvent.VK_SUBTRACT;
        case Keyboard.KEY_TAB:
            return java.awt.event.KeyEvent.VK_TAB;
        //    case Keyboard.KEY_UNDERLINE:
        case Keyboard.KEY_UP:
            return java.awt.event.KeyEvent.VK_UP;
        default:
            return 0;
        }
    }

    ///////////////////////////////////////////////////////////

    // Tessellator interface

    protected Tessellator createTessellator(TessellatorCallback callback) {
        return new Tessellator(callback);
    }

    protected class Tessellator implements PGL.Tessellator {
        protected GLUtessellator tess;
        protected TessellatorCallback callback;
        protected GLUCallback gluCallback;

        public Tessellator(TessellatorCallback callback) {
            this.callback = callback;
            tess = GLU.gluNewTess();
            gluCallback = new GLUCallback();

            tess.gluTessCallback(GLU.GLU_TESS_BEGIN, gluCallback);
            tess.gluTessCallback(GLU.GLU_TESS_END, gluCallback);
            tess.gluTessCallback(GLU.GLU_TESS_VERTEX, gluCallback);
            tess.gluTessCallback(GLU.GLU_TESS_COMBINE, gluCallback);
            tess.gluTessCallback(GLU.GLU_TESS_ERROR, gluCallback);
        }

        public void beginPolygon() {
            tess.gluTessBeginPolygon(null);
        }

        public void endPolygon() {
            tess.gluTessEndPolygon();
        }

        public void setWindingRule(int rule) {
            tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, rule);
        }

        public void beginContour() {
            tess.gluTessBeginContour();
        }

        public void endContour() {
            tess.gluTessEndContour();
        }

        public void addVertex(double[] v) {
            tess.gluTessVertex(v, 0, v);
        }

        protected class GLUCallback extends GLUtessellatorCallbackAdapter {
            @Override
            public void begin(int type) {
                callback.begin(type);
            }

            @Override
            public void end() {
                callback.end();
            }

            @Override
            public void vertex(Object data) {
                callback.vertex(data);
            }

            @Override
            public void combine(double[] coords, Object[] data, float[] weight, Object[] outData) {
                callback.combine(coords, data, weight, outData);
            }

            @Override
            public void error(int errnum) {
                callback.error(errnum);
            }
        }
    }

    protected String tessError(int err) {
        return GLU.gluErrorString(err);
    }

    ///////////////////////////////////////////////////////////

    // Font outline

    static {
        SHAPE_TEXT_SUPPORTED = true;
        SEG_MOVETO = PathIterator.SEG_MOVETO;
        SEG_LINETO = PathIterator.SEG_LINETO;
        SEG_QUADTO = PathIterator.SEG_QUADTO;
        SEG_CUBICTO = PathIterator.SEG_CUBICTO;
        SEG_CLOSE = PathIterator.SEG_CLOSE;
    }

    protected FontOutline createFontOutline(char ch, Object font) {
        return new FontOutline(ch, font);
    }

    protected class FontOutline implements PGL.FontOutline {
        PathIterator iter;

        public FontOutline(char ch, Object font) {
            char textArray[] = new char[] { ch };
            Graphics2D graphics = (Graphics2D) pg.parent.getGraphics();
            FontRenderContext frc = graphics.getFontRenderContext();
            GlyphVector gv = ((Font) font).createGlyphVector(frc, textArray);
            Shape shp = gv.getOutline();
            iter = shp.getPathIterator(null);
        }

        public boolean isDone() {
            return iter.isDone();
        }

        public int currentSegment(float coords[]) {
            return iter.currentSegment(coords);
        }

        public void next() {
            iter.next();
        }
    }

    ///////////////////////////////////////////////////////////

    // Constants

    static {
        FALSE = GL11.GL_FALSE;
        TRUE = GL11.GL_TRUE;

        INT = GL11.GL_INT;
        BYTE = GL11.GL_BYTE;
        SHORT = GL11.GL_SHORT;
        FLOAT = GL11.GL_FLOAT;
        BOOL = GL20.GL_BOOL;
        UNSIGNED_INT = GL11.GL_UNSIGNED_INT;
        UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE;
        UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT;

        RGB = GL11.GL_RGB;
        RGBA = GL11.GL_RGBA;
        ALPHA = GL11.GL_ALPHA;
        LUMINANCE = GL11.GL_LUMINANCE;
        LUMINANCE_ALPHA = GL11.GL_LUMINANCE_ALPHA;

        UNSIGNED_SHORT_5_6_5 = GL12.GL_UNSIGNED_SHORT_5_6_5;
        UNSIGNED_SHORT_4_4_4_4 = GL12.GL_UNSIGNED_SHORT_4_4_4_4;
        UNSIGNED_SHORT_5_5_5_1 = GL12.GL_UNSIGNED_SHORT_5_5_5_1;

        RGBA4 = GL11.GL_RGBA4;
        RGB5_A1 = GL11.GL_RGB5_A1;
        RGB565 = ARBES2Compatibility.GL_RGB565;
        RGB8 = GL11.GL_RGB8;
        RGBA8 = GL11.GL_RGBA8;
        ALPHA8 = GL11.GL_ALPHA8;

        READ_ONLY = GL15.GL_READ_ONLY;
        WRITE_ONLY = GL15.GL_WRITE_ONLY;
        READ_WRITE = GL15.GL_READ_WRITE;

        TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO;
        TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD;

        GENERATE_MIPMAP_HINT = GL14.GL_GENERATE_MIPMAP_HINT;
        FASTEST = GL11.GL_FASTEST;
        NICEST = GL11.GL_NICEST;
        DONT_CARE = GL11.GL_DONT_CARE;

        VENDOR = GL11.GL_VENDOR;
        RENDERER = GL11.GL_RENDERER;
        VERSION = GL11.GL_VERSION;
        EXTENSIONS = GL11.GL_EXTENSIONS;
        SHADING_LANGUAGE_VERSION = GL20.GL_SHADING_LANGUAGE_VERSION;

        MAX_SAMPLES = GL30.GL_MAX_SAMPLES;
        SAMPLES = GL13.GL_SAMPLES;

        ALIASED_LINE_WIDTH_RANGE = GL12.GL_ALIASED_LINE_WIDTH_RANGE;
        ALIASED_POINT_SIZE_RANGE = GL12.GL_ALIASED_POINT_SIZE_RANGE;

        DEPTH_BITS = GL11.GL_DEPTH_BITS;
        STENCIL_BITS = GL11.GL_STENCIL_BITS;

        CCW = GL11.GL_CCW;
        CW = GL11.GL_CW;

        VIEWPORT = GL11.GL_VIEWPORT;

        ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER;
        ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER;

        MAX_VERTEX_ATTRIBS = GL20.GL_MAX_VERTEX_ATTRIBS;

        STATIC_DRAW = GL15.GL_STATIC_DRAW;
        DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW;
        STREAM_DRAW = GL15.GL_STREAM_DRAW;

        BUFFER_SIZE = GL15.GL_BUFFER_SIZE;
        BUFFER_USAGE = GL15.GL_BUFFER_USAGE;

        POINTS = GL11.GL_POINTS;
        LINE_STRIP = GL11.GL_LINE_STRIP;
        LINE_LOOP = GL11.GL_LINE_LOOP;
        LINES = GL11.GL_LINES;
        TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN;
        TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP;
        TRIANGLES = GL11.GL_TRIANGLES;

        CULL_FACE = GL11.GL_CULL_FACE;
        FRONT = GL11.GL_FRONT;
        BACK = GL11.GL_BACK;
        FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK;

        POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL;

        UNPACK_ALIGNMENT = GL11.GL_UNPACK_ALIGNMENT;
        PACK_ALIGNMENT = GL11.GL_PACK_ALIGNMENT;

        TEXTURE_2D = GL11.GL_TEXTURE_2D;
        TEXTURE_RECTANGLE = GL31.GL_TEXTURE_RECTANGLE;

        TEXTURE_BINDING_2D = GL11.GL_TEXTURE_BINDING_2D;
        TEXTURE_BINDING_RECTANGLE = GL31.GL_TEXTURE_BINDING_RECTANGLE;

        MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE;
        TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT;
        MAX_TEXTURE_MAX_ANISOTROPY = EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;

        MAX_VERTEX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
        MAX_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_TEXTURE_IMAGE_UNITS;
        MAX_COMBINED_TEXTURE_IMAGE_UNITS = GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;

        NUM_COMPRESSED_TEXTURE_FORMATS = GL13.GL_NUM_COMPRESSED_TEXTURE_FORMATS;
        COMPRESSED_TEXTURE_FORMATS = GL13.GL_COMPRESSED_TEXTURE_FORMATS;

        NEAREST = GL11.GL_NEAREST;
        LINEAR = GL11.GL_LINEAR;
        LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST;
        LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR;

        CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE;
        REPEAT = GL11.GL_REPEAT;

        TEXTURE0 = GL13.GL_TEXTURE0;
        TEXTURE1 = GL13.GL_TEXTURE1;
        TEXTURE2 = GL13.GL_TEXTURE2;
        TEXTURE3 = GL13.GL_TEXTURE3;
        TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER;
        TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER;
        TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S;
        TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T;
        TEXTURE_WRAP_R = GL12.GL_TEXTURE_WRAP_R;

        TEXTURE_CUBE_MAP = GL13.GL_TEXTURE_CUBE_MAP;
        TEXTURE_CUBE_MAP_POSITIVE_X = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_X;
        TEXTURE_CUBE_MAP_POSITIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
        TEXTURE_CUBE_MAP_POSITIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
        TEXTURE_CUBE_MAP_NEGATIVE_X = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
        TEXTURE_CUBE_MAP_NEGATIVE_Y = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
        TEXTURE_CUBE_MAP_NEGATIVE_Z = GL13.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;

        VERTEX_SHADER = GL20.GL_VERTEX_SHADER;
        FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER;
        INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH;
        SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH;
        COMPILE_STATUS = GL20.GL_COMPILE_STATUS;
        LINK_STATUS = GL20.GL_LINK_STATUS;
        VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS;
        SHADER_TYPE = GL20.GL_SHADER_TYPE;
        DELETE_STATUS = GL20.GL_DELETE_STATUS;

        FLOAT_VEC2 = GL20.GL_FLOAT_VEC2;
        FLOAT_VEC3 = GL20.GL_FLOAT_VEC3;
        FLOAT_VEC4 = GL20.GL_FLOAT_VEC4;
        FLOAT_MAT2 = GL20.GL_FLOAT_MAT2;
        FLOAT_MAT3 = GL20.GL_FLOAT_MAT3;
        FLOAT_MAT4 = GL20.GL_FLOAT_MAT4;
        INT_VEC2 = GL20.GL_INT_VEC2;
        INT_VEC3 = GL20.GL_INT_VEC3;
        INT_VEC4 = GL20.GL_INT_VEC4;
        BOOL_VEC2 = GL20.GL_BOOL_VEC2;
        BOOL_VEC3 = GL20.GL_BOOL_VEC3;
        BOOL_VEC4 = GL20.GL_BOOL_VEC4;
        SAMPLER_2D = GL20.GL_SAMPLER_2D;
        SAMPLER_CUBE = GL20.GL_SAMPLER_CUBE;

        LOW_FLOAT = ARBES2Compatibility.GL_LOW_FLOAT;
        MEDIUM_FLOAT = ARBES2Compatibility.GL_MEDIUM_FLOAT;
        HIGH_FLOAT = ARBES2Compatibility.GL_HIGH_FLOAT;
        LOW_INT = ARBES2Compatibility.GL_LOW_INT;
        MEDIUM_INT = ARBES2Compatibility.GL_MEDIUM_INT;
        HIGH_INT = ARBES2Compatibility.GL_HIGH_INT;

        CURRENT_VERTEX_ATTRIB = GL20.GL_CURRENT_VERTEX_ATTRIB;

        VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = GL15.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING;
        VERTEX_ATTRIB_ARRAY_ENABLED = GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED;
        VERTEX_ATTRIB_ARRAY_SIZE = GL20.GL_VERTEX_ATTRIB_ARRAY_SIZE;
        VERTEX_ATTRIB_ARRAY_STRIDE = GL20.GL_VERTEX_ATTRIB_ARRAY_STRIDE;
        VERTEX_ATTRIB_ARRAY_TYPE = GL20.GL_VERTEX_ATTRIB_ARRAY_TYPE;
        VERTEX_ATTRIB_ARRAY_NORMALIZED = GL20.GL_VERTEX_ATTRIB_ARRAY_NORMALIZED;
        VERTEX_ATTRIB_ARRAY_POINTER = GL20.GL_VERTEX_ATTRIB_ARRAY_POINTER;

        BLEND = GL11.GL_BLEND;
        ONE = GL11.GL_ONE;
        ZERO = GL11.GL_ZERO;
        SRC_ALPHA = GL11.GL_SRC_ALPHA;
        DST_ALPHA = GL11.GL_DST_ALPHA;
        ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA;
        ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR;
        ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR;
        DST_COLOR = GL11.GL_DST_COLOR;
        SRC_COLOR = GL11.GL_SRC_COLOR;

        SAMPLE_ALPHA_TO_COVERAGE = GL13.GL_SAMPLE_ALPHA_TO_COVERAGE;
        SAMPLE_COVERAGE = GL13.GL_SAMPLE_COVERAGE;

        KEEP = GL11.GL_KEEP;
        REPLACE = GL11.GL_REPLACE;
        INCR = GL11.GL_INCR;
        DECR = GL11.GL_DECR;
        INVERT = GL11.GL_INVERT;
        INCR_WRAP = GL14.GL_INCR_WRAP;
        DECR_WRAP = GL14.GL_DECR_WRAP;
        NEVER = GL11.GL_NEVER;
        ALWAYS = GL11.GL_ALWAYS;

        EQUAL = GL11.GL_EQUAL;
        LESS = GL11.GL_LESS;
        LEQUAL = GL11.GL_LEQUAL;
        GREATER = GL11.GL_GREATER;
        GEQUAL = GL11.GL_GEQUAL;
        NOTEQUAL = GL11.GL_NOTEQUAL;

        FUNC_ADD = GL14.GL_FUNC_ADD;
        FUNC_MIN = GL14.GL_MIN;
        FUNC_MAX = GL14.GL_MAX;
        FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT;
        FUNC_SUBTRACT = GL14.GL_FUNC_SUBTRACT;

        DITHER = GL11.GL_DITHER;

        CONSTANT_COLOR = GL11.GL_CONSTANT_COLOR;
        CONSTANT_ALPHA = GL11.GL_CONSTANT_ALPHA;
        ONE_MINUS_CONSTANT_COLOR = GL11.GL_ONE_MINUS_CONSTANT_COLOR;
        ONE_MINUS_CONSTANT_ALPHA = GL11.GL_ONE_MINUS_CONSTANT_ALPHA;
        SRC_ALPHA_SATURATE = GL11.GL_SRC_ALPHA_SATURATE;

        SCISSOR_TEST = GL11.GL_SCISSOR_TEST;
        STENCIL_TEST = GL11.GL_STENCIL_TEST;
        DEPTH_TEST = GL11.GL_DEPTH_TEST;
        DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK;
        ALPHA_TEST = GL11.GL_ALPHA_TEST;

        COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT;
        DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT;
        STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT;

        FRAMEBUFFER = GL30.GL_FRAMEBUFFER;
        COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0;
        COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1;
        COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2;
        COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3;
        RENDERBUFFER = GL30.GL_RENDERBUFFER;
        DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT;
        STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT;
        READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER;
        DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER;

        DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8;

        DEPTH_COMPONENT = GL11.GL_DEPTH_COMPONENT;
        DEPTH_COMPONENT16 = GL14.GL_DEPTH_COMPONENT16;
        DEPTH_COMPONENT24 = GL14.GL_DEPTH_COMPONENT24;
        DEPTH_COMPONENT32 = GL14.GL_DEPTH_COMPONENT32;

        STENCIL_INDEX = GL11.GL_STENCIL_INDEX;
        STENCIL_INDEX1 = GL30.GL_STENCIL_INDEX1;
        STENCIL_INDEX4 = GL30.GL_STENCIL_INDEX4;
        STENCIL_INDEX8 = GL30.GL_STENCIL_INDEX8;

        DEPTH_STENCIL = GL30.GL_DEPTH_STENCIL;

        FRAMEBUFFER_COMPLETE = GL30.GL_FRAMEBUFFER_COMPLETE;
        FRAMEBUFFER_INCOMPLETE_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
        FRAMEBUFFER_INCOMPLETE_DIMENSIONS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
        FRAMEBUFFER_INCOMPLETE_FORMATS = EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
        FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
        FRAMEBUFFER_INCOMPLETE_READ_BUFFER = GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
        FRAMEBUFFER_UNSUPPORTED = GL30.GL_FRAMEBUFFER_UNSUPPORTED;

        FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE;
        FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = GL30.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
        FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL;
        FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = GL30.GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE;

        RENDERBUFFER_WIDTH = GL30.GL_RENDERBUFFER_WIDTH;
        RENDERBUFFER_HEIGHT = GL30.GL_RENDERBUFFER_HEIGHT;
        RENDERBUFFER_RED_SIZE = GL30.GL_RENDERBUFFER_RED_SIZE;
        RENDERBUFFER_GREEN_SIZE = GL30.GL_RENDERBUFFER_GREEN_SIZE;
        RENDERBUFFER_BLUE_SIZE = GL30.GL_RENDERBUFFER_BLUE_SIZE;
        RENDERBUFFER_ALPHA_SIZE = GL30.GL_RENDERBUFFER_ALPHA_SIZE;
        RENDERBUFFER_DEPTH_SIZE = GL30.GL_RENDERBUFFER_DEPTH_SIZE;
        RENDERBUFFER_STENCIL_SIZE = GL30.GL_RENDERBUFFER_STENCIL_SIZE;
        RENDERBUFFER_INTERNAL_FORMAT = GL30.GL_RENDERBUFFER_INTERNAL_FORMAT;

        MULTISAMPLE = GL13.GL_MULTISAMPLE;
        POINT_SMOOTH = GL11.GL_POINT_SMOOTH;
        LINE_SMOOTH = GL11.GL_LINE_SMOOTH;
        POLYGON_SMOOTH = GL11.GL_POLYGON_SMOOTH;
    }

    ///////////////////////////////////////////////////////////

    // Special Functions

    public void flush() {
        GL11.glFlush();
    }

    public void finish() {
        GL11.glFinish();
    }

    public void hint(int target, int hint) {
        GL11.glHint(target, hint);
    }

    ///////////////////////////////////////////////////////////

    // State and State Requests

    public void enable(int value) {
        if (-1 < value) {
            GL11.glEnable(value);
        }
    }

    public void disable(int value) {
        if (-1 < value) {
            GL11.glDisable(value);
        }
    }

    public void getBooleanv(int value, IntBuffer data) {
        if (-1 < value) {
            if (byteBuffer.capacity() < data.capacity()) {
                byteBuffer = allocateDirectByteBuffer(data.capacity());
            }
            GL11.glGetBoolean(value, byteBuffer);
            for (int i = 0; i < data.capacity(); i++) {
                data.put(i, byteBuffer.get(i));
            }
        } else {
            fillIntBuffer(data, 0, data.capacity() - 1, 0);
        }
    }

    public void getIntegerv(int value, IntBuffer data) {
        if (-1 < value) {
            GL11.glGetInteger(value, data);
        } else {
            fillIntBuffer(data, 0, data.capacity() - 1, 0);
        }
    }

    public void getFloatv(int value, FloatBuffer data) {
        if (-1 < value) {
            GL11.glGetFloat(value, data);
        } else {
            fillFloatBuffer(data, 0, data.capacity() - 1, 0);
        }
    }

    public boolean isEnabled(int value) {
        return GL11.glIsEnabled(value);
    }

    public String getString(int name) {
        return GL11.glGetString(name);
    }

    ///////////////////////////////////////////////////////////

    // Error Handling

    public int getError() {
        return GL11.glGetError();
    }

    public String errorString(int err) {
        return GLU.gluErrorString(err);
    }

    //////////////////////////////////////////////////////////////////////////////

    // Buffer Objects

    public void genBuffers(int n, IntBuffer buffers) {
        GL15.glGenBuffers(buffers);
    }

    public void deleteBuffers(int n, IntBuffer buffers) {
        GL15.glDeleteBuffers(buffers);
    }

    public void bindBuffer(int target, int buffer) {
        GL15.glBindBuffer(target, buffer);
    }

    public void bufferData(int target, int size, Buffer data, int usage) {
        if (data == null) {
            FloatBuffer empty = BufferUtils.createFloatBuffer(size);
            GL15.glBufferData(target, empty, usage);
        } else {
            if (data instanceof ByteBuffer) {
                GL15.glBufferData(target, (ByteBuffer) data, usage);
            } else if (data instanceof ShortBuffer) {
                GL15.glBufferData(target, (ShortBuffer) data, usage);
            } else if (data instanceof IntBuffer) {
                GL15.glBufferData(target, (IntBuffer) data, usage);
            } else if (data instanceof FloatBuffer) {
                GL15.glBufferData(target, (FloatBuffer) data, usage);
            }
        }
    }

    public void bufferSubData(int target, int offset, int size, Buffer data) {
        if (data instanceof ByteBuffer) {
            GL15.glBufferSubData(target, offset, (ByteBuffer) data);
        } else if (data instanceof ShortBuffer) {
            GL15.glBufferSubData(target, offset, (ShortBuffer) data);
        } else if (data instanceof IntBuffer) {
            GL15.glBufferSubData(target, offset, (IntBuffer) data);
        } else if (data instanceof FloatBuffer) {
            GL15.glBufferSubData(target, offset, (FloatBuffer) data);
        }
    }

    public void isBuffer(int buffer) {
        GL15.glIsBuffer(buffer);
    }

    public void getBufferParameteriv(int target, int value, IntBuffer data) {
        if (-1 < value) {
            int res = GL15.glGetBufferParameteri(target, value);
            data.put(0, res);
        } else {
            data.put(0, 0);
        }
    }

    public ByteBuffer mapBuffer(int target, int access) {
        return GL15.glMapBuffer(target, access, null);
    }

    public ByteBuffer mapBufferRange(int target, int offset, int length, int access) {
        return GL30.glMapBufferRange(target, offset, length, access, null);
    }

    public void unmapBuffer(int target) {
        GL15.glUnmapBuffer(target);
    }

    //////////////////////////////////////////////////////////////////////////////

    // Viewport and Clipping

    public void depthRangef(float n, float f) {
        GL11.glDepthRange(n, f);
    }

    public void viewport(int x, int y, int w, int h) {
        GL11.glViewport(x, y, w, h);
    }

    //////////////////////////////////////////////////////////////////////////////

    // Reading Pixels

    protected void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer) {
        GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer) buffer);
    }

    //////////////////////////////////////////////////////////////////////////////

    // Vertices

    public void vertexAttrib1f(int index, float value) {
        GL20.glVertexAttrib1f(index, value);
    }

    public void vertexAttrib2f(int index, float value0, float value1) {
        GL20.glVertexAttrib2f(index, value0, value1);
    }

    public void vertexAttrib3f(int index, float value0, float value1, float value2) {
        GL20.glVertexAttrib3f(index, value0, value1, value2);
    }

    public void vertexAttrib4f(int index, float value0, float value1, float value2, float value3) {
        GL20.glVertexAttrib4f(index, value0, value1, value2, value3);
    }

    public void vertexAttrib1fv(int index, FloatBuffer values) {
        GL20.glVertexAttrib1f(index, values.get());
    }

    public void vertexAttrib2fv(int index, FloatBuffer values) {
        GL20.glVertexAttrib2f(index, values.get(), values.get());
    }

    public void vertexAttrib3fv(int index, FloatBuffer values) {
        GL20.glVertexAttrib3f(index, values.get(), values.get(), values.get());
    }

    public void vertexAttri4fv(int index, FloatBuffer values) {
        GL20.glVertexAttrib4f(index, values.get(), values.get(), values.get(), values.get());
    }

    public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset) {
        GL20.glVertexAttribPointer(index, size, type, normalized, stride, offset);
    }

    public void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data) {
        if (type == UNSIGNED_INT) {
            GL20.glVertexAttribPointer(index, size, true, normalized, stride, (IntBuffer) data);
        } else if (type == UNSIGNED_BYTE) {
            GL20.glVertexAttribPointer(index, size, true, normalized, stride, (ByteBuffer) data);
        } else if (type == UNSIGNED_SHORT) {
            GL20.glVertexAttribPointer(index, size, true, normalized, stride, (ShortBuffer) data);
        } else if (type == FLOAT) {
            GL20.glVertexAttribPointer(index, size, normalized, stride, (FloatBuffer) data);
        }
    }

    public void enableVertexAttribArray(int index) {
        GL20.glEnableVertexAttribArray(index);
    }

    public void disableVertexAttribArray(int index) {
        GL20.glDisableVertexAttribArray(index);
    }

    public void drawArrays(int mode, int first, int count) {
        GL11.glDrawArrays(mode, first, count);
    }

    public void drawElements(int mode, int count, int type, int offset) {
        GL11.glDrawElements(mode, count, type, offset);
    }

    public void drawElements(int mode, int count, int type, Buffer indices) {
        if (type == UNSIGNED_INT) {
            GL11.glDrawElements(mode, (IntBuffer) indices);
        } else if (type == UNSIGNED_BYTE) {
            GL11.glDrawElements(mode, (ByteBuffer) indices);
        } else if (type == UNSIGNED_SHORT) {
            GL11.glDrawElements(mode, (ShortBuffer) indices);
        }
    }

    //////////////////////////////////////////////////////////////////////////////

    // Rasterization

    public void lineWidth(float width) {
        GL11.glLineWidth(width);
    }

    public void frontFace(int dir) {
        GL11.glFrontFace(dir);
    }

    public void cullFace(int mode) {
        GL11.glCullFace(mode);
    }

    public void polygonOffset(float factor, float units) {
        GL11.glPolygonOffset(factor, units);
    }

    //////////////////////////////////////////////////////////////////////////////

    // Pixel Rectangles

    public void pixelStorei(int pname, int param) {
        GL11.glPixelStorei(pname, param);
    }

    ///////////////////////////////////////////////////////////

    // Texturing

    public void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format,
            int type, Buffer data) {
        GL11.glTexImage2D(target, level, internalFormat, width, height, border, format, type, (IntBuffer) data);
    }

    public void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height,
            int border) {
        GL11.glCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
    }

    public void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format,
            int type, Buffer data) {
        GL11.glTexSubImage2D(target, level, xOffset, yOffset, width, height, format, type, (IntBuffer) data);
    }

    public void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width,
            int height) {
        GL11.glCopyTexSubImage2D(target, level, x, y, xOffset, yOffset, width, height);
    }

    public void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border,
            int imageSize, Buffer data) {
        GL13.glCompressedTexImage2D(target, level, internalFormat, width, height, border, (ByteBuffer) data);
    }

    public void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height,
            int format, int imageSize, Buffer data) {
        GL13.glCompressedTexSubImage2D(target, level, xOffset, yOffset, width, height, format, (ByteBuffer) data);
    }

    public void texParameteri(int target, int pname, int param) {
        GL11.glTexParameteri(target, pname, param);
    }

    public void texParameterf(int target, int pname, float param) {
        GL11.glTexParameterf(target, pname, param);
    }

    public void texParameteriv(int target, int pname, IntBuffer params) {
        GL11.glTexParameteri(target, pname, params.get());
    }

    public void texParameterfv(int target, int pname, FloatBuffer params) {
        GL11.glTexParameterf(target, pname, params.get());
    }

    public void generateMipmap(int target) {
        GL30.glGenerateMipmap(target);
    }

    public void genTextures(int n, IntBuffer textures) {
        GL11.glGenTextures(textures);
    }

    public void deleteTextures(int n, IntBuffer textures) {
        GL11.glDeleteTextures(textures);
    }

    public void getTexParameteriv(int target, int pname, IntBuffer params) {
        GL11.glGetTexParameter(target, pname, params);
    }

    public void getTexParameterfv(int target, int pname, FloatBuffer params) {
        GL11.glGetTexParameter(target, pname, params);
    }

    public boolean isTexture(int texture) {
        return GL11.glIsTexture(texture);
    }

    protected void activeTextureImpl(int texture) {
        GL13.glActiveTexture(texture);
    }

    protected void bindTextureImpl(int target, int texture) {
        GL11.glBindTexture(target, texture);
    }

    ///////////////////////////////////////////////////////////

    // Shaders and Programs

    public int createShader(int type) {
        return GL20.glCreateShader(type);
    }

    public void shaderSource(int shader, String source) {
        GL20.glShaderSource(shader, source);
    }

    public void compileShader(int shader) {
        GL20.glCompileShader(shader);
    }

    public void releaseShaderCompiler() {
        throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glReleaseShaderCompiler()"));
    }

    public void deleteShader(int shader) {
        GL20.glDeleteShader(shader);
    }

    public void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length) {
        throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glShaderBinary()"));
    }

    public int createProgram() {
        return GL20.glCreateProgram();
    }

    public void attachShader(int program, int shader) {
        GL20.glAttachShader(program, shader);
    }

    public void detachShader(int program, int shader) {
        GL20.glDetachShader(program, shader);
    }

    public void linkProgram(int program) {
        GL20.glLinkProgram(program);
    }

    public void useProgram(int program) {
        GL20.glUseProgram(program);
    }

    public void deleteProgram(int program) {
        GL20.glDeleteProgram(program);
    }

    public String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type) {
        IntBuffer typeTmp = BufferUtils.createIntBuffer(2);
        String name = GL20.glGetActiveAttrib(program, index, 256, typeTmp);
        size.put(typeTmp.get(0));
        type.put(typeTmp.get(1));
        return name;
    }

    public int getAttribLocation(int program, String name) {
        return GL20.glGetAttribLocation(program, name);
    }

    public void bindAttribLocation(int program, int index, String name) {
        GL20.glBindAttribLocation(program, index, name);
    }

    public int getUniformLocation(int program, String name) {
        return GL20.glGetUniformLocation(program, name);
    }

    public String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type) {
        IntBuffer typeTmp = BufferUtils.createIntBuffer(2);
        String name = GL20.glGetActiveUniform(program, index, 256, typeTmp);
        type.put(typeTmp.get(0));
        return name;
    }

    public void uniform1i(int location, int value) {
        GL20.glUniform1i(location, value);
    }

    public void uniform2i(int location, int value0, int value1) {
        GL20.glUniform2i(location, value0, value1);
    }

    public void uniform3i(int location, int value0, int value1, int value2) {
        GL20.glUniform3i(location, value0, value1, value2);
    }

    public void uniform4i(int location, int value0, int value1, int value2, int value3) {
        GL20.glUniform4i(location, value0, value1, value2, value3);
    }

    public void uniform1f(int location, float value) {
        GL20.glUniform1f(location, value);
    }

    public void uniform2f(int location, float value0, float value1) {
        GL20.glUniform2f(location, value0, value1);
    }

    public void uniform3f(int location, float value0, float value1, float value2) {
        GL20.glUniform3f(location, value0, value1, value2);
    }

    public void uniform4f(int location, float value0, float value1, float value2, float value3) {
        GL20.glUniform4f(location, value0, value1, value2, value3);
    }

    public void uniform1iv(int location, int count, IntBuffer v) {
        v.limit(count);
        GL20.glUniform1(location, v);
        v.clear();
    }

    public void uniform2iv(int location, int count, IntBuffer v) {
        v.limit(count);
        GL20.glUniform2(location, v);
        v.clear();
    }

    public void uniform3iv(int location, int count, IntBuffer v) {
        v.limit(count);
        GL20.glUniform3(location, v);
        v.clear();
    }

    public void uniform4iv(int location, int count, IntBuffer v) {
        v.limit(count);
        GL20.glUniform4(location, v);
        v.clear();
    }

    public void uniform1fv(int location, int count, FloatBuffer v) {
        v.limit(count);
        GL20.glUniform1(location, v);
        v.clear();
    }

    public void uniform2fv(int location, int count, FloatBuffer v) {
        v.limit(count);
        GL20.glUniform2(location, v);
        v.clear();
    }

    public void uniform3fv(int location, int count, FloatBuffer v) {
        v.limit(count);
        GL20.glUniform3(location, v);
        v.clear();
    }

    public void uniform4fv(int location, int count, FloatBuffer v) {
        v.limit(count);
        GL20.glUniform4(location, v);
        v.clear();
    }

    public void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat) {
        mat.limit(4);
        GL20.glUniformMatrix2(location, transpose, mat);
        mat.clear();
    }

    public void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat) {
        mat.limit(9);
        GL20.glUniformMatrix3(location, transpose, mat);
        mat.clear();
    }

    public void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat) {
        mat.limit(16);
        GL20.glUniformMatrix4(location, transpose, mat);
        mat.clear();
    }

    public void validateProgram(int program) {
        GL20.glValidateProgram(program);
    }

    public boolean isShader(int shader) {
        return GL20.glIsShader(shader);
    }

    public void getShaderiv(int shader, int pname, IntBuffer params) {
        GL20.glGetShader(shader, pname, params);
    }

    public void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders) {
        GL20.glGetAttachedShaders(program, count, shaders);
    }

    public String getShaderInfoLog(int shader) {
        int len = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
        return GL20.glGetShaderInfoLog(shader, len);
    }

    public String getShaderSource(int shader) {
        int len = GL20.glGetShaderi(shader, GL20.GL_SHADER_SOURCE_LENGTH);
        return GL20.glGetShaderSource(shader, len);
    }

    public void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision) {
        throw new RuntimeException(String.format(MISSING_GLFUNC_ERROR, "glGetShaderPrecisionFormat()"));
    }

    public void getVertexAttribfv(int index, int pname, FloatBuffer params) {
        GL20.glGetVertexAttrib(index, pname, params);
    }

    public void getVertexAttribiv(int index, int pname, IntBuffer params) {
        GL20.glGetVertexAttrib(index, pname, params);
    }

    public void getVertexAttribPointerv(int index, int pname, ByteBuffer data) {
        int len = data.capacity();
        ByteBuffer res = GL20.glGetVertexAttribPointer(index, pname, len);
        data.put(res);
    }

    public void getUniformfv(int program, int location, FloatBuffer params) {
        GL20.glGetUniform(program, location, params);
    }

    public void getUniformiv(int program, int location, IntBuffer params) {
        GL20.glGetUniform(program, location, params);
    }

    public boolean isProgram(int program) {
        return GL20.glIsProgram(program);
    }

    public void getProgramiv(int program, int pname, IntBuffer params) {
        GL20.glGetProgram(program, pname, params);
    }

    public String getProgramInfoLog(int program) {
        int len = GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH);
        return GL20.glGetProgramInfoLog(program, len);
    }

    ///////////////////////////////////////////////////////////

    // Per-Fragment Operations

    public void scissor(int x, int y, int w, int h) {
        GL11.glScissor(x, y, w, h);
    }

    public void sampleCoverage(float value, boolean invert) {
        GL13.glSampleCoverage(value, invert);
    }

    public void stencilFunc(int func, int ref, int mask) {
        GL11.glStencilFunc(func, ref, mask);
    }

    public void stencilFuncSeparate(int face, int func, int ref, int mask) {
        GL20.glStencilFuncSeparate(face, func, ref, mask);
    }

    public void stencilOp(int sfail, int dpfail, int dppass) {
        GL11.glStencilOp(sfail, dpfail, dppass);
    }

    public void stencilOpSeparate(int face, int sfail, int dpfail, int dppass) {
        GL20.glStencilOpSeparate(face, sfail, dpfail, dppass);
    }

    public void depthFunc(int func) {
        GL11.glDepthFunc(func);
    }

    public void blendEquation(int mode) {
        GL14.glBlendEquation(mode);
    }

    public void blendEquationSeparate(int modeRGB, int modeAlpha) {
        GL20.glBlendEquationSeparate(modeRGB, modeAlpha);
    }

    public void blendFunc(int src, int dst) {
        GL11.glBlendFunc(src, dst);
    }

    public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
        GL14.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
    }

    public void blendColor(float red, float green, float blue, float alpha) {
        GL14.glBlendColor(red, green, blue, alpha);
    }

    public void alphaFunc(int func, float ref) {
        GL11.glAlphaFunc(func, ref);
    }

    ///////////////////////////////////////////////////////////

    // Whole Framebuffer Operations

    public void colorMask(boolean r, boolean g, boolean b, boolean a) {
        GL11.glColorMask(r, g, b, a);
    }

    public void depthMask(boolean mask) {
        GL11.glDepthMask(mask);
    }

    public void stencilMask(int mask) {
        GL11.glStencilMask(mask);
    }

    public void stencilMaskSeparate(int face, int mask) {
        GL20.glStencilMaskSeparate(face, mask);
    }

    public void clear(int buf) {
        GL11.glClear(buf);
    }

    public void clearColor(float r, float g, float b, float a) {
        GL11.glClearColor(r, g, b, a);
    }

    public void clearDepth(float d) {
        GL11.glClearDepth(d);
    }

    public void clearStencil(int s) {
        GL11.glClearStencil(s);
    }

    ///////////////////////////////////////////////////////////

    // Framebuffers Objects

    protected void bindFramebufferImpl(int target, int framebuffer) {
        GL30.glBindFramebuffer(target, framebuffer);
    }

    public void deleteFramebuffers(int n, IntBuffer framebuffers) {
        GL30.glDeleteFramebuffers(framebuffers);
    }

    public void genFramebuffers(int n, IntBuffer framebuffers) {
        GL30.glGenFramebuffers(framebuffers);
    }

    public void bindRenderbuffer(int target, int renderbuffer) {
        GL30.glBindRenderbuffer(target, renderbuffer);
    }

    public void deleteRenderbuffers(int n, IntBuffer renderbuffers) {
        GL30.glDeleteRenderbuffers(renderbuffers);
    }

    public void genRenderbuffers(int n, IntBuffer renderbuffers) {
        GL30.glGenRenderbuffers(renderbuffers);
    }

    public void renderbufferStorage(int target, int internalFormat, int width, int height) {
        GL30.glRenderbufferStorage(target, internalFormat, width, height);
    }

    public void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer) {
        GL30.glFramebufferRenderbuffer(target, attachment, rendbuferfTarget, renderbuffer);
    }

    public void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level) {
        GL30.glFramebufferTexture2D(target, attachment, texTarget, texture, level);
    }

    public int checkFramebufferStatus(int target) {
        return GL30.glCheckFramebufferStatus(target);
    }

    public boolean isFramebuffer(int framebuffer) {
        return GL30.glIsFramebuffer(framebuffer);
    }

    public void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params) {
        GL30.glGetFramebufferAttachmentParameter(target, attachment, pname, params);
    }

    public boolean isRenderbuffer(int renderbuffer) {
        return GL30.glIsRenderbuffer(renderbuffer);
    }

    public void getRenderbufferParameteriv(int target, int pname, IntBuffer params) {
        GL30.glGetRenderbufferParameter(target, pname, params);
    }

    public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1,
            int dstY1, int mask, int filter) {
        GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
    }

    public void renderbufferStorageMultisample(int target, int samples, int format, int width, int height) {
        GL30.glRenderbufferStorageMultisample(target, samples, format, width, height);
    }

    public void readBuffer(int buf) {
        GL11.glReadBuffer(buf);
    }

    public void drawBuffer(int buf) {
        GL11.glDrawBuffer(buf);
    }

    @Override
    protected void getGL(PGL pgl) {
    }
}