/**
* 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.javase;
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.util.Arrays;
import loon.*;
import loon.geom.Dimension;
import loon.javase.JavaSEGame.JavaSetting;
import loon.jni.NativeSupport;
import loon.opengl.GL20;
import loon.utils.GLUtils;
import loon.utils.Scale;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
public class JavaSELwjglGraphics extends JavaSEGraphics {
private Dimension screenSize = new Dimension();
public JavaSELwjglGraphics(JavaSEGame game) {
super(game, new JavaSELwjglGL20(), Scale.ONE);
}
boolean isPowerOfTwo(int value) {
return value != 0 && (value & value - 1) == 0;
}
void checkScaleFactor() {
float scaleFactor = Display.getPixelScaleFactor();
if (scaleFactor != scale.factor) {
updateViewport(new Scale(scaleFactor), Display.getWidth(),
Display.getHeight());
}
}
@Override
public Dimension screenSize() {
DisplayMode mode = Display.getDesktopDisplayMode();
screenSize.width = scale.invScaled(mode.getWidth());
screenSize.height = scale.invScaled(mode.getHeight());
return screenSize;
}
@Override
public void setSize(int width, int height, boolean fullscreen) {
setDisplayMode(width, height, fullscreen);
}
@Override
protected void init() {
if (game.setting instanceof JavaSetting) {
JavaSetting setting = (JavaSetting) game.setting;
Display.setVSyncEnabled(setting.vSyncEnabled);
} else {
Display.setVSyncEnabled(true);
}
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);
}
try {
System.setProperty("org.lwjgl.opengl.Display.enableHighDPI", "true");
Display.setInitialBackground(0, 0, 0);
Display.create();
checkScaleFactor();
} catch (LWJGLException e) {
throw new RuntimeException(e);
}
}
@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) {
try {
DisplayMode mode = Display.getDisplayMode();
if (fullscreen == Display.isFullscreen()
&& mode.getWidth() == width && mode.getHeight() == height){
return;
}
if (!fullscreen) {
DisplayMode deskMode = Display.getDesktopDisplayMode();
if (width > deskMode.getWidth()) {
game.log().debug(
"Capping window width at desktop width: " + width
+ " -> " + deskMode.getWidth());
width = deskMode.getWidth();
}
if (height > deskMode.getHeight()) {
game.log().debug(
"Capping window height at desktop height: "
+ height + " -> " + deskMode.getHeight());
height = deskMode.getHeight();
}
mode = new DisplayMode(width, height);
} else {
DisplayMode matching = null;
for (DisplayMode dm : Display.getAvailableDisplayModes()) {
if (dm.getWidth() == width && dm.getHeight() == height
&& dm.isFullscreenCapable()) {
matching = dm;
}
}
if (matching != null) {
mode = matching;
} else {
game.log().info(
"Could not find a matching fullscreen mode, available: "
+ Arrays.asList(Display
.getAvailableDisplayModes()));
}
}
game.log().debug(
"Updating display mode: " + mode + ", fullscreen: "
+ fullscreen);
Scale scale = Scale.ONE;
if (fullscreen) {
Display.setDisplayModeAndFullscreen(mode);
scale = Scale.ONE;
} else {
Display.setDisplayMode(mode);
scale = new Scale(Display.getPixelScaleFactor());
}
updateViewport(scale, mode.getWidth(), mode.getHeight());
} catch (LWJGLException ex) {
throw new RuntimeException(ex);
}
}
}