use of com.badlogic.gdx.graphics.Color in project libgdx by libgdx.
the class FreeTypeFontGenerator method createGlyph.
/** @return null if glyph was not found. */
Glyph createGlyph(char c, FreeTypeBitmapFontData data, FreeTypeFontParameter parameter, Stroker stroker, float baseLine, PixmapPacker packer) {
boolean missing = face.getCharIndex(c) == 0 && c != 0;
if (missing)
return null;
if (!loadChar(c, getLoadingFlags(parameter)))
return null;
GlyphSlot slot = face.getGlyph();
FreeType.Glyph mainGlyph = slot.getGlyph();
try {
mainGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
} catch (GdxRuntimeException e) {
mainGlyph.dispose();
Gdx.app.log("FreeTypeFontGenerator", "Couldn't render char: " + c);
return null;
}
Bitmap mainBitmap = mainGlyph.getBitmap();
Pixmap mainPixmap = mainBitmap.getPixmap(Format.RGBA8888, parameter.color, parameter.gamma);
if (mainBitmap.getWidth() != 0 && mainBitmap.getRows() != 0) {
int offsetX = 0, offsetY = 0;
if (parameter.borderWidth > 0) {
// execute stroker; this generates a glyph "extended" along the outline
int top = mainGlyph.getTop(), left = mainGlyph.getLeft();
FreeType.Glyph borderGlyph = slot.getGlyph();
borderGlyph.strokeBorder(stroker, false);
borderGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
offsetX = left - borderGlyph.getLeft();
offsetY = -(top - borderGlyph.getTop());
// Render border (pixmap is bigger than main).
Bitmap borderBitmap = borderGlyph.getBitmap();
Pixmap borderPixmap = borderBitmap.getPixmap(Format.RGBA8888, parameter.borderColor, parameter.borderGamma);
// Draw main glyph on top of border.
for (int i = 0, n = parameter.renderCount; i < n; i++) borderPixmap.drawPixmap(mainPixmap, offsetX, offsetY);
mainPixmap.dispose();
mainGlyph.dispose();
mainPixmap = borderPixmap;
mainGlyph = borderGlyph;
}
if (parameter.shadowOffsetX != 0 || parameter.shadowOffsetY != 0) {
int mainW = mainPixmap.getWidth(), mainH = mainPixmap.getHeight();
int shadowOffsetX = Math.max(parameter.shadowOffsetX, 0), shadowOffsetY = Math.max(parameter.shadowOffsetY, 0);
int shadowW = mainW + Math.abs(parameter.shadowOffsetX), shadowH = mainH + Math.abs(parameter.shadowOffsetY);
Pixmap shadowPixmap = new Pixmap(shadowW, shadowH, mainPixmap.getFormat());
Color shadowColor = parameter.shadowColor;
float a = shadowColor.a;
if (a != 0) {
byte r = (byte) (shadowColor.r * 255), g = (byte) (shadowColor.g * 255), b = (byte) (shadowColor.b * 255);
ByteBuffer mainPixels = mainPixmap.getPixels();
ByteBuffer shadowPixels = shadowPixmap.getPixels();
for (int y = 0; y < mainH; y++) {
int shadowRow = shadowW * (y + shadowOffsetY) + shadowOffsetX;
for (int x = 0; x < mainW; x++) {
int mainPixel = (mainW * y + x) * 4;
byte mainA = mainPixels.get(mainPixel + 3);
if (mainA == 0)
continue;
int shadowPixel = (shadowRow + x) * 4;
shadowPixels.put(shadowPixel, r);
shadowPixels.put(shadowPixel + 1, g);
shadowPixels.put(shadowPixel + 2, b);
shadowPixels.put(shadowPixel + 3, (byte) ((mainA & 0xff) * a));
}
}
}
// Draw main glyph (with any border) on top of shadow.
for (int i = 0, n = parameter.renderCount; i < n; i++) shadowPixmap.drawPixmap(mainPixmap, Math.max(-parameter.shadowOffsetX, 0), Math.max(-parameter.shadowOffsetY, 0));
mainPixmap.dispose();
mainPixmap = shadowPixmap;
} else if (parameter.borderWidth == 0) {
// No shadow and no border, draw glyph additional times.
for (int i = 0, n = parameter.renderCount - 1; i < n; i++) mainPixmap.drawPixmap(mainPixmap, 0, 0);
}
}
GlyphMetrics metrics = slot.getMetrics();
Glyph glyph = new Glyph();
glyph.id = c;
glyph.width = mainPixmap.getWidth();
glyph.height = mainPixmap.getHeight();
glyph.xoffset = mainGlyph.getLeft();
glyph.yoffset = parameter.flip ? -mainGlyph.getTop() + (int) baseLine : -(glyph.height - mainGlyph.getTop()) - (int) baseLine;
glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance()) + (int) parameter.borderWidth + parameter.spaceX;
if (bitmapped) {
mainPixmap.setColor(Color.CLEAR);
mainPixmap.fill();
ByteBuffer buf = mainBitmap.getBuffer();
int whiteIntBits = Color.WHITE.toIntBits();
int clearIntBits = Color.CLEAR.toIntBits();
for (int h = 0; h < glyph.height; h++) {
int idx = h * mainBitmap.getPitch();
for (int w = 0; w < (glyph.width + glyph.xoffset); w++) {
int bit = (buf.get(idx + (w / 8)) >>> (7 - (w % 8))) & 1;
mainPixmap.drawPixel(w, h, ((bit == 1) ? whiteIntBits : clearIntBits));
}
}
}
Rectangle rect = packer.pack(mainPixmap);
// Glyph is always packed into the last page for now.
glyph.page = packer.getPages().size - 1;
glyph.srcX = (int) rect.x;
glyph.srcY = (int) rect.y;
// If a page was added, create a new texture region for the incrementally added glyph.
if (parameter.incremental && data.regions != null && data.regions.size <= glyph.page)
packer.updateTextureRegions(data.regions, parameter.minFilter, parameter.magFilter, parameter.genMipMaps);
mainPixmap.dispose();
mainGlyph.dispose();
return glyph;
}
use of com.badlogic.gdx.graphics.Color in project libgdx by libgdx.
the class Hiero method initializeEvents.
private void initializeEvents() {
fontList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
if (evt.getValueIsAdjusting())
return;
prefs.put("system.font", (String) fontList.getSelectedValue());
updateFont();
}
});
class FontUpdateListener implements ChangeListener, ActionListener {
public void stateChanged(ChangeEvent evt) {
updateFont();
}
public void actionPerformed(ActionEvent evt) {
updateFont();
}
public void addSpinners(JSpinner[] spinners) {
for (int i = 0; i < spinners.length; i++) {
final JSpinner spinner = spinners[i];
spinner.addChangeListener(this);
((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().addKeyListener(new KeyAdapter() {
String lastText;
public void keyReleased(KeyEvent evt) {
JFormattedTextField textField = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
String text = textField.getText();
if (text.length() == 0)
return;
if (text.equals(lastText))
return;
lastText = text;
int caretPosition = textField.getCaretPosition();
try {
spinner.setValue(Integer.valueOf(text));
} catch (NumberFormatException ex) {
}
textField.setCaretPosition(caretPosition);
}
});
}
}
}
FontUpdateListener listener = new FontUpdateListener();
listener.addSpinners(new JSpinner[] { padTopSpinner, padRightSpinner, padBottomSpinner, padLeftSpinner, padAdvanceXSpinner, padAdvanceYSpinner });
fontSizeSpinner.addChangeListener(listener);
gammaSpinner.addChangeListener(listener);
glyphPageWidthCombo.addActionListener(listener);
glyphPageHeightCombo.addActionListener(listener);
boldCheckBox.addActionListener(listener);
italicCheckBox.addActionListener(listener);
monoCheckBox.addActionListener(listener);
resetCacheButton.addActionListener(listener);
javaRadio.addActionListener(listener);
nativeRadio.addActionListener(listener);
freeTypeRadio.addActionListener(listener);
sampleTextRadio.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
glyphCachePanel.setVisible(false);
}
});
glyphCacheRadio.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
glyphCachePanel.setVisible(true);
}
});
fontFileText.getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent evt) {
changed();
}
public void insertUpdate(DocumentEvent evt) {
changed();
}
public void changedUpdate(DocumentEvent evt) {
changed();
}
private void changed() {
File file = new File(fontFileText.getText());
if (fontList.isEnabled() && (!file.exists() || !file.isFile()))
return;
prefs.put("font.file", fontFileText.getText());
updateFont();
}
});
final ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
updateFontSelector();
updateFont();
}
};
systemFontRadio.addActionListener(al);
fontFileRadio.addActionListener(al);
browseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
FileDialog dialog = new FileDialog(Hiero.this, "Choose TrueType font file", FileDialog.LOAD);
dialog.setLocationRelativeTo(null);
dialog.setFile("*.ttf");
dialog.setDirectory(prefs.get("dir.font", ""));
dialog.setVisible(true);
if (dialog.getDirectory() != null) {
prefs.put("dir.font", dialog.getDirectory());
}
String fileName = dialog.getFile();
if (fileName == null)
return;
fontFileText.setText(new File(dialog.getDirectory(), fileName).getAbsolutePath());
}
});
backgroundColorLabel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
java.awt.Color color = JColorChooser.showDialog(null, "Choose a background color", EffectUtil.fromString(prefs.get("background", "000000")));
if (color == null)
return;
renderingBackgroundColor = new Color(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, 1);
backgroundColorLabel.setIcon(getColorIcon(color));
prefs.put("background", EffectUtil.toString(color));
}
});
effectsList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
ConfigurableEffect selectedEffect = (ConfigurableEffect) effectsList.getSelectedValue();
boolean enabled = selectedEffect != null;
for (Iterator iter = effectPanels.iterator(); iter.hasNext(); ) {
ConfigurableEffect effect = ((EffectPanel) iter.next()).getEffect();
if (effect == selectedEffect) {
enabled = false;
break;
}
}
addEffectButton.setEnabled(enabled);
}
});
effectsList.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 2 && addEffectButton.isEnabled())
addEffectButton.doClick();
}
});
addEffectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
new EffectPanel((ConfigurableEffect) effectsList.getSelectedValue());
}
});
openMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
FileDialog dialog = new FileDialog(Hiero.this, "Open Hiero settings file", FileDialog.LOAD);
dialog.setLocationRelativeTo(null);
dialog.setFile("*.hiero");
dialog.setDirectory(prefs.get("dir.open", ""));
dialog.setVisible(true);
if (dialog.getDirectory() != null) {
prefs.put("dir.open", dialog.getDirectory());
}
String fileName = dialog.getFile();
if (fileName == null)
return;
lastOpenFilename = fileName;
open(new File(dialog.getDirectory(), fileName));
}
});
saveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
FileDialog dialog = new FileDialog(Hiero.this, "Save Hiero settings file", FileDialog.SAVE);
dialog.setLocationRelativeTo(null);
dialog.setFile("*.hiero");
dialog.setDirectory(prefs.get("dir.save", ""));
if (lastSaveFilename.length() > 0) {
dialog.setFile(lastSaveFilename);
} else if (lastOpenFilename.length() > 0) {
dialog.setFile(lastOpenFilename);
}
dialog.setVisible(true);
if (dialog.getDirectory() != null) {
prefs.put("dir.save", dialog.getDirectory());
}
String fileName = dialog.getFile();
if (fileName == null)
return;
if (!fileName.endsWith(".hiero"))
fileName += ".hiero";
lastSaveFilename = fileName;
File file = new File(dialog.getDirectory(), fileName);
try {
save(file);
} catch (IOException ex) {
throw new RuntimeException("Error saving Hiero settings file: " + file.getAbsolutePath(), ex);
}
}
});
saveBMFontMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
FileDialog dialog = new FileDialog(Hiero.this, "Save BMFont files", FileDialog.SAVE);
dialog.setLocationRelativeTo(null);
dialog.setFile("*.fnt");
dialog.setDirectory(prefs.get("dir.savebm", ""));
if (lastSaveBMFilename.length() > 0) {
dialog.setFile(lastSaveBMFilename);
} else if (lastOpenFilename.length() > 0) {
dialog.setFile(lastOpenFilename.replace(".hiero", ".fnt"));
}
dialog.setVisible(true);
if (dialog.getDirectory() != null) {
prefs.put("dir.savebm", dialog.getDirectory());
}
String fileName = dialog.getFile();
if (fileName == null)
return;
lastSaveBMFilename = fileName;
saveBm(new File(dialog.getDirectory(), fileName));
}
});
exitMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
dispose();
}
});
sampleNeheButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
sampleTextPane.setText(NEHE_CHARS);
resetCacheButton.doClick();
}
});
sampleAsciiButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
StringBuilder buffer = new StringBuilder();
buffer.append(NEHE_CHARS);
buffer.append('\n');
int count = 0;
for (int i = 33; i <= 255; i++) {
if (buffer.indexOf(Character.toString((char) i)) != -1)
continue;
buffer.append((char) i);
if (++count % 30 == 0)
buffer.append('\n');
}
sampleTextPane.setText(buffer.toString());
resetCacheButton.doClick();
}
});
sampleExtendedButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
sampleTextPane.setText(EXTENDED_CHARS);
resetCacheButton.doClick();
}
});
}
use of com.badlogic.gdx.graphics.Color in project libgdx by libgdx.
the class GlyphLayout method setText.
/** @param color The default color to use for the text (the BitmapFont {@link BitmapFont#getColor() color} is not used). If
* {@link BitmapFontData#markupEnabled} is true, color markup tags in the specified string may change the color for
* portions of the text.
* @param halign Horizontal alignment of the text, see {@link Align}.
* @param targetWidth The width used for alignment, line wrapping, and truncation. May be zero if those features are not used.
* @param truncate If not null and the width of the glyphs exceed targetWidth, the glyphs are truncated and the glyphs for the
* specified truncate string are placed at the end. Empty string can be used to truncate without adding glyphs.
* Truncate should not be used with text that contains multiple lines. Wrap is ignored if truncate is not null. */
public void setText(BitmapFont font, CharSequence str, int start, int end, Color color, float targetWidth, int halign, boolean wrap, String truncate) {
if (truncate != null)
// Causes truncate code to run, doesn't actually cause wrapping.
wrap = true;
else if (//
targetWidth <= font.data.spaceWidth)
// Avoid one line per character, which is very inefficient.
wrap = false;
BitmapFontData fontData = font.data;
boolean markupEnabled = fontData.markupEnabled;
Pool<GlyphRun> glyphRunPool = Pools.get(GlyphRun.class);
Array<GlyphRun> runs = this.runs;
glyphRunPool.freeAll(runs);
runs.clear();
float x = 0, y = 0, width = 0;
int lines = 0, blankLines = 0;
Array<Color> colorStack = this.colorStack;
Color nextColor = color;
colorStack.add(color);
Pool<Color> colorPool = Pools.get(Color.class);
int runStart = start;
outer: while (true) {
// Each run is delimited by newline or left square bracket.
int runEnd = -1;
boolean newline = false, colorRun = false;
if (start == end) {
// End of string with no run to process, we're done.
if (runStart == end)
break;
// End of string, process last run.
runEnd = end;
} else {
switch(str.charAt(start++)) {
case '\n':
// End of line.
runEnd = start - 1;
newline = true;
break;
case '[':
// Possible color tag.
if (markupEnabled) {
int length = parseColorMarkup(str, start, end, colorPool);
if (length >= 0) {
runEnd = start - 1;
start += length + 1;
nextColor = colorStack.peek();
colorRun = true;
} else if (length == -2) {
// Skip first of "[[" escape sequence.
start++;
continue outer;
}
}
break;
}
}
if (runEnd != -1) {
if (runEnd != runStart) {
// Can happen (eg) when a color tag is at text start or a line is "\n".
// Store the run that has ended.
GlyphRun run = glyphRunPool.obtain();
run.color.set(color);
run.x = x;
run.y = y;
fontData.getGlyphs(run, str, runStart, runEnd, colorRun);
if (run.glyphs.size == 0)
glyphRunPool.free(run);
else {
runs.add(run);
// Compute the run width, wrap if necessary, and position the run.
float[] xAdvances = run.xAdvances.items;
for (int i = 0, n = run.xAdvances.size; i < n; i++) {
float xAdvance = xAdvances[i];
x += xAdvance;
// Don't wrap if the glyph would fit with just its width (no xadvance or kerning).
if (wrap && x > targetWidth && i > 1 && x - xAdvance + (run.glyphs.get(i - 1).xoffset + run.glyphs.get(i - 1).width) * fontData.scaleX - 0.0001f > targetWidth) {
if (truncate != null) {
truncate(fontData, run, targetWidth, truncate, i, glyphRunPool);
x = run.x + run.width;
break outer;
}
int wrapIndex = fontData.getWrapIndex(run.glyphs, i);
if (// Require at least one glyph per line.
(run.x == 0 && wrapIndex == 0) || wrapIndex >= run.glyphs.size) {
// Wrap at least the glyph that didn't fit.
wrapIndex = i - 1;
}
GlyphRun next;
if (wrapIndex == 0)
// No wrap index, move entire run to next line.
next = run;
else {
next = wrap(fontData, run, glyphRunPool, wrapIndex, i);
runs.add(next);
}
// Start the loop over with the new run on the next line.
width = Math.max(width, run.x + run.width);
x = 0;
y += fontData.down;
lines++;
next.x = 0;
next.y = y;
i = -1;
n = next.xAdvances.size;
xAdvances = next.xAdvances.items;
run = next;
} else
run.width += xAdvance;
}
}
}
if (newline) {
// Next run will be on the next line.
width = Math.max(width, x);
x = 0;
float down = fontData.down;
if (runEnd == runStart) {
// Blank line.
down *= fontData.blankLineScale;
blankLines++;
} else
lines++;
y += down;
}
runStart = start;
color = nextColor;
}
}
width = Math.max(width, x);
for (int i = 1, n = colorStack.size; i < n; i++) colorPool.free(colorStack.get(i));
colorStack.clear();
// Align runs to center or right of targetWidth.
if ((halign & Align.left) == 0) {
// Not left aligned, so must be center or right aligned.
boolean center = (halign & Align.center) != 0;
float lineWidth = 0, lineY = Integer.MIN_VALUE;
int lineStart = 0, n = runs.size;
for (int i = 0; i < n; i++) {
GlyphRun run = runs.get(i);
if (run.y != lineY) {
lineY = run.y;
float shift = targetWidth - lineWidth;
if (center)
shift /= 2;
while (lineStart < i) runs.get(lineStart++).x += shift;
lineWidth = 0;
}
lineWidth += run.width;
}
float shift = targetWidth - lineWidth;
if (center)
shift /= 2;
while (lineStart < n) runs.get(lineStart++).x += shift;
}
this.width = width;
this.height = fontData.capHeight + lines * fontData.lineHeight + blankLines * fontData.lineHeight * fontData.blankLineScale;
}
use of com.badlogic.gdx.graphics.Color in project libgdx by libgdx.
the class GlyphLayout method parseColorMarkup.
private int parseColorMarkup(CharSequence str, int start, int end, Pool<Color> colorPool) {
// String ended with "[".
if (start == end)
return -1;
switch(str.charAt(start)) {
case '#':
// Parse hex color RRGGBBAA where AA is optional and defaults to 0xFF if less than 6 chars are used.
int colorInt = 0;
for (int i = start + 1; i < end; i++) {
char ch = str.charAt(i);
if (ch == ']') {
// Illegal number of hex digits.
if (i < start + 2 || i > start + 9)
break;
if (i - start <= 7) {
// RRGGBB or fewer chars.
for (int ii = 0, nn = 9 - (i - start); ii < nn; ii++) colorInt = colorInt << 4;
colorInt |= 0xff;
}
Color color = colorPool.obtain();
colorStack.add(color);
Color.rgba8888ToColor(color, colorInt);
return i - start;
}
if (ch >= '0' && ch <= '9')
colorInt = colorInt * 16 + (ch - '0');
else if (ch >= 'a' && ch <= 'f')
colorInt = colorInt * 16 + (ch - ('a' - 10));
else if (ch >= 'A' && ch <= 'F')
colorInt = colorInt * 16 + (ch - ('A' - 10));
else
// Unexpected character in hex color.
break;
}
return -1;
case // "[[" is an escaped left square bracket.
'[':
return -2;
case // "[]" is a "pop" color tag.
']':
if (colorStack.size > 1)
colorPool.free(colorStack.pop());
return 0;
}
// Parse named color.
int colorStart = start;
for (int i = start + 1; i < end; i++) {
char ch = str.charAt(i);
if (ch != ']')
continue;
Color namedColor = Colors.get(str.subSequence(colorStart, i).toString());
// Unknown color name.
if (namedColor == null)
return -1;
Color color = colorPool.obtain();
colorStack.add(color);
color.set(namedColor);
return i - start;
}
// Unclosed color tag.
return -1;
}
use of com.badlogic.gdx.graphics.Color in project libgdx by libgdx.
the class PolygonSprite method draw.
public void draw(PolygonSpriteBatch spriteBatch, float alphaModulation) {
Color color = getColor();
float oldAlpha = color.a;
color.a *= alphaModulation;
setColor(color);
draw(spriteBatch);
color.a = oldAlpha;
setColor(color);
}
Aggregations