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

681 lines
20 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "scene3d/scene.h"
#include "scene3d/mobject.h"
#include "scene3d/mlight.h"
#include "scene3d/mcamera.h"
#include "scene3d/mtrigger.h"
#include "scene3d/instance.h"
#include "scene3d/memitter.h"
#include "scene3d/mterrain.h"
#include "scene3d/mconstraint.h"
#include "scene3d/group.h"
#include "physic/physic_constraint.h"
#include "physic/physic_world.h"
#include "ui/ui.h"
#include "script/scripted_object.h"
#include "script/script_unit.h"
#include "container/nmap.h"
using namespace GS;
using namespace S3D;
using NML::Tag;
//------------------------------------------------------------------------------
static MItem *GetMappedItemFromTag(Scene &scene, Tag *pt, const char *tag, Map <uint, uint> &uid_map, MItemType type = Type_None)
{
Tag *muid = pt->GetTypedTag(tag, Variant::VariantInteger);
if (!muid)
__ERR__(__LOG_W__ << "Invalid UID tag.\n", NULL)
uint uid = muid->GetUnsigned();
if (!uid_map.HasKey(uid))
__ERR__(__LOG_W__ << "Invalid item UID.\n", NULL)
MItem *mitem = scene.ItemFromUid(uid_map[uid]);
if (mitem && (type != Type_None) && (mitem->GetItemType() != type))
__ERR__(__LOG_V__ << "Item type filtered out.\n", NULL)
return mitem;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static bool ShouldLoadItem(ToolMode mode, Tag *pt, uint flag, int load_level)
{
if (pt->GetTag("MItem:ToolSpecific;") || pt->GetTag("MItem:Helper;"))
{
if (!(flag & SceneIOHelper))
return false;
// Do not load tool specific items in no tool or project preview modes.
if ((mode == NoTool) || (mode == ToolProjectPreview))
return false;
// Do not load tool specific items in no tool mode above the first load level.
if (load_level > 0)
return false;
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
template <class T> static T *LoadItemDerived(Scene *scene, T *i, Map <uint, uint> &uid_map, Tag *t, uint type_flag, const uint load_flag, int load_level, ToolMode tool_mode)
{
if (!(load_flag & type_flag) || !ShouldLoadItem(tool_mode, t, load_flag, load_level))
{
delete i;
return NULL;
}
scene->SetupItemComponents(i);
if (i->FromMetaTag(*t))
{
uint olduid = i->GetUid(); // uid from source scene
scene->AddItem(i, false); // add to live scene
uid_map.Add(olduid, i->GetUid()); // store map from source to live scene
}
return i;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Scene::FromMetaTagStoreGroup(const Tag &tag, Group **group, uint load_flag, ToolMode tool_mode, int load_level)
{
if (tag.name != "Scene")
__ERR__(__LOG_E__ << "Could not parse scene, incorrect root tag (" << tag.name << ").\n", false);
Benchmark bench(true);
g_scene_messenger.BroadcastMessage(SceneMsg_Loading, this, 0);
ui->ResetCommandList();
// Create scene group.
if (group && !group[0])
{
group[0] = new Group;
group[0]->name = "SceneGroup";
group_list.Add(group[0]);
}
// Read items and setup uid remap array.
Map <uint, uint> uid_map;
if (Tag *itag = tag.GetTag("Items"))
{
// Item count in scene.
uint item_to_load = 0;
NMLTagForeach(pt, *itag)
if (Tag *item_tag = pt->GetTag("MItem;"))
item_to_load++;
NMLTagForeach(pt, *itag)
{
MItem *citem = NULL;
if (pt->name == "MCamera")
citem = LoadItemDerived(this, new MCamera, uid_map, pt, SceneIOCamera, load_flag, load_level, tool_mode);
else if (pt->name == "MObject")
citem = LoadItemDerived(this, new MObject, uid_map, pt, SceneIOObject, load_flag, load_level, tool_mode);
else if (pt->name == "MLight")
citem = LoadItemDerived(this, new MLight, uid_map, pt, SceneIOLight, load_flag, load_level, tool_mode);
else if ((pt->name == "MTrigger") || (pt->name == "Trigger")) // Legacy
citem = LoadItemDerived(this, new MTrigger, uid_map, pt, SceneIOTrigger, load_flag, load_level, tool_mode);
else if (pt->name == "Instance")
citem = LoadItemDerived(this, new Instance, uid_map, pt, SceneIOInstance, load_flag, load_level, tool_mode);
else if (pt->name == "MEmitter")
citem = LoadItemDerived(this, new MEmitter, uid_map, pt, SceneIOEmitter, load_flag, load_level, tool_mode);
else if (pt->name == "MTerrain")
citem = LoadItemDerived(this, new MTerrain, uid_map, pt, SceneIOTerrain, load_flag, load_level, tool_mode);
else if (pt->name == "MConstraint")
citem = LoadItemDerived(this, new MConstraint(physic_world ? physic_world->NewConstraint() : NULL), uid_map, pt, SceneIOConstraint, load_flag, load_level, tool_mode);
else
__LOG_W__ << "Unexpected <" << pt->name << "> sub-tag in <Items>.\n";
if (citem)
{
// Add item to the scene group.
if (group && group[0])
group[0]->Add(citem);
// Remove from active list if inactive.
if (!citem->isActive())
active_list.Remove(citem);
}
}
}
// Solve links.
if (Tag *ltag = tag.GetTag("Links"))
{
NMLTagForeach(pt, *ltag)
{
if (pt->name == "Link")
{
int item = -1, link = -1;
NMLTagForeach(lt, *pt)
{
if (lt->name == "Item") item = lt->GetInteger();
else if (lt->name == "Link") link = lt->GetInteger();
}
MItem *sitem = NULL, *litem = NULL;
if ((item == -1) || (link == -1))
__LOG_W__ << "Incomplete link tag.\n";
else
{
// Some items might have been masked out from import.
if (uid_map.HasKey(item) && uid_map.HasKey(link))
{
sitem = ItemFromUid(uid_map[item]);
litem = ItemFromUid(uid_map[link]);
if (sitem && litem)
sitem->GetBaseItem()->SetParent(litem->GetBaseItem());
// __LOG__ << "Solving link: " << item << "(" << (sitem ? "OK" : "Failed") << ")->" << link << "(" << (litem ? "OK" : "Failed") << ").\n";
}
// else __LOG_W__ << "Link item masked out during import.\n";
}
}
else
__LOG_W__ << "Unexpected <" << pt->name << "> sub-tag in <Links>.\n";
}
}
// Solve constraints.
if (Tag *ctag = tag.GetTag("Constraints"))
{
NMLTagForeach(pt, *ctag)
if (pt->name == "Constraint")
{
MItem *mitem = GetMappedItemFromTag(*this, pt, "Uid;", uid_map, Type_Constraint);
if (!mitem)
continue;
// Get constraint.
if (MConstraint *constraint = (MConstraint *)mitem)
{
MItem *mitem_a = GetMappedItemFromTag(*this, pt, "UidA;", uid_map),
*mitem_b = GetMappedItemFromTag(*this, pt, "UidB;", uid_map);
constraint->desc.item_a = mitem_a;
constraint->desc.item_b = mitem_b;
}
}
}
// Solve skins.
if (Tag *btag = tag.GetTag("Skins"))
{
NMLTagForeach(pt, *btag)
if (pt->name == "Skin")
if (MItem *mitem = GetMappedItemFromTag(*this, pt, "UId;", uid_map, Type_Object))
{
// We can now safely cast to the managed and core objects.
MObject *mobj = (MObject *)mitem;
Core::Object *obj = (Core::Object *)mobj;
uint bone_count = 0;
NMLTagForeach(st, *pt)
if (st->name == "Bone")
bone_count++;
if (!obj->AllocateSkin(bone_count))
continue;
// Process skin binding.
NMLTagForeach(st, *pt)
if (st->name == "Bone")
{
// Grab mandatory bone tags.
Tag *itag = st->GetTypedTag("Index", Variant::VariantInteger),
*utag = st->GetTypedTag("UId", Variant::VariantInteger);
if (!itag || !utag)
{ __LOG_E__ << "Invalid bone information, incomplete bone tag.\n"; continue; }
int index = itag->GetInteger();
if ((index < 0) || (index >= (int)obj->GetBoneCount()))
{ __LOG_E__ << "Invalid bone information, bone index out of bound.\n"; continue; }
// Locate bone item.
uint uid = utag->GetUnsigned();
if (!uid_map.HasKey(uid))
{ __LOG_E__ << "Invalid bone information, item uid out of bound.\n"; continue; }
MItem *bone = ItemFromUid(uid_map[uid]);
if (!bone)
{ __LOG_E__ << "Invalid bone information, item not found.\n"; continue; }
obj->BindBone(index, bone->GetBaseItem());
}
}
}
// Read groups.
if (load_flag & SceneIOGroup)
if (Tag *gstag = tag.GetTag("Groups"))
{
String _item("Item");
NMLTagForeach(gtag, *gstag)
{
if (gtag->name == "Group")
{
if (Tag *tid = gtag->GetTag("Id"))
{
if (Group *new_group = new Group)
{
new_group->name = tid->GetString();
group_list.Add(new_group);
NMLTagForeach(mtag, *gtag)
{
if (mtag->name == _item)
{
int uid = mtag->GetInteger();
if (uid_map.HasKey(uid))
new_group->Add(ItemFromUid(uid_map[uid]));
// else
// __LOG_W__ << "Group member masked out during import.\n";
}
}
// Add as sub-group.
if (group)
group[0]->Add(new_group);
}
else
__LOG_E__ << "Failed to allocate group '" << tid->GetString() << "'.\n";
}
else
__LOG_W__ << "Could not read group, no identifier found.\n";
}
}
}
// Script unit.
if (load_flag & SceneIOScript)
{
if (Tag *stag = tag.GetTag("ScriptedObject"))
scripted_object->FromMetaTag(*stag);
#if 1 // Compatibility
else
if (Tag *stag = tag.GetTag("ScriptUnit"))
if (Script::Unit *unit = scripted_object->AddUnit(scripted_object->NewUnit()))
unit->FromMetaTag(*stag);
#endif
}
// Motion sets.
if (load_flag & SceneIOMotion)
if (Tag *ctag = tag.GetTag("SceneMotionContainer"))
{
if (group)
{
if (*group)
(*group)->motion.FromMetaTag(*ctag, &uid_map);
}
else
motion.FromMetaTag(*ctag, &uid_map);
}
// Scene properties.
static String _bgc("BackgroundColor"), _abc("AmbientColor"), _abi("AmbientIntensity"), _tge("TargetExposure"),
_feb("FogEnable"), _fgn("FogNear"), _fgf("FogFar"), _fgc("FogColor"), _rad("Radiance"), _ird("Irradiance");
if (!group || (load_flag & SceneIOGlobals))
if (Tag *gtag = tag.GetTag("Globals"))
NMLTagForeach(t, *gtag)
{
if (t->name == _bgc)
background_color.FromMetaTag(*t);
else if (t->name == _abc)
ambient_color.FromMetaTag(*t);
else if (t->name == _abi)
ambient_intensity = t->GetReal();
else if (t->name == _rad)
radiance_probe = t->GetString();
else if (t->name == _ird)
irradiance_probe = t->GetString();
else if (t->name == _tge)
target_exposure = t->GetReal();
else if (t->name == _fgn)
fog_near = t->GetReal();
else if (t->name == _fgf)
fog_far = t->GetReal();
else if (t->name == _fgc)
fog_color.FromMetaTag(*t);
else if (t->name == "SkyLayer0")
skybox_layer[0] = t->GetString();
else if (t->name == "SkyLayer1")
skybox_layer[1] = t->GetString();
else if (t->name == "SkyShader")
skybox_shader = t->GetString();
else if (t->name == "TimeOfDay")
time_of_day = t->GetReal();
}
// Physic system.
if ((load_flag & SceneIOPhysic) && physic_world)
{
Tag *ptag = tag.GetTag("Physics;");
if (!ptag)
ptag = tag.GetTag("Tau;"); // Look for a legacy tag.
if (ptag)
{
NMLTagForeach(t, *ptag)
if (t->name == "Frequency")
physic_world->SetTimestep(1.f / t->GetReal());
}
}
// Group stats.
if (group && group[0])
__LOG__ << "Group '" << group[0]->name << "': " << group[0]->GetItemList().GetCount() << " item(s).\n";
// Load current camera.
if ((load_flag & SceneIOSettings) && (load_flag & SceneIOCamera))
if (Tag *cctag = tag.GetTag("CurrentCamera"))
{
MItem *i = Item(cctag->GetString());
if (i && (i->GetItemType() == Type_Camera))
current_camera = (Camera *)i->GetBaseItem();
}
// Query the editor tag if no camera found.
if (!current_camera && (tool_mode != ToolEdit))
if (MCamera *camera = new MCamera)
{
camera->name = "Default";
AddItem(camera, true);
current_camera = camera;
if (Tag *pt = tag.GetTag("ViewMatrix;"))
{
Matrix4 m;
if (m.FromMetaTag(*pt))
camera->SetMatrix(m);
}
}
bench.Stop();
__LOG__ << "Done loading scene in " << bench.GetMs() << "ms.\n";
g_scene_messenger.BroadcastMessage(SceneMsg_Loaded, this, 0);
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool Scene::FromMetaFileStoreGroup(const char *path, Group **group, uint flag, ToolMode tool_mode, int load_level)
{
NML::File file;
if (!NML::Parser::Load(path, file))
return false;
if (Tag *scene_tag = file.GetTag("Scene"))
{
if (FromMetaTagStoreGroup(*scene_tag, group, flag, tool_mode, load_level))
name = path;
}
else
__ERR__(__LOG_E__ << "No <Scene> tag in '" << path << "'.\n", false)
if (group && group[0])
group[0]->name = path;
return true;
}
bool Scene::IsItemToBeSaved(MItem *i, const Group *group, uint flag) const
{
if (!i)
return false;
// Filter out irrelevant items.
if (group && !group->IsMember(i))
return false;
switch (i->GetItemType())
{
case Type_Camera: if (!(flag & SceneIOCamera)) return false; break;
case Type_Object: if (!(flag & SceneIOObject)) return false; break;
case Type_Light: if (!(flag & SceneIOLight)) return false; break;
case Type_Trigger: if (!(flag & SceneIOTrigger)) return false; break;
case Type_Instance: if (!(flag & SceneIOInstance)) return false; break;
case Type_Emitter: if (!(flag & SceneIOEmitter)) return false; break;
case Type_Terrain: if (!(flag & SceneIOTerrain)) return false; break;
default: break;
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Scene::LinkInfoAsMetaTag(MItem *i, const Group *group, uint flag) const
{
if (!IsItemToBeSaved(i, group, flag))
return NULL;
// Grab link managed item.
Core::Item *link = i->GetBaseItem() ? i->GetBaseItem()->GetParent() : NULL;
MItem *mlink;
if (!link || ((mlink = LocateManagedItem(link)) == NULL))
return NULL;
if (!IsItemToBeSaved(mlink, group, flag))
return NULL;
// Save link information.
if (Tag *tag = new Tag("Link"))
{
tag->AddChild("Item", i->GetUid());
tag->AddChild("Link", mlink->GetUid());
return tag;
}
__ERR__(__LOG_E__ << "Failed to allocate link tag.\n", NULL)
}
Tag *Scene::SkinInfoAsMetaTag(MObject *mobj, const Group *group, uint flag) const
{
if (group && (!group->IsMember(mobj)))
return NULL;
// Go to the low-level core object.
Core::Object *obj = (Core::Object *)mobj;
if (!obj->HasSkin())
return NULL;
Tag *skin_tag = new Tag("Skin");
if (!skin_tag)
__ERR__(__LOG_E__ << "Failed to allocate skin tag.\n", NULL);
skin_tag->AddChild("UId", mobj->GetUid());
for (int n = 0; n < (int)obj->GetBoneCount(); ++n)
{
MItem *bone = Scene::LocateManagedItem(obj->GetBone(n));
if (!bone || (group && (!group->IsMember(bone))))
continue;
// Export bone informations.
if (Tag *bone_tag = skin_tag->AddChild("Bone"))
{
bone_tag->AddChild("Index", n);
bone_tag->AddChild("UId", bone->GetUid());
Matrix4 m;
if (obj->GetBindMatrix(n, m))
bone_tag->AddChild(m.AsMetaTag("BindMatrix"));
else
__LOG_E__ << "Failed to serialize bone " << n << " bind matrix for object '" << mobj->name << "'.\n";
}
else __LOG_E__ << "Failed to allocate bone tag.\n";
}
return skin_tag;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
Tag *Scene::AsMetaTag(const Group *group, uint save_flag, ToolMode tool_mode) const
{
Tag *root = new Tag("Scene");
if (!root)
__ERR__(__LOG_E__ << "Could not create scene root tag to serialize.\n", NULL);
// Write script object.
if (scripted_object.IsValid() && !group)
root->AddChild(scripted_object->AsMetaTag());
// Write motion sets.
if (save_flag & SceneIOMotion)
root->AddChild(motion.AsMetaTag());
// Write managed items.
if (Tag *itag = root->AddChild("Items"))
ListForeachPtr(MItem *, i, item_list)
{
if (group && !group->IsMember(i))
continue;
switch (i->GetItemType())
{
case Type_Camera: if (!(save_flag & SceneIOCamera)) continue; break;
case Type_Object: if (!(save_flag & SceneIOObject)) continue; break;
case Type_Light: if (!(save_flag & SceneIOLight)) continue; break;
case Type_Trigger: if (!(save_flag & SceneIOTrigger)) continue; break;
case Type_Instance: if (!(save_flag & SceneIOInstance)) continue; break;
case Type_Emitter: if (!(save_flag & SceneIOEmitter)) continue; break;
case Type_Terrain: if (!(save_flag & SceneIOTerrain)) continue; break;
case Type_Constraint: if (!(save_flag & SceneIOConstraint)) continue; break;
default: break;
}
itag->AddChild(i->AsMetaTag());
}
else
__ERR__(__LOG_E__ << "Failed to allocate <Items> root tag.\n", NULL);
// Write link informations.
if (Tag *ltag = root->AddChild("Links"))
ListForeachPtr(MItem *, i, item_list)
ltag->AddChild(LinkInfoAsMetaTag(i, group, save_flag));
else
__ERR__(__LOG_E__ << "Failed to allocate <Links> root tag.\n", NULL)
// Write skin informations.
if (Tag *stag = root->AddChild("Skins"))
{
ListForeachPtr(MItem *, i, item_list)
if (i->GetItemType() == Type_Object)
stag->AddChild(SkinInfoAsMetaTag((MObject *)i, group, save_flag));
if (stag->GetChildCount() == 0)
{
root->RemoveTag(stag);
_safe_delete(stag);
}
}
else
__ERR__(__LOG_E__ << "Failed to allocate <Skins> root tag.\n", NULL);
// Write constraints.
if (Tag *constraint_tag = root->AddChild("Constraints"))
ListForeachPtr(MItem *, i, item_list)
if (i->GetItemType() == Type_Constraint)
{
if (group && !group->IsMember(i))
continue;
MConstraint *c = (MConstraint *)i;
if (Tag *ctag = constraint_tag->AddChild("Constraint"))
{
ctag->AddChild("Uid", c->GetUid());
if (c->desc.item_a.IsValid())
ctag->AddChild("UidA", c->desc.item_a->GetUid());
if (c->desc.item_b.IsValid())
ctag->AddChild("UidB", c->desc.item_b->GetUid());
}
}
// Write scene groups.
if (!group)
{
if ((save_flag & SceneIOGroup) && group_list.GetCount())
{
if (Tag *gstag = root->AddChild("Groups"))
{
ListForeachPtr(Group *, group, group_list)
if (Tag *gtag = gstag->AddChild("Group"))
{
gtag->AddChild("Id", group->name.c_str());
ListForeachPtr(MItem *, item, group->GetItemList())
gtag->AddChild("Item", item->GetUid());
}
}
else
__ERR__(__LOG_E__ << "Failed to allocate <Groups> root tag.\n", NULL);
}
// Output scene properties.
if (save_flag & SceneIOGlobals)
{
if (Tag *gtag = root->AddChild("Globals"))
{
gtag->AddChild(background_color.AsMetaTag("BackgroundColor"));
gtag->AddChild(ambient_color.AsMetaTag("AmbientColor"));
if (!irradiance_probe.IsEmpty())
gtag->AddChild("Irradiance", irradiance_probe.c_str());
if (!radiance_probe.IsEmpty())
gtag->AddChild("Radiance", radiance_probe.c_str());
if (!skybox_layer[0].IsEmpty())
gtag->AddChild("SkyLayer0", skybox_layer[0].c_str());
if (!skybox_layer[1].IsEmpty())
gtag->AddChild("SkyLayer1", skybox_layer[1].c_str());
if (!skybox_shader.IsEmpty())
gtag->AddChild("SkyShader", skybox_shader.c_str());
gtag->AddChild("TimeOfDay", time_of_day);
gtag->AddChild("AmbientIntensity", ambient_intensity);
gtag->AddChild("TargetExposure", target_exposure);
gtag->AddChild("FogNear", fog_near);
gtag->AddChild("FogFar", fog_far);
gtag->AddChild(fog_color.AsMetaTag("FogColor"));
}
else
__ERR__(__LOG_E__ << "Failed to allocate <Globals> root tag.\n", NULL);
}
// Physics.
if ((save_flag & SceneIOPhysic) && physic_world.IsValid())
if (Tag *ptag = root->AddChild("Physics"))
ptag->AddChild("Frequency", 1.f / physic_world->GetTimestep());
// Current camera.
if (current_camera)
if (MItem *ci = LocateManagedItem(current_camera))
root->AddChild("CurrentCamera", ci->name);
}
return root;
}
//------------------------------------------------------------------------------