CCAtlasNode.js 14 KB

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