61 return L
"Save OBJ file";
66 return L
"OBJ files (*.obj)|*.obj";
76 namespace fs = std::filesystem;
79 const fs::path targetPath(target);
81 std::ofstream file(targetPath);
91 const fs::path matPath = targetPath.parent_path() / (targetPath.stem().wstring() + L
".mtl");
93 LOG_INFO <<
"Exporting" << model->
modelname.c_str() <<
"materials in" << matPath.wstring();
95 std::ofstream matFile(matPath);
96 if (!matFile.is_open())
98 LOG_ERROR <<
"Unable to open" << matPath.wstring();
102 std::ofstream& obj = file;
103 std::ofstream& mtl = matFile;
105 obj <<
"# Wavefront OBJ exported by ";
109 obj << fs::path(appName).string() <<
" "
110 << fs::path(appVer).string() <<
"\n";
113 obj <<
"mtllib " << matPath.filename().string() <<
"\n";
118 mtl <<
"# mtl file for " << targetPath.filename().string() <<
" obj file" <<
"\n";
144 std::map<POSITION_SLOTS, WoWModel*> itemModels = (*it)->models();
145 if (!itemModels.empty())
148 obj <<
"# " << (*it)->name() <<
"\n";
150 for (
const auto& It : itemModels)
156 const int l = model->
attLookup[It.first];
161 M = model->
bones[model->
atts[l].bone].mat;
162 pos = model->
atts[l].pos;
173 LOG_ERROR <<
"Error during materials export for model" << itemModel->
modelname.c_str();
190 bool vertMsg =
false;
194 for (
size_t i = 0; i < model->
passes.size(); i++)
201 for (
size_t k = 0, b = geoset->
istart; k < geoset->
icount; k++, b++)
207 if (vertMsg ==
false)
212 vert = mat * glm::vec4((model->
vertices[a] + pos), 1.0);
216 if (vertMsg ==
false)
218 LOG_INFO <<
"Using Original Verticies";
221 vert = mat * glm::vec4((model->
origVertices[a].pos + pos), 1.0);
225 snprintf(buf,
sizeof(buf),
"v %.06f %.06f %.06f", vert.x, vert.y, vert.z);
233 file <<
"# " << vertics <<
" vertices" <<
"\n" <<
"\n";
237 for (
size_t i = 0; i < model->
passes.size(); i++)
244 for (
size_t k = 0, b = geoset->
istart; k < geoset->
icount; k++, b++)
248 snprintf(buf,
sizeof(buf),
"vt %.06f %.06f", tc.x, 1 - tc.y);
257 for (
size_t i = 0; i < model->
passes.size(); i++)
263 for (
size_t k = 0, b = geoset->
istart; k < geoset->
icount; k++, b++)
267 snprintf(buf,
sizeof(buf),
"vn %.06f %.06f %.06f", n.x, n.y, n.z);
277 int triangles_total = 0;
278 for (
size_t i = 0; i < model->
passes.size(); i++)
288 Vert2Point[v] = pointnum;
292 snprintf(buf,
sizeof(buf),
"Geoset_%03i", g);
293 std::string val(buf);
294 std::string matName = model->
modelname +
"_" + val;
295 std::replace(matName.begin(), matName.end(),
'\\',
'_');
296 std::string partName = matName;
298 if (p->
unlit ==
true)
299 matName = matName +
"_Lum";
302 matName = matName +
"_Dbl";
310 partName +=
"-" + cgGroupName;
312 file <<
"g " << partName <<
"\n";
313 file <<
"usemtl " << matName <<
"\n";
314 file <<
"s 1" <<
"\n";
316 for (
size_t k = 0; k < geoset->
icount; k += 3)
319 file << counter <<
"/" << counter <<
"/" << counter <<
" ";
321 file << counter <<
"/" << counter <<
"/" << counter <<
" ";
323 file << counter <<
"/" << counter <<
"/" << counter <<
"\n";
327 file <<
"# " << triangles <<
" triangles in group" <<
"\n" <<
"\n";
330 if (triangles_total > UINT64_MAX - triangles)
332 LOG_ERROR <<
"Overflow detected in triangles_total!";
336 triangles_total += triangles;
339 file <<
"# " << triangles_total <<
" triangles total" <<
"\n" <<
"\n";
345 namespace fs = std::filesystem;
347 std::map<std::wstring, GLuint> texToExport;
350 for (
size_t i = 0; i < model->
passes.size(); i++)
357 std::string texStem = fs::path(tex).stem().string();
358 std::string mtlStem = fs::path(mtlFile).stem().string();
359 std::string texFile = mtlStem +
"_" + texStem +
".png";
362 glm::vec4 diff = p->
ocol;
364 snprintf(buf,
sizeof(buf),
"Geoset_%03i", model->
geosets[p->
geoIndex]->id);
365 std::string material = model->
modelname +
"_" + buf;
366 std::replace(material.begin(), material.end(),
'\\',
'_');
367 if (p->
unlit ==
true)
370 material = material +
"_Lum";
372 diff = glm::vec4(0, 0, 0, 0);
378 material = material +
"_Dbl";
381 file <<
"newmtl " << material <<
"\n";
382 file <<
"illum 2" <<
"\n";
383 snprintf(buf,
sizeof(buf),
"Kd %.06f %.06f %.06f", diff.x, diff.y, diff.z);
385 snprintf(buf,
sizeof(buf),
"Ka %.06f %.06f %.06f", amb, amb, amb);
387 snprintf(buf,
sizeof(buf),
"Ks %.06f %.06f %.06f", p->
ecol.x, p->
ecol.y, p->
ecol.z);
389 file <<
"Ke 0.000000 0.000000 0.000000" <<
"\n";
390 snprintf(buf,
sizeof(buf),
"Ns %0.6f", 0.0f);
393 file <<
"map_Kd " << texFile <<
"\n";
394 std::string fullTexPath = fs::path(mtlFile).parent_path().string() +
"\\" + texFile;
395 texToExport[fs::path(fullTexPath).wstring()] = model->
getGLTexture(p->
tex);
399 LOG_INFO <<
"nb textures to export :" << texToExport.size();
401 for (
const auto& it : texToExport)
void MakeModelFaceForwards(glm::vec4 &vect)
std::unordered_set< WoWItem * >::iterator iterator
void exportGLTexture(GLuint id, std::wstring filename) const
Extended geoset with 32-bit index start to support HD models with > 65535 indices.
Represents a single render pass (material + geometry) for an M2 model geoset.
bool init()
Initialise render state from the model's material data.
glm::vec4 ecol
Output and emissive colours.
int geoIndex
Geoset index this pass draws.
Abstract base interface for all 3D model types.
bool exportModelVertices(WoWModel *model, std::ofstream &file, int &counter, glm::mat4 m=glm::mat4(1.0), glm::vec3 pos=glm::vec3(0.0f)) const
bool exportModelMaterials(WoWModel *model, std::ofstream &file, std::string mtlFile) const
bool exportModel(Model *, std::wstring file)
std::wstring fileSaveFilter() const
std::wstring menuLabel() const
std::wstring fileSaveTitle() const
Core WoW .m2 model: geometry, animation, textures, and character data.
GLuint getGLTexture(uint16 tex) const
std::vector< uint32 > indices
std::vector< Bone > bones
std::vector< ModelRenderPass * > passes
std::string getNameForTex(uint16 tex)
static std::string getCGGroupName(CharGeosets cg)
std::vector< ModelAttachment > atts
std::vector< ModelGeosetHD * > geosets
std::vector< ModelVertex > origVertices
CharGeosets
Character geoset group identifiers (mesh IDs for body/armour regions).