/* ----------------------------------------------------------------------------- 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 &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 ::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 ::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); } //------------------------------------------------------------------------------