1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * The display manager of CocoStudio
 28  * @Class ccs.DisplayManager
 29  * @extend cc.Class
 30  */
 31 ccs.DisplayManager = ccs.Class.extend(/** @lends ccs.DisplayManager */{
 32     _decoDisplayList:null,
 33     _currentDecoDisplay:null,
 34     _displayRenderNode:null,
 35     _displayIndex: null,
 36     _forceChangeDisplay:false,
 37     _bone:null,
 38     _visible:true,
 39     _displayType: null,
 40 
 41     ctor:function () {
 42         this._decoDisplayList = [];
 43         this._currentDecoDisplay = null;
 44         this._displayRenderNode = null;
 45         this._displayIndex = null;
 46         this._forceChangeDisplay = false;
 47         this._bone = null;
 48         this._visible = true;
 49         this._displayType = ccs.DISPLAY_TYPE_MAX;
 50     },
 51 
 52     init:function (bone) {
 53         this._bone = bone;
 54         this.initDisplayList(bone.getBoneData());
 55         return true;
 56     },
 57 
 58     /**
 59      * <p>
 60      *     Add display and use  _DisplayData init the display.                              <br/>
 61      *     If index already have a display, then replace it.                                <br/>
 62      *     If index is current display index, then also change display to _index            <br/>
 63      * </p>
 64      * @param {ccs.DisplayData|cc.Node} display it include the display information, like DisplayType. If you want to create a sprite display, then create a SpriteDisplayData param
 65      * @param {Number} index  the index of the display you want to replace or add to. -1 : append display from back
 66      */
 67     addDisplay: function (display, index) {
 68         var decoDisplay, locDisplayList = this._decoDisplayList;
 69         if( (index >= 0) && (index < locDisplayList.length) )
 70             decoDisplay = locDisplayList[index];
 71         else{
 72             decoDisplay = ccs.DecorativeDisplay.create();
 73             locDisplayList.push(decoDisplay);
 74         }
 75 
 76         if(display instanceof ccs.DisplayData){
 77             cc.displayFactory.addDisplay(this._bone, decoDisplay, display);
 78             //! if changed display index is current display index, then change current display to the new display
 79             if(index == this._displayIndex) {
 80                 this._displayIndex = -1;
 81                 this.changeDisplayWithIndex(index, false);
 82             }
 83             return;
 84         }
 85 
 86         var displayData = null;
 87         if (display instanceof ccs.Skin) {
 88             display.setBone(this._bone);
 89             displayData = new ccs.SpriteDisplayData();
 90             ccs.displayFactory.initSpriteDisplay(this._bone, decoDisplay, display.getDisplayName(), display);
 91 
 92             var spriteDisplayData = decoDisplay.getDisplayData();
 93             if (spriteDisplayData instanceof ccs.SpriteDisplayData) {
 94                 display.setSkinData(spriteDisplayData.skinData);
 95                 displayData.skinData = spriteDisplayData.skinData;
 96             } else {
 97                 var find = false;
 98                 for (var i = locDisplayList.length - 2; i >= 0; i--) {
 99                     var dd = locDisplayList[i];
100                     var sdd = dd.getDisplayData();
101                     if (sdd instanceof ccs.SpriteDisplayData) {
102                         find = true;
103                         display.setSkinData(sdd.skinData);
104                         displayData.skinData = sdd.skinData;
105                         break;
106                     }
107                 }
108                 if (!find)
109                     display.setSkinData(new ccs.BaseData());
110             }
111         } else if (display instanceof cc.ParticleSystem){
112             displayData = new ccs.ParticleDisplayData();
113             display.removeFromParent();
114             display.cleanup();
115             var armature = this._bone.getArmature();
116             if (armature)
117                 display.setParent(armature);
118         } else if(display instanceof ccs.Armature) {
119             displayData = new ccs.ArmatureDisplayData();
120             displayData.displayName = display.getName();
121             display.setParentBone(this._bone);
122         } else
123             displayData = new ccs.DisplayData();
124         decoDisplay.setDisplay(display);
125         decoDisplay.setDisplayData(displayData);
126 
127         //! if changed display index is current display index, then change current display to the new display
128         if(index == this._displayIndex) {
129             this._displayIndex = -1;
130             this.changeDisplayWithIndex(index, false);
131         }
132     },
133 
134     _addDisplayOther:function(decoDisplay,display){
135         var displayData = null;
136         if (display instanceof ccs.Skin){
137             var skin = display;
138             skin.setBone(this._bone);
139             displayData = new ccs.SpriteDisplayData();
140             displayData.displayName = skin.getDisplayName();
141             ccs.displayFactory.initSpriteDisplay(this._bone, decoDisplay, skin.getDisplayName(), skin);
142             var spriteDisplayData = decoDisplay.getDisplayData();
143             if (spriteDisplayData instanceof ccs.SpriteDisplayData)
144                 skin.setSkinData(spriteDisplayData.skinData);
145             else{
146                 var find = false;
147                 for (var i = this._decoDisplayList.length - 2; i >= 0; i--) {
148                     var dd = this._decoDisplayList[i];
149                     var sdd = dd.getDisplayData();
150                     if (sdd) {
151                         find = true;
152                         skin.setSkinData(sdd.skinData);
153                         displayData.skinData = sdd.skinData;
154                         break;
155                     }
156                 }
157                 if (!find) {
158                     skin.setSkinData(new ccs.BaseData());
159                 }
160                 skin.setSkinData(new ccs.BaseData());
161             }
162                 
163         }
164         else if (display instanceof cc.ParticleSystem){
165             displayData = new ccs.ParticleDisplayData();
166             displayData.displayName = display._plistFile;
167         }
168         else if (display instanceof ccs.Armature){
169             displayData = new ccs.ArmatureDisplayData();
170             displayData.displayName = display.getName();
171             display.setParentBone(this._bone);
172         }
173         else  {
174             displayData = new ccs.DisplayData();
175         }
176         decoDisplay.setDisplay(display);
177         decoDisplay.setDisplayData(displayData);
178     },
179 
180     removeDisplay:function (index) {
181         this._decoDisplayList.splice(index, 1);
182         if (index === this._displayIndex) {
183             this.setCurrentDecorativeDisplay(null);
184             this._displayIndex = -1;
185         }
186     },
187 
188     getDecorativeDisplayList:function(){
189         return this._decoDisplayList;
190     },
191 
192     /**
193      * <p>
194      *     Change display by index. You can just use this method to change display in the display list.            <br/>
195      *     The display list is just used for this bone, and it is the displays you may use in every frame.         <br/>
196      *     Note : if index is the same with prev index, the method will not effect                                 <br/>
197      * </p>
198      * @param {Number} index  The index of the display you want to change
199      * @param {Number} force  If true, then force change display to specified display, or current display will set to  display index edit in the flash every key frame.
200      */
201     changeDisplayWithIndex:function (index, force) {
202         if (index >= this._decoDisplayList.length) {
203             cc.log("the index value is out of range");
204             return;
205         }
206         this._forceChangeDisplay = force;
207 
208         //if index is equal to current display index,then do nothing
209         if (this._displayIndex == index)
210             return;
211 
212         this._displayIndex = index;
213 
214         //! If displayIndex < 0, it means you want to hide you display
215         if (index < 0) {
216             if(this._displayRenderNode) {
217                 this._displayRenderNode.removeFromParent(true);
218                 this.setCurrentDecorativeDisplay(null);
219             }
220             return;
221         }
222         this.setCurrentDecorativeDisplay(this._decoDisplayList[index]);
223     },
224 
225     changeDisplayWithName: function (name, force) {
226         var locDisplayList = this._decoDisplayList;
227         for (var i = 0; i < locDisplayList.length; i++) {
228             if (locDisplayList[i].getDisplayData().displayName == name) {
229                 this.changeDisplayWithIndex(i, force);
230                 break;
231             }
232         }
233     },
234 
235     setCurrentDecorativeDisplay:function (decoDisplay) {
236         var locCurrentDecoDisplay = this._currentDecoDisplay;
237         if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
238             if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector())
239                 locCurrentDecoDisplay.getColliderDetector().setActive(false);
240         }
241 
242         this._currentDecoDisplay = decoDisplay;
243         locCurrentDecoDisplay = this._currentDecoDisplay;
244         if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) {
245             if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector())
246                 locCurrentDecoDisplay.getColliderDetector().setActive(true);
247         }
248 
249         var displayRenderNode = (!locCurrentDecoDisplay) ? null : locCurrentDecoDisplay.getDisplay();
250 
251         var locRenderNode = this._displayRenderNode, locBone = this._bone;
252         if (locRenderNode) {
253             if (locRenderNode instanceof ccs.Armature)
254                 locBone.setChildArmature(null);
255             locRenderNode.removeFromParent(true);
256         }
257         this._displayRenderNode = displayRenderNode;
258 
259         if (displayRenderNode) {
260             if (displayRenderNode instanceof ccs.Armature) {
261                 this._bone.setChildArmature(displayRenderNode);
262                 displayRenderNode.setParentBone(this._bone);
263             } else if (displayRenderNode instanceof cc.ParticleSystem) {
264                 if (displayRenderNode instanceof ccs.Armature) {
265                     locBone.setChildArmature(displayRenderNode);
266                     displayRenderNode.setParentBone(locBone);
267                 } else if (displayRenderNode instanceof cc.ParticleSystem)
268                     displayRenderNode.resetSystem();
269             }
270 
271             displayRenderNode.setColor(locBone.getDisplayedColor());
272             displayRenderNode.setOpacity(locBone.getDisplayedOpacity());
273 
274             this._displayRenderNode.setVisible(this._visible);
275             this._displayType = this._currentDecoDisplay.getDisplayData().displayType;
276         }else
277             this._displayType = ccs.DISPLAY_TYPE_MAX;
278     },
279 
280     getDisplayRenderNode:function () {
281         return this._displayRenderNode;
282     },
283 
284     getDisplayRenderNodeType:function(){
285         return this._displayType;
286     },
287 
288     getCurrentDisplayIndex:function () {
289         return this._displayIndex;
290     },
291 
292     getCurrentDecorativeDisplay:function () {
293         return this._currentDecoDisplay;
294     },
295 
296     getDecorativeDisplayByIndex:function (index) {
297         return this._decoDisplayList[index];
298     },
299 
300     /**
301      * <p>
302      *  Use BoneData to init the display list.
303      *  If display is a sprite, and it have texture info in the TextureData, then use TextureData to init the display node's anchor point
304      *  If the display is a Armature, then create a new Armature
305      * </p>
306      * @param {ccs.BoneData} boneData
307      */
308     initDisplayList:function (boneData) {
309         this._decoDisplayList.length = 0;
310         if (!boneData)
311             return;
312         var displayList = boneData.displayDataList, decoList = this._decoDisplayList, locBone = this._bone;
313         for (var i = 0; i < displayList.length; i++) {
314             var displayData = displayList[i];
315             var decoDisplay = ccs.DecorativeDisplay.create();
316             decoDisplay.setDisplayData(displayData);
317             ccs.displayFactory.createDisplay(locBone, decoDisplay);
318             decoList.push(decoDisplay);
319         }
320     },
321 
322     /**
323      * Check if the position is inside the bone.
324      * @param {cc.Point|Number} point
325      * @param {Number} [y]
326      * @returns {boolean}
327      */
328     containPoint: function (point, y) {
329         if (!this._visible || this._displayIndex < 0)
330             return false;
331 
332         if (y !== undefined)
333             point = cc.p(point, y);
334 
335         if(this._currentDecoDisplay.getDisplayData().displayType == ccs.DISPLAY_TYPE_SPRITE){
336             /*
337              *  First we first check if the point is in the sprite content rect. If false, then we continue to check
338              *  the contour point. If this step is also false, then we can say the bone not contain this point.
339              *
340              */
341             var sprite = this._currentDecoDisplay.getDisplay();
342             sprite = sprite.getChildByTag(0);
343             return ccs.SPRITE_CONTAIN_POINT_WITH_RETURN(sprite, point);
344         }
345         return false;
346     },
347 
348     /**
349      * <p>
350      *  Sets whether the display is visible                                               <br/>
351      *  The default value is true, a node is default to visible
352      * </p>
353      * @param {boolean} visible
354      */
355     setVisible:function (visible) {
356         if (!this._displayRenderNode)
357             return;
358         this._visible = visible;
359         this._displayRenderNode.setVisible(visible);
360     },
361 
362     /**
363      * Determines if the display is visible
364      * @returns {boolean} true if the node is visible, false if the node is hidden.
365      */
366     isVisible:function () {
367         return this._visible;
368     },
369 
370     getContentSize:function () {
371         if (!this._displayRenderNode)
372             return cc.size(0, 0);
373         return this._displayRenderNode.getContentSize();
374     },
375 
376     getBoundingBox:function () {
377         if (!this._displayRenderNode)
378             return cc.rect(0, 0, 0, 0);
379         return this._displayRenderNode.getBoundingBox();
380     },
381 
382     getAnchorPoint:function () {
383         if (!this._displayRenderNode)
384             return  cc.p(0, 0);
385         return this._displayRenderNode.getAnchorPoint();
386     },
387 
388     getAnchorPointInPoints:function () {
389         if (!this._displayRenderNode)
390             return  cc.p(0, 0);
391         return this._displayRenderNode.getAnchorPointInPoints();
392     },
393 
394     getForceChangeDisplay:function () {
395         return this._forceChangeDisplay;
396     },
397 
398     release:function () {
399         this._decoDisplayList = null;
400         if (this._displayRenderNode) {
401             this._displayRenderNode.removeFromParent(true);
402             this._displayRenderNode = null;
403         }
404     }
405 });
406 
407 ccs.DisplayManager.create = function (bone) {
408     var displayManager = new ccs.DisplayManager();
409     if (displayManager && displayManager.init(bone))
410         return displayManager;
411     return null;
412 };