diff options
Diffstat (limited to '')
-rw-r--r-- | MapTool/MapTool.pro | 35 | ||||
-rw-r--r-- | MapTool/MapTool.pro.user | 113 | ||||
-rw-r--r-- | MapTool/main.cpp | 10 | ||||
-rw-r--r-- | MapTool/mtmainwindow.cpp | 14 | ||||
-rw-r--r-- | MapTool/mtmainwindow.h | 21 | ||||
-rw-r--r-- | MapTool/mtmainwindow.ui | 137 | ||||
-rw-r--r-- | MapTool/t3d/common.h | 24 | ||||
-rw-r--r-- | MapTool/t3d/material.cpp | 4 | ||||
-rw-r--r-- | MapTool/t3d/material.h | 9 | ||||
-rw-r--r-- | MapTool/t3d/mesh.cpp | 4 | ||||
-rw-r--r-- | MapTool/t3d/mesh.h | 18 | ||||
-rw-r--r-- | MapTool/t3d/model.cpp | 4 | ||||
-rw-r--r-- | MapTool/t3d/model.h | 16 | ||||
-rw-r--r-- | MapTool/t3d/objreader.cpp | 80 | ||||
-rw-r--r-- | MapTool/t3d/objreader.h | 30 | ||||
-rw-r--r-- | MapTool/wii/archiveu8.cpp | 263 | ||||
-rw-r--r-- | MapTool/wii/archiveu8.h | 61 | ||||
-rw-r--r-- | MapTool/wii/common.cpp | 134 | ||||
-rw-r--r-- | MapTool/wii/common.h | 111 | ||||
-rw-r--r-- | MapTool/wii/filesystem.cpp | 141 | ||||
-rw-r--r-- | MapTool/wii/filesystem.h | 73 | ||||
-rw-r--r-- | MapTool/wii/stringtablebuilder.cpp | 25 | ||||
-rw-r--r-- | MapTool/wii/stringtablebuilder.h | 22 |
23 files changed, 1349 insertions, 0 deletions
diff --git a/MapTool/MapTool.pro b/MapTool/MapTool.pro new file mode 100644 index 0000000..94e83c7 --- /dev/null +++ b/MapTool/MapTool.pro @@ -0,0 +1,35 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-12-10T10:51:23 +# +#------------------------------------------------- + +QT += core gui opengl + +TARGET = MapTool +TEMPLATE = app + + +SOURCES += main.cpp\ + mtmainwindow.cpp \ + wii/stringtablebuilder.cpp \ + wii/filesystem.cpp \ + wii/common.cpp \ + wii/archiveu8.cpp \ + t3d/objreader.cpp \ + t3d/model.cpp \ + t3d/mesh.cpp \ + t3d/material.cpp + +HEADERS += mtmainwindow.h \ + wii/stringtablebuilder.h \ + wii/filesystem.h \ + wii/common.h \ + wii/archiveu8.h \ + t3d/objreader.h \ + t3d/model.h \ + t3d/mesh.h \ + t3d/common.h \ + t3d/material.h + +FORMS += mtmainwindow.ui diff --git a/MapTool/MapTool.pro.user b/MapTool/MapTool.pro.user new file mode 100644 index 0000000..447c181 --- /dev/null +++ b/MapTool/MapTool.pro.user @@ -0,0 +1,113 @@ +<!DOCTYPE QtCreatorProject> +<qtcreator> + <data> + <variable>ProjectExplorer.Project.ActiveTarget</variable> + <value type="int">0</value> + </data> + <data> + <variable>ProjectExplorer.Project.EditorSettings</variable> + <valuemap type="QVariantMap"> + <value key="EditorConfiguration.Codec" type="QByteArray">System</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.Target.0</variable> + <valuemap type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Desktop</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Target.DesktopTarget</value> + <value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value> + <value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value> + <valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap"> + <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value> + <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList"/> + </valuemap> + <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value> + <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value> + <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/> + <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value> + </valuemap> + <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value> + <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value> + <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value> + <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"> + <value type="QString">clean</value> + </valuelist> + <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value> + </valuemap> + <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value> + <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value> + <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Debug</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">2</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/home/me/Games/Newer/Kamek/MapTool-build-desktop</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">2</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value> + </valuemap> + <valuemap key="ProjectExplorer.Target.BuildConfiguration.1" type="QVariantMap"> + <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.0" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">qmake</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">QtProjectManager.QMakeBuildStep</value> + <valuelist key="QtProjectManager.QMakeBuildStep.QMakeArguments" type="QVariantList"/> + </valuemap> + <valuemap key="ProjectExplorer.BuildConfiguration.BuildStep.1" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value> + <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">false</value> + <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"/> + <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value> + </valuemap> + <value key="ProjectExplorer.BuildConfiguration.BuildStepsCount" type="int">2</value> + <valuemap key="ProjectExplorer.BuildConfiguration.CleanStep.0" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Make</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.MakeStep</value> + <value key="Qt4ProjectManager.MakeStep.Clean" type="bool">true</value> + <valuelist key="Qt4ProjectManager.MakeStep.MakeArguments" type="QVariantList"> + <value type="QString">clean</value> + </valuelist> + <value key="Qt4ProjectManager.MakeStep.MakeCommand" type="QString"></value> + </valuemap> + <value key="ProjectExplorer.BuildConfiguration.CleanStepsCount" type="int">1</value> + <value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value> + <valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">Release</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4BuildConfiguration</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration" type="int">0</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory" type="QString">/home/me/Games/Newer/Kamek/MapTool-build-desktop</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId" type="int">2</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.ToolChain" type="int">0</value> + <value key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild" type="bool">true</value> + </valuemap> + <value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">2</value> + <valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap"> + <value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString">MapTool</value> + <value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">Qt4ProjectManager.Qt4RunConfiguration</value> + <value key="Qt4ProjectManager.Qt4RunConfiguration.BaseEnvironmentBase" type="int">2</value> + <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments" type="QVariantList"/> + <value key="Qt4ProjectManager.Qt4RunConfiguration.ProFile" type="QString">MapTool.pro</value> + <value key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix" type="bool">false</value> + <value key="Qt4ProjectManager.Qt4RunConfiguration.UseTerminal" type="bool">false</value> + <valuelist key="Qt4ProjectManager.Qt4RunConfiguration.UserEnvironmentChanges" type="QVariantList"/> + <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetName" type="bool">false</value> + <value key="Qt4ProjectManager.Qt4RunConfiguration.UserSetWorkingDirectory" type="bool">false</value> + <value key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory" type="QString"></value> + </valuemap> + <value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value> + </valuemap> + </data> + <data> + <variable>ProjectExplorer.Project.TargetCount</variable> + <value type="int">1</value> + </data> + <data> + <variable>ProjectExplorer.Project.Updater.FileVersion</variable> + <value type="int">4</value> + </data> +</qtcreator> diff --git a/MapTool/main.cpp b/MapTool/main.cpp new file mode 100644 index 0000000..2241edd --- /dev/null +++ b/MapTool/main.cpp @@ -0,0 +1,10 @@ +#include <QtGui/QApplication> +#include "mtmainwindow.h" + +int main(int argc, char *argv[]) { + QApplication a(argc, argv); + MTMainWindow w; + w.show(); + + return a.exec(); +} diff --git a/MapTool/mtmainwindow.cpp b/MapTool/mtmainwindow.cpp new file mode 100644 index 0000000..587d0c3 --- /dev/null +++ b/MapTool/mtmainwindow.cpp @@ -0,0 +1,14 @@ +#include "mtmainwindow.h" +#include "ui_mtmainwindow.h" + +MTMainWindow::MTMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MTMainWindow) +{ + ui->setupUi(this); +} + +MTMainWindow::~MTMainWindow() +{ + delete ui; +} diff --git a/MapTool/mtmainwindow.h b/MapTool/mtmainwindow.h new file mode 100644 index 0000000..a73b9e0 --- /dev/null +++ b/MapTool/mtmainwindow.h @@ -0,0 +1,21 @@ +#ifndef MTMAINWINDOW_H +#define MTMAINWINDOW_H + +#include <QMainWindow> + +namespace Ui { + class MTMainWindow; +} + +class MTMainWindow : public QMainWindow { + Q_OBJECT + +public: + explicit MTMainWindow(QWidget *parent = 0); + ~MTMainWindow(); + +private: + Ui::MTMainWindow *ui; +}; + +#endif // MTMAINWINDOW_H diff --git a/MapTool/mtmainwindow.ui b/MapTool/mtmainwindow.ui new file mode 100644 index 0000000..d0ab60d --- /dev/null +++ b/MapTool/mtmainwindow.ui @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MTMainWindow</class> + <widget class="QMainWindow" name="MTMainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>425</height> + </rect> + </property> + <property name="windowTitle"> + <string>MTMainWindow</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="loadButton"> + <property name="text"> + <string>Load Scene</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="saveButton"> + <property name="text"> + <string>Save Scene</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Export ARC</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="groupTab"> + <attribute name="title"> + <string>Groups</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QListView" name="groupView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="modelTab"> + <attribute name="title"> + <string>Models</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Scene Graph</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QTreeView" name="sceneGraphView"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Available Models</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTreeView" name="availableModelView"/> + </item> + <item> + <widget class="QPushButton" name="editModelPoolButton"> + <property name="text"> + <string>Edit Available Models</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="stageTab"> + <attribute name="title"> + <string>Stages</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QTreeView" name="stageView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="pathTab"> + <attribute name="title"> + <string>Paths</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QTreeView" name="pathView"/> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/MapTool/t3d/common.h b/MapTool/t3d/common.h new file mode 100644 index 0000000..15b65b8 --- /dev/null +++ b/MapTool/t3d/common.h @@ -0,0 +1,24 @@ +#ifndef T3DCOMMON_H +#define T3DCOMMON_H + +struct Vec { + float x, y, z; +}; + +struct Vec2 { + float x, y; +}; + +struct Triangle { + Vec vertex[3]; + Vec2 texcoord[3]; + Vec normal[3]; +}; + +struct Quad { + Vec vertex[4]; + Vec2 texcoord[4]; + Vec normal[4]; +}; + +#endif // T3DCOMMON_H diff --git a/MapTool/t3d/material.cpp b/MapTool/t3d/material.cpp new file mode 100644 index 0000000..c9f3a35 --- /dev/null +++ b/MapTool/t3d/material.cpp @@ -0,0 +1,4 @@ +#include "material.h" + +T3DMaterial::T3DMaterial() { +} diff --git a/MapTool/t3d/material.h b/MapTool/t3d/material.h new file mode 100644 index 0000000..cc4bab3 --- /dev/null +++ b/MapTool/t3d/material.h @@ -0,0 +1,9 @@ +#ifndef T3DMATERIAL_H +#define T3DMATERIAL_H + +class T3DMaterial { +public: + T3DMaterial(); +}; + +#endif // T3DMATERIAL_H diff --git a/MapTool/t3d/mesh.cpp b/MapTool/t3d/mesh.cpp new file mode 100644 index 0000000..3dc10b8 --- /dev/null +++ b/MapTool/t3d/mesh.cpp @@ -0,0 +1,4 @@ +#include "mesh.h" + +T3DMesh::T3DMesh() { +} diff --git a/MapTool/t3d/mesh.h b/MapTool/t3d/mesh.h new file mode 100644 index 0000000..2b9ce89 --- /dev/null +++ b/MapTool/t3d/mesh.h @@ -0,0 +1,18 @@ +#ifndef T3DMESH_H +#define T3DMESH_H + +#include "common.h" +#include "material.h" +#include <QtCore/QVector> + +class T3DMesh { +public: + T3DMesh(); + + QVector<Triangle> triangles; + QVector<Quad> quads; + + T3DMaterial *material; +}; + +#endif // T3DMESH_H diff --git a/MapTool/t3d/model.cpp b/MapTool/t3d/model.cpp new file mode 100644 index 0000000..c2dc6dc --- /dev/null +++ b/MapTool/t3d/model.cpp @@ -0,0 +1,4 @@ +#include "model.h" + +T3DModel::T3DModel() { +} diff --git a/MapTool/t3d/model.h b/MapTool/t3d/model.h new file mode 100644 index 0000000..a6535af --- /dev/null +++ b/MapTool/t3d/model.h @@ -0,0 +1,16 @@ +#ifndef T3DMODEL_H +#define T3DMODEL_H + +#include <QtCore/QList> +#include "mesh.h" + +class T3DModel { +public: + T3DModel(); + ~T3DModel(); + + QList<T3DMesh *> meshes; + +}; + +#endif // T3DMODEL_H diff --git a/MapTool/t3d/objreader.cpp b/MapTool/t3d/objreader.cpp new file mode 100644 index 0000000..3a07323 --- /dev/null +++ b/MapTool/t3d/objreader.cpp @@ -0,0 +1,80 @@ +#include "objreader.h" + +T3DObjReader::T3DObjReader(T3DModel &model) { + m_model = model; +} + +T3DObjReader::parseLine(QString line) { + line = line.trimmed(); + if (line.isEmpty() || line.at(0) == '#') + return; + + QStringList params = line.split(' ', QString::SkipEmptyParts); + QString cmd = params[0]; + + if (cmd == "v") { + float x, y, z; + x = params[1].toFloat(); + y = params[2].toFloat(); + z = params[3].toFloat(); + known_vertices.append(Vec(x, y, z)); + } + + if (cmd == "vt") { + float x, y; + x = params[1].toFloat(); + y = params[2].toFloat(); + known_texcoords.append(Vec2(x, y)); + } + + if (cmd == "vn") { + float x, y, z; + x = params[1].toFloat(); + y = params[2].toFloat(); + z = params[3].toFloat(); + known_normals.append(Vec(x, y, z)); + } + + if (cmd == "f") { + int vtxCount = params.count() - 1; + if (vtxCount < 3 || vtxCount > 4) + return; + + int vtxID[4], tcID[4], nrmID[4]; + + for (int i = 0; i < vtxCount; i++) { + QString face = params[i+1]; + QStringList ids = face.split('/'); + vtxID[i] = ids[0].isEmpty() ? 0 : ids[0].toInt(); + tcID[i] = ids[1].isEmpty() ? 0 : ids[1].toInt(); + nrmID[i] = ids[2].isEmpty() ? 0 : ids[2].toInt(); + } + + if (vtxCount == 3) { + Triangle tri; + for (int i = 0; i < 3; i++) { + tri.vertex[i] = known_vertices[vtxID[i]]; + tri.texcoord[i] = known_texcoords[tcID[i]]; + tri.normal[i] = known_normals[nrmID[i]]; + } + m_currentMesh->triangles.append(tri); + } + + if (vtxCount == 4) { + Quad q; + for (int i = 0; i < 4; i++) { + q.vertex[i] = known_vertices[vtxID[i]]; + q.texcoord[i] = known_texcoords[tcID[i]]; + q.normal[i] = known_normals[nrmID[i]]; + } + m_currentMesh->quads.append(q); + } + } + + if (cmd == "usemtl") { + // treat this as "new shape" + m_currentMesh = new T3DMesh(); + m_model->meshes.append(m_currentMesh); + m_currentMesh->material = materials[params[1]]; + } +} diff --git a/MapTool/t3d/objreader.h b/MapTool/t3d/objreader.h new file mode 100644 index 0000000..6e518e8 --- /dev/null +++ b/MapTool/t3d/objreader.h @@ -0,0 +1,30 @@ +#ifndef T3DOBJREADER_H +#define T3DOBJREADER_H + +#include <QtCore/QList> +#include <QtCore/QVector> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QHash> +#include "model.h" + +class T3DObjReader { +private: + T3DModel *m_model; + T3DMesh *m_currentMesh; + + QVector<Vec> known_vertices; + QVector<Vec2> known_texcoords; + QVector<Vec> known_normals; + +public: + T3DObjReader(T3DModel &model); + + void parseLine(QString line); + + T3DModel *model() { return m_model; } + + QHash<QString, T3DMaterial *> materials; +}; + +#endif // T3DOBJREADER_H diff --git a/MapTool/wii/archiveu8.cpp b/MapTool/wii/archiveu8.cpp new file mode 100644 index 0000000..d27dfde --- /dev/null +++ b/MapTool/wii/archiveu8.cpp @@ -0,0 +1,263 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@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, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#include "archiveu8.h" + + + + + + +WiiArchiveU8::WiiArchiveU8() { } + +WiiArchiveU8::WiiArchiveU8(QDataStream &stream) { + U8ReadInfo info; + info.startPos = stream.device()->pos(); + + quint32 magic; + stream >> (quint32&)magic; + + if (magic != 0x55AA382D) + qWarning() << "WiiArchiveU8: tried to load an archive without the U8 magic"; + + quint32 fstStart, fstSize, dataOffset; + stream >> (quint32&)fstStart; + stream >> (quint32&)fstSize; + stream >> (quint32&)dataOffset; + + // read the FST + stream.device()->seek(info.startPos + fstStart); + + // read the root node + quint32 rootNodeLastChild; + + stream.skipRawData(8); // ignore type, nameOffset and dataOffset + stream >> (quint32&)rootNodeLastChild; + + // but before we do this, read the string table + qint64 savePos = stream.device()->pos(); + stream.device()->seek(savePos + ((rootNodeLastChild - 1) * 12)); + + int stringTableLength = fstSize - (rootNodeLastChild * 12); + + QByteArray rawStringTable; + rawStringTable.resize(stringTableLength); + stream.readRawData(rawStringTable.data(), stringTableLength); + + info.stringTable = QString::fromAscii(rawStringTable.constData(), stringTableLength); + + // now read the root node + stream.device()->seek(savePos); + + qDebug() << "Reading root node: last child is" << rootNodeLastChild; + info.currentNode = 1; + this->readDir(stream, this->root, rootNodeLastChild, info); +} + + +void WiiArchiveU8::readDir(QDataStream &in, WiiDirectory &dir, int lastChild, U8ReadInfo &info) { + // read every node in this directory + + while (info.currentNode < lastChild) { + info.currentNode++; + + //qDebug() << "Reading @ pos" << in.device()->pos(); + + quint32 value, dataOffset, size; + in >> (quint32&)value; + in >> (quint32&)dataOffset; + in >> (quint32&)size; + + int nameOffset = value & 0xFFFFFF; + int type = value >> 24; + + WiiFSObject *newObj; + if (type == 0) + newObj = new WiiFile; + else if (type == 1) + newObj = new WiiDirectory; + else + qFatal("WiiArchiveU8::readDir: Unknown fs obj type %d", type); + + // get the name + int nameSize = info.stringTable.indexOf(QChar::Null, nameOffset) - nameOffset; + newObj->name = info.stringTable.mid(nameOffset, nameSize); + + qDebug() << "Reading node" << info.currentNode << newObj->name << "- type:" << type << "size:" << size << "offset:" << dataOffset; + + // read the contents + if (newObj->isFile()) { + // get the file data + qint64 savePos = in.device()->pos(); + in.device()->seek(info.startPos + dataOffset); + + WiiFile *file = (WiiFile*)newObj; + file->data.resize(size); + in.readRawData(file->data.data(), size); + + in.device()->seek(savePos); + + } else if (newObj->isDirectory()) { + // read the children + this->readDir(in, *((WiiDirectory*)newObj), size, info); + + } + + qDebug() << "Adding" << newObj->name << "to" << dir.name; + dir.addChild(newObj); + }; +} + + + +void WiiArchiveU8::writeToDataStream(QDataStream &out) const { + U8WriteInfo info; + + // first off, before we do anything else, create the string table + this->addNodeToStringTable(this->root, info.stringTableBuilder); + + QByteArray stringTable = info.stringTableBuilder.pack(); + + // calculate various fun offsets/sizes + int nodeCount = 0; + this->countNode(this->root, &nodeCount); + + info.startPos = out.device()->pos(); + + quint32 fstStart = 0x20; + quint32 nodeDataSize = nodeCount * 12; + quint32 stringTableSize = stringTable.length(); + quint32 fstSize = nodeDataSize + stringTableSize; + quint32 dataOffset = AlignUp(fstStart + fstSize, 0x20); + + qDebug() << "Writing: fstStart" << fstStart << "nodeCount" << nodeCount; + qDebug() << "nodeDataSize" << nodeDataSize << "stringTableSize" << stringTableSize; + qDebug() << "fstSize" << fstSize << "dataOffset" << dataOffset; + + // now write the header + out << (quint32)0x55AA382D; + out << (quint32)fstStart; + out << (quint32)fstSize; + out << (quint32)dataOffset; + + WritePadding(0x10, out); + + // write root node + info.currentNode = 1; // root node is 1 + info.currentRecursionLevel = 0; + info.nextDataOffset = dataOffset; + + out << (quint32)(0x01000000 << info.stringTableBuilder.add("")); + out << (quint32)0; + out << (quint32)nodeCount; + + this->writeDir(out, this->root, info); + + // write string table + out.writeRawData(stringTable.constData(), stringTable.length()); + + // write data (after padding) + WritePadding(dataOffset - fstSize - fstStart, out); + + this->writeNodeData(out, this->root); + + // looks like we are finally done +} + + +void WiiArchiveU8::addNodeToStringTable(const WiiFSObject &node, WiiStringTableBuilder &table) const { + table.add(node.name); + + if (node.isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, dir->children) + this->addNodeToStringTable(*p, table); + } +} + + +void WiiArchiveU8::countNode(const WiiFSObject &node, int *countPtr) const { + (*countPtr)++; + + if (node.isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, dir->children) + this->countNode(*p, countPtr); + } +} + + +void WiiArchiveU8::writeDir(QDataStream &out, const WiiDirectory &dir, U8WriteInfo &info) const { + foreach (WiiFSObject *p, dir.children) { + info.currentNode++; + + if (p->isDirectory()) { + // write directory + WiiDirectory *thisDir = (WiiDirectory*)p; + + out << (quint32)(0x01000000 | info.stringTableBuilder.add(thisDir->name)); + out << (quint32)info.currentRecursionLevel; + + qint64 lastChildFieldPos = out.device()->pos(); + out << (quint32)0; // placeholder + + info.currentRecursionLevel++; + + this->writeDir(out, *thisDir, info); + + info.currentRecursionLevel--; + + // write lastChild field + qint64 dirEndPos = out.device()->pos(); + + out.device()->seek(lastChildFieldPos); + out << (quint32)info.currentNode; + out.device()->seek(dirEndPos); + + } else if (p->isFile()) { + // write file + WiiFile *thisFile = (WiiFile*)p; + + out << (quint32)info.stringTableBuilder.add(thisFile->name); + out << (quint32)info.nextDataOffset; + out << (quint32)thisFile->data.size(); + + info.nextDataOffset = AlignUp(info.nextDataOffset + thisFile->data.size(), 0x20); + } + } +} + + +void WiiArchiveU8::writeNodeData(QDataStream &out, const WiiFSObject &node) const { + if (node.isDirectory()) { + // write all the children's data + WiiDirectory *thisDir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, thisDir->children) + this->writeNodeData(out, *p); + + } else if (node.isFile()) { + // write this file's data + WiiFile *thisFile = (WiiFile*)&node; + + int len = thisFile->data.length(); + out.writeRawData(thisFile->data.constData(), len); + WritePadding(AlignUp(len, 0x20) - len, out); + } +} diff --git a/MapTool/wii/archiveu8.h b/MapTool/wii/archiveu8.h new file mode 100644 index 0000000..5561beb --- /dev/null +++ b/MapTool/wii/archiveu8.h @@ -0,0 +1,61 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@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, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#ifndef WIIARCHIVEU8_H +#define WIIARCHIVEU8_H + +#include "common.h" +#include "filesystem.h" +#include "stringtablebuilder.h" + + +struct U8ReadInfo { + qint64 startPos; + QString stringTable; + int currentNode; +}; + +struct U8WriteInfo { + qint64 startPos; + WiiStringTableBuilder stringTableBuilder; + int currentRecursionLevel; + int currentNode; + int nextDataOffset; +}; + + +class WiiArchiveU8 { +public: + WiiArchiveU8(); + WiiArchiveU8(QDataStream &stream); + + WiiDirectory root; + + void writeToDataStream(QDataStream &out) const; + +private: + void readDir(QDataStream &in, WiiDirectory &dir, int lastChild, U8ReadInfo &info); + + void addNodeToStringTable(const WiiFSObject &node, WiiStringTableBuilder &table) const; + void countNode(const WiiFSObject &node, int *countPtr) const; + + void writeDir(QDataStream &out, const WiiDirectory &dir, U8WriteInfo &info) const; + + void writeNodeData(QDataStream &out, const WiiFSObject &node) const; +}; + +#endif // WIIARCHIVEU8_H diff --git a/MapTool/wii/common.cpp b/MapTool/wii/common.cpp new file mode 100644 index 0000000..8f552b3 --- /dev/null +++ b/MapTool/wii/common.cpp @@ -0,0 +1,134 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@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, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#include "common.h" + +QByteArray PadByteArray(const QByteArray original, int newLength, char padWith) { + QByteArray newArray = original; + + if (original.length() > newLength) { + // the original array is longer than the length desired, so truncate it + newArray.truncate(newLength); + + } else if (original.length() < newLength) { + // the original array is shorter, so pad it + int oldLength = original.length(); + newArray.resize(newLength); + + for (int i = oldLength; i < newLength; i++) { + newArray[i] = '\0'; + } + } + + return newArray; +} + +QStringList ReadStringList(QDataStream &in) { + QStringList output; + + quint16 count; + in >> (quint16&)count; + in.skipRawData(2); // padding + + QVector<quint32> stringOffsets(count); + + // save the initial offset so we can get the strings later + // string offsets are based on the first offset entry (after the count) + // NOT on the section offset + qint64 savedPos = in.device()->pos(); + + for (int i = 0; i < count; i++) { + quint32 offset; + in >> (quint32&)offset; + in.skipRawData(4); // unused? + + stringOffsets[i] = offset; + } + + // ok, now we can get the strings + for (int i = 0; i < count; i++) { + in.device()->seek(savedPos + stringOffsets[i]); + + // how fun: no length is stored for each string, they're just zero + // terminated. so let's try to figure it out! + int stringLength = 0; + char check; + + in >> (quint8&)check; + while (check != 0) { + stringLength += 1; + in >> (quint8&)check; + } + + // now read the string + char *buffer = new char[stringLength]; + + in.device()->seek(savedPos + stringOffsets[i]); + in.readRawData(buffer, stringLength); + + output.append(QString::fromAscii(buffer, stringLength)); + + delete[] buffer; + + + qDebug() << "Read string:" << output.last(); + } + + return output; +} + +void WriteStringList(QDataStream &out, const QStringList list) { + out << (quint16)list.count(); + WritePadding(2, out); + + // calculate offsets for every string, and write them + // offset 0 points to the first entry in the offset list, etc, so + // take that into account for the string offset calculation + quint32 currentOffset = list.count() * 8; + + foreach (QString str, list) { + out << (quint32)currentOffset; + WritePadding(4, out); // unused? + + currentOffset += str.length() + 1; + } + + // now write the strings + foreach (QString str, list) { + QByteArray rawStr = str.toAscii(); + rawStr.append('\0'); + out.writeRawData(rawStr.constData(), rawStr.length()); + } +} + +QString ReadFixedLengthASCII(QDataStream &in, int length) { + QByteArray readStr(length, '\0'); + in.readRawData(readStr.data(), readStr.length()); + + QString str = QString::fromAscii(readStr.data(), readStr.length()); + if (str.contains(QChar('\0'))) + str.truncate(str.indexOf(QChar('\0'))); + + return str; +} + +void WriteFixedLengthASCII(QDataStream &out, const QString str, int length) { + QByteArray paddedStr = PadByteArray(str.toAscii(), length); + out.writeRawData(paddedStr.constData(), paddedStr.length()); +} + + diff --git a/MapTool/wii/common.h b/MapTool/wii/common.h new file mode 100644 index 0000000..b440841 --- /dev/null +++ b/MapTool/wii/common.h @@ -0,0 +1,111 @@ +#ifndef WIICOMMON_H +#define WIICOMMON_H + +#include <QtGlobal> +#include <QtCore/QByteArray> +#include <QtGui/QColor> +#include <QtCore/QPointF> +#include <QtCore/QDataStream> +#include <QtCore/QStringList> +#include <QtCore/QDebug> +#include <QtCore/QVector> + +inline quint32 AlignUp(quint32 value, quint32 alignTo) { + return (value + alignTo - 1) & ~(alignTo - 1); +} + +inline quint32 AlignDown(quint32 value, quint32 alignTo) { + return value & ~(alignTo - 1); +} + + +inline quint32 BitExtract(quint32 value, int count, int start) { + // this function relies on heavy compiler optimisation to be efficient :p + quint32 mask = 0; + for (int i = start; i < start+count; i++) { + mask |= (0x80000000 >> i); + } + + return (value & mask) >> (32 - (start + count)); +} + +inline quint32 BitInsert(quint32 value, int newValue, int count, int start) { + quint32 mask = 0; + for (int i = start; i < start+count; i++) { + mask |= (0x80000000 >> i); + } + + value &= ~mask; + value |= (newValue << (32 - (start + count))) & mask; + return value; +} + +inline void WritePadding(int num, QDataStream &out) { + for (int i = 0; i < num; i++) + out << (quint8)0; +} + + + + +QByteArray PadByteArray(QByteArray original, int newLength, char padWith='\0'); + +inline quint32 ColorToRGBA(QColor col) { + return (col.red() << 24) | (col.green() << 16) | (col.blue() << 8) | (col.alpha()); +} + +inline QColor RGBAToColor(quint32 col) { + return QColor(col >> 24, (col >> 16) & 0xFF, (col >> 8) & 0xFF, col & 0xFF); +} + +inline void ReadRGBA8Color(QColor &out, QDataStream &in) { + quint32 col; + in >> (quint32&)col; + out = RGBAToColor(col); +} + +inline void WriteRGBA8Color(const QColor in, QDataStream &out) { + out << (quint32)ColorToRGBA(in); +} + +inline void ReadS10Color(QColor &out, QDataStream &in) { + quint16 r, g, b, a; + in >> (quint16&)r; + in >> (quint16&)g; + in >> (quint16&)b; + in >> (quint16&)a; + out.setRgb(r, g, b, a); +} + +inline void WriteS10Color(const QColor in, QDataStream &out) { + out << (quint16)in.red(); + out << (quint16)in.green(); + out << (quint16)in.blue(); + out << (quint16)in.alpha(); +} + +inline void ReadPointF(QDataStream &stream, QPointF &point) { + float x, y; + stream >> x; + stream >> y; + point.setX(x); + point.setY(y); +} + +inline void WritePointF(QDataStream &stream, const QPointF &point) { + stream << (float)point.x(); + stream << (float)point.y(); +} + +inline void InitDataStream(QDataStream &stream) { + stream.setByteOrder(QDataStream::BigEndian); + stream.setVersion(QDataStream::Qt_4_5); +} + +QStringList ReadStringList(QDataStream &in); +void WriteStringList(QDataStream &out, QStringList list); + +QString ReadFixedLengthASCII(QDataStream &in, int length); +void WriteFixedLengthASCII(QDataStream &out, QString str, int length); + +#endif // WIICOMMON_H diff --git a/MapTool/wii/filesystem.cpp b/MapTool/wii/filesystem.cpp new file mode 100644 index 0000000..014b693 --- /dev/null +++ b/MapTool/wii/filesystem.cpp @@ -0,0 +1,141 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@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, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#include "filesystem.h" + + +/******************************************************************************/ + +WiiFSObject::WiiFSObject() { parent = 0; } +WiiFSObject::~WiiFSObject() { } + + + +void WiiFSObject::unlinkFromParent() { + if (this->parent == 0) + return; + + if (this->parent->isDirectory()) { + WiiDirectory *p = (WiiDirectory *)this->parent; + if (p->children.contains(this)) + p->children.removeAt(p->children.indexOf(this)); + } + + this->parent = 0; +} + +bool WiiFSObject::nameIsEqual(QString check) const { + return (bool)(QString::compare(this->name, check, Qt::CaseInsensitive) == 0); +} + +bool WiiFSObject::isFile() const { return false; } +bool WiiFSObject::isDirectory() const { return false; } + +/******************************************************************************/ + +bool WiiFile::isFile() const { return true; } + +/******************************************************************************/ + +WiiDirectory::~WiiDirectory() { + foreach (WiiFSObject *ptr, children) + delete ptr; +} + +bool WiiDirectory::isDirectory() const { return true; } + +WiiFSObject *WiiDirectory::findByName(QString name, bool recursive) const { + foreach (WiiFSObject *obj, children) { + if (obj->nameIsEqual(name)) + return obj; + + if (recursive && obj->isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)obj; + WiiFSObject *tryThis = dir->findByName(name, recursive); + + if (tryThis) + return tryThis; + } + } + + return 0; +} + +WiiFSObject *WiiDirectory::resolvePath(QString path) { + QStringList pathComponents = path.split('/'); + WiiDirectory *currentDir = this; + + // special case: handle absolute paths + if (pathComponents.at(0) == "") { + while (currentDir->parent != 0) + currentDir = (WiiDirectory*)currentDir->parent; + + pathComponents.removeFirst(); + } + + // now we can loop through the path + while (!pathComponents.isEmpty()) { + QString next = pathComponents.takeFirst(); + WiiFSObject *nextObj; + + // get the next object in the path + if (next == ".") { + nextObj = currentDir; + } else if (next == "..") { + nextObj = currentDir->parent; + } else { + nextObj = currentDir->findByName(next, false); + } + + if (nextObj == 0) { + qWarning() << "Failed to resolve path" << path << ": missing component" << next; + return 0; + } + + if (pathComponents.isEmpty()) { + // we've reached the end \o/ + return (WiiFSObject *)nextObj; + } + + // verify that this object is a directory + if (!nextObj->isDirectory()) { + qWarning() << "Failed to resolve path" << path << ": component" << next << "is not a directory"; + return 0; + } + + // ok, this has to be a directory, so let's just continue + currentDir = (WiiDirectory *)nextObj; + } + + // we should not reach here + qWarning() << "Failed to resolve path" << path << ": unknown error"; + return 0; +} + +bool WiiDirectory::addChild(WiiFSObject *obj) { + // verify to make sure an object does not exist with this name + if (this->findByName(obj->name, false) != 0) + return false; + + obj->unlinkFromParent(); + + this->children.append(obj); + obj->parent = this; + + return true; +} + diff --git a/MapTool/wii/filesystem.h b/MapTool/wii/filesystem.h new file mode 100644 index 0000000..7527a7d --- /dev/null +++ b/MapTool/wii/filesystem.h @@ -0,0 +1,73 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@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, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#ifndef WIIFILESYSTEM_H +#define WIIFILESYSTEM_H + +#include "common.h" + + +class WiiFSObject { + // abstract base class of all filesystem objects +public: + virtual ~WiiFSObject(); + + WiiFSObject *parent; + + QString name; + + + void unlinkFromParent(); + bool nameIsEqual(QString check) const; + + virtual bool isFile() const; + virtual bool isDirectory() const; + + +protected: + WiiFSObject(); // don't instantiate this class directly! +}; + + +/******************************************************************************/ + +class WiiFile : public WiiFSObject { +public: + QByteArray data; + + + bool isFile() const; +}; + +/******************************************************************************/ + +class WiiDirectory : public WiiFSObject { +public: + ~WiiDirectory(); + + QList<WiiFSObject *> children; + + + bool isDirectory() const; + + WiiFSObject *findByName(QString name, bool recursive) const; + WiiFSObject *resolvePath(QString path); + bool addChild(WiiFSObject *obj); +}; + + +#endif // FILESYSTEM_H diff --git a/MapTool/wii/stringtablebuilder.cpp b/MapTool/wii/stringtablebuilder.cpp new file mode 100644 index 0000000..d1f2d2b --- /dev/null +++ b/MapTool/wii/stringtablebuilder.cpp @@ -0,0 +1,25 @@ +#include "stringtablebuilder.h" + +WiiStringTableBuilder::WiiStringTableBuilder() { + m_nextOffset = 0; + m_data = ""; +} + +quint32 WiiStringTableBuilder::add(QString str) { + if (m_lookup.contains(str)) + return m_lookup.value(str); + + quint32 added = m_nextOffset; + m_lookup.insert(str, added); + + m_data.append(str.toAscii()); + m_data.append('\0'); + + m_nextOffset = m_data.length(); + + return added; +} + +QByteArray WiiStringTableBuilder::pack() const { + return m_data; +} diff --git a/MapTool/wii/stringtablebuilder.h b/MapTool/wii/stringtablebuilder.h new file mode 100644 index 0000000..4fce60f --- /dev/null +++ b/MapTool/wii/stringtablebuilder.h @@ -0,0 +1,22 @@ +#ifndef STRINGTABLEBUILDER_H +#define STRINGTABLEBUILDER_H + +#include "common.h" +#include <QtCore/QString> +#include <QtCore/QHash> +#include <QtCore/QByteArray> + +class WiiStringTableBuilder { +public: + WiiStringTableBuilder(); + + quint32 add(QString str); + QByteArray pack() const; + +protected: + int m_nextOffset; + QByteArray m_data; + QHash<QString, quint32> m_lookup; +}; + +#endif // STRINGTABLEBUILDER_H |