opengl pixel perfect blitting [stand alone working example]

Started by ouattwtym, March 03, 2011, 13:00:59

Previous topic - Next topic

ouattwtym

import java.nio.ByteBuffer;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

/**
 * <p>An example of pixel perfect blitting with proper alpha "masking" onto
 * an <b>existing</b> background. No dependencies except for lwjgl itself.
 * 
 * <p>A big improvement on 
 * <a href="http://lwjgl.org/wiki/index.php?title=Slick-Util_Library_-_Part_1_-_Loading_Images_for_LWJGL">this</a>
 * which
 * <ul>
 * <li>loads an external file
 * <li>isn't pixel perfect
 * <li>doesn't mask onto an existing background but just onto a colour they select(?!)
 * </ul>
 * 
 * <p>provided entirely free (MIT license) with the hope that it is useful.
 */
public class OpenGlBlitExample {
	private static final int SCREEN_HEIGHT = 200;
	private static final int SCREEN_WIDTH = 300;

	private static final int TEXTURE_WIDTH = 32;
	private static final int TEXTURE_HEIGHT = 32;

	private int textureId;

	private void initLwjglDisplay() {
		try {
			Display.setDisplayMode(new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT));
			Display.create();
			Display.setVSyncEnabled(true);
		}
		catch (LWJGLException e) {
			throw new RuntimeException(e);
		}
	}
	private void resetOpenGl() {
		GL11.glDisable(GL11.GL_BLEND);
		GL11.glDisable(GL11.GL_DITHER);
		GL11.glDisable(GL11.GL_FOG);
		GL11.glDisable(GL11.GL_LIGHTING);
		GL11.glDisable(GL11.GL_TEXTURE_1D);
		GL11.glDisable(GL11.GL_TEXTURE_2D);
		GL11.glShadeModel(GL11.GL_FLAT);
	}

	private void initOpenGL() {
		resetOpenGl();
		
		GL11.glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
		
		GL11.glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
	
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		GL11.glOrtho(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 1, -1);
		GL11.glMatrixMode(GL11.GL_MODELVIEW);
	}
	private void initTexture() {
		// generate a texture that is a blue triangle
		ByteBuffer buffer = ByteBuffer.allocateDirect(TEXTURE_WIDTH*TEXTURE_HEIGHT*4);
		for (int y=0; y<TEXTURE_HEIGHT; y++) {
			for (int x=0; x<TEXTURE_WIDTH; x++) {
				int a = x>y ? 0x00 : 0xff;
				buffer.put((byte) 0x00); // R
				buffer.put((byte) 0x00); // G
				buffer.put((byte) 0xff); // B
				buffer.put((byte) a); // A
			}
		}
		buffer.rewind();

		// store it under a textureId
		textureId = GL11.glGenTextures();
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0,
				GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
	}

	/**
	 * Draw a quad with the texture on it.
	 */
	private void render() {
		// clear the screen
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
		
		// configure the texture engine
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		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_MIN_FILTER, GL11.GL_NEAREST);
		GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

		// bind the texture
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
		
		// draw a quad with our texture on it
		float destination = 100f;
		int scale = 1;
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glTexCoord2f(0, 0);
		GL11.glVertex2f(destination, destination);
		GL11.glTexCoord2f(1, 0);
		GL11.glVertex2f(destination + TEXTURE_WIDTH * scale, destination);
		GL11.glTexCoord2f(1, 1);
		GL11.glVertex2f(destination + TEXTURE_WIDTH * scale, destination + TEXTURE_HEIGHT * scale);
		GL11.glTexCoord2f(0, 1);
		GL11.glVertex2f(destination, destination + TEXTURE_HEIGHT * scale);
		GL11.glEnd();
	}

	private void startTheExample() {
		initLwjglDisplay();
		initOpenGL();
		initTexture();

		while (true) {
			render();

			Display.update();
			Display.sync(20);

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

	public static void main(String[] argv) {
		new OpenGlBlitExample().startTheExample();
	}
}