Files
Webcam/include/engine/core/object.cpp

214 lines
5.9 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "core/object.h"
#include "core/camera.h"
#include "core/geometry.h"
#include "core/resource_factories.h"
#include "core/render_resource_factory.h"
#include "timing/benchmark.h"
#include "log/log.h"
using namespace GS;
using namespace GS::Core;
float Object::lod_bias = 0.f;
//------------------------------------------------------------------------------
void Object::RenderSetup(ResourceFactories *f)
{
render_data = new RenderData;
if (f && f->render)
{
render_data->geometry = f->render->LoadGeometry(geometry, !cache_geometry);
if (render_data->geometry.IsValid())
{
// Assert skin correctness.
uint bone_count = render_data->geometry->bone_bind_matrix.GetCount();
if (bone_count > 0)
{
if (skin.IsNull() || (skin->bones_mtx.GetCount() != bone_count))
{
AllocateSkin(render_data->geometry->bone_bind_matrix.GetCount());
// Initialize skin to the binding position.
for (uint n = 0; n < render_data->geometry->bone_bind_matrix.GetCount(); ++n)
skin->previous_bones_mtx[n] = skin->bones_mtx[n] = render_data->geometry->bone_bind_matrix[n];
}
}
else
FreeSkin();
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static float GetGeometrySortValue(const Matrix4 &vm, Render::Geometry *g, const Matrix4 &gm)
{ return vm.GetRow(2).Dot((g->hotspot * gm) - vm.GetRow(3)); }
void Object::ComputeRenderableMinMax(MinMax &mm)
{
ComputeLocalMinMax(mm);
OBB obb = OBB::FromMinMax(mm);
obb.Transform(GetMatrix());
obb.ComputeMinMax(mm);
}
uint Object::GetRenderablePrimitiveList(const Camera &view, const Camera &default_view, Stack <Render::Primitive *> &list, Renderable::Context context, bool cull)
{
Render::Geometry *g = render_data.IsValid() ? render_data->geometry.c_ptr() : NULL;
if (!g)
return 1;
// Recursive LOD selection.
{
float d2 = Vector4::Dist2(default_view.GetMatrix().GetRow(3), GetMatrix().GetRow(3)) + lod_bias * lod_bias;
d2 /= GetScale().Len2(); // [EJ] scale affects lod selection
for ( ; g; g = g->lod_proxy)
{
// If closer than lod, stop there.
if (d2 < (g->lod_distance * g->lod_distance))
break;
// Null lod.
if (g->flag.IsSet(Geometry::FlagNullLodProxy))
return 1;
// No lod to follow, stop there.
if (g->lod_proxy.IsNull())
break;
}
}
// Check context proxy on the selected lod.
if (context == Renderable::Context_Shadow)
{
// Null proxy.
if (g->flag.IsSet(Geometry::FlagNullShadowProxy))
return 1;
if (g->shadow_proxy.IsValid())
g = g->shadow_proxy;
}
// Test geometry hidden flag.
if (g->flag.IsSet(Geometry::FlagHidden))
return 1;
// Culling.
if (cull)
{
MinMax minmax;
ComputeLocalMinMax(minmax);
if (view.frustum.ClassifyMinMax(minmax, &GetMatrix()) == Frustum::Outside)
return 1;
}
list.Push(new Render::Primitive(g, this, GetGeometrySortValue(view.GetMatrix(), g, GetMatrix())));
return 1;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Object::GetBindMatrix(uint n, Matrix4 &m) const
{
if (render_data.IsNull() || render_data->geometry.IsNull())
return false;
if (n >= render_data->geometry->bone_bind_matrix.GetCount())
return false;
m = render_data->geometry->bone_bind_matrix[n];
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Object::ComputeLocalMinMax(MinMax &minmax) const
{
if (render_data.IsNull() || render_data->geometry.IsNull())
Item::ComputeLocalMinMax(minmax);
else
{
if (HasSkin())
{
// Compute skin minmax.
OBB obb;
for (uint n = 0; n < GetBoneCount(); ++n)
if (skin->ComputeBoneBoundingVolume(n, obb))
{
MinMax bmm;
obb.ComputeMinMax(bmm);
if (n)
minmax.Grow(bmm);
else minmax = bmm;
}
}
else
minmax = render_data->geometry->minmax;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Object::UpdateSkin()
{
if (render_data.IsValid() && render_data->geometry.IsValid())
for (uint n = 0; n < GetBoneCount(); ++n)
if (Item *bone = GetBone(n))
{
skin->previous_bones_mtx[n] = GetInverseMatrix() * (bone->GetPreviousMatrix() * render_data->geometry->bone_bind_matrix[n]);
skin->bones_mtx[n] = GetInverseMatrix() * (bone->GetMatrix() * render_data->geometry->bone_bind_matrix[n]);
}
else
{
skin->previous_bones_mtx[n] = Matrix4::IdentityMatrix();
skin->bones_mtx[n] = Matrix4::IdentityMatrix();
}
}
bool Object::BindBone(uint n, Item *bone)
{
if (skin.IsNull() || (n >= skin->bones.GetCount()))
return false;
skin->bones[n] = bone;
if (bone)
bone->item_flags.Set(ItemFlagBoneHint);
return true;
}
bool Object::AllocateSkin(uint bone_count)
{
skin = new Skin;
if (!skin->bones.Allocate(bone_count) || !skin->bones_mtx.Allocate(bone_count) || !skin->previous_bones_mtx.Allocate(bone_count) || !skin->bones_minmax.Allocate(bone_count))
{
FreeSkin();
__ERR__(__LOG_E__ << "Failed to allocate skinning structure.\n", false);
}
for (uint n = 0; n < bone_count; ++n)
{
skin->bones[n] = NULL;
skin->bones_mtx[n] = Matrix4::IdentityMatrix();
skin->previous_bones_mtx[n] = Matrix4::IdentityMatrix();
}
return true;
}
void Object::FreeSkin()
{
skin = NULL;
}
//------------------------------------------------------------------------------
Object::Object() : cache_geometry(true) {}