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,853 @@
/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/geometry.h"
#include "core/embedded_resource_handler_interface.h"
#include "timing/benchmark.h"
#include "metafile/nml.h"
#include "math/matrix4.h"
#include "ascii/parser.h"
#include "memory/endian.h"
#include "log/log.h"
using namespace GS::Core;
using namespace GS::AsciiParser;
//------------------------------------------------------------------------------
void Geometry::ParseVertex(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
vtx.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
float *fbff = (float *)vt->GetValue().GetBinaryBuffer();
if (vtx)
for (uint n = 0; n < vtx.GetCount(); ++n)
{
for (int m = 0; m < 3; ++m)
Endian::ToHost(&fbff[n * 3 + m], 4, Endian::Intel);
vtx[n].Set(fbff[n * 3 + 0], fbff[n * 3 + 1], fbff[n * 3 + 2]);
}
else __LOG_E__ << "Incomplete vertex chunk loading '" << name << "', expected vertex count integer tag.\n";
}
}
}
void Geometry::ParseAsciiVertex(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
vtx.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (vtx)
{
uint cvtx = 0;
NMLTagForeach(vx, *vt)
{
if (cvtx == vtx.GetCount())
{
__LOG_E__ << "Corrupter <AVertex> tag, more vertices than expected.\n";
break;
}
vtx[cvtx++].FromMetaTag(*vx);
}
}
else __LOG_E__ << "Incomplete vertex chunk loading '" << name << "', expected vertex count integer tag.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseSkin(const Tag *pt)
{
// Retrieve bone id list.
Tag *bonetag = pt->GetTag("Bones"),
*bindtag = pt->GetTag("Binds");
skin.Free();
bone_name.Free();
bone_bind_matrix.Free();
if (bonetag)
{
AllocateBone(bonetag->GetChildCount());
if (!bone_name)
__LOG_E__ << "Failed to allocate bone id list.\n";
else
{
int n = 0;
NMLTagForeach(b, *bonetag)
bone_name[n++] = b->GetString();
}
if (bindtag && (bindtag->GetChildCount() == bone_name.GetCount()))
{
int n = 0;
NMLTagForeach(m, *bindtag)
bone_bind_matrix[n++].FromMetaTag(*m);
}
}
// Retrieve skin weights.
Tag *weighttag = pt->GetTag("Weights");
if (bone_name.GetCount() && weighttag)
{
if (weighttag->GetChildCount() != vtx.GetCount())
__LOG_W__ << "Incoherent weight count (" << weighttag->GetChildCount() <<" for " << vtx.GetCount() << " vertice (is the skin being declared before the vertice?)).\n";
if (!skin.Allocate(weighttag->GetChildCount()))
__LOG_E__ << "Failed to allocate skin weights array.\n";
else
{
int n = 0;
NMLTagForeach(b, *weighttag)
{
const char *p = b->GetString(), *e = p + String::strlen(p);
skin[n].bone_index[0] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[1] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[2] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].bone_index[3] = (ushort)String::atoi(p);
p = NextEntry(p, e) + 1;
skin[n].w[0] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[1] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[2] = ((float)String::atoi(p)) / 255.f;
p = NextEntry(p, e) + 1;
skin[n].w[3] = ((float)String::atoi(p)) / 255.f;
// Re-normalize weights.
float tw = 0.f;
for (int w = 0; w < 4; ++w)
tw += skin[n].w[w];
float k = 1.f / tw;
for (int w = 0; w < 4; ++w)
skin[n].w[w] *= k;
++n;
}
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParsePolygon(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol.Allocate(vt->GetInteger());
else if (vt->name == "BindingCount")
binding.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (pol && binding)
{
uint *pbuffer = (uint *)vt->GetValue().GetBinaryBuffer();
uint *pbinding = binding;
for (uint m = 0; m < pol.GetCount(); m++)
{
Endian::ToHost(pbuffer, 4, Endian::Intel);
pol[m].vtx_count = (ushort)*pbuffer++;
pol[m].binding = pbinding;
for (uint j = 0; j < pol[m].vtx_count; j++)
{
Endian::ToHost(pbuffer, 4, Endian::Intel);
*pbinding++ = *pbuffer++;
}
Endian::ToHost(pbuffer, 4, Endian::Intel);
pol[m].material = (ushort)*pbuffer++;
}
}
else __LOG_E__ << "Could not allocate polygon/binding memory.\n";
}
}
}
void Geometry::ParseAsciiPolygon(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol.Allocate(vt->GetInteger());
else if (vt->name == "BindingCount")
binding.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (binding && pol)
{
static String _PolyIndex("Index");
uint *pbinding = binding;
uint cpoly = 0;
NMLTagForeach(poly, *vt)
{
if (cpoly == pol.GetCount())
{
__LOG_E__ << "Corrupted <APolygon> tag, too many polygons.\n";
break;
}
Tag *count_tag = poly->GetTag("Count;"),
*material_tag = poly->GetTag("Material;");
pol[cpoly].vtx_count = 0;
pol[cpoly].binding = pbinding;
pol[cpoly].material = 0;
if (count_tag && material_tag)
{
pol[cpoly].vtx_count = (ushort)count_tag->GetInteger();
pol[cpoly].material = (ushort)material_tag->GetInteger();
NMLTagForeach(tag, *poly)
if (tag->name == _PolyIndex)
*pbinding++ = tag->GetInteger();
}
else __LOG_E__ << "Corrupt <Polygon> tag in <APolygon>.\n";
++cpoly;
}
}
else __LOG_E__ << "Could not allocate polygon/binding memory.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParsePolygonNormal(const Tag *pt)
{
NMLTagForeach(vt, *pt)
{
if (vt->name == "Count")
pol_normal.Allocate(vt->GetInteger());
else if (vt->name == "Data")
{
if (pol_normal)
{
char *pbuffer = (char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < pol.GetCount(); m++)
{
pol_normal[m].x = (float)(pbuffer[0]) / 127.f;
pol_normal[m].y = (float)(pbuffer[1]) / 127.f;
pol_normal[m].z = (float)(pbuffer[2]) / 127.f;
pol_normal[m].Normalize();
pbuffer += 3;
}
}
else __LOG_E__ << "Incomplete polygon normal chunk loading '" << name << "'.\n";
}
}
}
void Geometry::ParseVertexNormal(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <VNormal>.\n")
vtx_normal.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <VNormal>.\n")
if (vtx_normal)
{
signed char *pbuffer = (signed char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < vtx_normal.GetCount(); ++m)
{
vtx_normal[m].x = ((float)pbuffer[0]) / 127.f;
vtx_normal[m].y = ((float)pbuffer[1]) / 127.f;
vtx_normal[m].z = ((float)pbuffer[2]) / 127.f;
vtx_normal[m].Normalize();
pbuffer += 3;
}
}
else __LOG_E__ << "Incomplete vertex normal chunk loading '" << name << "'.\n";
}
void Geometry::ParseVertexTangent(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <VTangent>.\n")
vtx_tangent.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <VTangent>.\n")
// Allocate vertex normals.
if (vtx_tangent)
{
signed char *pbuffer = (signed char *)vt->GetValue().GetBinaryBuffer();
for (uint m = 0; m < vtx_tangent.GetCount(); ++m)
{
Vector4 &T = vtx_tangent[m].T, &B = vtx_tangent[m].B;
T.x = ((float)pbuffer[0]) / 127.f;
T.y = ((float)pbuffer[1]) / 127.f;
T.z = ((float)pbuffer[2]) / 127.f;
T.Normalize();
B.x = ((float)pbuffer[3]) / 127.f;
B.y = ((float)pbuffer[4]) / 127.f;
B.z = ((float)pbuffer[5]) / 127.f;
B.Normalize();
pbuffer += 6;
}
}
else __LOG_E__ << "Incomplete vertex tangent chunk loading '" << name << "'.\n";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseAsciiRGB(const Tag *pt)
{
Tag *vt = pt->GetTag("Count;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No count tag in <ARGB>.\n")
rgb.Allocate(vt->GetInteger());
vt = pt->GetTag("Data;");
if (!vt)
__ERRRAW__(__LOG_E__ << "No data tag in <ARGB>.\n")
if (rgb)
{
uint rgb_count = 0;
NMLTagForeach(rt, *vt)
{
if (rgb_count == rgb.GetCount())
{
__LOG_E__ << "Too many <Value> tags in RGB list of geometry '" << name << "'.\n";
break;
}
Tag *r_tag = rt->GetTypedTag("R;", Variant::VariantFloat),
*g_tag = rt->GetTypedTag("G;", Variant::VariantFloat),
*b_tag = rt->GetTypedTag("B;", Variant::VariantFloat),
*a_tag = rt->GetTypedTag("A;", Variant::VariantFloat);
rgb[rgb_count].x = r_tag ? r_tag->GetReal() : 0;
rgb[rgb_count].y = g_tag ? g_tag->GetReal() : 0;
rgb[rgb_count].z = b_tag ? b_tag->GetReal() : 0;
rgb[rgb_count].w = a_tag ? a_tag->GetReal() : 1;
++rgb_count;
}
if (rgb_count != rgb.GetCount())
__LOG_W__ << "Not enough <Value> tags in RGB list of geometry '" << name << "'.\n";
}
else __LOG_E__ << "Could not allocate RGB for geometry '" << name << "'.\n";
}
void Geometry::ParseRGB(const Tag *pt)
{
if (Tag *vt = pt->GetTag("Data"))
{
float *pbuffer = (float *)vt->GetValue().GetBinaryBuffer();
size_t size = vt->GetValue().GetBinarySize();
if (rgb.Allocate(binding.GetCount()))
{
uint components = (size == binding.GetCount() * 4) ? 4 : 3;
for (uint m = 0; m < rgb.GetCount(); m++)
{
for (uint n = 0; n < components; ++n)
Endian::ToHost(&pbuffer[n], 4, Endian::Intel);
rgb[m].Set(pbuffer[0], pbuffer[1], pbuffer[2]);
rgb[m].w = components == 4 ? pbuffer[3] : 1.f;
pbuffer += components;
}
}
else __LOG_E__ << "Could not allocate RGB channel for geometry '" << name << "'.\n";
}
else __LOG_E__ << "Expected <Data> tag under <RGB> tag.\n";
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseUV(const Tag *pt)
{
uint current_uv = 0;
NMLTagForeach(vt, *pt)
{
if (vt->name != "Data")
continue;
if (current_uv == __UV_PER_GEOMETRY__)
{
__LOG_W__ << "Geometry '" << name << "' requires more UV channels than this build can handle.\n";
__LOG_W__ << "Please increase nUVMapCount and recompile to fully import this object.\n";
break;
}
float *pbuffer = (float *)vt->GetValue().GetBinaryBuffer();
if (uv[current_uv].Allocate(binding.GetCount()))
for (uint m = 0; m < binding.GetCount(); ++m)
{
for (int n = 0; n < 2; ++n)
Endian::ToHost(&pbuffer[n], 4, Endian::Intel);
uv[current_uv][m].x = pbuffer[0];
uv[current_uv][m].y = pbuffer[1];
pbuffer += 2;
}
else
__LOG_E__ << "could not allocate UV channel for geometry '" << name << "'.\n";
++current_uv;
}
}
void Geometry::ParseAsciiUV(const Tag *pt)
{
uint current_uv = 0;
NMLTagForeach(vt, *pt)
{
if (vt->name != "Data")
continue;
if (uv[current_uv].Allocate(binding.GetCount()))
{
uint uv_index = 0;
NMLTagForeach(uvt, *vt)
{
if (uv_index == binding.GetCount())
{
__LOG_E__ << "Too many <Value> tags in UV channel " << current_uv << " of geometry '" << name << "'.\n";
break;
}
Tag *u_tag = uvt->GetTypedTag("U;", Variant::VariantFloat),
*v_tag = uvt->GetTypedTag("V;", Variant::VariantFloat);
uv[current_uv][uv_index].x = u_tag ? u_tag->GetReal() : 0;
uv[current_uv][uv_index].y = v_tag ? v_tag->GetReal() : 0;
uv_index++;
}
}
else __LOG_E__ << "could not allocate UV channel for geometry '" << name << "'.\n";
if (++current_uv == __UV_PER_GEOMETRY__)
{
__LOG_W__ << "'" << name << "' requires more UV channels than this build can handle.\n";
__LOG_W__ << " Please increase nUVMapCount and recompile nEngine to fully import this object.\n";
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseMaterials(const Tag *pt)
{
// First pass, material count.
uint slot_count = 0;
NMLTagForeach(mt, *pt)
if ((mt->name == "Material") || (mt->name == "MaterialRef") || (mt->name == "MaterialRefEx"))
slot_count++;
// Allocate slots.
if (material_table.Allocate(slot_count))
{
slot_count = 0;
NMLTagForeach(mt, *pt)
{
String mref;
bool use_cache = true;
if (mt->name == "Material")
IEmbeddedResourceHandler::Get()->ExtractEmbeddedMaterial(mref, *mt, name, slot_count);
else if (mt->name == "MaterialRef")
mref = mt->GetString();
else if (mt->name == "MaterialRefEx")
{
if (Tag *t = mt->GetTypedTag("Name", Variant::VariantString))
mref = t->GetString();
if (Tag *t = mt->GetTypedTag("UseCache", Variant::VariantBool))
use_cache = t->GetBool();
}
material_table[slot_count].name = mref;
material_table[slot_count].use_cache = use_cache;
++slot_count;
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Geometry::ParseMisc(const Tag &tag)
{
NMLTagForeach(pt, tag)
{
if (pt->name == "LodDistance")
lod_distance = pt->GetReal();
else if (pt->name == "LodNull")
flag.Raise(FlagNullLodProxy, pt->GetBool());
else if (pt->name == "ShadowNull")
flag.Raise(FlagNullShadowProxy, pt->GetBool());
else if (pt->name == "CopyLock")
copy_lock = pt->GetString();
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Geometry::FromMetaTag(const Tag &tag)
{
Benchmark bench(true);
// Build binary objects base name.
if (tag.name != "Geometry")
__ERR__(__LOG_E__ << "Could not parse material, incorrect root tag (" << tag.name << ")...\n", false)
Free();
// Parse root tags.
Tag *pt;
if ((pt = tag.GetTag("Materials")) != NULL)
ParseMaterials(pt);
if ((pt = tag.GetTag("Vertex")) != NULL)
ParseVertex(pt);
else
if ((pt = tag.GetTag("AVertex")) != NULL)
ParseAsciiVertex(pt);
if ((pt = tag.GetTag("Polygon")) != NULL)
ParsePolygon(pt);
else
if ((pt = tag.GetTag("APolygon")) != NULL)
ParseAsciiPolygon(pt);
if ((pt = tag.GetTag("PNormal")) != NULL)
ParsePolygonNormal(pt);
if ((pt = tag.GetTag("VNormal")) != NULL)
ParseVertexNormal(pt);
if ((pt = tag.GetTag("VTangent")) != NULL)
ParseVertexTangent(pt);
if ((pt = tag.GetTag("Skin")) != NULL)
ParseSkin(pt);
if ((pt = tag.GetTag("RGB")) != NULL)
ParseRGB(pt);
else
if ((pt = tag.GetTag("ARGB")) != NULL)
ParseAsciiRGB(pt);
if ((pt = tag.GetTag("UV")) != NULL)
ParseUV(pt);
else
if ((pt = tag.GetTag("AUV")) != NULL)
ParseAsciiUV(pt);
if ((pt = tag.GetTag("LodProxy")) != NULL)
lod_proxy = pt->GetString();
if ((pt = tag.GetTag("ShadowProxy")) != NULL)
shadow_proxy = pt->GetString();
ParseMisc(tag);
// Quick integrity check.
if (!vtx.GetCount())
__ERR__(__LOG_E__ << "No vertice in geometry '" << name << "'.\n", false)
if (!pol.GetCount())
__ERR__(__LOG_E__ << "No polygon in geometry '" << name << "'.\n", false)
if (vtx_tangent.IsNull())
ComputeVertexTangent();
bench.Stop();
__LOG__ << "Geometry::FromMetaTag(Tag &tag) done in " << bench.GetMs() << "ms. " << vtx.GetCount() << " vertice, " << pol.GetCount() << " polygon(s), " << material_table.GetCount() << " material(s).\n";
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Geometry::AsMetaTag() const
{
// Integrity check.
if (!vtx.GetCount() || !pol.GetCount() || !material_table.GetCount())
__ERR__(__LOG_E__ << "Cannot serialize '" << name << "', geometry is empty.\n", NULL)
Tag *root = new Tag("Geometry");
if (!root)
__ERR__(__LOG_E__ << "Could not create root tag to serialize geometry '" << name << "'.\n", NULL)
uint n;
// Vertice.
if (Tag *vertex = root->AddChild("Vertex"))
{
vertex->AddChild("Count", (int)vtx.GetCount());
if (float *vtx_rl = new float[vtx.GetCount() * 3])
{
for (n = 0; n < vtx.GetCount(); n++)
{
vtx_rl[n * 3 + 0] = vtx[n].x;
vtx_rl[n * 3 + 1] = vtx[n].y;
vtx_rl[n * 3 + 2] = vtx[n].z;
}
vertex->AddChild("Data", (uchar *)vtx_rl, vtx.GetCount() * 3 * sizeof(float));
_safe_delete_array(vtx_rl);
}
else
__LOG_E__ << "Failed to allocate raw vertice buffer.\n";
}
// Polygons.
if (Tag *polygon = root->AddChild("Polygon"))
{
polygon->AddChild("Count", (int)pol.GetCount());
polygon->AddChild("BindingCount", (int)binding.GetCount());
if (uint *pol_u4 = new uint[binding.GetCount() + pol.GetCount() * 2])
{
uint *ptr = pol_u4;
for (n = 0; n < pol.GetCount(); n++)
{
*ptr++ = pol[n].vtx_count;
for (uint m = 0; m < pol[n].vtx_count; m++)
*ptr++ = pol[n].binding[m];
*ptr++ = (uint)pol[n].material;
}
polygon->AddChild("Data", (uchar *)pol_u4, (binding.GetCount() + pol.GetCount() * 2) * sizeof(uint));
_safe_delete_array(pol_u4);
}
else
__LOG_E__ << "Failed to allocate raw polygon buffer.\n";
}
// Polygon normals.
if (pol_normal)
if (Tag *pnormal = root->AddChild("PNormal"))
{
pnormal->AddChild("Count", (int)pol.GetCount());
if (char *pnrm = new char[pol.GetCount() * 3])
{
char *ptr = pnrm;
for (n = 0; n < pol.GetCount(); n++)
{
*ptr++ = (char)(pol_normal[n].x * 127.f);
*ptr++ = (char)(pol_normal[n].y * 127.f);
*ptr++ = (char)(pol_normal[n].z * 127.f);
}
pnormal->AddChild("Data", (uchar *)pnrm, pol.GetCount() * 3);
_safe_delete_array(pnrm);
}
else
__LOG_E__ << "Failed to allocate raw normal buffer.\n";
}
// Vertex normals.
if (vtx_normal)
if (Tag *vnormal = root->AddChild("VNormal"))
{
vnormal->AddChild("Count", (int)binding.GetCount());
if (char *vnrm = new char[binding.GetCount() * 3])
{
char *ptr = vnrm;
for (n = 0; n < binding.GetCount(); n++)
{
*ptr++ = (char)(vtx_normal[n].x * 127.f);
*ptr++ = (char)(vtx_normal[n].y * 127.f);
*ptr++ = (char)(vtx_normal[n].z * 127.f);
}
vnormal->AddChild("Data", (uchar *)vnrm, binding.GetCount() * 3);
_safe_delete_array(vnrm);
}
else
__LOG_E__ << "Failed to allocate raw normal buffer.\n";
}
// Vertex tangent frames.
if (vtx_tangent)
if (Tag *vtangent = root->AddChild("VTangent"))
{
vtangent->AddChild("Count", (int)binding.GetCount());
if (char *vfrm = new char[binding.GetCount() * 6])
{
char *ptr = vfrm;
for (n = 0; n < binding.GetCount(); n++)
{
*ptr++ = (char)(vtx_tangent[n].T.x * 127.f);
*ptr++ = (char)(vtx_tangent[n].T.y * 127.f);
*ptr++ = (char)(vtx_tangent[n].T.z * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.x * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.y * 127.f);
*ptr++ = (char)(vtx_tangent[n].B.z * 127.f);
}
vtangent->AddChild("Data", (uchar *)vfrm, binding.GetCount() * 6);
_safe_delete_array(vfrm);
}
else
__LOG_E__ << "Failed to allocate raw tangent frame buffer.\n";
}
// Output RGB.
if (rgb)
if (Tag *rgbtag = root->AddChild("RGB"))
{
// Test if we need to output alpha.
uint num_comp = 3;
for (uint m = 0; m < binding.GetCount(); ++m)
if (rgb[m].w < 1.f)
{
num_comp = 4;
break;
}
// Output buffer.
if (float *rgbbuf = new float[binding.GetCount() * num_comp])
{
float *prgb = rgbbuf;
for (uint m = 0; m < binding.GetCount(); ++m)
{
prgb[0] = rgb[m].x;
prgb[1] = rgb[m].y;
prgb[2] = rgb[m].z;
if (num_comp == 4)
prgb[3] = rgb[m].w;
prgb += num_comp;
}
rgbtag->AddChild("Data", (uchar *)rgbbuf, binding.GetCount() * num_comp * sizeof(float));
_safe_delete_array(rgbbuf);
}
}
// Output UVs.
if (GetUVCount())
if (Tag *uvtag = root->AddChild("UV"))
{
uvtag->AddChild("Count", (int)GetUVCount()); // LEGACY
if (float *uvbuf = new float[binding.GetCount() * 2])
{
for (n = 0; n < __UV_PER_GEOMETRY__; ++n)
if (uv[n])
{
for (uint m = 0; m < binding.GetCount(); m++)
{
uvbuf[m * 2 + 0] = uv[n][m].x;
uvbuf[m * 2 + 1] = uv[n][m].y;
}
uvtag->AddChild("Data", (uchar *)uvbuf, binding.GetCount() * 2 * sizeof(float));
}
_safe_delete_array(uvbuf);
}
else
__LOG_E__ << "Failed to allocate raw UVs buffer.\n";
}
// Output vertex weights.
if (bone_name.GetCount())
{
Tag *skintag = root->AddChild("Skin");
// Save bone id list.
if (Tag *bonetag = skintag->AddChild("Bones"))
for (uint n = 0; n < bone_name.GetCount(); ++n)
bonetag->AddChild("Id", bone_name[n]);
else
__LOG_E__ << "Failed to allocate bone id tag.\n";
// Save bone binding matrix.
if (Tag *bindtag = skintag->AddChild("Binds"))
for (uint n = 0; n < bone_name.GetCount(); ++n)
bindtag->AddChild(bone_bind_matrix[n].AsMetaTag("Matrix"));
else
__LOG_E__ << "Failed to allocate bone binding tag.\n";
// Save bone association/weights.
Tag *weighttag = skintag->AddChild("Weights");
for (uint n = 0; n < vtx.GetCount(); ++n)
weighttag->AddChild
(
"W", String::Format
( "%d,%d,%d,%d:%d,%d,%d,%d",
skin[n].bone_index[0], skin[n].bone_index[1], skin[n].bone_index[2], skin[n].bone_index[3],
(int)(skin[n].w[0] * 255.f), (int)(skin[n].w[1] * 255.f), (int)(skin[n].w[2] * 255.f), (int)(skin[n].w[3] * 255.f)).toUtf8()
);
}
// Proxies.
if (!lod_proxy.IsEmpty())
root->AddChild("LodProxy", lod_proxy.c_str());
if (lod_distance != Units::Mtr(100.f))
root->AddChild("LodDistance", lod_distance);
if (flag.IsSet(FlagNullLodProxy))
root->AddChild("LodNull", true);
if (!shadow_proxy.IsEmpty())
root->AddChild("ShadowProxy", shadow_proxy.c_str());
if (flag.IsSet(FlagNullShadowProxy))
root->AddChild("ShadowNull", true);
// Serialize materials.
if (Tag *mtag = root->AddChild("Materials"))
for (n = 0; n < material_table.GetCount(); n++)
if (Tag *extag = mtag->AddChild("MaterialRefEx"))
{
extag->AddChild("Name", material_table[n].name.c_str());
if (!material_table[n].use_cache)
extag->AddChild("UseCache", material_table[n].use_cache);
}
// Copyright lock.
if (!copy_lock.IsEmpty())
root->AddChild("CopyLock", copy_lock);
return root;
}
//------------------------------------------------------------------------------