mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 10:22:52 +01:00
rwviewer: view stored texts + fonts
This commit is contained in:
parent
ee455bb157
commit
6d4b69b742
@ -68,9 +68,9 @@ RWGame::RWGame(Logger& log, int argc, char* argv[])
|
||||
}
|
||||
|
||||
// Set up text renderer
|
||||
renderer.text.setFontTexture(0, "pager");
|
||||
renderer.text.setFontTexture(1, "font1");
|
||||
renderer.text.setFontTexture(2, "font2");
|
||||
renderer.text.setFontTexture(FONT_PAGER, "pager");
|
||||
renderer.text.setFontTexture(FONT_PRICEDOWN, "font1");
|
||||
renderer.text.setFontTexture(FONT_ARIAL, "font2");
|
||||
|
||||
debug.setDebugMode(btIDebugDraw::DBG_DrawWireframe |
|
||||
btIDebugDraw::DBG_DrawConstraints |
|
||||
|
@ -6,23 +6,43 @@ find_package(Qt5Widgets REQUIRED)
|
||||
|
||||
add_executable(rwviewer WIN32
|
||||
main.cpp
|
||||
OpenGLCompat.h
|
||||
|
||||
ViewerWindow.hpp
|
||||
ViewerWindow.cpp
|
||||
|
||||
models/ObjectListModel.hpp
|
||||
models/ObjectListModel.cpp
|
||||
models/DFFFramesTreeModel.hpp
|
||||
models/DFFFramesTreeModel.cpp
|
||||
models/TextModel.hpp
|
||||
models/TextModel.cpp
|
||||
|
||||
views/ViewerInterface.hpp
|
||||
views/ObjectViewer.hpp
|
||||
views/ObjectViewer.cpp
|
||||
views/ModelViewer.hpp
|
||||
views/ModelViewer.cpp
|
||||
views/TextViewer.hpp
|
||||
views/TextViewer.cpp
|
||||
views/WorldViewer.hpp
|
||||
views/WorldViewer.cpp
|
||||
views/ViewerInterface.hpp
|
||||
views/ViewerInterface.cpp
|
||||
|
||||
ViewerWidget.cpp
|
||||
ViewerWidget.hpp
|
||||
ItemListModel.hpp
|
||||
ItemListModel.cpp
|
||||
ItemListWidget.hpp
|
||||
ItemListWidget.cpp
|
||||
IMGArchiveModel.hpp
|
||||
IMGArchiveModel.cpp
|
||||
widgets/ModelFramesWidget.hpp
|
||||
widgets/ModelFramesWidget.cpp
|
||||
AnimationListModel.hpp
|
||||
AnimationListModel.cpp
|
||||
AnimationListWidget.hpp
|
||||
AnimationListWidget.cpp
|
||||
)
|
||||
|
||||
|
@ -2,12 +2,15 @@
|
||||
#include <QFileDialog>
|
||||
#include <QMouseEvent>
|
||||
#include <engine/Animator.hpp>
|
||||
#include <engine/GameData.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <objects/CharacterObject.hpp>
|
||||
#include <objects/InstanceObject.hpp>
|
||||
#include <objects/VehicleObject.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <render/ObjectRenderer.hpp>
|
||||
#include <render/TextRenderer.hpp>
|
||||
|
||||
constexpr float kViewFov = glm::radians(90.0f);
|
||||
|
||||
@ -32,6 +35,7 @@ ViewCamera OrbitCamera (const glm::vec2& viewPort, const glm::vec2& viewAngles,
|
||||
ViewerWidget::ViewerWidget(QOpenGLContext* context, QWindow* parent)
|
||||
: QWindow(parent)
|
||||
, context(context)
|
||||
, textInfos()
|
||||
, selectedFrame(nullptr)
|
||||
, viewDistance(1.f)
|
||||
, dragging(false)
|
||||
@ -127,6 +131,13 @@ void ViewerWidget::drawWorld(GameRenderer& r) {
|
||||
r.renderWorld(world(), vc, 0.f);
|
||||
}
|
||||
|
||||
void ViewerWidget::drawText(GameRenderer& r) {
|
||||
for(auto &textInfo : textInfos) {
|
||||
_renderer->text.renderText(textInfo, false);
|
||||
}
|
||||
r.renderPostProcess();
|
||||
}
|
||||
|
||||
void ViewerWidget::paintGL() {
|
||||
glViewport(0, 0, width() * devicePixelRatio(), height() * devicePixelRatio());
|
||||
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
|
||||
@ -141,7 +152,6 @@ void ViewerWidget::paintGL() {
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
|
||||
r.getRenderer()->invalidate();
|
||||
r.setupRender();
|
||||
|
||||
@ -155,6 +165,9 @@ void ViewerWidget::paintGL() {
|
||||
case Mode::World:
|
||||
drawWorld(r);
|
||||
break;
|
||||
case Mode::Text:
|
||||
drawText(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +241,18 @@ void ViewerWidget::showObject(quint16 item) {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWidget::clearText() {
|
||||
textInfos.clear();
|
||||
}
|
||||
|
||||
void ViewerWidget::showText(const TextRenderer::TextInfo &ti) {
|
||||
textInfos.push_back(ti);
|
||||
}
|
||||
|
||||
void ViewerWidget::showModel(ClumpPtr model) {
|
||||
_viewMode = Mode::Model;
|
||||
_model = model;
|
||||
textInfos.clear();
|
||||
}
|
||||
|
||||
void ViewerWidget::selectFrame(ModelFrame* frame) {
|
||||
@ -248,7 +270,7 @@ void ViewerWidget::exportModel() {
|
||||
if( it != world()->objectTypes.end() ) {
|
||||
for( auto& archive : world()->data.archives ) {
|
||||
for(size_t i = 0; i < archive.second.getAssetCount(); ++i) {
|
||||
auto& assetI = archive.second.getAssetInfoByIndex(i);
|
||||
auto& assetI = archive.second.getAssetInfoByIndex(i);;
|
||||
std::string q(assetI.name);
|
||||
std::transform(q.begin(), q.end(), q.begin(), ::tolower);
|
||||
if( q.find(it->second->modelName) != q.npos ) {
|
||||
|
@ -6,8 +6,9 @@
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <gl/DrawBuffer.hpp>
|
||||
#include <gl/GeometryBuffer.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <loaders/LoaderIFP.hpp>
|
||||
#include <render/TextRenderer.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// Prevent Qt from conflicting with glLoadGen on macOS
|
||||
#include "OpenGLCompat.h"
|
||||
@ -16,6 +17,7 @@
|
||||
|
||||
class GameRenderer;
|
||||
class Clump;
|
||||
|
||||
class ViewerWidget : public QWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -26,6 +28,8 @@ public:
|
||||
Model,
|
||||
//! View loaded instances, \see showWorld();
|
||||
World,
|
||||
//! View text strings, \see showText
|
||||
Text,
|
||||
};
|
||||
|
||||
ViewerWidget(QOpenGLContext* context, QWindow* parent);
|
||||
@ -54,6 +58,8 @@ public:
|
||||
public slots:
|
||||
void showObject(quint16 item);
|
||||
void showModel(ClumpPtr model);
|
||||
void clearText();
|
||||
void showText(const TextRenderer::TextInfo &ti);
|
||||
void selectFrame(ModelFrame* frame);
|
||||
void exportModel();
|
||||
|
||||
@ -78,6 +84,7 @@ protected:
|
||||
GameWorld* _world = nullptr;
|
||||
GameRenderer* _renderer = nullptr;
|
||||
|
||||
std::vector<TextRenderer::TextInfo> textInfos;
|
||||
ClumpPtr _model;
|
||||
ModelFrame* selectedFrame = nullptr;
|
||||
GameObject* _object = nullptr;
|
||||
@ -103,6 +110,7 @@ protected:
|
||||
void drawModel(GameRenderer& r, ClumpPtr& model);
|
||||
void drawObject(GameRenderer& r, GameObject* object);
|
||||
void drawWorld(GameRenderer& r);
|
||||
void drawText(GameRenderer& r);
|
||||
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "views/ModelViewer.hpp"
|
||||
#include "views/ObjectViewer.hpp"
|
||||
#include "views/WorldViewer.hpp"
|
||||
#include "views/TextViewer.hpp"
|
||||
|
||||
#include <engine/GameState.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
@ -42,14 +43,17 @@ void ViewerWindow::createMenus() {
|
||||
for (int i = 0; i < MaxRecentGames; ++i) {
|
||||
QAction* r = file->addAction("");
|
||||
recentGames.append(r);
|
||||
connect(r, SIGNAL(triggered()), SLOT(openRecent()));
|
||||
connect(r, &QAction::triggered, this, [r, this]() {
|
||||
QString recentGame = r->data().toString();
|
||||
loadGame(recentGame);
|
||||
});
|
||||
}
|
||||
|
||||
recentSep = file->addSeparator();
|
||||
auto ex = file->addAction("E&xit");
|
||||
ex->setShortcut(QKeySequence::Quit);
|
||||
connect(ex, SIGNAL(triggered()), QApplication::instance(),
|
||||
SLOT(closeAllWindows()));
|
||||
connect(ex, &QAction::triggered,
|
||||
QApplication::instance(), &QApplication::closeAllWindows);
|
||||
|
||||
mb->addMenu("&Data");
|
||||
|
||||
@ -94,6 +98,10 @@ void ViewerWindow::createDefaultViews() {
|
||||
views->addTab(worldView, "World");
|
||||
connect(this, &ViewerWindow::gameLoaded, worldView, &WorldViewer::showData);
|
||||
|
||||
auto textView = new TextViewer(this);
|
||||
views->addTab(textView, "Texts");
|
||||
connect(this, &ViewerWindow::gameLoaded, textView, &TextViewer::showData);
|
||||
|
||||
setCentralWidget(views);
|
||||
}
|
||||
|
||||
@ -143,6 +151,10 @@ void ViewerWindow::loadGame(const QString& path) {
|
||||
|
||||
gameWorld->data->load();
|
||||
|
||||
renderer->text.setFontTexture(FONT_PAGER, "pager");
|
||||
renderer->text.setFontTexture(FONT_PRICEDOWN, "font1");
|
||||
renderer->text.setFontTexture(FONT_ARIAL, "font2");
|
||||
|
||||
gameLoaded(gameWorld.get(), renderer.get());
|
||||
|
||||
QSettings settings("OpenRW", "rwviewer");
|
||||
@ -155,13 +167,6 @@ void ViewerWindow::loadGame(const QString& path) {
|
||||
updateRecentGames();
|
||||
}
|
||||
|
||||
void ViewerWindow::openRecent() {
|
||||
QAction* r = qobject_cast<QAction*>(sender());
|
||||
if (r) {
|
||||
loadGame(r->data().toString());
|
||||
}
|
||||
}
|
||||
|
||||
void ViewerWindow::showObjectModel(uint16_t) {
|
||||
#pragma message("implement me")
|
||||
}
|
||||
|
@ -49,7 +49,6 @@ signals:
|
||||
void gameLoaded(GameWorld*, GameRenderer*);
|
||||
|
||||
private slots:
|
||||
void openRecent();
|
||||
void showObjectModel(uint16_t object);
|
||||
|
||||
private:
|
||||
|
76
rwviewer/models/TextModel.cpp
Normal file
76
rwviewer/models/TextModel.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include "TextModel.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include <QBrush>
|
||||
|
||||
TextModel::TextModel(QObject *parent)
|
||||
: QAbstractTableModel(parent), m_font(FONT_PAGER) {
|
||||
|
||||
}
|
||||
|
||||
void TextModel::setData(const TextMapType &textMap) {
|
||||
beginResetModel();
|
||||
m_textMap = textMap;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int TextModel::rowCount(const QModelIndex &) const {
|
||||
return m_textMap.keys.size();
|
||||
}
|
||||
|
||||
int TextModel::columnCount(const QModelIndex &) const {
|
||||
return m_textMap.languages.size();
|
||||
}
|
||||
|
||||
const GameString &TextModel::lookupIndex(const QModelIndex &index) const {
|
||||
const auto &language = m_textMap.languages.at(index.column());
|
||||
const auto &key = m_textMap.keys.at(index.row());
|
||||
return m_textMap.map_lang_key_tran.at(language).at(key);
|
||||
}
|
||||
|
||||
QVariant TextModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
try {
|
||||
const auto &gameText = this->lookupIndex(index);
|
||||
auto gameString = GameStringUtil::toString(gameText, m_font);
|
||||
return QString::fromStdString(gameString);
|
||||
} catch (const std::out_of_range &) {
|
||||
return QVariant::Invalid;
|
||||
} catch (...) {
|
||||
throw;
|
||||
}
|
||||
case Qt::BackgroundRole:
|
||||
try {
|
||||
this->lookupIndex(index);
|
||||
return QVariant::Invalid;
|
||||
} catch (const std::out_of_range &) {
|
||||
return QBrush(Qt::red);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return QVariant::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
QVariant TextModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal:
|
||||
return QString::fromStdString(m_textMap.languages[section]);
|
||||
case Qt::Vertical:
|
||||
return QString::fromStdString(m_textMap.keys[section]);
|
||||
default:
|
||||
return QVariant::Invalid;
|
||||
}
|
||||
default:
|
||||
return QVariant::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
void TextModel::fontChanged(font_t font) {
|
||||
beginResetModel();
|
||||
m_font = font;
|
||||
endResetModel();
|
||||
}
|
35
rwviewer/models/TextModel.hpp
Normal file
35
rwviewer/models/TextModel.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef _TEXTMODEL_HPP_
|
||||
#define _TEXTMODEL_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
#include <fonts/GameTexts.hpp>
|
||||
|
||||
struct TextMapType {
|
||||
std::vector<std::string> languages;
|
||||
std::vector<std::string> keys;
|
||||
std::map<std::string, std::map<std::string, GameString>> map_lang_key_tran;
|
||||
};
|
||||
|
||||
class TextModel : public QAbstractTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TextModel(QObject *parent = nullptr);
|
||||
void setData(const TextMapType &textMap);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
const GameString &lookupIndex(const QModelIndex &index) const;
|
||||
public slots:
|
||||
void fontChanged(font_t font);
|
||||
private:
|
||||
font_t m_font;
|
||||
TextMapType m_textMap;
|
||||
};
|
||||
|
||||
#endif
|
251
rwviewer/views/TextViewer.cpp
Normal file
251
rwviewer/views/TextViewer.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
#include "TextViewer.hpp"
|
||||
|
||||
#include <render/TextRenderer.hpp>
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include <fonts/GameTexts.hpp>
|
||||
#include <loaders/LoaderGXT.hpp>
|
||||
#include <models/TextModel.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QItemSelection>
|
||||
#include <QLineEdit>
|
||||
#include <QModelIndex>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
#include <QRegExp>
|
||||
#include <QRegExpValidator>
|
||||
#include <QSpinBox>
|
||||
#include <QSplitter>
|
||||
#include <QTableView>
|
||||
#include <QTextEdit>
|
||||
|
||||
void TextTableView::selectionChanged(const QItemSelection &selected, const QItemSelection &) {
|
||||
if (!selected.size())
|
||||
return;
|
||||
auto index = selected.indexes()[0];
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
auto *textModel = dynamic_cast<TextModel *>(this->model());
|
||||
if (!textModel) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
auto gameString = textModel->lookupIndex(index);
|
||||
emit gameStringChanged(gameString);
|
||||
} catch (std::out_of_range &) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TextViewer::TextViewer(QWidget* parent, Qt::WindowFlags f)
|
||||
: ViewerInterface(parent, f) {
|
||||
|
||||
auto dataLayout = new QVBoxLayout;
|
||||
|
||||
auto splitter = new QSplitter;
|
||||
splitter->setChildrenCollapsible(false);
|
||||
splitter->setOrientation(Qt::Horizontal);
|
||||
|
||||
viewerWidget = createViewer();
|
||||
|
||||
textModel = new TextModel;
|
||||
textTable = new TextTableView;
|
||||
textTable->setModel(textModel);
|
||||
textTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
connect(textTable, &TextTableView::gameStringChanged, this, &TextViewer::onGameStringChange);
|
||||
dataLayout->addWidget(textTable);
|
||||
|
||||
auto propLayout = new QHBoxLayout;
|
||||
|
||||
connect(this, &TextViewer::fontChanged, this, &TextViewer::onFontChange);
|
||||
auto groupBox = new QGroupBox;
|
||||
auto *groupBoxLayout = new QHBoxLayout;
|
||||
auto *radioFont1 = new QRadioButton(tr("Pager"));
|
||||
connect(radioFont1, &QRadioButton::clicked, [this]() {emit fontChanged(FONT_PAGER);});
|
||||
groupBoxLayout->addWidget(radioFont1);
|
||||
auto *radioFont2 = new QRadioButton(tr("Pricedown"));
|
||||
connect(radioFont2, &QRadioButton::clicked, [this]() {emit fontChanged(FONT_PRICEDOWN);});
|
||||
groupBoxLayout->addWidget(radioFont2);
|
||||
auto *radioFont3 = new QRadioButton(tr("Arial"));
|
||||
connect(radioFont3, &QRadioButton::clicked, [this]() {emit fontChanged(FONT_ARIAL);});
|
||||
groupBoxLayout->addWidget(radioFont3);
|
||||
groupBox->setLayout(groupBoxLayout);
|
||||
groupBox->setProperty("border", "2px solid gray");
|
||||
propLayout->addWidget(groupBox);
|
||||
|
||||
radioFont1->click();
|
||||
|
||||
auto textSizeLayout = new QFormLayout;
|
||||
auto textSizeSpinBox = new QSpinBox;
|
||||
textSizeSpinBox->setMinimum(1);
|
||||
textSizeSpinBox->setMaximum(50);
|
||||
connect(textSizeSpinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TextViewer::onFontSizeChange);
|
||||
textSizeSpinBox->setValue(20);
|
||||
textSizeLayout->addRow(tr("Font size"), textSizeSpinBox);
|
||||
propLayout->addLayout(textSizeLayout);
|
||||
|
||||
propLayout->addStretch();
|
||||
dataLayout->addLayout(propLayout);
|
||||
|
||||
hexLineEdit = new QLineEdit;
|
||||
hexLineEdit->setReadOnly(true);
|
||||
hexLineEdit->setValidator(new QRegExpValidator(QRegExp("[0-9A-F]*")));
|
||||
dataLayout->addWidget(hexLineEdit);
|
||||
|
||||
textEdit = new QTextEdit;
|
||||
dataLayout->addWidget(textEdit);
|
||||
|
||||
auto dataWidget = new QWidget;
|
||||
dataWidget->setLayout(dataLayout);
|
||||
splitter->addWidget(dataWidget);
|
||||
|
||||
viewerWidget->setMode(ViewerWidget::Mode::Text);
|
||||
splitter->addWidget(QWidget::createWindowContainer(viewerWidget));
|
||||
|
||||
auto mainLayout = new QHBoxLayout;
|
||||
mainLayout->addWidget(splitter);
|
||||
setLayout(mainLayout);
|
||||
|
||||
connect(textSizeSpinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &TextViewer::onFontSizeChange);
|
||||
connect(textEdit, &QTextEdit::textChanged, this, &TextViewer::onStringChange);
|
||||
}
|
||||
|
||||
void TextViewer::onFontChange(font_t font) {
|
||||
currentFont = font;
|
||||
emit textModel->fontChanged(font);
|
||||
updateRender();
|
||||
}
|
||||
|
||||
void TextViewer::onFontSizeChange(int size) {
|
||||
currentFontSize = size;
|
||||
updateRender();
|
||||
}
|
||||
|
||||
void TextViewer::onStringChange() {
|
||||
auto string = textEdit->toPlainText();
|
||||
auto newGameString = GameStringUtil::fromString(string.toStdString(), currentFont);
|
||||
onGameStringChange(newGameString);
|
||||
}
|
||||
|
||||
void TextViewer::onGameStringChange(const GameString &gameString) {
|
||||
if (!currentGameString.compare(gameString)) {
|
||||
return;
|
||||
}
|
||||
currentGameString = gameString;
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::hex;
|
||||
for (auto c : gameString) {
|
||||
oss << std::setw(sizeof(gameString[0])) << std::setfill('0')
|
||||
<< int(c) << " ";
|
||||
}
|
||||
auto newHexText = QString::fromStdString(oss.str());
|
||||
if (hexLineEdit->text().compare(newHexText)) {
|
||||
hexLineEdit->setText(newHexText);
|
||||
}
|
||||
auto newText = QString::fromStdString(GameStringUtil::toString(gameString, currentFont));
|
||||
if (textEdit->toPlainText().compare(newText)) {
|
||||
textEdit->setText(newText);
|
||||
}
|
||||
|
||||
updateRender();
|
||||
}
|
||||
|
||||
void TextViewer::updateRender() {
|
||||
viewerWidget->clearText();
|
||||
const int ROW_STRIDE = currentFontSize * 1.2;
|
||||
const int COL_STRIDE = currentFontSize * 1.2;
|
||||
{
|
||||
TextRenderer::TextInfo ti;
|
||||
ti.font = currentFont;
|
||||
ti.size = currentFontSize;
|
||||
ti.baseColour = glm::u8vec3(255);
|
||||
ti.backgroundColour = glm::u8vec4(0, 0, 0, 0);
|
||||
ti.align = TextRenderer::TextInfo::TextAlignment::Left;
|
||||
ti.wrapX = 0;
|
||||
|
||||
ti.text = currentGameString;
|
||||
ti.screenPosition = glm::vec2(10, 10);
|
||||
viewerWidget->showText(ti);
|
||||
}
|
||||
|
||||
{
|
||||
TextRenderer::TextInfo ti;
|
||||
ti.font = currentFont;
|
||||
ti.size = currentFontSize;
|
||||
ti.baseColour = glm::u8vec3(255);
|
||||
ti.backgroundColour = glm::u8vec4(0, 0, 0, 0);
|
||||
ti.align = TextRenderer::TextInfo::TextAlignment::Left;
|
||||
ti.wrapX = 0;
|
||||
|
||||
for(GameStringChar c=0x20; c<0xb2; ++c) {
|
||||
unsigned column = c % 0x10;
|
||||
unsigned row = (c / 0x10) - 2 + 3; /* +3 to offset first line*/
|
||||
ti.text = c;
|
||||
ti.screenPosition = glm::vec2(10 + (column * COL_STRIDE), 10 + (row * ROW_STRIDE));
|
||||
viewerWidget->showText(ti);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextViewer::worldChanged() {
|
||||
auto textNames = getFontTextureNames();
|
||||
TextMapType textMap;
|
||||
LoaderGXT loader;
|
||||
std::set<std::string> keys;
|
||||
for(const auto &textName : textNames) {
|
||||
GameTexts texts;
|
||||
auto handle = world()->data->index.openFile(textName);
|
||||
loader.load(texts, handle);
|
||||
const auto &language = textName;
|
||||
textMap.languages.push_back(language);
|
||||
const auto &stringTable = texts.getStringTable();
|
||||
for (const auto &tableItem : stringTable) {
|
||||
keys.insert(tableItem.first);
|
||||
textMap.map_lang_key_tran[language][tableItem.first] = tableItem.second;
|
||||
}
|
||||
}
|
||||
textMap.keys.resize(keys.size());
|
||||
std::move(keys.begin(), keys.end(), textMap.keys.begin());
|
||||
|
||||
textModel->setData(textMap);
|
||||
}
|
||||
|
||||
std::vector<std::string> TextViewer::getFontTextureNames() {
|
||||
const auto &gameDataPath = rwfs::path(world()->data->getDataPath());
|
||||
rwfs::path textPath;
|
||||
for (const rwfs::path &p : rwfs::directory_iterator(gameDataPath)) {
|
||||
if (!rwfs::is_directory(p)) {
|
||||
continue;
|
||||
}
|
||||
std::string filename = p.filename().string();
|
||||
std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower);
|
||||
if (!filename.compare("text")) {
|
||||
textPath = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!textPath.string().length()) {
|
||||
throw std::runtime_error("text directory not found in gamedata path");
|
||||
}
|
||||
std::vector<std::string> names;
|
||||
for (const rwfs::path &p : rwfs::directory_iterator(textPath)) {
|
||||
// auto langName = p.lexically_relative(gameDataPath).string();
|
||||
auto langName = p.filename().string();
|
||||
std::transform(langName.begin(), langName.end(), langName.begin(), ::tolower);
|
||||
names.push_back(langName);
|
||||
}
|
||||
return names;
|
||||
}
|
64
rwviewer/views/TextViewer.hpp
Normal file
64
rwviewer/views/TextViewer.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef _TEXTVIEWER_HPP_
|
||||
#define _TEXTVIEWER_HPP_
|
||||
|
||||
#include "ViewerInterface.hpp"
|
||||
|
||||
#include <fonts/GameTexts.hpp>
|
||||
#include <rw/filesystem.hpp>
|
||||
|
||||
#include <QTableView>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class TextModel;
|
||||
class ViewerWidget;
|
||||
|
||||
class QLayout;
|
||||
class QItemSelection;
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
class QModelIndex;
|
||||
class QString;
|
||||
class QWidget;
|
||||
|
||||
class TextTableView : public QTableView {
|
||||
Q_OBJECT
|
||||
protected slots:
|
||||
virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override;
|
||||
signals:
|
||||
void gameStringChanged(const GameString &string);
|
||||
};
|
||||
|
||||
class TextViewer : public ViewerInterface {
|
||||
Q_OBJECT
|
||||
|
||||
TextModel *textModel;
|
||||
TextTableView *textTable;
|
||||
ViewerWidget *viewerWidget;
|
||||
|
||||
QLineEdit *hexLineEdit;
|
||||
QTextEdit *textEdit;
|
||||
|
||||
virtual void worldChanged() override;
|
||||
|
||||
GameString currentGameString;
|
||||
font_t currentFont;
|
||||
int currentFontSize;
|
||||
|
||||
void updateRender();
|
||||
|
||||
void setGameString(const GameString &gameString);
|
||||
std::vector<std::string> getFontTextureNames();
|
||||
public:
|
||||
TextViewer(QWidget* parent = 0, Qt::WindowFlags f = 0);
|
||||
|
||||
signals:
|
||||
void fontChanged(font_t font);
|
||||
private slots:
|
||||
void onGameStringChange(const GameString &gameString);
|
||||
void onStringChange();
|
||||
void onFontChange(size_t font);
|
||||
void onFontSizeChange(int font);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user