diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp index 5e3bc681f1..fd3c8c0fbc 100644 --- a/source/graphics/MapReader.cpp +++ b/source/graphics/MapReader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -859,15 +859,16 @@ void CXMLReader::ReadPaths(XMBElement parent) CCinemaData pathData; XMBAttributeList attrs = element.GetAttributes(); CStrW pathName(attrs.GetNamedItem(at_name).FromUTF8()); - pathData.m_Timescale = fixed::FromString(attrs.GetNamedItem(at_timescale)); - TNSpline pathSpline, targetSpline; - fixed lastTargetTime = fixed::Zero(); - pathData.m_Name = pathName; + pathData.m_Timescale = fixed::FromString(attrs.GetNamedItem(at_timescale)); pathData.m_Orientation = attrs.GetNamedItem(at_orientation).FromUTF8(); pathData.m_Mode = attrs.GetNamedItem(at_mode).FromUTF8(); pathData.m_Style = attrs.GetNamedItem(at_style).FromUTF8(); + TNSpline positionSpline, targetSpline; + fixed lastPositionTime = fixed::Zero(); + fixed lastTargetTime = fixed::Zero(); + XERO_ITER_EL(element, pathChild) { elementName = pathChild.GetNodeName(); @@ -876,9 +877,7 @@ void CXMLReader::ReadPaths(XMBElement parent) // Load node data used for spline if (elementName == el_node) { - bool positionDeclared = false; - SplineData data; - data.Distance = fixed::FromString(attrs.GetNamedItem(at_deltatime)); + lastPositionTime += fixed::FromString(attrs.GetNamedItem(at_deltatime)); lastTargetTime += fixed::FromString(attrs.GetNamedItem(at_deltatime)); XERO_ITER_EL(pathChild, nodeChild) { @@ -887,16 +886,17 @@ void CXMLReader::ReadPaths(XMBElement parent) if (elementName == el_position) { - data.Position.X = fixed::FromString(attrs.GetNamedItem(at_x)); - data.Position.Y = fixed::FromString(attrs.GetNamedItem(at_y)); - data.Position.Z = fixed::FromString(attrs.GetNamedItem(at_z)); - positionDeclared = true; + CFixedVector3D position; + position.X = fixed::FromString(attrs.GetNamedItem(at_x)); + position.Y = fixed::FromString(attrs.GetNamedItem(at_y)); + position.Z = fixed::FromString(attrs.GetNamedItem(at_z)); + + positionSpline.AddNode(position, CFixedVector3D(), lastPositionTime); + lastPositionTime = fixed::Zero(); } else if (elementName == el_rotation) { - data.Rotation.X = fixed::FromString(attrs.GetNamedItem(at_x)); - data.Rotation.Y = fixed::FromString(attrs.GetNamedItem(at_y)); - data.Rotation.Z = fixed::FromString(attrs.GetNamedItem(at_z)); + // TODO: Implement rotation slerp/spline as another object } else if (elementName == el_target) { @@ -911,17 +911,13 @@ void CXMLReader::ReadPaths(XMBElement parent) else LOGWARNING("Invalid cinematic element for node child"); } - - // Skip the node if no position - if (positionDeclared) - pathSpline.AddNode(data.Position, data.Rotation, data.Distance); } else LOGWARNING("Invalid cinematic element for path child"); } // Construct cinema path with data gathered - CCinemaPath path(pathData, pathSpline, targetSpline); + CCinemaPath path(pathData, positionSpline, targetSpline); if (path.Empty()) { LOGWARNING("Path with name '%s' is empty", pathName.ToUTF8()); diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp index 1a58a00a38..5bce47a4b0 100644 --- a/source/graphics/MapWriter.cpp +++ b/source/graphics/MapWriter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -409,7 +409,7 @@ void CMapWriter::WriteXML(const VfsPath& filename, for ( ; it != paths.end(); ++it ) { fixed timescale = it->second.GetTimescale(); - const std::vector& nodes = it->second.GetAllNodes(); + const std::vector& position_nodes = it->second.GetAllNodes(); const std::vector& target_nodes = it->second.GetTargetSpline().GetAllNodes(); const CCinemaData* data = it->second.GetData(); @@ -420,46 +420,55 @@ void CMapWriter::WriteXML(const VfsPath& filename, XML_Attribute("mode", data->m_Mode); XML_Attribute("style", data->m_Style); + struct SEvent + { + fixed time; + const char* type; + CFixedVector3D value; + SEvent(fixed time, const char* type, CFixedVector3D value) + : time(time), type(type), value(value) + {} + bool operator<(const SEvent& another) + { + return time < another.time; + } + }; + + // All events of a manipulating of camera (position/rotation/target) + std::vector events; + + fixed last_position = fixed::Zero(); + for (size_t i = 0; i < position_nodes.size(); ++i) + { + fixed distance = i > 0 ? position_nodes[i - 1].Distance : fixed::Zero(); + last_position += distance; + events.emplace_back(last_position, "Position", position_nodes[i].Position); + } + fixed last_target = fixed::Zero(); - for (size_t i = 0, j = 0; i < nodes.size(); ++i) + for (size_t i = 0; i < target_nodes.size(); ++i) + { + fixed distance = i > 0 ? target_nodes[i - 1].Distance : fixed::Zero(); + last_target += distance; + events.emplace_back(last_target, "Target", target_nodes[i].Position); + } + + std::sort(events.begin(), events.end()); + for (size_t i = 0; i < events.size();) { XML_Element("Node"); - fixed distance = i > 0 ? nodes[i - 1].Distance : fixed::Zero(); - last_target += distance; - - XML_Attribute("deltatime", distance); - + fixed deltatime = i > 0 ? (events[i].time - events[i - 1].time) : fixed::Zero(); + XML_Attribute("deltatime", deltatime); + size_t j = i; + for (; j < events.size() && events[j].time == events[i].time; ++j) { - XML_Element("Position"); - XML_Attribute("x", nodes[i].Position.X); - XML_Attribute("y", nodes[i].Position.Y); - XML_Attribute("z", nodes[i].Position.Z); + // Types: Position/Rotation/Target + XML_Element(events[j].type); + XML_Attribute("x", events[j].value.X); + XML_Attribute("y", events[j].value.Y); + XML_Attribute("z", events[j].value.Z); } - - { - XML_Element("Rotation"); - XML_Attribute("x", nodes[i].Rotation.X); - XML_Attribute("y", nodes[i].Rotation.Y); - XML_Attribute("z", nodes[i].Rotation.Z); - } - - if (j >= target_nodes.size()) - continue; - - fixed target_distance = j > 0 ? target_nodes[j - 1].Distance : fixed::Zero(); - - if (target_distance > last_target) - continue; - - { - XML_Element("Target"); - XML_Attribute("x", target_nodes[j].Position.X); - XML_Attribute("y", target_nodes[j].Position.Y); - XML_Attribute("z", target_nodes[j].Position.Z); - } - - last_target = fixed::Zero(); - ++j; + i = j; } } }