Files
Webcam/include/engine/scene3d/scene.cpp

495 lines
13 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "scene3d/scene.h"
#include "scene3d/mlight.h"
#include "scene3d/mobject.h"
#include "scene3d/mcamera.h"
#include "scene3d/mtrigger.h"
#include "scene3d/memitter.h"
#include "scene3d/mterrain.h"
#include "scene3d/instance.h"
#include "scene3d/mconstraint.h"
#include "scene3d/mitem_scripted_object.h"
#include "scene3d/scene_event_script_interface.h"
#include "scene3d/scene_renderer_environment_interface.h"
#include "scene3d/scene_physic_world_interface.h"
#include "scene3d/scene_scripted_object.h"
#include "scene3d/scene_script_unit.h"
#include "scene3d/mitem_event_script_interface.h"
#include "physic/physic_constraint.h"
#include "physic/physic_world.h"
#include "ui/ui.h"
using namespace GS;
using namespace S3D;
//------------------------------------------------------------------------------
void Scene::SetClock(Core::Clock *c, bool set_ui)
{
clock = c ? c : new Core::Clock;
if (set_ui)
ui->SetClock(c);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::GetMinMax(MinMax &minmax) const
{
bool initial = true;
ArrayListForeachPtr(MItem *, i, active_list)
{
if (i->GetItemType() != Type_Object)
continue;
MObject *object = (MObject *)i;
if (object->render_data.IsNull() || object->render_data->geometry.IsNull())
continue;
MinMax local_minmax = object->render_data->geometry->minmax;
if (initial)
minmax = local_minmax;
else minmax.Grow(local_minmax);
initial = false;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Group *Scene::AddGroup(Group *g)
{
group_list.Add(g);
return g;
}
bool Scene::RemoveGroup(Group *g)
{
return group_list.Remove(g);
}
Group *Scene::FindGroup(const char *name) const
{
ListForeachPtr(Group *, g, group_list)
if (g->name == name)
return g;
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint Scene::GetItemGroupList(const MItem *item, SharedList <Group *> &list) const
{
uint count = 0;
ListForeachPtr(Group *, g, group_list)
if (g->IsMember(item))
{
count++;
list.Add(g);
}
return count;
}
void Scene::UnregisterItemFromGroups(MItem *item) const
{
ListForeachPtr(Group *, g, group_list)
g->Remove(item);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Scene::ActivateItem(MItem *i, bool v)
{
if (v)
{
if (active_list.IndexOf(i) == -1)
active_list.Add(i);
}
else
active_list.Remove(i);
if (i->physic_item)
i->physic_item->SetActive(v);
i->mitem_flags.Raise(MItem::Flag_IsActive, v);
return true;
}
void Scene::ProcessItemActivationQueue()
{
ListForeachPtr(MItem *, i, activation_queue)
ActivateItem(i, true);
ListForeachPtr(MItem *, i, deactivation_queue)
ActivateItem(i, false);
activation_queue.Clear();
deactivation_queue.Clear();
}
void Scene::QueueItemActivation(MItem *item, bool activate, bool propagate)
{
if (item->mitem_flags.IsSet(MItem::Flag_IsActive) != activate)
{
// Queue item.
if (activate)
{
if (!activation_queue.Find(item))
activation_queue.Add(item);
deactivation_queue.Remove(item);
}
else
{
if (!deactivation_queue.Find(item))
deactivation_queue.Add(item);
activation_queue.Remove(item);
}
// Script callback.
item->item_event->OnActivate(item, activate);
item->mitem_flags.Raise(MItem::Flag_IsActive, activate);
}
if (propagate)
ListForeachPtr(Core::Item *, child, item->GetBaseItem()->GetChildren())
QueueItemActivation(LocateManagedItem(child), activate, true);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Scene::Create(PhysicWorld *w)
{
Clear();
if ((physic_world = w) != NULL)
{
if (!physic_world->Create())
return false;
// bullet_world->CreateDebugger(GetEngine().GetRenderer());
physic_world->SetWorldInterface(iphysic_world);
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
MTrigger *Scene::RaytraceTriggerList(Vector4 &s, Vector4 &d, float l, Vector4 *i)
{
ListForeachPtr(MItem *, item, item_list)
if (item->GetItemType() == Type_Trigger)
{
MTrigger *t = (MTrigger *)item;
// Move ray to trigger space.
Vector4 local_s, local_d;
t->GetInverseMatrix().Apply(&local_s, &s);
t->GetInverseMatrix().ApplyRotation(&local_d, &d);
// Test ray against bbox normalized space.
MinMax mm;
mm.SetFromPositionSize(Vector4(0, 0, 0), Vector4(1, 1, 1));
// Raytrace against minmax.
Vector4 local_i;
if (l == -1 ? mm.ClassifyLine(local_s, local_d, local_i) : mm.ClassifySegment(local_s, local_s + local_d * l, local_i))
{
if (i)
*i = local_i * t->GetMatrix();
return t;
}
}
return NULL;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::RecordAllItemLocation()
{
ListForeachPtr(MItem *, i, item_list)
i->SetInitialTransformation();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
MItem *Scene::ItemFromUid(uint uid) const
{
ListForeachPtr(MItem *, i, item_list)
if (i->GetUid() == uid)
return i;
return NULL;
}
MItemType Scene::LocateItem(const Core::Item *item, MItem **entity) const
{
ListForeachPtr(MItem *, i, item_list)
if (i->GetBaseItem() == item)
{
if (entity)
*entity = i;
return i->GetItemType();
}
return Type_None;
}
MItem *Scene::LocateManagedItem(Core::Item *i)
{
return i ? (MItem *)i->mitem : NULL;
}
//------------------------------------------------------------------------------
static bool FindItemByName(const MItem *i, const char *name) { return i->name == name; }
//------------------------------------------------------------------------------
MItem *Scene::Item(const char *item_name, MItem *parent) const
{
StringList node;
String(item_name).Split("/", node);
MItem *item = NULL;
if (parent)
ListForeachPtr(Core::Item *, child, parent->GetBaseItem()->GetChildren())
{
MItem *child_item = LocateManagedItem(child);
if (child_item && (child_item->name == node[0]))
{
item = child_item;
break;
}
}
else
item = ListFindEx(item_list, FindItemByName, node[0]);
if (!item)
__ERR__(__LOG_W__ << "No item named '" << item_name << "' in scene '" << name << "'.\n", NULL)
// Solve additional path.
if (node.GetCount() > 1)
for (uint n = 1; n < node.GetCount(); ++n)
{
if (item->GetItemType() != Type_Instance)
__ERR__(__LOG_W__ << "Cannot solve sub-path '" << node[n] << "' on item '" << item->name << "'.\n", NULL)
Instance *instance = (Instance *)item;
if (!instance->instance_group)
return NULL;
item = instance->instance_group->Item(node[n]);
}
return item;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::SetItemStatic(MItem *item, bool v)
{
item->mitem_flags.Raise(MItem::Flag_IsStatic, v);
if (Core::Renderable *r = item->GetRenderable())
{
RemoveRenderable(r);
AddRenderable(r, v);
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::AddRenderable(Core::Renderable *r, bool is_static)
{
if (is_static)
octree_culling_system.AddRenderable(r);
else simple_culling_system.AddRenderable(r);
}
void Scene::RemoveRenderable(Core::Renderable *r)
{
simple_culling_system.DeleteRenderable(r);
octree_culling_system.DeleteRenderable(r);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::SetupItemComponents(MItem *i)
{
// Create scripted object and event handler.
i->scripted_object = new MItemScriptedObject(i, vm);
if (vm)
i->item_event = new MItemScriptEvent;
// Create physic item.
if (physic_world && i->GetBaseItem())
{
i->physic_item = physic_world->NewItem();
i->physic_item->SetUserPointer((void *)i);
}
}
void Scene::AddItem(MItem *i, bool setup_components)
{
i->uid = current_item_uid++;
if (setup_components)
SetupItemComponents(i);
g_scene_messenger.BroadcastMessage(SceneMsg_AddingItem, this, i);
// Add to all lists.
item_list.Add(i);
active_list.Add(i);
switch (i->GetItemType())
{
case Type_Light: light_list.Add((MLight *)i); break;
case Type_Trigger: trigger_list.Add((MTrigger *)i); break;
}
// Add to culling systems.
if (Core::Renderable *r = i->GetRenderable())
AddRenderable(r, i->mitem_flags.IsSet(MItem::Flag_IsStatic));
g_scene_messenger.BroadcastMessage(SceneMsg_ItemAdded, this, i);
}
bool Scene::RemoveItem(MItem *i)
{
g_scene_messenger.BroadcastMessage(SceneMsg_DeletingItem, this, (void *)i);
i->item_event->OnDelete(i);
if (vm.IsValid())
vm->InvalidateNativeReference(i);
// Remove from groups.
UnregisterItemFromGroups(i);
if (Core::Renderable *r = i->GetRenderable())
{
// Remove from culling systems.
simple_culling_system.DeleteRenderable(r);
octree_culling_system.DeleteRenderable(r);
}
if (Core::Item *b = i->GetBaseItem())
{
// Unset if current camera.
if (current_camera == b)
current_camera = NULL;
// Remove from triggers & skins.
ListForeachPtr(MItem *, item, item_list)
switch (item->GetItemType())
{
case Type_Trigger:
((MTrigger *)item)->DropItem(b);
break;
case Type_Object:
{
MObject *o = (MObject *)item;
for (uint n = 0; n < o->GetBoneCount(); ++n)
if (o->GetBone(n) == b)
o->BindBone(n, NULL);
}
break;
}
}
// Remove from physic world.
i->physic_item = NULL;
switch (i->GetItemType())
{
case Type_Light: light_list.Remove((MLight *)i); break;
case Type_Trigger: trigger_list.Remove((MTrigger *)i); break;
}
active_list.Remove(i);
removal_queue.Remove(i);
activation_queue.Remove(i);
deactivation_queue.Remove(i);
item_list.Remove(i); // keep last
g_scene_messenger.BroadcastMessage(SceneMsg_ItemDeleted, this, i);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::QueueItemRemoval(MItem *i)
{ removal_queue.Add(i); }
void Scene::ProcessItemRemovalQueue()
{
while (List <MItem *> ::Item *r = removal_queue.GetRoot())
RemoveItem(r->Object());
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Scene::Clear(bool keep_script)
{
g_scene_messenger.BroadcastMessage(SceneMsg_Clearing, this, 0);
scene_event->OnDelete(this);
// Remove all items (immediate/non-queued).
while (List <MItem *> ::Item *i = item_list.GetRoot())
RemoveItem(i->Object());
// Drop UI.
ui->Clear();
// Close scripts.
if (!keep_script)
scripted_object->RemoveAllUnit();
fog_color.Set();
fog_near = 0;
fog_far = 0;
current_item_uid = 0;
g_scene_messenger.BroadcastMessage(SceneMsg_Cleared, this, 0);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Scene::Scene(Script::IVM *script_vm) : profiler(*this)
{
vm = script_vm;
current_camera = NULL;
current_item_uid = 0;
ambient_intensity = 1;
target_exposure = 0.25;
time_of_day = 0.5;
fog_near = 0;
fog_far = 0;
fog_color.Set(0, 0, 0);
background_color.Set(0, 0, 0);
ambient_color.Set(0, 0, 0);
clock = new Core::Clock;
scene_event = vm ? new SceneScriptEvent : new ISceneEvent;
scripted_object = new SceneScriptedObject(vm, this);
irenderer_environment = new IEnvironment(this);
iphysic_world = new IScenePhysicWorld(this);
ui = new S2D::Scene(vm);
}
Scene::~Scene()
{
SetAsScriptGlobalScene();
Clear();
if (vm)
vm->InvalidateNativeReference((void *)this);
}
//------------------------------------------------------------------------------