1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 
 28 /** <p> cc.AtlasNode is a subclass of cc.Node that implements the cc.RGBAProtocol and<br/>
 29  * cc.TextureProtocol protocol</p>
 30  *
 31  * <p> It knows how to render a TextureAtlas object.  <br/>
 32  * If you are going to render a TextureAtlas consider subclassing cc.AtlasNode (or a subclass of cc.AtlasNode)</p>
 33  *
 34  * <p> All features from cc.Node are valid, plus the following features:  <br/>
 35  * - opacity and RGB colors </p>
 36  * @class
 37  * @extends cc.Node
 38  */
 39 cc.AtlasNode = cc.Node.extend(/** @lends cc.AtlasNode# */{
 40     RGBAProtocol:true,
 41     //! chars per row
 42     _itemsPerRow:0,
 43     //! chars per column
 44     _itemsPerColumn:0,
 45     //! width of each char
 46     _itemWidth:0,
 47     //! height of each char
 48     _itemHeight:0,
 49     _colorUnmodified:cc.c3b(0, 0, 0),
 50     _textureAtlas:null,
 51     // protocol variables
 52     _isOpacityModifyRGB:false,
 53     _blendFunc: {src:cc.BLEND_SRC, dst:cc.BLEND_DST},
 54     _opacity:0,
 55     _color:null,
 56     _originalTexture:null,
 57     // quads to draw
 58     _quadsToDraw:0,
 59     _uniformColor:0,
 60 
 61     /** initializes an cc.AtlasNode  with an Atlas file the width and height of each item and the quantity of items to render
 62      * @param {String} tile
 63      * @param {Number} tileWidth
 64      * @param {Number} tileHeight
 65      * @param {Number} itemsToRender
 66      * @return {Boolean}
 67      */
 68     initWithTileFile:function (tile, tileWidth, tileHeight, itemsToRender) {
 69         cc.Assert(tile != null, "title should not be null");
 70         this._itemWidth = tileWidth;
 71         this._itemHeight = tileHeight;
 72 
 73         this._opacity = 255;
 74         this._color = cc.white();
 75         this._colorUnmodified = cc.white();
 76         this._isOpacityModifyRGB = true;
 77 
 78         this._blendFunc.src = cc.BLEND_SRC;
 79         this._blendFunc.dst = cc.BLEND_DST;
 80 
 81         var newAtlas = new cc.TextureAtlas();
 82         newAtlas.initWithFile(tile, itemsToRender);
 83         this.setTextureAtlas(newAtlas);
 84 
 85         if (cc.renderContextType == cc.CANVAS) {
 86             this._originalTexture = this._textureAtlas.getTexture();
 87         }
 88 
 89         if (!this._textureAtlas) {
 90             cc.log("cocos2d: Could not initialize cc.AtlasNode. Invalid Texture.");
 91             return false;
 92         }
 93 
 94         this._updateBlendFunc();
 95         this._updateOpacityModifyRGB();
 96 
 97         this._calculateMaxItems();
 98 
 99         this._quadsToDraw = itemsToRender;
100 
101         //shader stuff
102         //this.setShaderProgram(cc.ShaderCache.getInstance().programForKey(kCCShader_PositionTexture_uColor));
103         //this._uniformColor = glGetUniformLocation( this.getShaderProgram().getProgram(), "u_color");
104 
105         return true;
106 
107     },
108 
109     /** updates the Atlas (indexed vertex array).
110      * Shall be overriden in subclasses
111      */
112     updateAtlasValues:function () {
113         cc.Assert(false, "cc.AtlasNode:Abstract updateAtlasValue not overriden");
114     },
115 
116     /**
117      * @param {CanvasContext} ctx   CanvasContext
118      */
119     draw:function (ctx) {
120         this._super();
121         if (cc.renderContextType == cc.CANVAS) {
122 
123         } else {
124             //TODO for WebGL
125             //cc.NODE_DRAW_SETUP();
126 
127             //ccGLBlendFunc( this._blendFunc.src, this._blendFunc.dst );
128 
129             //var colors = [this._color.r / 255.0, this._color.g / 255.0, this._color.b / 255.0, this._opacity / 255.0];
130             //this.getShaderProgram().setUniformLocationWith4fv(this._uniformColor, colors, 1);
131 
132             //this._textureAtlas.drawNumberOfQuads(this._quadsToDraw, 0);
133         }
134     },
135 
136     /** cc.AtlasNode - RGBA protocol
137      * @return {cc.Color3B}
138      */
139     getColor:function () {
140         if (this._isOpacityModifyRGB) {
141             return this._colorUnmodified;
142         }
143         return this._color;
144     },
145 
146     /**
147      * @param {cc.Color3B} color3
148      */
149     setColor:function (color3) {
150         if ((this._color.r == color3.r) && (this._color.g == color3.g) && (this._color.b == color3.b)) {
151             return;
152         }
153         this._color = this._colorUnmodified = color3;
154 
155         if (this.getTexture()) {
156             if (cc.renderContextType == cc.CANVAS) {
157                 var cacheTextureForColor = cc.TextureCache.getInstance().getTextureColors(this._originalTexture);
158                 if (cacheTextureForColor) {
159                     var tx = this._originalTexture;
160                     var textureRect = cc.rect(0, 0, tx.width, tx.height);
161                     var colorTexture = cc.generateTintImage(tx, cacheTextureForColor, this._color, textureRect);
162                     var img = new Image();
163                     img.src = colorTexture.toDataURL();
164                     this.setTexture(img);
165                 }
166             }
167         }
168 
169         if (this._isOpacityModifyRGB) {
170             this._color.r = color3.r * this._opacity / 255;
171             this._color.g = color3.g * this._opacity / 255;
172             this._color.b = color3.b * this._opacity / 255;
173         }
174     },
175 
176     /**
177      * @return {Number}
178      */
179     getOpacity:function () {
180         return this._opacity;
181     },
182 
183     /**
184      * @param {Number} opacity
185      */
186     setOpacity:function (opacity) {
187         this._opacity = opacity;
188         // special opacity for premultiplied textures
189         //if (this._isOpacityModifyRGB) {
190         //    this.setColor(this._colorUnmodified);
191         //}
192     },
193 
194     /**
195      * @param {Boolean} value
196      */
197     setOpacityModifyRGB:function (value) {
198         var oldColor = this._color;
199         this._isOpacityModifyRGB = value;
200         this._color = oldColor;
201     },
202 
203     /**
204      * @return {Boolean}
205      */
206     isOpacityModifyRGB:function () {
207         return this._isOpacityModifyRGB;
208     },
209 
210     /** cc.AtlasNode - CocosNodeTexture protocol
211      * @return {cc.BlendFunc}
212      */
213     getBlendFunc:function () {
214         return this._blendFunc;
215     },
216 
217     /**
218      * @param {cc.BlendFunc} blendFunc
219      */
220     setBlendFunc:function (src, dst) {
221         if(arguments.length == 1)
222             this._blendFunc = src;
223         else
224             this._blendFunc = {src:src, dst:dst};
225     },
226 
227     // cc.Texture protocol
228 
229     /** returns the used texture
230      * @return {cc.Texture2D}
231      */
232     getTexture:function () {
233         return this._textureAtlas.getTexture();
234     },
235 
236     /** sets a new texture. it will be retained
237      * @param {cc.Texture2D} texture
238      */
239     setTexture:function (texture) {
240         this._textureAtlas.setTexture(texture);
241         this._updateBlendFunc();
242         this._updateOpacityModifyRGB();
243     },
244 
245     /**
246      * @param {cc.TextureAtlas} value
247      */
248     setTextureAtlas:function (value) {
249         this._textureAtlas = value;
250     },
251 
252     /**
253      * @return {cc.TextureAtlas}
254      */
255     getTextureAtlas:function () {
256         return this._textureAtlas;
257     },
258 
259     /**
260      * @return {Number}
261      */
262     getQuadsToDraw:function () {
263         return this._quadsToDraw;
264     },
265 
266     /**
267      * @param {Number} quadsToDraw
268      */
269     setQuadsToDraw:function (quadsToDraw) {
270         this._quadsToDraw = quadsToDraw;
271     },
272 
273     _calculateMaxItems:function () {
274         var size;
275         if (this._textureAtlas.getTexture() instanceof cc.Texture2D) {
276             size = this._textureAtlas.getTexture().getContentSize();
277         }
278         else {
279             size = cc.size(this._textureAtlas.getTexture().width, this._textureAtlas.getTexture().height);
280         }
281         this._itemsPerColumn = parseInt(size.height / this._itemHeight);
282         this._itemsPerRow = parseInt(size.width / this._itemWidth);
283     },
284 
285     _updateBlendFunc:function () {
286         /* if (!this._textureAtlas.getTexture().hasPremultipliedAlpha()) {
287          this._blendFunc.src = gl.SRC_ALPHA;
288          this._blendFunc.dst = gl.ONE_MINUS_SRC_ALPHA;
289          }*/
290     },
291 
292     _updateOpacityModifyRGB:function () {
293         //this._isOpacityModifyRGB = this._textureAtlas.getTexture().hasPremultipliedAlpha();
294     }
295 
296 });
297 
298 /** creates a cc.AtlasNode  with an Atlas file the width and height of each item and the quantity of items to render
299  * @param {String} tile
300  * @param {Number} tileWidth
301  * @param {Number} tileHeight
302  * @param {Number} itemsToRender
303  * @return {cc.AtlasNode}
304  * @example
305  * // example
306  * var node = cc.AtlasNode.create("pathOfTile", 16, 16, 1);
307  */
308 cc.AtlasNode.create = function (tile, tileWidth, tileHeight, itemsToRender) {
309     var ret = new cc.AtlasNode();
310     if (ret.initWithTileFile(tile, tileWidth, tileHeight, itemsToRender)) {
311         return ret;
312     }
313     return null;
314 };
315