001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.Gdx; 004import com.badlogic.gdx.assets.AssetDescriptor; 005import com.badlogic.gdx.assets.AssetManager; 006import com.badlogic.gdx.graphics.Color; 007import com.badlogic.gdx.graphics.Pixmap; 008import com.badlogic.gdx.graphics.Texture; 009import com.badlogic.gdx.graphics.g2d.Batch; 010import com.badlogic.gdx.graphics.g2d.BitmapFont; 011import com.badlogic.gdx.graphics.g2d.TextureRegion; 012import com.badlogic.gdx.graphics.glutils.ShaderProgram; 013import com.badlogic.gdx.scenes.scene2d.Actor; 014import com.badlogic.gdx.scenes.scene2d.ui.Image; 015import com.badlogic.gdx.scenes.scene2d.ui.Label; 016import com.badlogic.gdx.utils.Align; 017import com.badlogic.gdx.utils.Disposable; 018import regexodus.ds.CharCharMap; 019import squidpony.IColorCenter; 020import squidpony.Maker; 021import squidpony.StringKit; 022import squidpony.squidmath.NumberTools; 023import squidpony.squidmath.OrderedMap; 024 025import java.util.ArrayList; 026import java.util.Collection; 027 028/** 029 * Class for creating text blocks. 030 * 031 * This class defaults to having no padding and having no font set. You can use a 032 * default square or narrow font by calling the appropriate method, or set the font 033 * to any AngelCode bitmap font on the classpath (typically in libGDX, this would be 034 * in the assets folder; these fonts can be created by Hiero in the libGDX tools, 035 * see https://github.com/libgdx/libgdx/wiki/Hiero for more) 036 * 037 * After all settings are set, one of the initialization methods must be called 038 * before the factory can be used. 039 * 040 * In order to easily support Unicode, strings are treated as a series of code 041 * points. 042 * 043 * All images have transparent backgrounds. 044 * 045 * @author Eben Howard - http://squidpony.com - howard@squidpony.com 046 * @author Tommy Ettinger 047 */ 048public class TextCellFactory implements Disposable { 049 050 /** 051 * How many styles are supported by this TextCellFactory; always 1 unless changed in a subclass. 052 */ 053 public int supportedStyles() { 054 return 1; 055 } 056 /** 057 * The commonly used symbols in roguelike games. 058 */ 059 public static final String DEFAULT_FITTING = 060 " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 061 /** 062 * All symbols that squidlib-util permits itself to generate; this is a shared subset across most of the larger 063 * fonts in {@link DefaultResources}. 064 */ 065 public static final String SQUID_FITTING = StringKit.PERMISSIBLE_CHARS; 066 /** 067 * The {@link AssetManager} from where to load the font. Use it to share 068 * loading of a font's file across multiple factories. 069 */ 070 protected /* Nullable */AssetManager assetManager; 071 public BitmapFont bmpFont; 072 protected TextureRegion block; 073 protected TextureRegion dirMarker; 074 protected String fitting = SQUID_FITTING; 075 protected IColorCenter<Color> scc; 076 protected int leftPadding, rightPadding, topPadding, bottomPadding; 077 protected float width = 1, height = 1; 078 public float actualCellWidth = 1, actualCellHeight = 1; 079 protected float distanceFieldScaleX = 36f, distanceFieldScaleY = 36f; 080 protected boolean initialized, initializedByFont, initializedBySize; 081 protected boolean distanceField; 082 protected boolean msdf; 083 /** 084 * For distance field and MSDF fonts, this is the ShaderProgram that will produce the intended effect. 085 * Usually should not be changed manually unless you know what you are doing. 086 */ 087 public ShaderProgram shader; 088 protected float smoothingMultiplier = 1.2f; 089 protected float descent, lineHeight; 090 protected Label.LabelStyle style; 091 protected CharCharMap swap = new CharCharMap(8); 092 { 093 swap.defaultReturnValue('\uffff'); 094 } 095 protected char directionGlyph = '^'; 096 protected OrderedMap<Character, TextureRegion> glyphTextures = new OrderedMap<>(16); 097 098 protected StringBuilder mut = new StringBuilder(1).append('\0'); 099 100 /** 101 * Creates a default valued factory. One of the initialization methods must 102 * be called before this factory can be used! 103 */ 104 public TextCellFactory() { 105 this(null); 106 } 107 108 /** 109 * A default valued factory that uses the given {@link AssetManager} to load 110 * the font file. Use this constructor if you are likely to load the same 111 * font over and over (recall that, without an {@link AssetManager}, each 112 * instance of {@link TextCellFactory} will load its font from disk). This 113 * primarily matters if you are using fonts not bundled with SquidLib, since 114 * accessing a BitmapFont with a method (not a String) from DefaultResources 115 * caches the BitmapFont already. 116 * 117 * @param assetManager an ordinary libGDX AssetManager 118 */ 119 public TextCellFactory(/* Nullable */ AssetManager assetManager) { 120 this.assetManager = assetManager; 121 scc = DefaultResources.getSCC(); 122 swap.put('\u0006', ' '); 123 } 124 125 public TextCellFactory copy() 126 { 127 TextCellFactory next = new TextCellFactory(assetManager); 128 if(bmpFont == null) 129 bmpFont = DefaultResources.getIncludedFont(); 130 next.bmpFont = DefaultResources.copyFont(bmpFont); 131 next.block = block; 132 next.swap = swap.clone(); // explicitly implemented by CharCharMap 133 next.swap.defaultReturnValue('\uffff'); // ... but it forgets to copy this field 134 next.distanceField = distanceField; 135 next.msdf = msdf; 136 next.distanceFieldScaleX = distanceFieldScaleX; 137 next.distanceFieldScaleY = distanceFieldScaleY; 138 next.shader = null; 139 next.fitting = fitting; 140 next.height = height; 141 next.width = width; 142 next.actualCellWidth = actualCellWidth; 143 next.actualCellHeight = actualCellHeight; 144 next.descent = descent; 145 next.lineHeight = lineHeight; 146 next.smoothingMultiplier = smoothingMultiplier; 147 next.scc = scc; 148 next.directionGlyph = directionGlyph; 149 if(initializedBySize) 150 next.initBySize(); 151 else if(initializedByFont) 152 next.initByFont(); 153 return next; 154 } 155 /** 156 * Initializes the factory to then be able to create text cells on demand. 157 * <br> 158 * Will match the width and height to the space width of the font and the 159 * line height of the font, respectively. Calling this after the factory 160 * has already been initialized will re-initialize it. This will not work 161 * with distance field or MSDF fonts; for those, use {@link #initBySize()}. 162 * 163 * @return this for method chaining 164 */ 165 public TextCellFactory initByFont() { 166 if(bmpFont == null) 167 bmpFont = DefaultResources.getIncludedFont(); 168 bmpFont.setFixedWidthGlyphs(fitting); 169 width = bmpFont.getSpaceXadvance(); 170 lineHeight = bmpFont.getLineHeight(); 171 height = (lineHeight); 172 descent = bmpFont.getDescent(); 173 174 actualCellWidth = width; 175 actualCellHeight = height; 176 BitmapFont.Glyph g = bmpFont.getData().missingGlyph; 177 if(g != null) 178 { 179 block = new TextureRegion(bmpFont.getRegion(), g.srcX + 1, g.srcY + 1, 1, 1); 180 } 181 else { 182 Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888); 183 temp.setColor(Color.WHITE); 184 temp.fill(); 185 Texture white = new Texture(1, 1, Pixmap.Format.RGBA8888); 186 white.draw(temp, 0, 0); 187 block = new TextureRegion(white); 188 temp.dispose(); 189 } 190 style = new Label.LabelStyle(bmpFont, null); 191 BitmapFont.Glyph dg = bmpFont.getData().getGlyph(directionGlyph); 192 if(dg != null) 193 dirMarker = new TextureRegion(bmpFont.getRegion(dg.page), dg.srcX, dg.srcY, dg.width, dg.height); 194 initialized = true; 195 initializedByFont = true; 196 return this; 197 } 198 199 /** 200 * Initializes the factory to then be able to create text cells on demand. 201 * <br> 202 * Will strictly use the provided width and height values to size the cells. 203 * Calling this after the factory has already been initialized will 204 * re-initialize it, but will re-create several objects (including compiling 205 * a ShaderProgram, which can be very challenging for a GPU to do each frame). 206 * If you need to re-initialize often to adjust size, use {@link #resetSize()}, 207 * which does not allocate new objects if this was already initialized, and 208 * will just delegate to this method if this wasn't initialized. 209 * 210 * @return this for method chaining 211 */ 212 public TextCellFactory initBySize() { 213 if(bmpFont == null) 214 bmpFont = DefaultResources.getIncludedFont(); 215 BitmapFont.Glyph g = bmpFont.getData().missingGlyph; 216 if(g != null) 217 { 218 block = new TextureRegion(bmpFont.getRegion(), g.srcX + 1, g.srcY + 1, 1, 1); 219 } 220 else { 221 Pixmap temp = new Pixmap(1, 1, Pixmap.Format.RGBA8888); 222 temp.setColor(Color.WHITE); 223 temp.fill(); 224 Texture white = new Texture(1, 1, Pixmap.Format.RGBA8888); 225 white.draw(temp, 0, 0); 226 block = new TextureRegion(white); 227 temp.dispose(); 228 } 229 if(msdf) 230 { 231 bmpFont.getData().setScale(width / distanceFieldScaleX, height / distanceFieldScaleY); 232 233 shader = new ShaderProgram(DefaultResources.vertexShader, DefaultResources.msdfFragmentShader); 234 if (!shader.isCompiled()) { 235 Gdx.app.error("shader", "Distance Field font shader compilation failed:\n" + shader.getLog()); 236 } 237 //lineTweak = lineHeight / 20f; 238 //distanceFieldScaleX *= (((float)width) / height) / (distanceFieldScaleX / distanceFieldScaleY); 239 } 240 else if(distanceField) 241 { 242 bmpFont.getData().setScale(width / distanceFieldScaleX, height / distanceFieldScaleY); 243 244 shader = new ShaderProgram(DefaultResources.vertexShader, DefaultResources.fragmentShader); 245 if (!shader.isCompiled()) { 246 Gdx.app.error("shader", "Distance Field font shader compilation failed:\n" + shader.getLog()); 247 } 248 } 249 else { 250 shader = FilterBatch.createDefaultShader(); 251 } 252 lineHeight = bmpFont.getLineHeight(); 253 descent = bmpFont.getDescent(); 254 style = new Label.LabelStyle(bmpFont, null); 255 BitmapFont.Glyph dg = bmpFont.getData().getGlyph(directionGlyph); 256 if(dg != null) 257 dirMarker = new TextureRegion(bmpFont.getRegion(dg.page), dg.srcX, dg.srcY, dg.width, dg.height); 258 initialized = true; 259 initializedBySize = true; 260 return this; 261 } 262 263 /** 264 * Acts like calling {@link #initBySize()}, but doesn't create new ShaderPrograms or other objects if this has 265 * already been initialized. If this has not been initialized, simply returns initBySize(). This method is safe to 266 * call every frame if the font size continually changes, where initBySize() is not. 267 * @return this for chaining 268 */ 269 public TextCellFactory resetSize() 270 { 271 return resetSize(width, height); 272 } 273 274 /** 275 * Acts like calling {@link #width(float)}, {@link #height(float)}, and {@link #initBySize()} in succession, but 276 * doesn't create new ShaderPrograms or other objects if this has already been initialized. If this has not been 277 * initialized, calls width() and height() and then simply returns initBySize(). This method is safe to call every 278 * frame if the font size continually changes, where initBySize() is not. 279 * @param newWidth the new width of a single cell, as a float that usually corresponds to pixels 280 * @param newHeight the new height of a single cell, as a float that usually corresponds to pixels 281 * @return this for chaining 282 */ 283 public TextCellFactory resetSize(final float newWidth, final float newHeight) 284 { 285 width(newWidth); 286 height(newHeight); 287 if(!initialized) 288 return initBySize(); 289 if(msdf || distanceField) 290 { 291 bmpFont.getData().setScale(width / distanceFieldScaleX, height / distanceFieldScaleY); 292 } 293 lineHeight = bmpFont.getLineHeight(); 294 descent = bmpFont.getDescent(); 295 296 return this; 297 } 298 299 /** 300 * Identical to {@link #initBySize()}. 301 * 302 * @see #initBySize() The docs for initBySize() apply here. 303 * @return this for method chaining 304 */ 305 public TextCellFactory initVerbatim() { 306 return initBySize(); 307 } 308 309 /** 310 * Returns the {@link BitmapFont} used by this factory. 311 * 312 * @return the BitmapFont this uses 313 */ 314 public BitmapFont font() { 315 return bmpFont; 316 } 317 318 /** 319 * Sets this factory to use the provided font. 320 * 321 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 322 * methods in this class. 323 * 324 * This should be called with an argument such as "Rogue-Zodiac-6x12.fnt", that is, it should have the .fnt 325 * extension as opposed to the .png that accompanies such a bitmap font. The bitmap font should be either in the 326 * internal folder that libGDX knows about, which means it is in the assets folder of your project usually. 327 * These BitmapFont resources are already known by SquidLib, but may need separate downloads (detailed in the linked 328 * DefaultResources documentation): 329 * <ul> 330 * <li>{@link DefaultResources#getDefaultFont()} = "Zodiac-Square-12x12.fnt"</li> 331 * <li>{@link DefaultResources#getDefaultNarrowFont()} = "Rogue-Zodiac-6x12.fnt"</li> 332 * <li>{@link DefaultResources#getDefaultUnicodeFont()} = "Mandrill-6x16.fnt"</li> 333 * <li>{@link DefaultResources#getSmoothFont()} = "Inconsolata-LGC-8x18.fnt"</li> 334 * <li>{@link DefaultResources#getLargeFont()} = "Zodiac-Square-24x24.fnt"</li> 335 * <li>{@link DefaultResources#getLargeNarrowFont()} = "Rogue-Zodiac-12x24.fnt"</li> 336 * <li>{@link DefaultResources#getLargeUnicodeFont()} = "Mandrill-12x32.fnt"</li> 337 * <li>{@link DefaultResources#getLargeSmoothFont()} = "Inconsolata-LGC-12x24.fnt"</li> 338 * <li>{@link DefaultResources#getExtraLargeNarrowFont()} = "Rogue-Zodiac-18x36.fnt"</li> 339 * </ul> 340 * "Rogue-Zodiac-12x24.fnt", which is easily accessed by the field DefaultResources.narrowNameLarge , can also 341 * be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible 342 * as DefaultResources.squareName , can be set using TextCellFactory.defaultSquareFont() instead of font(). 343 * "Inconsolata-LGC-12x24.fnt", also accessible as DefaultResources.smoothNameLarge , can be set using 344 * TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if 345 * the same one is requested later, but this font() method will not. 346 * <br> 347 * See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts 348 * in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool. 349 * 350 * @param fontpath the path to the font to use 351 * @return this factory for method chaining 352 */ 353 public TextCellFactory font(String fontpath) { 354 if (assetManager == null) { 355 if (Gdx.files.internal(fontpath).exists()) 356 bmpFont = new BitmapFont(Gdx.files.internal(fontpath)); 357 else if (Gdx.files.classpath(fontpath).exists()) 358 bmpFont = new BitmapFont(Gdx.files.classpath(fontpath)); 359 else 360 bmpFont = DefaultResources.getIncludedFont(); 361 } 362 else { 363 assetManager.load(new AssetDescriptor<>(fontpath, BitmapFont.class)); 364 /* 365 * We're using the AssetManager not be asynchronous, but to avoid 366 * loading a file twice (because that takes some time (tens of 367 * milliseconds)). Hence this KISS code to avoid having to handle a 368 * not-yet-loaded font: 369 */ 370 assetManager.finishLoading(); 371 bmpFont = assetManager.get(fontpath, BitmapFont.class); 372 } 373 return this; 374 } 375 /** 376 * Sets this factory to use the provided BitmapFont as its font without re-constructing anything. 377 * 378 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 379 * methods in this class. 380 * 381 * This should be called with an argument such as {@code DefaultResources.getDefaultFont()} or any other variable 382 * with BitmapFont as its type. The bitmap font will not be loaded from file with this method, which it would be if 383 * you called the overload of font() that takes a String more than once. These BitmapFont resources are already 384 * known by SquidLib, but may need separate downloads (detailed in the linked DefaultResources documentation): 385 * <ul> 386 * <li>{@link DefaultResources#getDefaultFont()} = "Zodiac-Square-12x12.fnt"</li> 387 * <li>{@link DefaultResources#getDefaultNarrowFont()} = "Rogue-Zodiac-6x12.fnt"</li> 388 * <li>{@link DefaultResources#getDefaultUnicodeFont()} = "Mandrill-6x16.fnt"</li> 389 * <li>{@link DefaultResources#getSmoothFont()} = "Inconsolata-LGC-8x18.fnt"</li> 390 * <li>{@link DefaultResources#getLargeFont()} = "Zodiac-Square-24x24.fnt"</li> 391 * <li>{@link DefaultResources#getLargeNarrowFont()} = "Rogue-Zodiac-12x24.fnt"</li> 392 * <li>{@link DefaultResources#getLargeUnicodeFont()} = "Mandrill-12x32.fnt"</li> 393 * <li>{@link DefaultResources#getLargeSmoothFont()} = "Inconsolata-LGC-12x24.fnt"</li> 394 * <li>{@link DefaultResources#getExtraLargeNarrowFont()} = "Rogue-Zodiac-18x36.fnt"</li> 395 * </ul> 396 * "Rogue-Zodiac-12x24.fnt", which is easily accessed by the method DefaultResources.getLargeNarrowFont() , can also 397 * be set using TextCellFactory.defaultNarrowFont() instead of font(). "Zodiac-Square-12x12.fnt", also accessible 398 * with DefaultResources.getDefaultFont() , can be set using TextCellFactory.defaultSquareFont() instead of font(). 399 * "Inconsolata-LGC-12x24.fnt", also accessible with DefaultResources.getLargeSmoothFont() , can be set using 400 * TextCellFactory.defaultFont() instead of font(). All three of these alternatives will cache the BitmapFont if 401 * the same one is requested later, but this font() method will not. 402 * <br> 403 * See https://github.com/libgdx/libgdx/wiki/Hiero for some ways to create a bitmap font this can use. Several fonts 404 * in this list were created using Hiero (not Hiero4), and several were created with AngelCode's BMFont tool. 405 * 406 * @param bitmapFont the BitmapFont this should use 407 * @return this factory for method chaining 408 */ 409 public TextCellFactory font(BitmapFont bitmapFont) { 410 if (bitmapFont == null) { 411 bmpFont = DefaultResources.getIncludedFont(); 412 } 413 else { 414 bmpFont = bitmapFont; 415 } 416 return this; 417 } 418 419 /** 420 * Sets the font to a distance field font with the given String path to a .fnt file and String path to a texture. 421 * Distance field fonts should scale cleanly to multiple resolutions without artifacts. Does not use AssetManager 422 * since you shouldn't need to reload the font if it scales with one image. You need to configure the shader to use 423 * distance field fonts unless a class already does this for you (SquidLayers handles shader configuration 424 * internally, for example). TextCellFactory has a method, configureShader(Batch), that does this and should be 425 * called while that Batch has begun rendering, typically in an override of some containing Scene2D Group's 426 * draw(Batch, float) method. 427 * <br> 428 * At least two distance field fonts are included in SquidLib; one is square, one is narrow, and they can both be 429 * accessed using either the predefined TextCellFactory objects in DefaultResources, accessible with 430 * getStretchableFont() for narrow or getStretchableSquareFont() for square, or the setter methods in this class, 431 * defaultDistanceFieldFont() for square and defaultNarrowDistanceFieldFont() for narrow. 432 * <br> 433 * To create distance field fonts that work well with monospace layout is... time-consuming and error-prone, though 434 * not especially difficult for most fonts. The process is documented as well as we can, given how differently all 435 * fonts are made, in a file not included in the distribution JAR but present on GitHub: 436 * <a href="https://github.com/SquidPony/SquidLib/blob/master/squidlib/etc/making-distance-field-fonts.txt">Instructions here</a>. 437 * A separate project is dedicated to automating this process somewhat, 438 * <a href="https://github.com/tommyettinger/Glamer">Glamer</a>; Glamer can also produce MSDF fonts. 439 * @param fontPath the path to a .fnt bitmap font file with distance field effects applied, which requires a complex 440 * process to create. 441 * @param texturePath the path to the texture used by the bitmap font 442 * @return this factory for method chaining 443 */ 444 public TextCellFactory fontDistanceField(String fontPath, String texturePath) { 445 Texture tex; 446 if (Gdx.files.internal(texturePath).exists()) { 447 Gdx.app.debug("font", "Using internal font texture at " + texturePath); 448 tex = new Texture(Gdx.files.internal(texturePath), false); 449 tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); 450 } else if (Gdx.files.classpath(texturePath).exists()) { 451 Gdx.app.debug("font", "Using classpath font texture at " + texturePath); 452 tex = new Texture(Gdx.files.classpath(texturePath), false); 453 tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); 454 } else { 455 bmpFont = DefaultResources.getIncludedFont(); 456 Gdx.app.error("TextCellFactory", "Could not find font file: " + texturePath + ", using defaults"); 457 return this; 458 } 459 if (Gdx.files.internal(fontPath).exists()) { 460 Gdx.app.debug("font", "Using internal font at " + fontPath); 461 bmpFont = new BitmapFont(Gdx.files.internal(fontPath), new TextureRegion(tex), false); 462 distanceField = true; 463 } else if (Gdx.files.classpath(fontPath).exists()) { 464 Gdx.app.debug("font", "Using classpath font at " + fontPath); 465 bmpFont = new BitmapFont(Gdx.files.classpath(fontPath), new TextureRegion(tex), false); 466 distanceField = true; 467 } else { 468 bmpFont = DefaultResources.getIncludedFont(); 469 Gdx.app.error("TextCellFactory", "Could not find font file: " + fontPath + ", using defaults"); 470 } 471 //bmpFont.getData().padBottom = bmpFont.getDescent(); 472 distanceFieldScaleX = bmpFont.getSpaceXadvance() - 1f; 473 distanceFieldScaleY = bmpFont.getLineHeight() - 1f; 474 return this; 475 } 476 /** 477 * @param fontPath the path to a .fnt bitmap font file with multi-channel distance field effects applied, which 478 * requires a complex process to create. 479 * @param texturePath the path to the texture used by the bitmap font 480 * @return this factory for method chaining 481 */ 482 public TextCellFactory fontMultiDistanceField(String fontPath, String texturePath) { 483 Texture tex; 484 if (Gdx.files.internal(texturePath).exists()) { 485 Gdx.app.debug("font", "Using internal font texture at " + texturePath); 486 tex = new Texture(Gdx.files.internal(texturePath), Pixmap.Format.RGB888, false); 487 tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); 488 } else if (Gdx.files.classpath(texturePath).exists()) { 489 Gdx.app.debug("font", "Using classpath font texture at " + texturePath); 490 tex = new Texture(Gdx.files.classpath(texturePath), Pixmap.Format.RGB888, false); 491 tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); 492 } else { 493 bmpFont = DefaultResources.getIncludedFont(); 494 Gdx.app.error("TextCellFactory", "Could not find font file: " + texturePath + ", using defaults"); 495 return this; 496 } 497 if (Gdx.files.internal(fontPath).exists()) { 498 Gdx.app.debug("font", "Using internal font at " + fontPath); 499 bmpFont = new BitmapFont(Gdx.files.internal(fontPath), new TextureRegion(tex), false); 500 msdf = true; 501 } else if (Gdx.files.classpath(fontPath).exists()) { 502 Gdx.app.debug("font", "Using classpath font at " + fontPath); 503 bmpFont = new BitmapFont(Gdx.files.classpath(fontPath), new TextureRegion(tex), false); 504 msdf = true; 505 } else { 506 bmpFont = DefaultResources.getIncludedFont(); 507 Gdx.app.error("TextCellFactory", "Could not find font file: " + fontPath + ", using defaults"); 508 } 509 //bmpFont.getData().padBottom = bmpFont.getDescent(); 510 if(msdf) 511 { 512 bmpFont.getData().setScale(0.75f, 1f); 513 } 514 distanceFieldScaleX = bmpFont.getSpaceXadvance() - 1f; 515 distanceFieldScaleY = bmpFont.getLineHeight() - 1f; 516 return this; 517 } 518 /** 519 * Sets this factory to use the one font included with libGDX, which is Arial at size 15 px. Does it correctly 520 * display when used in a grid? Probably not as well as you'd hope. You should probably get some of the assets that 521 * accompany SquidLib, and can be downloaded directly from GitHub (not available as one monolithic jar via Maven 522 * Central, but that lets you pick and choose individual assets). Get a .fnt and its matching .png file from 523 * https://github.com/SquidPony/SquidLib/tree/master/assets and you can pass them to {@link #font(String)} or 524 * {@link #fontDistanceField(String, String)}. 525 * 526 * @return this factory for method chaining 527 */ 528 public TextCellFactory includedFont() 529 { 530 bmpFont = DefaultResources.getIncludedFont(); 531 return this; 532 }/** 533 * Sets this factory to use a default 12x24 font that supports Latin, Greek, Cyrillic, and many more, including 534 * box-drawing characters, zodiac signs, playing-card suits, and chess piece symbols. This is enough to support the 535 * output of anything that DungeonUtility can make for a dungeon or FakeLanguageGen can make for text with its 536 * defaults, which is difficult for any font to do. The box-drawing characters in this don't quite line up, and in 537 * some colors there may appear to be gaps (white text on black backgrounds will show it, but not much else). 538 * 539 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 540 * methods in this class. 541 * 542 * @return this factory for method chaining 543 */ 544 public TextCellFactory defaultFont() 545 { 546 bmpFont = DefaultResources.getLargeSmoothFont(); 547 return this; 548 } 549 /** 550 * Sets this factory to use a default 12x24 font that renders very accurately, with no gaps between box-drawing 551 * characters and very geometric lines. 552 * 553 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 554 * methods in this class. 555 * 556 * @return this factory for method chaining 557 */ 558 public TextCellFactory defaultNarrowFont() 559 { 560 bmpFont = DefaultResources.getLargeNarrowFont(); 561 return this; 562 } 563 564 /** 565 * Sets this factory to use a default 12x12 font, which... is square, and doesn't look as bad as many square fonts 566 * do, plus it supports box-drawing characters with no gaps. 567 * 568 * This is a way to complete a needed step; the font must be set before initializing, which can be done by a few 569 * methods in this class. 570 * 571 * @return this factory for method chaining 572 */ 573 public TextCellFactory defaultSquareFont() 574 { 575 bmpFont = DefaultResources.getDefaultFont(); 576 return this; 577 } 578 579 /** 580 * Sets the TextCellFactory to use a square distance field font that will resize to whatever size you request. 581 * You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers. 582 * The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers; 583 * see its docs for more information. 584 * @return this TextCellFactory set to use a square distance field font 585 */ 586 public TextCellFactory defaultDistanceFieldFont() 587 { 588 fontDistanceField(DefaultResources.distanceFieldSquare, DefaultResources.distanceFieldSquareTexture); 589 return this; 590 } 591 /** 592 * Sets the TextCellFactory to use a half-square distance field font that will resize to whatever size you request. 593 * You must configure the shader if you use a distance field font, unless a class does it for you, like SquidLayers. 594 * The configureShader(Batch) method of this class can be used to set up the shader if you don't use SquidLayers; 595 * see its docs for more information. 596 * @return this TextCellFactory set to use a half-square distance field font 597 */ 598 public TextCellFactory defaultNarrowDistanceFieldFont() 599 { 600 fontDistanceField(DefaultResources.distanceFieldNarrow, DefaultResources.distanceFieldNarrowTexture); 601 return this; 602 } 603 604 /** 605 * Returns the width of a single cell. 606 * 607 * @return the width 608 */ 609 public float width() { 610 return width; 611 } 612 613 /** 614 * Sets the factory's cell width to the provided value. Clamps at 1 on the 615 * lower bound to ensure valid calculations. 616 * 617 * @param width the desired width 618 * @return this factory for method chaining 619 */ 620 public TextCellFactory width(float width) { 621 this.width = Math.max(1, width); 622 actualCellWidth = this.width; 623 return this; 624 } 625 626 /** 627 * Returns the height of a single cell. 628 * 629 * @return the height of a single cell 630 */ 631 public float height() { 632 return height; 633 } 634 635 /** 636 * Sets the factory's cell height to the provided value. Clamps at 1 on the 637 * lower bound to ensure valid calculations. 638 * 639 * @param height the desired width 640 * @return this factory for method chaining 641 */ 642 public TextCellFactory height(float height) { 643 this.height = Math.max(1, height); 644 //modifiedHeight = this.height; 645 actualCellHeight = this.height; 646 return this; 647 } 648 /** 649 * Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at 650 * 1 on the lower bound to ensure valid calculations. 651 * 652 * @param width the desired width 653 * @return this factory for method chaining 654 */ 655 public TextCellFactory tweakWidth(float width) { 656 this.width = Math.max(1, width); 657 return this; 658 } 659 660 /** 661 * Sets the factory's height used for text to the provided value, but does not change the size of a cell. Clamps at 662 * 1 on the lower bound to ensure valid calculations. 663 * 664 * @param height the desired height 665 * @return this factory for method chaining 666 */ 667 public TextCellFactory tweakHeight(float height) { 668 this.height = Math.max(1, height); 669 //modifiedHeight = this.height; 670 return this; 671 } 672 673 /** 674 * Returns the current String of code points that are used for sizing the 675 * cells. 676 * 677 * Note that this is actually a set of codepoints and treating them as an 678 * array of chars might give undesired results. 679 * 680 * @return the String used for sizing calculations 681 */ 682 public String fit() { 683 return fitting; 684 } 685 686 /** 687 * Sets the characters that will be guaranteed to fit to the provided ones. 688 * This will override any previously set string. 689 * 690 * @param fit the String of code points to size to 691 * @return this factory for method chaining 692 */ 693 public TextCellFactory fit(String fit) { 694 fitting = fit; 695 bmpFont.setFixedWidthGlyphs(fitting); 696 width = bmpFont.getSpaceXadvance(); 697 return this; 698 } 699 700 /** 701 * Adds the code points in the string to the list of characters that will be 702 * guaranteed to fit. 703 * 704 * @param fit the String of code points to size to 705 * @return this factory for method chaining 706 */ 707 public TextCellFactory addFit(String fit) { 708 fitting += fit; 709 bmpFont.setFixedWidthGlyphs(fitting); 710 width = bmpFont.getSpaceXadvance(); 711 return this; 712 } 713 714 /** 715 * Returns whether this factory is currently set to do antialiasing on the 716 * characters rendered, which is always true. 717 * 718 * @return true if antialiasing is set, so, always 719 */ 720 public boolean antialias() { 721 return true; 722 } 723 724 /** 725 * All fonts will be rendered with antialiasing, this doesn't do anything. 726 * 727 * @param antialias ignored, will always use antialiasing 728 * @return this factory for method chaining 729 * @deprecated AA is the wave of the future! 730 */ 731 @Deprecated 732 public TextCellFactory antialias(boolean antialias) { 733 return this; 734 } 735 736 /** 737 * Sets the amount of padding on all sides to the provided value. 738 * 739 * @param padding how much padding in pixels 740 * @return this for method chaining 741 */ 742 public TextCellFactory padding(int padding) { 743 leftPadding = padding; 744 rightPadding = padding; 745 topPadding = padding; 746 bottomPadding = padding; 747 return this; 748 } 749 750 /** 751 * Returns the padding on the left side. 752 * 753 * @return amount of padding in pixels 754 */ 755 public int leftPadding() { 756 return leftPadding; 757 } 758 759 /** 760 * Sets the amount of padding on the left side to the provided value. 761 * 762 * @param padding how much padding in pixels 763 * @return this for method chaining 764 */ 765 public TextCellFactory leftPadding(int padding) { 766 leftPadding = padding; 767 return this; 768 } 769 770 /** 771 * Returns the padding on the right side. 772 * 773 * @return amount of padding in pixels 774 */ 775 public int rightPadding() { 776 return rightPadding; 777 } 778 779 /** 780 * Sets the amount of padding on the right side to the provided value. 781 * 782 * @param padding how much padding in pixels 783 * @return this for method chaining 784 */ 785 public TextCellFactory rightPadding(int padding) { 786 rightPadding = padding; 787 return this; 788 } 789 790 /** 791 * Returns the padding on the top side. 792 * 793 * @return amount of padding in pixels 794 */ 795 public int topPadding() { 796 return topPadding; 797 } 798 799 /** 800 * Sets the amount of padding on the top side to the provided value. 801 * 802 * @param padding how much padding in pixels 803 * @return this for method chaining 804 */ 805 public TextCellFactory topPadding(int padding) { 806 topPadding = padding; 807 return this; 808 } 809 810 /** 811 * Returns the padding on the bottom side. 812 * 813 * @return amount of padding in pixels 814 */ 815 public int bottomPadding() { 816 return bottomPadding; 817 } 818 819 /** 820 * Sets the amount of padding on the bottom side to the provided value. 821 * 822 * @param padding how much padding in pixels 823 * @return this for method chaining 824 */ 825 public TextCellFactory bottomPadding(int padding) { 826 bottomPadding = padding; 827 return this; 828 } 829 830 /** 831 * @param icc 832 * The color center to use. Should not be {@code null}. 833 * @return {@code this} 834 * @throws NullPointerException 835 * If {@code icc} is {@code null}. 836 */ 837 public TextCellFactory setColorCenter(IColorCenter<Color> icc) { 838 if (icc == null) 839 /* Better fail now than later */ 840 throw new NullPointerException( 841 "The color center should not be null in " + getClass().getSimpleName()); 842 scc = icc; 843 return this; 844 } 845 846 /** 847 * Returns true if this factory is fully initialized and ready to build text cells. 848 * 849 * @return true if initialized 850 */ 851 public boolean initialized() { 852 return initialized; 853 } 854 855 /** 856 * Returns true if the given character will fit inside the current cell 857 * dimensions with the current font. 858 * 859 * ISO Control characters, non-printing characters and invalid unicode 860 * characters are all considered by definition to fit. 861 * 862 * @param codepoint the codepoint of the char in question 863 * @return true if the char will fit, or if it is non-printing in some way; false otherwise 864 */ 865 public boolean willFit(int codepoint) { 866 if (!initialized) { 867 throw new IllegalStateException("This factory has not yet been initialized!"); 868 } 869 870 if (!Character.isValidCodePoint(codepoint) || 871 (codepoint <= 0x001F) || (codepoint >= 0x007F && codepoint <= 0x009F)) // same as isIsoControl 872 { 873 return true; 874 } 875 876 return fitting.contains(String.valueOf(Character.toChars(codepoint))); 877 } 878 879 private char getOrDefault(final char toGet) 880 { 881 final char got = swap.get(toGet); 882 return got == '\uffff' ? toGet : got; 883 } 884 /** 885 * Use the specified Batch to draw a String or other CharSequence (often just one char long) with the default color 886 * (white), with x and y determining the world-space coordinates for the upper-left corner. 887 * 888 * @param batch the LibGDX Batch to do the drawing 889 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 890 * @param x x of the upper-left corner of the region of text in world coordinates. 891 * @param y y of the upper-left corner of the region of text in world coordinates. 892 */ 893 public void draw(Batch batch, CharSequence s, float x, float y) { 894 if (!initialized) { 895 throw new IllegalStateException("This factory has not yet been initialized!"); 896 } 897 898 // + descent * 3 / 2f 899 // - distanceFieldScaleY / 12f 900 901 //height - lineTweak * 2f 902 if (s == null || s.length() == 0 || s.charAt(0) == 0) { 903 batch.setPackedColor(SColor.FLOAT_WHITE); 904 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // + descent * 1 / 3f 905 } else { 906 batch.setPackedColor(SColor.FLOAT_WHITE); // round trip so FilterBatch can filter BitmapFontCache 907 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 908 bmpFont.draw(batch, s, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false); 909 } 910 } 911 912 913 /** 914 * Use the specified Batch to draw a char with the default color (white), with x and y determining the world-space 915 * coordinates for the upper-left corner. If c is {@code '\0'}, will draw a solid white block instead. 916 * 917 * @param batch the LibGDX Batch to do the drawing 918 * @param c the char to draw. Can be {@code '\0'} to draw a solid block instead. 919 * @param x x of the upper-left corner of the region of text in world coordinates. 920 * @param y y of the upper-left corner of the region of text in world coordinates. 921 */ 922 public void draw(Batch batch, char c, float x, float y) { 923 if (!initialized) { 924 throw new IllegalStateException("This factory has not yet been initialized!"); 925 } 926 927 // + descent * 3 / 2f 928 // - distanceFieldScaleY / 12f 929 930 //height - lineTweak * 2f 931 if (c == 0) { 932 batch.setColor(1f,1f,1f,1f); 933 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // + descent * 1 / 3f 934 } else { 935 batch.setPackedColor(SColor.FLOAT_WHITE); // round trip so FilterBatch can filter BitmapFontCache 936 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 937 mut.setCharAt(0, getOrDefault(c)); 938 bmpFont.draw(batch, mut, x, y - descent + 1/* * 1.5f*//* - lineHeight * 0.2f */ /* + descent*/, width, Align.center, false); 939 } 940 } 941 /** 942 * Use the specified Batch to draw a String or other CharSequence (often just one char long) in the specified rgba 943 * color, with x and y determining the world-space coordinates for the upper-left corner. 944 * 945 * @param batch the LibGDX Batch to do the drawing 946 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 947 * @param r 0.0f to 1.0f red value 948 * @param g 0.0f to 1.0f green value 949 * @param b 0.0f to 1.0f blue value 950 * @param a 0.0f to 1.0f alpha value 951 * @param x x of the upper-left corner of the region of text in world coordinates. 952 * @param y y of the upper-left corner of the region of text in world coordinates. 953 */ 954 public void draw(Batch batch, CharSequence s, float r, float g, float b, float a, float x, float y) { 955 if (!initialized) { 956 throw new IllegalStateException("This factory has not yet been initialized!"); 957 } 958 959 if (s == null) { 960 float orig = batch.getPackedColor(); 961 batch.setColor(r, g, b, a); 962 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); // descent * 1 / 3f 963 batch.setPackedColor(orig); 964 } else if(s.length() > 0 && s.charAt(0) == '\0') { 965 float orig = batch.getPackedColor(); 966 batch.setColor(r, g, b, a); 967 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); 968 batch.setPackedColor(orig); 969 } else { 970 batch.setColor(r, g, b, a); // round trip so FilterBatch can filter BitmapFontCache 971 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 972 bmpFont.draw(batch, s, x, y - descent + 1, width, Align.center, false); 973 } 974 } 975 976 /** 977 * Use the specified Batch to draw a String or other CharSequence (often just one char long) in the specified LibGDX 978 * Color, with x and y 979 * determining the world-space coordinates for the upper-left corner. 980 * 981 * @param batch the LibGDX Batch to do the drawing 982 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 983 * @param color the LibGDX Color to draw the char(s) with, all the same color 984 * @param x x of the upper-left corner of the region of text in world coordinates. 985 * @param y y of the upper-left corner of the region of text in world coordinates. 986 */ 987 public void draw(Batch batch, CharSequence s, Color color, float x, float y) { 988 if (!initialized) { 989 throw new IllegalStateException("This factory has not yet been initialized!"); 990 } 991 992 if (s == null) { 993 float orig = batch.getPackedColor(); 994 batch.setColor(color); 995 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); 996 batch.setPackedColor(orig); 997 } else if(s.length() > 0 && s.charAt(0) == '\0') { 998 float orig = batch.getPackedColor(); 999 batch.setColor(color); 1000 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); 1001 batch.setPackedColor(orig); 1002 } else { 1003 batch.setColor(color); // round trip so FilterBatch can filter BitmapFontCache 1004 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 1005 bmpFont.draw(batch, s, x, y - descent + 1, width, Align.center, false); 1006 } 1007 } 1008 /** 1009 * Use the specified Batch to draw a String or other CharSequence (often just one char long) in the specified LibGDX 1010 * Color, with x and y determining the world-space coordinates for the upper-left corner. 1011 * 1012 * @param batch the LibGDX Batch to do the drawing 1013 * @param s the string to draw, often but not necessarily one char. Can be null to draw a solid block instead. 1014 * @param encodedColor the LibGDX Color to use, converted to float as by {@link Color#toFloatBits()} 1015 * @param x x of the upper-left corner of the region of text in world coordinates. 1016 * @param y y of the upper-left corner of the region of text in world coordinates. 1017 */ 1018 public void draw(Batch batch, CharSequence s, float encodedColor, float x, float y) { 1019 if (!initialized) { 1020 throw new IllegalStateException("This factory has not yet been initialized!"); 1021 } 1022 1023 if (s == null) { 1024 float orig = batch.getPackedColor(); 1025 batch.setPackedColor(encodedColor); 1026 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); 1027 batch.setPackedColor(orig); 1028 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1029 float orig = batch.getPackedColor(); 1030 batch.setPackedColor(encodedColor); 1031 batch.draw(block, x, y - actualCellHeight, actualCellWidth * s.length(), actualCellHeight); 1032 batch.setPackedColor(orig); 1033 } else 1034 { 1035 batch.setPackedColor(encodedColor); // round trip so FilterBatch can filter BitmapFontCache 1036 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 1037 bmpFont.draw(batch, s, x, y - descent + 1, width, Align.center, false); 1038 } 1039 } 1040 1041 /** 1042 * Use the specified Batch to draw a char in the specified LibGDX Color, with x and y 1043 * determining the world-space coordinates for the upper-left corner. 1044 * 1045 * @param batch the LibGDX Batch to do the drawing 1046 * @param c the char to draw. Can be {@code '\0'} to draw a solid block instead. 1047 * @param color the LibGDX Color (or SquidLib SColor) to use, as an object 1048 * @param x x of the upper-left corner of the region of text in world coordinates. 1049 * @param y y of the upper-left corner of the region of text in world coordinates. 1050 */ 1051 public void draw(Batch batch, char c, Color color, float x, float y) { 1052 if (!initialized) { 1053 throw new IllegalStateException("This factory has not yet been initialized!"); 1054 } 1055 if (c == 0) { 1056 float orig = batch.getPackedColor(); 1057 batch.setColor(color); 1058 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); 1059 batch.setPackedColor(orig); 1060 } else 1061 { 1062 batch.setColor(color); // round trip so FilterBatch can filter BitmapFontCache 1063 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 1064 mut.setCharAt(0, getOrDefault(c)); 1065 bmpFont.draw(batch, mut, x, y - descent + 1, width, Align.center, false); 1066 } 1067 } 1068 1069 /** 1070 * Use the specified Batch to draw a String (often just one char long) in the specified LibGDX Color, with x and y 1071 * determining the world-space coordinates for the upper-left corner. 1072 * 1073 * @param batch the LibGDX Batch to do the drawing 1074 * @param c the char to draw. Can be {@code '\0'} to draw a solid block instead. 1075 * @param encodedColor the LibGDX Color to use, converted to float as by {@link Color#toFloatBits()} 1076 * @param x x of the upper-left corner of the region of text in world coordinates. 1077 * @param y y of the upper-left corner of the region of text in world coordinates. 1078 */ 1079 public void draw(Batch batch, char c, float encodedColor, float x, float y) { 1080 if (!initialized) { 1081 throw new IllegalStateException("This factory has not yet been initialized!"); 1082 } 1083 if (c == 0) { 1084 float orig = batch.getPackedColor(); 1085 batch.setPackedColor(encodedColor); 1086 batch.draw(block, x, y - actualCellHeight, actualCellWidth, actualCellHeight); 1087 batch.setPackedColor(orig); 1088 } else 1089 { 1090 batch.setPackedColor(encodedColor); // round trip so FilterBatch can filter BitmapFontCache 1091 Color.abgr8888ToColor(bmpFont.getColor(), batch.getPackedColor()); 1092 mut.setCharAt(0, getOrDefault(c)); 1093 bmpFont.draw(batch, mut, x, y - descent + 1, width, Align.center, false); 1094 } 1095 } 1096 1097 /** 1098 * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y 1099 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1100 * if its size does not match what this TextCellFactory uses for width and height. 1101 * 1102 * @param batch the LibGDX Batch to do the drawing 1103 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1104 * @param x x of the upper-left corner of the region of text in world coordinates. 1105 * @param y y of the upper-left corner of the region of text in world coordinates. 1106 */ 1107 public void draw(Batch batch, TextureRegion tr, float x, float y) { 1108 if (!initialized) { 1109 throw new IllegalStateException("This factory has not yet been initialized!"); 1110 } 1111 1112 if (tr == null) { 1113 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 1114 } else { 1115 batch.draw(tr, x, y - height, width, height); 1116 } 1117 } 1118 /** 1119 * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y 1120 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1121 * if its size does not match what this TextCellFactory uses for width and height. 1122 * 1123 * @param batch the LibGDX Batch to do the drawing 1124 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1125 * @param r 0.0 to 0.1 red value 1126 * @param g 0.0 to 0.1 green value 1127 * @param b 0.0 to 0.1 blue value 1128 * @param a 0.0 to 0.1 alpha value 1129 * @param x x of the upper-left corner of the region of text in world coordinates. 1130 * @param y y of the upper-left corner of the region of text in world coordinates. 1131 */ 1132 public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y) { 1133 if (!initialized) { 1134 throw new IllegalStateException("This factory has not yet been initialized!"); 1135 } 1136 1137 if (tr == null) { 1138 float orig = batch.getPackedColor(); 1139 batch.setColor(r, g, b, a); 1140 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 1141 batch.setPackedColor(orig); 1142 } else { 1143 float orig = batch.getPackedColor(); 1144 batch.setColor(r, g, b, a); 1145 batch.draw(tr, x, y - height, width, height); 1146 batch.setPackedColor(orig); 1147 } 1148 } 1149 1150 /** 1151 * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y 1152 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1153 * if its size does not match what this TextCellFactory uses for width and height. 1154 * 1155 * @param batch the LibGDX Batch to do the drawing 1156 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1157 * @param color the LibGDX Color to draw the char(s) with, all the same color 1158 * @param x x of the upper-left corner of the region of text in world coordinates. 1159 * @param y y of the upper-left corner of the region of text in world coordinates. 1160 */ 1161 public void draw(Batch batch, TextureRegion tr, Color color, float x, float y) { 1162 if (!initialized) { 1163 throw new IllegalStateException("This factory has not yet been initialized!"); 1164 } 1165 1166 if (tr == null) { 1167 float orig = batch.getPackedColor(); 1168 batch.setColor(color); 1169 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 1170 batch.setPackedColor(orig); 1171 } else { 1172 float orig = batch.getPackedColor(); 1173 batch.setColor(color); 1174 batch.draw(tr, x, y - height, width, height); 1175 batch.setPackedColor(orig); 1176 } 1177 } 1178 /** 1179 * Use the specified Batch to draw a TextureRegion tinted with the specified encoded color as a float, with x and y 1180 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1181 * if its size does not match what this TextCellFactory uses for width and height. Colors can be converted to and 1182 * from floats using methods in SColor such as {@link SColor#floatGet(float, float, float, float)}, 1183 * {@link SColor#toFloatBits()}, {@link SColor#colorFromFloat(Color, float)}, and 1184 * {@link SColor#lerpFloatColors(float, float, float)}. 1185 * 1186 * @param batch the LibGDX Batch to do the drawing 1187 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1188 * @param encodedColor the float encoding a color (as ABGR8888; SColor can produce these) to draw the image with 1189 * @param x x of the upper-left corner of the image in world coordinates. 1190 * @param y y of the upper-left corner of the image in world coordinates. 1191 */ 1192 public void draw(Batch batch, TextureRegion tr, float encodedColor, float x, float y) 1193 { 1194 if (!initialized) { 1195 throw new IllegalStateException("This factory has not yet been initialized!"); 1196 } 1197 1198 if (tr == null) { 1199 float orig = batch.getPackedColor(); 1200 batch.setPackedColor(encodedColor); 1201 batch.draw(block, x, y - height, actualCellWidth, actualCellHeight); 1202 batch.setPackedColor(orig); 1203 } else { 1204 float orig = batch.getPackedColor(); 1205 batch.setPackedColor(encodedColor); 1206 batch.draw(tr, x, y - height, width, height); 1207 batch.setPackedColor(orig); 1208 } 1209 } 1210 1211 /** 1212 * Use the specified Batch to draw a TextureRegion with the default tint color (white, so un-tinted), with x and y 1213 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1214 * only if the supplied width and height do not match what its own dimensions are. 1215 * 1216 * @param batch the LibGDX Batch to do the drawing 1217 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1218 * @param x x of the upper-left corner of the region of text in world coordinates. 1219 * @param y y of the upper-left corner of the region of text in world coordinates. 1220 * @param width the width of the TextureRegion or solid block in pixels. 1221 * @param height the height of the TextureRegion or solid block in pixels. 1222 */ 1223 public void draw(Batch batch, TextureRegion tr, float x, float y, float width, float height) { 1224 if (!initialized) { 1225 throw new IllegalStateException("This factory has not yet been initialized!"); 1226 } 1227 1228 if (tr == null) { 1229 batch.draw(block, x, y - height, width, height); 1230 } else { 1231 batch.draw(tr, x, y - height, width, height); 1232 } 1233 } 1234 /** 1235 * Use the specified Batch to draw a TextureRegion tinted with the specified rgba color, with x and y 1236 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1237 * only if the supplied width and height do not match what its own dimensions are. 1238 * 1239 * @param batch the LibGDX Batch to do the drawing 1240 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1241 * @param r 0.0 to 0.1 red value 1242 * @param g 0.0 to 0.1 green value 1243 * @param b 0.0 to 0.1 blue value 1244 * @param a 0.0 to 0.1 alpha value 1245 * @param x x of the upper-left corner of the region of text in world coordinates. 1246 * @param y y of the upper-left corner of the region of text in world coordinates. 1247 * @param width the width of the TextureRegion or solid block in pixels. 1248 * @param height the height of the TextureRegion or solid block in pixels. 1249 */ 1250 public void draw(Batch batch, TextureRegion tr, float r, float g, float b, float a, float x, float y, float width, float height) { 1251 if (!initialized) { 1252 throw new IllegalStateException("This factory has not yet been initialized!"); 1253 } 1254 1255 if (tr == null) { 1256 float orig = batch.getPackedColor(); 1257 batch.setColor(r, g, b, a); 1258 batch.draw(block, x, y - height, width, height); 1259 batch.setPackedColor(orig); 1260 } else { 1261 float orig = batch.getPackedColor(); 1262 batch.setColor(r, g, b, a); 1263 batch.draw(tr, x, y - height, width, height); 1264 batch.setPackedColor(orig); 1265 } 1266 } 1267 1268 /** 1269 * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y 1270 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1271 * only if the supplied width and height do not match what its own dimensions are. 1272 * 1273 * @param batch the LibGDX Batch to do the drawing 1274 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1275 * @param color the LibGDX Color to draw the image with, all the same color 1276 * @param x x of the upper-left corner of the image in world coordinates. 1277 * @param y y of the upper-left corner of the image in world coordinates. 1278 * @param width the width of the TextureRegion or solid block in pixels. 1279 * @param height the height of the TextureRegion or solid block in pixels. 1280 */ 1281 public void draw(Batch batch, TextureRegion tr, Color color, float x, float y, float width, float height) { 1282 if (!initialized) { 1283 throw new IllegalStateException("This factory has not yet been initialized!"); 1284 } 1285 1286 if (tr == null) { 1287 float orig = batch.getPackedColor(); 1288 batch.setColor(color); 1289 batch.draw(block, x, y - height, width, height); 1290 batch.setPackedColor(orig); 1291 } else { 1292 float orig = batch.getPackedColor(); 1293 batch.setColor(color); 1294 batch.draw(tr, x, y - height, width, height); 1295 batch.setPackedColor(orig); 1296 } 1297 } 1298 1299 /** 1300 * Use the specified Batch to draw a TextureRegion tinted with the specified LibGDX Color, with x and y 1301 * determining the world-space coordinates for the upper-left corner. The TextureRegion will be stretched 1302 * only if the supplied width and height do not match what its own dimensions are. 1303 * 1304 * @param batch the LibGDX Batch to do the drawing 1305 * @param tr the TextureRegion to draw. Can be null to draw a solid block instead. 1306 * @param encodedColor the float encoding a color (as ABGR8888; SColor can produce these) to draw the image with 1307 * @param x x of the upper-left corner of the image in world coordinates. 1308 * @param y y of the upper-left corner of the image in world coordinates. 1309 * @param width the width of the TextureRegion or solid block in pixels. 1310 * @param height the height of the TextureRegion or solid block in pixels. 1311 */ 1312 public void draw(Batch batch, TextureRegion tr, float encodedColor, float x, float y, float width, float height) { 1313 if (!initialized) { 1314 throw new IllegalStateException("This factory has not yet been initialized!"); 1315 } 1316 1317 if (tr == null) { 1318 float orig = batch.getPackedColor(); 1319 batch.setPackedColor(encodedColor); 1320 batch.draw(block, x, y - height, width, height); 1321 batch.setPackedColor(orig); 1322 } else { 1323 float orig = batch.getPackedColor(); 1324 batch.setPackedColor(encodedColor); 1325 batch.draw(tr, x, y - height, width, height); 1326 batch.setPackedColor(orig); 1327 } 1328 } 1329 1330 /** 1331 * Draws a 2D array of floats that represent encoded colors, with each float used for a block of color the size of 1332 * one character cell (it will be {@link #actualCellWidth} by {@link #actualCellHeight} in size, using world units). 1333 * @param batch the LibGDX Batch to do the drawing 1334 * @param encodedColors a 2D float array of encoded colors, each usually produced by {@link Color#toFloatBits()} or an SColor method 1335 * @param x the x-position where this should render the block of many colors 1336 * @param y the y-position where this should render the block of many colors 1337 */ 1338 public void draw(Batch batch, float[][] encodedColors, float x, float y) 1339 { 1340 float orig = batch.getPackedColor(); 1341 final int w = encodedColors.length, h = encodedColors[0].length; 1342 float wm = x, hm; 1343 for (int i = 0; i < w; i++, wm += actualCellWidth) { 1344 hm = y + (h - 1) * actualCellHeight; 1345 for (int j = 0; j < h; j++, hm -= actualCellHeight) { 1346 if(encodedColors[i][j] == 0f) 1347 continue; 1348 batch.setPackedColor(encodedColors[i][j]); 1349 batch.draw(block, wm, hm, actualCellWidth, actualCellHeight); // descent * 1 / 3f 1350 } 1351 } 1352 batch.setPackedColor(orig); 1353 } 1354 1355 /** 1356 * Draws a 2D array of floats that represent encoded colors, with each float used for a block of color that will be 1357 * a fraction of the size of one character cell (it will be {@link #actualCellWidth} divided by {@code xSubCells} by 1358 * {@link #actualCellHeight} divided by {@code ySubCells} in size, using world units). Typically the 2D float array 1359 * should be larger than the 2D storage for text drawn over the colorful blocks (such as a 2D char array), since 1360 * more than one subcell may be drawn in the space of one character cell. 1361 * @param batch the LibGDX Batch to do the drawing 1362 * @param encodedColors a 2D float array of encoded colors, each usually produced by {@link Color#toFloatBits()} or an SColor method 1363 * @param x the x-position where this should render the block of many colors 1364 * @param y the y-position where this should render the block of many colors 1365 * @param xSubCells how many blocks of color should fit across the span of {@link #actualCellWidth}, each one float; must not be 0 1366 * @param ySubCells how many blocks of color should fit across the span of {@link #actualCellHeight}, each one float; must not be 0 1367 */ 1368 public void draw(Batch batch, float[][] encodedColors, float x, float y, int xSubCells, int ySubCells) 1369 { 1370 float orig = batch.getPackedColor(); 1371 final int w = encodedColors.length, h = encodedColors[0].length; 1372 final float subW = actualCellWidth / xSubCells, subH = actualCellHeight / ySubCells; 1373 float wm = x, hm; 1374 for (int i = 0; i < w; i++, wm += subW) { 1375 hm = y + (h - 1) * subH; 1376 for (int j = 0; j < h; j++, hm -= subH) { 1377 if(encodedColors[i][j] == 0f) 1378 continue; 1379 batch.setPackedColor(encodedColors[i][j]); 1380 batch.draw(block, wm, hm, subW, subH); 1381 } 1382 } 1383 batch.setPackedColor(orig); 1384 } 1385 1386 /** 1387 * Given a Pixmap and a 2D float array, uses each float in the array as an encoded color for a pixel in the Pixmap 1388 * at a location determined by the float's position in the array. This is meant to be used to draw backgrounds that 1389 * will be stretched by the {@link #actualCellWidth} and {@link #actualCellHeight} of this TextCellFactory. 1390 * <br> 1391 * Oddly, this doesn't seem to be very fast compared to {@link #draw(Batch, float[][], float, float)}, so if you 1392 * need to draw backgrounds then prefer that method (as SparseLayers does). It also doesn't work with a FilterBatch, 1393 * so if you want to use FloatFilter to adjust colors, you would need to use the other draw method for backgrounds. 1394 * @param pixmap a non-null Pixmap that will be modified 1395 * @param encodedColors a 2D float array that must be non-null and non-empty, and contains packed colors 1396 */ 1397 public void draw(Pixmap pixmap, float[][] encodedColors) 1398 { 1399 final int w = Math.min(pixmap.getWidth(), encodedColors.length), h = Math.min(pixmap.getHeight(), encodedColors[0].length); 1400 for (int i = 0; i < w; i++) { 1401 for (int j = h - 1; j >= 0; j--) { 1402 if (encodedColors[i][j] == 0f) 1403 continue; 1404 pixmap.drawPixel(i, j, NumberTools.floatToReversedIntBits(encodedColors[i][j])); 1405 } 1406 } 1407 } 1408 1409 /** 1410 * Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used 1411 * for preparing glyphs for animation effects. 1412 * @param s a String to make into an Actor, which can be null for a solid block. 1413 * @return the Actor, with no position set. 1414 */ 1415 public Label makeWrappingString(String s) { 1416 if (!initialized) { 1417 throw new IllegalStateException("This factory has not yet been initialized!"); 1418 } 1419 if (s == null) { 1420 s = ""; 1421 } 1422 Label lb = new Label(s, style); 1423 lb.setWrap(true); 1424 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1425 return lb; 1426 1427 } 1428 1429 /** 1430 * Converts a String into a Label, or if the argument s is null, creates an Image of a solid block. Can be used 1431 * for preparing glyphs for animation effects, and is used internally for this purpose. 1432 * @param s a String to make into an Actor, which can be null for a solid block. 1433 * @param color a Color to tint s with. 1434 * @return the Actor, with no position set. 1435 */ 1436 public Actor makeActor(String s, Color color) { 1437 if (!initialized) { 1438 throw new IllegalStateException("This factory has not yet been initialized!"); 1439 } 1440 if (s == null) { 1441 Image im = new Image(block); 1442 im.setColor(scc.filter(color)); 1443 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1444 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1445 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1446 return im; 1447 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1448 Image im = new Image(block); 1449 im.setColor(scc.filter(color)); 1450 //im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1451 im.setSize(actualCellWidth * s.length(), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1452 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1453 return im; 1454 } else { 1455 Label lb = new Label(s, style); 1456 //lb.setFontScale(bmpFont.getData().scaleX, bmpFont.getData().scaleY); 1457 lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f 1458 lb.setColor(scc.filter(color)); 1459 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1460 return lb; 1461 } 1462 } 1463 1464 /** 1465 * Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid 1466 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1467 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1468 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1469 * purposes of things like SquidPanel.hasActiveAnimations() . 1470 * @param s a String to make into an Actor, which can be null for a solid block. 1471 * @param colors a List of Color to tint s with, looping through all elements in the list each second 1472 * @return the Actor, with no position set. 1473 */ 1474 public Actor makeActor(String s, Collection<Color> colors) { 1475 return makeActor(s, colors, 2f, false); 1476 } 1477 /** 1478 * Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid 1479 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1480 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1481 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1482 * purposes of things like SquidPanel.hasActiveAnimations() . 1483 * @param s a String to make into an Actor, which can be null for a solid block. 1484 * @param colors a List of Color to tint s with, looping through all elements in the list each second 1485 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1486 * @return the Actor, with no position set. 1487 */ 1488 public Actor makeActor(String s, Collection<Color> colors, float loopTime) 1489 { 1490 return makeActor(s, colors, loopTime, false); 1491 } 1492 /** 1493 * Converts a String into a ColorChangeLabel, or if the argument s is null, creates a ColorChangeImage of a solid 1494 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1495 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1496 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1497 * purposes of things like SquidPanel.hasActiveAnimations() . 1498 * @param s a String to make into an Actor, which can be null for a solid block. 1499 * @param colors a List of Color to tint s with, looping through all elements in the list each second 1500 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1501 * @return the Actor, with no position set. 1502 */ 1503 public Actor makeActor(String s, Collection<Color> colors, float loopTime, boolean doubleWidth) { 1504 if (!initialized) { 1505 throw new IllegalStateException("This factory has not yet been initialized!"); 1506 } 1507 ArrayList<Color> colors2 = null; 1508 if(colors != null && !colors.isEmpty()) 1509 { 1510 colors2 = new ArrayList<>(colors.size()); 1511 for (Color c : colors) { 1512 colors2.add(scc.filter(c)); 1513 } 1514 } 1515 if (s == null) { 1516 ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2); 1517 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1518 im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1519 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1520 return im; 1521 } else if(s.length() > 0 && s.charAt(0) == '\0') { 1522 ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2); 1523 //im.setSize(width * s.length(), height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1524 im.setSize(actualCellWidth * s.length() * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1525 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1526 return im; 1527 } else { 1528 ColorChangeLabel lb = new ColorChangeLabel(s, style, loopTime, doubleWidth, colors2); 1529 lb.setSize(width * s.length(), height - descent); //+ lineTweak * 1f 1530 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1531 return lb; 1532 } 1533 } 1534 1535 /** 1536 * Converts a char into a Label, or if the argument c is '\0', creates an Image of a solid block. Can be used 1537 * for preparing glyphs for animation effects, and is used internally for this purpose. 1538 * @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block. 1539 * @param color a Color to tint c with. 1540 * @return the Actor, with no position set. 1541 */ 1542 public Actor makeActor(char c, Color color) { 1543 if (!initialized) { 1544 throw new IllegalStateException("This factory has not yet been initialized!"); 1545 } 1546 if (c == 0) { 1547 Image im = new Image(block); 1548 im.setColor(scc.filter(color)); 1549 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1550 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1551 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1552 return im; 1553 } else { 1554 mut.setCharAt(0, getOrDefault(c)); 1555 Label lb = new Label(mut, style); 1556 lb.setSize(width, height - descent); //+ lineTweak * 1f 1557 lb.setColor(scc.filter(color)); 1558 return lb; 1559 } 1560 } 1561 1562 /** 1563 * Converts a char into a Label, or if the argument c is '\0', creates an Image of a solid block. Can be used 1564 * for preparing glyphs for animation effects, and is used internally for this purpose. Instead of a libGDX Color 1565 * object, this takes an encoded float that represents a color as libGDX often does internally, ABGR-packed format. 1566 * You can use various methods in SColor to produce these, like {@link SColor#floatGet(float, float, float, float)} 1567 * or {@link Color#toFloatBits()}. 1568 * @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block. 1569 * @param encodedColor an ABGR packed float (as produced by {@link SColor#floatGet(float, float, float, float)}) to use as c's color 1570 * @return the Actor, with no position set. 1571 */ 1572 public Actor makeActor(char c, float encodedColor) { 1573 if (!initialized) { 1574 throw new IllegalStateException("This factory has not yet been initialized!"); 1575 } 1576 if (c == 0) { 1577 Image im = new Image(block); 1578 Color.abgr8888ToColor(im.getColor(), encodedColor); 1579 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1580 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1581 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1582 return im; 1583 } else { 1584 mut.setCharAt(0, getOrDefault(c)); 1585 Label lb = new Label(mut, style); 1586 //lb.setFontScale(bmpFont.getData().scaleX, bmpFont.getData().scaleY); 1587 lb.setSize(width, height - descent); //+ lineTweak * 1f 1588 Color.abgr8888ToColor(lb.getColor(), encodedColor); 1589 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1590 return lb; 1591 } 1592 } 1593 1594 /** 1595 * Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid 1596 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1597 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1598 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1599 * purposes of things like SquidPanel.hasActiveAnimations() . 1600 * @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block. 1601 * @param colors a List of Color to tint c with, looping through all elements in the list each second 1602 * @return the Actor, with no position set. 1603 */ 1604 public Actor makeActor(char c, Collection<Color> colors) { 1605 return makeActor(c, colors, 2f, false); 1606 } 1607 /** 1608 * Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid 1609 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1610 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1611 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1612 * purposes of things like SquidPanel.hasActiveAnimations() . 1613 * @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block. 1614 * @param colors a List of Color to tint c with, looping through all elements in the list each second 1615 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1616 * @return the Actor, with no position set. 1617 */ 1618 public Actor makeActor(char c, Collection<Color> colors, float loopTime) 1619 { 1620 return makeActor(c, colors, loopTime, false); 1621 } 1622 /** 1623 * Converts a char into a ColorChangeLabel, or if the argument c is '\0', creates a ColorChangeImage of a solid 1624 * block. Can be used for preparing glyphs for animation effects, and is used internally for this purpose. The 1625 * ColorChange classes will rotate between all colors given in the List each second, and are not affected by setColor, 1626 * though they are affected by their setColors methods. Their color change is not considered an animation for the 1627 * purposes of things like SquidPanel.hasActiveAnimations() . 1628 * @param c a char to make into an Actor, which can be the character with Unicode value 0 for a solid block. 1629 * @param colors a List of Color to tint c with, looping through all elements in the list each second 1630 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1631 * @return the Actor, with no position set. 1632 */ 1633 public Actor makeActor(char c, Collection<Color> colors, float loopTime, boolean doubleWidth) { 1634 if (!initialized) { 1635 throw new IllegalStateException("This factory has not yet been initialized!"); 1636 } 1637 ArrayList<Color> colors2 = null; 1638 if(colors != null && !colors.isEmpty()) 1639 { 1640 colors2 = new ArrayList<>(colors.size()); 1641 for (Color color : colors) { 1642 colors2.add(scc.filter(color)); 1643 } 1644 } 1645 if (c == 0) { 1646 ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2); 1647 //im.setSize(width, height - MathUtils.ceil(bmpFont.getDescent() / 2f)); 1648 im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1649 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1650 return im; 1651 } else { 1652 mut.setCharAt(0, getOrDefault(c)); 1653 ColorChangeLabel lb = new ColorChangeLabel(mut, style, loopTime, doubleWidth, colors2); 1654 lb.setSize(width, height - descent); //+ lineTweak * 1f 1655 // lb.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1656 return lb; 1657 } 1658 } 1659 public Actor makeActor(TextureRegion tr, Collection<Color> colors) 1660 { 1661 return makeActor(tr, colors, 2f, false); 1662 } 1663 public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime) 1664 { 1665 return makeActor(tr, colors, loopTime, false); 1666 } 1667 /** 1668 * Converts a TextureRegion into a ColorChangeImage that will cycle through the given colors. 1669 * ColorChange classes will rotate between all colors given in the List each loopTime, and are not affected by 1670 * setColor, though they are affected by their setColors methods. Their color change is not considered an animation 1671 * for the purposes of things like SquidPanel.hasActiveAnimations() . 1672 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1673 * @param colors a List of Color to tint c with, looping through all elements in the list each second 1674 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1675 * @return the Actor, with no position set. 1676 */ 1677 public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime, boolean doubleWidth){ 1678 return makeActor(tr, colors, loopTime, doubleWidth, 1679 actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); 1680 } 1681 1682 /** 1683 * Converts a TextureRegion into a ColorChangeImage that will cycle through the given colors. 1684 * ColorChange classes will rotate between all colors given in the List each loopTime, and are not affected by 1685 * setColor, though they are affected by their setColors methods. Their color change is not considered an animation 1686 * for the purposes of things like SquidPanel.hasActiveAnimations() . 1687 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1688 * @param colors a List of Color to tint c with, looping through all elements in the list each second 1689 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1690 * @return the Actor, with no position set. 1691 */ 1692 public Actor makeActor(TextureRegion tr, Collection<Color> colors, float loopTime, boolean doubleWidth, 1693 float width, float height){ 1694 if (!initialized) { 1695 throw new IllegalStateException("This factory has not yet been initialized!"); 1696 } 1697 ArrayList<Color> colors2 = null; 1698 if(colors != null && !colors.isEmpty()) 1699 { 1700 colors2 = new ArrayList<>(colors.size()); 1701 for (Color color : colors) { 1702 colors2.add(scc.filter(color)); 1703 } 1704 } 1705 if (tr == null) { 1706 ColorChangeImage im = new ColorChangeImage(block, loopTime, doubleWidth, colors2); 1707 im.setSize(width, height); 1708 return im; 1709 } else { 1710 ColorChangeImage im = new ColorChangeImage(tr, loopTime, doubleWidth, colors2); 1711 im.setSize(width, height); 1712 return im; 1713 } 1714 } 1715 1716 /** 1717 * Creates a ColorChangeImage Actor that should look like the glyph '^' in this font, but will be rotate-able. The 1718 * ColorChange classes will rotate between all colors given in the List in the given amount of loopTime, and are not 1719 * affected by setColor, though they are affected by their setColors methods. Their color change is not considered 1720 * an animation for the purposes of things like SquidPanel.hasActiveAnimations() . 1721 * @param colors a List of Color to tint the '^' with, looping through all elements in the list each second 1722 * @param loopTime the amount of time, in seconds, to spend looping through all colors in the list 1723 * @return the Actor, with no position set. 1724 */ 1725 public Image makeDirectionMarker(Collection<Color> colors, float loopTime, boolean doubleWidth) { 1726 if (!initialized) { 1727 throw new IllegalStateException("This factory has not yet been initialized!"); 1728 } 1729 ArrayList<Color> colors2 = null; 1730 if (colors != null && !colors.isEmpty()) { 1731 colors2 = new ArrayList<>(colors.size()); 1732 for (Color c : colors) { 1733 colors2.add(scc.filter(c)); 1734 } 1735 } 1736 ColorChangeImage im = new ColorChangeImage(dirMarker, loopTime, doubleWidth, 1737 actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), colors2); 1738 im.setAlign(2); 1739 im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1740 return im; 1741 } 1742 /** 1743 * Creates a Image Actor that should look like the glyph '^' in this font, but will be rotate-able. 1744 * @param color a Color to tint the '^' with 1745 * @return the Actor, with no position set. 1746 */ 1747 public Image makeDirectionMarker(Color color) { 1748 if (!initialized) { 1749 throw new IllegalStateException("This factory has not yet been initialized!"); 1750 } 1751 Image im = new Image(dirMarker); 1752 im.setColor(scc.filter(color)); 1753 im.setSize(actualCellWidth, actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1754 im.setOrigin(1); //center 1755 return im; 1756 } 1757 1758 /** 1759 * Given a char and a Color, makes a ColorChangeImage of that colored char so it can be rotated and so on. 1760 * @param glyph a char; should probably be visible, so not space or tab 1761 * @param color a Color to use for the image; will not change even though ColorChangeImage permits this 1762 * @return the ColorChangeImage with the one color for glyph 1763 */ 1764 public ColorChangeImage makeGlyphImage(char glyph, Color color) 1765 { 1766 return makeGlyphImage(glyph, color, false); 1767 } 1768 /** 1769 * Given a char and a Color, makes a ColorChangeImage of that colored char so it can be rotated and so on. 1770 * This overload allows double-width mode to be specified. 1771 * @param glyph a char; should probably be visible, so not space or tab 1772 * @param color a Color to use for the image; will not change even though ColorChangeImage permits this 1773 * @param doubleWidth true if layout uses two chars of width per logical cell, false otherwise 1774 * @return the ColorChangeImage with the one color for glyph 1775 */ 1776 public ColorChangeImage makeGlyphImage(char glyph, Color color, boolean doubleWidth) 1777 { 1778 if (!initialized) { 1779 throw new IllegalStateException("This factory has not yet been initialized!"); 1780 } 1781 TextureRegion tr; 1782 if (glyphTextures.containsKey(glyph)) 1783 { 1784 tr = glyphTextures.get(glyph); 1785 } 1786 else 1787 { 1788 BitmapFont.Glyph g = bmpFont.getData().getGlyph(glyph); 1789 tr = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height); 1790 glyphTextures.put(glyph, tr); 1791 } 1792 1793 ColorChangeImage im = new ColorChangeImage(tr, 1, doubleWidth, 1794 actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), Maker.makeList(scc.filter(color))); 1795 im.setAlign(2); 1796 im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1797 return im; 1798 } 1799 /** 1800 * Given a char and a Collection of Color (such as a List that might be produced by 1801 * {@link SquidColorCenter#gradient(Color, Color)}), makes a ColorChangeImage of that char so it can be rotated and 1802 * so on. The colors will cycle through the given collection onceper {@code loopTime} seconds. You can specify 1803 * double-width mode if you use it, probably in SquidPanel or SquidLayers. 1804 * @param glyph a char; should probably be visible, so not space or tab 1805 * @param colors a Collection of Colors to use for the image; the image will cycle through them in order 1806 * @param loopTime the amount of time, in seconds, it should take for all colors to be cycled through 1807 * @param doubleWidth true if layout uses two chars of width per logical cell, false otherwise 1808 * @return the ColorChangeImage with the one color for glyph 1809 */ 1810 public ColorChangeImage makeGlyphImage(char glyph, Collection<Color> colors, float loopTime, boolean doubleWidth) { 1811 if (!initialized) { 1812 throw new IllegalStateException("This factory has not yet been initialized!"); 1813 } 1814 TextureRegion tr; 1815 if (glyphTextures.containsKey(glyph)) 1816 { 1817 tr = glyphTextures.get(glyph); 1818 } 1819 else 1820 { 1821 BitmapFont.Glyph g = bmpFont.getData().getGlyph(glyph); 1822 tr = new TextureRegion(bmpFont.getRegion(g.page), g.srcX, g.srcY, g.width, g.height); 1823 glyphTextures.put(glyph, tr); 1824 } 1825 ArrayList<Color> colors2 = null; 1826 if (colors != null && !colors.isEmpty()) { 1827 colors2 = new ArrayList<>(colors.size()); 1828 for (Color c : colors) { 1829 colors2.add(scc.filter(c)); 1830 } 1831 } 1832 ColorChangeImage im = new ColorChangeImage(tr, loopTime, doubleWidth, 1833 actualCellWidth, actualCellHeight + (distanceField ? 1 : 0), colors2); 1834 im.setAlign(2); 1835 im.setSize(actualCellWidth * (doubleWidth ? 2 : 1), actualCellHeight + (distanceField ? 1 : 0)); // - lineHeight / actualCellHeight //+ lineTweak * 1f 1836 return im; 1837 } 1838 1839 /** 1840 * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be 1841 * used for preparing images for animation effects. Stretches the TextureRegion to match a single cell's dimensions. 1842 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1843 * @param color a Color to tint tr with. 1844 * @return the Actor, with no position set. 1845 */ 1846 public Actor makeActor(TextureRegion tr, Color color) { 1847 if (!initialized) { 1848 throw new IllegalStateException("This factory has not yet been initialized!"); 1849 } 1850 if (tr == null) { 1851 Image im = new Image(block); 1852 im.setColor(scc.filter(color)); 1853 im.setSize(width, height); 1854 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1855 return im; 1856 } else { 1857 Image im = new Image(tr); 1858 im.setColor(scc.filter(color)); 1859 im.setSize(width, height); 1860 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1861 return im; 1862 } 1863 } 1864 1865 /** 1866 * Converts a TextureRegion into an Image, or if the argument s is null, creates an Image of a solid block. Can be 1867 * used for preparing images for animation effects. Ensures the returned Image has the given width and height. 1868 * @param tr a TextureRegion to make into an Actor, which can be null for a solid block. 1869 * @param color a Color to tint tr with. 1870 * @return the Actor, with no position set. 1871 */ 1872 public Actor makeActor(TextureRegion tr, Color color, float width, float height) { 1873 if (!initialized) { 1874 throw new IllegalStateException("This factory has not yet been initialized!"); 1875 } 1876 if (tr == null) { 1877 Image im = new Image(block); 1878 im.setColor(scc.filter(color)); 1879 im.setSize(width, height); 1880 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1881 return im; 1882 } else { 1883 Image im = new Image(tr); 1884 im.setColor(scc.filter(color)); 1885 im.setSize(width, height); 1886 // im.setPosition(x - width * 0.5f, y - height * 0.5f, Align.center); 1887 return im; 1888 } 1889 } 1890 1891 /** 1892 * Returns a solid block of white, 1x1 pixel in size; can be drawn at other sizes by Batch. 1893 * @return a white 1x1 pixel Texture. 1894 */ 1895 public TextureRegion getSolid() { 1896 if (!initialized) { 1897 throw new IllegalStateException("This factory has not yet been initialized!"); 1898 } 1899 return block; 1900 } 1901 /** 1902 * Gets a Glyph with the given char to show, libGDX Color, and position as x and y in world coordinates. 1903 * Glyph is a kind of scene2d Actor that uses this TextCellFactory to handle its rendering instead of delegating 1904 * that to the Label class from scene2d.ui. 1905 * @param shown char to show; if this is the char with codepoint 0, then this will show a solid block 1906 * @param color the color as a libGDX Color; can also be an SColor or some other subclass of Color 1907 * @param x the x position of the Glyph in world coordinates, as would be passed to draw() 1908 * @param y the y position of the Glyph in world coordinates, as would be passed to draw() 1909 * @return a new Glyph that will use the specified char, color, and position 1910 */ 1911 1912 public Glyph glyph(char shown, Color color, float x, float y) 1913 { 1914 return new Glyph(shown, color, x, y); 1915 } 1916 1917 /** 1918 * Gets a Glyph with the given char to show, color as a packed float, and position as x and y in world coordinates. 1919 * Glyph is a kind of scene2d Actor that uses this TextCellFactory to handle its rendering instead of delegating 1920 * that to the Label class from scene2d.ui. 1921 * @param shown char to show; if this is the char with codepoint 0, then this will show a solid block 1922 * @param encodedColor the encoded color as a float, as produced by {@link Color#toFloatBits()} 1923 * @param x the x position of the Glyph in world coordinates, as would be passed to draw() 1924 * @param y the y position of the Glyph in world coordinates, as would be passed to draw() 1925 * @return a new Glyph that will use the specified char, color, and position 1926 */ 1927 public Glyph glyph(char shown, float encodedColor, float x, float y) 1928 { 1929 return new Glyph(shown, encodedColor, x, y); 1930 } 1931 1932 public boolean isMultiDistanceField() { 1933 return msdf; 1934 } 1935 1936 public boolean isDistanceField() { 1937 return distanceField; 1938 } 1939 1940 public float getDistanceFieldScaleX() { 1941 return distanceFieldScaleX; 1942 } 1943 public float getDistanceFieldScaleY() { 1944 return distanceFieldScaleY; 1945 } 1946 1947 /** 1948 * If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher 1949 * numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing. This starts 1950 * at 1.2f, usually ({@link DefaultResources} notes when a different value is used). 1951 * @return the current smoothing multiplier as a float, which starts at 1.2f for most fonts 1952 */ 1953 public float getSmoothingMultiplier() { 1954 return smoothingMultiplier; 1955 } 1956 1957 /** 1958 * If this uses a distance field font, the smoothing multiplier affects how crisp or blurry lines are, with higher 1959 * numbers generally resulting in more crisp fonts, but numbers that are too high cause jagged aliasing. Before this 1960 * is called, the smoothing multiplier is usually 1.2f; {@link DefaultResources} notes when other values are used. 1961 * @param smoothingMultiplier the new value for the smoothing multiplier as a float; should be fairly close to 1f. 1962 * @return this for chaining 1963 */ 1964 public TextCellFactory setSmoothingMultiplier(float smoothingMultiplier) { 1965 this.smoothingMultiplier = smoothingMultiplier; 1966 return this; 1967 } 1968 1969 /** 1970 * If using a distance field font, you MUST call this at some point while the batch has begun, or use code that 1971 * calls it for you (which is now much of SquidLib). A typical point to call it is in the 1972 * "void draw(Batch batch, float parentAlpha)" method or an overriding method for a Scene2D class. You should call 1973 * configureShader rarely, typically only a few times per frame if there are no images to render, and this means the 1974 * logical place to call it is in the outermost Group that contains any SquidPanel objects or other widgets. If you 1975 * have multipleTextCellFactory objects, each one needs to have configureShader called before it is used to draw. 1976 * <br> 1977 * SquidLayers, SparseLayers, SubcellLayers, SquidPanel, TextPanel, and ImageSquidPanel already call 1978 * this method in their draw overrides, so you don't need to call this manually if you use any of those. None of 1979 * those classes change the shader after they set it for their uses, so you may need to set the shader on your Batch 1980 * to null to revert to the default shader if you need to draw full-color art. 1981 * <br> 1982 * If you don't use a distance field font, you don't need to call this, but calling it won't cause problems. 1983 * 1984 * @param batch the Batch, such as a {@link FilterBatch}, to configure to render distance field fonts if necessary. 1985 */ 1986 public void configureShader(Batch batch) { 1987 if(initialized) 1988 { 1989 if(msdf) 1990 { 1991 if(!shader.equals(batch.getShader())) 1992 batch.setShader(shader); 1993 shader.setUniformf("u_smoothing", 2.1198158f * smoothingMultiplier * bmpFont.getData().scaleX); 1994 } 1995 else if (distanceField) { 1996 if(!shader.equals(batch.getShader())) 1997 batch.setShader(shader); 1998 shader.setUniformf("u_smoothing", 0.35f / (1.9f * smoothingMultiplier * (bmpFont.getData().scaleX + bmpFont.getData().scaleY))); 1999 } 2000 } 2001 } 2002 /** 2003 * Releases all resources of this object. 2004 */ 2005 @Override 2006 public void dispose() { 2007 if(block != null) block.getTexture().dispose(); 2008 if(bmpFont != null) bmpFont.dispose(); 2009 } 2010 2011 /** 2012 * Gets the descent of this TextCellFactory's BitmapFont, which may be useful for layout outside this class. 2013 * @return the descent of the BitmapFont this object uses 2014 */ 2015 public float getDescent() { 2016 return descent; 2017 } 2018 2019 public char getDirectionGlyph() { 2020 return directionGlyph; 2021 } 2022 2023 public TextCellFactory setDirectionGlyph(char directionGlyph) { 2024 this.directionGlyph = directionGlyph; 2025 return this; 2026 } 2027 2028 /** 2029 * Adds a pair of Strings (typically both with length 1) as a replacement pair, so when the find String is requested 2030 * to be drawn, the replace String is used instead. Swaps are used when drawing text in each cell in SquidPanel and 2031 * related classes, so Strings longer than 1 char are effectively disregarded beyond the first char. 2032 * <br> 2033 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2034 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2035 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap("^", ",")} and also 2036 * {@code addSwap(",", ":")}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2037 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2038 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2039 * @param find the requested String that will be changed 2040 * @param replace the replacement String that will be used in place of find 2041 * @return this for chaining 2042 */ 2043 public TextCellFactory addSwap(String find, String replace) 2044 { 2045 if(find == null || replace == null || find.isEmpty() || replace.isEmpty() || find.charAt(0) == 0) 2046 return this; 2047 swap.put(find.charAt(0), replace.charAt(0)); 2048 return this; 2049 } 2050 2051 /** 2052 * Adds a pair of chars as a replacement pair, so when the find char is requested to be drawn, the replace char is 2053 * used instead. 2054 * <br> 2055 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2056 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2057 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2058 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2059 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2060 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2061 * @param find the requested char that will be changed (converted to a length-1 String) 2062 * @param replace the replacement char that will be used in place of find (converted to a length-1 String) 2063 * @return this for chaining 2064 */ 2065 public TextCellFactory addSwap(char find, char replace) 2066 { 2067 if(find == 0) 2068 return this; 2069 swap.put(find, replace); 2070 return this; 2071 } 2072 2073 /** 2074 * Removes the replacement pair, if present, that searches for the given key, find. Swaps are used when drawing text 2075 * in each cell in SquidPanel and related classes, so Strings longer than 1 char are effectively disregarded beyond 2076 * the first char. 2077 * <br> 2078 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2079 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2080 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2081 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2082 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2083 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2084 * @param find the String that would be changed in the replacement pair 2085 * @return this for chaining 2086 */ 2087 public TextCellFactory removeSwap(String find) 2088 { 2089 2090 if(find != null && !find.isEmpty() && find.charAt(0) != 0) 2091 swap.remove(find.charAt(0)); 2092 return this; 2093 } 2094 2095 /** 2096 * Removes the replacement pair, if present, that searches for the given key, find. 2097 * <br> 2098 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2099 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2100 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2101 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2102 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2103 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2104 * @return this for chaining 2105 */ 2106 public TextCellFactory removeSwap(char find) 2107 { 2108 swap.remove(find); 2109 return this; 2110 } 2111 2112 /** 2113 * Gets the current mapping of "swaps", or replacement pairs, to replace keys requested for drawing with their 2114 * values in the {@link CharCharMap}. CharCharMap is a class from RegExodus (a dependency of squidlib-util that is 2115 * used for text matching and Unicode support), which is used here to avoid making yet another primitive-backed 2116 * collection class. 2117 * <br> 2118 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2119 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2120 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2121 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2122 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2123 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2124 * @return the mapping of replacement pairs 2125 */ 2126 public CharCharMap getAllSwaps() { 2127 return swap; 2128 } 2129 2130 /** 2131 * Sets the mapping of replacement pairs to a different one as a Map of Character keys to String values. 2132 * <br> 2133 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2134 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2135 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2136 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2137 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2138 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2139 * @param swaps the Map of replacement pairs; keys requested for drawing will be replaced with their values 2140 * @return this for chaining 2141 */ 2142 public TextCellFactory setAllSwaps(OrderedMap<Character, Character> swaps) { 2143 swap.clear(); 2144 for (int i = 0; i < swaps.size(); i++) { 2145 if(!swaps.keyAt(i).equals('\0')) 2146 swap.put(swaps.keyAt(i), swaps.getAt(i)); 2147 } 2148 return this; 2149 } 2150 2151 /** 2152 * Appends to the mapping of replacement pairs, adding or replacing any entries in the current mapping with the 2153 * entries in a Map of Character keys to String values. 2154 * <br> 2155 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2156 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2157 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2158 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2159 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2160 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2161 * @param swaps the Map of replacement pairs to add; keys requested for drawing will be replaced with their values 2162 * @return this for chaining 2163 */ 2164 public TextCellFactory addSwaps(OrderedMap<Character, Character> swaps) { 2165 for (int i = 0; i < swaps.size(); i++) { 2166 if(!swaps.keyAt(i).equals('\0')) 2167 swap.put(swaps.keyAt(i), swaps.getAt(i)); 2168 } 2169 return this; 2170 } 2171 2172 /** 2173 * Clears all replacement pairs this has been told to swap. 2174 * <br> 2175 * This can be useful when you want to use certain defaults in squidlib-util's dungeon generation, like '~' for deep 2176 * water, but not others, like ',' for shallow water, and would rather have a glyph of your choice replace something 2177 * that would be drawn. Replacements will not be chained; that is, if you {@code addSwap('^', ',')} and also 2178 * {@code addSwap(',', ':')}, then a requested '^' will be drawn as ',', not ':', but a requested ',' will be drawn 2179 * as ':' (only one swap will be performed). Typically you want a different TextCellFactory for UI elements that use 2180 * swapping, like a top-down char-based map, and elements that should not, like those that display normal text. 2181 * @return this for chaining 2182 */ 2183 public TextCellFactory clearSwaps() 2184 { 2185 swap.clear(); 2186 return this; 2187 } 2188 2189 /** 2190 * Not implemented in this class; in subclasses that do, this should change the currently-used font style, such as 2191 * from regular to italic or bold. Calling this method on a TextCellFactory does nothing, but won't cause problems. 2192 * @param style an int, typically a constant in a class that implements this, that determines what style to use. 2193 */ 2194 public void setStyle(int style) 2195 { 2196 } 2197 2198 /** 2199 * A kind of Actor for one char (with one color) that is innately drawn with a specific TextCellFactory, and will 2200 * match the layout behavior of that TextCellFactory when it is used for other purposes. This is an inner class of 2201 * TextCellFactory, and can't be constructed without a TextCellFactory being involved; usually you instantiate 2202 * Glyphs with {@link #glyph(char, Color, float, float)} or an overload of that method on TextCellFactory. 2203 */ 2204 public class Glyph extends Actor implements ICellVisible 2205 { 2206 /** 2207 * The char that will be shown for this Glyph. 2208 */ 2209 public char shown; 2210 2211 @Override 2212 public char getSymbol() 2213 { 2214 return shown; 2215 } 2216 2217 /** 2218 * Makes an orange '@' Glyph at 0,0 in world coordinates. 2219 */ 2220 public Glyph() { 2221 this('@', SColor.SAFETY_ORANGE, 0f, 0f); 2222 } 2223 2224 /** 2225 * Makes a Glyph of the given char in the given Color, at the specified world coordinates. 2226 * @param shown the char to show 2227 * @param color the Color to use; if null this will instead use {@link SColor#TRANSPARENT} 2228 * @param x x position in world coordinates 2229 * @param y y position in world coordinates 2230 */ 2231 public Glyph(char shown, Color color, float x, float y) 2232 { 2233 super(); 2234 this.shown = shown; 2235 super.getColor().set(color == null ? SColor.TRANSPARENT : color); 2236 setPosition(x, y); 2237 } 2238 2239 /** 2240 * Makes a Glyph of the given char in the given packed float color, at the specified world coordinates. 2241 * @param shown the char to show 2242 * @param color the packed float color to use, as produced by {@link Color#toFloatBits()} 2243 * @param x x position in world coordinates 2244 * @param y y position in world coordinates 2245 */ 2246 public Glyph(char shown, float color, float x, float y) { 2247 super(); 2248 this.shown = shown; 2249 Color.abgr8888ToColor(super.getColor(), color); 2250 setPosition(x, y); 2251 } 2252 2253 /** 2254 * Gets the color of this Glyph as a packed float color; does not allocate any objects. 2255 * @return the color of this Glyph as a packed float 2256 */ 2257 @Override 2258 public float getPackedColor() { 2259 return getColor().toFloatBits(); 2260 } 2261 2262 /** 2263 * Sets the color of this Glyph with the given packed float color; does not allocate any objects. 2264 * @param color the color to set this Glyph to, as a packed float 2265 */ 2266 public void setPackedColor(float color) { 2267 Color.abgr8888ToColor(super.getColor(), color); 2268 } 2269 2270 @Override 2271 public String toString() { 2272 return "Glyph{'" + 2273 + shown + 2274 "' with color " + getColor() + 2275 ", position (" + getX() + 2276 "," + getY() + 2277 ")}"; 2278 } 2279 2280 /** 2281 * Draws the actor. The batch is configured to draw in the parent's coordinate system. 2282 * {@link Batch#begin()} must have already been called on the batch before this method. 2283 * 2284 * @param batch the batch should be between begin() and end(), usually handled by Stage 2285 * @param parentAlpha Multiplied with this Glyph's alpha, allowing a parent's alpha to affect all children. 2286 */ 2287 @Override 2288 public void draw(Batch batch, float parentAlpha) { 2289 TextCellFactory.this.draw(batch, shown, SColor.multiplyAlpha(getColor(), parentAlpha), getX(), getY() + 1); 2290 } 2291 } 2292}