[committed] Support newline characters for BitmapText

The following patch allows using 'n' with BitmapText.

It only works with text which have a Box set.



edit: new patch to better support alignment



Index: src/com/jmex/angelfont/BitmapFont.java
===================================================================
--- src/com/jmex/angelfont/BitmapFont.java   (revision 4483)
+++ src/com/jmex/angelfont/BitmapFont.java   (working copy)
@@ -245,18 +245,22 @@
 
         for (int i = 0; i < text.length(); i++) {
             BitmapCharacter c = charSet.getCharacter((int) text.charAt(i));
-
-            if (c == null) {
+            if (c == null && (text.charAt(i) != 'n' && text.charAt(i) != 'r')) {
                 Logger.getLogger("").log(Level.FINE,
                         "Character '" + text.charAt(i) + "' is not in alphabet, skipping it.");
             } else {
-                float xOffset = c.getXOffset() * sizeScale;
-                float yOffset = c.getYOffset() * sizeScale;
-                float xAdvance = c.getXAdvance() * sizeScale;
-                float width = c.getWidth() * sizeScale;
-                float height = c.getHeight() * sizeScale;
-
-                // Newline
+                 float xOffset = 0;
+                float yOffset = 0;
+                float xAdvance = 0;
+                float width = 0;
+                float height = 0;
+               if (c != null) {
+                  xOffset = c.getXOffset() * sizeScale;
+                  yOffset = c.getYOffset() * sizeScale;
+                  xAdvance = c.getXAdvance() * sizeScale;
+                  width = c.getWidth() * sizeScale;
+                  height = c.getHeight() * sizeScale;
+               }
                 if (text.charAt(i) == 'n' || text.charAt(i) == 'r' || (lineWidth + xAdvance >= maxWidth)) {
                     x = block.getTextBox().x;
                     y -= charSet.getLineHeight() * sizeScale;
@@ -300,32 +304,31 @@
 
                             newLineLastChar = q.getCharacter();
                         } // for
-
-                        // Justify the previous (now complete) line
-                        if (alignment == Align.Center) {
-                            for (int k = 0; k < target.getQuantity(); k++) {
-                                FontQuad q = target.getQuad(k);
-
-                                if (q.getLineNumber() == lineNumber) {
-                                    q.setX(q.getX() + block.getTextBox().width / 2f - lastLineWidth / 2f);
-                                } // if
-                            } // for
-                        } // if
-                        if (alignment == Align.Right) {
-                            for (int k = 0; k < target.getQuantity(); k++) {
-                                FontQuad q = target.getQuad(k);
-                                if (q.getLineNumber() == lineNumber) {
-                                    q.setX(q.getX() + block.getTextBox().width - lastLineWidth);
-                                } // if
-                            } // for
-                        } // if
-
                     } else {
                         // New line without any "carry-down" word
                         firstCharOfLine = true;
                         lastLineWidth = lineWidth;
                         lineWidth = 0f;
                     } // else
+                    
+                   // Justify the previous (now complete) line
+                   if (alignment == Align.Center) {
+                      for (int k = 0; k < target.getQuantity(); k++) {
+                         FontQuad q = target.getQuad(k);
+                         
+                         if (q.getLineNumber() == lineNumber) {
+                            q.setX(q.getX() + block.getTextBox().width / 2f - lastLineWidth / 2f);
+                         } // if
+                      } // for
+                   } // if
+                   if (alignment == Align.Right) {
+                      for (int k = 0; k < target.getQuantity(); k++) {
+                         FontQuad q = target.getQuad(k);
+                         if (q.getLineNumber() == lineNumber) {
+                            q.setX(q.getX() + block.getTextBox().width - lastLineWidth);
+                         } // if
+                      } // for
+                   } // if
 
                     wordNumber = 1;
                     lineNumber++;


nice  :slight_smile:

i'n not sure if the alignment is correct now in all cases.

I will update TestBitmapFont to test more and different use cases before committing.

hey there.



now that i need it myself i was testing and two things were missing:

  • skip blanks at beginning of new line after n
  • add the feature to updateText(…) aswell (not just updateTextRect(…))



    heres the patch:


Index: src/com/jmex/angelfont/BitmapFont.java
===================================================================
--- src/com/jmex/angelfont/BitmapFont.java   (revision 4644)
+++ src/com/jmex/angelfont/BitmapFont.java   (working copy)
@@ -44,6 +44,7 @@
  *
  * @author dhdd, Andreas Grabner
  * @author Momoko_Fan (enhancements)
+ * @author Core_Dump, dhdd (n for new line feature)
  */
 public class BitmapFont {
 
@@ -101,24 +102,75 @@
         boolean useKerning = block.isKerning();
         target.ensureSize(text.length());
         int numActive = 0;
+        Align alignment = block.getAlignment();
+        float lastLineWidth = 0f;
 
         float incrScale = rightToLeft ? -1f : 1f;
 
         for (int i = 0; i < text.length(); i++) {
             char theChar = text.charAt(i);
             BitmapCharacter c = charSet.getCharacter((int) theChar);
-            if (c == null) {
-                // logger.warning("Character '" + text.charAt(i) +
-                // "' is not in alphabet, skipping it.");
-            } else if (theChar == 'n' || theChar == 'r' || theChar == 't') {
-                // dont print these characters
-                continue;
+            if (c == null && (text.charAt(i) != 'n' && text.charAt(i) != 'r')) {
+                Logger.getLogger("").log(Level.FINE,
+                        "Character '" + text.charAt(i) + "' is not in alphabet, skipping it.");
+            } else if(text.charAt(i) == ' ' && firstCharOfLine) {
+                Logger.getLogger("").log(Level.FINE,
+                        "Character '" + text.charAt(i) + "' is blank, skipping it because first char in line.");
             } else {
-                float xOffset = c.getXOffset() * sizeScale;
-                float yOffset = c.getYOffset() * sizeScale;
-                float xAdvance = c.getXAdvance() * sizeScale;
-                float width = c.getWidth() * sizeScale;
-                float height = c.getHeight() * sizeScale;
+                float xOffset = 0;
+                float yOffset = 0;
+                float xAdvance = 0;
+                float width = 0;
+                float height = 0;
+                if (c != null) {
+                    xOffset = c.getXOffset() * sizeScale;
+                    yOffset = c.getYOffset() * sizeScale;
+                    xAdvance = c.getXAdvance() * sizeScale;
+                    width = c.getWidth() * sizeScale;
+                    height = c.getHeight() * sizeScale;
+                }
+                
+                if (text.charAt(i) == 'n' || text.charAt(i) == 'r') {
+                    x = 0;
+                    y -= charSet.getLineHeight() * sizeScale;
+                    // float offset = 0f;
+                    
+                    // Justify the last (now complete) line
+                    if (alignment == Align.Center) {
+                        for (int k = 0; k < target.getQuantity(); k++) {
+                            FontQuad q = target.getQuad(k);
+                            if (q.getLineNumber() == lineNumber) {
+                                q.setX(q.getX() - lineWidth / 2f);
+                            } // if
+                        } // for
+                    } // if
+                    if (alignment == Align.Right) {
+                        for (int k = 0; k < target.getQuantity(); k++) {
+                            FontQuad q = target.getQuad(k);
+                            if (q.getLineNumber() == lineNumber) {
+                                q.setX(q.getX() - lineWidth);
+                            } // if
+                        } // for
+                    } // if
+                    if (rightToLeft) {
+                        // move all characters so that the current X = 0
+                        for (int k = 0; k < target.getQuantity(); k++) {
+                            FontQuad q = target.getQuad(k);
+                            if (q.getLineNumber() == lineNumber) {
+                                q.setX(q.getX() + lineWidth);
+                            } // if
+                        } // for
+                    } // if
+                    
+                    // New line without any "carry-down" word
+                    firstCharOfLine = true;
+                    lastLineWidth = lineWidth;
+                    lineWidth = 0f;
+                    wordNumber = 1;
+                    lineNumber++;
+                    continue;
+                } // End new line check
+                
 
                 // Adjust for kerning
                 float kernAmount = 0f;
@@ -179,7 +231,6 @@
             } // else
         } // for
 
-        Align alignment = block.getAlignment();
         // Justify the last (now complete) line
         if (alignment == Align.Center) {
             for (int k = 0; k < target.getQuantity(); k++) {
@@ -245,18 +296,25 @@
 
         for (int i = 0; i < text.length(); i++) {
             BitmapCharacter c = charSet.getCharacter((int) text.charAt(i));
-
-            if (c == null) {
+            if (c == null && (text.charAt(i) != 'n' && text.charAt(i) != 'r')) {
                 Logger.getLogger("").log(Level.FINE,
                         "Character '" + text.charAt(i) + "' is not in alphabet, skipping it.");
+            } else if(text.charAt(i) == ' ' && firstCharOfLine) {
+                Logger.getLogger("").log(Level.FINE,
+                        "Character '" + text.charAt(i) + "' is blank, skipping it because first char in line.");
             } else {
-                float xOffset = c.getXOffset() * sizeScale;
-                float yOffset = c.getYOffset() * sizeScale;
-                float xAdvance = c.getXAdvance() * sizeScale;
-                float width = c.getWidth() * sizeScale;
-                float height = c.getHeight() * sizeScale;
-
-                // Newline
+                 float xOffset = 0;
+                float yOffset = 0;
+                float xAdvance = 0;
+                float width = 0;
+                float height = 0;
+               if (c != null) {
+                  xOffset = c.getXOffset() * sizeScale;
+                  yOffset = c.getYOffset() * sizeScale;
+                  xAdvance = c.getXAdvance() * sizeScale;
+                  width = c.getWidth() * sizeScale;
+                  height = c.getHeight() * sizeScale;
+               }
                 if (text.charAt(i) == 'n' || text.charAt(i) == 'r' || (lineWidth + xAdvance >= maxWidth)) {
                     x = block.getTextBox().x;
                     y -= charSet.getLineHeight() * sizeScale;
@@ -300,32 +358,31 @@
 
                             newLineLastChar = q.getCharacter();
                         } // for
-
-                        // Justify the previous (now complete) line
-                        if (alignment == Align.Center) {
-                            for (int k = 0; k < target.getQuantity(); k++) {
-                                FontQuad q = target.getQuad(k);
-
-                                if (q.getLineNumber() == lineNumber) {
-                                    q.setX(q.getX() + block.getTextBox().width / 2f - lastLineWidth / 2f);
-                                } // if
-                            } // for
-                        } // if
-                        if (alignment == Align.Right) {
-                            for (int k = 0; k < target.getQuantity(); k++) {
-                                FontQuad q = target.getQuad(k);
-                                if (q.getLineNumber() == lineNumber) {
-                                    q.setX(q.getX() + block.getTextBox().width - lastLineWidth);
-                                } // if
-                            } // for
-                        } // if
-
                     } else {
                         // New line without any "carry-down" word
                         firstCharOfLine = true;
                         lastLineWidth = lineWidth;
                         lineWidth = 0f;
                     } // else
+                    
+                   // Justify the previous (now complete) line
+                   if (alignment == Align.Center) {
+                      for (int k = 0; k < target.getQuantity(); k++) {
+                         FontQuad q = target.getQuad(k);
+                         
+                         if (q.getLineNumber() == lineNumber) {
+                            q.setX(q.getX() + block.getTextBox().width / 2f - lastLineWidth / 2f);
+                         } // if
+                      } // for
+                   } // if
+                   if (alignment == Align.Right) {
+                      for (int k = 0; k < target.getQuantity(); k++) {
+                         FontQuad q = target.getQuad(k);
+                         if (q.getLineNumber() == lineNumber) {
+                            q.setX(q.getX() + block.getTextBox().width - lastLineWidth);
+                         } // if
+                      } // for
+                   } // if
 
                     wordNumber = 1;
                     lineNumber++;
Index: src/jmetest/text/TestBitmapFont.java
===================================================================
--- src/jmetest/text/TestBitmapFont.java   (revision 4644)
+++ src/jmetest/text/TestBitmapFont.java   (working copy)
@@ -35,6 +35,7 @@
 import java.net.URL;
 import java.util.concurrent.Callable;
 
+import com.jme.input.MouseInput;
 import com.jme.renderer.ColorRGBA;
 import com.jme.scene.Node;
 import com.jme.scene.Spatial.CullHint;
@@ -56,15 +57,19 @@
 public class TestBitmapFont {
 
     public static void main(String[] args) throws Exception {
-        final StandardGame game = new StandardGame("Test 3D Flat Text");
+        final StandardGame game = new StandardGame("Test BitmapFont & BitmapText");
         game.start();
 
-        final String txtB = "This extension provides a mechanism to specify vertex attrib and "
+        final String txtB = "This extension provides a mechanismn to specify vertex attrib and "
                 + "element array locations using GPU addresses.";
+        
+        final String txtC = "This extension provides a mechanism to specify vertex attrib and "
+            + "element array locations using GPU addresses.";
 
         GameTaskQueueManager.getManager().update(new Callable<Void>() {
 
             public Void call() throws Exception {
+                MouseInput.get().setCursorVisible(true);
                 final DebugGameState debug = new DebugGameState();
                 GameStateManager.getInstance().attachChild(debug);
                 debug.setActive(true);
@@ -104,20 +109,21 @@
                 txt3.setSize(32);
                 txt3.setAlignment(Align.Right);
                 txt3.setDefaultColor(ColorRGBA.blue.clone());
-                txt3.setText(txtB);
+                txt3.setText(txtC);
                 txt3.update();
 
                 BitmapText txt4 = new BitmapText(fnt, false);
                 txt4.setSize(32);
-                txt4.setText("Text without restriction. Text without restriction. Text without restriction. Text without restriction");
+                txt4.setAlignment(Align.Center);
+                txt4.setText("Text without restriction.n Text withoutn restriction.n Text without restriction. Text without restriction");
                 txt4.setDefaultColor(ColorRGBA.red.clone());
                 txt4.update();
-                txt4.setLocalTranslation(40, -game.getDisplay().getHeight() + txt2.getLineHeight() * 2, 0);
+                txt4.setLocalTranslation(140, -game.getDisplay().getHeight() + txt2.getLineHeight() * 5, 0);
 
-                txt4.setText("Shortened it! :)");
+                txt4.setText("Shortened it!n :)");
                 txt4.update();
 
-                txt4.setText("Elongated it to test! :)");
+                txt4.setText("Elongatedn it to test! :)");
                 txt4.update();
 
                 orthoNode.setLocalTranslation(0, game.getDisplay().getHeight(), 0);



please test.

great, seems to work fine.

i was hesitant to commit it, because it was not really complete, and i didn't use it much.

Core-Dump said:

great, seems to work fine.
i was hesitant to commit it, because it was not really complete, and i didn't use it much.


ok then, please commit it Core_Dump and set [Committed] flag  :)