/** * Copyright 2008 - 2015 The Loon Game Engine Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.5 */ package loon.lwjgl; import java.awt.Graphics2D; 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.IntBuffer; import loon.*; import loon.geom.Dimension; import loon.jni.NativeSupport; import loon.opengl.GL20; import loon.utils.GLUtils; import loon.utils.Scale; import static org.lwjgl.glfw.GLFW.*; import org.lwjgl.BufferUtils; import org.lwjgl.glfw.GLFWFramebufferSizeCallback; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import org.lwjgl.system.MemoryUtil; public class Lwjgl3Graphics extends Lwjgl3ImplGraphics { private final GLFWFramebufferSizeCallback fbSizeCallback = new GLFWFramebufferSizeCallback() { public void invoke(long window, int width, int height) { viewportAndScaleChanged(width, height); } }; private Dimension screenSize = new Dimension(); private final long window; public Lwjgl3Graphics(Lwjgl3Game game, long win) { super(game, new Lwjgl3GL20(), Scale.ONE); this.window = win; glfwSetFramebufferSizeCallback(window, fbSizeCallback); } boolean isPowerOfTwo(int value) { return value != 0 && (value & value - 1) == 0; } private void viewportAndScaleChanged(int fbWidth, int fbHeight) { float scale = fbWidth / viewSizeM.width; if (scale != scale().factor) { this.scale = new Scale(scale); } viewportChanged(scale(), fbWidth, fbHeight); } @Override public Dimension screenSize() { GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); screenSize.width = vidMode.width(); screenSize.height = vidMode.height(); return screenSize; } @Override public void setSize(int width, int height, boolean fullscreen) { setDisplayMode(width, height, fullscreen); } void shutdown() { fbSizeCallback.close(); } void setTitle(String title) { if (window != 0L) glfwSetWindowTitle(window, title); } @Override protected void init() { if (game.setting.width_zoom > 0 && game.setting.height_zoom > 0) { setDisplayMode(scale.scaledCeil(game.setting.width_zoom), scale.scaledCeil(game.setting.height_zoom), game.setting.fullscreen); } else { setDisplayMode(scale.scaledCeil(game.setting.width), scale.scaledCeil(game.setting.height), game.setting.fullscreen); } setTitle(game.setting.appName); } @Override protected void upload(BufferedImage img, LTexture tex) { if (img == null) { return; } BufferedImage bitmap = convertImage(img); DataBuffer dbuf = bitmap.getRaster().getDataBuffer(); ByteBuffer bbuf; int format, type; if (bitmap.getType() == BufferedImage.TYPE_INT_ARGB_PRE) { DataBufferInt ibuf = (DataBufferInt) dbuf; int iSize = ibuf.getSize() * 4; bbuf = checkGetImageBuffer(iSize); bbuf.asIntBuffer().put(ibuf.getData()); bbuf.position(bbuf.position() + iSize); bbuf.flip(); format = GL12.GL_BGRA; type = GL12.GL_UNSIGNED_INT_8_8_8_8_REV; } else if (bitmap.getType() == BufferedImage.TYPE_4BYTE_ABGR) { DataBufferByte dbbuf = (DataBufferByte) dbuf; bbuf = checkGetImageBuffer(dbbuf.getSize()); bbuf.put(dbbuf.getData()); bbuf.flip(); format = GL11.GL_RGBA; type = GL12.GL_UNSIGNED_INT_8_8_8_8; } else { int srcWidth = img.getWidth(); int srcHeight = img.getHeight(); int texWidth = GLUtils.powerOfTwo(srcWidth); int texHeight = GLUtils.powerOfTwo(srcHeight); int width = srcWidth; int height = srcHeight; boolean hasAlpha = img.getColorModel().hasAlpha(); if (isPowerOfTwo(srcWidth) && isPowerOfTwo(srcHeight)) { width = srcWidth; height = srcHeight; texHeight = srcHeight; texWidth = srcWidth; ByteBuffer source = NativeSupport.getByteBuffer((byte[]) img .getRaster().getDataElements(0, 0, img.getWidth(), img.getHeight(), null)); int srcPixelFormat = hasAlpha ? GL20.GL_RGBA : GL20.GL_RGB; gl.glBindTexture(GL11.GL_TEXTURE_2D, tex.getID()); gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, srcPixelFormat, texWidth, texHeight, 0, srcPixelFormat, GL20.GL_UNSIGNED_BYTE, source); gl.checkError("updateTexture"); return; } BufferedImage texImage = new BufferedImage(texWidth, texHeight, hasAlpha ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR); Graphics2D g = texImage.createGraphics(); g.drawImage(img, 0, 0, null); if (height < texHeight - 1) { copyArea(texImage, g, 0, 0, width, 1, 0, texHeight - 1); copyArea(texImage, g, 0, height - 1, width, 1, 0, 1); } if (width < texWidth - 1) { copyArea(texImage, g, 0, 0, 1, height, texWidth - 1, 0); copyArea(texImage, g, width - 1, 0, 1, height, 1, 0); } ByteBuffer source = NativeSupport.getByteBuffer((byte[]) texImage .getRaster().getDataElements(0, 0, texImage.getWidth(), texImage.getHeight(), null)); if (texImage != null) { texImage.flush(); texImage = null; } int srcPixelFormat = hasAlpha ? GL20.GL_RGBA : GL20.GL_RGB; gl.glBindTexture(GL11.GL_TEXTURE_2D, tex.getID()); gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, srcPixelFormat, texWidth, texHeight, 0, srcPixelFormat, GL20.GL_UNSIGNED_BYTE, source); gl.checkError("updateTexture"); return; } gl.glBindTexture(GL11.GL_TEXTURE_2D, tex.getID()); GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, format, type, bbuf); gl.checkError("updateTexture"); } void copyArea(BufferedImage image, Graphics2D g, int x, int y, int width, int height, int dx, int dy) { BufferedImage tmp = image.getSubimage(x, y, width, height); g.drawImage(tmp, x + dx, y + dy, null); tmp.flush(); tmp = null; } protected void setDisplayMode(int width, int height, boolean fullscreen) { if (game.setting.fullscreen != fullscreen) { game.log() .warn("fullscreen cannot be changed via setSize, use config.fullscreen instead"); return; } GLFWVidMode vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); if (width > vidMode.width()) { game.log().debug( "Capping window width at desktop width: " + width + " -> " + vidMode.width()); width = vidMode.width(); } if (height > vidMode.height()) { game.log().debug( "Capping window height at desktop height: " + height + " -> " + vidMode.height()); height = vidMode.height(); } glfwSetWindowSize(window, width, height); viewSizeM.setSize(width, height); IntBuffer fbSize = BufferUtils.createIntBuffer(2); long addr = MemoryUtil.memAddress(fbSize); nglfwGetFramebufferSize(window, addr, addr + 4); viewportAndScaleChanged(fbSize.get(0), fbSize.get(1)); } }