Skip to content

Commit

Permalink
Add preview and more options to OBJ import
Browse files Browse the repository at this point in the history
- Invert U/V, Scale, Rotate X/Y/Z.
- Show vertex and triangle counts, red text if too many.
- Allow deleting single shapes with DEL
- Green shape selection highlight in preview
  • Loading branch information
ousnius committed Apr 9, 2022
1 parent e9ffbef commit a2f8954
Show file tree
Hide file tree
Showing 15 changed files with 708 additions and 136 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ set(OSsources
src/ui/wxBrushSettingsPopup.cpp
src/program/EditUV.cpp
src/program/FBXImportDialog.cpp
src/program/ObjImportDialog.cpp
src/program/OutfitProject.cpp
src/program/OutfitStudio.cpp
src/program/ShapeProperties.cpp
Expand Down
5 changes: 4 additions & 1 deletion OutfitStudio.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@
<None Include="res\xrc\About.xrc" />
<None Include="res\xrc\Actions.xrc" />
<None Include="res\xrc\ConvertBodyReference.xrc" />
<None Include="res\xrc\EditUV.xrc" />
<None Include="res\xrc\ImportDialog.xrc" />
<None Include="res\xrc\OutfitStudio.xrc" />
<None Include="res\xrc\Project.xrc" />
<None Include="res\xrc\SavePreset.xrc" />
Expand Down Expand Up @@ -801,8 +803,8 @@
<ClInclude Include="src\program\ConvertBodyReferenceDialog.h" />
<ClInclude Include="src\program\EditUV.h" />
<ClInclude Include="src\program\FBXImportDialog.h" />
<ClInclude Include="src\program\FBXImportOptions.h" />
<ClInclude Include="src\program\GroupManager.h" />
<ClInclude Include="src\program\ObjImportDialog.h" />
<ClInclude Include="src\program\OutfitProject.h" />
<ClInclude Include="src\program\OutfitStudio.h" />
<ClInclude Include="src\program\PresetSaveDialog.h" />
Expand Down Expand Up @@ -878,6 +880,7 @@
<ClCompile Include="src\program\EditUV.cpp" />
<ClCompile Include="src\program\FBXImportDialog.cpp" />
<ClCompile Include="src\program\GroupManager.cpp" />
<ClCompile Include="src\program\ObjImportDialog.cpp" />
<ClCompile Include="src\program\OutfitProject.cpp" />
<ClCompile Include="src\program\OutfitStudio.cpp" />
<ClCompile Include="src\program\PresetSaveDialog.cpp" />
Expand Down
15 changes: 12 additions & 3 deletions OutfitStudio.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,12 @@
<None Include="lib\gli\glm\ext\vector_ulp.inl">
<Filter>Libraries\gli\glm\ext</Filter>
</None>
<None Include="res\xrc\EditUV.xrc">
<Filter>Resources</Filter>
</None>
<None Include="res\xrc\ImportDialog.xrc">
<Filter>Resources</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
Expand Down Expand Up @@ -769,9 +775,6 @@
<ClInclude Include="src\program\FBXImportDialog.h">
<Filter>Program</Filter>
</ClInclude>
<ClInclude Include="src\program\FBXImportOptions.h">
<Filter>Program</Filter>
</ClInclude>
<ClInclude Include="src\render\GLExtensions.h">
<Filter>Rendering</Filter>
</ClInclude>
Expand Down Expand Up @@ -1894,6 +1897,9 @@
<ClInclude Include="src\render\GLDialog.h">
<Filter>Rendering</Filter>
</ClInclude>
<ClInclude Include="src\program\ObjImportDialog.h">
<Filter>Program</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="lib\TinyXML-2\tinyxml2.cpp">
Expand Down Expand Up @@ -2112,6 +2118,9 @@
<ClCompile Include="src\render\GLCanvas.cpp">
<Filter>Rendering</Filter>
</ClCompile>
<ClCompile Include="src\program\ObjImportDialog.cpp">
<Filter>Program</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Xml Include="Config.xml">
Expand Down
70 changes: 37 additions & 33 deletions res/xrc/FBXImport.xrc → res/xrc/ImportDialog.xrc
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<resource xmlns="http://www.wxwidgets.org/wxxrc" version="2.5.3.0">
<object class="wxDialog" name="dlgFBXImport">
<object class="wxDialog" name="importDialog">
<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>
<size>600,700</size>
<title>FBX Import Options...</title>
<title>Import Options...</title>
<centered>1</centered>
<object class="wxBoxSizer">
<orient>wxVERTICAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>
<border>10</border>
<object class="wxStaticText" name="lbWarning">
<bg>#ffff00</bg>
<hidden>1</hidden>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxListCtrl" name="meshesList">
<style>wxLC_REPORT</style>
<object class="listcol">
<text>Name</text>
<width>100</width>
</object>
<object class="listcol">
<text>Vertices #</text>
<width>75</width>
</object>
<object class="listcol">
<text>Triangles #</text>
<width>75</width>
</object>
<object class="listcol">
<text>Info</text>
<width>425</width>
</object>
</object>
</object>
<object class="sizeritem">
<option>0</option>
<flag>wxEXPAND|wxALL</flag>
Expand Down Expand Up @@ -127,36 +159,8 @@
<option>1</option>
<flag>wxEXPAND</flag>
<border>0</border>
<object class="wxBoxSizer">
<orient>wxHORIZONTAL</orient>
<object class="sizeritem">
<option>0</option>
<flag>wxALL|wxEXPAND</flag>
<border>5</border>
<object class="wxListCtrl" name="meshesList">
<style>wxLC_REPORT</style>
<object class="listcol">
<text>Name</text>
<width>100</width>
</object>
<object class="listcol">
<text>Vertices #</text>
<width>75</width>
</object>
<object class="listcol">
<text>Triangles #</text>
<width>75</width>
</object>
</object>
</object>
<object class="sizeritem">
<option>1</option>
<flag>wxEXPAND</flag>
<border>0</border>
<minsize>500,600</minsize>
<object class="unknown" name="glView" />
</object>
</object>
<minsize>700,600</minsize>
<object class="unknown" name="glView" />
</object>
<object class="sizeritem">
<option>0</option>
Expand Down
14 changes: 10 additions & 4 deletions src/files/FBXWrangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,8 @@ void FBXWrangler::Priv::LoadMesh(const FBXImportOptions& options, FbxNode* node)
FBXShape shape;
shape.name = node->GetName();

if (!options.ImportAll) {
if (options.ImportShapes.count(shape.name) == 0)
return;
}
if (!options.ImportAll && options.ImportShapes.count(shape.name) == 0)
return;

FbxMesh* m = (FbxMesh*)node->GetNodeAttribute();

Expand Down Expand Up @@ -660,8 +658,16 @@ void FBXWrangler::Priv::LoadMesh(const FBXImportOptions& options, FbxNode* node)
mat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));
mat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));

Matrix4 matRot;
matRot.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));
matRot.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));
matRot.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));

for (auto& v : shape.verts)
v = mat * v;

for (auto& n : shape.normals)
n = matRot * n;

shapes[shape.name] = std::move(shape);
}
15 changes: 14 additions & 1 deletion src/files/FBXWrangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@ See the included LICENSE file
#include "../components/Mesh.h"
#include "../program/FBXImportOptions.h"
#include "NifFile.hpp"
#include <memory>

#include <memory>
#include <set>

struct FBXImportOptions {
bool InvertU = false;
bool InvertV = false;
float Scale = 1.0f;
float RotateX = 0.0f;
float RotateY = 0.0f;
float RotateZ = 0.0f;

bool ImportAll = true;
std::set<std::string> ImportShapes;
};

class FBXShape {
public:
Expand Down
56 changes: 48 additions & 8 deletions src/files/ObjFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,27 @@ int ObjFile::AddGroup(
return 0;
}

int ObjFile::LoadForNif(const std::string& fileName, const ObjOptionsImport& options) {
int ObjFile::LoadForNif(const std::string& fileName, const ObjImportOptions& options) {
std::fstream file;
PlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);
if (file.fail())
return 1;

if (options.noFaces)
LoadNoFaces(file);
if (options.NoFaces)
LoadNoFaces(file, options);
else
LoadForNif(file);
LoadForNif(file, options);

return 0;
}

void ObjFile::LoadNoFaces(std::istream& ins) {
void ObjFile::LoadNoFaces(std::istream& ins, const ObjImportOptions& options) {
Matrix4 mat;
mat.PushScale(options.Scale, options.Scale, options.Scale);
mat.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));
mat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));
mat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));

ObjData d;

while (!ins.eof()) {
Expand All @@ -54,14 +61,17 @@ void ObjFile::LoadNoFaces(std::istream& ins) {
if (cmd == "v") {
Vector3 v;
lineiss >> v.x >> v.y >> v.z;
v = mat * v;
d.verts.push_back(v);
}
else if (cmd == "o" || cmd == "g") {
std::string curgrp;
lineiss >> curgrp;

if (!d.name.empty()) {
data[d.name] = std::move(d);
if (options.ImportAll || options.ImportShapes.count(d.name) > 0)
data[d.name] = std::move(d);

d = ObjData();
}

Expand All @@ -71,6 +81,12 @@ void ObjFile::LoadNoFaces(std::istream& ins) {
Vector2 uv;
lineiss >> uv.u >> uv.v;
uv.v = 1.0f - uv.v;

if (options.InvertU)
uv.u = 1.0f - uv.u;
if (options.InvertV)
uv.v = 1.0f - uv.v;

d.uvs.push_back(uv);
}
}
Expand All @@ -79,12 +95,24 @@ void ObjFile::LoadNoFaces(std::istream& ins) {
d.name = "object";

if (!d.verts.empty())
data[d.name] = std::move(d);
if (options.ImportAll || options.ImportShapes.count(d.name) > 0)
data[d.name] = std::move(d);
else
data.erase(d.name);
}

void ObjFile::LoadForNif(std::istream& ins) {
void ObjFile::LoadForNif(std::istream& ins, const ObjImportOptions& options) {
Matrix4 mat;
mat.PushScale(options.Scale, options.Scale, options.Scale);
mat.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));
mat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));
mat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));

Matrix4 matRot;
matRot.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));
matRot.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));
matRot.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));

// First, parse the file into verts, uvs, norms, and faces. Faces
// are grouped by group/object name; the rest are not.
std::vector<Vector3> verts;
Expand All @@ -105,6 +133,7 @@ void ObjFile::LoadForNif(std::istream& ins) {
ni = atoi(s.substr(pos + 1).c_str());
}
};

// groups[group/object name][face index][face-vertex index]
std::unordered_map<std::string, std::vector<std::vector<FaceVertex>>> groups;
std::vector<std::vector<FaceVertex>>* currentgroup = &groups["object"];
Expand All @@ -122,6 +151,7 @@ void ObjFile::LoadForNif(std::istream& ins) {
if (cmd == "v") {
Vector3 v;
lineiss >> v.x >> v.y >> v.z;
v = mat * v;
verts.push_back(v);
}
else if (cmd == "o" || cmd == "g") {
Expand All @@ -133,11 +163,18 @@ void ObjFile::LoadForNif(std::istream& ins) {
Vector2 uv;
lineiss >> uv.u >> uv.v;
uv.v = 1.0f - uv.v;

if (options.InvertU)
uv.u = 1.0f - uv.u;
if (options.InvertV)
uv.v = 1.0f - uv.v;

uvs.push_back(uv);
}
else if (cmd == "vn") {
Vector3 vn;
lineiss >> vn.x >> vn.y >> vn.z;
vn = matRot * vn;
norms.push_back(vn);
}
else if (cmd == "f") {
Expand Down Expand Up @@ -189,6 +226,9 @@ void ObjFile::LoadForNif(std::istream& ins) {
// get it into the right form. We work on one group/object at a time.
for (auto& gfp : groups) {
std::string groupName = gfp.first;
if (!options.ImportAll && options.ImportShapes.count(groupName) == 0)
continue;

const std::vector<std::vector<FaceVertex>>& faces = gfp.second;
if (faces.empty())
continue;
Expand Down
21 changes: 16 additions & 5 deletions src/files/ObjFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@ See the included LICENSE file
#include <fstream>
#include <map>
#include <string>
#include <set>

struct ObjOptionsImport {
bool noFaces = false;
struct ObjImportOptions {
bool InvertU = false;
bool InvertV = false;
float Scale = 1.0f;
float RotateX = 0.0f;
float RotateY = 0.0f;
float RotateZ = 0.0f;

bool ImportAll = true;
std::set<std::string> ImportShapes;

bool NoFaces = false;
};

struct ObjData {
Expand All @@ -39,9 +50,9 @@ class ObjFile {
void SetScale(const nifly::Vector3& inScale) { scale = inScale; }
void SetOffset(const nifly::Vector3& inOffset) { offset = inOffset; }

int LoadForNif(const std::string& fileName, const ObjOptionsImport& options = ObjOptionsImport());
void LoadNoFaces(std::istream& base);
void LoadForNif(std::istream& base);
int LoadForNif(const std::string& fileName, const ObjImportOptions& options = ObjImportOptions());
void LoadNoFaces(std::istream& base, const ObjImportOptions& options);
void LoadForNif(std::istream& base, const ObjImportOptions& options);

int Save(const std::string& fileName);

Expand Down
Loading

0 comments on commit a2f8954

Please sign in to comment.