Skip to content

Commit 0397ce4

Browse files
committed
Initial commit
0 parents  commit 0397ce4

File tree

8 files changed

+985
-0
lines changed

8 files changed

+985
-0
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "theory"]
2+
path = theory
3+
url = https://github.com/SDmodding/TheoryEngine/

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# PermToFBX
2+
A simple CLI tool that exports models from perm.bin to FBX format.
3+
4+
The tool automatically parses all loaded files and exports only the models.
5+
6+
If you want textures to be exported as well, you must load the texture specific files alongside the "model" files.
7+
8+
## Command-line Options
9+
10+
<table>
11+
<thead>
12+
<tr>
13+
<th>Option</th>
14+
<th>Description</th>
15+
<th>Example</th>
16+
</tr>
17+
</thead>
18+
<tbody>
19+
<tr>
20+
<td><code>-output=&lt;path&gt; [optional]</code></td>
21+
<td>Path where the models & textures should be exported.</td>
22+
<td><code>-output=some_folder</code></td>
23+
</tr>
24+
<tr>
25+
<td><code>-rig=&lt;name&gt; [optional]</code></td>
26+
<td>Uses specific rig while exporting models.</td>
27+
<td><code>-rig=BasicFemale</code></td>
28+
</tr>
29+
<tr>
30+
<td><code>-model=&lt;name&gt; [optional]</code></td>
31+
<td>Export only specific model with this name.</td>
32+
<td><code>-model=SANDRA_SKIN_BODY</code></td>
33+
</tr>
34+
</tbody>
35+
</table>

core.hh

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#pragma once
2+
#define BYTE4N_FLT(x) ((static_cast<f32>(x) / 255.f) * 2.f - 1.f)
3+
4+
namespace core
5+
{
6+
using namespace UFG;
7+
8+
const char* GetParamValue(const char* arg, const qString& param)
9+
{
10+
if (const char* find = qStringFindInsensitive(arg, param)) {
11+
return &find[param.Length()];
12+
}
13+
14+
return 0;
15+
}
16+
17+
bool IsPermFile(const qString& path)
18+
{
19+
qString path2 = path.ToLower();
20+
return (path2.EndsWith(".bin") && !path2.EndsWith(".temp.bin"));
21+
}
22+
23+
void LoadPermFiles(const qString& find_path)
24+
{
25+
WIN32_FIND_DATAA wFindData = { 0 };
26+
HANDLE hFind = FindFirstFileA(find_path, &wFindData);
27+
28+
if (hFind == INVALID_HANDLE_VALUE) {
29+
return;
30+
}
31+
32+
char* end = &find_path.mData[find_path.mLength - 2];
33+
bool recursive = (end[0] == '*' && end[1] == '*');
34+
35+
qString folder = find_path.GetFilePath() + "\\";
36+
37+
do
38+
{
39+
qString file_path = (folder + wFindData.cFileName);
40+
41+
if (wFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
42+
{
43+
if (wFindData.cFileName[0] == '.') {
44+
continue;
45+
}
46+
47+
if (recursive)
48+
{
49+
file_path += "\\**";
50+
LoadPermFiles(file_path);
51+
}
52+
53+
continue;
54+
}
55+
56+
if (IsPermFile(file_path)) {
57+
StreamResourceLoader::LoadResourceFile(file_path);
58+
}
59+
} while (FindNextFileA(hFind, &wFindData));
60+
61+
FindClose(hFind);
62+
}
63+
64+
Illusion::VertexStreamDescriptor* GetVertexStreamDescriptor(u32 name_uid)
65+
{
66+
auto streamDescriptors = Illusion::VertexStreamDescriptor::GetStreamDescriptors();
67+
for (auto streamDescriptor = streamDescriptors->begin(); streamDescriptor != streamDescriptors->end(); streamDescriptor = streamDescriptor->next())
68+
{
69+
if (streamDescriptor->mNameUID == name_uid) {
70+
return streamDescriptor;
71+
}
72+
}
73+
74+
return 0;
75+
}
76+
77+
Illusion::VertexStreamElement* GetVertexStreamElement(Illusion::VertexStreamDescriptor* stream_descriptor, Illusion::VertexStreamElementUsage usage)
78+
{
79+
for (int i = 0; stream_descriptor->GetTotalElements() > i; ++i)
80+
{
81+
auto stream_element = stream_descriptor->GetElement(i);
82+
if (stream_element && stream_element->mUsage == usage) {
83+
return stream_element;
84+
}
85+
}
86+
87+
return 0;
88+
}
89+
90+
void* GetVertexStreamData(Illusion::VertexStreamDescriptor* stream_descriptor, Illusion::VertexStreamElement* stream_element, Illusion::Buffer* vertex_buffer, u32 index)
91+
{
92+
return vertex_buffer->mData.Get(stream_element->mOffset + (stream_descriptor->GetStreamSize(stream_element->mStream) * index));
93+
}
94+
95+
void InitMeshHandles(Illusion::Mesh* mesh)
96+
{
97+
auto warehouse = qResourceWarehouse::Instance();
98+
99+
mesh->mMaterialHandle.mData = warehouse->DebugGet(RTypeUID_Material, mesh->mMaterialHandle.mNameUID);
100+
mesh->mIndexBufferHandle.mData = warehouse->DebugGet(RTypeUID_Buffer, mesh->mIndexBufferHandle.mNameUID);
101+
102+
for (auto& vertexBufferHandle : mesh->mVertexBufferHandles) {
103+
vertexBufferHandle.mData = warehouse->DebugGet(RTypeUID_Buffer, vertexBufferHandle.mNameUID);
104+
}
105+
}
106+
107+
bool ValidateBonesWithRig(RigResource* rig, Illusion::BonePalette* bone_palette)
108+
{
109+
auto skeleton = rig->mSkeleton;
110+
111+
for (u32 b = 0; bone_palette->mNumBones > b; ++b)
112+
{
113+
bool found = 0;
114+
u32 bone_uid = *bone_palette->mBoneUIDTable[b];
115+
116+
for (int i = 0; skeleton->m_bones.m_size > i; ++i)
117+
{
118+
auto bone = &skeleton->m_bones.m_data[i];
119+
if (qStringHashUpper32(bone->m_name) == bone_uid)
120+
{
121+
found = 1;
122+
break;
123+
}
124+
}
125+
126+
if (!found) {
127+
return 0;
128+
}
129+
}
130+
131+
return 1;
132+
}
133+
}

fbxmodel.hh

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#pragma once
2+
3+
class qFBXModel
4+
{
5+
public:
6+
fbxsdk::FbxScene* mScene = 0;
7+
8+
qFBXModel(fbxsdk::FbxManager* mgr)
9+
{
10+
mScene = fbxsdk::FbxScene::Create(mgr, "");
11+
12+
mScene->GetGlobalSettings().SetSystemUnit(FbxSystemUnit::m);
13+
}
14+
15+
~qFBXModel()
16+
{
17+
mScene->Destroy(1);
18+
}
19+
20+
bool Export(fbxsdk::FbxManager* mgr, const char* filename)
21+
{
22+
fbxsdk::FbxAxisSystem targetSystem(fbxsdk::FbxAxisSystem::EUpVector::eYAxis, fbxsdk::FbxAxisSystem::EFrontVector::eParityOdd, fbxsdk::FbxAxisSystem::eRightHanded);
23+
targetSystem.DeepConvertScene(mScene);
24+
25+
FbxExporter* exporter = FbxExporter::Create(mgr, "");
26+
27+
bool exported = exporter->Initialize(filename, -1, mgr->GetIOSettings());
28+
if (!exporter->Export(mScene)) {
29+
exported = 0;
30+
}
31+
32+
exporter->Destroy();
33+
return exported;
34+
}
35+
36+
fbxsdk::FbxMesh* CreateMesh(const char* name, int num_cp)
37+
{
38+
auto node = fbxsdk::FbxNode::Create(mScene, name);
39+
auto mesh = fbxsdk::FbxMesh::Create(mScene, name);
40+
41+
node->SetNodeAttribute(mesh);
42+
mesh->InitControlPoints(num_cp);
43+
44+
mScene->GetRootNode()->AddChild(node);
45+
46+
return mesh;
47+
}
48+
49+
fbxsdk::FbxSurfacePhong* CreateDiffuseMaterial(const char* name, const char* filename, const char* uvset)
50+
{
51+
auto fileTexture = fbxsdk::FbxFileTexture::Create(mScene, name);
52+
fileTexture->SetFileName(filename);
53+
fileTexture->SetTextureUse(fbxsdk::FbxTexture::eStandard);
54+
fileTexture->SetMappingType(fbxsdk::FbxTexture::eUV);
55+
fileTexture->SetMaterialUse(fbxsdk::FbxFileTexture::eModelMaterial);
56+
fileTexture->SetSwapUV(0);
57+
fileTexture->UVSet.Set(uvset);
58+
59+
auto material = fbxsdk::FbxSurfacePhong::Create(mScene, name);
60+
material->Diffuse.Set(fbxsdk::FbxDouble3(1, 1, 1));
61+
material->DiffuseFactor.Set(1.0);
62+
material->Diffuse.ConnectSrcObject(fileTexture);
63+
64+
return material;
65+
}
66+
67+
fbxsdk::FbxSurfacePhong* CreateBumpMaterial(const char* name, const char* filename, const char* uvset)
68+
{
69+
auto fileTexture = fbxsdk::FbxFileTexture::Create(mScene, name);
70+
fileTexture->SetFileName(filename);
71+
fileTexture->SetTextureUse(fbxsdk::FbxTexture::eBumpNormalMap);
72+
fileTexture->SetMappingType(fbxsdk::FbxTexture::eUV);
73+
fileTexture->SetMaterialUse(fbxsdk::FbxFileTexture::eModelMaterial);
74+
fileTexture->SetSwapUV(0);
75+
fileTexture->UVSet.Set(uvset);
76+
77+
auto layeredTexture = fbxsdk::FbxLayeredTexture::Create(mScene, "");
78+
layeredTexture->SetTextureUse(fbxsdk::FbxLayeredTexture::eBumpNormalMap);
79+
layeredTexture->ConnectSrcObject(fileTexture);
80+
81+
auto material = fbxsdk::FbxSurfacePhong::Create(mScene, name);
82+
material->Bump.Set(fbxsdk::FbxDouble3(1, 1, 1));
83+
material->Bump.ConnectSrcObject(fileTexture);
84+
85+
return material;
86+
}
87+
88+
fbxsdk::FbxSkin* CreateSkin(const char* name)
89+
{
90+
return fbxsdk::FbxSkin::Create(mScene, name);
91+
}
92+
93+
fbxsdk::FbxNode* CreateLimbNode(const char* name, const fbxsdk::FbxAMatrix& matrix)
94+
{
95+
auto skel = fbxsdk::FbxSkeleton::Create(mScene, name);
96+
skel->SetSkeletonType(fbxsdk::FbxSkeleton::eLimbNode);
97+
98+
auto node = fbxsdk::FbxNode::Create(mScene, name);
99+
node->SetNodeAttribute(skel);
100+
101+
node->LclTranslation.Set(matrix.GetT());
102+
node->LclRotation.Set(matrix.GetR());
103+
node->LclScaling.Set(matrix.GetS());
104+
105+
return node;
106+
}
107+
108+
fbxsdk::FbxCluster* CreateCluster(fbxsdk::FbxSkin* skin, fbxsdk::FbxNode* node, const fbxsdk::FbxAMatrix& matrix)
109+
{
110+
auto cluster = fbxsdk::FbxCluster::Create(mScene, node->GetName());
111+
cluster->SetLink(node);
112+
cluster->SetLinkMode(fbxsdk::FbxCluster::eNormalize);
113+
114+
cluster->SetTransformMatrix(matrix);
115+
cluster->SetTransformLinkMatrix(node->EvaluateGlobalTransform());
116+
117+
skin->AddCluster(cluster);
118+
119+
return cluster;
120+
}
121+
};

0 commit comments

Comments
 (0)