commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
449
include/engine/core/geometry.cpp
Normal file
449
include/engine/core/geometry.cpp
Normal file
@ -0,0 +1,449 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "core/geometry.h"
|
||||
#include "math/matrix4.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
|
||||
static const float HomogeneousDistance = Units::Mm(0.01f);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Core::ComputeVertexArrayMinMax(const Array <Vector4> &vtx, MinMax &mm, const Matrix4 *mtx)
|
||||
{
|
||||
if (!vtx.GetCount())
|
||||
return false;
|
||||
|
||||
Vector4 tvt = mtx ? vtx[0] * mtx[0] : vtx[0], mn = tvt, mx = tvt;
|
||||
|
||||
if (mtx)
|
||||
for (uint n = 0; n < vtx.GetCount(); ++n)
|
||||
{
|
||||
tvt = vtx[n] * mtx[0];
|
||||
if (tvt.x > mx.x) mx.x = tvt.x;
|
||||
if (tvt.y > mx.y) mx.y = tvt.y;
|
||||
if (tvt.z > mx.z) mx.z = tvt.z;
|
||||
if (tvt.x < mn.x) mn.x = tvt.x;
|
||||
if (tvt.y < mn.y) mn.y = tvt.y;
|
||||
if (tvt.z < mn.z) mn.z = tvt.z;
|
||||
}
|
||||
else
|
||||
for (uint n = 0; n < vtx.GetCount(); ++n)
|
||||
{
|
||||
tvt = vtx[n];
|
||||
if (tvt.x > mx.x) mx.x = tvt.x;
|
||||
if (tvt.y > mx.y) mx.y = tvt.y;
|
||||
if (tvt.z > mx.z) mx.z = tvt.z;
|
||||
if (tvt.x < mn.x) mn.x = tvt.x;
|
||||
if (tvt.y < mn.y) mn.y = tvt.y;
|
||||
if (tvt.z < mn.z) mn.z = tvt.z;
|
||||
}
|
||||
|
||||
mm.mn = mn;
|
||||
mm.mx = mx;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Geometry::GetUVCount() const
|
||||
{
|
||||
uint c = 0;
|
||||
for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n)
|
||||
if (uv[n])
|
||||
++c;
|
||||
return c;
|
||||
}
|
||||
uint Geometry::GetBoneCount() const
|
||||
{ return bone_name.GetCount(); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Geometry::ComputeBoneBoundingVolumes(Array <MinMax> &bone_mm) const
|
||||
{
|
||||
uint bone_count = bone_bind_matrix.GetCount();
|
||||
|
||||
if (skin.IsNull() || !bone_count)
|
||||
return false;
|
||||
|
||||
if (!bone_mm.Allocate(bone_count))
|
||||
__ERR__(__LOG_E__ << "Failed to allocate bon minmax array.\n", false)
|
||||
|
||||
Array <bool> bone_mm_init(bone_count);
|
||||
for (uint n = 0; n < bone_count; ++n)
|
||||
bone_mm_init[n] = false;
|
||||
|
||||
for (uint v = 0; v < vtx.GetCount(); ++v)
|
||||
for (int b = 0; b < __PV_BONE_LIMIT__; ++b)
|
||||
if (skin[v].w[b] > 0.f)
|
||||
{
|
||||
int idx = skin[v].bone_index[b];
|
||||
|
||||
if (!bone_mm_init[idx])
|
||||
{
|
||||
bone_mm[idx].Set(vtx[v], vtx[v]);
|
||||
bone_mm_init[idx] = true;
|
||||
}
|
||||
else
|
||||
bone_mm[idx].Grow(vtx[v]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Geometry::ComputePolygonBindingCount() const
|
||||
{
|
||||
uint c = 0;
|
||||
for (uint n = 0; n < pol.GetCount(); ++n)
|
||||
c += pol[n].vtx_count;
|
||||
return c;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
MinMax Geometry::ComputeMinMax(const Matrix4 *mtx) const
|
||||
{
|
||||
MinMax mm;
|
||||
ComputeVertexArrayMinMax(vtx, mm, mtx);
|
||||
return mm;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Geometry::AllocateVertex(uint count)
|
||||
{ return vtx.Allocate(count); }
|
||||
bool Geometry::AllocatePolygon(uint count)
|
||||
{
|
||||
binding.Free();
|
||||
return pol.Allocate(count);
|
||||
}
|
||||
bool Geometry::AllocatePolygonBinding()
|
||||
{
|
||||
uint count = ComputePolygonBindingCount();
|
||||
|
||||
if (!binding.Allocate(count))
|
||||
return false;
|
||||
|
||||
count = 0;
|
||||
for (uint n = 0; n < pol.GetCount(); ++n)
|
||||
{
|
||||
pol[n].binding = &binding[count];
|
||||
count += pol[n].vtx_count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Geometry::AllocateBone(uint count)
|
||||
{ return bone_name.Allocate(count) && bone_bind_matrix.Allocate(count); }
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Geometry::ComputePolygonIndex(Array <uint> &i) const
|
||||
{
|
||||
if (i.Allocate(pol.GetCount()))
|
||||
for (uint pc = 0, ci = 0; pc < pol.GetCount(); ++pc)
|
||||
{
|
||||
i[pc] = ci;
|
||||
ci += pol[pc].vtx_count;
|
||||
}
|
||||
}
|
||||
void Geometry::ComputeVertexToPolygon(Array <VertexToPolygon> &vtx_to_pol) const
|
||||
{
|
||||
if (!pol || !vtx)
|
||||
return;
|
||||
|
||||
Array <uint> pol_per_vtx(vtx.GetCount());
|
||||
if (!pol_per_vtx)
|
||||
return;
|
||||
|
||||
Memory::Set(&pol_per_vtx[0], 0, pol_per_vtx.GetSize());
|
||||
|
||||
uint p, v;
|
||||
for (p = 0; p < pol.GetCount(); ++p)
|
||||
for (v = 0; v < pol[p].vtx_count; ++v)
|
||||
pol_per_vtx[pol[p].binding[v]]++;
|
||||
|
||||
vtx_to_pol.Allocate(vtx.GetCount());
|
||||
for (v = 0; v < vtx.GetCount(); ++v)
|
||||
{
|
||||
vtx_to_pol[v].pol_count = 0;
|
||||
vtx_to_pol[v].pol_index.Allocate(pol_per_vtx[v]);
|
||||
}
|
||||
|
||||
for (p = 0; p < pol.GetCount(); ++p)
|
||||
for (v = 0; v < pol[p].vtx_count; ++v)
|
||||
vtx_to_pol[pol[p].binding[v]].pol_index[vtx_to_pol[pol[p].binding[v]].pol_count++] = p;
|
||||
}
|
||||
void Geometry::ComputeVertexToVertex(Array <VertexToVertex> &vtx_to_vtx, const Array <VertexToPolygon> *vtx_to_pol) const
|
||||
{
|
||||
if (!pol || !vtx)
|
||||
return;
|
||||
|
||||
// Allocate vertex to vertex buffer.
|
||||
if (!vtx_to_vtx.Allocate(vtx.GetCount()))
|
||||
__ERRRAW__(__LOG_E__ << "Could not allocate memory.\n")
|
||||
|
||||
// Allocate work area.
|
||||
#define __VertexToVertexTempListSize 1024
|
||||
PolygonVertex tmp_vtx_to_vtx[__VertexToVertexTempListSize];
|
||||
|
||||
// Compute vertex to polygon if not provided.
|
||||
Array <VertexToPolygon> _vtx_to_pol;
|
||||
if (!vtx_to_pol)
|
||||
{
|
||||
vtx_to_pol = &_vtx_to_pol;
|
||||
ComputeVertexToPolygon(_vtx_to_pol);
|
||||
}
|
||||
|
||||
for (int pass = 0; pass < 2; ++pass)
|
||||
for (uint v = 0; v < vtx.GetCount(); ++v)
|
||||
{
|
||||
vtx_to_vtx[v].vtx_count = 0;
|
||||
|
||||
uint vtx_vtx_count = 0;
|
||||
for (uint p = 0; p < (*vtx_to_pol)[v].pol_count; ++p)
|
||||
{
|
||||
uint pol_index = (*vtx_to_pol)[v].pol_index[p];
|
||||
Polygon *poly = &pol[pol_index];
|
||||
|
||||
int ci;
|
||||
for (ci = 0; ci < poly->vtx_count; ++ci)
|
||||
if (poly->binding[ci] == v)
|
||||
break;
|
||||
|
||||
for (int _c = (ci - 1); _c <= (ci + 1); _c += 2)
|
||||
{
|
||||
int vtx_index = _c;
|
||||
if (vtx_index < 0)
|
||||
vtx_index += poly->vtx_count;
|
||||
if (vtx_index >= poly->vtx_count)
|
||||
vtx_index -= poly->vtx_count;
|
||||
|
||||
// Invalidate already registered candidate.
|
||||
bool insert = true;
|
||||
for (uint nl = 0; nl < vtx_vtx_count; ++nl)
|
||||
if ((tmp_vtx_to_vtx[nl].pol_index == pol_index) && (tmp_vtx_to_vtx[nl].vtx_index == (uint)vtx_index))
|
||||
{
|
||||
insert = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
tmp_vtx_to_vtx[vtx_vtx_count].pol_index = pol_index;
|
||||
tmp_vtx_to_vtx[vtx_vtx_count].vtx_index = vtx_index;
|
||||
|
||||
if (vtx_vtx_count == __VertexToVertexTempListSize)
|
||||
{
|
||||
__LOG_E__ << "Temporary list exceeded, vertex to vertex LUT corrupted.\n";
|
||||
vtx_vtx_count = __VertexToVertexTempListSize - 1;
|
||||
}
|
||||
|
||||
if (pass == 1)
|
||||
{
|
||||
vtx_to_vtx[v].vtx[vtx_vtx_count].pol_index = pol_index;
|
||||
vtx_to_vtx[v].vtx[vtx_vtx_count].vtx_index = vtx_index;
|
||||
}
|
||||
++vtx_vtx_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate vertex container for this vertex.
|
||||
if (pass == 0)
|
||||
vtx_to_vtx[v].vtx.Allocate(vtx_vtx_count);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Geometry::FlagHomogeneousVertex(Array <bool> &flag, const Array <uint> &pol_index, const Array <VertexToPolygon> &vtx_to_pol, int mat) const
|
||||
{
|
||||
if (!flag.Allocate(vtx.GetCount()))
|
||||
__ERRRAW__(__LOG_E__ << "Could not allocate homogeneous vertex table.\n")
|
||||
for (uint n = 0; n < vtx.GetCount(); ++n)
|
||||
flag[n] = true;
|
||||
|
||||
#if 0
|
||||
// Test for early exit in case no polygon uses this material.
|
||||
for (uint n = 0; n < pol.GetCount(); n++)
|
||||
if (pol[n].material == n)
|
||||
break;
|
||||
if (n == pol.GetCount())
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (uint m = 0; m < vtx.GetCount(); ++m)
|
||||
{
|
||||
uint ngeo = vtx_to_pol[m].pol_count;
|
||||
for (uint ac = 0; ac < ngeo; ++ac)
|
||||
for (uint bc = 0; bc < ngeo; ++bc)
|
||||
{
|
||||
uint i_ac = vtx_to_pol[m].pol_index[ac],
|
||||
i_bc = vtx_to_pol[m].pol_index[bc];
|
||||
Polygon *apoly = &pol[i_ac], *bpoly = &pol[i_bc];
|
||||
|
||||
if (apoly == bpoly)
|
||||
continue;
|
||||
if (apoly->material == bpoly->material)
|
||||
{
|
||||
if ((mat == -1) || (apoly->material == (uint)mat))
|
||||
{
|
||||
uint _u, _v;
|
||||
for (_u = 0; _u < apoly->vtx_count; ++_u)
|
||||
if ( apoly->binding[_u] == m )
|
||||
break;
|
||||
for (_v = 0; _v < bpoly->vtx_count; ++_v)
|
||||
if ( bpoly->binding[_v] == m )
|
||||
break;
|
||||
|
||||
if (vtx_normal)
|
||||
if (Vector4::Dist2(vtx_normal[pol_index[i_ac] + _u], vtx_normal[pol_index[i_bc] + _v]) > HomogeneousDistance)
|
||||
flag[m] = false;
|
||||
/*
|
||||
if (vtx_tangent)
|
||||
if (
|
||||
(nVector::Dist2(vtx_tangent[pol_index[i_ac] + _u].B, vtx_tangent[pol_index[i_bc] + _v].B) > HomogeneousDistance) ||
|
||||
(nVector::Dist2(vtx_tangent[pol_index[i_ac] + _u].T, vtx_tangent[pol_index[i_bc] + _v].T) > HomogeneousDistance)
|
||||
)
|
||||
vtx_homogeneous[m] = false;
|
||||
*/
|
||||
if (rgb)
|
||||
if (Vector4::Dist2(rgb[pol_index[i_ac] + _u], rgb[pol_index[i_bc] + _v]) > HomogeneousDistance)
|
||||
flag[m] = false;
|
||||
|
||||
for (uint cuv = 0; cuv < __UV_PER_GEOMETRY__; ++cuv)
|
||||
if (uv[cuv])
|
||||
if (Vector2::Dist2(uv[cuv][pol_index[i_ac] + _u], uv[cuv][pol_index[i_bc] + _v]) > HomogeneousDistance)
|
||||
flag[m] = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
flag[m] = false;
|
||||
|
||||
if (!flag[m])
|
||||
goto nxth;
|
||||
}
|
||||
nxth:;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
uint Geometry::MergeDuplicateMaterials()
|
||||
{
|
||||
if (material_table.GetCount() < 2)
|
||||
return 0;
|
||||
|
||||
__LOG_H__ << "Merging materials in geometry '" << name << "'...\n";
|
||||
|
||||
// Build the drop table.
|
||||
uint old_slot_count = material_table.GetCount();
|
||||
Array <bool> drop(material_table.GetCount());
|
||||
for (uint n = 0; n < material_table.GetCount(); ++n)
|
||||
drop[n] = false;
|
||||
|
||||
Array <uint> material_remap(material_table.GetCount());
|
||||
for (uint n = 0; n < material_table.GetCount(); ++n)
|
||||
material_remap[n] = n;
|
||||
|
||||
// Flag materials to drop.
|
||||
for (uint n = 0; n < material_table.GetCount(); ++n)
|
||||
{
|
||||
if (drop[n]) // Already dropped.
|
||||
continue;
|
||||
|
||||
for (uint m = n + 1; m < material_table.GetCount(); ++m)
|
||||
{
|
||||
// Check by material name.
|
||||
if (material_table[n].name != material_table[m].name)
|
||||
goto skip_material_drop;
|
||||
|
||||
// Drop material.
|
||||
drop[m] = true;
|
||||
material_remap[m] = n;
|
||||
|
||||
skip_material_drop:;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new material array.
|
||||
uint new_material_slot_count = 0;
|
||||
for (uint n = 0; n < material_table.GetCount(); ++n)
|
||||
if (!drop[n])
|
||||
new_material_slot_count++;
|
||||
|
||||
Array <Geometry::MaterialSlot> new_material_slot(new_material_slot_count);
|
||||
new_material_slot_count = 0;
|
||||
for (uint n = 0; n < material_table.GetCount(); ++n)
|
||||
if (!drop[n])
|
||||
{
|
||||
for (uint m = 0; m < material_table.GetCount(); ++m)
|
||||
if (material_remap[m] == n)
|
||||
material_remap[m] = new_material_slot_count;
|
||||
|
||||
new_material_slot[new_material_slot_count].name = material_table[n].name;
|
||||
new_material_slot[new_material_slot_count].use_cache = material_table[n].use_cache;
|
||||
++new_material_slot_count;
|
||||
}
|
||||
|
||||
material_table.Transfer(new_material_slot);
|
||||
|
||||
// Remap polygon references.
|
||||
for (uint n = 0; n < pol.GetCount(); ++n)
|
||||
pol[n].material = (ushort)material_remap[pol[n].material];
|
||||
|
||||
uint merge_count = old_slot_count - material_table.GetCount();
|
||||
|
||||
__LOG__ << "Done, merged " << merge_count << " material slot(s).\n";
|
||||
return merge_count;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Geometry::Free()
|
||||
{
|
||||
bone_name.Free();
|
||||
skin.Free();
|
||||
bone_bind_matrix.Free();
|
||||
|
||||
vtx.Free();
|
||||
vtx_normal.Free();
|
||||
vtx_tangent.Free();
|
||||
pol_normal.Free();
|
||||
pol_tangent.Free();
|
||||
pol.Free();
|
||||
binding.Free();
|
||||
|
||||
for (uint n = 0; n < __UV_PER_GEOMETRY__; n++)
|
||||
uv[n].Free();
|
||||
rgb.Free();
|
||||
|
||||
material_table.Free();
|
||||
|
||||
lod_proxy = NULL;
|
||||
lod_distance = Units::Mtr(100.f);
|
||||
|
||||
shadow_proxy = NULL;
|
||||
|
||||
flag.Raise(FlagNullShadowProxy | FlagNullLodProxy, false);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Geometry::Geometry()
|
||||
{
|
||||
lod_distance = Units::Mtr(100.f);
|
||||
}
|
||||
Geometry::~Geometry()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user