Added a bitmap font layout test.

monkanim
Paul Speed 7 years ago
parent 15285cc302
commit 989a4a2420
  1. 551
      jme3-examples/src/main/java/jme3test/gui/TestBitmapFontLayout.java
  2. 1031
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif16I.fnt
  3. BIN
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif16I_0.png
  4. 1031
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif16Ipad5555.fnt
  5. BIN
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif16Ipad5555_0.png
  6. 5904
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif32.fnt
  7. BIN
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif32_0.png
  8. 8790
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif64I.fnt
  9. BIN
      jme3-examples/src/main/resources/jme3test/font/BM-FreeSerif64I_0.png
  10. 18131
      jme3-examples/src/main/resources/jme3test/font/FT-FreeSerif16I.fnt
  11. BIN
      jme3-examples/src/main/resources/jme3test/font/FT-FreeSerif16I.png
  12. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif.ttf
  13. 8029
      jme3-examples/src/main/resources/jme3test/font/FreeSerif16I.fnt
  14. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif16I.png
  15. 8030
      jme3-examples/src/main/resources/jme3test/font/FreeSerif16Ipad5555.fnt
  16. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif16Ipad55551.png
  17. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif16Ipad55552.png
  18. 23475
      jme3-examples/src/main/resources/jme3test/font/FreeSerif32.fnt
  19. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif321.png
  20. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif322.png
  21. 27837
      jme3-examples/src/main/resources/jme3test/font/FreeSerif64I.fnt
  22. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif64I1.png
  23. BIN
      jme3-examples/src/main/resources/jme3test/font/FreeSerif64I2.png
  24. 18131
      jme3-examples/src/main/resources/jme3test/font/Native-FreeSerif16I.fnt
  25. BIN
      jme3-examples/src/main/resources/jme3test/font/Native-FreeSerif16I.png

@ -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;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Loading…
Cancel
Save