@ -0,0 +1,551 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 20018 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: |
||||||
|
* |
||||||
|
* 1. Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* 2. 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. |
||||||
|
* |
||||||
|
* 3. Neither the name of the copyright holder 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 HOLDER 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 jme3test.gui; |
||||||
|
|
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Font; |
||||||
|
import java.awt.FontFormatException; |
||||||
|
import java.awt.FontMetrics; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Graphics2D; |
||||||
|
import java.awt.GridBagConstraints; |
||||||
|
import java.awt.GridBagLayout; |
||||||
|
import java.awt.GridLayout; |
||||||
|
import java.awt.RenderingHints; |
||||||
|
import java.awt.Toolkit; |
||||||
|
import java.awt.geom.AffineTransform; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.awt.font.TextAttribute; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.*; |
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
import com.jme3.app.DebugKeysAppState; |
||||||
|
import com.jme3.app.StatsAppState; |
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.app.state.ScreenshotAppState; |
||||||
|
import com.jme3.bounding.BoundingBox; |
||||||
|
import com.jme3.font.BitmapCharacter; |
||||||
|
import com.jme3.font.BitmapCharacterSet; |
||||||
|
import com.jme3.font.BitmapFont; |
||||||
|
import com.jme3.font.BitmapText; |
||||||
|
import com.jme3.input.KeyInput; |
||||||
|
import com.jme3.input.controls.ActionListener; |
||||||
|
import com.jme3.input.controls.KeyTrigger; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.scene.*; |
||||||
|
import com.jme3.scene.debug.WireBox; |
||||||
|
import com.jme3.scene.shape.*; |
||||||
|
import com.jme3.texture.Image; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
import com.jme3.texture.Texture2D; |
||||||
|
import com.jme3.texture.plugins.AWTLoader; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author pspeed42 |
||||||
|
*/ |
||||||
|
public class TestBitmapFontLayout extends SimpleApplication { |
||||||
|
|
||||||
|
public static final String SCROLL_UP = "scroll up"; |
||||||
|
public static final String SCROLL_DOWN = "scroll down"; |
||||||
|
public static final String SCROLL_LEFT = "scroll left"; |
||||||
|
public static final String SCROLL_RIGHT = "scroll right"; |
||||||
|
public static final String ZOOM_IN = "zoom in"; |
||||||
|
public static final String ZOOM_OUT = "zoom out"; |
||||||
|
public static final String RESET_ZOOM = "reset zoom"; |
||||||
|
public static final String RESET_VIEW = "reset view"; |
||||||
|
|
||||||
|
public static final float ZOOM_SPEED = 0.1f; |
||||||
|
public static final float SCROLL_SPEED = 50; |
||||||
|
|
||||||
|
private Node testRoot = new Node("test root"); |
||||||
|
private Node scrollRoot = new Node("scroll root"); |
||||||
|
private Vector3f scroll = new Vector3f(0, 0, 0); |
||||||
|
private Vector3f zoom = new Vector3f(0, 0, 0); |
||||||
|
|
||||||
|
public static void main(String[] args){ |
||||||
|
TestBitmapFontLayout app = new TestBitmapFontLayout(); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public TestBitmapFontLayout() { |
||||||
|
super(new StatsAppState(), |
||||||
|
new DebugKeysAppState(), |
||||||
|
new ScreenshotAppState("", System.currentTimeMillis())); |
||||||
|
} |
||||||
|
|
||||||
|
public static Font loadTtf( String resource ) { |
||||||
|
try { |
||||||
|
return Font.createFont(Font.TRUETYPE_FONT, |
||||||
|
TestBitmapFontLayout.class.getResourceAsStream(resource)); |
||||||
|
} catch( FontFormatException | IOException e ) { |
||||||
|
throw new RuntimeException("Error loading resource:" + resource, e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected Texture renderAwtFont( TestConfig test, int width, int height, BitmapFont bitmapFont ) { |
||||||
|
|
||||||
|
BitmapCharacterSet charset = bitmapFont.getCharSet(); |
||||||
|
|
||||||
|
// Create an image at least as big as our JME text
|
||||||
|
System.out.println("Creating image size:" + width + ", " + height); |
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); |
||||||
|
Graphics2D g2 = (Graphics2D)image.getGraphics(); |
||||||
|
|
||||||
|
g2.setColor(Color.lightGray); |
||||||
|
g2.fillRect(0, 0, width, height); |
||||||
|
g2.setColor(Color.cyan); |
||||||
|
g2.drawRect(0, 0, width, height); |
||||||
|
|
||||||
|
g2.setColor(new Color(0, 0, 128)); |
||||||
|
//g2.drawLine(0, 0, 50, 50);
|
||||||
|
//g2.drawLine(xFont, yFont, xFont + 30, yFont);
|
||||||
|
//g2.drawLine(xFont, yFont, xFont, yFont + 30);
|
||||||
|
|
||||||
|
//g2.drawString("Testing", 0, 10);
|
||||||
|
|
||||||
|
Font font = test.awtFont; |
||||||
|
System.out.println("Java font:" + font); |
||||||
|
|
||||||
|
float size = font.getSize2D(); |
||||||
|
FontMetrics fm = g2.getFontMetrics(font); |
||||||
|
System.out.println("Java font metrics:" + fm); |
||||||
|
|
||||||
|
String[] lines = test.text.split("\n"); |
||||||
|
|
||||||
|
g2.setFont(font); |
||||||
|
g2.setRenderingHint( |
||||||
|
RenderingHints.KEY_TEXT_ANTIALIASING, |
||||||
|
RenderingHints.VALUE_TEXT_ANTIALIAS_ON); |
||||||
|
|
||||||
|
int y = fm.getLeading() + fm.getMaxAscent(); |
||||||
|
for( String s : lines ) { |
||||||
|
g2.drawString(s, 0, y); |
||||||
|
y += fm.getHeight(); |
||||||
|
} |
||||||
|
|
||||||
|
g2.dispose(); |
||||||
|
|
||||||
|
Image jmeImage = new AWTLoader().load(image, true); |
||||||
|
return new Texture2D(jmeImage); |
||||||
|
} |
||||||
|
|
||||||
|
protected Node createVisual( TestConfig test ) { |
||||||
|
Node result = new Node(test.name); |
||||||
|
|
||||||
|
// For reasons I have trouble articulating, I want the visual's 0,0,0 to be
|
||||||
|
// the same as the JME rendered text. All other things will then be positioned relative
|
||||||
|
// to that.
|
||||||
|
// JME BitmapText (currently) renders from what it thinks the top of the letter is
|
||||||
|
// down. The actual bitmap text bounds may extend upwards... so we need to account
|
||||||
|
// for that in any labeling we add above it.
|
||||||
|
// Thus we add and setup the main test text first.
|
||||||
|
|
||||||
|
BitmapFont bitmapFont = assetManager.loadFont(test.jmeFont); |
||||||
|
BitmapCharacterSet charset = bitmapFont.getCharSet(); |
||||||
|
|
||||||
|
System.out.println("Test name:" + test.name); |
||||||
|
System.out.println("Charset line height:" + charset.getLineHeight()); |
||||||
|
System.out.println(" base:" + charset.getBase()); |
||||||
|
System.out.println(" rendered size:" + charset.getRenderedSize()); |
||||||
|
System.out.println(" width:" + charset.getWidth() + " height:" + charset.getHeight()); |
||||||
|
|
||||||
|
BitmapText bitmapText = new BitmapText(bitmapFont); |
||||||
|
bitmapText.setText(test.text); |
||||||
|
bitmapText.setColor(ColorRGBA.Black); |
||||||
|
result.attachChild(bitmapText); |
||||||
|
|
||||||
|
// And force it to update because BitmapText builds itself lazily.
|
||||||
|
result.updateLogicalState(0.1f); |
||||||
|
BoundingBox bb = (BoundingBox)bitmapText.getWorldBound(); |
||||||
|
|
||||||
|
BitmapText label = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt")); |
||||||
|
label.setText("Test:" + test.name); |
||||||
|
// Move the label up by its own size plus whatever extra headspace
|
||||||
|
// that the test text might have... plus a couple pixels of padding.
|
||||||
|
float yOffset = Math.max(0, bb.getCenter().y + bb.getYExtent()); |
||||||
|
label.move(0, label.getSize() + yOffset + 2, 0); |
||||||
|
label.setColor(new ColorRGBA(0, 0.2f, 0, 1f)); |
||||||
|
result.attachChild(label); |
||||||
|
|
||||||
|
|
||||||
|
// Bitmap text won't update itself automatically... it's lazy.
|
||||||
|
// That means it won't be able to tell us its bounding volume, etc... so
|
||||||
|
// we'll force it to update.
|
||||||
|
result.updateLogicalState(0.1f); |
||||||
|
|
||||||
|
// Add a bounding box visual
|
||||||
|
WireBox box = new WireBox(bb.getXExtent(), bb.getYExtent(), bb.getZExtent()); |
||||||
|
Geometry geom = new Geometry(test.name + " bounds", box); |
||||||
|
geom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); |
||||||
|
geom.getMaterial().setColor("Color", ColorRGBA.Red); |
||||||
|
geom.setLocalTranslation(bb.getCenter()); |
||||||
|
result.attachChild(geom); |
||||||
|
|
||||||
|
// Add a box to show 0,0 + font size
|
||||||
|
float size = bitmapText.getLineHeight() * 0.5f; |
||||||
|
box = new WireBox(size, size, 0); |
||||||
|
geom = new Geometry(test.name + " metric", box); |
||||||
|
geom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); |
||||||
|
geom.getMaterial().setColor("Color", ColorRGBA.Blue); |
||||||
|
geom.setLocalTranslation(size, -size, 0); |
||||||
|
result.attachChild(geom); |
||||||
|
|
||||||
|
float yBaseline = -charset.getBase(); |
||||||
|
Line line = new Line(new Vector3f(0, yBaseline, 0), new Vector3f(50, yBaseline, 0)); |
||||||
|
geom = new Geometry(test.name + " base", line); |
||||||
|
geom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); |
||||||
|
geom.getMaterial().setColor("Color", ColorRGBA.Green); |
||||||
|
result.attachChild(geom); |
||||||
|
|
||||||
|
System.out.println("text bb:" + bb); |
||||||
|
// We want the width and the height to cover the whole potential area
|
||||||
|
// for the font. So it can't just be the rendered bounds but must encompass
|
||||||
|
// the whole abstract font space... 0, 0, to center + extents.
|
||||||
|
//int width = (int)Math.round(bb.getCenter().x + bb.getXExtent());
|
||||||
|
//int height = (int)Math.round(-bb.getCenter().y + bb.getYExtent());
|
||||||
|
// No, that's not right either because in case like this:
|
||||||
|
// text bb:BoundingBox [Center: (142.0, -15.5, 0.0) xExtent: 142.0 yExtent: 20.5 zExtent: 0.0]
|
||||||
|
// We get:
|
||||||
|
// Creating image size:284, 36
|
||||||
|
// ...when it should be at least 41 high.
|
||||||
|
float x1 = bb.getCenter().x - bb.getXExtent(); |
||||||
|
float x2 = bb.getCenter().x + bb.getXExtent(); |
||||||
|
float y1 = bb.getCenter().y - bb.getYExtent(); |
||||||
|
float y2 = bb.getCenter().y + bb.getYExtent(); |
||||||
|
System.out.println("xy1:" + x1 + ", " + y1 + " xy2:" + x2 + ", " + y2); |
||||||
|
int width = (int)Math.round(x2 - Math.min(0, x1)); |
||||||
|
int height = (int)Math.round(y2 - Math.min(0, y1)); |
||||||
|
|
||||||
|
Texture awtText = renderAwtFont(test, width, height, bitmapFont); |
||||||
|
Quad quad = new Quad(width, height); |
||||||
|
geom = new Geometry(test.name + " awt1", quad); |
||||||
|
geom.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); |
||||||
|
geom.getMaterial().setTexture("ColorMap", awtText); |
||||||
|
// Quads render from the lower left corner up
|
||||||
|
geom.move(0, -height, 0); |
||||||
|
|
||||||
|
// That quad is now positioned directly over where the bitmap text is.
|
||||||
|
// We'll clone it and move one right and one down
|
||||||
|
Geometry right = geom.clone(); |
||||||
|
right.move(width, 0, 0); |
||||||
|
result.attachChild(right); |
||||||
|
|
||||||
|
Geometry down = geom.clone(); |
||||||
|
down.move(0, bb.getCenter().y - bb.getYExtent() - 1, 0); |
||||||
|
result.attachChild(down); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
setPauseOnLostFocus(false); |
||||||
|
setDisplayStatView(false); |
||||||
|
setDisplayFps(false); |
||||||
|
viewPort.setBackgroundColor(ColorRGBA.LightGray); |
||||||
|
|
||||||
|
setupTestScene(); |
||||||
|
setupUserInput(); |
||||||
|
|
||||||
|
setupInstructionsNote(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void setupInstructionsNote() { |
||||||
|
// Add some instructional text
|
||||||
|
String instructions = "WASD/Cursor Keys = scroll\n" |
||||||
|
+ "+/- = zoom\n" |
||||||
|
+ "space = reset view\n" |
||||||
|
+ "0 = reset zoom\n"; |
||||||
|
BitmapText note = new BitmapText(guiFont); |
||||||
|
note.setText(instructions); |
||||||
|
note.setColor(new ColorRGBA(0, 0.3f, 0, 1)); |
||||||
|
note.updateLogicalState(0.1f); |
||||||
|
|
||||||
|
BoundingBox bb = (BoundingBox)note.getWorldBound(); |
||||||
|
|
||||||
|
note.setLocalTranslation(cam.getWidth() - bb.getXExtent() * 2 - 20, |
||||||
|
cam.getHeight() - 20, 10); |
||||||
|
|
||||||
|
guiNode.attachChild(note); |
||||||
|
|
||||||
|
BitmapText note2 = note.clone(); |
||||||
|
note2.setColor(ColorRGBA.Black); |
||||||
|
note2.move(1, -1, -2); |
||||||
|
guiNode.attachChild(note2); |
||||||
|
|
||||||
|
BitmapText note3 = note.clone(); |
||||||
|
note3.setColor(ColorRGBA.White); |
||||||
|
note3.move(-1, 1, -1); |
||||||
|
guiNode.attachChild(note3); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected void setupTestScene() { |
||||||
|
String fox = "The quick brown fox jumps over the lazy dog."; |
||||||
|
String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"; |
||||||
|
String foxIpsum = fox + "\n" + loremIpsum; |
||||||
|
|
||||||
|
List<TestConfig> tests = new ArrayList<>(); |
||||||
|
|
||||||
|
|
||||||
|
// Note: for some Java fonts we reduce the point size to more closely
|
||||||
|
// match the pixel size... other than the Java-rendered fonts from Hiero, it will never
|
||||||
|
// be exact because of different font engines.
|
||||||
|
tests.add(new TestConfig("Hiero Java FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/FreeSerif16I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 16f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("Hiero FreeType FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/FT-FreeSerif16I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 14f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("Hiero Native FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/Native-FreeSerif16I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 15f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("AngelCode FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/BM-FreeSerif16I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 12f))); |
||||||
|
// It's actually between 12 and 13 but Java rounds up.
|
||||||
|
|
||||||
|
tests.add(new TestConfig("Hiero Padded FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/FreeSerif16Ipad5555.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 16f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("AngelCode Padded FreeSerif-16-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/BM-FreeSerif16Ipad5555.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 12f))); |
||||||
|
// It's actually between 12 and 13 but Java rounds up.
|
||||||
|
|
||||||
|
tests.add(new TestConfig("Hiero FreeSerif-32", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/FreeSerif32.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(32f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("AngelCode FreeSerif-32", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/BM-FreeSerif32.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(25f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("Hiero FreeSerif-64-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/FreeSerif64I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 64f))); |
||||||
|
|
||||||
|
tests.add(new TestConfig("AngelCode FreeSerif-64-Italic", |
||||||
|
foxIpsum, |
||||||
|
"jme3test/font/BM-FreeSerif64I.fnt", |
||||||
|
loadTtf("/jme3test/font/FreeSerif.ttf").deriveFont(Font.ITALIC, 50f))); |
||||||
|
|
||||||
|
|
||||||
|
/*tests.add(new TestConfig("Japanese", |
||||||
|
"\u3042\u3047\u3070\u3090\u309E\u3067\u308A\u3089\n"+ |
||||||
|
"\u3042\u3047\u3070\u3090\u309E\u3067\u308A\u3089", |
||||||
|
"jme3test/font/DJapaSubset.fnt", |
||||||
|
loadTtf("/jme3test/font/DroidSansFallback.ttf").deriveFont(32f)));*/ |
||||||
|
|
||||||
|
/*tests.add(new TestConfig("DroidSansMono-32", |
||||||
|
"Ă㥹ĔĕĖėχψωӮӯ₴₵₹\n"+ |
||||||
|
"Ă㥹ĔĕĖėχψωӮӯ₴₵₹", |
||||||
|
"jme3test/font/DMono32BI.fnt", |
||||||
|
loadTtf("/jme3test/font/DroidSansMono.ttf").deriveFont(32f)));*/ |
||||||
|
|
||||||
|
/*tests.add(new TestConfig("DroidSansMono-32", |
||||||
|
"Ă㥹ĔĕĖėχψωӮӯ\n"+ |
||||||
|
"Ă㥹ĔĕĖėχψωӮӯ", |
||||||
|
"jme3test/font/DMono32BI.fnt", |
||||||
|
loadTtf("/jme3test/font/DroidSansMono.ttf").deriveFont(Font.BOLD | Font.ITALIC, 32f))); |
||||||
|
*/ |
||||||
|
|
||||||
|
// Setup the test root node so that y = 0 is the top of the screen
|
||||||
|
testRoot.setLocalTranslation(0, cam.getHeight(), 0); |
||||||
|
testRoot.attachChild(scrollRoot); |
||||||
|
guiNode.attachChild(testRoot); |
||||||
|
|
||||||
|
float y = 0; //cam.getHeight();
|
||||||
|
|
||||||
|
for( TestConfig test : tests ) { |
||||||
|
System.out.println("y:" + y); |
||||||
|
|
||||||
|
Node vis = createVisual(test); |
||||||
|
|
||||||
|
BoundingBox bb = (BoundingBox)vis.getWorldBound(); |
||||||
|
System.out.println("bb:" + bb); |
||||||
|
|
||||||
|
// Render it relative to y, projecting down
|
||||||
|
vis.setLocalTranslation(1 + bb.getCenter().x - bb.getXExtent(), |
||||||
|
y - bb.getCenter().y - bb.getYExtent(), |
||||||
|
0); |
||||||
|
//vis.setLocalTranslation(1, y, 0);
|
||||||
|
scrollRoot.attachChild(vis); |
||||||
|
|
||||||
|
// Position to render the next one
|
||||||
|
y -= bb.getYExtent() * 2; |
||||||
|
|
||||||
|
// plus 5 pixels of padding
|
||||||
|
y -= 5; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void resetZoom() { |
||||||
|
testRoot.setLocalScale(1, 1, 1); |
||||||
|
} |
||||||
|
|
||||||
|
protected void resetView() { |
||||||
|
resetZoom(); |
||||||
|
scrollRoot.setLocalTranslation(0, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
protected void setupUserInput() { |
||||||
|
|
||||||
|
inputManager.addMapping(SCROLL_UP, new KeyTrigger(KeyInput.KEY_UP), |
||||||
|
new KeyTrigger(KeyInput.KEY_W)); |
||||||
|
inputManager.addMapping(SCROLL_DOWN, new KeyTrigger(KeyInput.KEY_DOWN), |
||||||
|
new KeyTrigger(KeyInput.KEY_S)); |
||||||
|
inputManager.addMapping(SCROLL_LEFT, new KeyTrigger(KeyInput.KEY_LEFT), |
||||||
|
new KeyTrigger(KeyInput.KEY_A)); |
||||||
|
inputManager.addMapping(SCROLL_RIGHT, new KeyTrigger(KeyInput.KEY_RIGHT), |
||||||
|
new KeyTrigger(KeyInput.KEY_D)); |
||||||
|
inputManager.addMapping(ZOOM_IN, new KeyTrigger(KeyInput.KEY_ADD), |
||||||
|
new KeyTrigger(KeyInput.KEY_EQUALS), |
||||||
|
new KeyTrigger(KeyInput.KEY_Q)); |
||||||
|
inputManager.addMapping(ZOOM_OUT, new KeyTrigger(KeyInput.KEY_MINUS), |
||||||
|
new KeyTrigger(KeyInput.KEY_SUBTRACT), |
||||||
|
new KeyTrigger(KeyInput.KEY_Z)); |
||||||
|
inputManager.addMapping(RESET_VIEW, new KeyTrigger(KeyInput.KEY_SPACE)); |
||||||
|
inputManager.addMapping(RESET_ZOOM, new KeyTrigger(KeyInput.KEY_0)); |
||||||
|
|
||||||
|
inputManager.addListener(new KeyStateListener(), |
||||||
|
RESET_VIEW, RESET_ZOOM, |
||||||
|
SCROLL_UP, SCROLL_DOWN, SCROLL_LEFT, SCROLL_RIGHT, |
||||||
|
ZOOM_IN, ZOOM_OUT); |
||||||
|
} |
||||||
|
|
||||||
|
public void simpleUpdate( float tpf ) { |
||||||
|
if( scroll.lengthSquared() != 0 ) { |
||||||
|
scrollRoot.move(scroll.mult(tpf)); |
||||||
|
} |
||||||
|
if( zoom.lengthSquared() != 0 ) { |
||||||
|
Vector3f current = testRoot.getLocalScale(); |
||||||
|
testRoot.setLocalScale(current.add(zoom.mult(tpf))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class KeyStateListener implements ActionListener { |
||||||
|
public void onAction(String name, boolean value, float tpf) { |
||||||
|
switch( name ) { |
||||||
|
case RESET_VIEW: |
||||||
|
// Only on the up
|
||||||
|
if( !value ) { |
||||||
|
resetView(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case RESET_ZOOM: |
||||||
|
// Only on the up
|
||||||
|
if( !value ) { |
||||||
|
resetZoom(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case ZOOM_IN: |
||||||
|
if( value ) { |
||||||
|
zoom.set(ZOOM_SPEED, ZOOM_SPEED, 0); |
||||||
|
} else { |
||||||
|
zoom.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
case ZOOM_OUT: |
||||||
|
if( value ) { |
||||||
|
zoom.set(-ZOOM_SPEED, -ZOOM_SPEED, 0); |
||||||
|
} else { |
||||||
|
zoom.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
case SCROLL_UP: |
||||||
|
if( value ) { |
||||||
|
scroll.set(0, -SCROLL_SPEED, 0); |
||||||
|
} else { |
||||||
|
scroll.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
case SCROLL_DOWN: |
||||||
|
if( value ) { |
||||||
|
scroll.set(0, SCROLL_SPEED, 0); |
||||||
|
} else { |
||||||
|
scroll.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
case SCROLL_LEFT: |
||||||
|
if( value ) { |
||||||
|
scroll.set(SCROLL_SPEED, 0, 0); |
||||||
|
} else { |
||||||
|
scroll.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
case SCROLL_RIGHT: |
||||||
|
if( value ) { |
||||||
|
scroll.set(-SCROLL_SPEED, 0, 0); |
||||||
|
} else { |
||||||
|
scroll.set(0, 0, 0); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class TestConfig { |
||||||
|
String name; |
||||||
|
String jmeFont; |
||||||
|
Font awtFont; |
||||||
|
String text; |
||||||
|
|
||||||
|
public TestConfig( String name, String text, String jmeFont, Font awtFont ) { |
||||||
|
this.name = name; |
||||||
|
this.text = text; |
||||||
|
this.jmeFont = jmeFont; |
||||||
|
this.awtFont = awtFont; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 211 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 241 KiB |
After Width: | Height: | Size: 127 KiB |
After Width: | Height: | Size: 58 KiB |