mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-21 00:25:44 +00:00
Add ObjDumper for general use
This commit is contained in:
parent
0478a88d15
commit
76a7ca99c3
54
src/ObjCommon/Model/Obj/ObjCommon.cpp
Normal file
54
src/ObjCommon/Model/Obj/ObjCommon.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "ObjCommon.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
bool operator==(const ObjVertex& lhs, const ObjVertex& rhs)
|
||||||
|
{
|
||||||
|
return std::fabs(lhs.coordinates[0] - rhs.coordinates[0]) < std::numeric_limits<float>::epsilon()
|
||||||
|
&& std::fabs(lhs.coordinates[1] - rhs.coordinates[1]) < std::numeric_limits<float>::epsilon()
|
||||||
|
&& std::fabs(lhs.coordinates[2] - rhs.coordinates[2]) < std::numeric_limits<float>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ObjVertex& lhs, const ObjVertex& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const ObjVertex& lhs, const ObjVertex& rhs)
|
||||||
|
{
|
||||||
|
return std::tie(lhs.coordinates[0], lhs.coordinates[1], lhs.coordinates[2]) < std::tie(rhs.coordinates[0], rhs.coordinates[1], rhs.coordinates[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ObjNormal& lhs, const ObjNormal& rhs)
|
||||||
|
{
|
||||||
|
return std::fabs(lhs.normal[0] - rhs.normal[0]) < std::numeric_limits<float>::epsilon()
|
||||||
|
&& std::fabs(lhs.normal[1] - rhs.normal[1]) < std::numeric_limits<float>::epsilon()
|
||||||
|
&& std::fabs(lhs.normal[2] - rhs.normal[2]) < std::numeric_limits<float>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ObjNormal& lhs, const ObjNormal& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const ObjNormal& lhs, const ObjNormal& rhs)
|
||||||
|
{
|
||||||
|
return std::tie(lhs.normal[0], lhs.normal[1], lhs.normal[2]) < std::tie(rhs.normal[0], rhs.normal[1], rhs.normal[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ObjUv& lhs, const ObjUv& rhs)
|
||||||
|
{
|
||||||
|
return std::fabs(lhs.uv[0] - rhs.uv[0]) < std::numeric_limits<float>::epsilon()
|
||||||
|
&& std::fabs(lhs.uv[1] - rhs.uv[1]) < std::numeric_limits<float>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const ObjUv& lhs, const ObjUv& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const ObjUv& lhs, const ObjUv& rhs)
|
||||||
|
{
|
||||||
|
return std::tie(lhs.uv[0], lhs.uv[1]) < std::tie(rhs.uv[0], rhs.uv[1]);
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct ObjObject
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
int materialIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjVertex
|
||||||
|
{
|
||||||
|
float coordinates[3];
|
||||||
|
|
||||||
|
friend bool operator==(const ObjVertex& lhs, const ObjVertex& rhs);
|
||||||
|
friend bool operator!=(const ObjVertex& lhs, const ObjVertex& rhs);
|
||||||
|
friend bool operator<(const ObjVertex& lhs, const ObjVertex& rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjNormal
|
||||||
|
{
|
||||||
|
float normal[3];
|
||||||
|
|
||||||
|
friend bool operator==(const ObjNormal& lhs, const ObjNormal& rhs);
|
||||||
|
friend bool operator!=(const ObjNormal& lhs, const ObjNormal& rhs);
|
||||||
|
friend bool operator<(const ObjNormal& lhs, const ObjNormal& rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjUv
|
||||||
|
{
|
||||||
|
float uv[2];
|
||||||
|
|
||||||
|
friend bool operator==(const ObjUv& lhs, const ObjUv& rhs);
|
||||||
|
friend bool operator!=(const ObjUv& lhs, const ObjUv& rhs);
|
||||||
|
friend bool operator<(const ObjUv& lhs, const ObjUv& rhs);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjFace
|
||||||
|
{
|
||||||
|
int vertexIndex[3];
|
||||||
|
int normalIndex[3];
|
||||||
|
int uvIndex[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MtlMaterial
|
||||||
|
{
|
||||||
|
std::string materialName;
|
||||||
|
std::string colorMapName;
|
||||||
|
std::string normalMapName;
|
||||||
|
std::string specularMapName;
|
||||||
|
};
|
@ -5,59 +5,6 @@
|
|||||||
|
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
|
|
||||||
/*
|
|
||||||
template <typename T>
|
|
||||||
class Deduplicator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Deduplicator()
|
|
||||||
: m_current_entry_index(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit Deduplicator(const size_t totalEntryCount)
|
|
||||||
: m_current_entry_index(0)
|
|
||||||
{
|
|
||||||
m_position_lookup.reserve(totalEntryCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AddEntry(T pos)
|
|
||||||
{
|
|
||||||
const auto mapEntry = m_index_map.find(pos);
|
|
||||||
if (mapEntry == m_index_map.end())
|
|
||||||
{
|
|
||||||
m_position_lookup.push_back(m_current_entry_index);
|
|
||||||
m_unique_entry_position_indices.push_back(m_current_entry_index);
|
|
||||||
m_index_map.emplace(std::make_pair(pos, m_current_entry_index));
|
|
||||||
m_current_entry_index++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_position_lookup.push_back(mapEntry->second);
|
|
||||||
m_current_entry_index++;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetUniqueIndexForIndex(const size_t entryIndex)
|
|
||||||
{
|
|
||||||
if (entryIndex >= m_position_lookup.size())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_position_lookup[entryIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
_NODISCARD const std::vector<size_t>& GetUniqueEntryIndices() const
|
|
||||||
{
|
|
||||||
return m_unique_entry_position_indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_current_entry_index;
|
|
||||||
std::vector<size_t> m_unique_entry_position_indices;
|
|
||||||
std::vector<size_t> m_position_lookup;
|
|
||||||
std::map<T, int> m_index_map;
|
|
||||||
};*/
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class DistinctMapper
|
class DistinctMapper
|
||||||
{
|
{
|
||||||
@ -123,6 +70,16 @@ public:
|
|||||||
return m_distinct_values;
|
return m_distinct_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_NODISCARD size_t GetInputValueCount() const
|
||||||
|
{
|
||||||
|
return m_input_entry_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NODISCARD size_t GetDistinctValueCount() const
|
||||||
|
{
|
||||||
|
return m_distinct_entry_index;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_input_entry_index;
|
size_t m_input_entry_index;
|
||||||
size_t m_distinct_entry_index;
|
size_t m_distinct_entry_index;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#include "AssetDumperXModel.h"
|
#include "AssetDumperXModel.h"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <set>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#include "ObjWriting.h"
|
#include "ObjWriting.h"
|
||||||
#include "Game/IW4/CommonIW4.h"
|
#include "Game/IW4/CommonIW4.h"
|
||||||
@ -18,151 +16,168 @@ bool AssetDumperXModel::ShouldDump(XAssetInfo<XModel>* asset)
|
|||||||
return !asset->m_name.empty() && asset->m_name[0] != ',';
|
return !asset->m_name.empty() && asset->m_name[0] != ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::DumpObjMatMaterial(AssetDumpingContext& context, const Material* material, std::ostream& stream)
|
void AssetDumperXModel::AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
|
||||||
{
|
{
|
||||||
stream << "\n";
|
if (!model->materialHandles)
|
||||||
stream << "newmtl " << material->info.name << "\n";
|
return;
|
||||||
|
|
||||||
GfxImage* colorMap = nullptr;
|
for (auto surfIndex = 0u; surfIndex < model->numsurfs; surfIndex++)
|
||||||
GfxImage* normalMap = nullptr;
|
|
||||||
GfxImage* specularMap = nullptr;
|
|
||||||
|
|
||||||
for (auto i = 0u; i < material->textureCount; i++)
|
|
||||||
{
|
{
|
||||||
const auto& texture = material->textureTable[i];
|
Material* material = model->materialHandles[surfIndex];
|
||||||
|
if (!materialMapper.Add(material))
|
||||||
|
continue;
|
||||||
|
|
||||||
switch (texture.semantic)
|
MtlMaterial mtl;
|
||||||
|
mtl.materialName = std::string(material->info.name);
|
||||||
|
|
||||||
|
GfxImage* colorMap = nullptr;
|
||||||
|
GfxImage* normalMap = nullptr;
|
||||||
|
GfxImage* specularMap = nullptr;
|
||||||
|
|
||||||
|
for (auto i = 0u; i < material->textureCount; i++)
|
||||||
{
|
{
|
||||||
case TS_COLOR_MAP:
|
const auto& texture = material->textureTable[i];
|
||||||
colorMap = texture.u.image;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TS_NORMAL_MAP:
|
switch (texture.semantic)
|
||||||
normalMap = texture.u.image;
|
{
|
||||||
break;
|
case TS_COLOR_MAP:
|
||||||
|
colorMap = texture.u.image;
|
||||||
|
break;
|
||||||
|
|
||||||
case TS_SPECULAR_MAP:
|
// Disabled due to looking weird in Blender
|
||||||
specularMap = texture.u.image;
|
// case TS_NORMAL_MAP:
|
||||||
break;
|
// normalMap = texture.u.image;
|
||||||
|
// break;
|
||||||
|
|
||||||
default:
|
case TS_SPECULAR_MAP:
|
||||||
break;
|
specularMap = texture.u.image;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorMap != nullptr)
|
||||||
|
mtl.colorMapName = colorMap->name;
|
||||||
|
if (normalMap != nullptr)
|
||||||
|
mtl.normalMapName = normalMap->name;
|
||||||
|
if (specularMap != nullptr)
|
||||||
|
mtl.specularMapName = specularMap->name;
|
||||||
|
|
||||||
|
writer.AddMaterial(std::move(mtl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperXModel::AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex)
|
||||||
|
{
|
||||||
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
|
{
|
||||||
|
ObjObject object;
|
||||||
|
object.name = "surf" + std::to_string(surfIndex);
|
||||||
|
object.materialIndex = static_cast<int>(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfaceIndex));
|
||||||
|
|
||||||
|
writer.AddObject(std::move(object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetDumperXModel::AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||||
|
{
|
||||||
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
|
{
|
||||||
|
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||||
|
|
||||||
|
for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++)
|
||||||
|
{
|
||||||
|
const auto& v = surface.verts0[vertexIndex];
|
||||||
|
vec2_t uv;
|
||||||
|
vec3_t normalVec;
|
||||||
|
vec4_t color;
|
||||||
|
|
||||||
|
Common::Vec2UnpackTexCoords(v.texCoord, &uv);
|
||||||
|
Common::Vec3UnpackUnitVec(v.normal, &normalVec);
|
||||||
|
Common::Vec4UnpackGfxColor(v.color, &color);
|
||||||
|
|
||||||
|
ObjVertex objVertex{};
|
||||||
|
ObjNormal objNormal{};
|
||||||
|
ObjUv objUv{};
|
||||||
|
objVertex.coordinates[0] = v.xyz[0];
|
||||||
|
objVertex.coordinates[1] = v.xyz[2];
|
||||||
|
objVertex.coordinates[2] = -v.xyz[1];
|
||||||
|
objNormal.normal[0] = normalVec[0];
|
||||||
|
objNormal.normal[1] = normalVec[2];
|
||||||
|
objNormal.normal[2] = -normalVec[1];
|
||||||
|
objUv.uv[0] = uv[0];
|
||||||
|
objUv.uv[1] = 1.0f - uv[1];
|
||||||
|
|
||||||
|
writer.AddVertex(static_cast<int>(surfIndex), objVertex);
|
||||||
|
writer.AddNormal(static_cast<int>(surfIndex), objNormal);
|
||||||
|
writer.AddUv(static_cast<int>(surfIndex), objUv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (colorMap)
|
void AssetDumperXModel::AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs)
|
||||||
stream << "map_Kd " << colorMap->name << ".dds\n";
|
{
|
||||||
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
|
{
|
||||||
|
const auto& surface = modelSurfs->surfs[surfIndex];
|
||||||
|
for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++)
|
||||||
|
{
|
||||||
|
const auto& tri = surface.triIndices[triIndex];
|
||||||
|
|
||||||
if (normalMap)
|
ObjFace face{};
|
||||||
stream << "map_bump " << normalMap->name << ".dds\n";
|
face.vertexIndex[0] = tri[2] + surface.baseVertIndex;
|
||||||
|
face.vertexIndex[1] = tri[1] + surface.baseVertIndex;
|
||||||
if (specularMap)
|
face.vertexIndex[2] = tri[0] + surface.baseVertIndex;
|
||||||
stream << "map_Ks " << specularMap->name << ".dds\n";
|
face.normalIndex[0] = face.vertexIndex[0];
|
||||||
|
face.normalIndex[1] = face.vertexIndex[1];
|
||||||
|
face.normalIndex[2] = face.vertexIndex[2];
|
||||||
|
face.uvIndex[0] = face.vertexIndex[0];
|
||||||
|
face.uvIndex[1] = face.vertexIndex[1];
|
||||||
|
face.uvIndex[2] = face.vertexIndex[2];
|
||||||
|
writer.AddFace(static_cast<int>(surfIndex), face);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
void AssetDumperXModel::DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||||
{
|
{
|
||||||
const auto* model = asset->Asset();
|
const auto* model = asset->Asset();
|
||||||
const auto matFile = context.OpenAssetFile("xmodelsurfs/" + std::string(model->name) + ".mtl");
|
const auto matFile = context.OpenAssetFile("model_export/" + std::string(model->name) + ".mtl");
|
||||||
|
|
||||||
if (!matFile)
|
if (!matFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& stream = *matFile;
|
ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||||
stream << "# OpenAssetTools MAT File (IW4)\n";
|
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||||
|
|
||||||
if (model->numsurfs == 0 || model->materialHandles == nullptr)
|
AddObjMaterials(writer, materialMapper, model);
|
||||||
return;
|
writer.WriteMtl(*matFile);
|
||||||
|
|
||||||
std::set<Material*> uniqueMaterials;
|
|
||||||
for (auto i = 0u; i < model->numsurfs; i++)
|
|
||||||
{
|
|
||||||
if (model->materialHandles[i] != nullptr)
|
|
||||||
uniqueMaterials.emplace(model->materialHandles[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << "# Material count: " << uniqueMaterials.size() << "\n";
|
|
||||||
|
|
||||||
for (const auto* material : uniqueMaterials)
|
|
||||||
{
|
|
||||||
DumpObjMatMaterial(context, material, stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod)
|
void AssetDumperXModel::DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod)
|
||||||
{
|
{
|
||||||
const auto* model = asset->Asset();
|
const auto* model = asset->Asset();
|
||||||
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
|
const auto* modelSurfs = model->lodInfo[lod].modelSurfs;
|
||||||
const auto assetFile = context.OpenAssetFile("xmodelsurfs/" + std::string(modelSurfs->name) + ".obj");
|
|
||||||
|
if (modelSurfs->name[0] == ',' || modelSurfs->surfs == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto assetFile = context.OpenAssetFile("model_export/" + std::string(modelSurfs->name) + ".obj");
|
||||||
|
|
||||||
if (!assetFile)
|
if (!assetFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& stream = *assetFile;
|
ObjWriter writer(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||||
stream << "# OpenAssetTools OBJ File (IW4)\n";
|
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||||
|
|
||||||
stream << "mtllib " << model->name << ".mtl\n";
|
AddObjMaterials(writer, materialMapper, model);
|
||||||
|
AddObjObjects(writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
|
||||||
|
AddObjVertices(writer, modelSurfs);
|
||||||
|
AddObjFaces(writer, modelSurfs);
|
||||||
|
|
||||||
if (model->lodInfo[lod].modelSurfs == nullptr || model->lodInfo[lod].modelSurfs->surfs == nullptr)
|
writer.WriteObj(*assetFile, std::string(model->name) + ".mtl");
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto i = 0; i < model->lodInfo[lod].numsurfs; i++)
|
|
||||||
{
|
|
||||||
const auto* surf = &modelSurfs->surfs[i];
|
|
||||||
|
|
||||||
stream << "o surf" << i << "\n";
|
|
||||||
|
|
||||||
for (auto vi = 0; vi < surf->vertCount; vi++)
|
|
||||||
{
|
|
||||||
const auto* vertex = &surf->verts0[vi];
|
|
||||||
stream << "v " << vertex->xyz[0] << " " << vertex->xyz[2] << " " << -vertex->xyz[1] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << "\n";
|
|
||||||
|
|
||||||
for (auto vi = 0; vi < surf->vertCount; vi++)
|
|
||||||
{
|
|
||||||
const auto* vertex = &surf->verts0[vi];
|
|
||||||
vec2_t texCoords;
|
|
||||||
Common::Vec2UnpackTexCoords(vertex->texCoord, &texCoords);
|
|
||||||
|
|
||||||
stream << "vt " << texCoords[0] << " " << (1.0f - texCoords[1]) << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << "\n";
|
|
||||||
|
|
||||||
for (auto vi = 0; vi < surf->vertCount; vi++)
|
|
||||||
{
|
|
||||||
const auto* vertex = &surf->verts0[vi];
|
|
||||||
vec3_t normalVec;
|
|
||||||
Common::Vec3UnpackUnitVec(vertex->normal, &normalVec);
|
|
||||||
|
|
||||||
stream << "vn " << normalVec[0] << " " << normalVec[2] << " " << -normalVec[1] << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << "\n";
|
|
||||||
|
|
||||||
if (model->numsurfs > i && model->materialHandles && model->materialHandles[i])
|
|
||||||
{
|
|
||||||
stream << "usemtl " << model->materialHandles[i]->info.name << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << "\n";
|
|
||||||
|
|
||||||
for (auto ti = 0; ti < surf->triCount; ti++)
|
|
||||||
{
|
|
||||||
const auto* indices = reinterpret_cast<r_index16_t*>(surf->triIndices);
|
|
||||||
|
|
||||||
const auto i0 = surf->baseVertIndex + indices[ti * 3 + 0] + 1;
|
|
||||||
const auto i1 = surf->baseVertIndex + indices[ti * 3 + 1] + 1;
|
|
||||||
const auto i2 = surf->baseVertIndex + indices[ti * 3 + 2] + 1;
|
|
||||||
|
|
||||||
stream << "f " << i2 << "/" << i2 << "/" << i2
|
|
||||||
<< " " << i1 << "/" << i1 << "/" << i1
|
|
||||||
<< " " << i0 << "/" << i0 << "/" << i0
|
|
||||||
<< "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||||
@ -176,7 +191,7 @@ void AssetDumperXModel::DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddBonesToWriter(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
|
void AssetDumperXModel::AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model)
|
||||||
{
|
{
|
||||||
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
|
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
|
||||||
{
|
{
|
||||||
@ -224,7 +239,7 @@ void AssetDumperXModel::AddBonesToWriter(const AssetDumpingContext& context, Abs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddMaterialsToWriter(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
|
void AssetDumperXModel::AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model)
|
||||||
{
|
{
|
||||||
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
|
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
|
||||||
{
|
{
|
||||||
@ -251,7 +266,7 @@ void AssetDumperXModel::AddMaterialsToWriter(AbstractXModelWriter& writer, Disti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddObjectsToWriter(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
|
void AssetDumperXModel::AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
|
||||||
{
|
{
|
||||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
{
|
{
|
||||||
@ -262,7 +277,7 @@ void AssetDumperXModel::AddObjectsToWriter(AbstractXModelWriter& writer, const X
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddVerticesToWriter(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
|
void AssetDumperXModel::AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs)
|
||||||
{
|
{
|
||||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
{
|
{
|
||||||
@ -298,7 +313,7 @@ void AssetDumperXModel::AddVerticesToWriter(AbstractXModelWriter& writer, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AllocateBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
void AssetDumperXModel::AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||||
{
|
{
|
||||||
weightCollection.totalWeightCount = 0u;
|
weightCollection.totalWeightCount = 0u;
|
||||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
@ -322,7 +337,7 @@ void AssetDumperXModel::AllocateBoneWeights(const XModelSurfs* modelSurfs, XMode
|
|||||||
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
|
weightCollection.weights = std::make_unique<XModelBoneWeight[]>(weightCollection.totalWeightCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
void AssetDumperXModel::AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection)
|
||||||
{
|
{
|
||||||
size_t weightOffset = 0u;
|
size_t weightOffset = 0u;
|
||||||
|
|
||||||
@ -484,8 +499,8 @@ void AssetDumperXModel::AddVertexBoneWeights(AbstractXModelWriter& writer, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetDumperXModel::AddFacesToWriter(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs,
|
void AssetDumperXModel::AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs,
|
||||||
const int baseSurfaceIndex)
|
const int baseSurfaceIndex)
|
||||||
{
|
{
|
||||||
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
for (auto surfIndex = 0u; surfIndex < modelSurfs->numsurfs; surfIndex++)
|
||||||
{
|
{
|
||||||
@ -521,14 +536,14 @@ void AssetDumperXModel::DumpXModelExportLod(const AssetDumpingContext& context,
|
|||||||
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
const auto writer = XModelExportWriter::CreateWriterForVersion6(context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||||
XModelVertexBoneWeightCollection boneWeightCollection;
|
XModelVertexBoneWeightCollection boneWeightCollection;
|
||||||
AllocateBoneWeights(modelSurfs, boneWeightCollection);
|
AllocateXModelBoneWeights(modelSurfs, boneWeightCollection);
|
||||||
|
|
||||||
AddBonesToWriter(context, *writer, model);
|
AddXModelBones(context, *writer, model);
|
||||||
AddMaterialsToWriter(*writer, materialMapper, model);
|
AddXModelMaterials(*writer, materialMapper, model);
|
||||||
AddObjectsToWriter(*writer, modelSurfs);
|
AddXModelObjects(*writer, modelSurfs);
|
||||||
AddVerticesToWriter(*writer, modelSurfs);
|
AddXModelVertices(*writer, modelSurfs);
|
||||||
AddVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
|
AddXModelVertexBoneWeights(*writer, modelSurfs, boneWeightCollection);
|
||||||
AddFacesToWriter(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
|
AddXModelFaces(*writer, materialMapper, modelSurfs, model->lodInfo[lod].surfIndex);
|
||||||
|
|
||||||
writer->Write(*assetFile);
|
writer->Write(*assetFile);
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include "Dumping/AbstractAssetDumper.h"
|
#include "Dumping/AbstractAssetDumper.h"
|
||||||
#include "Game/IW4/IW4.h"
|
#include "Game/IW4/IW4.h"
|
||||||
#include "Model/XModel/XModelExportWriter.h"
|
|
||||||
#include "Utils/DistinctMapper.h"
|
#include "Utils/DistinctMapper.h"
|
||||||
|
#include "Model/XModel/AbstractXModelWriter.h"
|
||||||
|
#include "Model/Obj/ObjWriter.h"
|
||||||
|
|
||||||
namespace IW4
|
namespace IW4
|
||||||
{
|
{
|
||||||
class AssetDumperXModel final : public AbstractAssetDumper<XModel>
|
class AssetDumperXModel final : public AbstractAssetDumper<XModel>
|
||||||
{
|
{
|
||||||
|
static void AddObjMaterials(ObjWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
|
||||||
|
static void AddObjObjects(ObjWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
|
||||||
|
static void AddObjVertices(ObjWriter& writer, const XModelSurfs* modelSurfs);
|
||||||
|
static void AddObjFaces(ObjWriter& writer, const XModelSurfs* modelSurfs);
|
||||||
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
|
static void DumpObjLod(AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
|
||||||
static void DumpObjMatMaterial(AssetDumpingContext& context, const Material* material, std::ostream& stream);
|
|
||||||
static void DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
static void DumpObjMat(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
||||||
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
static void DumpObj(AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
||||||
|
|
||||||
static void AddBonesToWriter(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
|
static void AddXModelBones(const AssetDumpingContext& context, AbstractXModelWriter& writer, const XModel* model);
|
||||||
static void AddMaterialsToWriter(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
|
static void AddXModelMaterials(AbstractXModelWriter& writer, DistinctMapper<Material*>& materialMapper, const XModel* model);
|
||||||
static void AddObjectsToWriter(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
|
static void AddXModelObjects(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
|
||||||
static void AddVerticesToWriter(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
|
static void AddXModelVertices(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs);
|
||||||
static void AllocateBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
|
static void AllocateXModelBoneWeights(const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
|
||||||
static void AddVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
|
static void AddXModelVertexBoneWeights(AbstractXModelWriter& writer, const XModelSurfs* modelSurfs, XModelVertexBoneWeightCollection& weightCollection);
|
||||||
static void AddFacesToWriter(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
|
static void AddXModelFaces(AbstractXModelWriter& writer, const DistinctMapper<Material*>& materialMapper, const XModelSurfs* modelSurfs, int baseSurfaceIndex);
|
||||||
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, const unsigned lod);
|
static void DumpXModelExportLod(const AssetDumpingContext& context, XAssetInfo<XModel>* asset, unsigned lod);
|
||||||
static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
static void DumpXModelExport(const AssetDumpingContext& context, XAssetInfo<XModel>* asset);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -0,0 +1,159 @@
|
|||||||
|
#include "ObjWriter.h"
|
||||||
|
|
||||||
|
#include "Game/IW4/CommonIW4.h"
|
||||||
|
|
||||||
|
ObjWriter::ObjWriter(std::string gameName, std::string zoneName)
|
||||||
|
: m_game_name(std::move(gameName)),
|
||||||
|
m_zone_name(std::move(zoneName))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddObject(ObjObject object)
|
||||||
|
{
|
||||||
|
m_objects.emplace_back(std::move(object));
|
||||||
|
m_object_data.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddMaterial(MtlMaterial material)
|
||||||
|
{
|
||||||
|
m_materials.emplace_back(std::move(material));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddVertex(const int objectId, const ObjVertex vertex)
|
||||||
|
{
|
||||||
|
if (objectId < 0 || static_cast<unsigned>(objectId) >= m_object_data.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_object_data[objectId].m_vertices.Add(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddNormal(const int objectId, const ObjNormal normal)
|
||||||
|
{
|
||||||
|
if (objectId < 0 || static_cast<unsigned>(objectId) >= m_object_data.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_object_data[objectId].m_normals.Add(normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddUv(const int objectId, const ObjUv uv)
|
||||||
|
{
|
||||||
|
if (objectId < 0 || static_cast<unsigned>(objectId) >= m_object_data.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_object_data[objectId].m_uvs.Add(uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::AddFace(const int objectId, const ObjFace face)
|
||||||
|
{
|
||||||
|
if (objectId < 0 || static_cast<unsigned>(objectId) >= m_object_data.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_object_data[objectId].m_faces.push_back(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::GetObjObjectDataOffsets(std::vector<ObjObjectDataOffsets>& inputOffsets, std::vector<ObjObjectDataOffsets>& distinctOffsets)
|
||||||
|
{
|
||||||
|
ObjObjectDataOffsets currentInputOffsets{};
|
||||||
|
ObjObjectDataOffsets currentDistinctOffsets{};
|
||||||
|
|
||||||
|
for (const auto& objectData : m_object_data)
|
||||||
|
{
|
||||||
|
inputOffsets.push_back(currentInputOffsets);
|
||||||
|
distinctOffsets.push_back(currentDistinctOffsets);
|
||||||
|
|
||||||
|
currentInputOffsets.vertexOffset += objectData.m_vertices.GetInputValueCount();
|
||||||
|
currentInputOffsets.normalOffset += objectData.m_normals.GetInputValueCount();
|
||||||
|
currentInputOffsets.uvOffset += objectData.m_uvs.GetInputValueCount();
|
||||||
|
currentDistinctOffsets.vertexOffset += objectData.m_vertices.GetDistinctValueCount();
|
||||||
|
currentDistinctOffsets.normalOffset += objectData.m_normals.GetDistinctValueCount();
|
||||||
|
currentDistinctOffsets.uvOffset += objectData.m_uvs.GetDistinctValueCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::WriteObj(std::ostream& stream)
|
||||||
|
{
|
||||||
|
WriteObj(stream, std::string());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::WriteObj(std::ostream& stream, const std::string& mtlName)
|
||||||
|
{
|
||||||
|
stream << "# OpenAssetTools OBJ File ( " << m_game_name << ")\n";
|
||||||
|
stream << "# Game Origin: " << m_game_name << "\n";
|
||||||
|
stream << "# Zone Origin: " << m_zone_name << "\n";
|
||||||
|
|
||||||
|
if (!mtlName.empty())
|
||||||
|
stream << "mtllib " << mtlName << "\n";
|
||||||
|
|
||||||
|
std::vector<ObjObjectDataOffsets> inputOffsetsByObject;
|
||||||
|
std::vector<ObjObjectDataOffsets> distinctOffsetsByObject;
|
||||||
|
GetObjObjectDataOffsets(inputOffsetsByObject, distinctOffsetsByObject);
|
||||||
|
|
||||||
|
auto objectIndex = 0;
|
||||||
|
for (const auto& object : m_objects)
|
||||||
|
{
|
||||||
|
const auto& objectData = m_object_data[objectIndex];
|
||||||
|
stream << "o " << object.name << "\n";
|
||||||
|
|
||||||
|
for (const auto& v : objectData.m_vertices.GetDistinctValues())
|
||||||
|
stream << "v " << v.coordinates[0] << " " << v.coordinates[1] << " " << v.coordinates[2] << "\n";
|
||||||
|
for (const auto& uv : objectData.m_uvs.GetDistinctValues())
|
||||||
|
stream << "vt " << uv.uv[0] << " " << uv.uv[1] << "\n";
|
||||||
|
for (const auto& n : objectData.m_normals.GetDistinctValues())
|
||||||
|
stream << "vn " << n.normal[0] << " " << n.normal[1] << " " << n.normal[2] << "\n";
|
||||||
|
|
||||||
|
if (object.materialIndex >= 0 && static_cast<unsigned>(object.materialIndex) < m_materials.size())
|
||||||
|
stream << "usemtl " << m_materials[object.materialIndex].materialName << "\n";
|
||||||
|
|
||||||
|
for (const auto& f : objectData.m_faces)
|
||||||
|
{
|
||||||
|
const size_t v[3]
|
||||||
|
{
|
||||||
|
objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[0] - inputOffsetsByObject[objectIndex].vertexOffset) + distinctOffsetsByObject[objectIndex].vertexOffset + 1,
|
||||||
|
objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[1] - inputOffsetsByObject[objectIndex].vertexOffset) + distinctOffsetsByObject[objectIndex].vertexOffset + 1,
|
||||||
|
objectData.m_vertices.GetDistinctPositionByInputPosition(f.vertexIndex[2] - inputOffsetsByObject[objectIndex].vertexOffset) + distinctOffsetsByObject[objectIndex].vertexOffset + 1
|
||||||
|
};
|
||||||
|
const size_t n[3]
|
||||||
|
{
|
||||||
|
objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[0] - inputOffsetsByObject[objectIndex].normalOffset) + distinctOffsetsByObject[objectIndex].normalOffset + 1,
|
||||||
|
objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[1] - inputOffsetsByObject[objectIndex].normalOffset) + distinctOffsetsByObject[objectIndex].normalOffset + 1,
|
||||||
|
objectData.m_normals.GetDistinctPositionByInputPosition(f.normalIndex[2] - inputOffsetsByObject[objectIndex].normalOffset) + distinctOffsetsByObject[objectIndex].normalOffset + 1
|
||||||
|
};
|
||||||
|
const size_t uv[3]
|
||||||
|
{
|
||||||
|
objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[0] - inputOffsetsByObject[objectIndex].uvOffset) + distinctOffsetsByObject[objectIndex].uvOffset + 1,
|
||||||
|
objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[1] - inputOffsetsByObject[objectIndex].uvOffset) + distinctOffsetsByObject[objectIndex].uvOffset + 1,
|
||||||
|
objectData.m_uvs.GetDistinctPositionByInputPosition(f.uvIndex[2] - inputOffsetsByObject[objectIndex].uvOffset) + distinctOffsetsByObject[objectIndex].uvOffset + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
stream << "f " << v[0] << "/" << uv[0] << "/" << n[0]
|
||||||
|
<< " " << v[1] << "/" << uv[1] << "/" << n[1]
|
||||||
|
<< " " << v[2] << "/" << uv[2] << "/" << n[2]
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
objectIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjWriter::WriteMtl(std::ostream& stream)
|
||||||
|
{
|
||||||
|
stream << "# OpenAssetTools MAT File ( " << m_game_name << ")\n";
|
||||||
|
stream << "# Game Origin: " << m_game_name << "\n";
|
||||||
|
stream << "# Zone Origin: " << m_zone_name << "\n";
|
||||||
|
stream << "# Material count: " << m_materials.size() << "\n";
|
||||||
|
|
||||||
|
for (const auto& material : m_materials)
|
||||||
|
{
|
||||||
|
stream << "\n";
|
||||||
|
stream << "newmtl " << material.materialName << "\n";
|
||||||
|
|
||||||
|
if (!material.colorMapName.empty())
|
||||||
|
stream << "map_Kd ../images/" << material.colorMapName << ".dds\n";
|
||||||
|
|
||||||
|
if (!material.normalMapName.empty())
|
||||||
|
stream << "map_bump ../images/" << material.normalMapName << ".dds\n";
|
||||||
|
|
||||||
|
if (!material.specularMapName.empty())
|
||||||
|
stream << "map_Ks ../images/" << material.specularMapName << ".dds\n";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "Model/Obj/ObjCommon.h"
|
||||||
|
#include "Utils/DistinctMapper.h"
|
||||||
|
|
||||||
|
class ObjWriter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct ObjObjectData
|
||||||
|
{
|
||||||
|
DistinctMapper<ObjVertex> m_vertices;
|
||||||
|
DistinctMapper<ObjNormal> m_normals;
|
||||||
|
DistinctMapper<ObjUv> m_uvs;
|
||||||
|
std::vector<ObjFace> m_faces;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjObjectDataOffsets
|
||||||
|
{
|
||||||
|
size_t vertexOffset;
|
||||||
|
size_t normalOffset;
|
||||||
|
size_t uvOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string m_game_name;
|
||||||
|
std::string m_zone_name;
|
||||||
|
std::vector<ObjObject> m_objects;
|
||||||
|
std::vector<ObjObjectData> m_object_data;
|
||||||
|
std::vector<MtlMaterial> m_materials;
|
||||||
|
|
||||||
|
void GetObjObjectDataOffsets(std::vector<ObjObjectDataOffsets>& inputOffsets, std::vector<ObjObjectDataOffsets>& distinctOffsets);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ObjWriter(std::string gameName, std::string zoneName);
|
||||||
|
|
||||||
|
void AddObject(ObjObject object);
|
||||||
|
void AddMaterial(MtlMaterial material);
|
||||||
|
void AddVertex(int objectId, ObjVertex vertex);
|
||||||
|
void AddNormal(int objectId, ObjNormal normal);
|
||||||
|
void AddUv(int objectId, ObjUv uv);
|
||||||
|
void AddFace(int objectId, ObjFace face);
|
||||||
|
|
||||||
|
void WriteObj(std::ostream& stream);
|
||||||
|
void WriteObj(std::ostream& stream, const std::string& mtlName);
|
||||||
|
void WriteMtl(std::ostream& stream);
|
||||||
|
};
|
@ -162,7 +162,7 @@ bool UnlinkerArgs::SetModelDumpingMode()
|
|||||||
|
|
||||||
if (specifiedValue == "obj")
|
if (specifiedValue == "obj")
|
||||||
{
|
{
|
||||||
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT;
|
ObjWriting::Configuration.ModelOutputFormat = ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user