parent
698d03cd82
commit
4c6fa126d6
|
@ -227,16 +227,17 @@ StarTextures
|
|||
# text on the display screen. To view the list of fonts available with
|
||||
# your distribution of Celestia, look in the fonts directory located
|
||||
# under the Celestia root directory. The default fonts are UTF-8
|
||||
# compatible in order to display non-English characters.
|
||||
# compatible in order to display non-English characters. Font size is
|
||||
# measured in points to ensure the same sizes on all DPI configurations.
|
||||
#
|
||||
# Font: Used to display all informational text.
|
||||
# Default: "sans12.txf"
|
||||
# Default: "DejaVuSans.ttf,9"
|
||||
#
|
||||
# LabelFont: Used to display all label text (objects, locations, etc.).
|
||||
# Default "sans12.txf"
|
||||
# Default "DejaVuSans.ttf,9"
|
||||
#
|
||||
# TitleFont: Used to display object names, messages, and script text.
|
||||
# Default "sansbold20.txf"
|
||||
# Default "DejaVuSans-Bold.ttf,15"
|
||||
#------------------------------------------------------------------------
|
||||
Font "DejaVuSans.ttf,9"
|
||||
LabelFont "DejaVuSans.ttf,9"
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
if(NOT ENABLE_QT)
|
||||
message("Qt frontend is disabled, not building qttxf.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(USE_QT6)
|
||||
message("Qt tools not supported on Qt6, not building cmodview.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(APPLE AND EXISTS /usr/local/opt/qt5)
|
||||
# Homebrew installs Qt5 (up to at least 5.9.1) in
|
||||
# /usr/local/qt5, ensure it can be found by CMake since
|
||||
# it is not in the default /usr/local prefix.
|
||||
list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5")
|
||||
endif()
|
||||
|
||||
set(QT_LIBS Widgets)
|
||||
find_package(Qt5 COMPONENTS ${QT_LIBS} CONFIG REQUIRED)
|
||||
|
||||
# Instruct CMake to run moc automatically when needed
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
# Find includes in corresponding build directories
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
add_executable(qttxf WIN32 main.cpp mainwindow.cpp)
|
||||
install(TARGETS qttxf RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
qt5_use_modules(qttxf ${QT_LIBS})
|
|
@ -1,10 +0,0 @@
|
|||
qttxf is a simple GUI tool for creating bitmap font files for use with
|
||||
Celestia and other applications. The font files are saved in the TXF format
|
||||
introduced by Mark Kilgard in his GLUT toolkit.
|
||||
|
||||
qttxf is Copyright (C) 2009 by Chris Laurel, and is distributed under the
|
||||
terms of the GNU General Public License version 2. Please forward comments
|
||||
and patches to claurel@gmail.com.
|
||||
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// qttxf - a Qt-based application to generate GLUT txf files from
|
||||
// system fonts
|
||||
//
|
||||
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#include <QApplication>
|
||||
#include "mainwindow.h"
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
|
@ -1,391 +0,0 @@
|
|||
// qttxf - a Qt-based application to generate GLUT txf files from
|
||||
// system fonts
|
||||
//
|
||||
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include <QComboBox>
|
||||
#include <QFontComboBox>
|
||||
#include <QScrollArea>
|
||||
#include <QLabel>
|
||||
#include <QFont>
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QFile>
|
||||
#include <QAction>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QPainter>
|
||||
|
||||
// TXF format constants
|
||||
const char* TXF_HEADER_BYTES = "\377txf";
|
||||
const quint32 TXF_ENDIANNESS_TEST = 0x12345678;
|
||||
|
||||
|
||||
MainWindow::MainWindow() :
|
||||
m_scrollArea(nullptr),
|
||||
m_imageWidget(nullptr),
|
||||
m_fontCombo(nullptr),
|
||||
m_sizeCombo(nullptr),
|
||||
m_styleCombo(nullptr),
|
||||
m_saveAction(nullptr)
|
||||
{
|
||||
QWidget *centralWidget = new QWidget();
|
||||
|
||||
QLabel *fontLabel = new QLabel(tr("Font:"));
|
||||
m_fontCombo = new QFontComboBox;
|
||||
QLabel *sizeLabel = new QLabel(tr("Size:"));
|
||||
m_sizeCombo = new QComboBox;
|
||||
QLabel *styleLabel = new QLabel(tr("Style:"));
|
||||
m_styleCombo = new QComboBox;
|
||||
|
||||
m_scrollArea = new QScrollArea();
|
||||
m_imageWidget = new QLabel();
|
||||
|
||||
m_scrollArea->setWidget(m_imageWidget);
|
||||
|
||||
findStyles(m_fontCombo->currentFont());
|
||||
findSizes(m_fontCombo->currentFont());
|
||||
|
||||
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
|
||||
this, SLOT(findStyles(const QFont &)));
|
||||
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
|
||||
this, SLOT(findSizes(const QFont &)));
|
||||
connect(m_fontCombo, SIGNAL(currentFontChanged(const QFont &)),
|
||||
this, SLOT(updateFont(const QFont &)));
|
||||
connect(m_sizeCombo, SIGNAL(currentIndexChanged(const QString &)),
|
||||
this, SLOT(updateSize(const QString &)));
|
||||
connect(m_styleCombo, SIGNAL(currentIndexChanged(const QString &)),
|
||||
this, SLOT(updateStyle(const QString &)));
|
||||
|
||||
QHBoxLayout *controlsLayout = new QHBoxLayout;
|
||||
controlsLayout->addWidget(fontLabel);
|
||||
controlsLayout->addWidget(m_fontCombo, 1);
|
||||
controlsLayout->addWidget(sizeLabel);
|
||||
controlsLayout->addWidget(m_sizeCombo, 1);
|
||||
controlsLayout->addWidget(styleLabel);
|
||||
controlsLayout->addWidget(m_styleCombo, 1);
|
||||
|
||||
QVBoxLayout *centralLayout = new QVBoxLayout();
|
||||
centralLayout->addLayout(controlsLayout);
|
||||
centralLayout->addWidget(m_scrollArea, 1);
|
||||
centralWidget->setLayout(centralLayout);
|
||||
|
||||
setCentralWidget(centralWidget);
|
||||
setWindowTitle("QtTXF");
|
||||
|
||||
QMenuBar* menuBar = new QMenuBar(this);
|
||||
|
||||
QMenu* fileMenu = new QMenu(tr("File"));
|
||||
m_saveAction = new QAction(tr("&Save..."), this);
|
||||
QAction* quitAction = new QAction(tr("&Quit"), this);
|
||||
fileMenu->addAction(m_saveAction);
|
||||
fileMenu->addAction(quitAction);
|
||||
menuBar->addMenu(fileMenu);
|
||||
|
||||
setMenuBar(menuBar);
|
||||
|
||||
m_saveAction->setShortcut(QKeySequence::Save);
|
||||
connect(m_saveAction, SIGNAL(triggered()), this, SLOT(saveFont()));
|
||||
quitAction->setShortcut(QKeySequence("Ctrl+Q"));
|
||||
connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
|
||||
|
||||
buildTxf();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::findStyles(const QFont &font)
|
||||
{
|
||||
QFontDatabase fontDatabase;
|
||||
QString currentItem = m_styleCombo->currentText();
|
||||
m_styleCombo->clear();
|
||||
|
||||
QString style;
|
||||
foreach (style, fontDatabase.styles(font.family()))
|
||||
{
|
||||
m_styleCombo->addItem(style);
|
||||
}
|
||||
|
||||
int styleIndex = m_styleCombo->findText(currentItem);
|
||||
|
||||
if (styleIndex == -1)
|
||||
m_styleCombo->setCurrentIndex(0);
|
||||
else
|
||||
m_styleCombo->setCurrentIndex(styleIndex);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::findSizes(const QFont &font)
|
||||
{
|
||||
QFontDatabase fontDatabase;
|
||||
QString currentSize = m_sizeCombo->currentText();
|
||||
m_sizeCombo->blockSignals(true);
|
||||
m_sizeCombo->clear();
|
||||
|
||||
int size;
|
||||
if (fontDatabase.isSmoothlyScalable(font.family(), fontDatabase.styleString(font)))
|
||||
{
|
||||
foreach(size, QFontDatabase::standardSizes())
|
||||
{
|
||||
m_sizeCombo->addItem(QVariant(size).toString());
|
||||
m_sizeCombo->setEditable(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (size, fontDatabase.smoothSizes(font.family(), fontDatabase.styleString(font)))
|
||||
{
|
||||
m_sizeCombo->addItem(QVariant(size).toString());
|
||||
m_sizeCombo->setEditable(false);
|
||||
}
|
||||
}
|
||||
|
||||
m_sizeCombo->blockSignals(false);
|
||||
|
||||
int sizeIndex = m_sizeCombo->findText(currentSize);
|
||||
if (sizeIndex == -1)
|
||||
{
|
||||
m_sizeCombo->setCurrentIndex(qMax(0, m_sizeCombo->count() / 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sizeCombo->setCurrentIndex(sizeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::updateFont(const QFont& font)
|
||||
{
|
||||
qDebug() << font.family() << " match: " << font.exactMatch();
|
||||
m_currentFont.setFamily(font.family());
|
||||
buildTxf();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::updateSize(const QString& sizeString)
|
||||
{
|
||||
m_currentFont.setPointSize(sizeString.toInt());
|
||||
buildTxf();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::updateStyle(const QString& /* styleName */)
|
||||
{
|
||||
buildTxf();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::saveFont()
|
||||
{
|
||||
if (!m_fontData.isEmpty())
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this,
|
||||
tr("Save Font File"),
|
||||
"",
|
||||
tr("Texture Fonts (*.txf)"));
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("File Error"), tr("Error writing to %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream out(&file);
|
||||
out.writeRawData(m_fontData.data(), m_fontData.length());
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct BasicGlyphInfo
|
||||
{
|
||||
QChar ch;
|
||||
int height;
|
||||
};
|
||||
|
||||
bool operator<(const BasicGlyphInfo& info0, const BasicGlyphInfo& info1)
|
||||
{
|
||||
return info0.height > info1.height;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MainWindow::buildTxf()
|
||||
{
|
||||
// Build a txf font from the current system font. Attempt to fit it into a 128x128
|
||||
// texture, progressively increasing the texture size until it fits.
|
||||
bool fitsInTexture = false;
|
||||
int textureWidth = 128;
|
||||
int textureHeight = 128;
|
||||
|
||||
while (textureWidth <= 1024 && !fitsInTexture)
|
||||
{
|
||||
m_fontData.clear();
|
||||
QDataStream out(&m_fontData, QIODevice::WriteOnly);
|
||||
if (buildTxf(m_currentFont, out, textureWidth, textureHeight))
|
||||
{
|
||||
fitsInTexture = true;
|
||||
}
|
||||
|
||||
if (textureWidth == textureHeight)
|
||||
textureWidth *= 2;
|
||||
else
|
||||
textureHeight *= 2;
|
||||
}
|
||||
|
||||
if (!fitsInTexture)
|
||||
{
|
||||
QMessageBox::warning(this,
|
||||
tr("Font Error"),
|
||||
tr("Font is too large to fit in texture"));
|
||||
m_fontData.clear();
|
||||
}
|
||||
|
||||
m_saveAction->setEnabled(fitsInTexture);
|
||||
|
||||
return fitsInTexture;
|
||||
}
|
||||
|
||||
|
||||
QString characterRange(unsigned int firstChar, unsigned int lastChar)
|
||||
{
|
||||
QString s;
|
||||
for (unsigned int i = firstChar; i <= lastChar; ++i)
|
||||
{
|
||||
s += QChar(i);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MainWindow::buildTxf(const QFont& font, QDataStream& out, int texWidth, int texHeight)
|
||||
{
|
||||
QString charset;
|
||||
|
||||
charset += characterRange(0x0020, 0x007e); // ASCII
|
||||
charset += characterRange(0x00a0, 0x00ff); // Latin-1 supplement
|
||||
charset += characterRange(0x0100, 0x017f); // Latin Extended-A
|
||||
charset += characterRange(0x0391, 0x03ce); // Greek
|
||||
|
||||
QPixmap pixmap(texWidth, texHeight);
|
||||
QPainter painter(&pixmap);
|
||||
|
||||
QVector<BasicGlyphInfo> glyphInfoList;
|
||||
|
||||
QFont devFont(font, &pixmap);
|
||||
QFontMetrics fm(devFont);
|
||||
for (int i = 0; i < charset.length(); i++)
|
||||
{
|
||||
QChar ch = charset[i];
|
||||
if (fm.inFont(ch))
|
||||
{
|
||||
BasicGlyphInfo info;
|
||||
info.ch = ch;
|
||||
info.height = fm.boundingRect(ch).height();
|
||||
glyphInfoList << info;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the glyphs by height so that they pack more compactly
|
||||
// into the available space.
|
||||
std::sort(glyphInfoList.begin(), glyphInfoList.end());
|
||||
|
||||
if (glyphInfoList.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write txf file header
|
||||
int maxAscent = 0;
|
||||
int maxDescent = 0;
|
||||
out.writeRawData(TXF_HEADER_BYTES, 4);
|
||||
out << TXF_ENDIANNESS_TEST;
|
||||
out << (quint32) 0;
|
||||
out << (quint32) texWidth << (quint32) texHeight;
|
||||
out << (quint32) maxAscent << (quint32) maxDescent;
|
||||
out << (quint32) glyphInfoList.size();
|
||||
|
||||
// Clear the image
|
||||
painter.fillRect(0, 0, texWidth, texHeight, Qt::black);
|
||||
|
||||
int rowHeight = glyphInfoList.first().height;
|
||||
int x = 1;
|
||||
int y = rowHeight;
|
||||
int xSpacing = 3;
|
||||
int ySpacing = 3;
|
||||
|
||||
painter.setFont(devFont);
|
||||
foreach (BasicGlyphInfo info, glyphInfoList)
|
||||
{
|
||||
QRect bounds = fm.boundingRect(info.ch);
|
||||
if (x + bounds.width() >= texWidth)
|
||||
{
|
||||
y += rowHeight + ySpacing;
|
||||
rowHeight = bounds.height();
|
||||
x = 1;
|
||||
|
||||
if (y >= texHeight)
|
||||
{
|
||||
qDebug() << "Not enough room in font glyph texture.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
painter.setPen(Qt::white);
|
||||
painter.drawText(x - bounds.left(), y - bounds.bottom(), QString(info.ch));
|
||||
|
||||
#if 0
|
||||
// Show bounding rectangles for debugging
|
||||
painter.setPen(Qt::red);
|
||||
QRect glyphRect = bounds;
|
||||
glyphRect.translate(x - bounds.left(), y - bounds.bottom());
|
||||
painter.drawRect(glyphRect);
|
||||
#endif
|
||||
|
||||
// Write out the glyph record;
|
||||
out << (quint16) info.ch.unicode();
|
||||
out << (quint8) (bounds.width() + 2) << (quint8) (bounds.height() + 2);
|
||||
out << (qint8) bounds.left() << (qint8) (-bounds.bottom());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
|
||||
out << (qint8) fm.horizontalAdvance(info.ch);
|
||||
#else
|
||||
out << (qint8) fm.width(info.ch);
|
||||
#endif
|
||||
out << (quint8) 0; /* unused */
|
||||
out << (quint16) (x - 1) << (quint16) (texHeight - y - 2);
|
||||
|
||||
x += bounds.width() + xSpacing;
|
||||
}
|
||||
|
||||
// Write out the glyph texture map
|
||||
QImage glyphImage = pixmap.toImage();
|
||||
for (int iy = 0; iy < texHeight; iy++)
|
||||
{
|
||||
for (int ix = 0; ix < texWidth; ix++)
|
||||
{
|
||||
QRgb rgb = glyphImage.pixel(ix, texHeight - iy - 1);
|
||||
out << (quint8) qGreen(rgb);
|
||||
}
|
||||
}
|
||||
|
||||
QLabel* label = new QLabel(m_scrollArea);
|
||||
label->setPixmap(pixmap);
|
||||
m_scrollArea->setWidget(label);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
// qttxf - a Qt-based application to generate GLUT txf files from
|
||||
// system fonts
|
||||
//
|
||||
// Copyright (C) 2009, Chris Laurel <claurel@gmail.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
|
||||
#ifndef _QTTXF_MAINWINDOW_H_
|
||||
#define _QTTXF_MAINWINDOW_H_
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QString>
|
||||
|
||||
class QComboBox;
|
||||
class QFontComboBox;
|
||||
class QScrollArea;
|
||||
class QLabel;
|
||||
class QFont;
|
||||
class QDataStream;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
bool buildTxf();
|
||||
bool buildTxf(const QFont& font, QDataStream& out, int texWidth, int texHeight);
|
||||
|
||||
public slots:
|
||||
void findStyles(const QFont& font);
|
||||
void findSizes(const QFont& font);
|
||||
void updateFont(const QFont& font);
|
||||
void updateSize(const QString& sizeString);
|
||||
void updateStyle(const QString& styleName);
|
||||
void saveFont();
|
||||
|
||||
private:
|
||||
QScrollArea *m_scrollArea;
|
||||
QLabel* m_imageWidget;
|
||||
QFontComboBox* m_fontCombo;
|
||||
QComboBox* m_sizeCombo;
|
||||
QComboBox* m_styleCombo;
|
||||
QAction* m_saveAction;
|
||||
QFont m_currentFont;
|
||||
QByteArray m_fontData;
|
||||
};
|
||||
|
||||
#endif // _QTTXF_MAINWINDOW_H_
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
TEMPLATE = app
|
||||
TARGET = qttxf
|
||||
|
||||
QT += widgets
|
||||
|
||||
DESTDIR = build
|
||||
OBJECTS_DIR = build
|
||||
MOC_DIR = build
|
||||
|
||||
HEADERS = \
|
||||
mainwindow.h
|
||||
|
||||
SOURCES = \
|
||||
mainwindow.cpp \
|
||||
main.cpp
|
Loading…
Reference in New Issue