commit x64 compilation from lulu cause the other branch dont seems to compile properly at home

This commit is contained in:
2026-07-17 16:08:20 +02:00
parent c0f3eeb00d
commit 0efa4ee6f7
625 changed files with 117283 additions and 4426 deletions

View File

@ -0,0 +1,683 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "import_obj/import_obj.h"
#include "scene3d/scene.h"
#include "scene3d/mobject.h"
#include "core/graphic_resource_factory.h"
#include "core/geometry.h"
#include "metafile/nml_object.h"
#include "ascii/parser.h"
#include "filesystem/filesystem.h"
#include "filesystem/io_handle.h"
#include "platform.h"
using namespace GS;
using namespace GS::Core;
using namespace GS::S3D;
using namespace GS::AsciiParser;
//------------------------------------------------------------------------------
struct ObjPoly
{
List <int> vtx, uv, nrm;
uint mat;
ObjPoly() : mat(0) {}
};
struct ObjGroup
{
String name;
List <ObjPoly *> pol_list;
void Free()
{ ListDeleteAllPtr(ObjPoly *, pol_list) }
~ObjGroup()
{ Free(); }
};
struct ObjMtl
{
String name;
String path;
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void ExportMaterialStage(NML::Tag *mtag, const String &texture, const char *channel, int index)
{
if (texture.IsEmpty())
return;
if (NML::Tag *ttag = mtag->AddChild("TextureStage"))
{
ttag->AddChild("Active");
ttag->AddChild("Texture", texture);
ttag->AddChild("Channel", channel);
ttag->AddChild("Index", index);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool OBJImporter::LoadMaterialLibrary(List <ObjMtl *> &mtl_list, const char *uri)
{
Array <char> obj;
if (!Platform::Get().io->FileLoad(uri, obj))
__ERR__(__LOG_E__ << "OBJ material library file '" << uri << "' not found.\n", false)
// Now parse.
const char *pobj = &obj[0], *eobj = pobj + obj.GetSize();
ObjMtl *current_mtl = NULL;
String map_Ka, map_Kd, map_Ks, map_Ke;
forever
{
String word(pobj, SkipEntry(pobj, eobj));
// Export material to file.
if ((word == "newmtl") || (pobj >= eobj))
if (current_mtl)
{
current_mtl->path = String::Format("%s/%s.nmm", config->base_path.c_str(), current_mtl->name.c_str());
// Only export material if it does not exist.
if (!Platform::Get().io->Exists(current_mtl->path))
{
String name = Platform::Get().io->StripRootPath(current_mtl->path);
NML::File file;
if (NML::Tag *mtag = file.AddRoot("Material"))
{
mtag->AddChild("Id", name);
ExportMaterialStage(mtag, map_Kd, "Diffuse", 0);
ExportMaterialStage(mtag, map_Ka, "Opacity", 1);
ExportMaterialStage(mtag, map_Ks, "Specular", 2);
ExportMaterialStage(mtag, map_Ke, "Emissive", 3);
if (NML::Tag *rtag = mtag->AddChild("RenderMask"))
rtag->AddChild("NormalMapTangent");
}
NML::Parser::Save(current_mtl->path, file);
}
}
if (pobj >= eobj)
break;
// Create new material.
if (word == "newmtl")
{
// Create new material.
mtl_list.Add(current_mtl = new ObjMtl);
pobj = NextEntry(pobj + 1, eobj);
const char *eon = SkipEntry(pobj, eobj);
current_mtl->name.Set(pobj, eon);
pobj = NextEntry(eon, eobj, true);
}
else if (current_mtl)
{
//------------------------------------------------------------------
#define __ReadObjMaterialMap(_map) \
{ \
pobj = NextEntry(pobj + 1, eobj); \
const char *eon = RunToEOL(pobj, eobj); \
_map.Set(pobj, eon); \
pobj = NextEntry(eon, eobj, true); \
}
//------------------------------------------------------------------
if (word == "map_Ka")
__ReadObjMaterialMap(map_Ka)
else if (word == "map_Ks")
__ReadObjMaterialMap(map_Ks)
else if (word == "map_Kd")
__ReadObjMaterialMap(map_Kd)
else if (word == "map_Ke")
__ReadObjMaterialMap(map_Ke)
else
pobj = NextEntry(RunToEOL(pobj, eobj), eobj);
}
else
pobj = NextEntry(RunToEOL(pobj, eobj), eobj);
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool OBJImporter::TestImport(const char *uri)
{
String ext = String::FileGetExtension(uri).Lower();
return ext == "obj";
}
bool OBJImporter::ImportScene(Scene *scene, const char *uri, const Config &_config, Group **)
{
Array <char> obj;
if (!Platform::Get().io->FileLoad(uri, obj))
__ERR__(__LOG_E__ << "OBJ file '" << uri << "' not found.\n", false)
// Now parse.
config = &_config;
if (config->event_handler)
config->event_handler->OpenLoad();
const char *pobj = &obj[0], *eobj = pobj + obj.GetSize();
//--------------------------------------------------------------------------
{
bool has_uv = false, has_vnm = false;
AutoList <Vector4 *> vtx_list, vnm_list;
AutoList <Vector2 *> uv_list;
AutoList <ObjGroup *> group_list;
AutoList <ObjMtl *> mat_list;
ObjGroup *current_group = new ObjGroup;
current_group->name = "default";
group_list.Add(current_group);
int current_mat = 0;
while (pobj < eobj)
{
String word(pobj, SkipEntry(pobj, eobj));
if (config->event_handler)
config->event_handler->LoadProgress(String::Format("Parsing tag '%s'...", word.c_str()), (float)(pobj - &obj[0]) / obj.GetSize());
// Declare material library.
if (word == "mtllib")
{
pobj = NextEntry(pobj + 1, eobj);
const char *eon = RunToEOL(pobj, eobj);
String lib_path = String(pobj, eon);
if (!lib_path.IsAbsolutePath())
lib_path = String(uri).GetFilePath() + "/" + lib_path;
LoadMaterialLibrary(mat_list, lib_path);
pobj = NextEntry(eon, eobj, true);
}
// Use material.
else if (word == "usemtl")
{
pobj = NextEntry(pobj + 1, eobj);
const char *eon = SkipEntry(pobj, eobj);
String name(pobj, eon);
// Locate in library.
current_mat = 0;
ListForeachPtr(ObjMtl *, mat, mat_list)
{
if (mat->name == name)
break;
current_mat++;
}
pobj = NextEntry(eon, eobj, true);
}
// Append vertex.
else if (word == "v")
{
// Parse vertex.
pobj = NextEntry(pobj, eobj);
float x = 0, y = 0, z = 0;
x = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
y = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
z = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
vtx_list.Add(new Vector4(x * config->scale, y * config->scale, -z * config->scale));
}
// Append vertex normal.
else if (word == "vn")
{
pobj = NextEntry(pobj, eobj);
float x = 0, y = 0, z = 0;
x = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
y = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
z = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
// vnm_list.Add(new nVector(-y, -z, -x));
vnm_list.Add(new Vector4(x, y, -z));
}
// Append UV.
else if (word == "vt")
{
pobj = NextEntry(pobj, eobj);
float u = 0, v = 0;
u = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
v = String::atof(pobj, eobj); pobj = NextEntry(pobj, eobj, true);
uv_list.Add(new Vector2(u, 1.f - v));
}
// Declare group.
else if (word == "g")
{
group_list.Add(current_group = new ObjGroup);
// Check for named group.
const char *eol = RunToEOL(pobj, eobj);
pobj = NextEntry(pobj + 1, eobj);
if (pobj <= eol)
{
const char *eon = SkipEntry(pobj, eobj);
current_group->name.Set(pobj, eon);
pobj = NextEntry(eon, eobj, true);
}
else // no name
pobj = NextEntry(eol, eobj, true);
}
// Build group polygons.
else if (word == "f")
{
pobj = NextEntry(pobj, eobj);
ObjPoly *pol = new ObjPoly;
pol->mat = current_mat;
const char *eol = RunToEOL(pobj, eobj);
while (pobj < eol)
{
pol->vtx.Add(String::atoi(pobj)); // Index.
pobj = NextEntry(pobj, eobj, true);
if (pobj[0] == '/')
{
pobj++;
if (pobj[0] != '/')
{
has_uv = true;
pol->uv.Add(String::atoi(pobj)); // UV index.
pobj = NextEntry(pobj, eobj, true);
}
}
if (pobj[0] == '/')
{
pobj++;
has_vnm = true;
pol->nrm.Add(String::atoi(pobj)); // Normal index.
pobj = NextEntry(pobj, eobj, true);
}
}
if (pol->vtx.GetCount() < 3)
delete pol;
else
current_group->pol_list.Add(pol);
}
else
pobj = NextEntry(RunToEOL(pobj, eobj), eobj);
}
obj.Free();
//--------------------------------------------------------------------------
// Get flat UV array.
Array <Vector2> flat_uv;
if (has_uv && flat_uv.Allocate(uv_list.GetCount()))
{
Vector2 *pflat_uv = flat_uv;
ListForeachPtr(Vector2 *, uv, uv_list)
*pflat_uv++ = *uv;
}
// Get flat vertex normal array.
Array <Vector4> flat_vnm;
if (has_vnm && flat_vnm.Allocate(vnm_list.GetCount()))
{
Vector4 *pflat_vnm = flat_vnm;
ListForeachPtr(Vector4 *, vnm, vnm_list)
*pflat_vnm++ = *vnm;
}
//--------------------------------------------------------------------------
Array <int> vtx_map(vtx_list.GetCount()),
mat_map(mat_list.GetCount());
//--------------------------------------------------------------------------
// Build scene.
int n_pg = 0;
ListForeachPtr(ObjGroup *, group, group_list)
{
++n_pg;
if (!vtx_list.GetCount() || !group->pol_list.GetCount())
continue;
if (config->event_handler)
config->event_handler->LoadProgress(String::Format("Importing group '%s'...", group->name.toUtf8()), (float)(n_pg - 1) / group_list.GetCount());
// Create geometry.
Geometry *geo = new Geometry;
// Remap vertices.
for (uint n = 0; n < vtx_map.GetCount(); ++n)
vtx_map[n] = -1;
// Total vertex count.
uint vtx_count = 0;
ListForeachPtr(ObjPoly *, p, group->pol_list)
ListForeachPtr(int, i, p->vtx)
if (vtx_map[i - 1] == -1)
vtx_map[i - 1] = vtx_count++;
// Transfer vertices.
if (geo->vtx.Allocate(vtx_count))
{
for (uint i = 0; i < vtx_list.GetCount(); ++i)
if (vtx_map[i] != -1)
geo->vtx[vtx_map[i]] = *vtx_list[i];
}
else
__LOG_E__ << "Failed to allocate " << geo->vtx.GetCount() << " vertices.\n";
// Transfer topology and attributes.
if (geo->pol.Allocate(group->pol_list.GetCount()))
{
// Compute bind index count.
uint binding_count = 0;
ListForeachPtr(ObjPoly *, p, group->pol_list)
binding_count += p->vtx.GetCount();
if (geo->binding.Allocate(binding_count))
{
uint *pbind = &geo->binding[0];
// Allocate attributes.
Vector2 *puv = NULL;
if (has_uv)
{
geo->uv[0].Allocate(binding_count);
puv = &geo->uv[0][0];
}
Vector4 *pvnm = NULL;
if (has_vnm)
{
geo->vtx_normal.Allocate(binding_count);
pvnm = &geo->vtx_normal[0];
}
// Transfer data.
uint cpol = 0;
ListForeachPtr(ObjPoly *, p, group->pol_list)
{
Polygon *pol = &geo->pol[cpol++];
pol->vtx_count = (ushort)p->vtx.GetCount();
pol->binding = pbind;
pol->material = 0;
for (int i = p->vtx.GetCount(); i > 0; --i)
{
int idx = p->vtx[i - 1] - 1;
if (idx > (int)vtx_map.GetCount())
idx = 0;
*pbind++ = vtx_map[idx];
}
if (puv)
for (int i = p->uv.GetCount(); i > 0; --i)
*puv++ = flat_uv[p->uv[i - 1] - 1];
if (pvnm)
for (int i = p->nrm.GetCount(); i > 0; --i)
*pvnm++ = flat_vnm[p->nrm[i - 1] - 1];
}
}
else
__LOG_E__ << "Failed to allocate " << geo->binding.GetCount() << " polygon binding entries.\n";
// Remap and assign materials.
for (uint i = 0; i < mat_list.GetCount(); ++i)
mat_map[i] = -1;
int mat_count = 0;
ListForeachPtr(ObjPoly *, p, group->pol_list)
if (p->mat < mat_map.GetCount())
if (mat_map[p->mat] == -1)
mat_map[p->mat] = mat_count++;
uint cpol = 0;
ListForeachPtr(ObjPoly *, p, group->pol_list)
geo->pol[cpol++].material = (ushort)(p->mat < mat_map.GetCount() ? mat_map[p->mat] : 0);
// Load materials.
if (mat_list.GetCount())
{
geo->material_table.Allocate(mat_count);
for (uint i = 0; i < mat_list.GetCount(); ++i)
if (mat_map[i] != -1)
geo->material_table[mat_map[i]].name = mat_list[i]->path;
}
else
geo->material_table.Allocate(1);
// Vertex normal.
if (!has_vnm)
geo->ComputeVertexNormal(true);
// Save geometry.
geo->name = String::Format("%s/%s.nmg", config->base_path.c_str(), group->name.toUtf8());
NML::SaveToFile(*geo, geo->name);
geo->name = Platform::Get().io->StripRootPath(geo->name);
// Add to scene.
MObject *object = new MObject;
object->name = group->name;
scene->AddItem(object, true);
object->geometry = geo->name;
// Ease up memory.
group->Free();
}
else
__LOG_E__ << "Failed to allocate " << geo->pol.GetCount() << " polygons.\n";
}
}
//--------------------------------------------------------------------------
// Save scene.
scene->name = String::Format("%s/scene.nms", config->base_path.c_str());
NML::SaveToFile(*scene, scene->name);
scene->name = Platform::Get().io->StripRootPath(scene->name);
if (config->event_handler)
config->event_handler->EndLoad();
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Geometry *OBJImporter::ImportGeometry(const char *uri, IResourceFactoryEvent *event_handler)
{
if (!uri)
__ERR__(__LOG_E__ << "No URI to import.\n", NULL)
AutoPtr <Geometry> geo(new Geometry);
// Load file in memory.
Array <char> obj;
if (!Platform::Get().io->FileLoad(uri, obj))
__ERR__(__LOG_E__ << "File '" << uri << "' not found.\n", NULL)
// Now parse.
List <Vector4 *> vtx_list;
List <Vector2 *> uv_list;
List <ObjPoly *> pol_list;
bool has_uv = false;
const char *pobj = &obj[0], *eobj = pobj + obj.GetSize();
while (pobj < eobj)
{
String word(pobj, SkipEntry(pobj, eobj));
if (word == "v")
{
pobj = NextEntry(pobj, eobj);
float x = 0, y = 0, z = 0;
x = String::atof(pobj, eobj);
pobj = NextEntry(pobj, eobj, true);
y = String::atof(pobj, eobj);
pobj = NextEntry(pobj, eobj, true);
z = -String::atof(pobj, eobj);
pobj = NextEntry(pobj, eobj, true);
vtx_list.Add(new Vector4(x, y, z));
}
else if (word == "vt")
{
pobj = NextEntry(pobj, eobj);
float u = 0, v = 0;
u = String::atof(pobj, eobj);
pobj = NextEntry(pobj, eobj, true);
v = String::atof(pobj, eobj);
pobj = NextEntry(pobj, eobj, true);
uv_list.Add(new Vector2(u, v));
}
else if (word == "f")
{
pobj = NextEntry(pobj, eobj);
ObjPoly *pol = new ObjPoly;
pol_list.Add(pol);
const char *eol = RunToEOL(pobj, eobj);
while (pobj < eol)
{
pol->vtx.Add(String::atoi(pobj)); // Index.
pobj = NextEntry(pobj, eobj, true);
if (pobj[0] == '/')
{
pobj++;
if (pobj[0] != '/')
{
has_uv = true;
pol->uv.Add(String::atoi(pobj)); // UV index.
pobj = NextEntry(pobj, eobj, true);
}
}
if (pobj[0] == '/')
{
pobj++;
pol->nrm.Add(String::atoi(pobj)); // Normal index.
pobj = NextEntry(pobj, eobj, true);
}
}
}
else
pobj = NextEntry(RunToEOL(pobj, eobj), eobj);
}
// Drop OBJ.
obj.Free();
// Transfer vertice.
if (geo->vtx.Allocate(vtx_list.GetCount()))
{
uint cvtx = 0;
ListForeachPtr(Vector4 *, v, vtx_list)
geo->vtx[cvtx++] = *v;
}
else
__LOG_E__ << "Failed to allocate " << vtx_list.GetCount() << " vertices.\n";
ListDeleteAllPtr(Vector4 *, vtx_list)
// Transfer polygon.
if (geo->pol.Allocate(pol_list.GetCount()))
{
uint binding_count = 0;
ListForeachPtr(ObjPoly *, p, pol_list)
binding_count += p->vtx.GetCount();
geo->binding.Allocate(binding_count);
Array <Vector2> flat_uv;
if (has_uv)
if (flat_uv.Allocate(binding_count))
{
geo->uv[0].Allocate(binding_count);
Vector2 *pflat_uv = &flat_uv[0];
ListForeachPtr(Vector2 *, uv, uv_list)
*pflat_uv++ = *uv;
ListDeleteAllPtr(Vector2 *, uv_list)
}
Vector2 *puv = &geo->uv[0][0];
if (geo->binding)
{
uint *pbind = &geo->binding[0];
uint cpol = 0;
ListForeachPtr(ObjPoly *, p, pol_list)
{
Polygon *pol = &geo->pol[cpol];
pol->vtx_count = (ushort)p->vtx.GetCount();
pol->binding = pbind;
pol->material = 0;
for (int v = p->vtx.GetCount(); v > 0; --v)
*pbind++ = p->vtx.ObjectAt(v - 1) - 1;
ListForeachPtr(int, i, p->uv)
*puv++ = flat_uv[i - 1];
}
}
else
__LOG_E__ << "Failed to allocate " << geo->binding.GetCount() << " polygon binding entries.\n";
}
else
__LOG_E__ << "Failed to allocate " << geo->pol.GetCount() << " polygons.\n";
ListDeleteAllPtr(ObjPoly *, pol_list)
// Load materials.
geo->material_table.Allocate(1);
geo->material_table[0].name = "Default";
// Setup defaults.
geo->ComputeVertexNormal();
return geo.Detach();
}
//------------------------------------------------------------------------------