From cf66bd4d45d909906f9ab52c81b8ab2f7ea79f10 Mon Sep 17 00:00:00 2001 From: "Zer..om" Date: Wed, 30 Jan 2013 14:12:26 +0000 Subject: [PATCH] Updated font creator too: 1. Not create an entry for glyphs that cannot be rendered 2. Look at the pixel bounds of an image when allocating space for it to prevent overlaps and prevent wasted space 3. Allow a character range to be selected (0->256 is default) when creating the font git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10245 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../gde/angelfont/AngelFontVisualPanel2.form | 131 +++++++++++++----- .../gde/angelfont/AngelFontVisualPanel2.java | 119 ++++++++++++---- .../com/jme3/gde/angelfont/Bundle.properties | 4 + .../com/jme3/gde/angelfont/FontCreator.java | 50 ++++--- 4 files changed, 225 insertions(+), 79 deletions(-) diff --git a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.form b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.form index 9e6c8aff6..0f6cb4878 100644 --- a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.form +++ b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.form @@ -1,4 +1,4 @@ - +
@@ -25,22 +25,23 @@ - + - - + + + - + - - - - - + + + + + @@ -80,7 +81,7 @@ - + @@ -93,16 +94,13 @@ - - - - - - + + + + - + - @@ -233,21 +231,41 @@ - - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + - + @@ -268,10 +286,17 @@ - + - + + + + + + + + @@ -355,6 +380,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.java b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.java index da57bca97..999acc144 100644 --- a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.java +++ b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/AngelFontVisualPanel2.java @@ -18,6 +18,8 @@ public final class AngelFontVisualPanel2 extends JPanel { int letterSpacing = 0; String fileName = ""; int style = Font.PLAIN; + int charRangeStart = 0; + int charRangeEnd = 256; /** Creates new form AngelFontVisualPanel2 */ public AngelFontVisualPanel2() { @@ -26,7 +28,6 @@ public final class AngelFontVisualPanel2 extends JPanel { jComboBox1.addItem("PLAIN"); jComboBox1.addItem("ITALIC"); jComboBox1.addItem("BOLD"); - } @Override @@ -46,7 +47,7 @@ public final class AngelFontVisualPanel2 extends JPanel { } private void updateFont() { - jLabel3.setIcon(new ImageIcon(FontCreator.buildFont(fontName, getFileName(), imageSize, fontSize, style, paddingX, paddingY, letterSpacing, true).getImage())); + jLabel3.setIcon(new ImageIcon(FontCreator.buildFont(fontName, getFileName(), imageSize, fontSize, style, paddingX, paddingY, letterSpacing, charRangeStart, charRangeEnd, true).getImage())); jLabel3.repaint(); jPanel1.repaint(); } @@ -81,6 +82,10 @@ public final class AngelFontVisualPanel2 extends JPanel { jLabel10 = new javax.swing.JLabel(); jLabel11 = new javax.swing.JLabel(); jSpinner5 = new javax.swing.JSpinner(); + jLabel12 = new javax.swing.JLabel(); + jSpinner6 = new javax.swing.JSpinner(); + jLabel13 = new javax.swing.JLabel(); + jSpinner7 = new javax.swing.JSpinner(); org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AngelFontVisualPanel2.class, "AngelFontVisualPanel2.jButton1.text")); // NOI18N @@ -147,14 +152,12 @@ public final class AngelFontVisualPanel2 extends JPanel { .addComponent(jLabel5) .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jSpinner3, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jSpinner2) - .addComponent(jTextField1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)) - .addComponent(jSpinner4, javax.swing.GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)) + .addComponent(jSpinner3) + .addComponent(jSpinner4) + .addComponent(jSpinner2) + .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 188, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel8) - .addGap(45, 45, 45)) + .addComponent(jLabel8)) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -213,23 +216,57 @@ public final class AngelFontVisualPanel2 extends JPanel { } }); + org.openide.awt.Mnemonics.setLocalizedText(jLabel12, org.openide.util.NbBundle.getMessage(AngelFontVisualPanel2.class, "AngelFontVisualPanel2.jLabel12.text")); // NOI18N + + jSpinner6.setModel(new javax.swing.SpinnerNumberModel(0, 0, 65535, 32)); + jSpinner6.setToolTipText(org.openide.util.NbBundle.getMessage(AngelFontVisualPanel2.class, "AngelFontVisualPanel2.jSpinner6.toolTipText")); // NOI18N + jSpinner6.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + jSpinner6letterSpacingUpdate(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel13, org.openide.util.NbBundle.getMessage(AngelFontVisualPanel2.class, "AngelFontVisualPanel2.jLabel13.text")); // NOI18N + + jSpinner7.setModel(new javax.swing.SpinnerNumberModel(256, 0, 65535, 32)); + jSpinner7.setToolTipText(org.openide.util.NbBundle.getMessage(AngelFontVisualPanel2.class, "AngelFontVisualPanel2.jSpinner7.toolTipText")); // NOI18N + jSpinner7.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + jSpinner7letterSpacingUpdate(evt); + } + }); + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel3Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jLabel11) - .addComponent(jLabel9) - .addComponent(jLabel1) - .addComponent(jLabel6)) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel3Layout.createSequentialGroup() + .addGap(27, 27, 27) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel9) + .addComponent(jLabel1) + .addComponent(jLabel6))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(jLabel12, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(jLabel11, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSpinner1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 78, Short.MAX_VALUE) - .addComponent(jLabel10, javax.swing.GroupLayout.DEFAULT_SIZE, 78, Short.MAX_VALUE) - .addComponent(jComboBox1, javax.swing.GroupLayout.Alignment.TRAILING, 0, 78, Short.MAX_VALUE) - .addComponent(jSpinner5, javax.swing.GroupLayout.DEFAULT_SIZE, 78, Short.MAX_VALUE)) + .addComponent(jSpinner1, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel10, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jComboBox1, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSpinner5) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jSpinner6, javax.swing.GroupLayout.PREFERRED_SIZE, 60, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel13) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSpinner7, javax.swing.GroupLayout.PREFERRED_SIZE, 58, Short.MAX_VALUE))) .addContainerGap()) ); jPanel3Layout.setVerticalGroup( @@ -246,10 +283,16 @@ public final class AngelFontVisualPanel2 extends JPanel { .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jSpinner1, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel1)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jSpinner5, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel11)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 8, Short.MAX_VALUE) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel11) - .addComponent(jSpinner5, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jLabel12, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jSpinner6, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel13) + .addComponent(jSpinner7, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); @@ -257,20 +300,21 @@ public final class AngelFontVisualPanel2 extends JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGroup(layout.createSequentialGroup() .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 531, Short.MAX_VALUE) + .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 404, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 432, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) ); }// //GEN-END:initComponents @@ -312,12 +356,25 @@ private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F private void letterSpacingUpdate(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_letterSpacingUpdate letterSpacing = (Integer) jSpinner5.getValue(); }//GEN-LAST:event_letterSpacingUpdate + + private void jSpinner6letterSpacingUpdate(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSpinner6letterSpacingUpdate + charRangeStart = (Integer)jSpinner6.getValue(); + updateFont(); + }//GEN-LAST:event_jSpinner6letterSpacingUpdate + + private void jSpinner7letterSpacingUpdate(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSpinner7letterSpacingUpdate + charRangeEnd = (Integer)jSpinner7.getValue(); + updateFont(); + }//GEN-LAST:event_jSpinner7letterSpacingUpdate + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JComboBox jComboBox1; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel10; private javax.swing.JLabel jLabel11; + private javax.swing.JLabel jLabel12; + private javax.swing.JLabel jLabel13; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; @@ -334,6 +391,8 @@ private void letterSpacingUpdate(javax.swing.event.ChangeEvent evt) {//GEN-FIRST private javax.swing.JSpinner jSpinner3; private javax.swing.JSpinner jSpinner4; private javax.swing.JSpinner jSpinner5; + private javax.swing.JSpinner jSpinner6; + private javax.swing.JSpinner jSpinner7; private javax.swing.JTextField jTextField1; // End of variables declaration//GEN-END:variables } diff --git a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/Bundle.properties b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/Bundle.properties index 3e53a0607..bcf24347c 100644 --- a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/Bundle.properties +++ b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/Bundle.properties @@ -28,3 +28,7 @@ AngelFontVisualPanel2.jComboBox1.toolTipText=The style of the font AngelFontVisualPanel2.jTextField1.toolTipText=The name of the generated files AngelFontVisualPanel2.jSpinner2.toolTipText=The resulting png image size will be Image Size x Image Size AngelFontVisualPanel2.jSpinner5.toolTipText=Defines the vertical padding used for each letter cell +AngelFontVisualPanel2.jLabel12.text=Char Range: +AngelFontVisualPanel2.jSpinner6.toolTipText=Defines the vertical padding used for each letter cell +AngelFontVisualPanel2.jLabel13.text=to +AngelFontVisualPanel2.jSpinner7.toolTipText=Defines the vertical padding used for each letter cell diff --git a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/FontCreator.java b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/FontCreator.java index eb8091d9d..46b370686 100644 --- a/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/FontCreator.java +++ b/sdk/jme3-angelfont/src/com/jme3/gde/angelfont/FontCreator.java @@ -9,6 +9,8 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; @@ -43,8 +45,12 @@ public abstract class FontCreator { public static AngelFont buildFont(String fontName, int bitmapSize, int fontSize, int style, boolean debug) { return buildFont(fontName, fontName, bitmapSize, fontSize, style, 0, 0, 0, debug); } - + public static AngelFont buildFont(String fontName, String fileName, int bitmapSize, int fontSize, int style, int paddingX, int paddingY, int letterSpacing, boolean debug) { + return buildFont(fontName, fileName, bitmapSize, fontSize, style, paddingX, paddingY, letterSpacing, 0, 256, debug); + } + + public static AngelFont buildFont(String fontName, String fileName, int bitmapSize, int fontSize, int style, int paddingX, int paddingY, int letterSpacing, int firstChar, int lastChar, boolean debug) { BufferedImage fontImage; Font font; @@ -62,6 +68,7 @@ public abstract class FontCreator { } g.setColor(OPAQUE_WHITE); g.setBackground(TRANSPARENT_BLACK); + FontRenderContext frc = g.getFontRenderContext(); FontMetrics fm = g.getFontMetrics(); @@ -70,38 +77,49 @@ public abstract class FontCreator { g.drawRect(0, 0, bitmapSize - 1, bitmapSize - 1); } int xPos = 0; - int yPos = 0; - int height = 0; - for (int i = 0; i < 256; i++) { + int height = fm.getDescent() + fm.getAscent(); + int yPos = height + (paddingY * 2); + + for (int i = firstChar; i <= lastChar; i++) { char ch[] = {(char) i}; String temp = new String(ch); - Rectangle2D bounds = fm.getStringBounds(temp, g); - height = fm.getDescent() + fm.getAscent(); - if (yPos == 0) { - yPos = height + (paddingY * 2); + + if (!font.canDisplay((char)i)) { + continue; } - if (xPos + bounds.getWidth() + (paddingX * 2) > bitmapSize) { + + TextLayout tl = new TextLayout(temp, font, frc); + Rectangle2D pixelBounds = tl.getPixelBounds(frc, xPos, yPos); + + int width = (int)Math.ceil(pixelBounds.getWidth()); + + int advance = (int)Math.ceil(tl.getAdvance()); + + int xOffset = (int)Math.round(pixelBounds.getX()) - xPos; + + if (xPos + width + (paddingX * 2) > bitmapSize) { xPos = 0; yPos += height + (paddingY * 2); } - g.drawString(temp, xPos + paddingX, yPos + paddingY); + + g.drawString(temp, xPos + paddingX - xOffset, yPos + paddingY); if (debug) { g.setColor(Color.BLUE); - g.drawRect(xPos, yPos - fm.getAscent(), (int) bounds.getWidth() + (paddingX * 2), height + (paddingY * 2)); + g.drawRect(xPos, yPos - fm.getAscent(), width + (paddingX * 2), height + (paddingY * 2)); g.setColor(Color.WHITE); } charLocs = charLocs + "char id=" + i + " x=" + xPos + " y=" + (yPos - fm.getAscent()) - + " width=" + ((int) bounds.getWidth() + (paddingX * 2)) - + " height=" + ((int) bounds.getHeight() + (paddingY * 2)) - + " xoffset=0" + + " width=" + (width + (paddingX * 2)) + + " height=" + (fm.getHeight() + (paddingY * 2)) + + " xoffset=" + (xOffset) + " yoffset=0" - + " xadvance=" + (((int) bounds.getWidth() + letterSpacing) - 1) + " " + + " xadvance=" + ((advance + letterSpacing) - 1) + " " + " page=0" + " chnl=0\n"; - xPos += bounds.getWidth() + (paddingX * 2); + xPos += width + (paddingX * 2); } charLocs = "info face=null " + "size=" + fontSize + " "