03 Jme3和Nifty1.4.2中文显示

用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-niftygui的gradle,build并替换就可以在gui及项目中使用中文了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据学习笔记

Service Unavailable (HTTP 503)和Unable to connect to WSGI daemon process 'keystone-admin' on '/run/ht

1、遇到问题 [root@master ~]# openstack service create --name keystone --description ...

35810
来自专栏菩提树下的杨过

Silverlight Telerik控件学习:TreeView数据绑定并初始化选中状态、PanelBar的Accordion效果、TabPanel、Frame基本使用

实际开发中控件的数据源肯定是动态绑定的,不可能在xaml里写死item项。既然要绑定,就先来几个实体类: ? 上面是类图,各类的代码如下:  Business...

3018
来自专栏码匠的流水账

聊聊rocketmq的RequestTask

org/apache/rocketmq/remoting/netty/RequestTask.java

2182
来自专栏游戏杂谈

CURLcode的定义

http://curl.haxx.se/libcurl/c/libcurl-errors.html

3942
来自专栏MasiMaro 的技术博文

遍历系统中加载的驱动程序以及通过设备对象指针获取设备对象名称

遍历系统中加载的驱动可以在R3层完成,通过几个未导出的函数:ZwOpenDirectoryObject、ZwQueryDirectoryObject,下面是具体...

1292
来自专栏菩提树下的杨过

发布一个轻量级的滑块控件

比系统自带的组件体积要小很多,而且支持进度条显示(在做播放器时,显示缓冲进度很有用哦),另外也支持三角形的音量调整显示 使用示例: package { imp...

3928
来自专栏数据库新发现

在RAC环境中如何管理日志(redolog file)组

http://www.eygle.com/faq/How.To.Mangement.redologfile.in.Rac.Raw.htm

1042
来自专栏算法+

3D Lut 电影级调色算法 附完整C代码

长话短说,3d lut(全称 : 3D Lookup table )它是通过建立一个颜色映射表,对图像的色调进行重调的算法。

1.1K10
来自专栏流媒体人生

基于S3C6410和ffmpeg的视频加速示例

1094
来自专栏乐享123

Udp Packet Receive Errors

6225

扫码关注云+社区

领取腾讯云代金券