用JMonkey最大的问题就是中文问题,IDE不是中文没关系,反正可以迁移到Idea里,但是打包发布的项目以及Nifty做的GUI里没有中文就心塞塞了。好在找到一篇前两年的博客,叫JME3与NIFTY GUI1.3结合,修改使其支持中文的输入与显示,里面有大神解决过该问题,虽然他的版本有些老,很多语句和新的不太一样,但帮了很大忙。
源代码修改
看过前两篇的同学就知道,我使用gradle管理的依赖,现在要改源代码,所以就要把原项目作为一个项目依赖,试了很久没成功,干脆把原项目重新打开,修改完源码以后自己打个包,再导入项目,开源项目就是方便。原项目也是用gradle管理的,打包也很方便,到github上拉下来就好。
打开以后是这个样子:
- 修改jme3-lwjgl中的com.jme3.input.lwjgl.LwjglKeyInput.java中的update方法,直接copy下面代码即可。
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.input.lwjgl;
import com.jme3.input.KeyInput;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.input.RawInputListener;
import com.jme3.system.lwjgl.LwjglAbstractDisplay;
import com.jme3.system.lwjgl.LwjglTimer;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import javax.swing.*;
public class LwjglKeyInput implements KeyInput {
private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName());
private LwjglAbstractDisplay context;
private RawInputListener listener;
public LwjglKeyInput(LwjglAbstractDisplay context){
this.context = context;
}
public void initialize() {
if (!context.isRenderable())
return;
try {
Keyboard.create();
Keyboard.enableRepeatEvents(true);
logger.fine("Keyboard created.");
} catch (LWJGLException ex) {
logger.log(Level.SEVERE, "Error while creating keyboard.", ex);
}
}
public int getKeyCount(){
return Keyboard.KEYBOARD_SIZE;
}
char chcode = 0;
public void update() {
if (!context.isRenderable())
return;
Keyboard.poll();
while (Keyboard.next()){
// int keyCode = Keyboard.getEventKey();
// char keyChar = Keyboard.getEventCharacter();
// boolean pressed = Keyboard.getEventKeyState();
// boolean down = Keyboard.isRepeatEvent();
// long time = Keyboard.getEventNanoseconds();
// KeyInputEvent evt = new KeyInputEvent(keyCode, keyChar, pressed, down);
// evt.setTime(time);
// listener.onKeyEvent(evt);
//若接受到的是中文
char character = Keyboard.getEventCharacter();
if (chcode == 0) {
chcode = character;
if (character > 127) {
return;
}
} else {
chcode = (char) (character + (chcode << 8));
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
long time = Keyboard.getEventNanoseconds();
if (Keyboard.getEventKeyState()) // if pressed
{
sendEvent(time, Keyboard.getEventKey(), chcode, true);
} else {
sendEvent(time, Keyboard.getEventKey(), chcode, false);
}
chcode = 0;
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
private Map<Int, Char> characters = new HashMap<Int, Char>();
private static Int anInt = new Int(0);
private void handEvent(long time, int keyCode, char character, boolean pressed) {
KeyInputEvent evt = new KeyInputEvent(keyCode, character, pressed, Keyboard.isRepeatEvent());
evt.setTime(time);
listener.onKeyEvent(evt);
}
private void sendEvent(long time, int keyCode2, char character, boolean pressed) {
int keyCode = com.jme3.input.awt.AwtKeyInput.convertJmeCode(keyCode2);
try {
if (keyCode != 0) {
// if (character == '\0') {
// character = KeyEvent.CHAR_UNDEFINED;
// }
if (pressed) {
// if (character != KeyEvent.CHAR_UNDEFINED) {
if (character <= 255) {
//英文和特殊字符,即之前不支持中文时的字符
handEvent(time, keyCode2, character, pressed);
}
anInt.value = keyCode;
Char c = characters.get(anInt);
if (c == null) {
characters.put(new Int(keyCode), new Char(character));
} else {
c.value = character;
}
}
if (!pressed) {
anInt.value = keyCode;
if (character > 255 && character < 65535) {
char s = new String(new byte[]{(byte) (character / 256), (byte) (character % 256)}, "gbk").toCharArray()[0];
//中文
handEvent(time, keyCode, s, true);
handEvent(time, keyCode, s, false);
} else {
//英文和特殊字符,即之前不支持中文时的字符
handEvent(time, keyCode2, character, false);
}
}
}
} catch (Exception e) {
// logger.info("");
}
}
private static class Int {
public Int(int value) {
this.value = value;
}
public boolean equals(Object obj) {
return obj instanceof Int && ((Int) obj).value == value;
}
public int hashCode() {
return value;
}
int value;
}
private static class Char {
public Char(char value) {
this.value = value;
}
char value;
}
public void destroy() {
if (!context.isRenderable())
return;
Keyboard.destroy();
logger.fine("Keyboard destroyed.");
}
public boolean isInitialized() {
return Keyboard.isCreated();
}
public void setInputListener(RawInputListener listener) {
this.listener = listener;
}
public long getInputTimeNanos() {
return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;
}
}
- 在jme3-niftygui中的com.jme3.niftygui中新建类RenderFontAWT.java,直接copy下面代码即可:
package com.jme3.niftygui;
import de.lessvoid.nifty.spi.render.RenderFont;
import javax.annotation.Nonnull;
import java.awt.*;
import java.awt.image.BufferedImage;
public class RenderFontAWT implements RenderFont {
private FontMetrics fontMetrics;
public RenderFontAWT() {
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
Font awtFont = new Font("黑体", java.awt.Font.PLAIN, 12);
fontMetrics = image.createGraphics().getFontMetrics(awtFont);
}
@Override
public int getWidth(String text) {
if (text.length() == 0) {
return 0;
}
return fontMetrics.stringWidth(text);
}
@Override
public int getWidth(@Nonnull String text, float size) {
return 0;
}
@Override
public int getHeight() {
return (fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent());
}
@Override
public int getCharacterAdvance(char currentCharacter, char nextCharacter, float size) {
return -1;
}
@Override
public void dispose() {
//To change body of implemented methods use File | Settings | File Templates.
}
}
- 在jme3-niftygui中的com.jme3.niftygui中新建类RenderDeviceAWT.java,直接copy下面代码即可:
package com.jme3.niftygui;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Matrix4f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.util.BufferUtils;
import de.lessvoid.nifty.render.BlendMode;
import de.lessvoid.nifty.spi.render.*;
import de.lessvoid.nifty.tools.Color;
import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
import javax.annotation.Nonnull;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
public class RenderDeviceAWT implements RenderDevice {
private FontMetrics fontMetrics;
private Font awtFont = null;
private NiftyJmeDisplay display;
private RenderManager rm;
private Renderer r;
private final Quad quad
= new Quad(1, -1, true);
private final Geometry quadGeom
= new Geometry("nifty-quad", quad);
private RenderState renderState = new RenderState();
private Material colorMaterial;
private Material textureColorMaterial;
private Material vertexColorMaterial;
private boolean clipWasSet = false;
private BlendMode blendMode = null;
private VertexBuffer quadDefaultTC = quad.getBuffer(Type.TexCoord);
private VertexBuffer quadModTC = quadDefaultTC.clone();
private VertexBuffer quadColor;
private Matrix4f tempMat = new Matrix4f();
private ColorRGBA tempColor = new ColorRGBA();
public RenderDeviceAWT(NiftyJmeDisplay display) {
this.display = display;
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
awtFont = new Font("黑体", java.awt.Font.PLAIN, 12);
fontMetrics = image.createGraphics().getFontMetrics(awtFont);
quadColor = new VertexBuffer(Type.Color);
quadColor.setNormalized(true);
ByteBuffer bb = BufferUtils.createByteBuffer(4 * 4);
quadColor.setupData(Usage.Stream, 4, Format.UnsignedByte, bb);
quad.setBuffer(quadColor);
quadModTC.setUsage(Usage.Stream);
// Load the 3 material types separately to avoid
// reloading the shader when the defines change.
// Material with a single color (no texture or vertex color)
colorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
// Material with a texture and a color (no vertex color)
textureColorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
// Material with vertex color, used for gradients (no texture)
vertexColorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
vertexColorMaterial.setBoolean("VertexColor", true);
// Shared render state for all materials
renderState.setDepthTest(false);
renderState.setDepthWrite(false);
}
@Override
public void setResourceLoader(@Nonnull NiftyResourceLoader niftyResourceLoader) {
}
public void setRenderManager(RenderManager rm) {
this.rm = rm;
this.r = rm.getRenderer();
}
// TODO: Cursor support
public MouseCursor createMouseCursor(String str, int x, int y){
return new MouseCursor() {
@Override
public void enable() {
}
@Override
public void disable() {
}
public void dispose() {
}
};
}
public void enableMouseCursor(MouseCursor cursor){
}
public void disableMouseCursor(){
}
public RenderImage createImage(String filename, boolean linear) {
return new RenderImageJme(filename, linear, display);
}
public RenderFont createFont(String filename) {
// return new RenderFontJme(filename, display);
return new RenderFontAWT();
}
public void beginFrame() {
}
public void endFrame() {
}
public int getWidth() {
return display.getWidth();
}
public int getHeight() {
return display.getHeight();
}
public void clear() {
}
public void setBlendMode(BlendMode blendMode) {
renderState.setBlendMode(convertBlend(blendMode));
}
private RenderState.BlendMode convertBlend(BlendMode blendMode) {
if (blendMode == null) {
return RenderState.BlendMode.Off;
} else if (blendMode == BlendMode.BLEND) {
return RenderState.BlendMode.Alpha;
} else if (blendMode == BlendMode.MULIPLY) {
return RenderState.BlendMode.Modulate;
} else {
throw new UnsupportedOperationException();
}
}
private int convertColor(Color color){
int color2 = 0;
color2 |= ((int)(255.0 * color.getAlpha())) << 24;
color2 |= ((int)(255.0 * color.getBlue())) << 16;
color2 |= ((int)(255.0 * color.getGreen())) << 8;
color2 |= ((int)(255.0 * color.getRed()));
return color2;
}
private ColorRGBA convertColor(Color inColor, ColorRGBA outColor){
return outColor.set(inColor.getRed(), inColor.getGreen(), inColor.getBlue(), inColor.getAlpha());
}
private void setColor(Color color){
ByteBuffer buf = (ByteBuffer) quadColor.getData();
buf.rewind();
int color2 = convertColor(color);
buf.putInt(color2);
buf.putInt(color2);
buf.putInt(color2);
buf.putInt(color2);
buf.flip();
quadColor.updateData(buf);
}
@Override
public void renderFont(@Nonnull RenderFont font, @Nonnull String text, int x, int y,
@Nonnull Color fontColor, float sizeX, float sizeY) {
//多行时还不知道有没有问题
if (text.length() == 0) {
return;
}
// if (font instanceof TextRenderer.RenderFontNull) {
// return;
// }
Texture texture = createTexture2D(text);
// WARNING: Not compatible with OpenGL1 implementations..
textureColorMaterial.setColor("Color", convertColor(fontColor, tempColor));
textureColorMaterial.setBoolean("VertexColor", true);
textureColorMaterial.setTexture("ColorMap", texture);
// niftyMat.setInt("m_Mode", 3);
float width = texture.getImage().getWidth();
float height = texture.getImage().getHeight();
Mesh text1 = new Quad(width, height);
Geometry text2 = new Geometry("text", text1);
float x0 = x + 0.5f * width * (1f - sizeX);
float y0 = y + 0.5f * height * (1f - sizeX) + height;
tempMat.loadIdentity();
tempMat.setTranslation(x0, getHeight() - y0, 0);
tempMat.setScale(sizeX, sizeY, 0);
rm.setWorldMatrix(tempMat);
textureColorMaterial.render(text2, rm);
}
private Texture2D createTexture2D(String str) {
BufferedImage bi = new BufferedImage(fontMetrics.stringWidth(str), fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent(),
BufferedImage.TYPE_INT_ARGB);
java.awt.Color renderColor = java.awt.Color.WHITE;
Graphics2D g = (Graphics2D) bi.getGraphics();
g.setColor(renderColor);
g.setBackground(java.awt.Color.WHITE);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setFont(awtFont);
g.drawString(str, 0, fontMetrics.getMaxAscent() - 1);
Texture2D texture2d = new Texture2D(load(bi, true));
texture2d.setMagFilter(Texture.MagFilter.Bilinear);
texture2d.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
return texture2d;
}
private com.jme3.texture.Image load(BufferedImage img, boolean flipY) {
int width = img.getWidth();
int height = img.getHeight();
switch (img.getType()) {
case BufferedImage.TYPE_3BYTE_BGR: // most common in JPEG images
byte[] dataBuf = extractImageData(img);
if (flipY) {
flipImage(dataBuf, width, height, 24);
}
ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 3);
data.put(dataBuf);
return new com.jme3.texture.Image(com.jme3.texture.Image.Format.BGR8, width, height, data);
case BufferedImage.TYPE_BYTE_GRAY: // grayscale fonts
byte[] dataBuf2 = extractImageData(img);
if (flipY) {
flipImage(dataBuf2, width, height, 8);
}
ByteBuffer data2 = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight());
data2.put(dataBuf2);
return new com.jme3.texture.Image(com.jme3.texture.Image.Format.Luminance8, width, height, data2);
default:
break;
}
if (img.getTransparency() == Transparency.OPAQUE) {
ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 3);
// no alpha
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int ny = y;
if (flipY) {
ny = height - y - 1;
}
int rgb = img.getRGB(x, ny);
byte r = (byte) ((rgb & 0x00FF0000) >> 16);
byte g = (byte) ((rgb & 0x0000FF00) >> 8);
byte b = (byte) ((rgb & 0x000000FF));
data.put(r).put(g).put(b);
}
}
data.flip();
return new com.jme3.texture.Image(com.jme3.texture.Image.Format.RGB8, width, height, data);
} else {
ByteBuffer data = BufferUtils.createByteBuffer(img.getWidth() * img.getHeight() * 4);
// no alpha
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int ny = y;
if (flipY) {
ny = height - y - 1;
}
int rgb = img.getRGB(x, ny);
byte a = (byte) ((rgb & 0xFF000000) >> 24);
byte r = (byte) ((rgb & 0x00FF0000) >> 16);
byte g = (byte) ((rgb & 0x0000FF00) >> 8);
byte b = (byte) ((rgb & 0x000000FF));
data.put(r).put(g).put(b).put(a);
}
}
data.flip();
return new com.jme3.texture.Image(com.jme3.texture.Image.Format.RGBA8, width, height, data);
}
}
private byte[] extractImageData(BufferedImage img) {
DataBuffer buf = img.getRaster().getDataBuffer();
switch (buf.getDataType()) {
case DataBuffer.TYPE_BYTE:
DataBufferByte byteBuf = (DataBufferByte) buf;
return byteBuf.getData();
}
return null;
}
private void flipImage(byte[] img, int width, int height, int bpp) {
int scSz = (width * bpp) / 8;
byte[] sln = new byte[scSz];
int y2;
for (int y1 = 0; y1 < height / 2; y1++) {
y2 = height - y1 - 1;
System.arraycopy(img, y1 * scSz, sln, 0, scSz);
System.arraycopy(img, y2 * scSz, img, y1 * scSz, scSz);
System.arraycopy(sln, 0, img, y2 * scSz, scSz);
}
}
public void renderImage(RenderImage image, int x, int y, int w, int h,
int srcX, int srcY, int srcW, int srcH,
Color color, float scale,
int centerX, int centerY) {
RenderImageJme jmeImage = (RenderImageJme) image;
Texture2D texture = jmeImage.getTexture();
textureColorMaterial.setColor("Color", convertColor(color, tempColor));
textureColorMaterial.setTexture("ColorMap", texture);
setColor(color);
float imageWidth = texture.getImage().getWidth();
float imageHeight = texture.getImage().getHeight();
FloatBuffer texCoords = (FloatBuffer) quadModTC.getData();
float startX = srcX / imageWidth;
float startY = srcY / imageHeight;
float endX = startX + (srcW / imageWidth);
float endY = startY + (srcH / imageHeight);
startY = 1f - startY;
endY = 1f - endY;
texCoords.rewind();
texCoords.put(startX).put(startY);
texCoords.put(endX).put(startY);
texCoords.put(endX).put(endY);
texCoords.put(startX).put(endY);
texCoords.flip();
quadModTC.updateData(texCoords);
quad.clearBuffer(VertexBuffer.Type.TexCoord);
quad.setBuffer(quadModTC);
float x0 = centerX + (x - centerX) * scale;
float y0 = centerY + (y - centerY) * scale;
tempMat.loadIdentity();
tempMat.setTranslation(x0, getHeight() - y0, 0);
tempMat.setScale(w * scale, h * scale, 0);
rm.setWorldMatrix(tempMat);
rm.setForcedRenderState(renderState);
textureColorMaterial.render(quadGeom, rm);
}
public void renderImage(RenderImage image, int x, int y, int width, int height,
Color color, float imageScale) {
RenderImageJme jmeImage = (RenderImageJme) image;
textureColorMaterial.setColor("Color", convertColor(color, tempColor));
textureColorMaterial.setTexture("ColorMap", jmeImage.getTexture());
textureColorMaterial.setBoolean("VertexColor", true);
setColor(color);
quad.clearBuffer(VertexBuffer.Type.TexCoord);
quad.setBuffer(quadDefaultTC);
float x0 = x + 0.5f * width * (1f - imageScale);
float y0 = y + 0.5f * height * (1f - imageScale);
tempMat.loadIdentity();
tempMat.setTranslation(x0, getHeight() - y0, 0);
tempMat.setScale(width * imageScale, height * imageScale, 0);
rm.setWorldMatrix(tempMat);
rm.setForcedRenderState(renderState);
textureColorMaterial.render(quadGeom, rm);
}
public void renderQuad(int x, int y, int width, int height, Color color) {
if(color.getAlpha() >0){
colorMaterial.setColor("Color", convertColor(color, tempColor));
tempMat.loadIdentity();
tempMat.setTranslation(x, getHeight() - y, 0);
tempMat.setScale(width, height, 0);
rm.setWorldMatrix(tempMat);
rm.setForcedRenderState(renderState);
colorMaterial.render(quadGeom, rm);
}
}
public void renderQuad(int x, int y, int width, int height,
Color topLeft, Color topRight, Color bottomRight, Color bottomLeft) {
ByteBuffer buf = (ByteBuffer) quadColor.getData();
buf.rewind();
buf.putInt(convertColor(bottomRight));
buf.putInt(convertColor(bottomLeft));
buf.putInt(convertColor(topLeft));
buf.putInt(convertColor(topRight));
buf.flip();
quadColor.updateData(buf);
tempMat.loadIdentity();
tempMat.setTranslation(x, getHeight() - y, 0);
tempMat.setScale(width, height, 0);
rm.setWorldMatrix(tempMat);
rm.setForcedRenderState(renderState);
vertexColorMaterial.render(quadGeom, rm);
}
public void enableClip(int x0, int y0, int x1, int y1) {
clipWasSet = true;
r.setClipRect(x0, getHeight() - y1, x1 - x0, y1 - y0);
}
public void disableClip() {
if (clipWasSet) {
r.clearClipRect();
clipWasSet = false;
}
}
}
- 修改com.jme3.niftygui中的NiftyJmeDisplay.java文件,使其使用RenderDeviceAWT类,copy下面代码即可
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.niftygui;
import java.io.InputStream;
import java.net.URL;
import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetManager;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioRenderer;
import com.jme3.input.InputManager;
import com.jme3.input.event.KeyInputEvent;
import com.jme3.post.SceneProcessor;
import com.jme3.profile.AppProfiler;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.texture.FrameBuffer;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.render.batch.BatchRenderConfiguration;
import de.lessvoid.nifty.render.batch.BatchRenderDevice;
import de.lessvoid.nifty.tools.TimeProvider;
import de.lessvoid.nifty.tools.resourceloader.ResourceLocation;
public class NiftyJmeDisplay implements SceneProcessor {
protected boolean inited = false;
protected Nifty nifty;
protected AssetManager assetManager;
protected RenderManager renderManager;
protected InputManager inputManager;
protected RenderDeviceAWT renderDev;
protected JmeBatchRenderBackend batchRendererBackend;
protected InputSystemJme inputSys;
protected SoundDeviceJme soundDev;
protected Renderer renderer;
protected ViewPort vp;
protected ResourceLocationJme resourceLocation;
protected int w, h;
private AppProfiler prof;
protected class ResourceLocationJme implements ResourceLocation {
public InputStream getResourceAsStream(String path) {
AssetKey<Object> key = new AssetKey<Object>(path);
AssetInfo info = assetManager.locateAsset(key);
if (info != null) {
return info.openStream();
} else {
throw new AssetNotFoundException(path);
}
}
public URL getResource(String path) {
throw new UnsupportedOperationException();
}
}
//Empty constructor needed for jMP to create replacement input system
public NiftyJmeDisplay() {
}
/**
* Create a new NiftyJmeDisplay for use with the Batched Nifty Renderer.
*
* Nifty will use texture atlases for rendering. Every graphical asset
* you're rendering through Nifty will be placed into a texture atlas. The
* goal is to render all Nifty components in a single (or at least very few)
* draw calls. This should speed up rendering quite a bit.
*
* This call will use a default BatchRenderConfiguration for Nifty.
* See the other method {@link #newNiftyJmeDisplay(com.jme3.asset.AssetManager, com.jme3.input.InputManager, com.jme3.audio.AudioRenderer, com.jme3.renderer.ViewPort, de.lessvoid.nifty.render.batch.BatchRenderConfiguration) }
* when you want to change the default BatchRenderConfiguration and provide
* your own.
*
* @param assetManager jME AssetManager
* @param inputManager jME InputManager
* @param audioRenderer jME AudioRenderer
* @param viewport Viewport to use
*/
public static NiftyJmeDisplay newNiftyJmeDisplay(
final AssetManager assetManager,
final InputManager inputManager,
final AudioRenderer audioRenderer,
final ViewPort viewport) {
return newNiftyJmeDisplay(
assetManager,
inputManager,
audioRenderer,
viewport,
new BatchRenderConfiguration());
}
/**
* Create a new NiftyJmeDisplay for use with the Batched Nifty Renderer.
*
* Nifty will use texture atlas for rendering. Every graphical asset you're
* rendering through Nifty will be placed into a texture atlas. The goal is
* to render all Nifty components in a single (or at least very few) draw
* calls. This should speed up rendering quite a bit.
*
* @param assetManager jME AssetManager
* @param inputManager jME InputManager
* @param audioRenderer jME AudioRenderer
* @param viewport Viewport to use
* @param batchRenderConfiguration the Nifty BatchRenderConfiguration that
* you can use to further configure batch rendering. If unsure you
* can simply use new BatchRenderConfiguration() in here for the
* default configuration which should give you good default values.
*/
public static NiftyJmeDisplay newNiftyJmeDisplay(
final AssetManager assetManager,
final InputManager inputManager,
final AudioRenderer audioRenderer,
final ViewPort viewport,
final BatchRenderConfiguration batchRenderConfiguration) {
return new NiftyJmeDisplay(
assetManager,
inputManager,
audioRenderer,
viewport,
batchRenderConfiguration);
}
/**
* Create a new NiftyJmeDisplay for use with the Batched Nifty Renderer (improved Nifty rendering performance).
*
* Nifty will use a single texture of the given dimensions (see atlasWidth and atlasHeight parameters). Every
* graphical asset you're rendering through Nifty will be placed into this big texture. The goal is to render
* all Nifty components in a single (or at least very few) draw calls. This should speed up rendering quite a
* bit.
*
* Currently you have to make sure to not use more image space than this single texture provides. However, Nifty
* tries to be smart about this and internally will make sure that only the images are uploaded that your GUI
* really needs. So in general this shoudln't be an issue.
*
* A complete re-organisation of the texture atlas happens when a Nifty screen ends and another begins. Dynamically
* adding images while a screen is running is supported as well.
*
* @param assetManager jME AssetManager
* @param inputManager jME InputManager
* @param audioRenderer jME AudioRenderer
* @param viewport Viewport to use
* @param atlasWidth the width of the texture atlas Nifty uses to speed up rendering (2048 is a good value)
* @param atlasHeight the height of the texture atlas Nifty uses to speed up rendering (2048 is a good value)
*
* @deprecated use the static factory methods {@link #newNiftyJmeDisplay(com.jme3.asset.AssetManager, com.jme3.input.InputManager, com.jme3.audio.AudioRenderer, com.jme3.renderer.ViewPort) }
* or {@link #newNiftyJmeDisplay(com.jme3.asset.AssetManager, com.jme3.input.InputManager, com.jme3.audio.AudioRenderer, com.jme3.renderer.ViewPort, de.lessvoid.nifty.render.batch.BatchRenderConfiguration) }
* instead of this constructor.
*/
public NiftyJmeDisplay(
final AssetManager assetManager,
final InputManager inputManager,
final AudioRenderer audioRenderer,
final ViewPort viewport,
final int atlasWidth,
final int atlasHeight) {
// The code duplication in here really sucks - it's a copy of the
// private constructor below that takes a BatchRenderConfiguration as an
// additional parameter. This method should really be removed soon and
// users should simply call the new factory methods.
//
// For now I keep this constructor as-is but have marked it as deprecated
// to allow migration to the new way to instantiate this class.
initialize(assetManager, inputManager, audioRenderer, viewport);
this.renderDev = null;
this.batchRendererBackend = new JmeBatchRenderBackend(this);
BatchRenderConfiguration batchRenderConfiguration = new BatchRenderConfiguration();
batchRenderConfiguration.atlasWidth = atlasWidth;
batchRenderConfiguration.atlasHeight = atlasHeight;
nifty = new Nifty(
new BatchRenderDevice(batchRendererBackend, batchRenderConfiguration),
soundDev,
inputSys,
new TimeProvider());
inputSys.setNifty(nifty);
resourceLocation = new ResourceLocationJme();
nifty.getResourceLoader().removeAllResourceLocations();
nifty.getResourceLoader().addResourceLocation(resourceLocation);
}
private NiftyJmeDisplay(
final AssetManager assetManager,
final InputManager inputManager,
final AudioRenderer audioRenderer,
final ViewPort viewport,
final BatchRenderConfiguration batchRenderConfiguration) {
initialize(assetManager, inputManager, audioRenderer, viewport);
this.renderDev = null;
this.batchRendererBackend = new JmeBatchRenderBackend(this);
nifty = new Nifty(
new BatchRenderDevice(batchRendererBackend, batchRenderConfiguration),
soundDev,
inputSys,
new TimeProvider());
inputSys.setNifty(nifty);
resourceLocation = new ResourceLocationJme();
nifty.getResourceLoader().removeAllResourceLocations();
nifty.getResourceLoader().addResourceLocation(resourceLocation);
}
/**
* Create a standard NiftyJmeDisplay. This uses the old Nifty renderer. It's probably slower then the batched
* renderer and is mainly here for backwards compatibility.
*
* @param assetManager jME AssetManager
* @param inputManager jME InputManager
* @param audioRenderer jME AudioRenderer
* @param vp Viewport to use
*/
public NiftyJmeDisplay(AssetManager assetManager,
InputManager inputManager,
AudioRenderer audioRenderer,
ViewPort vp){
initialize(assetManager, inputManager, audioRenderer, vp);
this.renderDev = new RenderDeviceAWT(this);
this.batchRendererBackend = null;
nifty = new Nifty(renderDev, soundDev, inputSys, new TimeProvider());
inputSys.setNifty(nifty);
resourceLocation = new ResourceLocationJme();
nifty.getResourceLoader().removeAllResourceLocations();
nifty.getResourceLoader().addResourceLocation(resourceLocation);
}
private void initialize(
final AssetManager assetManager,
final InputManager inputManager,
final AudioRenderer audioRenderer,
final ViewPort viewport) {
this.assetManager = assetManager;
this.inputManager = inputManager;
this.w = viewport.getCamera().getWidth();
this.h = viewport.getCamera().getHeight();
this.soundDev = new SoundDeviceJme(assetManager, audioRenderer);
this.inputSys = new InputSystemJme(inputManager);
}
public void initialize(RenderManager rm, ViewPort vp) {
this.renderManager = rm;
if (renderDev != null) {
renderDev.setRenderManager(rm);
} else {
batchRendererBackend.setRenderManager(rm);
}
if (inputManager != null) {
// inputSys.setInputManager(inputManager);
inputManager.addRawInputListener(inputSys);
}
inited = true;
this.vp = vp;
this.renderer = rm.getRenderer();
inputSys.reset();
inputSys.setHeight(vp.getCamera().getHeight());
}
public Nifty getNifty() {
return nifty;
}
public void simulateKeyEvent( KeyInputEvent event ) {
inputSys.onKeyEvent(event);
}
AssetManager getAssetManager() {
return assetManager;
}
RenderManager getRenderManager() {
return renderManager;
}
int getHeight() {
return h;
}
int getWidth() {
return w;
}
Renderer getRenderer(){
return renderer;
}
public void reshape(ViewPort vp, int w, int h) {
this.w = w;
this.h = h;
inputSys.setHeight(h);
nifty.resolutionChanged();
}
public boolean isInitialized() {
return inited;
}
public void preFrame(float tpf) {
}
public void postQueue(RenderQueue rq) {
// render nifty before anything else
renderManager.setCamera(vp.getCamera(), true);
//nifty.update();
nifty.render(false);
renderManager.setCamera(vp.getCamera(), false);
}
public void postFrame(FrameBuffer out) {
}
public void cleanup() {
inited = false;
inputSys.reset();
if (inputManager != null) {
inputManager.removeRawInputListener(inputSys);
}
}
@Override
public void setProfiler(AppProfiler profiler) {
this.prof = profiler;
}
}
打包
用gradle将改动的包build,然后把jar替换到项目里即可
jme3-desktop打包
jme3-desktop的jar包
同理找到jme3-niftygui的gradle,build并替换就可以在gui及项目中使用中文了。