Java tutorial
/* * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package com.badlogic.gdx.hiero; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.FileDialog; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashSet; import java.util.prefs.Preferences; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.JWindow; import javax.swing.KeyStroke; import javax.swing.ScrollPaneConstants; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.lwjgl.opengl.GL11; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.backends.lwjgl.LwjglCanvas; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.Texture.TextureWrap; import com.badlogic.gdx.graphics.TextureData; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.hiero.unicodefont.UnicodeFont; import com.badlogic.gdx.hiero.unicodefont.effects.EffectUtil; import de.matthiasmann.twlthemeeditor.fontgen.CharSet; import de.matthiasmann.twlthemeeditor.fontgen.Effect; import de.matthiasmann.twlthemeeditor.fontgen.FontData; import de.matthiasmann.twlthemeeditor.fontgen.FontGenerator; import de.matthiasmann.twlthemeeditor.fontgen.FontGenerator.ExportFormat; import de.matthiasmann.twlthemeeditor.fontgen.FontGenerator.GeneratorMethod; import de.matthiasmann.twlthemeeditor.fontgen.Padding; import static org.lwjgl.opengl.GL11.*; /** * WIP, based on Matthias' TWL font renderer. Currently missing effects and saving hiero settings.<br> * <br> * A tool to visualize settings for {@link UnicodeFont} and to export BMFont files for use with {@link BitmapFont}. * @author Nathan Sweet */ public class Hiero4 extends JFrame { static final String NEHE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" // + "abcdefghijklmnopqrstuvwxyz\n1234567890\n" // + "\"!`?'.,;:()[]{}<>|/@\\^$-%+=#_&~*\u007F"; Color renderingBackgroundColor = Color.BLACK; Preferences prefs; Renderer renderer; FontData fontData; FontGenerator fontGenerator; HashSet<Character> sampleChars = new HashSet(256); HashSet<Character> remainingSampleChars = new HashSet(256); JScrollPane appliedEffectsScroll; JPanel appliedEffectsPanel; JButton addEffectButton; JTextPane sampleTextPane; JSpinner padAdvanceXSpinner; JList effectsList; JPanel gamePanel; JTextField fontFileText; JRadioButton fontFileRadio; JRadioButton systemFontRadio; JSpinner padBottomSpinner; JSpinner padLeftSpinner; JSpinner padRightSpinner; JSpinner padTopSpinner; JList fontList; JSpinner fontSizeSpinner; DefaultComboBoxModel fontListModel; JLabel backgroundColorLabel; JButton browseButton; JSpinner padAdvanceYSpinner; JCheckBox italicCheckBox; JCheckBox boldCheckBox; JRadioButton vectorRadio; JRadioButton drawStringRadio; JRadioButton freetypeRadio; JComboBox glyphPageHeightCombo; JComboBox glyphPageWidthCombo; JPanel glyphCachePanel; JRadioButton glyphCacheRadio; JRadioButton sampleTextRadio; JButton sampleAsciiButton; JButton sampleNeheButton; DefaultComboBoxModel effectsListModel; JMenuItem openMenuItem; JMenuItem saveMenuItem; JMenuItem exitMenuItem; JMenuItem saveBMFontMenuItem; public Hiero4() { super("Hiero v4.0 - Bitmap Font Tool"); Splash splash = new Splash(this, "/splash.jpg", 2000); initialize(); splash.close(); gamePanel.add(new LwjglCanvas(renderer = new Renderer(), false).getCanvas()); prefs = Preferences.userNodeForPackage(Hiero4.class); java.awt.Color backgroundColor = EffectUtil.fromString(prefs.get("background", "000000")); backgroundColorLabel.setIcon(getColorIcon(backgroundColor)); renderingBackgroundColor = new Color(backgroundColor.getRed() / 255f, backgroundColor.getGreen() / 255f, backgroundColor.getBlue() / 255f, 1); boolean useFontList = getFontFile(Font.decode("Arial")) != null; fontList.setEnabled(useFontList); systemFontRadio.setEnabled(useFontList); fontFileRadio.setSelected(!useFontList); fontFileText.setText(prefs.get("font.file", "")); setVisible(true); } void initialize() { initializeComponents(); initializeMenus(); initializeEvents(); setSize(800, 600); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); sampleNeheButton.doClick(); } void changeFont() { if (renderer.batch == null) return; String path; if (systemFontRadio.isSelected()) { path = getFontFile(Font.decode((String) fontList.getSelectedValue())); } else { path = fontFileText.getText(); } if (path == null) { renderer.font = null; return; } int fontSize = ((Integer) fontSizeSpinner.getValue()).intValue(); try { fontData = new FontData(new File(path), fontSize); } catch (IOException ex) { ex.printStackTrace(); renderer.font = null; return; } sampleChars.clear(); updateFont(true); } void updateFont(boolean force) { if (fontData == null || renderer.batch == null) return; String text = sampleTextPane.getText(); if (!force) { // Don't regenerate font unless the text has new characters or has removed characters. boolean newCharFound = false; remainingSampleChars.clear(); remainingSampleChars.addAll(sampleChars); for (int i = text.length() - 1; i >= 0; i--) { Character ch = text.charAt(i); if (sampleChars.add(ch)) newCharFound = true; remainingSampleChars.remove(ch); } if (!newCharFound && remainingSampleChars.isEmpty()) return; } sampleChars.clear(); for (int i = text.length() - 1; i >= 0; i--) sampleChars.add(text.charAt(i)); int fontSize = ((Integer) fontSizeSpinner.getValue()).intValue(); int style = Font.PLAIN; if (boldCheckBox.isSelected()) { style = Font.BOLD; if (italicCheckBox.isSelected()) style |= Font.ITALIC; } else if (italicCheckBox.isSelected()) // style = Font.ITALIC; fontData = fontData.deriveFont(fontSize, style); int sampleFontSize = sampleTextPane.getFont().getSize(); if (sampleFontSize < 14) sampleFontSize = 14; sampleTextPane.setFont(fontData.getJavaFont().deriveFont((float) sampleFontSize)); Padding padding = new Padding((Integer) padTopSpinner.getValue(), (Integer) padLeftSpinner.getValue(), (Integer) padBottomSpinner.getValue(), (Integer) padRightSpinner.getValue(), (Integer) padAdvanceXSpinner.getValue()); final int width = (Integer) glyphPageWidthCombo.getSelectedItem(); final int height = (Integer) glyphPageHeightCombo.getSelectedItem(); GeneratorMethod method; if (vectorRadio.isSelected()) method = GeneratorMethod.AWT_VECTOR; else if (drawStringRadio.isSelected()) method = GeneratorMethod.AWT_DRAWSTRING; else method = GeneratorMethod.FREETYPE2; fontGenerator = new FontGenerator(fontData, method); CharSet charset = new CharSet(); charset.setManualCharacters(text); try { fontGenerator.generate(width, height, charset, padding, new Effect.Renderer[0], true); final ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 4); buffer.order(ByteOrder.LITTLE_ENDIAN); fontGenerator.getTextureData(buffer.asIntBuffer()); TextureRegion glyphRegion = new TextureRegion(new Texture(new TextureData() { public void load() { GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); } public int getWidth() { return width; } public int getHeight() { return height; } })); fontGenerator.write(new File("out"), ExportFormat.TEXT); renderer.font = new BitmapFont(Gdx.files.absolute("out"), glyphRegion, false); } catch (IOException ex) { ex.printStackTrace(); } } private void initializeEvents() { class FontChangeListener implements ChangeListener, ActionListener { public void stateChanged(ChangeEvent evt) { changeFont(); } public void actionPerformed(ActionEvent evt) { changeFont(); } } FontChangeListener change = new FontChangeListener(); fontFileRadio.addActionListener(change); systemFontRadio.addActionListener(change); fontList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { if (evt.getValueIsAdjusting()) return; prefs.put("system.font", (String) fontList.getSelectedValue()); changeFont(); } }); class FontUpdateListener implements ChangeListener, ActionListener, DocumentListener { private final boolean force; public FontUpdateListener(boolean force) { this.force = force; } public void stateChanged(ChangeEvent evt) { updateFont(force); } public void actionPerformed(ActionEvent evt) { updateFont(force); } public void removeUpdate(DocumentEvent evt) { updateFont(force); } public void insertUpdate(DocumentEvent evt) { updateFont(force); } public void changedUpdate(DocumentEvent evt) { updateFont(force); } public void addSpinners(JSpinner[] spinners) { // Swing sucks. 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)); textField.setCaretPosition(caretPosition); } catch (Throwable ignored) { } } }); } } } FontUpdateListener update = new FontUpdateListener(true); FontUpdateListener updateText = new FontUpdateListener(false); update.addSpinners(new JSpinner[] { padTopSpinner, padRightSpinner, padBottomSpinner, padLeftSpinner, padAdvanceXSpinner, padAdvanceYSpinner }); fontSizeSpinner.addChangeListener(update); glyphPageWidthCombo.addActionListener(update); glyphPageHeightCombo.addActionListener(update); boldCheckBox.addActionListener(update); italicCheckBox.addActionListener(update); vectorRadio.addActionListener(update); drawStringRadio.addActionListener(update); freetypeRadio.addActionListener(update); sampleTextPane.getDocument().addDocumentListener(updateText); 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(true); } }); browseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { FileDialog dialog = new FileDialog(Hiero4.this, "Choose TrueType font file", FileDialog.LOAD); dialog.setLocationRelativeTo(null); dialog.setFile("*.ttf"); dialog.setVisible(true); 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)); } }); saveBMFontMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if (fontGenerator == null) return; FileDialog dialog = new FileDialog(Hiero4.this, "Save BMFont files", FileDialog.SAVE); dialog.setLocationRelativeTo(null); dialog.setFile("*.fnt"); dialog.setVisible(true); String fileName = dialog.getFile(); if (fileName == null) return; try { fontGenerator.write(new File(dialog.getDirectory(), fileName), ExportFormat.TEXT); } catch (IOException ex) { ex.printStackTrace(); } } }); exitMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { dispose(); } }); sampleNeheButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { sampleTextPane.setText(NEHE); } }); sampleAsciiButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { StringBuilder buffer = new StringBuilder(); buffer.append(NEHE); 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()); } }); } private void initializeComponents() { getContentPane().setLayout(new GridBagLayout()); JPanel leftSidePanel = new JPanel(); leftSidePanel.setLayout(new GridBagLayout()); getContentPane().add(leftSidePanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); { JPanel fontPanel = new JPanel(); leftSidePanel.add(fontPanel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); fontPanel.setLayout(new GridBagLayout()); fontPanel.setBorder(BorderFactory.createTitledBorder("Font")); { fontSizeSpinner = new JSpinner(new SpinnerNumberModel(32, 0, 256, 1)); fontPanel.add(fontSizeSpinner, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); ((JSpinner.DefaultEditor) fontSizeSpinner.getEditor()).getTextField().setColumns(2); } { JScrollPane fontScroll = new JScrollPane(); fontPanel.add(fontScroll, new GridBagConstraints(1, 1, 4, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 5, 5), 0, 0)); { fontListModel = new DefaultComboBoxModel( GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()); fontList = new JList(); fontScroll.setViewportView(fontList); fontList.setModel(fontListModel); fontList.setVisibleRowCount(6); fontList.setSelectedIndex(0); fontScroll.setMinimumSize( new Dimension(220, fontList.getPreferredScrollableViewportSize().height)); } } { systemFontRadio = new JRadioButton("System:", true); fontPanel.add(systemFontRadio, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 5), 0, 0)); systemFontRadio.setMargin(new Insets(0, 0, 0, 0)); } { fontFileRadio = new JRadioButton("File:"); fontPanel.add(fontFileRadio, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0)); fontFileRadio.setMargin(new Insets(0, 0, 0, 0)); } { fontFileText = new JTextField(); fontPanel.add(fontFileText, new GridBagConstraints(1, 2, 3, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0)); } { fontPanel.add(new JLabel("Size:"), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { boldCheckBox = new JCheckBox("Bold"); fontPanel.add(boldCheckBox, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { italicCheckBox = new JCheckBox("Italic"); fontPanel.add(italicCheckBox, new GridBagConstraints(3, 3, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { browseButton = new JButton("..."); fontPanel.add(browseButton, new GridBagConstraints(4, 2, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); browseButton.setMargin(new Insets(0, 0, 0, 0)); } { fontPanel.add(new JLabel("Rendering:"), new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { vectorRadio = new JRadioButton("Vector"); fontPanel.add(vectorRadio, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { drawStringRadio = new JRadioButton("DrawString"); fontPanel.add(drawStringRadio, new GridBagConstraints(2, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { freetypeRadio = new JRadioButton("FreeType"); fontPanel.add(freetypeRadio, new GridBagConstraints(3, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); freetypeRadio.setSelected(true); } ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(systemFontRadio); buttonGroup.add(fontFileRadio); buttonGroup = new ButtonGroup(); buttonGroup.add(vectorRadio); buttonGroup.add(drawStringRadio); buttonGroup.add(freetypeRadio); } { JPanel samplePanel = new JPanel(); leftSidePanel.add(samplePanel, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 5, 5), 0, 0)); samplePanel.setLayout(new GridBagLayout()); samplePanel.setBorder(BorderFactory.createTitledBorder("Sample Text")); { JScrollPane textScroll = new JScrollPane(); samplePanel.add(textScroll, new GridBagConstraints(0, 0, 3, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0)); { sampleTextPane = new JTextPane(); textScroll.setViewportView(sampleTextPane); } } { sampleNeheButton = new JButton(); sampleNeheButton.setText("NEHE"); samplePanel.add(sampleNeheButton, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { sampleAsciiButton = new JButton(); sampleAsciiButton.setText("ASCII"); samplePanel.add(sampleAsciiButton, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } } { JPanel renderingPanel = new JPanel(); leftSidePanel.add(renderingPanel, new GridBagConstraints(0, 1, 2, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0)); renderingPanel.setBorder(BorderFactory.createTitledBorder("Rendering")); renderingPanel.setLayout(new GridBagLayout()); { JPanel wrapperPanel = new JPanel(); renderingPanel.add(wrapperPanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0)); wrapperPanel.setLayout(new BorderLayout()); wrapperPanel.setBackground(java.awt.Color.white); { gamePanel = new JPanel(); wrapperPanel.add(gamePanel); gamePanel.setLayout(new BorderLayout()); gamePanel.setBackground(java.awt.Color.white); } } { glyphCachePanel = new JPanel() { private int maxWidth; public Dimension getPreferredSize() { // Keep glyphCachePanel width from ever going down so the CanvasGameContainer doesn't change sizes and flicker. Dimension size = super.getPreferredSize(); maxWidth = Math.max(maxWidth, size.width); size.width = maxWidth; return size; } }; glyphCachePanel.setVisible(false); renderingPanel.add(glyphCachePanel, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); glyphCachePanel.setLayout(new GridBagLayout()); { glyphCachePanel.add(new JLabel("Page width:"), new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0)); } { glyphCachePanel.add(new JLabel("Page height:"), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0)); } { glyphPageWidthCombo = new JComboBox(new DefaultComboBoxModel( new Integer[] { new Integer(32), new Integer(64), new Integer(128), new Integer(256), new Integer(512), new Integer(1024), new Integer(2048) })); glyphCachePanel.add(glyphPageWidthCombo, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); glyphPageWidthCombo.setSelectedIndex(4); } { glyphPageHeightCombo = new JComboBox(new DefaultComboBoxModel( new Integer[] { new Integer(32), new Integer(64), new Integer(128), new Integer(256), new Integer(512), new Integer(1024), new Integer(2048) })); glyphCachePanel.add(glyphPageHeightCombo, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); glyphPageHeightCombo.setSelectedIndex(4); } } { JPanel radioButtonsPanel = new JPanel(); renderingPanel.add(radioButtonsPanel, new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); radioButtonsPanel.setLayout(new GridBagLayout()); { sampleTextRadio = new JRadioButton("Sample text"); radioButtonsPanel.add(sampleTextRadio, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); sampleTextRadio.setSelected(true); } { glyphCacheRadio = new JRadioButton("Glyph cache"); radioButtonsPanel.add(glyphCacheRadio, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } { radioButtonsPanel.add(new JLabel("Background:"), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0)); } { backgroundColorLabel = new JLabel(); radioButtonsPanel.add(backgroundColorLabel, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0)); } ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(glyphCacheRadio); buttonGroup.add(sampleTextRadio); } } JPanel rightSidePanel = new JPanel(); rightSidePanel.setLayout(new GridBagLayout()); getContentPane().add(rightSidePanel, new GridBagConstraints(1, 0, 1, 2, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); { JPanel paddingPanel = new JPanel(); paddingPanel.setLayout(new GridBagLayout()); rightSidePanel.add(paddingPanel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 5, 5), 0, 0)); paddingPanel.setBorder(BorderFactory.createTitledBorder("Padding")); { padTopSpinner = new JSpinner(); paddingPanel.add(padTopSpinner, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); ((JSpinner.DefaultEditor) padTopSpinner.getEditor()).getTextField().setColumns(2); } { padRightSpinner = new JSpinner(); paddingPanel.add(padRightSpinner, new GridBagConstraints(2, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0)); ((JSpinner.DefaultEditor) padRightSpinner.getEditor()).getTextField().setColumns(2); } { padLeftSpinner = new JSpinner(); paddingPanel.add(padLeftSpinner, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0)); ((JSpinner.DefaultEditor) padLeftSpinner.getEditor()).getTextField().setColumns(2); } { padBottomSpinner = new JSpinner(); paddingPanel.add(padBottomSpinner, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); ((JSpinner.DefaultEditor) padBottomSpinner.getEditor()).getTextField().setColumns(2); } { JPanel advancePanel = new JPanel(); FlowLayout advancePanelLayout = new FlowLayout(); advancePanel.setLayout(advancePanelLayout); paddingPanel.add(advancePanel, new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); { advancePanel.add(new JLabel("X:")); } { padAdvanceXSpinner = new JSpinner(); advancePanel.add(padAdvanceXSpinner); ((JSpinner.DefaultEditor) padAdvanceXSpinner.getEditor()).getTextField().setColumns(2); } { advancePanel.add(new JLabel("Y:")); } { padAdvanceYSpinner = new JSpinner(); advancePanel.add(padAdvanceYSpinner); ((JSpinner.DefaultEditor) padAdvanceYSpinner.getEditor()).getTextField().setColumns(2); } } } { JPanel effectsPanel = new JPanel(); effectsPanel.setLayout(new GridBagLayout()); rightSidePanel.add(effectsPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 0, 5, 5), 0, 0)); effectsPanel.setBorder(BorderFactory.createTitledBorder("Effects")); effectsPanel.setMinimumSize(new Dimension(210, 1)); { JScrollPane effectsScroll = new JScrollPane(); effectsPanel.add(effectsScroll, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 5), 0, 0)); { effectsListModel = new DefaultComboBoxModel(); effectsList = new JList(); effectsScroll.setViewportView(effectsList); effectsList.setModel(effectsListModel); effectsList.setVisibleRowCount(6); effectsScroll.setMinimumSize(effectsList.getPreferredScrollableViewportSize()); } } { addEffectButton = new JButton("Add"); effectsPanel.add(addEffectButton, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0, 5, 6, 5), 0, 0)); addEffectButton.setEnabled(false); } { appliedEffectsScroll = new JScrollPane(); effectsPanel.add(appliedEffectsScroll, new GridBagConstraints(1, 3, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0)); appliedEffectsScroll.setBorder(new EmptyBorder(0, 0, 0, 0)); appliedEffectsScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); { JPanel panel = new JPanel(); panel.setLayout(new GridBagLayout()); appliedEffectsScroll.setViewportView(panel); { appliedEffectsPanel = new JPanel(); appliedEffectsPanel.setLayout(new GridBagLayout()); panel.add(appliedEffectsPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); appliedEffectsPanel .setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, java.awt.Color.black)); } } } } } private void initializeMenus() { { JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); { JMenu fileMenu = new JMenu(); menuBar.add(fileMenu); fileMenu.setText("File"); fileMenu.setMnemonic(KeyEvent.VK_F); { openMenuItem = new JMenuItem("Open Hiero settings file..."); openMenuItem.setMnemonic(KeyEvent.VK_O); openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK)); fileMenu.add(openMenuItem); } { saveMenuItem = new JMenuItem("Save Hiero settings file..."); saveMenuItem.setMnemonic(KeyEvent.VK_S); saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK)); fileMenu.add(saveMenuItem); } fileMenu.addSeparator(); { saveBMFontMenuItem = new JMenuItem("Save BMFont files (text)..."); saveBMFontMenuItem.setMnemonic(KeyEvent.VK_B); saveBMFontMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_MASK)); fileMenu.add(saveBMFontMenuItem); } fileMenu.addSeparator(); { exitMenuItem = new JMenuItem("Exit"); exitMenuItem.setMnemonic(KeyEvent.VK_X); fileMenu.add(exitMenuItem); } } } } static Icon getColorIcon(java.awt.Color color) { BufferedImage image = new BufferedImage(32, 16, BufferedImage.TYPE_INT_RGB); java.awt.Graphics g = image.getGraphics(); g.setColor(color); g.fillRect(1, 1, 30, 14); g.setColor(java.awt.Color.black); g.drawRect(0, 0, 31, 15); return new ImageIcon(image); } static private class Splash extends JWindow { final int minMillis; final long startTime; public Splash(Frame frame, String imageFile, int minMillis) { super(frame); this.minMillis = minMillis; getContentPane().add(new JLabel(new ImageIcon(Splash.class.getResource(imageFile))), BorderLayout.CENTER); pack(); setLocationRelativeTo(null); setVisible(true); startTime = System.currentTimeMillis(); } public void close() { final long endTime = System.currentTimeMillis(); new Thread(new Runnable() { public void run() { if (endTime - startTime < minMillis) { addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { dispose(); } }); try { Thread.sleep(minMillis - (endTime - startTime)); } catch (InterruptedException ignored) { } } EventQueue.invokeLater(new Runnable() { public void run() { dispose(); } }); } }, "Splash").start(); } } class Renderer implements ApplicationListener { SpriteBatch batch; BitmapFont font; @Override public void create() { batch = new SpriteBatch(); changeFont(); } @Override public void resize(int width, int height) { batch.getProjectionMatrix().setToOrtho(0, Gdx.graphics.getWidth(), 0, Gdx.graphics.getHeight(), 0, 1); } @Override public void render() { int viewWidth = Gdx.graphics.getWidth(); int viewHeight = Gdx.graphics.getHeight(); BitmapFont font = this.font; if (font == null) { glClearColor(0, 0, 0, 0); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); return; } if (sampleTextRadio.isSelected()) { glClearColor(renderingBackgroundColor.r, renderingBackgroundColor.g, renderingBackgroundColor.b, renderingBackgroundColor.a); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); batch.begin(); font.drawWrapped(batch, sampleTextPane.getText(), 0, viewHeight, viewWidth); batch.end(); } else { glClearColor(1, 1, 1, 1); GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); TextureRegion region = font.getRegion(); float y = viewHeight - region.getRegionHeight(); glColor4f(renderingBackgroundColor.r, renderingBackgroundColor.g, renderingBackgroundColor.b, 0); glBegin(GL_QUADS); glVertex3f(0, y + region.getRegionHeight(), 0); glVertex3f(0, y, 0); glVertex3f(region.getRegionWidth(), y, 0); glVertex3f(region.getRegionWidth(), y + region.getRegionHeight(), 0); glEnd(); batch.begin(); batch.draw(region, 0, y); batch.end(); } } @Override public void pause() { } @Override public void resume() { } @Override public void dispose() { } } static public String getFontFile(Font font) { try { font.getFamily(); // Causes font2DHandle to be set. Field font2DHandleField = Font.class.getDeclaredField("font2DHandle"); font2DHandleField.setAccessible(true); Object font2DHandle = font2DHandleField.get(font); Field font2DField = font2DHandle.getClass().getDeclaredField("font2D"); Object font2D = font2DField.get(font2DHandle); Field platNameField = Class.forName("sun.font.PhysicalFont").getDeclaredField("platName"); platNameField.setAccessible(true); return (String) platNameField.get(font2D); } catch (Exception ex) { return null; } } static public void main(String[] args) throws Exception { LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels(); for (int i = 0, n = lookAndFeels.length; i < n; i++) { if ("Nimbus".equals(lookAndFeels[i].getName())) { try { UIManager.setLookAndFeel(lookAndFeels[i].getClassName()); } catch (Throwable ignored) { } break; } } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new Hiero4(); } }); } }