mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-20 11:47:45 +00:00
Use physis in mdlviewer
This commit is contained in:
parent
7a4c5efbf3
commit
2b79c33d1f
7 changed files with 117 additions and 112 deletions
|
@ -9,13 +9,13 @@ target_include_directories(mdlviewer
|
||||||
PUBLIC
|
PUBLIC
|
||||||
include)
|
include)
|
||||||
target_link_libraries(mdlviewer PUBLIC
|
target_link_libraries(mdlviewer PUBLIC
|
||||||
libxiv
|
|
||||||
${LIBRARIES}
|
${LIBRARIES}
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
renderer
|
renderer
|
||||||
assimp::assimp
|
assimp::assimp
|
||||||
magic_enum)
|
magic_enum
|
||||||
|
physis z)
|
||||||
|
|
||||||
install(TARGETS mdlviewer
|
install(TARGETS mdlviewer
|
||||||
DESTINATION "${INSTALL_BIN_PATH}")
|
DESTINATION "${INSTALL_BIN_PATH}")
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
#include "types/slot.h"
|
|
||||||
#include "types/race.h"
|
|
||||||
#include "havokxmlparser.h"
|
|
||||||
|
|
||||||
struct ModelInfo {
|
struct ModelInfo {
|
||||||
int primaryID;
|
int primaryID;
|
||||||
|
@ -25,31 +23,39 @@ class StandaloneWindow;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
public:
|
public:
|
||||||
MainWindow(GameData& data);
|
MainWindow(GameData* data);
|
||||||
|
|
||||||
void exportModel(Model& model, Skeleton& skeleton, QString fileName);
|
void exportModel(physis_MDL& model, physis_Skeleton& skeleton, QString fileName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadInitialGearInfo(GearInfo& info);
|
void loadInitialGearInfo(GearInfo& info);
|
||||||
void reloadGearModel();
|
void reloadGearModel();
|
||||||
void reloadGearAppearance();
|
void reloadGearAppearance();
|
||||||
|
void calculate_bone_inverse_pose(physis_Skeleton& skeleton, physis_Bone& bone, physis_Bone* parent_bone);
|
||||||
|
void calculate_bone(physis_Skeleton& skeleton, physis_Bone& bone, const physis_Bone* parent_bone);
|
||||||
|
|
||||||
std::vector<GearInfo> gears;
|
std::vector<GearInfo> gears;
|
||||||
|
|
||||||
struct LoadedGear {
|
struct LoadedGear {
|
||||||
GearInfo* gearInfo;
|
GearInfo* gearInfo;
|
||||||
Model model;
|
physis_MDL model;
|
||||||
RenderModel renderModel;
|
RenderModel renderModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BoneExtra {
|
||||||
|
glm::mat4 localTransform, finalTransform, inversePose;
|
||||||
|
};
|
||||||
|
|
||||||
LoadedGear loadedGear;
|
LoadedGear loadedGear;
|
||||||
|
|
||||||
QComboBox* raceCombo, *lodCombo;
|
QComboBox* raceCombo, *lodCombo;
|
||||||
|
|
||||||
Race currentRace = Race::HyurMidlanderMale;
|
Race currentRace = Race::Hyur;
|
||||||
|
Subrace currentSubrace = Subrace::Midlander;
|
||||||
|
Gender currentGender = Gender::Male;
|
||||||
int currentLod = 0;
|
int currentLod = 0;
|
||||||
glm::vec3 currentScale = glm::vec3(1);
|
glm::vec3 currentScale = glm::vec3(1);
|
||||||
Bone* currentEditedBone = nullptr;
|
physis_Bone* currentEditedBone = nullptr;
|
||||||
|
|
||||||
GameData& data;
|
GameData& data;
|
||||||
|
|
||||||
|
@ -57,5 +63,6 @@ private:
|
||||||
VulkanWindow* vkWindow;
|
VulkanWindow* vkWindow;
|
||||||
StandaloneWindow* standaloneWindow;
|
StandaloneWindow* standaloneWindow;
|
||||||
|
|
||||||
Skeleton skeleton;
|
physis_Skeleton skeleton;
|
||||||
|
std::vector<BoneExtra> extraBone;
|
||||||
};
|
};
|
|
@ -1,14 +1,12 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "gamedata.h"
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
GameData data(argv[1]);
|
MainWindow w(physis_gamedata_initialize(argv[1]));
|
||||||
|
|
||||||
MainWindow w(data);
|
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|
|
@ -22,13 +22,9 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
|
#include <physis.hpp>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "gamedata.h"
|
|
||||||
#include "exhparser.h"
|
|
||||||
#include "exdparser.h"
|
|
||||||
#include "mdlparser.h"
|
|
||||||
#include "equipment.h"
|
|
||||||
#include "glm/glm.hpp"
|
|
||||||
#include "vec3edit.h"
|
#include "vec3edit.h"
|
||||||
|
|
||||||
#ifndef USE_STANDALONE_WINDOW
|
#ifndef USE_STANDALONE_WINDOW
|
||||||
|
@ -86,25 +82,26 @@ private:
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void calculate_bone_inverse_pose(Skeleton& skeleton, Bone& bone, Bone* parent_bone) {
|
void MainWindow::calculate_bone_inverse_pose(physis_Skeleton& skeleton, physis_Bone& bone, physis_Bone* parent_bone) {
|
||||||
const glm::mat4 parentMatrix = parent_bone == nullptr ? glm::mat4(1.0f) : parent_bone->inversePose;
|
const glm::mat4 parentMatrix = parent_bone == nullptr ? glm::mat4(1.0f) : extraBone[parent_bone->index].inversePose;
|
||||||
|
|
||||||
glm::mat4 local(1.0f);
|
glm::mat4 local(1.0f);
|
||||||
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
|
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
|
||||||
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
|
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
|
||||||
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
|
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
|
||||||
|
|
||||||
bone.inversePose = parentMatrix * local;
|
extraBone[bone.index].inversePose = parentMatrix * local;
|
||||||
|
|
||||||
for(auto& b : skeleton.bones) {
|
for(int i = 0; i < skeleton.num_bones; i++) {
|
||||||
if(b.parent != nullptr && b.parent->name == bone.name)
|
if(skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0) {
|
||||||
calculate_bone_inverse_pose(skeleton, b, &bone);
|
calculate_bone_inverse_pose(skeleton, skeleton.bones[i], &bone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addItem(Skeleton& skeleton, Bone& bone, QTreeWidget* widget, QTreeWidgetItem* parent_item = nullptr) {
|
void addItem(physis_Skeleton& skeleton, physis_Bone& bone, QTreeWidget* widget, QTreeWidgetItem* parent_item = nullptr) {
|
||||||
auto item = new QTreeWidgetItem();
|
auto item = new QTreeWidgetItem();
|
||||||
item->setText(0, bone.name.c_str());
|
item->setText(0, bone.name);
|
||||||
|
|
||||||
if(parent_item == nullptr) {
|
if(parent_item == nullptr) {
|
||||||
widget->addTopLevelItem(item);
|
widget->addTopLevelItem(item);
|
||||||
|
@ -112,13 +109,13 @@ void addItem(Skeleton& skeleton, Bone& bone, QTreeWidget* widget, QTreeWidgetIte
|
||||||
parent_item->addChild(item);
|
parent_item->addChild(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& b : skeleton.bones) {
|
for(int i = 0; i < skeleton.num_bones; i++) {
|
||||||
if(b.parent != nullptr && b.parent->name == bone.name)
|
if(skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0)
|
||||||
addItem(skeleton, b, widget, item);
|
addItem(skeleton, skeleton.bones[i], widget, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData& data) : data(data) {
|
MainWindow::MainWindow(GameData* in_data) : data(*in_data) {
|
||||||
setWindowTitle("mdlviewer");
|
setWindowTitle("mdlviewer");
|
||||||
setMinimumSize(QSize(640, 480));
|
setMinimumSize(QSize(640, 480));
|
||||||
|
|
||||||
|
@ -131,7 +128,9 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
"~",
|
"~",
|
||||||
"FFXIV Model File (*.mdl)");
|
"FFXIV Model File (*.mdl)");
|
||||||
|
|
||||||
loadedGear.model = parseMDL(read_file_to_buffer(fileName.toStdString()));
|
auto buffer = physis_read_file(fileName.toStdString().c_str());
|
||||||
|
|
||||||
|
loadedGear.model = physis_mdl_parse(buffer.size, buffer.data);
|
||||||
|
|
||||||
reloadGearAppearance();
|
reloadGearAppearance();
|
||||||
});
|
});
|
||||||
|
@ -160,20 +159,20 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
gears.push_back(info);
|
gears.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto exh = *data.readExcelSheet("Item");
|
auto exh = physis_gamedata_read_excel_sheet_header(&data, "Item");
|
||||||
|
auto exd = physis_gamedata_read_excel_sheet(&data, "Item", exh, Language::English, 1);
|
||||||
|
|
||||||
auto path = getEXDFilename(exh, "item", getLanguageCode(Language::English), exh.pages[1]);
|
for(int i = 0; i < exd.row_count; i++) {
|
||||||
auto exd = readEXD(exh, *data.extractFile("exd/" + path), exh.pages[1]);
|
const auto row = exd.row_data[i];
|
||||||
for(auto row : exd.rows) {
|
auto primaryModel = row.column_data[47].u_int64._0;
|
||||||
auto primaryModel = row.data[47].uint64Data;
|
auto secondaryModel = row.column_data[48].u_int64._0;
|
||||||
auto secondaryModel = row.data[48].uint64Data;
|
|
||||||
|
|
||||||
int16_t parts[4];
|
int16_t parts[4];
|
||||||
memcpy(parts, &primaryModel, sizeof(int16_t) * 4);
|
memcpy(parts, &primaryModel, sizeof(int16_t) * 4);
|
||||||
|
|
||||||
GearInfo info = {};
|
GearInfo info = {};
|
||||||
info.name = row.data[9].data;
|
info.name = row.column_data[9].string._0;
|
||||||
info.slot = *get_slot_from_id(row.data[17].uint64Data);
|
info.slot = physis_slot_from_id(row.column_data[17].u_int8._0);
|
||||||
info.modelInfo.primaryID = parts[0];
|
info.modelInfo.primaryID = parts[0];
|
||||||
|
|
||||||
gears.push_back(info);
|
gears.push_back(info);
|
||||||
|
@ -243,7 +242,7 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
"model.fbx",
|
"model.fbx",
|
||||||
tr("FBX Files (*.fbx)"));
|
tr("FBX Files (*.fbx)"));
|
||||||
|
|
||||||
Model model;
|
physis_MDL model;
|
||||||
#ifdef USE_STANDALONE_WINDOW
|
#ifdef USE_STANDALONE_WINDOW
|
||||||
model = standaloneWindow->models[0].model;
|
model = standaloneWindow->models[0].model;
|
||||||
#else
|
#else
|
||||||
|
@ -263,11 +262,12 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
skeleton = parseHavokXML("test.xml");
|
skeleton = physis_skeleton_from_skel(physis_read_file("c0101b0001.skel"));
|
||||||
|
extraBone.resize(skeleton.num_bones);
|
||||||
calculate_bone_inverse_pose(skeleton, *skeleton.root_bone, nullptr);
|
calculate_bone_inverse_pose(skeleton, *skeleton.root_bone, nullptr);
|
||||||
|
|
||||||
auto boneListWidget = new QTreeWidget();
|
auto boneListWidget = new QTreeWidget();
|
||||||
for(auto& bone : skeleton.bones) {
|
for(auto& bone : extraBone) {
|
||||||
bone.inversePose = glm::inverse(bone.inversePose);
|
bone.inversePose = glm::inverse(bone.inversePose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,10 +276,10 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
boneListWidget->setMaximumWidth(200);
|
boneListWidget->setMaximumWidth(200);
|
||||||
|
|
||||||
connect(boneListWidget, &QTreeWidget::itemClicked, [this](QTreeWidgetItem* item, int column) {
|
connect(boneListWidget, &QTreeWidget::itemClicked, [this](QTreeWidgetItem* item, int column) {
|
||||||
for(auto& bone : skeleton.bones) {
|
for(int i = 0; i < skeleton.num_bones; i++) {
|
||||||
if(bone.name == item->text(column).toStdString()) {
|
if(strcmp(skeleton.bones[i].name, item->text(column).toStdString().c_str()) == 0) {
|
||||||
currentScale = glm::make_vec3(bone.scale.data());
|
currentScale = glm::make_vec3(skeleton.bones[i].scale);
|
||||||
currentEditedBone = &bone;
|
currentEditedBone = &skeleton.bones[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -288,22 +288,22 @@ MainWindow::MainWindow(GameData& data) : data(data) {
|
||||||
|
|
||||||
Vector3Edit* scaleEdit = new Vector3Edit(currentScale);
|
Vector3Edit* scaleEdit = new Vector3Edit(currentScale);
|
||||||
connect(scaleEdit, &Vector3Edit::onValueChanged, [this] {
|
connect(scaleEdit, &Vector3Edit::onValueChanged, [this] {
|
||||||
memcpy(currentEditedBone->scale.data(), glm::value_ptr(currentScale), sizeof(float) * 3);
|
memcpy(currentEditedBone->scale, glm::value_ptr(currentScale), sizeof(float) * 3);
|
||||||
reloadGearAppearance();
|
reloadGearAppearance();
|
||||||
});
|
});
|
||||||
layout->addWidget(scaleEdit);
|
layout->addWidget(scaleEdit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName) {
|
void MainWindow::exportModel(physis_MDL& model, physis_Skeleton& skeleton, QString fileName) {
|
||||||
Assimp::Exporter exporter;
|
Assimp::Exporter exporter;
|
||||||
|
|
||||||
aiScene scene;
|
aiScene scene;
|
||||||
scene.mRootNode = new aiNode();
|
scene.mRootNode = new aiNode();
|
||||||
|
|
||||||
scene.mRootNode->mNumChildren = model.lods[0].parts.size() + 1; // plus one for the skeleton
|
scene.mRootNode->mNumChildren = model.lods[0].num_parts + 1; // plus one for the skeleton
|
||||||
scene.mRootNode->mChildren = new aiNode*[scene.mRootNode->mNumChildren];
|
scene.mRootNode->mChildren = new aiNode*[scene.mRootNode->mNumChildren];
|
||||||
|
|
||||||
scene.mNumMeshes = model.lods[0].parts.size();
|
scene.mNumMeshes = model.lods[0].num_parts;
|
||||||
scene.mMeshes = new aiMesh*[scene.mNumMeshes];
|
scene.mMeshes = new aiMesh*[scene.mNumMeshes];
|
||||||
|
|
||||||
auto skeleton_node = new aiNode();
|
auto skeleton_node = new aiNode();
|
||||||
|
@ -315,37 +315,37 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
|
|
||||||
std::vector<aiNode*> skeletonNodes;
|
std::vector<aiNode*> skeletonNodes;
|
||||||
|
|
||||||
for(int i = 0; i < model.affectedBoneNames.size(); i++) {
|
for(int i = 0; i < model.num_affected_bones; i++) {
|
||||||
auto& node = skeletonNodes.emplace_back();
|
auto& node = skeletonNodes.emplace_back();
|
||||||
node = new aiNode();
|
node = new aiNode();
|
||||||
node->mName = model.affectedBoneNames[i];
|
node->mName = model.affected_bone_names[i];
|
||||||
|
|
||||||
int real_bone_id = 0;
|
int real_bone_id = 0;
|
||||||
for(int k = 0; k < skeleton.bones.size(); k++) {
|
for(int k = 0; k < skeleton.num_bones; k++) {
|
||||||
if(skeleton.bones[k].name == model.affectedBoneNames[i]) {
|
if(strcmp(skeleton.bones[k].name, model.affected_bone_names[i]) == 0) {
|
||||||
real_bone_id = k;
|
real_bone_id = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->mChildren = new aiNode*[model.affectedBoneNames.size()];
|
node->mChildren = new aiNode*[model.num_affected_bones];
|
||||||
|
|
||||||
auto& real_bone = skeleton.bones[real_bone_id];
|
auto& real_bone = skeleton.bones[real_bone_id];
|
||||||
memcpy(&node->mTransformation, glm::value_ptr(real_bone.finalTransform), sizeof(aiMatrix4x4));
|
memcpy(&node->mTransformation, glm::value_ptr(extraBone[real_bone.index].finalTransform), sizeof(aiMatrix4x4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup parenting
|
// setup parenting
|
||||||
for(int i = 0; i < model.affectedBoneNames.size(); i++) {
|
for(int i = 0; i < model.num_affected_bones; i++) {
|
||||||
int real_bone_id = 0;
|
int real_bone_id = 0;
|
||||||
for(int k = 0; k < skeleton.bones.size(); k++) {
|
for(int k = 0; k < skeleton.num_bones; k++) {
|
||||||
if(skeleton.bones[k].name == model.affectedBoneNames[i]) {
|
if(strcmp(skeleton.bones[k].name, model.affected_bone_names[i]) == 0) {
|
||||||
real_bone_id = k;
|
real_bone_id = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& real_bone = skeleton.bones[real_bone_id];
|
auto& real_bone = skeleton.bones[real_bone_id];
|
||||||
if(real_bone.parent != nullptr) {
|
if(real_bone.parent_bone != nullptr) {
|
||||||
for(int k = 0; k < model.affectedBoneNames.size(); k++) {
|
for(int k = 0; k < model.num_affected_bones; k++) {
|
||||||
if(model.affectedBoneNames[k] == real_bone.parent->name) {
|
if(strcmp(model.affected_bone_names[k], real_bone.parent_bone->name) == 0) {
|
||||||
skeletonNodes[i]->mParent = skeletonNodes[k];
|
skeletonNodes[i]->mParent = skeletonNodes[k];
|
||||||
skeletonNodes[k]->mChildren[skeletonNodes[k]->mNumChildren++] = skeletonNodes[i];
|
skeletonNodes[k]->mChildren[skeletonNodes[k]->mNumChildren++] = skeletonNodes[i];
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
|
|
||||||
skeleton_node->mChildren[0] = new aiNode();
|
skeleton_node->mChildren[0] = new aiNode();
|
||||||
skeleton_node->mChildren[0]->mName = "root";
|
skeleton_node->mChildren[0]->mName = "root";
|
||||||
skeleton_node->mChildren[0]->mChildren = new aiNode*[model.affectedBoneNames.size()];
|
skeleton_node->mChildren[0]->mChildren = new aiNode*[model.num_affected_bones];
|
||||||
|
|
||||||
for(int i = 0; i < skeletonNodes.size(); i++) {
|
for(int i = 0; i < skeletonNodes.size(); i++) {
|
||||||
if(skeletonNodes[i]->mParent == nullptr) {
|
if(skeletonNodes[i]->mParent == nullptr) {
|
||||||
|
@ -363,7 +363,7 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < model.lods[0].parts.size(); i++) {
|
for(int i = 0; i < model.lods[0].num_parts; i++) {
|
||||||
scene.mMeshes[i] = new aiMesh();
|
scene.mMeshes[i] = new aiMesh();
|
||||||
scene.mMeshes[i]->mMaterialIndex = 0;
|
scene.mMeshes[i]->mMaterialIndex = 0;
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
node->mMeshes[0] = i;
|
node->mMeshes[0] = i;
|
||||||
|
|
||||||
auto mesh = scene.mMeshes[i];
|
auto mesh = scene.mMeshes[i];
|
||||||
mesh->mNumVertices = model.lods[0].parts[i].vertices.size();
|
mesh->mNumVertices = model.lods[0].parts[i].num_vertices;
|
||||||
mesh->mVertices = new aiVector3D [mesh->mNumVertices];
|
mesh->mVertices = new aiVector3D [mesh->mNumVertices];
|
||||||
mesh->mNormals = new aiVector3D [mesh->mNumVertices];
|
mesh->mNormals = new aiVector3D [mesh->mNumVertices];
|
||||||
mesh->mTextureCoords[0] = new aiVector3D [mesh->mNumVertices];
|
mesh->mTextureCoords[0] = new aiVector3D [mesh->mNumVertices];
|
||||||
|
@ -386,7 +386,7 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
mesh->mTextureCoords[0][j] = aiVector3D(vertex.uv[0], vertex.uv[1], 0.0f);
|
mesh->mTextureCoords[0][j] = aiVector3D(vertex.uv[0], vertex.uv[1], 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->mNumBones = model.affectedBoneNames.size();
|
mesh->mNumBones = model.num_affected_bones;
|
||||||
mesh->mBones = new aiBone*[mesh->mNumBones];
|
mesh->mBones = new aiBone*[mesh->mNumBones];
|
||||||
for(int j = 0; j < mesh->mNumBones; j++) {
|
for(int j = 0; j < mesh->mNumBones; j++) {
|
||||||
int real_bone_id = j;
|
int real_bone_id = j;
|
||||||
|
@ -397,27 +397,27 @@ void MainWindow::exportModel(Model& model, Skeleton& skeleton, QString fileName)
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
mesh->mBones[j] = new aiBone();
|
mesh->mBones[j] = new aiBone();
|
||||||
mesh->mBones[j]->mName = model.affectedBoneNames[j];
|
mesh->mBones[j]->mName = model.affected_bone_names[j];
|
||||||
mesh->mBones[j]->mNumWeights = mesh->mNumVertices * 4;
|
mesh->mBones[j]->mNumWeights = mesh->mNumVertices * 4;
|
||||||
mesh->mBones[j]->mWeights = new aiVertexWeight[mesh->mBones[j]->mNumWeights];
|
mesh->mBones[j]->mWeights = new aiVertexWeight[mesh->mBones[j]->mNumWeights];
|
||||||
mesh->mBones[j]->mNode = skeleton_node->mChildren[j];
|
mesh->mBones[j]->mNode = skeleton_node->mChildren[j];
|
||||||
|
|
||||||
for(int k = 0; k < mesh->mNumVertices; k++) {
|
for(int k = 0; k < mesh->mNumVertices; k++) {
|
||||||
for(int z = 0; z < 4; z++) {
|
for(int z = 0; z < 4; z++) {
|
||||||
if (model.lods[0].parts[i].vertices[k].boneIds[z] == real_bone_id) {
|
if (model.lods[0].parts[i].vertices[k].bone_id[z] == real_bone_id) {
|
||||||
auto &weight = mesh->mBones[j]->mWeights[k * 4 + z];
|
auto &weight = mesh->mBones[j]->mWeights[k * 4 + z];
|
||||||
weight.mVertexId = k;
|
weight.mVertexId = k;
|
||||||
weight.mWeight = model.lods[0].parts[i].vertices[k].boneWeights[z];
|
weight.mWeight = model.lods[0].parts[i].vertices[k].bone_weight[z];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->mNumFaces = model.lods[0].parts[i].indices.size() / 3;
|
mesh->mNumFaces = model.lods[0].parts[i].num_indices / 3;
|
||||||
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
|
|
||||||
int lastFace = 0;
|
int lastFace = 0;
|
||||||
for(int j = 0; j < model.lods[0].parts[i].indices.size(); j += 3) {
|
for(int j = 0; j < model.lods[0].parts[i].num_indices; j += 3) {
|
||||||
aiFace& face = mesh->mFaces[lastFace++];
|
aiFace& face = mesh->mFaces[lastFace++];
|
||||||
|
|
||||||
face.mNumIndices = 3;
|
face.mNumIndices = 3;
|
||||||
|
@ -441,44 +441,45 @@ void MainWindow::loadInitialGearInfo(GearInfo& info) {
|
||||||
|
|
||||||
raceCombo->clear();
|
raceCombo->clear();
|
||||||
for(auto [race, race_name] : magic_enum::enum_entries<Race>()) {
|
for(auto [race, race_name] : magic_enum::enum_entries<Race>()) {
|
||||||
if(data.exists(build_equipment_path(loadedGear.gearInfo->modelInfo.primaryID, race, loadedGear.gearInfo->slot)))
|
auto equip_path = physis_build_equipment_path(loadedGear.gearInfo->modelInfo.primaryID, race, currentSubrace, currentGender, loadedGear.gearInfo->slot);
|
||||||
raceCombo->addItem(race_name.data());
|
|
||||||
|
if(physis_gamedata_exists(&data, equip_path))
|
||||||
|
raceCombo->addItem(race_name.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
currentLod = 0;
|
currentLod = 0;
|
||||||
currentRace = Race::HyurMidlanderMale;
|
currentRace = Race::Hyur;
|
||||||
|
|
||||||
reloadGearModel();
|
reloadGearModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::reloadGearModel() {
|
void MainWindow::reloadGearModel() {
|
||||||
auto mdl_data = data.extractFile(build_equipment_path(loadedGear.gearInfo->modelInfo.primaryID, currentRace, loadedGear.gearInfo->slot));
|
auto mdl_data = physis_gamedata_extract_file(&data, physis_build_equipment_path(loadedGear.gearInfo->modelInfo.primaryID, currentRace, currentSubrace, currentGender, loadedGear.gearInfo->slot));
|
||||||
if(mdl_data == std::nullopt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
loadedGear.model = parseMDL(*mdl_data);
|
loadedGear.model = physis_mdl_parse(mdl_data.size, mdl_data.data);
|
||||||
|
|
||||||
lodCombo->clear();
|
lodCombo->clear();
|
||||||
for(int i = 0; i < loadedGear.model.lods.size(); i++)
|
for(int i = 0; i < loadedGear.model.num_lod; i++)
|
||||||
lodCombo->addItem(QString::number(i));
|
lodCombo->addItem(QString::number(i));
|
||||||
|
|
||||||
reloadGearAppearance();
|
reloadGearAppearance();
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculate_bone(Skeleton& skeleton, Bone& bone, const Bone* parent_bone) {
|
void MainWindow::calculate_bone(physis_Skeleton& skeleton, physis_Bone& bone, const physis_Bone* parent_bone) {
|
||||||
const glm::mat4 parent_matrix = parent_bone == nullptr ? glm::mat4(1.0f) : parent_bone->localTransform;
|
const glm::mat4 parent_matrix = parent_bone == nullptr ? glm::mat4(1.0f) : extraBone[parent_bone->index].localTransform;
|
||||||
|
|
||||||
glm::mat4 local = glm::mat4(1.0f);
|
glm::mat4 local = glm::mat4(1.0f);
|
||||||
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
|
local = glm::translate(local, glm::vec3(bone.position[0], bone.position[1], bone.position[2]));
|
||||||
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
|
local *= glm::mat4_cast(glm::quat(bone.rotation[3], bone.rotation[0], bone.rotation[1], bone.rotation[2]));
|
||||||
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
|
local = glm::scale(local, glm::vec3(bone.scale[0], bone.scale[1], bone.scale[2]));
|
||||||
|
|
||||||
bone.localTransform = parent_matrix * local;
|
extraBone[bone.index].localTransform = parent_matrix * local;
|
||||||
bone.finalTransform = bone.localTransform * bone.inversePose;
|
extraBone[bone.index].finalTransform = extraBone[bone.index].localTransform * extraBone[bone.index].inversePose;
|
||||||
|
|
||||||
for(auto& b : skeleton.bones) {
|
for(int i = 0; i < skeleton.num_bones; i++) {
|
||||||
if(b.parent != nullptr && b.parent->name == bone.name)
|
if(skeleton.bones[i].parent_bone != nullptr && strcmp(skeleton.bones[i].parent_bone->name, bone.name) == 0) {
|
||||||
calculate_bone(skeleton, b, &bone);
|
calculate_bone(skeleton, skeleton.bones[i], &bone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,15 +490,15 @@ void MainWindow::reloadGearAppearance() {
|
||||||
|
|
||||||
// we want to map the actual affected bones to bone ids
|
// we want to map the actual affected bones to bone ids
|
||||||
std::map<int, int> boneMapping;
|
std::map<int, int> boneMapping;
|
||||||
for(int i = 0; i < loadedGear.model.affectedBoneNames.size(); i++) {
|
for(int i = 0; i < loadedGear.model.num_affected_bones; i++) {
|
||||||
for(int k = 0; k < skeleton.bones.size(); k++) {
|
for(int k = 0; k < skeleton.num_bones; k++) {
|
||||||
if(skeleton.bones[k].name == loadedGear.model.affectedBoneNames[i])
|
if(strcmp(skeleton.bones[k].name, loadedGear.model.affected_bone_names[i]) == 0)
|
||||||
boneMapping[i] = k;
|
boneMapping[i] = k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < loadedGear.model.affectedBoneNames.size(); i++) {
|
for(int i = 0; i < loadedGear.model.num_affected_bones; i++) {
|
||||||
loadedGear.renderModel.boneData[i] = skeleton.bones[boneMapping[i]].finalTransform;
|
loadedGear.renderModel.boneData[i] = extraBone[boneMapping[i]].finalTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USE_STANDALONE_WINDOW
|
#ifndef USE_STANDALONE_WINDOW
|
||||||
|
|
|
@ -16,7 +16,7 @@ endif()
|
||||||
|
|
||||||
add_library(renderer src/renderer.cpp ${EXTRA_SRC})
|
add_library(renderer src/renderer.cpp ${EXTRA_SRC})
|
||||||
target_include_directories(renderer PUBLIC include)
|
target_include_directories(renderer PUBLIC include)
|
||||||
target_link_libraries(renderer PUBLIC Vulkan::Vulkan fmt::fmt libxiv glm::glm ${EXTRA_LIBRARIES})
|
target_link_libraries(renderer PUBLIC Vulkan::Vulkan fmt::fmt physis z glm::glm ${EXTRA_LIBRARIES})
|
||||||
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
|
target_compile_definitions(renderer PUBLIC GLM_FORCE_RADIANS GLM_FORCE_DEPTH_ZERO_TO_ONE)
|
||||||
|
|
||||||
if(USE_STANDALONE_WINDOW)
|
if(USE_STANDALONE_WINDOW)
|
||||||
|
|
|
@ -5,19 +5,17 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <glm/ext/matrix_float4x4.hpp>
|
#include <glm/ext/matrix_float4x4.hpp>
|
||||||
|
|
||||||
#include "mdlparser.h"
|
#include <physis.hpp>
|
||||||
|
|
||||||
struct RenderPart {
|
struct RenderPart {
|
||||||
size_t numIndices;
|
size_t numIndices;
|
||||||
|
|
||||||
VkBuffer vertexBuffer, indexBuffer;
|
VkBuffer vertexBuffer, indexBuffer;
|
||||||
VkDeviceMemory vertexMemory, indexMemory;
|
VkDeviceMemory vertexMemory, indexMemory;
|
||||||
|
|
||||||
std::vector<PartSubmesh> submeshes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderModel {
|
struct RenderModel {
|
||||||
Model model;
|
physis_MDL model;
|
||||||
std::vector<RenderPart> parts;
|
std::vector<RenderPart> parts;
|
||||||
std::array<glm::mat4, 128> boneData;
|
std::array<glm::mat4, 128> boneData;
|
||||||
};
|
};
|
||||||
|
@ -32,7 +30,7 @@ public:
|
||||||
bool initSwapchain(VkSurfaceKHR surface, int width, int height);
|
bool initSwapchain(VkSurfaceKHR surface, int width, int height);
|
||||||
void resize(VkSurfaceKHR surface, int width, int height);
|
void resize(VkSurfaceKHR surface, int width, int height);
|
||||||
|
|
||||||
RenderModel addModel(const Model& model, int lod);
|
RenderModel addModel(const physis_MDL& model, int lod);
|
||||||
|
|
||||||
void render(std::vector<RenderModel> models);
|
void render(std::vector<RenderModel> models);
|
||||||
|
|
||||||
|
|
|
@ -442,7 +442,7 @@ void Renderer::render(std::vector<RenderModel> models) {
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr);
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr);
|
||||||
|
|
||||||
for(auto part : model.parts) {
|
for(const auto& part : model.parts) {
|
||||||
VkDeviceSize offsets[] = {0};
|
VkDeviceSize offsets[] = {0};
|
||||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets);
|
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets);
|
||||||
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16);
|
||||||
|
@ -554,21 +554,22 @@ uint32_t Renderer::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags pro
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderModel Renderer::addModel(const Model& model, int lod) {
|
RenderModel Renderer::addModel(const physis_MDL& model, int lod) {
|
||||||
RenderModel renderModel;
|
RenderModel renderModel;
|
||||||
renderModel.model = model;
|
renderModel.model = model;
|
||||||
|
|
||||||
if(lod < 0 || lod > model.lods.size())
|
if(lod < 0 || lod > model.num_lod)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
for(auto part : model.lods[lod].parts) {
|
for(int i = 0; i < model.lods[0].num_parts; i++) {
|
||||||
RenderPart renderPart;
|
RenderPart renderPart;
|
||||||
renderPart.submeshes = part.submeshes;
|
|
||||||
|
|
||||||
size_t vertexSize = part.vertices.size() * sizeof(Vertex);
|
const physis_Part part = model.lods[0].parts[i];
|
||||||
|
|
||||||
|
size_t vertexSize = part.num_vertices * sizeof(Vertex);
|
||||||
auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
auto[vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||||
|
|
||||||
size_t indexSize = part.indices.size() * sizeof(uint16_t);
|
size_t indexSize = part.num_indices * sizeof(uint16_t);
|
||||||
auto[indexBuffer, indexMemory] = createBuffer(indexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
auto[indexBuffer, indexMemory] = createBuffer(indexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
||||||
|
|
||||||
// copy vertex data
|
// copy vertex data
|
||||||
|
@ -576,7 +577,7 @@ RenderModel Renderer::addModel(const Model& model, int lod) {
|
||||||
void* mapped_data = nullptr;
|
void* mapped_data = nullptr;
|
||||||
vkMapMemory(device, vertexMemory, 0, vertexSize, 0, &mapped_data);
|
vkMapMemory(device, vertexMemory, 0, vertexSize, 0, &mapped_data);
|
||||||
|
|
||||||
memcpy(mapped_data, part.vertices.data(), vertexSize);
|
memcpy(mapped_data, part.vertices, vertexSize);
|
||||||
|
|
||||||
VkMappedMemoryRange range = {};
|
VkMappedMemoryRange range = {};
|
||||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
|
@ -592,7 +593,7 @@ RenderModel Renderer::addModel(const Model& model, int lod) {
|
||||||
void* mapped_data = nullptr;
|
void* mapped_data = nullptr;
|
||||||
vkMapMemory(device, indexMemory, 0, indexSize, 0, &mapped_data);
|
vkMapMemory(device, indexMemory, 0, indexSize, 0, &mapped_data);
|
||||||
|
|
||||||
memcpy(mapped_data, part.indices.data(), indexSize);
|
memcpy(mapped_data, part.indices, indexSize);
|
||||||
|
|
||||||
VkMappedMemoryRange range = {};
|
VkMappedMemoryRange range = {};
|
||||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||||
|
@ -603,7 +604,7 @@ RenderModel Renderer::addModel(const Model& model, int lod) {
|
||||||
vkUnmapMemory(device, indexMemory);
|
vkUnmapMemory(device, indexMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPart.numIndices = part.indices.size();
|
renderPart.numIndices = part.num_indices;
|
||||||
|
|
||||||
renderPart.vertexBuffer = vertexBuffer;
|
renderPart.vertexBuffer = vertexBuffer;
|
||||||
renderPart.vertexMemory = vertexMemory;
|
renderPart.vertexMemory = vertexMemory;
|
||||||
|
@ -648,12 +649,12 @@ void Renderer::initPipeline() {
|
||||||
VkVertexInputAttributeDescription boneWeightAttribute = {};
|
VkVertexInputAttributeDescription boneWeightAttribute = {};
|
||||||
boneWeightAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
boneWeightAttribute.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
boneWeightAttribute.location = 2;
|
boneWeightAttribute.location = 2;
|
||||||
boneWeightAttribute.offset = offsetof(Vertex, boneWeights);
|
boneWeightAttribute.offset = offsetof(Vertex, bone_weight);
|
||||||
|
|
||||||
VkVertexInputAttributeDescription boneIdAttribute = {};
|
VkVertexInputAttributeDescription boneIdAttribute = {};
|
||||||
boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT;
|
boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT;
|
||||||
boneIdAttribute.location = 3;
|
boneIdAttribute.location = 3;
|
||||||
boneIdAttribute.offset = offsetof(Vertex, boneIds);
|
boneIdAttribute.offset = offsetof(Vertex, bone_id);
|
||||||
|
|
||||||
std::array<VkVertexInputAttributeDescription, 4> attributes = {positionAttribute, normalAttribute, boneWeightAttribute, boneIdAttribute};
|
std::array<VkVertexInputAttributeDescription, 4> attributes = {positionAttribute, normalAttribute, boneWeightAttribute, boneIdAttribute};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue