mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 01:25:45 -05:00
Feature: Implement MxHd type
This commit is contained in:
parent
6442e5d513
commit
4f7b4eead4
12 changed files with 334 additions and 3 deletions
|
@ -4,6 +4,11 @@ find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
|
|||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
panels/mxhd.cpp
|
||||
panels/mxhd.h
|
||||
panels/panel.cpp
|
||||
panels/panel.h
|
||||
|
||||
chunkmodel.cpp
|
||||
chunkmodel.h
|
||||
main.cpp
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#include <QTreeWidget>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow{parent}
|
||||
QMainWindow{parent},
|
||||
last_set_data_(nullptr)
|
||||
{
|
||||
auto splitter = new QSplitter();
|
||||
splitter->setChildrenCollapsible(false);
|
||||
this->setCentralWidget(splitter);
|
||||
|
||||
model_.SetChunk(&chunk_);
|
||||
|
@ -17,8 +19,20 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
auto tree = new QTreeView();
|
||||
tree->setModel(&model_);
|
||||
splitter->addWidget(tree);
|
||||
connect(tree->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &MainWindow::SelectionChanged);
|
||||
|
||||
config_stack_ = new QStackedWidget();
|
||||
splitter->addWidget(config_stack_);
|
||||
|
||||
panel_blank_ = new Panel();
|
||||
config_stack_->addWidget(panel_blank_);
|
||||
|
||||
panel_mxhd_ = new MxHdPanel();
|
||||
config_stack_->addWidget(panel_mxhd_);
|
||||
|
||||
InitializeMenuBar();
|
||||
|
||||
splitter->setSizes({99999, 99999});
|
||||
}
|
||||
|
||||
void MainWindow::InitializeMenuBar()
|
||||
|
@ -40,11 +54,48 @@ void MainWindow::InitializeMenuBar()
|
|||
setMenuBar(menubar);
|
||||
}
|
||||
|
||||
void MainWindow::SetPanel(Panel *panel, Data *data)
|
||||
{
|
||||
auto current = static_cast<Panel*>(config_stack_->currentWidget());
|
||||
current->SetData(nullptr);
|
||||
|
||||
config_stack_->setCurrentWidget(panel);
|
||||
panel->SetData(data);
|
||||
last_set_data_ = data;
|
||||
}
|
||||
|
||||
void MainWindow::OpenFile()
|
||||
{
|
||||
QString s = QFileDialog::getOpenFileName(this, QString(), QString(), tr("Interleaf Files (*.si)"));
|
||||
if (!s.isEmpty()) {
|
||||
model_.SetChunk(nullptr);
|
||||
SetPanel(panel_blank_, nullptr);
|
||||
chunk_.Read(s.toStdString());
|
||||
model_.SetChunk(&chunk_);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::SelectionChanged(const QModelIndex &index)
|
||||
{
|
||||
Panel *panel_to_set = panel_blank_;
|
||||
Data *data = nullptr;
|
||||
|
||||
if (Chunk *c = static_cast<Chunk*>(index.internalPointer())) {
|
||||
data = c->data();
|
||||
|
||||
switch (c->type()) {
|
||||
case Chunk::MxHd:
|
||||
panel_to_set = panel_mxhd_;
|
||||
break;
|
||||
case Chunk::RIFF:
|
||||
case Chunk::LIST:
|
||||
case Chunk::MxSt:
|
||||
case Chunk::pad_:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (panel_to_set != config_stack_->currentWidget() || data != last_set_data_) {
|
||||
SetPanel(panel_to_set, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
|
||||
#include <chunk.h>
|
||||
#include <QMainWindow>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "chunkmodel.h"
|
||||
#include "panels/mxhd.h"
|
||||
#include "panels/panel.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
|
@ -19,14 +22,25 @@ private:
|
|||
|
||||
void InitializeMenuBar();
|
||||
|
||||
void SetPanel(Panel *panel, Data *data);
|
||||
|
||||
ChunkModel model_;
|
||||
Chunk chunk_;
|
||||
|
||||
QStackedWidget *config_stack_;
|
||||
|
||||
Panel *panel_blank_;
|
||||
MxHdPanel *panel_mxhd_;
|
||||
|
||||
Data *last_set_data_;
|
||||
|
||||
private slots:
|
||||
void OpenFile();
|
||||
//bool SaveFile();
|
||||
//bool SaveFileAs();
|
||||
|
||||
void SelectionChanged(const QModelIndex &index);
|
||||
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
74
app/panels/mxhd.cpp
Normal file
74
app/panels/mxhd.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "mxhd.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
|
||||
MxHdPanel::MxHdPanel(QWidget *parent)
|
||||
: Panel{parent}
|
||||
{
|
||||
auto outer = new QVBoxLayout(this);
|
||||
|
||||
auto layout = new QGridLayout();
|
||||
outer->addLayout(layout);
|
||||
|
||||
int row = 0;
|
||||
|
||||
auto version_layout = new QHBoxLayout();
|
||||
layout->addLayout(version_layout, row, 0, 1, 2);
|
||||
|
||||
version_layout->addWidget(new QLabel(tr("Major Version")));
|
||||
|
||||
major_version_edit_ = new QSpinBox();
|
||||
major_version_edit_->setMinimum(0);
|
||||
major_version_edit_->setMaximum(UINT16_MAX);
|
||||
version_layout->addWidget(major_version_edit_);
|
||||
|
||||
version_layout->addWidget(new QLabel(tr("Minor Version")));
|
||||
|
||||
minor_version_edit_ = new QSpinBox();
|
||||
minor_version_edit_->setMinimum(0);
|
||||
minor_version_edit_->setMaximum(UINT16_MAX);
|
||||
version_layout->addWidget(minor_version_edit_);
|
||||
|
||||
row++;
|
||||
|
||||
layout->addWidget(new QLabel(tr("Buffer Alignment")), row, 0);
|
||||
|
||||
buffer_alignment_edit_ = new QSpinBox();
|
||||
buffer_alignment_edit_->setMinimum(0);
|
||||
buffer_alignment_edit_->setMaximum(INT_MAX); // Technically this is UINT32_MAX but QSpinBox only supports int
|
||||
layout->addWidget(buffer_alignment_edit_, row, 1);
|
||||
|
||||
row++;
|
||||
|
||||
layout->addWidget(new QLabel(tr("Buffer Count")), row, 0);
|
||||
|
||||
buffer_count_edit_ = new QSpinBox();
|
||||
buffer_count_edit_->setMinimum(0);
|
||||
buffer_count_edit_->setMaximum(INT_MAX); // Technically this is UINT32_MAX but QSpinBox only supports int
|
||||
layout->addWidget(buffer_count_edit_, row, 1);
|
||||
|
||||
outer->addStretch();
|
||||
}
|
||||
|
||||
void MxHdPanel::OnOpeningData(Data *data)
|
||||
{
|
||||
MxHd *mxhd = static_cast<MxHd *>(data);
|
||||
|
||||
uint16_t major_ver = mxhd->dwVersion >> 16;
|
||||
uint16_t minor_ver = mxhd->dwVersion;
|
||||
|
||||
major_version_edit_->setValue(major_ver);
|
||||
minor_version_edit_->setValue(minor_ver);
|
||||
buffer_alignment_edit_->setValue(mxhd->dwBufferSize);
|
||||
buffer_count_edit_->setValue(mxhd->dwBufferCount);
|
||||
}
|
||||
|
||||
void MxHdPanel::OnClosingData(Data *data)
|
||||
{
|
||||
MxHd *mxhd = static_cast<MxHd *>(data);
|
||||
|
||||
mxhd->dwVersion = (major_version_edit_->value() << 16 | (minor_version_edit_->value() & 0xFFFF));
|
||||
mxhd->dwBufferSize = buffer_alignment_edit_->value();
|
||||
mxhd->dwBufferCount = buffer_count_edit_->value();
|
||||
}
|
32
app/panels/mxhd.h
Normal file
32
app/panels/mxhd.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef MXHDPANEL_H
|
||||
#define MXHDPANEL_H
|
||||
|
||||
#include <data/mxhd.h>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
|
||||
#include "panel.h"
|
||||
|
||||
class MxHdPanel : public Panel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MxHdPanel(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
protected:
|
||||
virtual void OnOpeningData(Data *data) override;
|
||||
virtual void OnClosingData(Data *data) override;
|
||||
|
||||
private:
|
||||
QSpinBox *major_version_edit_;
|
||||
QSpinBox *minor_version_edit_;
|
||||
QSpinBox *buffer_alignment_edit_;
|
||||
QSpinBox *buffer_count_edit_;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // MXHDPANEL_H
|
21
app/panels/panel.cpp
Normal file
21
app/panels/panel.cpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "panel.h"
|
||||
|
||||
Panel::Panel(QWidget *parent)
|
||||
: QWidget{parent},
|
||||
data_(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Panel::SetData(Data *data)
|
||||
{
|
||||
if (data_) {
|
||||
OnClosingData(data_);
|
||||
}
|
||||
|
||||
data_ = data;
|
||||
|
||||
if (data_) {
|
||||
OnOpeningData(data_);
|
||||
}
|
||||
}
|
27
app/panels/panel.h
Normal file
27
app/panels/panel.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef PANEL_H
|
||||
#define PANEL_H
|
||||
|
||||
#include <data/data.h>
|
||||
#include <QWidget>
|
||||
|
||||
class Panel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Panel(QWidget *parent = nullptr);
|
||||
|
||||
Data *GetData() const { return data_; }
|
||||
void SetData(Data *data);
|
||||
|
||||
signals:
|
||||
|
||||
protected:
|
||||
virtual void OnOpeningData(Data *data){}
|
||||
virtual void OnClosingData(Data *data){}
|
||||
|
||||
private:
|
||||
Data *data_;
|
||||
|
||||
};
|
||||
|
||||
#endif // PANEL_H
|
|
@ -1,9 +1,13 @@
|
|||
add_library(libweaver SHARED
|
||||
option(LIBWEAVER_BUILD_DOXYGEN "Build Doxygen documentation" OFF)
|
||||
|
||||
set(LIBWEAVER_SOURCES
|
||||
# Data types
|
||||
data/data.cpp
|
||||
data/data.h
|
||||
data/generic.cpp
|
||||
data/generic.h
|
||||
data/mxhd.cpp
|
||||
data/mxhd.h
|
||||
data/mxst.cpp
|
||||
data/mxst.h
|
||||
data/riff.cpp
|
||||
|
@ -18,8 +22,21 @@ add_library(libweaver SHARED
|
|||
types.h
|
||||
)
|
||||
|
||||
add_library(libweaver SHARED
|
||||
${LIBWEAVER_SOURCES}
|
||||
)
|
||||
|
||||
target_compile_definitions(libweaver PRIVATE LIBWEAVER_LIBRARY)
|
||||
set_target_properties(libweaver PROPERTIES
|
||||
CXX_STANDARD 98
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
|
||||
if(LIBWEAVER_BUILD_DOXYGEN)
|
||||
find_package(Doxygen)
|
||||
set(DOXYGEN_PROJECT_NAME "libweaver")
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/docs")
|
||||
set(DOXYGEN_EXTRACT_ALL "YES")
|
||||
set(DOXYGEN_EXTRACT_PRIVATE "YES")
|
||||
doxygen_add_docs(docs ALL ${LIBWEAVER_SOURCES})
|
||||
endif()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "data/generic.h"
|
||||
#include "data/mxhd.h"
|
||||
#include "data/mxst.h"
|
||||
#include "data/riff.h"
|
||||
|
||||
|
@ -140,6 +141,10 @@ Data *Chunk::CreateDataFromID(u32 id)
|
|||
return new RIFFData();
|
||||
case MxSt:
|
||||
return new MxStData();
|
||||
case MxHd:
|
||||
return new ::MxHd();
|
||||
case pad_:
|
||||
return new GenericData();
|
||||
}
|
||||
|
||||
return new GenericData();
|
||||
|
@ -154,6 +159,10 @@ const char *Chunk::GetTypeDescription(Type type)
|
|||
return "List of sub-elements";
|
||||
case MxSt:
|
||||
return "MxStreamer";
|
||||
case MxHd:
|
||||
return "Interleaf Header";
|
||||
case pad_:
|
||||
return "Padding";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
|
|
|
@ -14,7 +14,9 @@ public:
|
|||
{
|
||||
RIFF = 0x46464952,
|
||||
LIST = 0x5453494c,
|
||||
MxSt = 0x7453784d
|
||||
MxSt = 0x7453784d,
|
||||
MxHd = 0x6448784d,
|
||||
pad_ = 0x20646170
|
||||
};
|
||||
|
||||
Chunk();
|
||||
|
@ -39,6 +41,7 @@ public:
|
|||
|
||||
Type type() const { return static_cast<Type>(id_); }
|
||||
const u32 &id() const { return id_; }
|
||||
Data *data() const { return data_; }
|
||||
|
||||
static Data *CreateDataFromID(u32 id);
|
||||
|
||||
|
|
22
lib/data/mxhd.cpp
Normal file
22
lib/data/mxhd.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "mxhd.h"
|
||||
|
||||
MxHd::MxHd()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MxHd::Read(std::ifstream &f, u32 sz)
|
||||
{
|
||||
// Read version information
|
||||
f.read((char *) &dwVersion, sizeof(dwVersion));
|
||||
|
||||
if (dwVersion == 0x00010000) { // 1.0
|
||||
// This MxHd is only 8 bytes long
|
||||
// FIXME: Not actually sure yet what the second 4 bytes are for, so we just read them into here
|
||||
f.read((char *) &dwBufferSize, sizeof(dwBufferSize));
|
||||
} else {
|
||||
// Version 2.2 has buffer size and buffer count, known due to the leaked .SS files on Korean
|
||||
f.read((char *) &dwBufferSize, sizeof(dwBufferSize));
|
||||
f.read((char *) &dwBufferCount, sizeof(dwBufferCount));
|
||||
}
|
||||
}
|
56
lib/data/mxhd.h
Normal file
56
lib/data/mxhd.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef MXHDDATA_H
|
||||
#define MXHDDATA_H
|
||||
|
||||
#include "data.h"
|
||||
|
||||
/**
|
||||
* @brief The main header section of an Interleaf file.
|
||||
*
|
||||
* MxHd is generally the first section to appear in an Interleaf file. It contains information
|
||||
* about the file as a whole, including version information and settings for how the file should
|
||||
* be streamed.
|
||||
*/
|
||||
class MxHd : public Data
|
||||
{
|
||||
public:
|
||||
MxHd();
|
||||
|
||||
virtual void Read(std::ifstream &f, u32 sz);
|
||||
|
||||
/**
|
||||
* @brief The version of this Interleaf file.
|
||||
*
|
||||
* This is stored as two 16-bit words inside a 32-bit dword - the high word being the major
|
||||
* version and the low word being the minor version.
|
||||
*
|
||||
* If the version is 0x00010000, as it is in Warhammer: Shadow of the Horned Rat and early builds
|
||||
* of LEGO Island, the resulting version is 1.0. If the version is 0x00020002, as it is in the
|
||||
* retail release of LEGO Island, the resulting version number is 2.2.
|
||||
*/
|
||||
u32 dwVersion;
|
||||
|
||||
/**
|
||||
* @brief The amount of data to read from disk at a time
|
||||
*
|
||||
* MxStreamer will read data from the file in chunks of this size. This means all sections of the
|
||||
* file must be aligned around multiples of this number, i.e. a section starting before a multiple
|
||||
* of this number must either end before it if possible, or padding should be used to make it
|
||||
* start immediately on one. If dwBufferSize is 0x20000, sections must not cross 0x20000, 0x40000,
|
||||
* 0x60000, 0x80000, etc. If a section does, it will cause an out of bounds read as the game
|
||||
* tries to read past the buffer that it's allocated and read into.
|
||||
*/
|
||||
u32 dwBufferSize;
|
||||
|
||||
/**
|
||||
* @brief Buffer number
|
||||
*
|
||||
* It is currently not known exactly what this value does. Source .SS files leaked on the Korean
|
||||
* ISO call it "buffersNum", implying it's the number of buffers to read at a time (in tandem with
|
||||
* dwBufferSize), however that behavior has not been tested yet. This field also does not exist
|
||||
* on version 1.0 SI files.
|
||||
*/
|
||||
u32 dwBufferCount;
|
||||
|
||||
};
|
||||
|
||||
#endif // MXHDDATA_H
|
Loading…
Reference in a new issue