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); }
UpdateSub(SsPartRes res, int frame, bool initialize = false) { // priority if (res.HasAttrFlags(SsKeyAttrFlags.Prio)) { int nowPrio = (int)res.Prio(frame); if (_priority != nowPrio) { _priority = nowPrio; _mgr._prioChanged = true; } } // visibility if (res.HasAttrFlags(SsKeyAttrFlags.Hide)) { if (res.IsRoot) { _visible = !res.Hide(frame); } else if (res.Type == SsPartType.Normal) { bool nowVisible; if (res.IsBeforeFirstKey(frame)) { nowVisible = false; } else { if (_parent != null && !_parent._res.IsRoot && (res.InheritRate(SsKeyAttr.Hide) > 0.5f)) { nowVisible = _parent._visible; } else { nowVisible = !res.Hide(frame); } } #if _INHERITS_FORCE_VISIBLE if (_forceVisibleAvailable) { nowVisible = _forceVisible; } #endif if (nowVisible != _visible) { Show(nowVisible); } } } // vertex color if (res.HasAttrFlags(SsKeyAttrFlags.PartsCol)) { SsColorBlendKeyValue cbk = res.PartsCol(frame); SsColorBlendOperation cbkOp = ColorBlendType; if (cbk == null) { if (_colorBlendKeyValue != null) { // set back default color cbkOp = SsColorBlendOperation.Non; for (int i = 0; i < 4; ++i) { _mgr._colors[_vIndex + i] = _vertexColor; } _mgr._colorChanged = true; } } else { cbkOp = cbk.Operation; if (cbk.Target == SsColorBlendTarget.Vertex) { // vertex colors for (int i = 0; i < 4; ++i) { _mgr._colors[_vIndex + i] = GetBlendedColor(cbk.Colors[i], cbk.Operation); } } else { // affect a color to overall, so it doesn't inidicate that this is not vertex color. Color c = GetBlendedColor(cbk.Colors[0], cbk.Operation); for (int i = 0; i < 4; ++i) { _mgr._colors[_vIndex + i] = c; } } _mgr._colorChanged = true; } _colorBlendKeyValue = cbk; if (_mgr._colorChanged) { if (cbkOp != ColorBlendType) { // change other shader ColorBlendType = cbkOp; // place stored alpha is variable with color blend type. where is simply in color.a if blend is none. AlphaValue = AlphaValue; } } } // transparency if (_hasTransparency) { float nowAlpha = res.Trans(frame); if (_parent != null && res.Inherits(SsKeyAttr.Trans)) { float parentAlpha; // if parent is root, it doesn't have material. if (_parent._material == null) { parentAlpha = _parent._res.Trans(frame); } else { parentAlpha = _parent.AlphaValue; } // just multiply simply nowAlpha = parentAlpha * nowAlpha; } if (_forceAlphaAvailable) { nowAlpha = _forceAlpha; } if (nowAlpha != AlphaValue) { AlphaValue = nowAlpha; } } // scale if (res.HasAttrFlags(SsKeyAttrFlags.Scale)) { var scale = new Vector3(res.ScaleX(frame), res.ScaleY(frame), 1f); if (scale != _scale) { _scale = scale; _mgr._vertChanged = true; } } // rotation (now supports only Z axis) if (res.HasAttrFlags(SsKeyAttrFlags.Angle)) { var ang = res.Angle(frame); // SpriteStudio demands me to Z axis rotation consistently. if (_parent) { // reverse angle direction if parent part's scale is negative value. if (_parent._pivotMatrix.m00 * _parent._pivotMatrix.m11 < 0) { ang *= -1; } if (_mgr.hFlip ^ _mgr.vFlip) { ang *= -1; } } Quaternion rot = Quaternion.Euler(0, 0, ang); if (rot != _quaternion) { _quaternion = rot; _mgr._vertChanged = true; #if _MAKE_ROOT_TO_LOCAL_TRANSFORM _rotChanged = true; #endif } #if _MAKE_ROOT_TO_LOCAL_TRANSFORM else { _rotChanged = false; } #endif } // translate if (res.HasAttrFlags(SsKeyAttrFlags.Pos)) { var pos = new Vector3(res.PosX(frame), -res.PosY(frame)); #if false if (_parent != null) { if (_parent._flipH) { pos.x *= -1; } if (_parent._flipV) { pos.y *= -1; } } #endif #if _APPLY_ROOT_POS_AS_PIVOT // apply X,Y position as pivot if this is root. if (res.IsRoot) { pos += _rootPivot; } #endif #if false // update vertices when position is changed. if (_pos != pos) #endif { _pos = pos; _mgr._vertChanged = true; } } bool orgVertChanged = false; // UV animation if (res.HasAttrFlags(SsKeyAttrFlags.ImageOffset)) { int nowImgOfs = res.ImageOffsetX(frame); if (nowImgOfs != _imgOfsX) { _imgOfsX = nowImgOfs; _mgr._uvChanged = true; } nowImgOfs = res.ImageOffsetY(frame); if (nowImgOfs != _imgOfsY) { _imgOfsY = nowImgOfs; _mgr._uvChanged = true; } bool sizeChnaged = false; nowImgOfs = res.ImageOffsetW(frame); if (nowImgOfs != _imgOfsW) { _imgOfsW = nowImgOfs; _mgr._uvChanged = true; sizeChnaged = true; } nowImgOfs = res.ImageOffsetH(frame); if (nowImgOfs != _imgOfsH) { _imgOfsH = nowImgOfs; _mgr._uvChanged = true; sizeChnaged = true; } if (sizeChnaged) { // modify polygon size Vector2 size = res.PicArea.WH(); size.x += _imgOfsW; size.y += _imgOfsH; _orgVertices = res.GetVertices(size); orgVertChanged = true; } if (_mgr._uvChanged) { res.CalcUVs(_imgOfsX, _imgOfsY, _imgOfsW, _imgOfsH); } } // origin animation if (res.HasAttrFlags(SsKeyAttrFlags.OriginOffset)) { int nowOrgOfsX = -res.OriginOffsetX(frame); if (nowOrgOfsX != _originOffset.x) { _originOffset.x = nowOrgOfsX; orgVertChanged = true; } int nowOrgOfsY = res.OriginOffsetY(frame); if (nowOrgOfsY != _originOffset.y) { _originOffset.y = nowOrgOfsY; orgVertChanged = true; } } if (res.HasAttrFlags(SsKeyAttrFlags.Vertex)) { orgVertChanged = true; } // vertex modification if (orgVertChanged && _vertPositions != null) { for (int i = 0; i < _vertPositions.Length; ++i) { _vertPositions[i] = _orgVertices[i]; if (res.HasAttrFlags(SsKeyAttrFlags.Vertex)) { _vertPositions[i] += res.Vertex(frame).Vertex3(i); } if (res.HasAttrFlags(SsKeyAttrFlags.OriginOffset)) { _vertPositions[i] += _originOffset; } } orgVertChanged = false; _mgr._vertChanged = true; } // flip image only. the setting is given from anime resource. bool dontFlipCoord = res.IsRoot ? false : _mgr._animation.hvFlipForImageOnly; // flip H bool nowFlipH = false; if (res.IsRoot) { nowFlipH = _mgr.hFlip; } else { if (dontFlipCoord) { if (_parent != null && res.Inherits(SsKeyAttr.FlipH)) { if (!_parent._res.IsRoot) { nowFlipH = _parent._flipH; } } } if (res.FlipH(frame)) { nowFlipH = !nowFlipH; } } if (!dontFlipCoord) { if ((nowFlipH && _scale.x > 0f) || (!nowFlipH && _scale.x < 0f)) { _scale.x *= -1; _mgr._vertChanged = true; } } // flip V bool nowFlipV = false; if (res.IsRoot) { nowFlipV = _mgr.vFlip; } else { if (dontFlipCoord) { if (_parent != null && res.Inherits(SsKeyAttr.FlipV)) { if (!_parent._res.IsRoot) { nowFlipV = _parent._flipV; // 2012.06.27 fixed an issue that nowFlipV refers _parent._flipH } } } if (res.FlipV(frame)) { nowFlipV = !nowFlipV; } } if (!dontFlipCoord) { if ((nowFlipV && _scale.y > 0f) || (!nowFlipV && _scale.y < 0f)) { _scale.y *= -1; _mgr._vertChanged = true; } } if (nowFlipH != _flipH || nowFlipV != _flipV) { _flipH = nowFlipH; _flipV = nowFlipV; if (dontFlipCoord) { _mgr._uvChanged = true; } } // udpate uv indices if (_mgr._uvChanged && res.UVs != null && // root part has no UVs res.UVs.Length == 4) { if (dontFlipCoord) { int index = -1; if (nowFlipV) { index = 1; } if (nowFlipH) { ++index; } for (int i = 0; i < 4; ++i) { _mgr._uvs[_vIndex + i] = res.UVs[index >= 0 ? _flippedUvIndices[index, i] : i]; } } else { for (int i = 0; i < 4; ++i) { _mgr._uvs[_vIndex + i] = res.UVs[i]; } } } // update vertex buffer if (_mgr._vertChanged) { // udpate matrix var p = _pos; var s = _scale; if (_parent) { // previously apply compensated value if this doesn't want to inherit parent's value. if (!res.Inherits(SsKeyAttr.ScaleX)) { s.x /= _parent._scale.x; p.x /= _parent._scale.x; } if (!res.Inherits(SsKeyAttr.ScaleY)) { s.y /= _parent._scale.y; p.y /= _parent._scale.y; } } _pivotMatrix.SetTRS(p, _quaternion, s); // multiply parent's if (_parent) { _pivotMatrix = _parent._pivotMatrix * _pivotMatrix; } if (_vertPositions != null) { // apply matrix to vertices for (int i = 0; i < _vertPositions.Length; ++i) { Vector3 v = _pivotMatrix.MultiplyPoint3x4(_vertPositions[i]); _mgr._vertices[_vIndex + i] = v; } #if false if (_drawPartsRect) { // get rectangle from bounding box. Vector3 lt = _vertTransforms[0].position; Vector3 rb = _vertTransforms[2].position; Vector3 rt = lt; rt.x = rb.x; Vector3 lb = lt; lb.y = rb.y; // draw rectangle Debug.DrawLine(lt, rt, Color.red); Debug.DrawLine(rt, rb, Color.red); Debug.DrawLine(rb, lb, Color.red); Debug.DrawLine(lb, lt, Color.red); } #endif } } if (_transform) { #if _MAKE_ROOT_TO_LOCAL_TRANSFORM // update quaternion in root space and my transform if (_parent != null && _parent._rotChanged) { // apply parent's rotation on ahead _rootSpaceQuaternion = _quaternion * _parent._quaternion; UpdateRootTransform(); } else #endif if (_mgr._vertChanged) { // update transform in this part's local space. _transform.localPosition = _pos; _transform.localRotation = _quaternion; _transform.localScale = _scale; } } // ignore when called from initializing. if (initialize) { return; } // do callback at userdata key if (ExistsOnUserDataKey && _res.HasAttrFlags(SsKeyAttrFlags.User)) { _OnEvent(SsKeyAttr.User); } // do callback at sound key if (ExistsOnSoundKey && _res.HasAttrFlags(SsKeyAttrFlags.Sound)) { _OnEvent(SsKeyAttr.Sound); } }