commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
853
include/engine/core/geometry_nml.cpp
Normal file
853
include/engine/core/geometry_nml.cpp
Normal 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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user