681 lines
20 KiB
C++
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;
|
|
}
|
|
//------------------------------------------------------------------------------
|