202 lines
5.6 KiB
C++
202 lines
5.6 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include "tools/geometry_merge.h"
|
|
#include "core/geometry.h"
|
|
#include "math/matrix4.h"
|
|
#include "log/log.h"
|
|
|
|
using namespace GS::Core;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
Geometry *GS::Core::MergeGeometry(Geometry *geo_a, Geometry *geo_b, const Matrix4 *mtx_a, const Matrix4 *mtx_b)
|
|
{
|
|
if (!geo_a || !geo_b)
|
|
__ERR__(__LOG_E__ << "Cannot merge NULL geometry.\n", NULL)
|
|
|
|
if (!mtx_a)
|
|
mtx_a = &Matrix4::IdentityMatrix();
|
|
if (!mtx_b)
|
|
mtx_b = &Matrix4::IdentityMatrix();
|
|
|
|
// Allocate a new geometry.
|
|
Geometry *geo_o = new Geometry;
|
|
if (!geo_o)
|
|
__ERR__(__LOG_E__ << "Failed to allocate merged geometry.\n", NULL)
|
|
|
|
geo_o->name = geo_a->name; // Nothing fancy here, the string length would blow up on large merge.
|
|
|
|
// Update data for all geometries.
|
|
if (geo_a->pol_normal || geo_b->pol_normal)
|
|
{
|
|
geo_a->ComputePolygonNormal();
|
|
geo_b->ComputePolygonNormal();
|
|
}
|
|
if (geo_a->vtx_normal || geo_b->vtx_normal)
|
|
{
|
|
geo_a->ComputeVertexNormal();
|
|
geo_b->ComputeVertexNormal();
|
|
}
|
|
|
|
// Append vertex.
|
|
if (geo_o->vtx.Allocate(geo_a->vtx.GetCount() + geo_b->vtx.GetCount()))
|
|
{
|
|
Vector4 *pvtx = &geo_o->vtx[0];
|
|
for (uint n = 0; n < geo_a->vtx.GetCount(); ++n)
|
|
*pvtx++ = geo_a->vtx[n] * *mtx_a;
|
|
for (uint n = 0; n < geo_b->vtx.GetCount(); ++n)
|
|
*pvtx++ = geo_b->vtx[n] * *mtx_b;
|
|
}
|
|
|
|
// Append polygon.
|
|
if (geo_o->binding.Allocate(geo_a->binding.GetCount() + geo_b->binding.GetCount()))
|
|
{
|
|
uint *pbind = &geo_o->binding[0];
|
|
for (uint n = 0; n < geo_a->binding.GetCount(); ++n)
|
|
*pbind++ = geo_a->binding[n];
|
|
for (uint n = 0; n < geo_b->binding.GetCount(); ++n)
|
|
*pbind++ = geo_b->binding[n] + geo_a->vtx.GetCount();
|
|
}
|
|
|
|
if (geo_o->pol.Allocate(geo_a->pol.GetCount() + geo_b->pol.GetCount()))
|
|
{
|
|
uint total_binding = 0;
|
|
|
|
Polygon *ppol = &geo_o->pol[0];
|
|
for (uint n = 0; n < geo_a->pol.GetCount(); ++n)
|
|
{
|
|
ppol->vtx_count = geo_a->pol[n].vtx_count;
|
|
ppol->material = geo_a->pol[n].material;
|
|
ppol->binding = &geo_o->binding[total_binding];
|
|
total_binding += ppol->vtx_count;
|
|
ppol++;
|
|
}
|
|
for (uint n = 0; n < geo_b->pol.GetCount(); ++n)
|
|
{
|
|
ppol->vtx_count = geo_b->pol[n].vtx_count;
|
|
ppol->material = (ushort)(geo_b->pol[n].material + geo_a->material_table.GetCount());
|
|
ppol->binding = &geo_o->binding[total_binding];
|
|
total_binding += ppol->vtx_count;
|
|
ppol++;
|
|
}
|
|
}
|
|
|
|
// Append polygon normal.
|
|
static Vector4 default_normal(0, 0, 1);
|
|
|
|
if (geo_a->pol_normal || geo_b->pol_normal)
|
|
if (geo_o->pol_normal.Allocate(geo_o->pol.GetCount()))
|
|
{
|
|
Vector4 *ppnrm = &geo_o->pol_normal[0];
|
|
for (uint n = 0; n < geo_a->pol.GetCount(); ++n)
|
|
{
|
|
if (geo_a->pol_normal)
|
|
{
|
|
mtx_a->ApplyRotation(ppnrm, &geo_a->pol_normal[n]);
|
|
*ppnrm++ = ppnrm->Normalized();
|
|
}
|
|
else
|
|
*ppnrm++ = default_normal;
|
|
}
|
|
for (uint n = 0; n < geo_b->pol.GetCount(); ++n)
|
|
{
|
|
if (geo_b->pol_normal)
|
|
{
|
|
mtx_b->ApplyRotation(ppnrm, &geo_b->pol_normal[n]);
|
|
*ppnrm++ = ppnrm->Normalized();
|
|
}
|
|
else
|
|
*ppnrm++ = default_normal;
|
|
}
|
|
}
|
|
|
|
// Append vertex normal.
|
|
if (geo_a->vtx_normal || geo_b->vtx_normal)
|
|
if (geo_o->vtx_normal.Allocate(geo_o->binding.GetCount()))
|
|
{
|
|
Vector4 *pvnrm = &geo_o->vtx_normal[0];
|
|
for (uint n = 0; n < geo_a->binding.GetCount(); ++n)
|
|
{
|
|
if (geo_a->vtx_normal)
|
|
{
|
|
mtx_a->ApplyRotation(pvnrm, &geo_a->vtx_normal[n]);
|
|
*pvnrm++ = pvnrm->Normalized();
|
|
}
|
|
else
|
|
*pvnrm++ = Vector4(0, 0, 1);
|
|
}
|
|
for (uint n = 0; n < geo_b->binding.GetCount(); ++n)
|
|
{
|
|
if (geo_b->vtx_normal)
|
|
{
|
|
mtx_b->ApplyRotation(pvnrm, &geo_b->vtx_normal[n]);
|
|
*pvnrm++ = pvnrm->Normalized();
|
|
}
|
|
else
|
|
*pvnrm++ = Vector4(0, 0, 1);
|
|
}
|
|
}
|
|
|
|
// Append RGB.
|
|
if (geo_a->rgb || geo_b->rgb)
|
|
if (geo_o->rgb.Allocate(geo_o->binding.GetCount()))
|
|
{
|
|
Color *prgb = &geo_o->rgb[0];
|
|
for (uint n = 0; n < geo_a->binding.GetCount(); ++n)
|
|
*prgb++ = geo_a->rgb ? geo_a->rgb[n] : Color::White;
|
|
for (uint n = 0; n < geo_b->binding.GetCount(); ++n)
|
|
*prgb++ = geo_b->rgb ? geo_b->rgb[n] : Color::White;
|
|
}
|
|
|
|
// Append all UV channels.
|
|
static Vector2 default_uv(0.5, 0.5);
|
|
|
|
for (uint n = 0; n < __UV_PER_GEOMETRY__; ++n)
|
|
if (geo_a->uv[n] || geo_b->uv[n])
|
|
if (geo_o->uv[n].Allocate(geo_o->binding.GetCount()))
|
|
{
|
|
Vector2 *puv = &geo_o->uv[n][0];
|
|
|
|
if (geo_a->uv[n])
|
|
for (uint v = 0; v < geo_a->binding.GetCount(); ++v)
|
|
*puv++ = geo_a->uv[n][v];
|
|
else
|
|
for (uint v = 0; v < geo_a->binding.GetCount(); ++v)
|
|
*puv++ = default_uv;
|
|
|
|
if (geo_b->uv[n])
|
|
for (uint v = 0; v < geo_b->binding.GetCount(); ++v)
|
|
*puv++ = geo_b->uv[n][v];
|
|
else
|
|
for (uint v = 0; v < geo_b->binding.GetCount(); ++v)
|
|
*puv++ = default_uv;
|
|
}
|
|
|
|
// Append all materials.
|
|
geo_o->material_table.Allocate(geo_a->material_table.GetCount() + geo_b->material_table.GetCount());
|
|
Geometry::MaterialSlot *pslot = geo_o->material_table.c_ptr();
|
|
|
|
for (uint n = 0; n < geo_a->material_table.GetCount(); ++n)
|
|
{
|
|
pslot->name = geo_a->material_table[n].name;
|
|
pslot->use_cache = geo_a->material_table[n].use_cache;
|
|
++pslot;
|
|
}
|
|
for (uint n = 0; n < geo_b->material_table.GetCount(); ++n)
|
|
{
|
|
pslot->name = geo_b->material_table[n].name;
|
|
pslot->use_cache = geo_b->material_table[n].use_cache;
|
|
++pslot;
|
|
}
|
|
|
|
// Merge materials.
|
|
geo_o->MergeDuplicateMaterials();
|
|
|
|
return geo_o;
|
|
}
|
|
//------------------------------------------------------------------------------
|