Parse(bool isAnime) // = true) { if (_text == null) { return(false); } XmlDocument doc = new XmlDocument(); // doc is the new xml document. doc.LoadXml(_text); // load the file. string rootTagStr, rootNSStr; if (isAnime) { // this is .ssax rootTagStr = "SpriteStudioMotion"; rootNSStr = "http://www.webtech.co.jp/SpriteStudio/XML/Motion"; } else { // this is .sssx rootTagStr = "SpriteStudioScene"; rootNSStr = "http://www.webtech.co.jp/SpriteStudio/XML/Scene"; } // check the root tag name validity // root is ?xml, so skip to the next XmlNode rootNode = doc.FirstChild; rootNode = rootNode.NextSibling; if (rootNode.Name != rootTagStr) { Debug.LogError("Invalid root tag name: " + rootNode.Name); return(false); } // check the root tag namespace validity XmlAttributeCollection rootNodeAttrs = rootNode.Attributes; XmlNode nodeXMLNS = rootNodeAttrs["xmlns"]; if (nodeXMLNS.Value != rootNSStr) { Debug.LogError("\"xmlns\" doesn't match: " + rootNode.Name); return(false); } // check file format version validity XmlNode versionNode = rootNodeAttrs["version"]; int readVersion = SsVersion.ToInt(versionNode.Value); if (readVersion < RequiredVersion) { Debug.LogError("Version under " + SsVersion.ToString(RequiredVersion) + " is not supported -> " + SsVersion.ToString(readVersion)); return(false); } if (readVersion > CurrentVersion) { Debug.LogError("This version " + SsVersion.ToString(readVersion) + " is not supported yet. supports up to " + SsVersion.ToString(CurrentVersion)); return(false); } #if false // made sure the rootNode has Header, ImageList, Parts XmlNodeList children = rootNode.ChildNodes; foreach (XmlNode n in children) { Debug.Log(n.Name); } #endif // Create an XmlNamespaceManager to resolve namespaces. NameTable nt = new NameTable(); _nsMgr = new XmlNamespaceManager(nt); _nsMgr.AddNamespace("cur", nodeXMLNS.Value); // read header XmlNode headerNode = _SelectSingleNode(rootNode, "cur:Header"); if (headerNode == null) { Debug.LogError("Header node is not found"); return(false); } XmlNode endFrameNode = _SelectSingleNode(headerNode, "cur:EndFrame"); if (endFrameNode == null) { Debug.LogError("EndFrame node is not found"); return(false); } _anmRes.EndFrame = _ToInt(endFrameNode.InnerText); #if NEED_EDIT_MODE _editMode = _ToInt(_SelectSingleNode(headerNode, "cur:EditMode").InnerText); #endif _anmRes.FPS = _ToInt(_SelectSingleNode(headerNode, "cur:BaseTickTime").InnerText); // read option settings XmlNode optionNode = _SelectSingleNode(headerNode, "cur:OptionState"); if (optionNode != null) { XmlNode n = _SelectSingleNode(optionNode, "cur:hvFlipForImageOnly"); if (n == null) { _anmRes.hvFlipForImageOnly = true; } else { _anmRes.hvFlipForImageOnly = _ToBool(n.InnerText); } } // create image manager singleton //var imgMgr = SsImageManager.Singleton; // enumerate image paths // it is possible to be nothing in .ssax XmlNodeList imageNodeList = _SelectNodes(rootNode, "./cur:ImageList/cur:Image"); if (imageNodeList == null) { Debug.LogError("ImageList node is not found"); return(false); } if (imageNodeList.Count <= 0) { Debug.LogError("ImageList has no contents"); return(false); } _anmRes.ImageList = new SsImageFile[imageNodeList.Count]; //Debug.Log("imageNodeList.Count: " + imageNodeList.Count); foreach (XmlNode e in imageNodeList) { string idStr = e.Attributes["Id"].Value; int index = _ToInt(idStr) - 1; // because it starts from 1. string path = e.Attributes["Path"].Value; // remove the useless string "./cur:" on head //Debug.Log("Id=" + idStr + " Path=" + path); if (path.StartsWith(@".\")) { path = path.Remove(0, 2); } path = path.Replace(@"\", "/"); // for Mac //path = _relPath + "/" + path; // doesn't care about ../ string baseFullPath = Path.GetFullPath("./"); path = Path.GetFullPath(Path.Combine(_relPath, path)); // combine path considering ../ path = path.Substring(baseFullPath.Length); path = path.Replace(@"\", "/"); // just in case //Debug.Log("Id=" + index + " Path=" + path); // get image file info which contains a Texture Asset. SsImageFile imgFile = GetImage(path); if (imgFile == null) { return(false); } XmlNode widthNode = e.Attributes["Width"]; if (widthNode != null) { imgFile.width = _ToInt(widthNode.Value); if (!_IsPowerOfTwo(imgFile.width)) { Debug.LogWarning("Image width is not power of 2, it will be scaled."); } } else { imgFile.width = imgFile.texture.width; } XmlNode heightNode = e.Attributes["Height"]; if (heightNode != null) { imgFile.height = _ToInt(heightNode.Value); if (!_IsPowerOfTwo(imgFile.height)) { Debug.LogWarning("Image height is not power of 2, it will be scaled."); } } else { imgFile.height = imgFile.texture.height; } // For now, bpp is not used anywhere. XmlNode bppNode = e.Attributes["Bpp"]; if (bppNode != null) { imgFile.bpp = _ToInt(bppNode.Value); if (imgFile.bpp <= 8) { Debug.LogWarning(path + " seems index color image, so it has to be converted to direct color or compressed type"); } } else { switch (imgFile.texture.format) { default: imgFile.bpp = 0; // Zero means something compressed type break; case TextureFormat.ARGB4444: case TextureFormat.RGB565: imgFile.bpp = 16; break; case TextureFormat.RGB24: imgFile.bpp = 24; break; case TextureFormat.ARGB32: case TextureFormat.RGBA32: imgFile.bpp = 32; break; } } // register image info into the list _anmRes.ImageList[index] = imgFile; } // enumerate parts XmlNodeList partList = _SelectNodes(rootNode, "./cur:Parts/cur:Part"); if (partList == null) { Debug.LogError("Parts node is not found"); return(false); } //Debug.Log("Parts Num: " + partList.Count); if (partList.Count <= 0) { Debug.LogError("No existence of Parts"); return(false); } _anmRes.PartList = new SsPartRes[partList.Count]; foreach (XmlNode part in partList) { // create a part var partBase = new SsPartRes(); partBase.AnimeRes = _anmRes; XmlAttribute rootAttr = part.Attributes["Root"]; partBase.InheritState.Initialize(4, _anmRes.hvFlipForImageOnly); string partName = _GetNodeValue(part, "./cur:Name"); partBase.Name = System.String.Copy(partName); if (rootAttr != null) { // this is root parts partBase.Type = SsPartType.Root; partBase.MyId = 0; partBase.ParentId = -1; } else { // general parts partBase.Type = (SsPartType)_ToInt(_GetNodeValue(part, "./cur:Type")); partBase.PicArea.Top = _ToInt(_GetNodeValue(part, "./cur:PictArea/cur:Top")); partBase.PicArea.Left = _ToInt(_GetNodeValue(part, "./cur:PictArea/cur:Left")); partBase.PicArea.Bottom = _ToInt(_GetNodeValue(part, "./cur:PictArea/cur:Bottom")); partBase.PicArea.Right = _ToInt(_GetNodeValue(part, "./cur:PictArea/cur:Right")); partBase.OriginX = _ToInt(_GetNodeValue(part, "./cur:OriginX")); partBase.OriginY = _ToInt(_GetNodeValue(part, "./cur:OriginY")); partBase.MyId = 1 + _ToInt(_GetNodeValue(part, "./cur:ID")); partBase.ParentId = 1 + _ToInt(_GetNodeValue(part, "./cur:ParentID")); partBase.SrcObjId = _ToInt(_GetNodeValue(part, "./cur:PicID")); partBase.AlphaBlendType = (SsAlphaBlendOperation)(1 + _ToInt(_GetNodeValue(part, "./cur:TransBlendType"))); partBase.InheritState.Type = (SsInheritanceType)_ToInt(_GetNodeValue(part, "./cur:InheritType")); if (partBase.SrcObjId >= _anmRes.ImageList.Length) { /* * // supply lack of image * int count = 1 + partBase.SrcObjId - _anmRes.ImageList.Length; * _anmRes.ImageList. * for (int i = 0; i < count; ++i) * { * _anmRes.ImageList[partBase.SrcObjId + i] = SsImageFile.invalidInstance; * } */ // clamp id Debug.LogWarning("Picture ID is out of image list. Part: " + partName + " PicId: " + partBase.SrcObjId); partBase.SrcObjId = 0; } partBase.imageFile = _anmRes.ImageList[partBase.SrcObjId]; if (partBase.imageFile != SsImageFile.invalidInstance) { // precalc UV coordinates partBase.CalcUVs(0, 0, 0, 0); // add basic material with basic shader AddMaterials(partBase, SsColorBlendOperation.Non); } if (partBase.InheritState.Type == SsInheritanceType.Parent) { // copy parent's value and rate statically. dynamic reference is certain implement but it costs much more. for (int i = 0; i < (int)SsKeyAttr.Num; ++i) { SsKeyAttr attr = (SsKeyAttr)i; var param = _anmRes.PartList[partBase.ParentId].InheritParam(attr); partBase.InheritState.Values[i] = param; //Debug.Log(partBase.Name +" inherits parent's attr: " + attr + " use: " + param.Use + " rate:" + param.Rate); } } } // make original 4 vertices will be not modified. it consists of OriginX/Y and PicArea.WH. partBase.OrgVertices = partBase.GetVertices(partBase.PicArea.WH()); #if false // parent part SsPartRes parentPart = null; if (partBase.ParentId >= 0) { parentPart = _anmRes.PartList[partBase.ParentId]; } #endif if (!isAnime) { // scene only has this element partBase.SrcObjType = (SsSourceObjectType)_ToInt(_GetNodeValue(part, "./cur:ObjectType")); } // parse attributes XmlNodeList attrList = _SelectNodes(part, "./cur:Attributes/cur:Attribute"); string attrName; foreach (XmlNode attrNode in attrList) { // recognize the tag attrName = attrNode.Attributes["Tag"].Value; if (attrName.Length != 4) { Debug.LogWarning("invalid attribute tag!!: " + attrName); continue; } SsKeyAttrDesc attrDesc = SsKeyAttrDescManager.Get(attrName); if (attrDesc == null) { Debug.LogWarning("Unknown or Unsupported attribute: " + attrName); continue; } switch (attrDesc.Attr) { case SsKeyAttr.PartsPal: if (attrNode.HasChildNodes) { Debug.LogWarning("Unsupported attribute: " + attrName); } continue; } // set inheritance parameter to part instance. if (partBase.Type != SsPartType.Root) { if (partBase.InheritState.Type == SsInheritanceType.Self) { // has its own value. var InheritParam = new SsInheritanceParam(); XmlNode InheritNode = attrNode.Attributes.GetNamedItem("Inherit"); if (InheritNode != null) { // mix my value and parent's value, but actually user 100% parent's... InheritParam.Use = true; InheritParam.Rate = (100 * _ToInt(InheritNode.Value)) / SSIO_SUCCEED_DENOMINATOR; } else { // absolutely not refer the parent's value. InheritParam.Use = false; InheritParam.Rate = 0; } // apply to part partBase.InheritState.Values[(int)attrDesc.Attr] = InheritParam; //Debug.LogError(partBase.Name +" has own value! attr:" + attrDesc.Attr + " use:" + InheritParam.Use); } } // enumerate keys XmlNodeList keyList = _SelectNodes(attrNode, "./cur:Key"); if (keyList == null || keyList.Count < 1) { //Debug.Log(attrName + " has no keys"); } else { foreach (XmlNode key in keyList) { //dynamic keyBase; cannot use dynamic at this time SsKeyFrameInterface keyBase; bool bNeedCurve = true; switch (attrDesc.ValueType) { case SsKeyValueType.Data: { // if value type is Data, string format of node "Value" depends on attribute type. string strValue = _GetNodeValue(key, "./cur:Value"); switch (attrDesc.CastType) { default: case SsKeyCastType.Bool: // not supported currently case SsKeyCastType.Other: // not supported currently case SsKeyCastType.Int: case SsKeyCastType.Hex: // these types are used as integer. var intKey = new SsIntKeyFrame(); // to make intellisence working, really?? if (attrDesc.CastType == SsKeyCastType.Hex) { intKey.Value = _HexToInt(strValue); } else { intKey.Value = _ToInt(strValue); } switch (attrDesc.Attr) { case SsKeyAttr.PosX: case SsKeyAttr.PosY: // apply scale factor intKey.Value = (int)((float)intKey.Value * _anmRes.ScaleFactor); break; #if _FORCE_BOUND_PART_TO_MOST_TOP // force bound part to most top to draw surely if wanted case SsKeyAttr.Prio: if (partBase.Type == SsPartType.Bound) { intKey.Value = short.MaxValue; // int.MaxValue is failed to unbox } break; #endif } #if _DEBUG Debug.LogWarning("Is it OK? -> " + strValue + " = " + intKey.Value); #endif keyBase = intKey; break; case SsKeyCastType.Float: case SsKeyCastType.Degree: var floatKey = new SsFloatKeyFrame(); // to make intellisence working, really?? #if _FORCE_BOUND_PART_TO_BE_TRANSPARENT // force bound part to transparent to draw if wanted if (attrDesc.Attr == SsKeyAttr.Trans && partBase.Type == SsPartType.Bound) { floatKey.Value = 0.5f; } else #endif floatKey.Value = (float)_ToDouble(strValue); // unnecessary to convert to radian. because Unity requires degree unit. //if (attrDesc.CastType == SsKeyCastType.Degree) //floatKey.Value = (float)_DegToRad( _ToDouble(strValue) ); keyBase = floatKey; break; } } break; case SsKeyValueType.Param: { var boolKey = new SsBoolKeyFrame(); keyBase = boolKey; boolKey.Value = _ToUInt(_GetNodeValue(key, "./cur:Value")) != 0 ? true : false; bNeedCurve = false; } break; case SsKeyValueType.Palette: { var paletteKey = new SsPaletteKeyFrame(); keyBase = paletteKey; var v = new SsPaletteKeyValue(); v.Use = _ToUInt(_GetNodeValue(key, "./cur:Use")) != 0 ? true : false; v.Page = _ToInt(_GetNodeValue(key, "./cur:Page")); v.Block = (byte)_ToInt(_GetNodeValue(key, "./cur:Block")); paletteKey.Value = v; } break; case SsKeyValueType.Color: { var colorBlendKey = new SsColorBlendKeyFrame(); keyBase = colorBlendKey; var v = new SsColorBlendKeyValue(4); v.Target = (SsColorBlendTarget)_ToUInt(_GetNodeValue(key, "./cur:Type")); v.Operation = (SsColorBlendOperation)(1 + _ToUInt(_GetNodeValue(key, "./cur:Blend"))); AddMaterials(partBase, v.Operation); switch (v.Target) { case SsColorBlendTarget.None: // no color, but do care about interpolation to/from 4 vertex colors for (int i = 0; i < 4; ++i) { v.Colors[i].R = v.Colors[i].G = v.Colors[i].B = 255; // 0 alpha value means no effect. v.Colors[i].A = 0; } break; case SsColorBlendTarget.Overall: // one color, but do care about interpolation to/from 4 vertex colors _GetColorRef(v.Colors[0], key, "./cur:Value"); for (int i = 1; i < 4; ++i) { v.Colors[i] = v.Colors[0]; } break; case SsColorBlendTarget.Vertex: // 4 vertex colors. the order is clockwise. _GetColorRef(v.Colors[0], key, "./cur:TopLeft"); _GetColorRef(v.Colors[1], key, "./cur:TopRight"); _GetColorRef(v.Colors[2], key, "./cur:BottomRight"); _GetColorRef(v.Colors[3], key, "./cur:BottomLeft"); break; } colorBlendKey.Value = v; } break; case SsKeyValueType.Vertex: { var vertexKey = new SsVertexKeyFrame(); keyBase = vertexKey; var v = new SsVertexKeyValue(4); _GetPoint(v.Vertices[0], key, "./cur:TopLeft"); _GetPoint(v.Vertices[1], key, "./cur:TopRight"); if (readVersion <= (uint)SsAnimeFormatVersion.V320) { // for obsolete version _GetPoint(v.Vertices[2], key, "./cur:BottomLeft"); _GetPoint(v.Vertices[3], key, "./cur:BottomRight"); } else { _GetPoint(v.Vertices[3], key, "./cur:BottomLeft"); _GetPoint(v.Vertices[2], key, "./cur:BottomRight"); } // apply scale factor for (int i = 0; i < v.Vertices.Length; ++i) { v.Vertices[i].Scale(_anmRes.ScaleFactor); } vertexKey.Value = v; } break; case SsKeyValueType.User: { var userKey = new SsUserDataKeyFrame(); keyBase = userKey; var v = new SsUserDataKeyValue(); XmlNode numberNode = _SelectSingleNode(key, "./cur:Number"); if (numberNode != null) { v.IsNum = true; v.Num = _ToInt(numberNode.InnerText); } XmlNode rectNode = _SelectSingleNode(key, "./cur:Rect"); if (rectNode != null) { v.IsRect = true; v.Rect = new SsRect(); _GetRect(v.Rect, rectNode); } XmlNode pointNode = _SelectSingleNode(key, "./cur:Point"); if (pointNode != null) { v.IsPoint = true; v.Point = new SsPoint(); _GetPoint(v.Point, pointNode); } XmlNode stringNode = _SelectSingleNode(key, "./cur:String"); if (stringNode != null) { v.IsString = true; v.String = System.String.Copy(stringNode.InnerText); } // writeback userKey.Value = v; bNeedCurve = false; } // case KEYTYPE_USERDATA break; case SsKeyValueType.Sound: { var soundKey = new SsSoundKeyFrame(); keyBase = soundKey; var v = new SsSoundKeyValue(); v.Flags = (SsSoundKeyFlags)_ToUInt(_SelectSingleNode(key, "./cur:Use").InnerText); v.NoteOn = _ToByte(_SelectSingleNode(key, "./cur:Note").InnerText); v.SoundId = _ToByte(_SelectSingleNode(key, "./cur:ID").InnerText); v.LoopNum = _ToByte(_SelectSingleNode(key, "./cur:Loop").InnerText); v.Volume = _ToByte(_SelectSingleNode(key, "./cur:Volume").InnerText); v.UserData = _ToUInt(_SelectSingleNode(key, "./cur:Data").InnerText); // writeback soundKey.Value = v; bNeedCurve = false; } break; default: Debug.LogError("Fatal error!! not implemented cast type: " + _ToInt(attrNode.Value)); continue; } // switch //keyBase = InitKeyFrameData(); keyBase.ValueType = attrDesc.ValueType; keyBase.Time = _ToInt(key.Attributes["Time"].Value); if (bNeedCurve) { // make values to interpolate var v = new SsCurveParams(); XmlNode curveTypeNode = key.Attributes["CurveType"]; if (curveTypeNode == null) { v.Type = SsInterpolationType.None; } else { v.Type = (SsInterpolationType)_ToUInt(curveTypeNode.Value); if (v.Type == SsInterpolationType.Hermite || v.Type == SsInterpolationType.Bezier) { // must exist if (key.Attributes["CurveStartT"] == null) { Debug.LogError("CurveStartT param not found!!"); return(false); } v.StartT = _ToFloat(key.Attributes["CurveStartT"].Value); v.StartV = _ToFloat(key.Attributes["CurveStartV"].Value); v.EndT = _ToFloat(key.Attributes["CurveEndT"].Value); v.EndV = _ToFloat(key.Attributes["CurveEndV"].Value); switch (attrDesc.Attr) { case SsKeyAttr.PosX: case SsKeyAttr.PosY: case SsKeyAttr.Vertex: // apply scale factor v.StartV *= _anmRes.ScaleFactor; v.EndV *= _anmRes.ScaleFactor; break; case SsKeyAttr.Angle: if (_database.AngleCurveParamAsRadian) { // degree to radian v.StartV = (float)(v.StartV * 180 / System.Math.PI); v.EndV = (float)(v.EndV * 180 / System.Math.PI); } break; } } } keyBase.Curve = v; } #if false//_DEBUG // dump debug info SsDebugLog.Print("Attr: " + attrDesc.Attr + " " + keyBase.ToString()); #endif // add keyFrame info to part instance. partBase.AddKeyFrame(attrDesc.Attr, keyBase); } } } #if _DEBUG // dump debug info SsDebugLog.Print(partBase.ToString()); #endif if (_precalcAttrValues) { // precalculate attribute values each frame partBase.CreateAttrValues(_anmRes.EndFrame + 1); } // add to list // if the container is Dictionary, allow non-sequential ID order of the stored parts, but it occurs to search by ID. _anmRes.PartList[partBase.MyId] = partBase; //_anmRes.PartList.Add(partBase); } // Debug.Log("_anmRes.PartList.Count: " + _anmRes.PartList.Count); #if false // precalculate values to inherit parent's one. if (PrecalcAttrValues) { //foreach (var e in _anmRes.PartList.Values) // for Dictionary version foreach (var e in _anmRes.PartList) { if (!e.IsRoot && e.HasParent) { e.CalcInheritedValues(_anmRes.PartList[e.ParentId]); } } } #endif return(true); }
CreateAttrValues(int frameNum) { if (frameNum <= 0) { Debug.LogWarning("No keys to precalculate."); return; } FrameNum = frameNum; // if (keyFrameLists == null) // { // Debug.LogError("Key frame list must be prepared."); // return; // } #if _DEBUG SsDebugLog.PrintLn("CreateAttrValues()"); SsDebugLog.PrintLn("Name: " + Name); #endif // create temporary key frame list // keyFrameLists = new List<SsKeyFrameInterface>[(int)SsKeyAttr.Num]; // keyFrameLists[(int)SsKeyAttr.PosX] = PosXKeys; // create attribute value lists for (int attrIdx = 0; attrIdx < (int)SsKeyAttr.Num; ++attrIdx) { SsKeyAttr attr = (SsKeyAttr)attrIdx; int keyNum = GetKeyNumOf(attr); // skip non-key attribute if (keyNum <= 0) { continue; } int curKeyIndex = 0; SsKeyFrameInterface curKey = GetKey(attr, 0); int nextKeyIndex = 0; SsKeyFrameInterface nextKey = null; int valuesNum = 1; if (keyNum > 1) { nextKey = GetKey(attr, 1); nextKeyIndex = 1; // consolidate identical values if possible for (int i = 1; i < keyNum; ++i) { SsKeyFrameInterface key = GetKey(attr, i); if (!key.EqualsValue(curKey)) { // give up consolidating valuesNum = frameNum; break; } } } else if (keyNum == 1) { if (attr == SsKeyAttr.Hide) { SsBoolKeyFrame hideKey = (SsBoolKeyFrame)curKey; if (hideKey.Value == false) { valuesNum = frameNum; } } } SsKeyAttrDesc attrDesc = SsKeyAttrDescManager.GetById(attr); switch (attr) { case SsKeyAttr.PosX: PosXValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.PosY: PosYValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.Angle: AngleValues = new SsFloatAttrValue[valuesNum]; break; case SsKeyAttr.ScaleX: ScaleXValues = new SsFloatAttrValue[valuesNum]; break; case SsKeyAttr.ScaleY: ScaleYValues = new SsFloatAttrValue[valuesNum]; break; case SsKeyAttr.Trans: TransValues = new SsFloatAttrValue[valuesNum]; break; case SsKeyAttr.Prio: PrioValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.FlipH: FlipHValues = new SsBoolAttrValue[valuesNum]; break; case SsKeyAttr.FlipV: FlipVValues = new SsBoolAttrValue[valuesNum]; break; case SsKeyAttr.Hide: HideValues = new SsBoolAttrValue[valuesNum]; break; case SsKeyAttr.PartsCol: PartsColValues = new SsColorBlendAttrValue[valuesNum]; break; case SsKeyAttr.PartsPal: PartsPalValues = new SsPaletteAttrValue[valuesNum]; break; case SsKeyAttr.Vertex: VertexValues = new SsVertexAttrValue[valuesNum]; break; case SsKeyAttr.User: UserValues = new SsUserDataAttrValue[valuesNum]; break; case SsKeyAttr.Sound: SoundValues = new SsSoundAttrValue[valuesNum]; break; case SsKeyAttr.ImageOffsetX: ImageOffsetXValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.ImageOffsetY: ImageOffsetYValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.ImageOffsetW: ImageOffsetWValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.ImageOffsetH: ImageOffsetHValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.OriginOffsetX: OriginOffsetXValues = new SsIntAttrValue[valuesNum]; break; case SsKeyAttr.OriginOffsetY: OriginOffsetYValues = new SsIntAttrValue[valuesNum]; break; } // mark that this attribute is used. _hasAttrFlags |= (SsKeyAttrFlags)(1 << attrIdx); #if _DEBUG SsDebugLog.Print(string.Format("\tAttr[{0}]: {1}\n", attrIdx, attrDesc.Attr)); #endif for (int frame = 0; frame < valuesNum; ++frame) { if (nextKey != null && frame >= nextKey.Time) { // advance to next keyed frame curKeyIndex = nextKeyIndex; curKey = nextKey; ++nextKeyIndex; nextKey = nextKeyIndex < keyNum?GetKey(attr, nextKeyIndex) : null; } // base typed value SsAttrValue v = null; // create new value to add SsBoolAttrValue boolValue = null; SsIntAttrValue intValue = null; SsFloatAttrValue floatValue = null; // SsPointAttrValue pointValue = null; SsPaletteAttrValue paletteValue = null; SsColorBlendAttrValue colorBlendValue = null; SsVertexAttrValue vertexValue = null; SsUserDataAttrValue userValue = null; SsSoundAttrValue soundValue = null; switch (attrDesc.ValueType) { case SsKeyValueType.Data: ///< actually decimal or integer switch (attrDesc.CastType) { default: v = intValue = new SsIntAttrValue(); break; case SsKeyCastType.Float: case SsKeyCastType.Degree: v = floatValue = new SsFloatAttrValue(); break; } break; case SsKeyValueType.Param: ///< actually boolean v = boolValue = new SsBoolAttrValue(); break; // case SsKeyValueType.Point: ///< x,y // v = pointValue = new SsPointAttrValue(); // break; case SsKeyValueType.Palette: ///< left,top,right,bottom v = paletteValue = new SsPaletteAttrValue(); break; case SsKeyValueType.Color: ///< single or vertex colors v = colorBlendValue = new SsColorBlendAttrValue(); break; case SsKeyValueType.Vertex: ///< vertex positions relative to origin v = vertexValue = new SsVertexAttrValue(); break; case SsKeyValueType.User: ///< user defined data(numeric|point|rect|string...) v = userValue = new SsUserDataAttrValue(); break; case SsKeyValueType.Sound: ///< sound id, volume, note on... v = soundValue = new SsSoundAttrValue(); break; } #if false // move this care to runtime if (attrDesc.Attr == SsKeyAttr.Hide && frame < curKey.Time) { // "hide" needs special care, it will be true before first key. boolValue.Value = true; } else #endif if (attrDesc.NeedsInterpolatable && nextKey != null && frame >= curKey.Time) { bool doInterpolate = true; if (attrDesc.Attr == SsKeyAttr.PartsCol) { var curCbk = (SsColorBlendKeyValue)curKey.ObjectValue; var nextCbk = (SsColorBlendKeyValue)nextKey.ObjectValue; // if current and next key has no target, new value simply refers current key. if (curCbk.Target == SsColorBlendTarget.None && nextCbk.Target == SsColorBlendTarget.None) { v.RefKeyIndex = curKeyIndex; doInterpolate = false; } } if (doInterpolate) { // needs interpolation object res; if (frame == curKey.Time) { // use start key value as is. res = curKey.ObjectValue; } else { // interpolate curKey~nextKey res = SsInterpolation.InterpolateKeyValue(curKey, nextKey, frame); } try{ // can't restore primitive type from the boxed through casting. if (boolValue) { boolValue.Value = System.Convert.ToBoolean(res); } else if (intValue) { intValue.Value = System.Convert.ToInt32(res); } else if (floatValue) { floatValue.Value = System.Convert.ToSingle(res); } else { v.SetValue(res); } }catch { Debug.LogError("[INTERNAL] failed to unbox: " + res); } if (attrDesc.Attr == SsKeyAttr.PartsCol) { var curCbk = (SsColorBlendKeyValue)curKey.ObjectValue; var nextCbk = (SsColorBlendKeyValue)nextKey.ObjectValue; // if current or next key has vertex colors, key between them should have vertex colors. if (curCbk.Target == SsColorBlendTarget.Vertex || nextCbk.Target == SsColorBlendTarget.Vertex) { var newCbk = colorBlendValue.Value; newCbk.Target = SsColorBlendTarget.Vertex; // use next key operation. newCbk.Operation = nextCbk.Operation; } } } } else { // just use the value at last referred key frame. v.RefKeyIndex = curKeyIndex; } #if _DEBUG if (v.Value != null) { SsDebugLog.Print(string.Format("\t\tframe[{0}]: {1}\n", frame, v.Value)); } #endif // add value to the relative array switch (attr) { case SsKeyAttr.PosX: PosXValues[frame] = intValue; break; case SsKeyAttr.PosY: PosYValues[frame] = intValue; break; case SsKeyAttr.Angle: AngleValues[frame] = floatValue; break; case SsKeyAttr.ScaleX: ScaleXValues[frame] = floatValue; break; case SsKeyAttr.ScaleY: ScaleYValues[frame] = floatValue; break; case SsKeyAttr.Trans: TransValues[frame] = floatValue; break; case SsKeyAttr.Prio: PrioValues[frame] = intValue; break; case SsKeyAttr.FlipH: FlipHValues[frame] = boolValue; break; case SsKeyAttr.FlipV: FlipVValues[frame] = boolValue; break; case SsKeyAttr.Hide: HideValues[frame] = boolValue; break; case SsKeyAttr.PartsCol: PartsColValues[frame] = colorBlendValue; break; case SsKeyAttr.PartsPal: PartsPalValues[frame] = paletteValue; break; case SsKeyAttr.Vertex: VertexValues[frame] = vertexValue; break; case SsKeyAttr.User: UserValues[frame] = userValue; break; case SsKeyAttr.Sound: SoundValues[frame] = soundValue; break; case SsKeyAttr.ImageOffsetX: ImageOffsetXValues[frame] = intValue; break; case SsKeyAttr.ImageOffsetY: ImageOffsetYValues[frame] = intValue; break; case SsKeyAttr.ImageOffsetW: ImageOffsetWValues[frame] = intValue; break; case SsKeyAttr.ImageOffsetH: ImageOffsetHValues[frame] = intValue; break; case SsKeyAttr.OriginOffsetX: OriginOffsetXValues[frame] = intValue; break; case SsKeyAttr.OriginOffsetY: OriginOffsetYValues[frame] = intValue; break; } } } // set having transparency flag HasTrancparency = false; if (HasAttrFlags(SsKeyAttrFlags.Trans)) { // if opacity value under 1 exists in some keys, we recognize this will be transparent at some frames foreach (SsFloatKeyFrame e in TransKeys) { if (e.Value < 1f) { HasTrancparency = true; break; } } } }