diff --git a/.gitignore b/.gitignore index af2dade7dc..73b9c1ae31 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ lib build aspnet_client node_modules -/tools/jsdoc_toolkit-2.4.0 \ No newline at end of file +/tools/jsdoc_toolkit-2.4.0 +/package +/tools/jsdoc_toolkit/jsdoc_toolkit-2.4.0 +/.project diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 43af3292c4..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "samples"] - path = samples - url = https://github.com/cocos2d/cocos2d-js-tests.git diff --git a/AUTHORS.txt b/AUTHORS.txt index ce58b34302..e61d18e5cb 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -10,13 +10,13 @@ Core Developers: Dingping Lv (David Lv) - Shengxiang Chen (Nero Chan) - Ricardo Quesada - Xingsen Ma + Huabin LING (@pandamicro) + + Sijie Wang (@VisualSJ) - Huabin LING + Jialong Zhai (@JoshuaAstray) Contributors: Name GithubID Main contribution @@ -24,6 +24,7 @@ Name GithubID Main contribution Dali Kilani @dadilcool added instruction to read me Chris @hannon235 added node.js api for box2d + added SocketIO and SocketIO tests Jason Aeschliman @jaeschliman fixed cc.Node setposition @@ -61,6 +62,7 @@ keisuke hata(Square) @Seasons7 Code review, bug fix Marat Yakupov @moadib Various bug fixes Liang Wu @akira-cn Touch location fix for designResolution + ScrollView on paused bugs fix Jimmy Sambuo @jsambuo AudioEngine improvements @@ -84,8 +86,9 @@ Kang-Hao Lu(Opera/Oupeng) @kennyluck Optimize John Resig's inheritance patter Mark Henderson @MarkEHenderson Code review, LabelTTF and Scale9Sprite bug fix Jing Wang @06wj CCScheduler improvements - Js file loading image add - cc.RectApplyAffineTransform improvements + Js file loading image add + cc.RectApplyAffineTransform improvements + Fixed a bug of cc.Node.setPosition that parameter check is incorrect Ze Wang @WanderWang Fix crash when BrowserTypes match nothing from navigator.userAgent LabelTTF improvements @@ -112,6 +115,8 @@ XiaoJun Zheng @SmallAiTT _getResType error fix refactor some public functions in cc to private add node.js scripts for publishing game refactor cc.CCBReader + cc.view bug fix + multiple property object supports in extend function Guozhu Cheng @bengol cc.SimpleAudioEngine bug fix @@ -151,16 +156,113 @@ samael @samael65535 CCPhysicsSprite bug fix NatWeiss @NatWeiss Add analytics plugin protocol ,Flurry plugin and ProtocolAds.js plugin protocol cc.FileUtils refactoring + cc.Audio bugs fix + cc.Texture2D bug fix Andor Salga @asalga typo fix erykwalder @erykwalder Function.prototype.bind bug fix ZippoLag @ZippoLag cc.Application.getCurrentLanguage bug fix + typo fix + +Asano @LaercioAsano cc.Node bug fix + +Bruno Assarisse @bassarisse cc.LabelBMFont bug fix + +Mykyta Usikov @musikov cc.ClippingNode bugs fix + cc.fontLoader bug fix + Inverted ClippingNode with DrawNode as stencil bug fix under canvas render mode + JumpTo bug with wrong _delta position bug fix + cc.ProgressTimer bugs fix + cc.Scale9Sprite bugs fix + cc.RenderTexture bug fix + cc.ParticleSystem bug fix + +Han XiaoLong @kpkhxlgy0 cc.ParticleSytem bug fix + +AaronRZH @AaronRZH Creation of a sequence objcet or a spawn object by using new method bug fix + +Xiaodong Liu @tianxing113 cc.Spawn.create bug fix + ccui.LoadingBar.setPercent crash bug fix + +Park Hyun Chen @sincntx Touch anywhere of screen to finish input when using cc.EditBox + ccui.TextBMFont bug fix + cc.game bug fix + Fixed an issue of cc.ArmatureAnimation's setMovementEventCallFunc + +Ninja Lau @mutoo A typo bug in UILayout fix + One-loop CCArmatureAnimation can't finish when setSpeedScale is less than 1.0 bug fix + A transform error in CCTransformHelp.js fix + ccs.DisplayManager bug fix + Fix child armature lost _parentBone issue + cc.eventManager bug fix + ccs.Bone bug fix + ccs.ActionFrame bug fix + ccui.Widget bug fix + ccui.LoadingBar bug fix + +Taras Tovchenko @tovchenko cc.Skin bounding box calculation bug fix under canvas render mode + +Minh Quy @MQuy cc.MenuItemSprite bug fix + Check empty string for textureData + Adds type check functions + +Michael Yin @layerssss cc.game refactored + +Yang Yuchen @yycdef cc.sys bug fix + +K @kiwigrc cc.ParticleSystem bug fix + +Claudio Freitas @claudiofreitas ccui.TextField typo fix. + +nopakos @nopakos cc.Texture2D bug fix + +Robert Rouhani @Robmaister cc.TMXMapInfo bug fix + cc.TMXLayer bug fix + +Igor Mats @IgorMats cc.Scale9Sprite bug fix + Spine runtime update + Add getStroke and setStroke method to cc.MotionStreak + +Tim @duhaibo0404 ccs.csLoader bug fix + +Hermanto @man2 cc.loader bug fix + +Long Jiang @jianglong0156 cc.LabelBMFont bug fix + KeyCode bug fix + ccui.ListView bug fix + +Joe Lafiosca @lafiosca Added Javascript file loader + +galapagosit @galapagosit ccs.actionManager bug fix + +Dany Ellement @DEllement cc.FontDefinition & ccui.RichText improvements + cc.LayerGradient improvements + +IShm @IShm cc.Screen bug fix + cc.ParticleSystem bug fix + ccui.PageView bug fix + +Thomas Jablonski @thomas-jablonski cc.audioEngine bug fix + Cocostudio typo fix + +WingGao @WingGao cc.TMXLayer bug fix + +Skliar Ihor @igogo5yo Add Bower support + +feijing566 @feijing566 cc.Audio bug fix + +RackovychV @RackovychV Fixed a bug of `cc.Scheduler`'s `pauseAllTargetsWithMinPriority` + + +Retired Core Developers: + Shengxiang Chen (Nero Chan) + Xingsen Ma Cocos2d-x and cocos2d-html5 can not grow so fast without the active community. -Thanks to all developers who report & trace bugs, dicuss the engine usage in forum & QQ groups! +Thanks to all developers who report & trace bugs, discuss the engine usage in forum & QQ groups! Special thanks to Ricardo Quesada for giving us lots of guidances & suggestions. diff --git a/Base64Images.js b/Base64Images.js index 8f7cce4362..0d983506be 100644 --- a/Base64Images.js +++ b/Base64Images.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/CCBoot.js b/CCBoot.js index 4d4d2d3cd7..1be2d4ff3b 100644 --- a/CCBoot.js +++ b/CCBoot.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,8 +23,13 @@ THE SOFTWARE. ****************************************************************************/ +/** + * The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace + * @namespace + * @name cc + */ var cc = cc || {}; -var _tmp = _tmp || {}; +cc._tmp = cc._tmp || {}; cc._LogInfos = {}; /** @expose */ @@ -67,22 +71,98 @@ cc._isNodeJs = typeof require !== 'undefined' && require("fs"); * Iterate over an object or an array, executing a function for each matched element. * @param {object|array} obj * @param {function} iterator - * @param {object} context * @param {object} [context] */ cc.each = function (obj, iterator, context) { - if (!obj) return; + if (!obj) + return; if (obj instanceof Array) { for (var i = 0, li = obj.length; i < li; i++) { - if (iterator.call(context, obj[i], i) === false) return; + if (iterator.call(context, obj[i], i) === false) + return; } } else { for (var key in obj) { - if (iterator.call(context, obj[key], key) === false) return; + if (iterator.call(context, obj[key], key) === false) + return; } } }; +/** + * Copy all of the properties in source objects to target object and return the target object. + * @param {object} target + * @param {object} *sources + * @returns {object} + */ +cc.extend = function(target) { + var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : []; + + cc.each(sources, function(src) { + for(var key in src) { + if (src.hasOwnProperty(key)) { + target[key] = src[key]; + } + } + }); + return target; +}; + +/** + * Check the obj whether is function or not + * @param {*} obj + * @returns {boolean} + */ +cc.isFunction = function(obj) { + return typeof obj === 'function'; +}; + +/** + * Check the obj whether is number or not + * @param {*} obj + * @returns {boolean} + */ +cc.isNumber = function(obj) { + return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]'; +}; + +/** + * Check the obj whether is string or not + * @param {*} obj + * @returns {boolean} + */ +cc.isString = function(obj) { + return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]'; +}; + +/** + * Check the obj whether is array or not + * @param {*} obj + * @returns {boolean} + */ +cc.isArray = function(obj) { + return Array.isArray(obj) || + (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]'); +}; + +/** + * Check the obj whether is undefined or not + * @param {*} obj + * @returns {boolean} + */ +cc.isUndefined = function(obj) { + return typeof obj === 'undefined'; +}; + +/** + * Check the obj whether is object or not + * @param {*} obj + * @returns {boolean} + */ +cc.isObject = function(obj) { + return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]'; +}; + /** * Check the url whether cross origin * @param {String} url @@ -94,125 +174,206 @@ cc.isCrossOrigin = function (url) { return false; } var startIndex = url.indexOf("://"); - if (startIndex == -1) + if (startIndex === -1) return false; var endIndex = url.indexOf("/", startIndex + 3); - var urlOrigin = (endIndex == -1) ? url : url.substring(0, endIndex); - return urlOrigin != location.origin; + var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex); + return urlOrigin !== location.origin; }; //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++ -cc.async = { - // Counter for cc.async - _counterFunc: function (err) { - var counter = this.counter; - if (counter.err) return; - var length = counter.length; - var results = counter.results; - var option = counter.option; - var cb = option.cb, cbTarget = option.cbTarget, trigger = option.trigger, triggerTarget = option.triggerTarget; - if (err) { - counter.err = err; - if (cb) return cb.call(cbTarget, err); - return; +/** + * Async Pool class, a helper of cc.async + * @param {Object|Array} srcObj + * @param {Number} limit the limit of parallel number + * @param {function} iterator + * @param {function} onEnd + * @param {object} target + * @constructor + */ +cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){ + var self = this; + self._srcObj = srcObj; + self._limit = limit; + self._pool = []; + self._iterator = iterator; + self._iteratorTarget = target; + self._onEnd = onEnd; + self._onEndTarget = target; + self._results = srcObj instanceof Array ? [] : {}; + self._isErr = false; + + cc.each(srcObj, function(value, index){ + self._pool.push({index : index, value : value}); + }); + + self.size = self._pool.length; + self.finishedSize = 0; + self._workingSize = 0; + + self._limit = self._limit || self.size; + + self.onIterator = function(iterator, target){ + self._iterator = iterator; + self._iteratorTarget = target; + }; + + self.onEnd = function(endCb, endCbTarget){ + self._onEnd = endCb; + self._onEndTarget = endCbTarget; + }; + + self._handleItem = function(){ + var self = this; + if(self._pool.length === 0 || self._workingSize >= self._limit) + return; //return directly if the array's length = 0 or the working size great equal limit number + + var item = self._pool.shift(); + var value = item.value, index = item.index; + self._workingSize++; + self._iterator.call(self._iteratorTarget, value, index, + function(err) { + if (self._isErr) + return; + + self.finishedSize++; + self._workingSize--; + if (err) { + self._isErr = true; + if (self._onEnd) + self._onEnd.call(self._onEndTarget, err); + return; + } + + var arr = Array.prototype.slice.call(arguments, 1); + self._results[this.index] = arr[0]; + if (self.finishedSize === self.size) { + if (self._onEnd) + self._onEnd.call(self._onEndTarget, null, self._results); + return; + } + self._handleItem(); + }.bind(item), + self); + }; + + self.flow = function(){ + var self = this; + if(self._pool.length === 0) { + if(self._onEnd) + self._onEnd.call(self._onEndTarget, null, []); + return; } - var result = Array.apply(null, arguments).slice(1); - var l = result.length; - if (l == 0) result = null; - else if (l == 1) result = result[0]; - else result = result; - results[this.index] = result; - counter.count--; - if (trigger) trigger.call(triggerTarget, result, length - counter.count, length); - if (counter.count == 0 && cb) cb.apply(cbTarget, [null, results]); - }, + for(var i = 0; i < self._limit; i++) + self._handleItem(); + } +}; - // Empty function for async. - _emptyFunc: function () { +/** + * @class + */ +cc.async = /** @lends cc.async# */{ + /** + * Do tasks series. + * @param {Array|Object} tasks + * @param {function} [cb] callback + * @param {Object} [target] + * @return {cc.AsyncPool} + */ + series : function(tasks, cb, target){ + var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){ + func.call(target, cb1); + }, cb, target); + asyncPool.flow(); + return asyncPool; }, /** * Do tasks parallel. - * @param {array} tasks - * @param {object|function} [option] - * @param {function} [cb] + * @param {Array|Object} tasks + * @param {function} cb callback + * @param {Object} [target] + * @return {cc.AsyncPool} */ - parallel: function (tasks, option, cb) { - var async = cc.async; - if (cb !== undefined) { - if (typeof option == "function") option = {trigger: option}; - option.cb = cb || option.cb; - } - else if (option !== undefined) { - if (typeof option == "function") option = {cb: option}; - } else if (tasks !== undefined) option = {}; - else throw "arguments error!"; - var isArr = tasks instanceof Array; - var li = isArr ? tasks.length : Object.keys(tasks).length; - if (li == 0) { - if (option.cb) option.cb.call(option.cbTarget, null); - return; - } - var results = isArr ? [] : {}; - var counter = { length: li, count: li, option: option, results: results}; + parallel : function(tasks, cb, target){ + var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){ + func.call(target, cb1); + }, cb, target); + asyncPool.flow(); + return asyncPool; + }, - cc.each(tasks, function (task, index) { - if (counter.err) return false; - var counterFunc = !option.cb && !option.trigger ? async._emptyFunc : async._counterFunc.bind({counter: counter, index: index});//bind counter and index - task(counterFunc, index); - }); + /** + * Do tasks waterfall. + * @param {Array|Object} tasks + * @param {function} cb callback + * @param {Object} [target] + * @return {cc.AsyncPool} + */ + waterfall : function(tasks, cb, target){ + var args = []; + var lastResults = [null];//the array to store the last results + var asyncPool = new cc.AsyncPool(tasks, 1, + function (func, index, cb1) { + args.push(function (err) { + args = Array.prototype.slice.call(arguments, 1); + if(tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task + cb1.apply(null, arguments); + }); + func.apply(target, args); + }, function (err) { + if (!cb) + return; + if (err) + return cb.call(target, err); + cb.apply(target, lastResults); + }); + asyncPool.flow(); + return asyncPool; }, /** * Do tasks by iterator. - * The format of the option should be: - * { - * cb: function, - * target: object, - * iterator: function, - * iteratorTarget: function - * } - * @param {array} tasks - * @param {object|function} [option] - * @param {function} [cb] + * @param {Array|Object} tasks + * @param {function|Object} iterator + * @param {function} [callback] + * @param {Object} [target] + * @return {cc.AsyncPool} */ - map: function (tasks, option, cb) { - var self = this; - var len = arguments.length; - if (typeof option == "function") - option = {iterator: option}; - if (len === 3) - option.cb = cb || option.cb; - else if (len == 2); - else - throw "arguments error!"; - if (typeof option == "function") option = {iterator: option}; - if (cb !== undefined) - option.cb = cb || option.cb; - else if (option !== undefined) - ; - else throw "arguments error!"; - var isArr = tasks instanceof Array; - var li = isArr ? tasks.length : Object.keys(tasks).length; - if (li == 0) { - if (option.cb) option.cb.call(option.cbTarget, null); - return; + map : function(tasks, iterator, callback, target){ + var locIterator = iterator; + if(typeof(iterator) === "object"){ + callback = iterator.cb; + target = iterator.iteratorTarget; + locIterator = iterator.iterator; } - var results = isArr ? [] : {}; - var counter = { length: li, count: li, option: option, results: results}; - cc.each(tasks, function (task, index) { - if (counter.err) return false; - var counterFunc = !option.cb ? self._emptyFunc : self._counterFunc.bind({counter: counter, index: index});//bind counter and index - option.iterator.call(option.iteratorTarget, task, index, counterFunc); - }); + var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target); + asyncPool.flow(); + return asyncPool; + }, + + /** + * Do tasks by iterator limit. + * @param {Array|Object} tasks + * @param {Number} limit + * @param {function} iterator + * @param {function} cb callback + * @param {Object} [target] + */ + mapLimit : function(tasks, limit, iterator, cb, target){ + var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target); + asyncPool.flow(); + return asyncPool; } }; //+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++ -cc.path = { - +/** + * @class + */ +cc.path = /** @lends cc.path# */{ /** * Join strings to be a path. * @example @@ -227,7 +388,7 @@ cc.path = { var l = arguments.length; var result = ""; for (var i = 0; i < l; i++) { - result = (result + (result == "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, ""); + result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, ""); } return result; }, @@ -247,6 +408,20 @@ cc.path = { return temp ? temp[1] : null; }, + /** + * Get the main name of a file name + * @param {string} fileName + * @returns {string} + */ + mainFileName: function(fileName){ + if(fileName){ + var idx = fileName.lastIndexOf("."); + if(idx !== -1) + return fileName.substring(0,idx); + } + return fileName; + }, + /** * Get the file name of a file path. * @example @@ -266,21 +441,27 @@ cc.path = { var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, "")); if (!result) return null; var baseName = result[2]; - if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() == extname.toLowerCase()) + if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase()) return baseName.substring(0, baseName.length - extname.length); return baseName; }, /** - * Get ext name of a file path. + * Get dirname of a file path. * @example + * unix cc.path.driname("a/b/c.png");//-->"a/b" cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b" + cc.path.dirname("a/b/");//-->"a/b" + cc.path.dirname("c.png");//-->"" + * windows + cc.path.driname("a\\b\\c.png");//-->"a\b" + cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b" * @param {string} pathStr * @returns {*} */ dirname: function (pathStr) { - return pathStr.replace(/(\/|\\\\)$/, "").replace(/(\/|\\\\)[^(\/|\\\\)]+$/, ""); + return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2'); }, /** @@ -318,7 +499,7 @@ cc.path = { * @returns {string} */ changeBasename: function (pathStr, basename, isSameExt) { - if (basename.indexOf(".") == 0) return this.changeExtname(pathStr, basename); + if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename); var index = pathStr.indexOf("?"); var tempStr = ""; var ext = isSameExt ? this.extname(pathStr) : ""; @@ -334,7 +515,11 @@ cc.path = { //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++ //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++ -cc.loader = { +/** + * Loader for resource loading process. It's a singleton object. + * @class + */ +cc.loader = /** @lends cc.loader# */{ _jsCache: {},//cache for js _register: {},//register of loaders _langPathCache: {},//cache for lang path @@ -360,7 +545,7 @@ cc.loader = { if (args.length === 1) { results[1] = a0 instanceof Array ? a0 : [a0]; } else if (args.length === 2) { - if (typeof a1 == "function") { + if (typeof a1 === "function") { results[1] = a0 instanceof Array ? a0 : [a0]; results[2] = a1; } else { @@ -379,23 +564,24 @@ cc.loader = { * Load js files. * If the third parameter doesn't exist, then the baseDir turns to be "". * - * @param {string} [baseDir] The pre path for jsList. + * @param {string} [baseDir] The pre path for jsList or the list of js path. * @param {array} jsList List of js path. - * @param {function} [cb] Callback function + * @param {function} [cb] Callback function * @returns {*} */ loadJs: function (baseDir, jsList, cb) { var self = this, localJsCache = self._jsCache, args = self._getArgs4Js(arguments); + var preDir = args[0], list = args[1], callback = args[2]; if (navigator.userAgent.indexOf("Trident/5") > -1) { - self._loadJs4Dependency(args[0], args[1], 0, args[2]); + self._loadJs4Dependency(preDir, list, 0, callback); } else { - cc.async.map(args[1], function (item, index, cb1) { - var jsPath = cc.path.join(args[0], item); + cc.async.map(list, function (item, index, cb1) { + var jsPath = cc.path.join(preDir, item); if (localJsCache[jsPath]) return cb1(null); self._createScript(jsPath, false, cb1); - }, args[2]); + }, callback); } }, /** @@ -417,13 +603,22 @@ cc.loader = { _createScript: function (jsPath, isAsync, cb) { var d = document, self = this, s = cc.newElement('script'); s.async = isAsync; - s.src = jsPath; self._jsCache[jsPath] = true; + if(cc.game.config["noCache"] && typeof jsPath === "string"){ + if(self._noCacheRex.test(jsPath)) + s.src = jsPath + "&_t=" + (new Date() - 0); + else + s.src = jsPath + "?_t=" + (new Date() - 0); + }else{ + s.src = jsPath; + } cc._addEventListener(s, 'load', function () { + s.parentNode.removeChild(s); this.removeEventListener('load', arguments.callee, false); cb(); }, false); cc._addEventListener(s, 'error', function () { + s.parentNode.removeChild(s); cb("Load " + jsPath + " failed!"); }, false); d.body.appendChild(s); @@ -476,12 +671,14 @@ cc.loader = { // IE-specific logic here xhr.setRequestHeader("Accept-Charset", "utf-8"); xhr.onreadystatechange = function () { - xhr.readyState == 4 && xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo); + if(xhr.readyState === 4) + xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo); }; } else { if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); xhr.onload = function () { - xhr.readyState == 4 && xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo); + if(xhr.readyState === 4) + xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo); }; } xhr.send(null); @@ -503,7 +700,7 @@ cc.loader = { if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); } xhr.send(null); - if (!xhr.readyState == 4 || xhr.status != 200) { + if (!xhr.readyState === 4 || xhr.status !== 200) { return null; } return xhr.responseText; @@ -513,6 +710,23 @@ cc.loader = { } }, + loadCsb: function(url, cb){ + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + + xhr.onload = function () { + var arrayBuffer = xhr.response; // Note: not oReq.responseText + if (arrayBuffer) { + window.msg = arrayBuffer; + } + if(xhr.readyState === 4) + xhr.status === 200 ? cb(null, xhr.response) : cb("load " + url + " failed!"); + }; + + xhr.send(null); + }, + /** * Load a single resource as json. * @param {string} url @@ -520,10 +734,18 @@ cc.loader = { */ loadJson: function (url, cb) { this.loadTxt(url, function (err, txt) { - try { - err ? cb(err) : cb(null, JSON.parse(txt)); - } catch (e) { - throw "load json [" + url + "] failed : " + e; + if (err) { + cb(err); + } + else { + try { + var result = JSON.parse(txt); + } + catch (e) { + throw "parse json [" + url + "] failed : " + e; + return; + } + cb(null, result); } }); }, @@ -536,37 +758,52 @@ cc.loader = { * Load a single image. * @param {!string} url * @param {object} [option] - * @param {function} cb - * @param {string} url - * @param {object} [option] - * @param {function} [cb] + * @param {function} callback * @returns {Image} */ - loadImg: function (url, option, cb) { + loadImg: function (url, option, callback) { var opt = { isCrossOrigin: true }; - if (cb !== undefined) { - opt.isCrossOrigin = option.isCrossOrigin == null ? opt.isCrossOrigin : option.isCrossOrigin; - } + if (callback !== undefined) + opt.isCrossOrigin = option.isCrossOrigin === null ? opt.isCrossOrigin : option.isCrossOrigin; else if (option !== undefined) - cb = option; + callback = option; + + var img = this.getRes(url); + if (img) { + callback && callback(null, img); + return img; + } - var img = new Image(); - if (opt.isCrossOrigin) + img = new Image(); + if (opt.isCrossOrigin && location.origin !== "file://") img.crossOrigin = "Anonymous"; - cc._addEventListener(img, "load", function () { - this.removeEventListener('load', arguments.callee, false); - this.removeEventListener('error', arguments.callee, false); - if (cb) - cb(null, img); - }); - cc._addEventListener(img, "error", function () { - this.removeEventListener('error', arguments.callee, false); - if (cb) - cb("load image failed"); - }); + var loadCallback = function () { + this.removeEventListener('load', loadCallback, false); + this.removeEventListener('error', errorCallback, false); + + cc.loader.cache[url] = img; + if (callback) + callback(null, img); + }; + + var self = this; + var errorCallback = function () { + this.removeEventListener('error', errorCallback, false); + + if(img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous"){ + opt.isCrossOrigin = false; + self.release(url); + cc.loader.loadImg(url, opt, callback); + }else{ + typeof callback === "function" && callback("load image failed"); + } + }; + + cc._addEventListener(img, "load", loadCallback); + cc._addEventListener(img, "error", errorCallback); img.src = url; return img; }, @@ -590,18 +827,30 @@ cc.loader = { type = cc.path.extname(url); } - var obj = self.cache[url]; + var obj = self.getRes(url); if (obj) return cb(null, obj); - var loader = self._register[type.toLowerCase()]; - if (!loader) - return cb("loader for [" + type + "] not exists!"); + var loader = null; + if (type) { + loader = self._register[type.toLowerCase()]; + } + if (!loader) { + cc.error("loader for [" + type + "] not exists!"); + return cb(); + } var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; var realUrl = self.getUrl(basePath, url); + if(cc.game.config["noCache"] && typeof realUrl === "string"){ + if(self._noCacheRex.test(realUrl)) + realUrl += "&_t=" + (new Date() - 0); + else + realUrl += "?_t=" + (new Date() - 0); + } loader.load(realUrl, url, item, function (err, data) { if (err) { cc.log(err); self.cache[url] = null; + delete self.cache[url]; cb(); } else { self.cache[url] = data; @@ -609,6 +858,7 @@ cc.loader = { } }); }, + _noCacheRex: /\?/, /** * Get url with basePath. @@ -623,12 +873,15 @@ cc.loader = { var type = path.extname(url); type = type ? type.toLowerCase() : ""; var loader = self._register[type]; - if (!loader) basePath = self.resPath; - else basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; + if (!loader) + basePath = self.resPath; + else + basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; } - url = cc.path.join(basePath || "", url) + url = cc.path.join(basePath || "", url); if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) { - if (langPathCache[url]) return langPathCache[url]; + if (langPathCache[url]) + return langPathCache[url]; var extname = path.extname(url) || ""; url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname; } @@ -637,36 +890,48 @@ cc.loader = { /** * Load resources then call the callback. - * @param {string} res - * @param {function|Object} [option] option or cb - * @param {function} [cb] + * @param {string} resources + * @param {function} [option] callback or trigger + * @param {function|Object} [loadCallback] + * @return {cc.AsyncPool} */ - load: function (res, option, cb) { - if (cb !== undefined) { - if (typeof option == "function") - option = {trigger: option}; - } - else if (option !== undefined) { - if (typeof option == "function") { - cb = option; - option = {}; + load : function(resources, option, loadCallback){ + var self = this; + var len = arguments.length; + if(len === 0) + throw "arguments error!"; + + if(len === 3){ + if(typeof option === "function"){ + if(typeof loadCallback === "function") + option = {trigger : option, cb : loadCallback }; + else + option = { cb : option, cbTarget : loadCallback}; } - } - else if (res !== undefined) + }else if(len === 2){ + if(typeof option === "function") + option = {cb : option}; + }else if(len === 1){ option = {}; - else - throw "arguments error!"; - option.cb = function (err, results) { - if (err) - cc.log(err); - if (cb) - cb(results); - }; - if (!(res instanceof Array)) - res = [res]; - option.iterator = this._loadResIterator; - option.iteratorTarget = this; - cc.async.map(res, option); + } + + if(!(resources instanceof Array)) + resources = [resources]; + var asyncPool = new cc.AsyncPool( + resources, 0, + function (value, index, AsyncPoolCallback, aPool) { + self._loadResIterator(value, index, function (err) { + if (err) + return AsyncPoolCallback(err); + var arr = Array.prototype.slice.call(arguments, 1); + if (option.trigger) + option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger + AsyncPoolCallback(null, arr[0]); + }); + }, + option.cb, option.cbTarget); + asyncPool.flow(); + return asyncPool; }, _handleAliases: function (fileNames, cb) { @@ -706,27 +971,29 @@ cc.loader = { *
*
*

- * @param {String} filename The plist file name. - * @param {Function} [cb] callback + * @param {String} url The plist file name. + * @param {Function} [callback] */ - loadAliases: function (url, cb) { + loadAliases: function (url, callback) { var self = this, dict = self.getRes(url); if (!dict) { - self.load(url, function (results) { - self._handleAliases(results[0]["filenames"], cb); + self.load(url, function (err, results) { + self._handleAliases(results[0]["filenames"], callback); }); - } else self._handleAliases(dict["filenames"], cb); + } else + self._handleAliases(dict["filenames"], callback); }, /** * Register a resource loader into loader. - * @param {string} extname + * @param {string} extNames * @param {function} loader */ register: function (extNames, loader) { if (!extNames || !loader) return; var self = this; - if (typeof extNames == "string") return this._register[extNames.trim().toLowerCase()] = loader; + if (typeof extNames === "string") + return this._register[extNames.trim().toLowerCase()] = loader; for (var i = 0, li = extNames.length; i < li; i++) { self._register["." + extNames[i].trim().toLowerCase()] = loader; } @@ -757,31 +1024,71 @@ cc.loader = { */ releaseAll: function () { var locCache = this.cache, aliases = this._aliases; - for (var key in locCache) { + for (var key in locCache) delete locCache[key]; - } - for (var key in aliases) { + for (var key in aliases) delete aliases[key]; - } } - }; //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++ +/** + * A string tool to construct a string with format string. + * for example: + * cc.formatStr("a: %d, b: %b", a, b); + * cc.formatStr(a, b, c); + * @returns {String} + */ +cc.formatStr = function(){ + var args = arguments; + var l = args.length; + if(l < 1) + return ""; + + var str = args[0]; + var needToFormat = true; + if(typeof str === "object"){ + needToFormat = false; + } + for(var i = 1; i < l; ++i){ + var arg = args[i]; + if(needToFormat){ + while(true){ + var result = null; + if(typeof arg === "number"){ + result = str.match(/(%d)|(%s)/); + if(result){ + str = str.replace(/(%d)|(%s)/, arg); + break; + } + } + result = str.match(/%s/); + if(result) + str = str.replace(/%s/, arg); + else + str += " " + arg; + break; + } + }else + str += " " + arg; + } + return str; +}; + //+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++ (function () { var win = window, hidden, visibilityChange, _undef = "undefined"; - if (typeof document.hidden !== _undef) { + if (!cc.isUndefined(document.hidden)) { hidden = "hidden"; visibilityChange = "visibilitychange"; - } else if (typeof document.mozHidden !== _undef) { + } else if (!cc.isUndefined(document.mozHidden)) { hidden = "mozHidden"; visibilityChange = "mozvisibilitychange"; - } else if (typeof document.msHidden !== _undef) { + } else if (!cc.isUndefined(document.msHidden)) { hidden = "msHidden"; visibilityChange = "msvisibilitychange"; - } else if (typeof document.webkitHidden !== _undef) { + } else if (!cc.isUndefined(document.webkitHidden)) { hidden = "webkitHidden"; visibilityChange = "webkitvisibilitychange"; } @@ -793,6 +1100,12 @@ cc.loader = { var onShow = function () { if (cc.eventManager && cc.game._eventShow) cc.eventManager.dispatchEvent(cc.game._eventShow); + + if(cc.game._intervalId){ + window.cancelAnimationFrame(cc.game._intervalId); + + cc.game._runMainLoop(); + } }; if (hidden) { @@ -805,6 +1118,10 @@ cc.loader = { cc._addEventListener(win, "focus", onShow, false); } + if(navigator.userAgent.indexOf("MicroMessenger") > -1){ + win.onfocus = function(){ onShow() }; + } + if ("onpageshow" in window && "onpagehide" in window) { cc._addEventListener(win, "pagehide", onHidden, false); cc._addEventListener(win, "pageshow", onShow, false); @@ -848,149 +1165,375 @@ cc._initSys = function (config, CONFIG_KEY) { /** * Canvas of render type * @constant - * @type Number + * @type {Number} */ cc._RENDER_TYPE_CANVAS = 0; /** * WebGL of render type * @constant - * @type Number + * @type {Number} */ cc._RENDER_TYPE_WEBGL = 1; - var sys = cc.sys = {}; + /** + * System variables + * @namespace + * @name cc.sys + */ + cc.sys = {}; + var sys = cc.sys; /** * English language code + * @memberof cc.sys + * @name LANGUAGE_ENGLISH * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_ENGLISH = "en"; /** * Chinese language code + * @memberof cc.sys + * @name LANGUAGE_CHINESE * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_CHINESE = "zh"; /** * French language code + * @memberof cc.sys + * @name LANGUAGE_FRENCH * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_FRENCH = "fr"; /** * Italian language code + * @memberof cc.sys + * @name LANGUAGE_ITALIAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_ITALIAN = "it"; /** * German language code + * @memberof cc.sys + * @name LANGUAGE_GERMAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_GERMAN = "de"; /** * Spanish language code + * @memberof cc.sys + * @name LANGUAGE_SPANISH * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_SPANISH = "es"; + /** + * Spanish language code + * @memberof cc.sys + * @name LANGUAGE_DUTCH + * @constant + * @type {Number} + */ + sys.LANGUAGE_DUTCH = "du"; + /** * Russian language code + * @memberof cc.sys + * @name LANGUAGE_RUSSIAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_RUSSIAN = "ru"; /** * Korean language code + * @memberof cc.sys + * @name LANGUAGE_KOREAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_KOREAN = "ko"; /** * Japanese language code + * @memberof cc.sys + * @name LANGUAGE_JAPANESE * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_JAPANESE = "ja"; /** * Hungarian language code + * @memberof cc.sys + * @name LANGUAGE_HUNGARIAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_HUNGARIAN = "hu"; /** * Portuguese language code + * @memberof cc.sys + * @name LANGUAGE_PORTUGUESE * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_PORTUGUESE = "pt"; /** * Arabic language code + * @memberof cc.sys + * @name LANGUAGE_ARABIC * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_ARABIC = "ar"; /** * Norwegian language code + * @memberof cc.sys + * @name LANGUAGE_NORWEGIAN * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_NORWEGIAN = "no"; /** * Polish language code + * @memberof cc.sys + * @name LANGUAGE_POLISH * @constant - * @type Number + * @type {Number} */ sys.LANGUAGE_POLISH = "pl"; /** + * @memberof cc.sys + * @name OS_IOS + * @constant + * @type {string} + */ + sys.OS_IOS = "iOS"; + /** + * @memberof cc.sys + * @name OS_ANDROID + * @constant + * @type {string} + */ + sys.OS_ANDROID = "Android"; + /** + * @memberof cc.sys + * @name OS_WINDOWS * @constant * @type {string} */ sys.OS_WINDOWS = "Windows"; /** + * @memberof cc.sys + * @name OS_MARMALADE * @constant * @type {string} */ - sys.OS_IOS = "iOS"; + sys.OS_MARMALADE = "Marmalade"; /** + * @memberof cc.sys + * @name OS_LINUX + * @constant + * @type {string} + */ + sys.OS_LINUX = "Linux"; + /** + * @memberof cc.sys + * @name OS_BADA + * @constant + * @type {string} + */ + sys.OS_BADA = "Bada"; + /** + * @memberof cc.sys + * @name OS_BLACKBERRY + * @constant + * @type {string} + */ + sys.OS_BLACKBERRY = "Blackberry"; + /** + * @memberof cc.sys + * @name OS_OSX * @constant * @type {string} */ sys.OS_OSX = "OS X"; /** + * @memberof cc.sys + * @name OS_WP8 * @constant * @type {string} */ - sys.OS_UNIX = "UNIX"; + sys.OS_WP8 = "WP8"; /** + * @memberof cc.sys + * @name OS_WINRT * @constant * @type {string} */ - sys.OS_LINUX = "Linux"; + sys.OS_WINRT = "WINRT"; /** + * @memberof cc.sys + * @name OS_UNKNOWN * @constant * @type {string} */ - sys.OS_ANDROID = "Android"; sys.OS_UNKNOWN = "Unknown"; + /** + * @memberof cc.sys + * @name UNKNOWN + * @constant + * @default + * @type {Number} + */ + sys.UNKNOWN = 0; + /** + * @memberof cc.sys + * @name IOS + * @constant + * @default + * @type {Number} + */ + sys.IOS = 1; + /** + * @memberof cc.sys + * @name ANDROID + * @constant + * @default + * @type {Number} + */ + sys.ANDROID = 2; + /** + * @memberof cc.sys + * @name WIN32 + * @constant + * @default + * @type {Number} + */ + sys.WIN32 = 3; + /** + * @memberof cc.sys + * @name MARMALADE + * @constant + * @default + * @type {Number} + */ + sys.MARMALADE = 4; + /** + * @memberof cc.sys + * @name LINUX + * @constant + * @default + * @type {Number} + */ + sys.LINUX = 5; + /** + * @memberof cc.sys + * @name BADA + * @constant + * @default + * @type {Number} + */ + sys.BADA = 6; + /** + * @memberof cc.sys + * @name BLACKBERRY + * @constant + * @default + * @type {Number} + */ + sys.BLACKBERRY = 7; + /** + * @memberof cc.sys + * @name MACOS + * @constant + * @default + * @type {Number} + */ + sys.MACOS = 8; + /** + * @memberof cc.sys + * @name NACL + * @constant + * @default + * @type {Number} + */ + sys.NACL = 9; + /** + * @memberof cc.sys + * @name EMSCRIPTEN + * @constant + * @default + * @type {Number} + */ + sys.EMSCRIPTEN = 10; + /** + * @memberof cc.sys + * @name TIZEN + * @constant + * @default + * @type {Number} + */ + sys.TIZEN = 11; + /** + * @memberof cc.sys + * @name QT5 + * @constant + * @default + * @type {Number} + */ + sys.QT5 = 12; + /** + * @memberof cc.sys + * @name WP8 + * @constant + * @default + * @type {Number} + */ + sys.WP8 = 13; + /** + * @memberof cc.sys + * @name WINRT + * @constant + * @default + * @type {Number} + */ + sys.WINRT = 14; + /** + * @memberof cc.sys + * @name MOBILE_BROWSER + * @constant + * @default + * @type {Number} + */ + sys.MOBILE_BROWSER = 100; + /** + * @memberof cc.sys + * @name DESKTOP_BROWSER + * @constant + * @default + * @type {Number} + */ + sys.DESKTOP_BROWSER = 101; + sys.BROWSER_TYPE_WECHAT = "wechat"; sys.BROWSER_TYPE_ANDROID = "androidbrowser"; sys.BROWSER_TYPE_IE = "ie"; @@ -1002,96 +1545,174 @@ cc._initSys = function (config, CONFIG_KEY) { sys.BROWSER_TYPE_BAIDU = "baidubrowser"; sys.BROWSER_TYPE_MAXTHON = "maxthon"; sys.BROWSER_TYPE_OPERA = "opera"; + sys.BROWSER_TYPE_OUPENG = "oupeng"; sys.BROWSER_TYPE_MIUI = "miuibrowser"; sys.BROWSER_TYPE_FIREFOX = "firefox"; sys.BROWSER_TYPE_SAFARI = "safari"; sys.BROWSER_TYPE_CHROME = "chrome"; + sys.BROWSER_TYPE_LIEBAO = "liebao"; + sys.BROWSER_TYPE_QZONE = "qzone"; + sys.BROWSER_TYPE_SOUGOU = "sogou"; sys.BROWSER_TYPE_UNKNOWN = "unknown"; /** * Is native ? This is set to be true in jsb auto. - * @constant - * @type Boolean + * @memberof cc.sys + * @name isNative + * @type {Boolean} */ sys.isNative = false; - /** - * WhiteList of browser for WebGL. - * @constant - * @type Array - */ - var webglWhiteList = [sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_SAFARI]; - var multipleAudioWhiteList = [ - sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, - sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE - ]; - var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement; var ua = nav.userAgent.toLowerCase(); - sys.isMobile = ua.indexOf('mobile') != -1 || ua.indexOf('android') != -1; + /** + * Indicate whether system is mobile system + * @memberof cc.sys + * @name isMobile + * @type {Boolean} + */ + sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1; + + /** + * Indicate the running platform + * @memberof cc.sys + * @name platform + * @type {Number} + */ + sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER; var currLanguage = nav.language; currLanguage = currLanguage ? currLanguage : nav.browserLanguage; currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH; - sys.language = currLanguage; - /** The type of browser */ + /** + * Indicate the current language of the running system + * @memberof cc.sys + * @name language + * @type {String} + */ + sys.language = currLanguage; var browserType = sys.BROWSER_TYPE_UNKNOWN; - var browserTypes = ua.match(/micromessenger|qqbrowser|mqqbrowser|ucbrowser|360browser|baiduboxapp|baidubrowser|maxthon|trident|opera|miuibrowser|firefox/i) + var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i) || ua.match(/chrome|safari/i); if (browserTypes && browserTypes.length > 0) { - browserType = browserTypes[0].toLowerCase(); - if (browserType == 'micromessenger') { + browserType = browserTypes[0]; + if (browserType === 'micromessenger') { browserType = sys.BROWSER_TYPE_WECHAT; } else if (browserType === "safari" && (ua.match(/android.*applewebkit/))) browserType = sys.BROWSER_TYPE_ANDROID; - else if (browserType == "trident") browserType = sys.BROWSER_TYPE_IE; + else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE; + else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360; + }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){ + browserType = "safari"; } + /** + * Indicate the running browser type + * @memberof cc.sys + * @name browserType + * @type {String} + */ sys.browserType = browserType; + // Get the os of system + var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false ); + var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false; + var osName = sys.OS_UNKNOWN; + if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS; + else if (iOS) osName = sys.OS_IOS; + else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX; + else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX; + else if (isAndroid) osName = sys.OS_ANDROID; + else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX; + + /** + * Indicate the running os name + * @memberof cc.sys + * @name os + * @type {String} + */ + sys.os = osName; + + var multipleAudioWhiteList = [ + sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP, + sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE + ]; + sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1; + //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++ - var userRenderMode = parseInt(config[CONFIG_KEY.renderMode]); - var renderType = cc._RENDER_TYPE_WEBGL; - var tempCanvas = cc.newElement("Canvas"); - cc._supportRender = true; - var notInWhiteList = webglWhiteList.indexOf(sys.browserType) == -1; - if (userRenderMode === 1 || (userRenderMode === 0 && (sys.isMobile || notInWhiteList))) { - renderType = cc._RENDER_TYPE_CANVAS; - } + (function(sys, config){ + var userRenderMode = config[CONFIG_KEY.renderMode] - 0; + if(isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0) + userRenderMode = 0; + var shieldOs = [sys.OS_ANDROID]; + var shieldBrowser = []; + var tmpCanvas = cc.newElement("canvas"); + cc._renderType = cc._RENDER_TYPE_CANVAS; + cc._supportRender = false; + + var supportWebGL = win.WebGLRenderingContext; + + if(userRenderMode === 2 || (userRenderMode === 0 && supportWebGL && shieldOs.indexOf(sys.os) === -1 && shieldBrowser.indexOf(sys.browserType) === -1)) + try{ + var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true }); + if(context){ + cc._renderType = cc._RENDER_TYPE_WEBGL; + cc._supportRender = true; + } + }catch(e){} - if (renderType == cc._RENDER_TYPE_WEBGL) { - if (!win.WebGLRenderingContext - || !cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true })) { - if (userRenderMode == 0) renderType = cc._RENDER_TYPE_CANVAS; - else cc._supportRender = false; - } - } + if(userRenderMode === 1 || (userRenderMode === 0 && cc._supportRender === false)) + try { + tmpCanvas.getContext("2d"); + cc._renderType = cc._RENDER_TYPE_CANVAS; + cc._supportRender = true; + } catch (e) {} + })(sys, config); + + sys._canUseCanvasNewBlendModes = function(){ + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var context = canvas.getContext('2d'); + context.fillStyle = '#000'; + context.fillRect(0,0,1,1); + context.globalCompositeOperation = 'multiply'; + + var canvas2 = document.createElement('canvas'); + canvas2.width = 1; + canvas2.height = 1; + var context2 = canvas2.getContext('2d'); + context2.fillStyle = '#fff'; + context2.fillRect(0,0,1,1); + + context.drawImage(canvas2, 0, 0, 1, 1); + + return context.getImageData(0,0,1,1).data[0] === 0; + }; - if (renderType == cc._RENDER_TYPE_CANVAS) { - try { - tempCanvas.getContext("2d"); - } catch (e) { - cc._supportRender = false; - } - } - cc._renderType = renderType; - //++++++++++++++++++something about cc._renderTYpe and cc._supportRender end++++++++++++++++++++++++++++++ + //Whether or not the Canvas BlendModes are supported. + sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes(); + //++++++++++++++++++something about cc._renderType and cc._supportRender end++++++++++++++++++++++++++++++ // check if browser supports Web Audio // check Web Audio's context try { - sys._supportWebAudio = !!(new (win.AudioContext || win.webkitAudioContext || win.mozAudioContext)()); + sys._supportWebAudio = !!(win.AudioContext || win.webkitAudioContext || win.mozAudioContext); } catch (e) { sys._supportWebAudio = false; } - /** LocalStorage is a local storage component. + /** + * cc.sys.localStorage is a local storage component. + * @memberof cc.sys + * @name localStorage + * @type {Object} */ try { var localStorage = sys.localStorage = win.localStorage; @@ -1106,46 +1727,80 @@ cc._initSys = function (config, CONFIG_KEY) { }; } - var capabilities = sys.capabilities = {"canvas": true}; - if (cc._renderType == cc._RENDER_TYPE_WEBGL) + if (cc._renderType === cc._RENDER_TYPE_WEBGL) capabilities["opengl"] = true; - if (docEle['ontouchstart'] !== undefined || nav.msPointerEnabled) + if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled) capabilities["touches"] = true; - else if (docEle['onmouseup'] !== undefined) + if (docEle['onmouseup'] !== undefined) capabilities["mouse"] = true; if (docEle['onkeyup'] !== undefined) capabilities["keyboard"] = true; if (win.DeviceMotionEvent || win.DeviceOrientationEvent) capabilities["accelerometer"] = true; - /** Get the os of system */ - var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false ); - var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false; - var osName = sys.OS_UNKNOWN; - if (nav.appVersion.indexOf("Win") != -1) osName = sys.OS_WINDOWS; - else if (iOS) osName = sys.OS_IOS; - else if (nav.appVersion.indexOf("Mac") != -1) osName = sys.OS_OSX; - else if (nav.appVersion.indexOf("X11") != -1) osName = sys.OS_UNIX; - else if (nav.appVersion.indexOf("Linux") != -1) osName = sys.OS_LINUX; - else if (isAndroid) osName = sys.OS_ANDROID; - sys.os = osName; - - // Forces the garbage collector + /** + * Forces the garbage collection, only available in JSB + * @memberof cc.sys + * @name garbageCollect + * @function + */ sys.garbageCollect = function () { // N/A in cocos2d-html5 }; - // Dumps rooted objects + /** + * Dumps rooted objects, only available in JSB + * @memberof cc.sys + * @name dumpRoot + * @function + */ sys.dumpRoot = function () { // N/A in cocos2d-html5 }; - // restarts the JS VM + /** + * Restart the JS VM, only available in JSB + * @memberof cc.sys + * @name restartVM + * @function + */ sys.restartVM = function () { // N/A in cocos2d-html5 }; + /** + * Clean a script in the JS VM, only available in JSB + * @memberof cc.sys + * @name cleanScript + * @param {String} jsfile + * @function + */ + sys.cleanScript = function (jsfile) { + // N/A in cocos2d-html5 + }; + + /** + * Check whether an object is valid, + * In web engine, it will return true if the object exist + * In native engine, it will return true if the JS object and the correspond native object are both valid + * @memberof cc.sys + * @name isObjectValid + * @param {Object} obj + * @return {boolean} Validity of the object + * @function + */ + sys.isObjectValid = function (obj) { + if (obj) return true; + else return false; + }; + + /** + * Dump system informations + * @memberof cc.sys + * @name dump + * @function + */ sys.dump = function () { var self = this; var str = ""; @@ -1154,8 +1809,19 @@ cc._initSys = function (config, CONFIG_KEY) { str += "browserType : " + self.browserType + "\r\n"; str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n"; str += "os : " + self.os + "\r\n"; + str += "platform : " + self.platform + "\r\n"; cc.log(str); } + + /** + * Open a url in browser + * @memberof cc.sys + * @name openURL + * @param {String} url + */ + sys.openURL = function(url){ + window.open(url); + } }; //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++ @@ -1165,52 +1831,52 @@ cc._initSys = function (config, CONFIG_KEY) { /** * Device oriented vertically, home button on the bottom * @constant - * @type Number + * @type {Number} */ cc.ORIENTATION_PORTRAIT = 0; /** * Device oriented vertically, home button on the top * @constant - * @type Number + * @type {Number} */ cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1; /** * Device oriented horizontally, home button on the right * @constant - * @type Number + * @type {Number} */ cc.ORIENTATION_LANDSCAPE_LEFT = 2; /** * Device oriented horizontally, home button on the left * @constant - * @type Number + * @type {Number} */ cc.ORIENTATION_LANDSCAPE_RIGHT = 3; /** * drawing primitive of game engine - * @type cc.DrawingPrimitive + * @type {cc.DrawingPrimitive} */ cc._drawingUtil = null; /** * main Canvas 2D/3D Context of game engine - * @type CanvasRenderingContext2D|WebGLRenderingContext + * @type {CanvasRenderingContext2D|WebGLRenderingContext} */ cc._renderContext = null; /** * main Canvas of game engine - * @type HTMLCanvasElement + * @type {HTMLCanvasElement} */ cc._canvas = null; /** * This Div element contain all game canvas - * @type HTMLDivElement + * @type {HTMLDivElement} */ cc._gameDiv = null; @@ -1238,17 +1904,18 @@ cc._rendererInitialized = false; * // declare like this:
* cc._setup("Cocos2dGameContainer"); */ +cc._setupCalled = false; cc._setup = function (el, width, height) { + // Avoid setup to be called twice. + if (cc._setupCalled) return; + else cc._setupCalled = true; var win = window; - win.requestAnimFrame = win.requestAnimationFrame || - win.webkitRequestAnimationFrame || - win.mozRequestAnimationFrame || - win.oRequestAnimationFrame || - win.msRequestAnimationFrame; - var element = cc.$(el) || cc.$('#' + el); var localCanvas, localContainer, localConStyle; - if (element.tagName == "CANVAS") { + + cc.game._setAnimFrame(); + + if (element.tagName === "CANVAS") { width = width || element.width; height = height || element.height; @@ -1259,19 +1926,21 @@ cc._setup = function (el, width, height) { localCanvas.appendTo(localContainer); localContainer.setAttribute('id', 'Cocos2dGameContainer'); } else {//we must make a new canvas and place into this element - if (element.tagName != "DIV") { + if (element.tagName !== "DIV") { cc.log("Warning: target element is not a DIV or CANVAS"); } width = width || element.clientWidth; height = height || element.clientHeight; localContainer = cc.container = element; - localCanvas = cc._canvas = cc.newElement("CANVAS"); + localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS")); element.appendChild(localCanvas); } localCanvas.addClass("gameCanvas"); localCanvas.setAttribute("width", width || 480); localCanvas.setAttribute("height", height || 320); + localCanvas.setAttribute("tabindex", 99); + localCanvas.style.outline = "none"; localConStyle = localContainer.style; localConStyle.width = (width || 480) + "px"; localConStyle.height = (height || 320) + "px"; @@ -1281,12 +1950,13 @@ cc._setup = function (el, width, height) { localConStyle.overflow = 'hidden'; localContainer.top = '100%'; - if (cc._renderType == cc._RENDER_TYPE_WEBGL) + if (cc._renderType === cc._RENDER_TYPE_WEBGL) cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, { 'stencil': true, 'preserveDrawingBuffer': true, 'antialias': !cc.sys.isMobile, - 'alpha': false}); + 'alpha': false + }); if (cc._renderContext) { win.gl = cc._renderContext; // global variable declared in CCMacro.js cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext); @@ -1294,9 +1964,7 @@ cc._setup = function (el, width, height) { cc.textureCache._initializingRenderer(); cc.shaderCache._init(); } else { - cc._renderContext = localCanvas.getContext("2d"); - cc._mainRenderContextBackup = cc._renderContext; - cc._renderContext.translate(0, localCanvas.height); + cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d")); cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null; } @@ -1315,18 +1983,36 @@ cc._setup = function (el, width, height) { // Init singletons - // View + /** + * @type {cc.EGLView} + * @name cc.view + * cc.view is the shared view object. + */ cc.view = cc.EGLView._getInstance(); // register system events cc.inputManager.registerSystemEvent(cc._canvas); - // Director + /** + * @type {cc.Director} + * @name cc.director + */ cc.director = cc.Director._getInstance(); - if (cc.director.setOpenGLView)cc.director.setOpenGLView(cc.view); + if (cc.director.setOpenGLView) + cc.director.setOpenGLView(cc.view); + /** + * @type {cc.Size} + * @name cc.winSize + * cc.winSize is the alias object for the size of the current game window. + */ cc.winSize = cc.director.getWinSize(); // Parsers cc.saxParser = new cc.SAXParser(); + /** + * @type {cc.PlistParser} + * @name cc.plistParser + * A Plist Parser + */ cc.plistParser = new cc.PlistParser(); }; @@ -1349,8 +2035,10 @@ cc._setContextMenuEnable = function (enabled) { /** * An object to boot the game. + * @class + * @name cc.game */ -cc.game = { +cc.game = /** @lends cc.game# */{ DEBUG_MODE_NONE: 0, DEBUG_MODE_INFO: 1, DEBUG_MODE_WARN: 2, @@ -1368,7 +2056,7 @@ cc.game = { /** * Key of config * @constant - * @type Object + * @type {Object} */ CONFIG_KEY: { engineDir: "engineDir", @@ -1387,22 +2075,25 @@ cc.game = { _paused: true,//whether the game is paused _intervalId: null,//interval target of main + + _lastTime: null, + _frameTime: null, /** * Config of game - * @type Object + * @type {Object} */ config: null, /** * Callback when the scripts of engine have been load. - * @type Function + * @type {Function} */ onStart: null, /** * Callback when game exits. - * @type Function + * @type {Function} */ onStop: null, @@ -1413,54 +2104,95 @@ cc.game = { setFrameRate: function (frameRate) { var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY; config[CONFIG_KEY.frameRate] = frameRate; - if (self._intervalId) clearInterval(self._intervalId); + if (self._intervalId) + window.cancelAnimationFrame(self._intervalId); self._paused = true; + self._setAnimFrame(); self._runMainLoop(); }, - /** - * Run game. - * @private - */ + _setAnimFrame: function () { + this._lastTime = new Date(); + this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate]; + if((cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT) || cc.game.config[cc.game.CONFIG_KEY.frameRate] !== 60) { + window.requestAnimFrame = this._stTime; + window.cancelAnimationFrame = this._ctTime; + } + else { + window.requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + this._stTime; + window.cancelAnimationFrame = window.cancelAnimationFrame || + window.cancelRequestAnimationFrame || + window.msCancelRequestAnimationFrame || + window.mozCancelRequestAnimationFrame || + window.oCancelRequestAnimationFrame || + window.webkitCancelRequestAnimationFrame || + window.msCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.oCancelAnimationFrame || + this._ctTime; + } + }, + _stTime: function(callback){ + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime)); + var id = window.setTimeout(function() { callback(); }, + timeToCall); + cc.game._lastTime = currTime + timeToCall; + return id; + }, + _ctTime: function(id){ + window.clearTimeout(id); + }, + //Run game. _runMainLoop: function () { var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY, - win = window, frameRate = config[CONFIG_KEY.frameRate], director = cc.director; + director.setDisplayStats(config[CONFIG_KEY.showFPS]); - if (win.requestAnimFrame && frameRate == 60) { - callback = function () { - if (!self._paused) { - director.mainLoop(); - win.requestAnimFrame(callback); - } - }; - win.requestAnimFrame(callback); - } else { - callback = function () { + + callback = function () { + if (!self._paused) { director.mainLoop(); - }; - self._intervalId = setInterval(callback, 1000.0 / frameRate); - } + if(self._intervalId) + window.cancelAnimationFrame(self._intervalId); + self._intervalId = window.requestAnimFrame(callback); + } + }; + + window.requestAnimFrame(callback); self._paused = false; }, + /** + * Restart game. + */ + restart: function () { + cc.director.popToSceneStackLevel(0); + // Clean up audio + cc.audioEngine && cc.audioEngine.end(); + + cc.game.onStart(); + }, + /** * Run game. */ - run: function () { + run: function (id) { var self = this; - if (!self._prepareCalled) { - self.prepare(function () { - if (cc._supportRender) { - cc._setup(self.config[self.CONFIG_KEY.id]); - self._runMainLoop(); - self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE); - self._eventHide.setUserData(self); - self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW); - self._eventShow.setUserData(self); - self.onStart(); - } - }); - } else { + var _run = function () { + if (id) { + self.config[self.CONFIG_KEY.id] = id; + } + if (!self._prepareCalled) { + self.prepare(function () { + self._prepared = true; + }); + } if (cc._supportRender) { self._checkPrepare = setInterval(function () { if (self._prepared) { @@ -1475,28 +2207,48 @@ cc.game = { } }, 10); } - } + }; + document.body ? + _run() : + cc._addEventListener(window, 'load', function () { + this.removeEventListener('load', arguments.callee, false); + _run(); + }, false); }, - /** - * Init config. - * @param cb - * @returns {*} - * @private - */ + _initConfig: function () { var self = this, CONFIG_KEY = self.CONFIG_KEY; var _init = function (cfg) { cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5"; - cfg[CONFIG_KEY.debugMode] = cfg[CONFIG_KEY.debugMode] || 0; + if(cfg[CONFIG_KEY.debugMode] == null) + cfg[CONFIG_KEY.debugMode] = 0; cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60; - cfg[CONFIG_KEY.renderMode] = cfg[CONFIG_KEY.renderMode] || 0; + if(cfg[CONFIG_KEY.renderMode] == null) + cfg[CONFIG_KEY.renderMode] = 1; return cfg; }; if (document["ccConfig"]) { self.config = _init(document["ccConfig"]); } else { try { - var txt = cc.loader._loadTxtSync("project.json"); + var cocos_script = document.getElementsByTagName('script'); + for(var i=0;i ccGame.DEBUG_MODE_ERROR){ + //log to web page + locLog = cc._logToWebPage.bind(cc); + cc.error = function(){ + locLog("ERROR : " + cc.formatStr.apply(cc, arguments)); + }; + cc.assert = function(cond, msg) { + if (!cond && msg) { + for (var i = 2; i < arguments.length; i++) + msg = msg.replace(/(%s)|(%d)/, cc._formatString(arguments[i])); + locLog("Assert: " + msg); } - cc._logToWebPage(msg); + }; + if(mode !== ccGame.DEBUG_MODE_ERROR_FOR_WEB_PAGE){ + cc.warn = function(){ + locLog("WARN : " + cc.formatStr.apply(cc, arguments)); + }; + } + if(mode === ccGame.DEBUG_MODE_INFO_FOR_WEB_PAGE){ + cc.log = function(){ + locLog(cc.formatStr.apply(cc, arguments)); + }; } + } else if(console && console.log.apply){//console is null when user doesn't open dev tool on IE9 + //log to console + + cc.error = function(){ + return console.error.apply(console, arguments); + }; + cc.assert = function (cond, msg) { + if (!cond && msg) { + for (var i = 2; i < arguments.length; i++) + msg = msg.replace(/(%s)|(%d)/, cc._formatString(arguments[i])); + throw msg; + } + }; + if(mode !== ccGame.DEBUG_MODE_ERROR) + cc.warn = function(){ + return console.warn.apply(console, arguments); + }; + if(mode === ccGame.DEBUG_MODE_INFO) + cc.log = function(){ + return console.log.apply(console, arguments); + }; } -} - +}; +cc._initDebugSetting(cc.game.config[cc.game.CONFIG_KEY.debugMode]); //+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++ \ No newline at end of file diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c51ecbc9e7..50b7feade2 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,521 @@ ChangeLog: + +Cocos2d-JS v3.6 @ April 29 2015 + +* Added GAF web runtime to the web engine, the native support will be merged in future version. +* Synchronised Cocos2d-x v3.6. + +* Bug fixes: + 1. Fixed a bug of Cocos Studio parser that it doesn't parse correctly the outline of text widget and button widget. + 2. Fixed a bug of Cocos Studio parser that it doesn't support inner action correctly. + 3. Fixed a bug of Cocos Studio parser that `ccui.Text`'s content size is set incorrectly. + 4. Fixed a bug of Cocos Studio parser that `ccui.Layout`'s background color is set incorrectly. + 5. Fixed a bug of `cc.Node`'s `removeAllChildren` that it doesn't notify the renderer to update. + 6. Fixed a bug of audio system that the resume of music may start from the beginning. + 7. Fixed a bug that sprite's `setTexture` fails to update its content size. + 8. Fixed a bug that Scale9Sprite's children doesn't get transformed recursively. + 9. Fixed constant naming issue of `ccs.FrameEaseType`. + 10. Fixed `cc.LoaderScene.preload` API inconsistency between web engine and native engine. + 11. Fixed a bug that `ccui.Slider` doesn't act correctly when it's scaled. + 12. Fixed a bug that `ccui.Button` renders incorrectly when scale9sprite option enabled. + 13. Fixed circular invocation issue in `cc.Sprite`'s canvas render command. + +Cocos2d-JS v3.6 Beta @ April 22 2015 + +* Improved TMX transform to support RotationX and RotationY. +* Refactored Spine skeleton render command. +* Added checks to prevent issues when `cc.Node.WebGLRenderCmd` is not exist. +* Improved iOS browsers detection. +* Added getter setter function for `cc.MotionStreak`'s stroke property. +* Improved the detection of render mode. +* Upgraded Action Timeline and parser for the latest version of Cocos editor. +* Added `enumerateChildren` function for `cc.Node`. +* Make `cc.Scale9Sprite` support unpreloaded texture. +* Added `cc.sys.isObjectValid` to detect whether an object is still valid (in web and native engine). + +* Bug fixes: + 1. Fixed a bug that `cc.Scheduler`'s `scheduleOnce` runs multiply times. + 2. Fixed a bug of `cc.Scheduler`'s `pauseAllTargetsWithMinPriority`. + 3. Fixed a bug of `cc.eventManager` that its event listeners' order is incorrect when some nodes haven't been added to the scene graph or have been removed from parent without cleanup. + 4. Fixed a bug of `cc.LabelTTF` that `enableShadow` doesn't work. + 5. Fixed a bug of `cc.LabelTTF` that `setColor` doesn't set shadow color under Canvas render mode. + 6. Fixed a bug that stopped audios can be resume after invoking pause on them. + 7. Fixed a bug that `ccui.LoadingBar`'s texture renders incorrectly without preload. + 8. Fixed a bug that cocos builder's callback doesn't get invoked. + 9. Fixed a bug that TMX objects' position is incorrect when content scale factor is modified. + 10. Fixed a mistaken usage of `cc.isObject` in `cc.Sprite` implementation. + 11. Fixed a bug that position type haven't been copied in `cc.ParticleSystem`'s `clone` function. + 12. Fixed some undefined parameter check issues in `cc.Node`. + 13. Fixed a bug that setter for `scaleY` of `cc.EditBox` is incorrect. + 14. Fixed a bug of `cc.SkeletonAnimation` that its canvas render command doesn't work correctly. + 15. Fixed a parsing issue for the width of `cc.LabelBMFont`. + 16. Fixed `ccs.TweenType`'s constants naming issue. + 17. Fixed a bug that the spine skeleton may be rendered under the unsupported mode. + 18. Fixed a bug when setting `cc.ParticleSystem`'s blend function in the ActionTimeline parser. + 19. Added check to prevent issues that functions may not exist in the ActionTimeline parser. + 20. Fixed a typo of `ccs.displayFactory`. + 21. Fixed a bug of `cc.Node.setPosition` that parameter check is incorrect. + +Cocos2d-JS v3.5 @ April 1 2015 + +* Upgraded Cocos Studio parser to support Cocos Studio v2.2. +* Upgraded Spine support to v2.1, added spine test case with FFD. FFD is supported in native but not in web, both engine can parse the new version file correctly, but the web engine will ignore FFD informations. +* Replaced '==' with '===' for better performance. +* Added `path` parameter in `ccs.load` to support modifying cocostudio project resource path. +* Added animationList to Cocostudio ActionTimeline to support playing animation by name. +* Made ParticleSystem support creation from an map object. +* Added missing functions to `cc.Grid3D` and `cc.PageTurn3D`. +* Added tip message functions to `cc.TextFieldTTF` for mobile browser. +* Added a function `cc.sys.openURL`. +* Disabled retina display by default for better performance. +* Added Bower support. +* Updated `cc.sys.OS_XXX` informations for supported systems. + +* Bug fixes: + 1. Fixed a bug of chipmunk.js that it doesn't work under closure compiler advanced mode. + 2. Fixed a bug of Cocos Studio parser that widget didn't set its layout component. + 3. Fixed grammatical mistakes in cocostudio parser logs. + 4. Fixed memory leak issue in `cc.LabelBMFont`. + 5. Fixed a bug of `cc.Scale9Sprite` that its `updateDisplayColor` doesn't take effect. + 6. Fixed a bug of Cocos Studio parser that `cc.Scale9Sprite` doesn't display correctly if its texture isn't preloaded. + 7. Fixed a bug of `cc.MenuItemSprite` that the construction will fail when parameter `selectedSprite` is a Scale9Sprite instance. + 8. Fixed a bug of Cocos Studio parser that the background color of `ccui.Layout` can't be parsed correctly. + 9. Fixed a bug of `cc.ClippingNode` that it doesn't work when set `inverted` to true in Canvas Mode. + 10. Fixed a bug of `ccs.Armature` that its name was modified to animation name when loading from json files. + 11. Fixed a bug of `ccui.PageView` that it cancel child touch during movment of page view. + 12. Fixed a bug of `cc.Scheduler` that its parameter `repeat` is invalid in schedule function. + 13. Fixed a bug of `cc.Scheduler` that `unschedule` function may fail. + +Cocos2d-JS v3.4 Beta0 @ March 19 2015 + +* Added Windows Phone 8.0 platform support. +* Upgraded SpiderMonkey to v33, greatly improved JS object garbage collection and performance. +* Bound 3D modules including camera, light, sprite 3d, animation 3d, billboard, etc. +* Improved `cc.FontDefinition` & `ccui.RichText` in the web engine. +* Added gradient stops feature to `cc.LayerGradient` [Web exclusive]. +* Upgraded `cc.Scheduler` in the web engine with Cocos2d-x v3.4 implementation. +* Added a loading screen when scripts are loading. +* Improved performance by replacing `Object.defineProperties` with `cc.defineGetterSetter`. +* Supported loading sprite frames from json object. +* Refactored math library to improve web engine performance. +* Removed some variables from `cc` namespace to improve web engine performance. +* Added the Firefox OS Web manifest to support Firefox OS apps. +* Added `cocos` attr to the script element in templates. +* Moved loading.js to res folder for Cocos Console release mode. + +* Bug fixes: + 1. Added `getSpriteFrame` to `cc.Sprite` to fix API inconsistency. + 2. Added `getObejct` to `cc.TMXObjectGroup` to fix API inconsistency. + 3. Added `addImageAsync` to `cc.textureCache` to fix API inconsistency. + 4. Fixed a bug of `cc.text` that its default font name is incorrect. + 5. Fixed a bug of `ccui.PageView` that its `getPage` doesn't work. + 6. Fixed a bug of `ccui.ImageView` that its `loadTexture` doesn't work while it's invoked multiple times at the same frame. + 7. Fixed a bug of `ccui` that its load event callbacks have some mistakes. + 8. Fixed a bug of `cc.Layer` that its bake function doesn't work when the layer has a parent node. + 9. Fixed typos in `cc.ClippingNode.WebGLRenderCmd` and `cc.ParticleSystem.WebGLRenderCmd` creation. + 10. Fixed a bug of `cc.Sprite` in `setTextureRect`. + 11. Fixed a bug of `cc.Screen`. + 12. Fixed a bug of `cc.view` that it doesn't work on iOS 8.1.2. + 13. Fixed a bug of cc.DrawNode that its lineWidth is always to default value when set linewidth to zero. + 14. Fixed a bug in hack for particles performance on canvas. + 15. Fixed a bug of `cc.audioEngine` that it doesn't work after minified/compiled. + 16. Fixed a bug in `CCBoot.js` that WebGL is not activated in web view of iOS 8. + 17. Fixed a bug of `cc.CheckBox` that its position is incorrect when its texture isn't preloaded. + 18. Fixed a bug of `cc.TMXLayer` that it stops to work after `setTileGID` called. + 19. Fixed a bug of Cocos parser 2.x that it doesn't set widget's LayoutComponent. + 20. Fixed a bug of `cc.isObject` that it considered function as an object. + +Cocos2d-JS v3.3 @ Feb.9, 2015 + +* Upgraded spine runtime to support the latest version and updated its test case. +* Added an option "noCache" for debugging on browsers. +* Set the default value of `cc.ParticleSystem`'s draw mode to texture mode. +* Added message to `ccs.load` when loading armature json file. +* Improved particle system test case. + +* Bug fixes: + 1. Fixed a bug of `cc.Sprite` that its `setSpriteFrame` doesn't work when sprite frame's `rotated` property is true. + 2. Fixed a bug of `cc.ClippingNode` when its stencil is `cc.Node` object in canvas mode. + 3. Fixed a ccui bug that the position of widgets is incorrect after loaded v2.x json file with `ccs.load`. + 4. Fixed a bug of `cc.PhysicsSprite` that `setIgnoreBodyRotation` function doesn't work. + 5. Fixed a bug of `ccui.Button` that setting pressed texture doesn't work when scale9 enabled. + 6. Fixed a bug of `ccui.ScrollView` that its `dir` property is null when passing `DIR_NONE` as `direction` in `_endRecordSlidAction` function. + +Cocos2d-JS v3.3 RC0 @ Feb.1, 2015 + +* Added web exclusive functions: `_getFontStyle`, `_setFontStyle`, `_getFontWeight` and `_setFontWeight` APIs to `cc.LabelTTF`. +* Observed orientation change event on mobile for resolution policy adaptation. + +* Bug fixes: + 1. Fixed Cocos Studio JSON parser's issues for parsing nested animation. + 2. Fixed Cocos Studio JSON parser's parameters parsing issues. + 3. Fixed Cocos Studio JSON parser's issue for parsing layer. + 4. Fixed Cocos Studio JSON action parser's issues. + 5. Fixed Cocos Studio JSON parser's issue for parsing Scale9Sprite. + 6. Fixed Cocos Studio JSON parser's issues caused by parsing process order. + 7. Fixed Cocos Studio JSON parser's issue for parsing loading bar's direction. + 8. Fixed UI layout system issues. + 9. Fixed `cc.EditBox`'s position issue under certain resolution policies. + 10. Fixed `ccui.ListView`'s issue for setting direction. + 11. Fixed an issue of `cc.Tween` that its `_currentPercent` is incorrect in `updateHandler` function. + 12. Fixed an issue of `ccui.Button` that its state is incorrect in `_onPressStateChangedToNormal`. + 13. Fixed an issue of `cc.ArmatureAnimation`'s `setMovementEventCallFunc`. + 14. Fixed an issue of `cc.Sequence` action when it's repeated. + 15. Fixed `_anchorPointInPoints` usage issue. + 16. Fixed an issue of `cc.GLProgram` that it doesn't work on some devices which didn't support highp float precision. + 17. Fixed an issue of fade actions that they don't work when duration is 0. + 18. Fixed `onended` callback issue of audio engine on iOS. + 19. Fixed Cocos Builder's parser issue for auto playing animations. + 20. Added a message to `ccs.Armature` that it doesn't support adding widget as its child. + 21. Improved test cases for stability. + +Cocos2d-JS v3.3 Beta @ Jan.24, 2015 + +* Added Cocos Studio v2.x parser and refactored 1.x parser. +* Upgraded new flow layout UI system in web engine. +* Refactored `load` events of texture2d, sprite and so on to be more intuitive. +* Added JavaScript file loader. +* Allowed set texture to null in `cc.Sprite`. +* Added full test cases for Cocos Studio v2.x parser and the new flow layout UI system. +* Upgraded MoonWarriors sample's UI and graphic design. + +* Bug fixes: + 1. Fixed a bug of Cocos2d UI, their focus event has been supported. + 2. Fixed a buf of `ccui.Widget` that its percent position doesn't work. + 3. Fixed a bug of `ccs.Armature` that its position doesn't update in visit on WebGL render mode. + 4. Fixed a bug of `cc.Sprite` that its `setTextureRect` function doesn't work when `setColor` invoked. + 5. Fixed a bug of `cc.PhysicsSprite` that its position is incorrect. + 6. Fixed a bug of `ccs.Bone` that its `setOpacity` and `setColor` doesn't work. + 7. Fixed a bug of `cc.LabelBMFont` that its word wrap doesn't work. + 8. Fixed a bug of `cc.sys` that it gets the incorrect OS type when system is Linux. + 9. Fixed a bug of `cc.audioEngine` that its loading path is incorrect. + 10. Fixed a bug of `ccui.Widget` that it can't touch when it's reused. + 11. Fixed a bug of UI system that the `setNormalizedPosition` doesn't work. + 12. Fixed a bug of `cc.ActionInterval` that its `_times` conflict with `cc.Blink`. + 13. Fixed release texture issue in canvas mode. + 14. Fixed a bug of `ccs.actionManager` that its `getActionByName` doesn't work. + 15. Fixed a bug of `cc.Sprite` that it can't draw without texture on WebGL mode. + 16. Fixed a bug of `cc.audioEngine` that it doesn't work on baidu browser. + 17. Fixed a bug of `cc.EditBox` that its position is incorrect on Canvas Mode and its string value is wrong when PlaceHolder is showing. + 18. Fixed a bug of `cc.loader` that its `loadImg` function doesn't work when image is accessed cross origin. + 19. Fixed a bug of `ccui.TextField` that its `contentSize` is incorrect in text field event. + +Cocos2d-JS v3.2 @ Dec.29, 2014 + +* Replaced `transform` function with `setTransform` function under canvas render mode for better performance. +* Added a timer in `cc.audioEngine` to check audio element loading event, prevent the loading process being stucked when load audio file failed. +* Added some new browser types to `cc.sys`. +* Added some audio resource loading codes to ensure compatibility with Wechat browser. +* Added check for WebAudio support to ensure compatibility. + +* Bug fixes: + 1. Fixed an issue that `cc.InputManager` doesn't trigger touch event on chrome mobile emulator. + 2. Fixed an issue that `cc.game.setFrameRate` doesn't work. + 3. Fixed an issue that `cc.view` can't remove resize event listener. + 4. Fixed an issue that `cc.EventManager` didn't set register flag to false when a listener is removed. + 5. Fixed an issue that `cc.audioEngine` doesn't play some audios on some iOS devices. + 6. Fixed an issue of ccui controls that their `setColor` doesn't work when cascade color is enabled. + 7. Fixed an issue that `ccs.Armature`'s `setColor` doesn't work in canvas render mode. + 8. Fixed an issue that `ccs.Armature` crashes when adding a child to it. + 9. Fixed an issue that `cc.SpriteBatchNode`'s status is incorrect in WebGL render mode. + 10. Fixed an issue of `cc.Layer` that its position is incorrect under bake mode. + 11. Fixed an issue of `ccui.RichText` that its `setContentSize` doesn't work. + 12. Fixed an issue of `cc.LabelTTF` that its `setColor` doesn't work when cascade color is enabled. + 13. Fixed an issue of spine that its skeletons position is incorrect when scaleX equals to -1 and scaleY equals to 1. + 14. Fixed `sp.Skeleton`'s API inconsistence by renaming `boundingBox` to `getBoundingBox`. + 15. Removed all usages of deprecated create functions in the test cases. + +Cocos2d-JS v3.2 RC0 @ Dec.11, 2014 + +* Refactoration of web engine by separating the render logic, the arthictecture level refactoration is now completed and brounght great performance improvement. +* Refactoration of web engine's resolution adaptation and audio engine with polyfilled adaptation logics for different devices and browsers. This ensures better compatibility and better extensibility for future needs. +* Added `setRotation` method to `ccui.ImageView`. +* Added a function that fill sprite with repeated texture in Canvas mode. +* Added `setLineHeight` method to `cc.LabelTTF`. +* Added `dumpAudioInfo` to `cc.audioEngine` for debugging purpose on mobile browser. +* Removed Cocos Studio's Protobuffer support from the framework. +* Added an outline shader sample. + +* Bug fixes: + 1. Fixed an issue of `cc.Sprite` that its rendering is incorrect without texture. + 2. Fixed an issue of `cc.ClippingNode` that its stencil drawing is incorrect on Canvas Mode. + 3. Fixed an issue of `TextFieldReader` that it will throw an error when 'areaWidth' and 'areaHeight' equal to zero. + 4. Fixed an issue of `ccui.CheckBox` that its getSelectedState doesn't return its state. + 5. Fixed an issue of `cc.LabelTTF` that it doesn't update the string when its string become to empty string. + 6. Fixed an issue of `cc.ParticleSystem` that it can't change its texture mode and shape type in Canvas mode. + 7. Fixed an issue of `cc.Layer`'s bake function that its position is incorrect when cc.view's scale isn't 1. + 8. Fixed an issue of `ccs.ArmatureAnimation`'s `setMovementEventCallFunc` and `setFrameEventCallFunc`. + 9. Fixed an issue of `console.log` that it isn't a funtion on IE9. + 10. Fixed an issue of `CSLoader` that it will add duplicate resources to sprite frame cache. + 11. Fixed an issue of `cc.ProgressTimer` that its setColor is not taking effect. + 12. Fixed an issue of `cc.loader` that it will throw an error when loading a remote texture. + 13. Upgrade html5 version chipmunk to the latest release. + +Cocos2d-JS-v3.1 @ Oct.22, 2014 + +* Released Facebook Integration for Cocos2d-JS v1.0, all APIs have been significantly polished and stabilized. Improved test cases for Facebook with more features demonstrated. +* Upgraded Cocos2d-x to v3.3 rc0 +* Supported Cocos Studio v2.0 including Timeline animation support and proto buffers format support for both web engine and JSB engine. +* Refactored load event of texture, sprite frame and sprite for better maintainability. +* Refactored `cc.rendererCanvas` for improving performance. +* Moved the `CC_Texture0` definition of fragment shader to cc.GLProgram to ensure compatibility with JSB. +* Added normalized position functions to cc.Node. +* Refactored the constructor of Cocos Studio's classes and deprecated all create functions. +* Refactored Cocos Studio reader for better maintainability. +* Improved Facebook SDK. +* Modified `cc.ProgressTo`'s behavior, its progression didn't reset to zero when the progression is 100. +* Changed `ccui.Widget`'s default anchor point to (0, 0) in widget reader. +* Removed all deprecated create function usage in engine and in the test cases. + +* Bug fixes: + 1. Fixed an issue of `cc.UILayout` that its scissor mode didn't work. + 2. Fixed an issue of `ccui.TextBMFont` that its 'string' property setting was incorrect. + 3. Fixed an issue of `cc.DrawNode` that its element's position was incorrect in Canvas mode. + 4. Fixed an issue of `cc.Layer` that its bake function didn't work in new renderer. + 5. Fixed an issue of `cc.Scale9Sprite` that its cached canvas size was incorrect. + 6. Fixed an issue of `cc.Director` that its position was incorrect when calling `setProjection` in new renderer. + 7. Fixed an issue of `cc.view` that the reinitialization logic of frame size was incorrect. + 8. Fixed incorrect usage of `cc.progressTo` in progress action test. + 9. Fixed an issue of CocosNodeTest for the new renderer. + 10. Fixed minor issues in test cases. + +* Known Issues: + 1. `jsb.AssetsManager` doesn't work on windows due to a bug in libcurl + +Cocos2d-JS v3.1 beta @ Oct.13, 2014 + +* Refactoration of the web engine with new renderer on the architecture level, optimization is under going. +* Released Facebook SDK for Cocos2d-JS beta2, its API have been significantly improved and stablized. +* Upgraded MoonWarriors sample with new set of graphical assets. +* Automatically enabled WebGL on iOS 8 safari. +* Upgraded chipmunk.js to the newest version. +* Supported setting color of shadow for `cc.LabelTTF`. +* Added `getTitleRenderer` function to ccui.Button. +* Supported Coco Studio timeline animation. +* Set the default value of LabelAtlas's `cascadeOpacityEnabled` and `cascadeColorEnabled` to true. +* Added a listener of texture to `cc.Sprite#setTexture` when the texture hasn't loaded. +* Activated `cc.pool` for all kind of objects. +* Added query test for chipmunk and added necessary JavaScript bindings. + +* Bugs fix: + 1. Fixed a bug of `cc.ComponentContainer` that a 'if' statement behavior is incorrect. + 2. Fixed a bug of `cc.Scale9Sprite` that the behavior of Canvas and WebGL is different. + 3. Fixed a bug of `cc.EventListener` that its pause state should set to true. + 4. Fixed a bug of `cc.ParticleSystem` that it should apply canvas scaling on canvas rendering mode. + 5. Fixed a bug of CCBoot.js that `cc.loader` should add a condition to check whether `crossOrign` property is undefined on IE9 and IE10. + 6. Fixed a bug of `ccui.Widget` that its `setPosition` function's behavior is incorrect. + 7. Fixed a bug of `ccui.LoadingBar` that its `barRenderer` should add to protected children array. + 8. Fixed a bug of `cc.Texture2D` that its `TEXTURE_MAG_FILTER` should set to LINEAR. + 9. Fixed a bug of `cc.TMXMapInfo` that its doesn't parse `rotation` property. + +Cocos2d-JS-v3.0 Final @ Sep.10, 2014 + +* Facebook SDK Beta2: Added `appRequest` API. +* Facebook SDK Beta2: Added permission request in `login` API, removed `requestPermission` API. +* Facebook SDK Beta2: Renamed `request` API to `api`. +* Facebook SDK Beta2: Renamed `publishInstall` API to `activateApp`. +* Added getter and setter function for browser's density dpi: `cc.view.setTargetDensityDPI`, `cc.view.getTargetDensityDPI`. +* Added some type check functions. +* Added audio support for wechat browser. +* Added setPlaceHolderColor and setTextColor to ccui.TextField. +* Added API reference for Cocos Studio extension. + +* Bugs fix: + 1. Fixed an issue of `cc.Menu` that its item's touch priority is different than cc.eventManager. + 2. Fixed an issue of `cc.view` that its NO_BORDER mode doesn't work correctly. + 3. Fixed an issue of `cc.LabelBMFont` that its content size is different than JSB. + 4. Fixed an issue of `cc.LabelBMFont` that its `setColor` is invalid on some mobile devices. + 5. Fixed an issue of `cc.PageView` that it can't receive TOUCH_CANCEL event. + 6. Fixed an issue of `cc.loader` that it can't load cross origin textures. + 7. Fixed an issue that Facebook SDK Web's `appRequest` wraps info parameter incorrectly. + 8. Fixed an issue of ccui widgets' `addEventListener` that it doesn't accept function's target as parameter. + +Cocos2d-JS-v3.0 RC3 @ Aug.29, 2014 + +* Facebook SDK Beta: Unified the callback parameters for different platform. +* Facebook SDK Beta: Added payment API on Web platform. +* Facebook SDK Beta: Supported app request and share open graph API on Web platform. +* Facebook SDK Beta: Remove plugin configuration for Facebook SDK to simplify the usage. +* Facebook SDK Beta: Added test case for new features and improve all test cases. +* Cocos Console: Improved web compile with `--advanced` tag. +* Improved Cocos2d-JS inline docs to provide a better API reference document. +* Refactored cc.game for maintainability. +* Refactored cc.async to simplify and improve the usage. +* Added `cc.formatStr` for string formatting, for example: `cc.formatStr("a: %d, b: %b", a, b)`. +* Refactored cc.log to support formatted string. +* Refactored cc.pool's `hasObj` to `hasObject` and `removeObj` to `removeObject`. +* Added some state check to cc.audioEngine. +* Refactored sprite's blend function to support more features on Canvas. +* Refactored `cc.textureCache.textureForKey` to `cc.textureCache.getTextureForKey`, `cc.TMXTilemap#propertiesForGID` to `cc.TMXTilemap#getPropertiesForGID` to follow the standard API naming style. +* Detected mouse event on touch screen tablets. +* Support new construction for cc.PhysicsDebugNode and deprecated `cc.PhysicsDebugNode.create` +* Made cc.Texture2D's setTexParameters supports two types of parameters. +* Added test case for remote image loading. + +* Bugs fix: + 1. Fixed an issue of tilemap that it can't runAction in canvas render mode. + 2. Fixed an issue of cc.eventManager that its removeListeners' codes are unreachable. + 3. Fixed an issue of cc.EditBox that its position is incorrect. + 4. Fixed an issue of cc.WebAudio that its stopped state is incorrect. + 5. Fixed an issue of cc.audioEngine that it doesn't work on firefox after it compiled with advanced mode. + 6. Fixed an issue of ccs.Bone that it doesn't update color and opacity correctly. + 7. Fixed an issue of ccs.Armature that its setShaderProgram doesn't work. + 8. Fixed cc.Sprite and cc.Scale9Sprite's issue so that their texture loads incorrectly. + 9. Fixed an issue of ccui.LoadingBar that its setPercent is invalid. + 10. Fixed an issue of Armature reader that it can't parse isTween property. + 11. Fixed an issue of ccui.PageView that its getTouchBeganPosition returns incorrect value. + 12. Fixed an issue of ccui.ImageView that its setColor doesn't work. + 13. Fixed an issue of cc.RenderTexture that it doesn't support parameter depthStencilFormat. + 14. Fixed an issue of ccs.ArmatureAnimation.setSpeedScale. + 15. Fixed an issue of cc.Scale9Sprite that it has a line on iOS device. + 16. Fixed CCProgressTimer draw on canvas with colorized sprite + 17. Fixed an issue of cc.game that its frameRate setter is invalid. + 18. Fixed an issue of cc.loader that its callback state is incorrect. + +Cocos2d-html5-v3.0 RC2 @ Aug.8, 2014 + +* Refactored Cocos UI for more stable and friendly user experience. +* Upgraded Cocostudio reader to support version 1.2 - 1.5.x. +* Upgraded Cocostudio Armature animation from Cocos2d-x v3.2. +* Added back 2.x createWithXXX functions and deprecate all create/createWithXXX functions. +* Merged cc.NodeRGBA and cc.LayerRGBA to cc.Node. +* Fixed ctor functions bugs to support new construction. +* Refactored cc.Sprite's setColor to improve its performance. +* Renamed CCAffineTransform.js's functions to lowercase started functions. +* Upgraded cc.Scale9Sprite from Cocos2d-x 3.2. +* Improved cc.LabelTTF's line break algorithms to support multi-languages. +* Made cc.RenderTexture's beginWithClear accept color value from 0-255. +* Improved implementation of all Actions lower case alias creation functions. +* Added lower case creation functions for 3d actions and progress actions. +* Added cc.sys.platform API for detecting platform. +* Upgraded HelloWorld project with v3.0 APIs. + +* Bugs fix: + 1. Fixed a bug of cc.WebAudio that sourceNode's playbackState is invalid on some browsers. + 2. Fixed a bug of cc.MenuItemToggle that callback is not correctly initialized when using new construction. + 3. Fixed a bug of ccui.Layout that its clipping area is incorrect. + 4. Fixed a bug of requestAnimFrame that it doesn't work after re-focus WeChat browser on Samsung mobile. + 5. Fixed a bug of CCBoot.js that bind function is undefined in Safari for iOS 5.1. + 6. Fixed a bug in cc.layer's bake function that its position is incorrect when cc.view is scaled. + 7. Fixed a bug of cc.LayerMultiplex. + 8. Fixed a bug of cc.TMXLayer that it can't display all map image when its type is hexagonal. + 9. Fixed a transform error in ccs.TransformHelp. + 10. Fixed a bug of cc.ControlSwitch. + 11. Fixed image format constant inconsistence. + 12. Fixed a bug of ccui.Widget that it is invisible after popScene. + 13. Correct behavior of cc.TransitionSlideInB and cc.TransitionSlideInT. + 14. Fixed bugs of ccui.Widget and ccui.Text's clone functions. + + +Cocos2d-html5-v3.0 RC0 @ July.3, 2014 +* Added Facebook SDK plugin into Pluginx extension. +* Refactoration of gui system `ccui` for better performance, usage and maintainbility. +* Added `bake` function to `cc.Layer` to support layer baking. +* Added object pool extension: `cc.pool`. +* Added new easing functions: bezier action, quadratic actions, quartic actions, quintic actions, circle actions, cubic actions. +* Made `cc.loader` continue the counter process even if a resource failed to be loaded. +* Supported multiple property objects in `cc.Class.extend` function. +* Refactored `ccui.Widget`'s `getLeftInParent`, `getBottomInParent`, `getRightInParent`, `getTopInParent` to `getLeftBoundary`, `getBottomBoundary`, `getRightBoundary`, `getTopBoundary`. +* Refactored `cc.FadeIn.create(duration, toOpacity)` to `cc.FadeIn.create(duration)`. +* Refactroed all string access functions in `ccui` extension to `setString` and `getString`. +* Added `getContentSize` and `setContentSize` in `ccui` extension. +* Changed the default alpha value of `cc.Color` from `undefined` to 255. +* Made `cc.log` support formatted string. + +* Bugs fix: + 1. Fix bugs on creating sequence objcet or spawn object using new method. + 2. Fix a bug that `ccui.LoadingBar`'s `setPercent` function will crash when its texture is in a plist file and scale9Enabled is true. + 3. Fixed a bug of `cc.audioEngine` that it crashs when audio isn't correctly loaded and its duration is infinity. + 4. Correction of the calculation of `cc.visibleRect`. + 5. Fix `cc.Skin`'s bounding box calculation for canvas rendering. + 6. Fix an issue that `cc.TextureCache` doesn't handle loaded texture in some case. + 7. Fix an issue that texture rect could be zero sized in `initWithFile` function of `cc.Sprite`. + 8. Fix a bug on inverted ClippingNode with DrawNode as stencil in Canvas render mode. + 9. Fix a bug that `cc.SpriteFrame` didn't support initialization with texture name parameter. + 10. Fix a bug on `ccs.ArmatureAnimation`'s loop parameter. + 11. Fix a bug that `cc.JumpTo`'s `_delta` position calculation is incorrect. + 12. Fix a bug of `cc._audioLoader` that it doesn't work when it failed to load an audio file. + +Cocos2d-html5-v3.0 beta @ May.23, 2014 + +* Refactored actions to make it more friendly and easy-to-use. +* Integrated Spine skeleton animation feature. +* Renamed constants of ProgressTimer, Scale9Sprite, TMXLayerInfo, Node, ParticleSystem for maintainability. +* Modified mouseMove event behavior of cc.inputManager to compatible with Cocos2d-x +* Modified cc.game.run to receive a canvas id as parameter. +* Added local audio file playing from 'file://' origin. +* Added local images file displaying from 'file://' origin. +* Refactored cc.TMXLayer's setTileAt etc functions to support point or x,y as their parameters. +* Added a check to cc.Sprite and cc.SpriteFrame to avoid its texture rect out of bounds. +* Added a check to cc.SpriteFrame to avoid cc.loader release invalid sprite frame file. +* Made cc.Touch return copies of point. +* Made the default of cc.Color alpha value is 255 to avoid cc.Sprite's setColor is invalid. +* Optimized cc.Node.sortAllChildren for better performance. +* Added warning of cc.Texture2D if it has an invalid texture. + +* Bugs fix: + 1. Fixed a bug of cc.winSize that it returns incorrect value when using setDesignResolution. + 2. Added a check to cc._setup to avoid double invocation. + 3. Fixed a bug of cc.TMXMapInfo that its tile's property id is incorrect. + 4. Fixed a bug of cc.Scale9Sprite that its CascadeColor and CascadeOpacity are invalid. + 5. Fixed a bug of ccs.UILoadingBar which its barRendererScaleChangedWithSize is incorrect. + 6. Added some forgotten files to build.xml for minimize core. + 7. Corrected a mistake of renderMode default value in CCBoot.js. + 8. Fixed a bug of ccui.Layout's draw function that its scaleX, scaleY value is incorrect. + 9. Fixed a bug of cc.Audio's stopMusic function. + 10. Fixed a bug of TextureCache that it can't remove image's event handler. + 11. Fixed ClippingNode's DrawNode stencil bug on Canvas. + 12. Fixed a typo 'cc.radiansToDegress' function to 'cc.radiansToDegrees'. + 13. Fixed a bug of ccui.ImageView that its setSize is invalid when the picture without pre-load. + 14. Fixed a bug of cc.ParticleSystem that it throws a error when create from CocosBuilder. + 15. Fixed a bug of cc.LabelAtlas that it can't display its children. + 16. Fixed a bug of cc.fontLoader that it can't load custom font. + 17. Fixed a bug of ccui.Widget that its setOpacity is invalid. + 18. Fixed a bug of cc.Node that it transform value is incorrect when a node skew to a special value. + +Cocos2d-html5-v3.0 alpha2 @ April.14, 2014 + +* Minimized the size of core from 254k to 113k after google closure advanced compiling +* Made cc.DrawNode support some DrawingPrimitive's drawing function on WebGL mode +* Added undefined checking in cc.loader for better performance. +* cc.Sprite supports creating a sprite through external URL. +* Added the warning information to notice developers that their project.json cannot be loaded or parsed. +* Added retina display support to cc.Editbox. +* cc.Node's pauseSchedulerAndActions and resumeSchedulerAndActions are deprecated, please use pause and resume instead. +* Added render mode checking to 3D action classes. +* Added SocketIO +* Sync cc.eventManager to the latest version of Cocos2d-x v3.0 Stable. +* ccui.Layout's doLayout function has been set to private function "_doLayout" +* Made actions extendable directly via ctor +* Added null callback check in cc.textureCache.addImage +* Fixed the API inconsistence of ccs.ArmatureAnimation.play +* Fixed compatibility and performance for ctor +* Renamed all Uppercase functions to lowercase in CCMacro +* Added necessary GL constants in H5 +* Fixed CONSTANTS inconsistence between h5 and JSB + +* Bugs fix: + 1. Fixed ccs.comAttribute API incompatible issue + 2. Fixed a bug of Cocostudio's data reader that getting isTween value is incorrect when the attribute value is false. + 3. Fixed a bug of Sprite that it doesn't work when its texture doesn't preload and its parent is a SpriteBatchNode + 4. Fixed a bug in CCBoot.js that console.error is invalid on firefox. + 5. Fixed some comment errors of framework. + 6. Fixed a bug of cc.LabelBMFont that it's multiline works incorrectly. + 7. Fixed a bug that Touches event doesn't work in release mode on IE browser. + 8. Fixed a bug that cc.winSize has not been reset after cc.view.setDesignResolutionSize. + 9. Fixed typo in ccui.Widget.TOUCH_BEGAN + 10. Fixed a bug of cc.MenuItemSprite.create that + 11. Fixed a bug of cc.loader that it need to set value before call the callback. + 12. Fixed a bug of cc.log that it doesn't work in IE9 + 13. Fixed IE incompatible issue with __lookupGetter__ + 14. Fixed a mistake of cc.Node that it return a reference of _position in getPosition + 15. Fixed a bug of cc.ClippingNode that its _super is undefined + 16. Fixed a bug of inputManager's touch event in IE browser + +* Known Issues: + 1. EventListener is not extendable. + + Cocos2d-html5-v3.0 alpha @ March.15, 2014 * Refactor some properties of all rendering classes with getter setter for providing javascript user friendly APIs. diff --git a/README.mdown b/README.mdown index 503e6af636..20868869a1 100644 --- a/README.mdown +++ b/README.mdown @@ -3,7 +3,9 @@ Cocos2d-html5 [Cocos2d-html5][1] is a cross-platform 2D game engine written in Javascript, based on [Cocos2d-X][2] and licensed under MIT. It incorporates the same high level api as “Cocos2d JS-binding engine” and compatible with Cocos2d-X. -It currently supports canvas and will support WebGL in the future. +It currently supports canvas and WebGL renderer. + +#### Cocos2d-html5 has evolved to Cocos Creator, new generation of Cocos game engine with a full featured editor and content creation friendly workflow. The latest repository is maintained in here [Engine of Cocos Creator][9]. Cross Platform ------------- @@ -14,18 +16,7 @@ Cross Platform Documentation ------------------ * Website: [www.cocos2d-x.org][3] - -Running the tests ------------------- - -```shell -$ git clone git://github.com/cocos2d/cocos2d-html5.git -$ cd cocos2d-html5 -$ git submodule update --init -$ python -m SimpleHTTPServer -``` -... and then open a browser and go to `http://localhost:8000/tests` - + * Cocos Creator download: [Cocos Creator][4] Contact us ------------------ @@ -36,7 +27,9 @@ Contact us [1]: http://www.cocos2d-x.org "Cocos2d-html5" [2]: http://www.cocos2d-x.org "Cocos2d-X" [3]: http://www.cocos2d-x.org "www.cocos2d-x.org" -[4]: http://www.cocos2d-x.org/embedded/cocos2d-x/classes.html "API References" +[4]: http://www.cocos2d-x.org/download [5]: http://forum.cocos2d-x.org "http://forum.cocos2d-x.org" [6]: http://www.twitter.com/cocos2dhtml5 "http://www.twitter.com/cocos2dhtml5" [7]: http://t.sina.com.cn/cocos2dhtml5 "http://t.sina.com.cn/cocos2dhtml5" +[8]: http://bower.io "http://bower.io" +[9]: https://github.com/cocos-creator/engine diff --git a/bower.json b/bower.json new file mode 100644 index 0000000000..5493b6e512 --- /dev/null +++ b/bower.json @@ -0,0 +1,37 @@ +{ + "name": "cocos2d-html5", + "version": "3.4", + "homepage": "http://www.cocos2d-x.org", + "authors": [ + "AUTHORS.txt" + ], + "description": "Cocos2d-html5 is a cross-platform 2D game engine written in Javascript, based on Cocos2d-X and licensed under MIT. It incorporates the same high level api as “Cocos2d JS-binding engine” and compatible with Cocos2d-X. It currently supports canvas and WebGL renderering.", + "main": "README.mdown", + "keywords": [ + "cocos2d-x", + "cocos2d", + "game", + "engine", + "opengl", + "cross", + "multi", + "platform", + "iphone", + "ipad", + "android", + "windows", + "metro", + "bada", + "marmalade", + "playbook" + ], + "license": "MIT", + "private": false, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} \ No newline at end of file diff --git a/cocos2d/actions/CCAction.js b/cocos2d/actions/CCAction.js index ade6d8d428..cce37bbebd 100644 --- a/cocos2d/actions/CCAction.js +++ b/cocos2d/actions/CCAction.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,12 +27,14 @@ /** Default Action tag * @constant * @type {Number} + * @default */ cc.ACTION_TAG_INVALID = -1; /** * Base class for cc.Action objects. * @class + * * @extends cc.Class * * @property {cc.Node} target - The target will be set with the 'startWithTarget' method. When the 'stop' method is called, target will be set to nil. @@ -46,6 +48,10 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ tag:cc.ACTION_TAG_INVALID, //**************Public Functions*********** + + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + */ ctor:function () { this.originalTarget = null; this.target = null; @@ -54,15 +60,20 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ /** * to copy object with deep copy. - * @deprecated - * @return {object} + * + * @deprecated since v3.0 please use .clone + * + * @return {cc.Action} */ copy:function () { + cc.log("copy is deprecated. Please use clone instead."); return this.clone(); }, /** - * returns a clone of action + * to copy object with deep copy. + * returns a clone of action. + * * @return {cc.Action} */ clone:function () { @@ -74,7 +85,8 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ }, /** - * return true if the action has finished + * return true if the action has finished. + * * @return {Boolean} */ isDone:function () { @@ -83,6 +95,7 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ /** * called before the action start. It will also set the target. + * * @param {cc.Node} target */ startWithTarget:function (target) { @@ -91,35 +104,34 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ }, /** - * called after the action has finished. It will set the 'target' to nil. + * called after the action has finished. It will set the 'target' to nil.
* IMPORTANT: You should never call "action stop" manually. Instead, use: "target.stopAction(action);" */ stop:function () { this.target = null; }, - /** called every frame with it's delta time. DON'T override unless you know what you are doing. + + /** + * called every frame with it's delta time.
+ * DON'T override unless you know what you are doing. * * @param {Number} dt */ - step:function (dt) { cc.log("[Action step]. override me"); }, /** -

called once per frame. time a value between 0 and 1

- -

For example:
- - 0 means that the action just started
- - 0.5 means that the action is in the middle
- - 1 means that the action is over

- * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { cc.log("[Action update]. override me"); }, /** + * get the target. * * @return {cc.Node} */ @@ -127,7 +139,8 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ return this.target; }, - /** The action will modify the target properties. + /** + * The action will modify the target properties. * * @param {cc.Node} target */ @@ -136,6 +149,7 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ }, /** + * get the original target. * * @return {cc.Node} */ @@ -143,7 +157,8 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ return this.originalTarget; }, - /** Set the original target, since target can be nil.
+ /** + * Set the original target, since target can be nil.
* Is the target that were used to run the action.
* Unless you are doing something complex, like cc.ActionManager, you should NOT call this method.
* The target is 'assigned', it is not 'retained'.
@@ -154,7 +169,7 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ }, /** - * + * get tag number. * @return {Number} */ getTag:function () { @@ -162,39 +177,62 @@ cc.Action = cc.Class.extend(/** @lends cc.Action# */{ }, /** - * + * set tag number. * @param {Number} tag */ setTag:function (tag) { this.tag = tag; }, + /** - * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB, - * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. - * This is a hack, and should be removed once JSB fixes the retain/release bug + * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
+ * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
+ * This is a hack, and should be removed once JSB fixes the retain/release bug. */ retain:function () { }, + + /** + * Currently JavaScript Bindigns (JSB), in some cases, needs to use retain and release. This is a bug in JSB,
+ * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB.
+ * This is a hack, and should be removed once JSB fixes the retain/release bug. + */ release:function () { } }); -/** Allocates and initializes the action - * @returns {cc.Action} + +/** + * Allocates and initializes the action. + * + * @function cc.action + * @static + * @return {cc.Action} + * * @example - * // example - * var action = cc.Action.create(); + * // return {cc.Action} + * var action = cc.action(); */ -cc.Action.create = function () { +cc.action = function () { return new cc.Action(); }; +/** + * Please use cc.action instead.
+ * Allocates and initializes the action. + * + * @deprecated since v3.0 please use cc.action() instead. + * @static + * @returns {cc.Action} + */ +cc.Action.create = cc.action; + /** - *

Base class actions that do have a finite time duration.
+ * Base class actions that do have a finite time duration.
* Possible actions:
- * - An action with a duration of 0 seconds
- * - An action with a duration of 35.5 seconds

- + * - An action with a duration of 0 seconds.
+ * - An action with a duration of 35.5 seconds. + * * Infinite time actions are valid * @class * @extends cc.Action @@ -203,20 +241,25 @@ cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ //! duration in seconds _duration:0, + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + */ ctor:function () { cc.Action.prototype.ctor.call(this); this._duration = 0; }, - /** get duration in seconds of the action + /** + * get duration of the action. (seconds) * * @return {Number} */ getDuration:function () { - return this._duration; + return this._duration * (this._timesForRepeat || 1); }, - /** set duration in seconds of the action + /** + * set duration of the action. (seconds) * * @param {Number} duration */ @@ -224,7 +267,12 @@ cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ this._duration = duration; }, - /** returns a reversed action + /** + * Returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten * * @return {Null} */ @@ -234,7 +282,10 @@ cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ }, /** + * to copy object with deep copy. + * returns a clone of action. * + * @return {cc.FiniteTimeAction} */ clone:function () { return new cc.FiniteTimeAction(); @@ -242,19 +293,22 @@ cc.FiniteTimeAction = cc.Action.extend(/** @lends cc.FiniteTimeAction# */{ }); /** - * Changes the speed of an action, making it take longer (speed>1) - * or less (speed<1) time.
+ * Changes the speed of an action, making it take longer (speed > 1) + * or less (speed < 1) time.
* Useful to simulate 'slow motion' or 'fast forward' effect. + * * @warning This action can't be Sequenceable because it is not an cc.IntervalAction * @class * @extends cc.Action + * @param {cc.ActionInterval} action + * @param {Number} speed */ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ _speed:0.0, _innerAction:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {cc.ActionInterval} action * @param {Number} speed */ @@ -267,20 +321,27 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** + * Gets the current running speed.
+ * Will get a percentage number, compared to the original speed. + * * @return {Number} */ getSpeed:function () { return this._speed; }, - /** alter the speed of the inner function in runtime + /** + * alter the speed of the inner function in runtime. + * * @param {Number} speed */ setSpeed:function (speed) { this._speed = speed; }, - /** initializes the action + /** + * initializes the action. + * * @param {cc.ActionInterval} action * @param {Number} speed * @return {Boolean} @@ -295,7 +356,9 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** - * returns a clone of action + * to copy object with deep copy. + * returns a clone of action. + * * @returns {cc.Speed} */ clone:function () { @@ -305,6 +368,8 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** + * called before the action start. It will also set the target. + * * @param {cc.Node} target */ startWithTarget:function (target) { @@ -313,7 +378,7 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** - * Stop the action + * Stop the action. */ stop:function () { this._innerAction.stop(); @@ -321,6 +386,9 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** + * called every frame with it's delta time.
+ * DON'T override unless you know what you are doing. + * * @param {Number} dt */ step:function (dt) { @@ -328,6 +396,8 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** + * return true if the action has finished. + * * @return {Boolean} */ isDone:function () { @@ -335,23 +405,30 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ }, /** - * @return {cc.ActionInterval} + * returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * + * @return {cc.Speed} */ reverse:function () { - return (cc.Speed.create(this._innerAction.reverse(), this._speed)); + return new cc.Speed(this._innerAction.reverse(), this._speed); }, /** - * + * Set inner Action. * @param {cc.ActionInterval} action */ setInnerAction:function (action) { - if (this._innerAction != action) { + if (this._innerAction !== action) { this._innerAction = action; } }, /** + * Get inner Action. * * @return {cc.ActionInterval} */ @@ -359,24 +436,57 @@ cc.Speed = cc.Action.extend(/** @lends cc.Speed# */{ return this._innerAction; } }); -/** creates the action + +/** + * creates the speed action. * + * @function cc.speed * @param {cc.ActionInterval} action * @param {Number} speed * @return {cc.Speed} */ -cc.Speed.create = function (action, speed) { +cc.speed = function (action, speed) { return new cc.Speed(action, speed); }; /** - * cc.Follow is an action that "follows" a node. + * Please use cc.speed instead. + * creates the action. + * + * @param {cc.ActionInterval} action + * @param {Number} speed + * @return {cc.Speed} + * @static + * @deprecated since v3.0 please use cc.speed() instead. + */ +cc.Speed.create = cc.speed; +/** + * cc.Follow is an action that "follows" a node. + * * @example * //example * //Instead of using cc.Camera as a "follower", use this action instead. - * layer.runAction(cc.Follow.actionWithTarget(hero)); - + * layer.runAction(cc.follow(hero)); + * + * @property {Number} leftBoundary - world leftBoundary. + * @property {Number} rightBoundary - world rightBoundary. + * @property {Number} topBoundary - world topBoundary. + * @property {Number} bottomBoundary - world bottomBoundary. + * + * @param {cc.Node} followedNode + * @param {cc.Rect} rect + * @example + * // creates the action with a set boundary + * var sprite = new cc.Sprite("spriteFileName"); + * var followAction = new cc.Follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); + * this.runAction(followAction); + * + * // creates the action with no boundary set + * var sprite = new cc.Sprite("spriteFileName"); + * var followAction = new cc.Follow(sprite); + * this.runAction(followAction); + * * @class * @extends cc.Action */ @@ -390,43 +500,19 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ // fast access to the screen dimensions _halfScreenSize:null, _fullScreenSize:null, + _worldRect:null, - /** world leftBoundary - * @Type {Number} - */ leftBoundary:0.0, - /** world rightBoundary - * @Type Number - */ rightBoundary:0.0, - /** world topBoundary - * @Type Number - */ topBoundary:0.0, - /** world bottomBoundary - * @Type {Number} - */ bottomBoundary:0.0, - _worldRect:null, /** - * creates the action with a set boundary
- * creates the action with no boundary set - * - * @constructor - * @param {cc.Node} followedNode - * @param {cc.Rect} rect - * @example - * // example - * // creates the action with a set boundary - * var sprite = new cc.Sprite("spriteFileName"); - * var followAction = new cc.Follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); - * this.runAction(followAction); - * - * // creates the action with no boundary set - * var sprite = new cc.Sprite("spriteFileName"); - * var followAction = new cc.Follow(sprite); - * this.runAction(followAction); + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates the action with a set boundary.
+ * creates the action with no boundary set. + * @param {cc.Node} followedNode + * @param {cc.Rect} rect */ ctor:function (followedNode, rect) { cc.Action.prototype.ctor.call(this); @@ -448,6 +534,12 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ : this.initWithTarget(followedNode); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.Follow} + */ clone:function () { var action = new cc.Follow(); var locRect = this._worldRect; @@ -457,21 +549,26 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ }, /** + * Get whether camera should be limited to certain area. + * * @return {Boolean} */ isBoundarySet:function () { return this._boundarySet; }, - /** alter behavior - turn on/off boundary + /** + * alter behavior - turn on/off boundary. + * * @param {Boolean} value */ setBoudarySet:function (value) { this._boundarySet = value; }, - /** initializes the action - * initializes the action with a set boundary + /** + * initializes the action with a set boundary. + * * @param {cc.Node} followedNode * @param {cc.Rect} [rect=] * @return {Boolean} @@ -480,42 +577,46 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ if(!followedNode) throw "cc.Follow.initWithAction(): followedNode must be non nil"; + var _this = this; rect = rect || cc.rect(0, 0, 0, 0); - this._followedNode = followedNode; - this._worldRect = rect; + _this._followedNode = followedNode; + _this._worldRect = rect; - this._boundarySet = !cc._rectEqualToZero(rect); + _this._boundarySet = !cc._rectEqualToZero(rect); - this._boundaryFullyCovered = false; + _this._boundaryFullyCovered = false; var winSize = cc.director.getWinSize(); - this._fullScreenSize = cc.p(winSize.width, winSize.height); - this._halfScreenSize = cc.pMult(this._fullScreenSize, 0.5); + _this._fullScreenSize = cc.p(winSize.width, winSize.height); + _this._halfScreenSize = cc.pMult(_this._fullScreenSize, 0.5); - if (this._boundarySet) { - this.leftBoundary = -((rect.x + rect.width) - this._fullScreenSize.x); - this.rightBoundary = -rect.x; - this.topBoundary = -rect.y; - this.bottomBoundary = -((rect.y + rect.height) - this._fullScreenSize.y); + if (_this._boundarySet) { + _this.leftBoundary = -((rect.x + rect.width) - _this._fullScreenSize.x); + _this.rightBoundary = -rect.x; + _this.topBoundary = -rect.y; + _this.bottomBoundary = -((rect.y + rect.height) - _this._fullScreenSize.y); - if (this.rightBoundary < this.leftBoundary) { + if (_this.rightBoundary < _this.leftBoundary) { // screen width is larger than world's boundary width //set both in the middle of the world - this.rightBoundary = this.leftBoundary = (this.leftBoundary + this.rightBoundary) / 2; + _this.rightBoundary = _this.leftBoundary = (_this.leftBoundary + _this.rightBoundary) / 2; } - if (this.topBoundary < this.bottomBoundary) { + if (_this.topBoundary < _this.bottomBoundary) { // screen width is larger than world's boundary width //set both in the middle of the world - this.topBoundary = this.bottomBoundary = (this.topBoundary + this.bottomBoundary) / 2; + _this.topBoundary = _this.bottomBoundary = (_this.topBoundary + _this.bottomBoundary) / 2; } - if ((this.topBoundary == this.bottomBoundary) && (this.leftBoundary == this.rightBoundary)) - this._boundaryFullyCovered = true; + if ((_this.topBoundary === _this.bottomBoundary) && (_this.leftBoundary === _this.rightBoundary)) + _this._boundaryFullyCovered = true; } return true; }, /** + * called every frame with it's delta time.
+ * DON'T override unless you know what you are doing. + * * @param {Number} dt */ step:function (dt) { @@ -524,6 +625,9 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ tempPosX = this._halfScreenSize.x - tempPosX; tempPosY = this._halfScreenSize.y - tempPosY; + //TODO Temporary treatment - The dirtyFlag symbol error + this.target._renderCmd._dirtyFlag = 0; + if (this._boundarySet) { // whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased if (this._boundaryFullyCovered) @@ -536,6 +640,8 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ }, /** + * Return true if the action has finished. + * * @return {Boolean} */ isDone:function () { @@ -550,23 +656,39 @@ cc.Follow = cc.Action.extend(/** @lends cc.Follow# */{ cc.Action.prototype.stop.call(this); } }); -/** creates the action with a set boundary
- * creates the action with no boundary set + +/** + * creates the action with a set boundary.
+ * creates the action with no boundary set. + * + * @function * @param {cc.Node} followedNode * @param {cc.Rect} rect * @return {cc.Follow|Null} returns the cc.Follow object on success * @example * // example * // creates the action with a set boundary - * var sprite = cc.Sprite.create("spriteFileName"); - * var followAction = cc.Follow.create(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); + * var sprite = new cc.Sprite("spriteFileName"); + * var followAction = cc.follow(sprite, cc.rect(0, 0, s.width * 2 - 100, s.height)); * this.runAction(followAction); * * // creates the action with no boundary set - * var sprite = cc.Sprite.create("spriteFileName"); - * var followAction = cc.Follow.create(sprite); + * var sprite = new cc.Sprite("spriteFileName"); + * var followAction = cc.follow(sprite); * this.runAction(followAction); */ -cc.Follow.create = function (followedNode, rect) { +cc.follow = function (followedNode, rect) { return new cc.Follow(followedNode, rect); }; + +/** + * Please use cc.follow instead. + * creates the action with a set boundary.
+ * creates the action with no boundary set. + * @param {cc.Node} followedNode + * @param {cc.Rect} rect + * @return {cc.Follow|Null} returns the cc.Follow object on success + * @static + * @deprecated since v3.0 please cc.follow() instead. + */ +cc.Follow.create = cc.follow; diff --git a/cocos2d/actions/CCActionCamera.js b/cocos2d/actions/CCActionCamera.js index f055f6ca8e..0ff5786b71 100644 --- a/cocos2d/actions/CCActionCamera.js +++ b/cocos2d/actions/CCActionCamera.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -40,6 +40,9 @@ cc.ActionCamera = cc.ActionInterval.extend(/** @lends cc.ActionCamera# */{ _upYOrig:0, _upZOrig:0, + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + */ ctor:function(){ var _t = this; cc.ActionInterval.prototype.ctor.call(_t); @@ -55,7 +58,11 @@ cc.ActionCamera = cc.ActionInterval.extend(/** @lends cc.ActionCamera# */{ _t._upZOrig=0; }, - + /** + * called before the action start. It will also set the target. + * + * @param {cc.Node} target + */ startWithTarget:function (target) { var _t = this; cc.ActionInterval.prototype.startWithTarget.call(_t, target); @@ -78,20 +85,39 @@ cc.ActionCamera = cc.ActionInterval.extend(/** @lends cc.ActionCamera# */{ }, /** + * to copy object with deep copy. * returns a new clone of the action + * * @returns {cc.ActionCamera} */ clone:function(){ return new cc.ActionCamera(); }, + /** + * returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * + */ reverse:function () { - return cc.ReverseTime.create(this); + return new cc.ReverseTime(this); } }); /** - * Orbits the camera around the center of the screen using spherical coordinates + * Orbits the camera around the center of the screen using spherical coordinates. + * + * @param {Number} t time + * @param {Number} radius + * @param {Number} deltaRadius + * @param {Number} angleZ + * @param {Number} deltaAngleZ + * @param {Number} angleX + * @param {Number} deltaAngleX + * * @class * @extends cc.ActionCamera */ @@ -108,8 +134,8 @@ cc.OrbitCamera = cc.ActionCamera.extend(/** @lends cc.OrbitCamera# */{ _radDeltaX: 0.0, /** - * creates a cc.OrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates a cc.OrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX. * @param {Number} t time * @param {Number} radius * @param {Number} deltaRadius @@ -180,6 +206,11 @@ cc.OrbitCamera = cc.ActionCamera.extend(/** @lends cc.OrbitCamera# */{ return {newRadius:newRadius, zenith:zenith, azimuth:azimuth}; }, + /** + * called before the action start. It will also set the target. + * + * @param {cc.Node} target + */ startWithTarget:function (target) { var _t = this; cc.ActionInterval.prototype.startWithTarget.call(_t, target); @@ -188,22 +219,34 @@ cc.OrbitCamera = cc.ActionCamera.extend(/** @lends cc.OrbitCamera# */{ _t._radius = retValue.newRadius; if (isNaN(_t._angleZ)) - _t._angleZ = cc.radiansToDegress(retValue.zenith); + _t._angleZ = cc.radiansToDegrees(retValue.zenith); if (isNaN(_t._angleX)) - _t._angleX = cc.radiansToDegress(retValue.azimuth); + _t._angleX = cc.radiansToDegrees(retValue.azimuth); _t._radZ = cc.degreesToRadians(_t._angleZ); _t._radX = cc.degreesToRadians(_t._angleX); }, + /** + * to copy object with deep copy. + * returns a new clone of the action + * + * @returns {cc.ActionCamera} + */ clone:function(){ var a = new cc.OrbitCamera(), _t = this; a.initWithDuration(_t._duration, _t._radius, _t._deltaRadius, _t._angleZ, _t._deltaAngleZ, _t._angleX, _t._deltaAngleX); return a; }, + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ update:function (dt) { + dt = this._computeEaseTime(dt); var r = (this._radius + this._deltaRadius * dt) * cc.Camera.getZEye(); var za = this._radZ + this._radDeltaZ * dt; var xa = this._radX + this._radDeltaX * dt; @@ -213,11 +256,13 @@ cc.OrbitCamera = cc.ActionCamera.extend(/** @lends cc.OrbitCamera# */{ var k = Math.cos(za) * r + this._centerZOrig; this.target.getCamera().setEye(i, j, k); + this.target.setNodeDirty(); } }); /** * creates a cc.OrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX + * @function * @param {Number} t time * @param {Number} radius * @param {Number} deltaRadius @@ -227,6 +272,22 @@ cc.OrbitCamera = cc.ActionCamera.extend(/** @lends cc.OrbitCamera# */{ * @param {Number} deltaAngleX * @return {cc.OrbitCamera} */ -cc.OrbitCamera.create = function (t, radius, deltaRadius, angleZ, deltaAngleZ, angleX, deltaAngleX) { +cc.orbitCamera = function (t, radius, deltaRadius, angleZ, deltaAngleZ, angleX, deltaAngleX) { return new cc.OrbitCamera(t, radius, deltaRadius, angleZ, deltaAngleZ, angleX, deltaAngleX); }; + +/** + * Please use cc.orbitCamera instead + * creates a cc.OrbitCamera action with radius, delta-radius, z, deltaZ, x, deltaX + * @param {Number} t time + * @param {Number} radius + * @param {Number} deltaRadius + * @param {Number} angleZ + * @param {Number} deltaAngleZ + * @param {Number} angleX + * @param {Number} deltaAngleX + * @return {cc.OrbitCamera} + * @static + * @deprecated since v3.0 please use cc.orbitCamera() instead. + */ +cc.OrbitCamera.create = cc.orbitCamera; diff --git a/cocos2d/actions/CCActionCatmullRom.js b/cocos2d/actions/CCActionCatmullRom.js index b1fd07e501..4ab0dfd7fc 100644 --- a/cocos2d/actions/CCActionCatmullRom.js +++ b/cocos2d/actions/CCActionCatmullRom.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008 Radu Gruian Copyright (c) 2011 Vit Valentin @@ -33,9 +33,10 @@ ****************************************************************************/ /** - *

Returns the Cardinal Spline position for a given set of control points, tension and time CatmullRom Spline formula:
- * s(-ttt + 2tt - t)P1 + s(-ttt + tt)P2 + (2ttt - 3tt + 1)P2 + s(ttt - 2tt + t)P3 + (-2ttt + 3tt)P3 + s(ttt - tt)P4 - *

+ * Returns the Cardinal Spline position for a given set of control points, tension and time.
+ * CatmullRom Spline formula.
+ * s(-ttt + 2tt - t)P1 + s(-ttt + tt)P2 + (2ttt - 3tt + 1)P2 + s(ttt - 2tt + t)P3 + (-2ttt + 3tt)P3 + s(ttt - tt)P4 + * * @function * @param {cc.Point} p0 * @param {cc.Point} p1 @@ -64,9 +65,9 @@ cc.cardinalSplineAt = function (p0, p1, p2, p3, tension, t) { return cc.p(x, y); }; - /** * returns a new copy of the array reversed. + * * @return {Array} */ cc.reverseControlPoints = function (controlPoints) { @@ -77,15 +78,31 @@ cc.reverseControlPoints = function (controlPoints) { return newArray; }; -cc.copyControlPoints = function (controlPoints) { + +/** + * returns a new clone of the controlPoints + * + * @param controlPoints + * @returns {Array} + */ +cc.cloneControlPoints = function (controlPoints) { var newArray = []; for (var i = 0; i < controlPoints.length; i++) newArray.push(cc.p(controlPoints[i].x, controlPoints[i].y)); return newArray; }; +/** + * returns a new clone of the controlPoints + * @deprecated since v3.0 please use cc.cloneControlPoints() instead. + * @param controlPoints + * @returns {Array} + */ +cc.copyControlPoints = cc.cloneControlPoints; + /** * returns a point from the array + * * @param {Array} controlPoints * @param {Number} pos * @return {Array} @@ -96,7 +113,9 @@ cc.getControlPointAt = function (controlPoints, pos) { }; /** - * reverse the current control point array inline, without generating a new one + * reverse the current control point array inline, without generating a new one
+ * + * @param controlPoints */ cc.reverseControlPointsInline = function (controlPoints) { var len = controlPoints.length; @@ -110,13 +129,18 @@ cc.reverseControlPointsInline = function (controlPoints) { /** - * Cardinal Spline path. http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline + * Cardinal Spline path. {@link http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline} + * Absolute coordinates. + * * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {Array} points array of control points + * @param {Number} tension * * @example * //create a cc.CardinalSplineTo - * var action1 = cc.CardinalSplineTo.create(3, array, 0); + * var action1 = cc.cardinalSplineTo(3, array, 0); */ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# */{ /** Array of control points */ @@ -127,16 +151,11 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * _accumulatedDiff:null, /** - * Creates an action with a Cardinal Spline array of points and tension - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates an action with a Cardinal Spline array of points and tension. * @param {Number} duration * @param {Array} points array of control points * @param {Number} tension - * - * @example - * //create a cc.CardinalSplineTo - * var action1 = new cc.CardinalSplineTo(3, array, 0); */ ctor: function (duration, points, tension) { cc.ActionInterval.prototype.ctor.call(this); @@ -147,13 +166,15 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * /** * initializes the action with a duration and an array of points + * * @param {Number} duration * @param {Array} points array of control points * @param {Number} tension + * * @return {Boolean} */ initWithDuration:function (duration, points, tension) { - if(!points || points.length == 0) + if(!points || points.length === 0) throw "Invalid configuration. It must at least have one control point"; if (cc.ActionInterval.prototype.initWithDuration.call(this, duration)) { @@ -166,6 +187,7 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * /** * returns a new clone of the action + * * @returns {cc.CardinalSplineTo} */ clone:function () { @@ -175,6 +197,8 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * }, /** + * called before the action start. It will also set the target. + * * @param {cc.Node} target */ startWithTarget:function (target) { @@ -186,22 +210,25 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); var p, lt; var ps = this._points; // eg. // p..p..p..p..p..p..p // 1..2..3..4..5..6..7 // want p to be 1, 2, 3, 4, 5, 6 - if (time == 1) { + if (dt === 1) { p = ps.length - 1; lt = 1; } else { var locDT = this._deltaT; - p = 0 | (time / locDT); - lt = (time - locDT * p) / locDT; + p = 0 | (dt / locDT); + lt = (dt - locDT * p) / locDT; } var newPos = cc.cardinalSplineAt( @@ -215,7 +242,7 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * var tempX, tempY; tempX = this.target.getPositionX() - this._previousPosition.x; tempY = this.target.getPositionY() - this._previousPosition.y; - if (tempX != 0 || tempY != 0) { + if (tempX !== 0 || tempY !== 0) { var locAccDiff = this._accumulatedDiff; tempX = locAccDiff.x + tempX; tempY = locAccDiff.y + tempY; @@ -229,16 +256,19 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * }, /** - * reverse a new cc.CardinalSplineTo + * reverse a new cc.CardinalSplineTo.
+ * Along the track of movement in the opposite. + * * @return {cc.CardinalSplineTo} */ reverse:function () { var reversePoints = cc.reverseControlPoints(this._points); - return cc.CardinalSplineTo.create(this._duration, reversePoints, this._tension); + return cc.cardinalSplineTo(this._duration, reversePoints, this._tension); }, /** * update position of target + * * @param {cc.Point} newPos */ updatePosition:function (newPos) { @@ -248,6 +278,7 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * /** * Points getter + * * @return {Array} */ getPoints:function () { @@ -256,6 +287,7 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * /** * Points setter + * * @param {Array} points */ setPoints:function (points) { @@ -264,7 +296,8 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * }); /** - * creates an action with a Cardinal Spline array of points and tension + * creates an action with a Cardinal Spline array of points and tension. + * * @function * @param {Number} duration * @param {Array} points array of control points @@ -273,28 +306,46 @@ cc.CardinalSplineTo = cc.ActionInterval.extend(/** @lends cc.CardinalSplineTo# * * * @example * //create a cc.CardinalSplineTo - * var action1 = cc.CardinalSplineTo.create(3, array, 0); + * var action1 = cc.cardinalSplineTo(3, array, 0); */ -cc.CardinalSplineTo.create = function (duration, points, tension) { +cc.cardinalSplineTo = function (duration, points, tension) { return new cc.CardinalSplineTo(duration, points, tension); }; /** - * Cardinal Spline path. http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline + * Please use cc.cardinalSplineTo instead.
+ * creates an action with a Cardinal Spline array of points and tension + * + * @function + * @param {Number} duration + * @param {Array} points array of control points + * @param {Number} tension + * @return {cc.CardinalSplineTo} + * @static + * @deprecated since v3.0 please use cc.cardinalSplineTo(duration, points, tension) instead. + */ +cc.CardinalSplineTo.create = cc.cardinalSplineTo; + +/** + * Cardinal Spline path. {@link http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline} + * Relative coordinates. + * * @class * @extends cc.CardinalSplineTo + * @param {Number} duration + * @param {Array} points + * @param {Number} tension * * @example * //create a cc.CardinalSplineBy - * var action1 = cc.CardinalSplineBy.create(3, array, 0); + * var action1 = cc.cardinalSplineBy(3, array, 0); */ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# */{ _startPosition:null, /** - * creates an action with a Cardinal Spline array of points and tension - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates an action with a Cardinal Spline array of points and tension. * @param {Number} duration * @param {Array} points * @param {Number} tension @@ -307,6 +358,8 @@ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# }, /** + * called before the action start. It will also set the target. + * * @param {cc.Node} target */ startWithTarget:function (target) { @@ -317,6 +370,7 @@ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# /** * reverse a new cc.CardinalSplineBy + * * @return {cc.CardinalSplineBy} */ reverse:function () { @@ -352,11 +406,12 @@ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# reverseArray[i] = current; p = current; } - return cc.CardinalSplineBy.create(this._duration, reverseArray, this._tension); + return cc.cardinalSplineBy(this._duration, reverseArray, this._tension); }, /** * update position of target + * * @param {cc.Point} newPos */ updatePosition:function (newPos) { @@ -370,6 +425,7 @@ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# /** * returns a new clone of the action + * * @returns {cc.CardinalSplineBy} */ clone:function () { @@ -380,40 +436,53 @@ cc.CardinalSplineBy = cc.CardinalSplineTo.extend(/** @lends cc.CardinalSplineBy# }); /** - * creates an action with a Cardinal Spline array of points and tension + * creates an action with a Cardinal Spline array of points and tension. + * * @function * @param {Number} duration * @param {Array} points * @param {Number} tension + * * @return {cc.CardinalSplineBy} */ -cc.CardinalSplineBy.create = function (duration, points, tension) { +cc.cardinalSplineBy = function (duration, points, tension) { return new cc.CardinalSplineBy(duration, points, tension); }; /** - *

- * An action that moves the target with a CatmullRom curve to a destination point.
- * A Catmull Rom is a Cardinal Spline with a tension of 0.5.
- * http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline - *

+ * Please use cc.cardinalSplineBy instead. + * creates an action with a Cardinal Spline array of points and tension. + * @function + * @param {Number} duration + * @param {Array} points + * @param {Number} tension + * @return {cc.CardinalSplineBy} + * @static + * @deprecated since v3.0 please use cc.cardinalSplineBy(duration, points, tension); + */ +cc.CardinalSplineBy.create = cc.cardinalSplineBy; + +/** + * An action that moves the target with a CatmullRom curve to a destination point.
+ * A Catmull Rom is a Cardinal Spline with a tension of 0.5.
+ * {@link http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline} + * Absolute coordinates. + * * @class * @extends cc.CardinalSplineTo + * @param {Number} dt + * @param {Array} points * * @example - * var action1 = cc.CatmullRomTo.create(3, array); + * var action1 = cc.catmullRomTo(3, array); */ cc.CatmullRomTo = cc.CardinalSplineTo.extend(/** @lends cc.CatmullRomTo# */{ /** - * creates an action with a Cardinal Spline array of points and tension - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates an action with a Cardinal Spline array of points and tension. * @param {Number} dt * @param {Array} points - * - * @example - * var action1 = new cc.CatmullRomTo(3, array); */ ctor: function(dt, points) { points && this.initWithDuration(dt, points); @@ -422,7 +491,6 @@ cc.CatmullRomTo = cc.CardinalSplineTo.extend(/** @lends cc.CatmullRomTo# */{ /** * Initializes the action with a duration and an array of points * - * @function * @param {Number} dt * @param {Array} points */ @@ -442,41 +510,52 @@ cc.CatmullRomTo = cc.CardinalSplineTo.extend(/** @lends cc.CatmullRomTo# */{ }); /** - * creates an action with a Cardinal Spline array of points and tension + * creates an action with a Cardinal Spline array of points and tension. + * + * @function * @param {Number} dt * @param {Array} points * @return {cc.CatmullRomTo} * * @example - * var action1 = cc.CatmullRomTo.create(3, array); + * var action1 = cc.catmullRomTo(3, array); */ -cc.CatmullRomTo.create = function (dt, points) { +cc.catmullRomTo = function (dt, points) { return new cc.CatmullRomTo(dt, points); }; +/** + * Please use cc.catmullRomTo instead. + * creates an action with a Cardinal Spline array of points and tension. + * + * @param {Number} dt + * @param {Array} points + * @return {cc.CatmullRomTo} + * @static + * @deprecated since v3.0 please use cc.catmullRomTo(dt, points) instead. + */ +cc.CatmullRomTo.create = cc.catmullRomTo; /** - *

- * An action that moves the target with a CatmullRom curve by a certain distance.
- * A Catmull Rom is a Cardinal Spline with a tension of 0.5.
- * http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline - *

+ * An action that moves the target with a CatmullRom curve by a certain distance.
+ * A Catmull Rom is a Cardinal Spline with a tension of 0.5.
+ * http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Catmull.E2.80.93Rom_spline + * Relative coordinates. + * * @class * @extends cc.CardinalSplineBy + * @param {Number} dt + * @param {Array} points * * @example - * var action1 = cc.CatmullRomBy.create(3, array); + * var action1 = cc.catmullRomBy(3, array); */ cc.CatmullRomBy = cc.CardinalSplineBy.extend({ /** - * Creates an action with a Cardinal Spline array of points and tension - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates an action with a Cardinal Spline array of points and tension. * @param {Number} dt * @param {Array} points - * - * @example - * var action1 = new cc.CatmullRomBy(3, array); */ ctor: function(dt, points) { cc.CardinalSplineBy.prototype.ctor.call(this); @@ -507,10 +586,20 @@ cc.CatmullRomBy = cc.CardinalSplineBy.extend({ /** * Creates an action with a Cardinal Spline array of points and tension - * + * @function + * @param {Number} dt + * @param {Array} points + * @return {cc.CatmullRomBy} * @example - * var action1 = cc.CatmullRomBy.create(3, array); + * var action1 = cc.catmullRomBy(3, array); */ -cc.CatmullRomBy.create = function (dt, points) { +cc.catmullRomBy = function (dt, points) { return new cc.CatmullRomBy(dt, points); }; +/** + * Please use cc.catmullRomBy instead + * Creates an action with a Cardinal Spline array of points and tension + * @static + * @deprecated since v3.0 please cc.catmullRomBy(dt, points) instead. + */ +cc.CatmullRomBy.create = cc.catmullRomBy; diff --git a/cocos2d/actions/CCActionEase.js b/cocos2d/actions/CCActionEase.js index 295136f94f..ca8b0a6cb0 100644 --- a/cocos2d/actions/CCActionEase.js +++ b/cocos2d/actions/CCActionEase.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -28,26 +28,29 @@ * Base class for Easing actions * @class * @extends cc.ActionInterval + * @param {cc.ActionInterval} action + * + * @deprecated since v3.0 Does not recommend the use of the base object. + * + * @example + * var moveEase = new cc.ActionEase(action); */ - cc.ActionEase = cc.ActionInterval.extend(/** @lends cc.ActionEase# */{ _inner:null, /** - * creates the action of ActionEase - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates the action of ActionEase. * @param {cc.ActionInterval} action - * - * @example - * var moveEase = new cc.ActionEase(action); */ ctor: function (action) { cc.ActionInterval.prototype.ctor.call(this); action && this.initWithAction(action); }, - /** initializes the action + /** + * initializes the action + * * @param {cc.ActionInterval} action * @return {Boolean} */ @@ -62,6 +65,12 @@ cc.ActionEase = cc.ActionInterval.extend(/** @lends cc.ActionEase# */{ return false; }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.ActionEase} + */ clone:function(){ var action = new cc.ActionEase(); action.initWithAction(this._inner.clone()); @@ -69,6 +78,8 @@ cc.ActionEase = cc.ActionInterval.extend(/** @lends cc.ActionEase# */{ }, /** + * called before the action start. It will also set the target. + * * @param {cc.Node} target */ startWithTarget:function (target) { @@ -85,53 +96,84 @@ cc.ActionEase = cc.ActionInterval.extend(/** @lends cc.ActionEase# */{ }, /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - this._inner.update(time1); + update:function (dt) { + this._inner.update(dt); }, /** - * @return {cc.ActionInterval} + * Create new action to original operation effect opposite.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * @return {cc.ActionEase} */ reverse:function () { - return cc.ActionEase.create(this._inner.reverse()); + return new cc.ActionEase(this._inner.reverse()); }, + /** + * Get inner Action. + * + * @return {cc.ActionInterval} + */ getInnerAction:function(){ return this._inner; } }); -/** creates the action of ActionEase +/** + * creates the action of ActionEase + * * @param {cc.ActionInterval} action * @return {cc.ActionEase} * @example * // example - * var moveEase = cc.ActionEase.create(action); + * var moveEase = cc.actionEase(action); */ -cc.ActionEase.create = function (action) { +cc.actionEase = function (action) { return new cc.ActionEase(action); }; +/** + * Please use cc.actionEase instead + * creates the action of ActionEase + * + * @param {cc.ActionInterval} action + * @return {cc.ActionEase} + * @static + * @deprecated since v3.0 please use cc.actionEase(action) instead. + */ +cc.ActionEase.create = cc.actionEase; + /** * Base class for Easing actions with rate parameters + * * @class * @extends cc.ActionEase + * @param {cc.ActionInterval} action + * @param {Number} rate + * + * @deprecated since v3.0 please cc.easeRateAction(action, 3.0); + * + * @example + * //The old usage + * cc.EaseRateAction.create(action, 3.0); + * //The new usage + * var moveEaseRateAction = cc.easeRateAction(action, 3.0); */ cc.EaseRateAction = cc.ActionEase.extend(/** @lends cc.EaseRateAction# */{ _rate:0, /** - * Creates the action with the inner action and the rate parameter - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with the inner action and the rate parameter. * @param {cc.ActionInterval} action * @param {Number} rate - * - * @example - * // example - * var moveEaseRateAction = new cc.EaseRateAction(action, 3.0); */ ctor: function(action, rate){ cc.ActionEase.prototype.ctor.call(this); @@ -139,7 +181,8 @@ cc.EaseRateAction = cc.ActionEase.extend(/** @lends cc.EaseRateAction# */{ rate !== undefined && this.initWithAction(action, rate); }, - /** set rate value for the actions + /** + * set rate value for the actions * @param {Number} rate */ setRate:function (rate) { @@ -167,6 +210,12 @@ cc.EaseRateAction = cc.ActionEase.extend(/** @lends cc.EaseRateAction# */{ return false; }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseRateAction} + */ clone:function(){ var action = new cc.EaseRateAction(); action.initWithAction(this._inner.clone(), this._rate); @@ -174,45 +223,88 @@ cc.EaseRateAction = cc.ActionEase.extend(/** @lends cc.EaseRateAction# */{ }, /** - * @return {cc.ActionInterval} + * Create new action to original operation effect opposite.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * @return {cc.EaseRateAction} */ reverse:function () { - return cc.EaseRateAction.create(this._inner.reverse(), 1 / this._rate); + return new cc.EaseRateAction(this._inner.reverse(), 1 / this._rate); } }); -/** Creates the action with the inner action and the rate parameter +/** + * Creates the action with the inner action and the rate parameter. + * * @param {cc.ActionInterval} action * @param {Number} rate * @return {cc.EaseRateAction} * @example * // example - * var moveEaseRateAction = cc.EaseRateAction.create(action, 3.0); + * var moveEaseRateAction = cc.easeRateAction(action, 3.0); */ -cc.EaseRateAction.create = function (action, rate) { +cc.easeRateAction = function (action, rate) { return new cc.EaseRateAction(action, rate); }; /** - * cc.EaseIn action with a rate + * Please use cc.easeRateAction instead.
+ * Creates the action with the inner action and the rate parameter. + * + * @param {cc.ActionInterval} action + * @param {Number} rate + * @return {cc.EaseRateAction} + * @static + * @deprecated since v3.0 please use cc.easeRateAction(action, rate) + * @example + * //The old usage + * cc.EaseRateAction.create(action, 3.0); + * //The new usage + * var moveEaseRateAction = cc.easeRateAction(action, 3.0); + */ +cc.EaseRateAction.create = cc.easeRateAction; + +/** + * cc.EaseIn action with a rate. From slow to fast. + * * @class * @extends cc.EaseRateAction + * + * @deprecated since v3.0 please use action.easing(cc.easeIn(3)); + * + * @example + * //The old usage + * cc.EaseIn.create(action, 3); + * //The new usage + * action.easing(cc.easeIn(3.0)); */ cc.EaseIn = cc.EaseRateAction.extend(/** @lends cc.EaseIn# */{ + /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - this._inner.update(Math.pow(time1, this._rate)); + update:function (dt) { + this._inner.update(Math.pow(dt, this._rate)); }, /** - * @return {cc.ActionInterval} + * Create a cc.easeIn action. Opposite with the original motion trajectory. + * @return {cc.EaseIn} */ reverse:function () { - return cc.EaseIn.create(this._inner.reverse(), 1 / this._rate); + return new cc.EaseIn(this._inner.reverse(), 1 / this._rate); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseIn} + */ clone:function(){ var action = new cc.EaseIn(); action.initWithAction(this._inner.clone(), this._rate); @@ -220,37 +312,88 @@ cc.EaseIn = cc.EaseRateAction.extend(/** @lends cc.EaseIn# */{ } }); -/** Creates the action with the inner action and the rate parameter +/** + * Creates the action with the inner action and the rate parameter.
+ * From slow to fast. + * + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeIn(3)) + * + * @example + * //The old usage + * cc.EaseIn.create(action, 3); + * //The new usage + * action.easing(cc.easeIn(3.0)); + * * @param {cc.ActionInterval} action * @param {Number} rate * @return {cc.EaseIn} - * @example - * // example - * var moveEaseIn = cc.EaseIn.create(action, 3.0); */ cc.EaseIn.create = function (action, rate) { return new cc.EaseIn(action, rate); }; + +/** + * Creates the action easing object with the rate parameter.
+ * From slow to fast. + * + * @function + * @param {Number} rate + * @return {Object} + * @example + * // example + * action.easing(cc.easeIn(3.0)); + */ +cc.easeIn = function (rate) { + return { + _rate: rate, + easing: function (dt) { + return Math.pow(dt, this._rate); + }, + reverse: function(){ + return cc.easeIn(1 / this._rate); + } + }; +}; + /** - * cc.EaseOut action with a rate + * cc.EaseOut action with a rate. From fast to slow. + * * @class * @extends cc.EaseRateAction + * + * @deprecated since v3.0 please use action.easing(cc.easeOut(3)) + * + * @example + * //The old usage + * cc.EaseOut.create(action, 3); + * //The new usage + * action.easing(cc.easeOut(3.0)); */ cc.EaseOut = cc.EaseRateAction.extend(/** @lends cc.EaseOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - this._inner.update(Math.pow(time1, 1 / this._rate)); + update:function (dt) { + this._inner.update(Math.pow(dt, 1 / this._rate)); }, /** - * @return {cc.ActionInterval} + * Create a cc.easeIn action. Opposite with the original motion trajectory. + * @return {cc.EaseOut} */ reverse:function () { - return cc.EaseOut.create(this._inner.reverse(), 1 / this._rate); + return new cc.EaseOut(this._inner.reverse(), 1 / this._rate); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseOut} + */ clone:function(){ var action = new cc.EaseOut(); action.initWithAction(this._inner.clone(),this._rate); @@ -258,35 +401,84 @@ cc.EaseOut = cc.EaseRateAction.extend(/** @lends cc.EaseOut# */{ } }); -/** Creates the action with the inner action and the rate parameter +/** + * Creates the action with the inner action and the rate parameter.
+ * From fast to slow. + * + * @static + * @deprecated since v3.0
Please use cc.easeOut instead. + * + * @example + * //The old usage + * cc.EaseOut.create(action, 3); + * //The new usage + * action.easing(cc.easeOut(3.0)); + * * @param {cc.ActionInterval} action * @param {Number} rate * @return {cc.EaseOut} - * @example - * // example - * var moveEaseOut = cc.EaseOut.create(action, 3.0); */ cc.EaseOut.create = function (action, rate) { return new cc.EaseOut(action, rate); }; /** - * cc.EaseInOut action with a rate + * Creates the action easing object with the rate parameter.
+ * From fast to slow. + * + * @function + * @param {Number} rate + * @return {Object} + * @example + * // example + * action.easing(cc.easeOut(3.0)); + */ +cc.easeOut = function (rate) { + return { + _rate: rate, + easing: function (dt) { + return Math.pow(dt, 1 / this._rate); + }, + reverse: function(){ + return cc.easeOut(1 / this._rate) + } + }; +}; + +/** + * cc.EaseInOut action with a rate.
+ * Slow to fast then to slow. * @class * @extends cc.EaseRateAction + * + * @deprecated since v3.0 please use action.easing(cc.easeInOut(3.0)) + * + * @example + * //The old usage + * cc.EaseInOut.create(action, 3); + * //The new usage + * action.easing(cc.easeInOut(3.0)); */ cc.EaseInOut = cc.EaseRateAction.extend(/** @lends cc.EaseInOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - time1 *= 2; - if (time1 < 1) - this._inner.update(0.5 * Math.pow(time1, this._rate)); + update:function (dt) { + dt *= 2; + if (dt < 1) + this._inner.update(0.5 * Math.pow(dt, this._rate)); else - this._inner.update(1.0 - 0.5 * Math.pow(2 - time1, this._rate)); + this._inner.update(1.0 - 0.5 * Math.pow(2 - dt, this._rate)); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseInOut} + */ clone:function(){ var action = new cc.EaseInOut(); action.initWithAction(this._inner.clone(), this._rate); @@ -294,44 +486,100 @@ cc.EaseInOut = cc.EaseRateAction.extend(/** @lends cc.EaseInOut# */{ }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseInOut action. Opposite with the original motion trajectory. + * @return {cc.EaseInOut} */ reverse:function () { - return cc.EaseInOut.create(this._inner.reverse(), this._rate); + return new cc.EaseInOut(this._inner.reverse(), this._rate); } }); -/** Creates the action with the inner action and the rate parameter +/** + * Creates the action with the inner action and the rate parameter. + * Slow to fast then to slow. + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeInOut(3.0)) + * + * @example + * //The old usage + * cc.EaseInOut.create(action, 3); + * //The new usage + * action.easing(cc.easeInOut(3.0)); + * * @param {cc.ActionInterval} action * @param {Number} rate * @return {cc.EaseInOut} - * @example - * // example - * var moveEaseInOut = cc.EaseInOut.create(action, 3.0); */ cc.EaseInOut.create = function (action, rate) { return new cc.EaseInOut(action, rate); }; + +/** + * Creates the action easing object with the rate parameter.
+ * Slow to fast then to slow. + * @function + * @param {Number} rate + * @return {Object} + * + * @example + * //The new usage + * action.easing(cc.easeInOut(3.0)); + */ +cc.easeInOut = function (rate) { + return { + _rate: rate, + easing: function (dt) { + dt *= 2; + if (dt < 1) + return 0.5 * Math.pow(dt, this._rate); + else + return 1.0 - 0.5 * Math.pow(2 - dt, this._rate); + }, + reverse: function(){ + return cc.easeInOut(this._rate); + } + }; +}; + /** - * cc.Ease Exponential In + * cc.Ease Exponential In. Slow to Fast.
+ * Reference easeInExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please action.easing(cc.easeExponentialIn()) + * + * @example + * //The old usage + * cc.EaseExponentialIn.create(action); + * //The new usage + * action.easing(cc.easeExponentialIn()); */ cc.EaseExponentialIn = cc.ActionEase.extend(/** @lends cc.EaseExponentialIn# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - this._inner.update(time1 === 0 ? 0 : Math.pow(2, 10 * (time1 - 1))); + update:function (dt) { + this._inner.update(dt === 0 ? 0 : Math.pow(2, 10 * (dt - 1))); }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseExponentialOut action. Opposite with the original motion trajectory. + * @return {cc.EaseExponentialOut} */ reverse:function () { - return cc.EaseExponentialOut.create(this._inner.reverse()); + return new cc.EaseExponentialOut(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseExponentialIn} + */ clone:function(){ var action = new cc.EaseExponentialIn(); action.initWithAction(this._inner.clone()); @@ -339,37 +587,87 @@ cc.EaseExponentialIn = cc.ActionEase.extend(/** @lends cc.EaseExponentialIn# */{ } }); -/** creates the action +/** + * Creates the action easing object with the rate parameter.
+ * Reference easeInExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeExponentialIn()) * @param {cc.ActionInterval} action * @return {cc.EaseExponentialIn} + * * @example - * // example - * var moveEaseExponentialIn = cc.EaseExponentialIn.create(action); + * //The old usage + * cc.EaseExponentialIn.create(action); + * //The new usage + * action.easing(cc.easeExponentialIn()); */ cc.EaseExponentialIn.create = function (action) { return new cc.EaseExponentialIn(action); }; + +cc._easeExponentialInObj = { + easing: function(dt){ + return dt === 0 ? 0 : Math.pow(2, 10 * (dt - 1)); + }, + reverse: function(){ + return cc._easeExponentialOutObj; + } +}; + +/** + * Creates the action easing object with the rate parameter.
+ * Reference easeInExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeExponentialIn()); + */ +cc.easeExponentialIn = function(){ + return cc._easeExponentialInObj; +}; + /** - * Ease Exponential Out + * Ease Exponential Out.
+ * Reference easeOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeExponentialOut()) + * + * @example + * //The old usage + * cc.EaseExponentialOut.create(action); + * //The new usage + * action.easing(cc.easeExponentialOut()); */ cc.EaseExponentialOut = cc.ActionEase.extend(/** @lends cc.EaseExponentialOut# */{ - /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - this._inner.update(time1 == 1 ? 1 : (-(Math.pow(2, -10 * time1)) + 1)); + update:function (dt) { + this._inner.update(dt === 1 ? 1 : (-(Math.pow(2, -10 * dt)) + 1)); }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseExponentialIn action. Opposite with the original motion trajectory. + * @return {cc.EaseExponentialIn} */ reverse:function () { - return cc.EaseExponentialIn.create(this._inner.reverse()); + return new cc.EaseExponentialIn(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseExponentialOut} + */ clone:function(){ var action = new cc.EaseExponentialOut(); action.initWithAction(this._inner.clone()); @@ -377,44 +675,95 @@ cc.EaseExponentialOut = cc.ActionEase.extend(/** @lends cc.EaseExponentialOut# * } }); -/** creates the action +/** + * Creates the action easing object with the rate parameter.
+ * Reference easeOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeExponentialOut()) * @param {cc.ActionInterval} action - * @return {cc.EaseExponentialOut} + * @return {Object} + * * @example - * // example - * var moveEaseExponentialOut = cc.EaseExponentialOut.create(action); + * //The old usage + * cc.EaseExponentialOut.create(action); + * //The new usage + * action.easing(cc.easeExponentialOut()); */ cc.EaseExponentialOut.create = function (action) { return new cc.EaseExponentialOut(action); }; +cc._easeExponentialOutObj = { + easing: function(dt){ + return dt === 1 ? 1 : (-(Math.pow(2, -10 * dt)) + 1); + }, + reverse: function(){ + return cc._easeExponentialInObj; + } +}; + +/** + * creates the action easing object.
+ * Reference easeOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * + * @return {Object} + * @example + * // example + * action.easing(cc.easeExponentialOut()); + */ +cc.easeExponentialOut = function(){ + return cc._easeExponentialOutObj; +}; + /** - * Ease Exponential InOut + * Ease Exponential InOut.
+ * Reference easeInOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeExponentialInOut) + * + * @example + * //The old usage + * cc.EaseExponentialInOut.create(action); + * //The new usage + * action.easing(cc.easeExponentialInOut()); */ cc.EaseExponentialInOut = cc.ActionEase.extend(/** @lends cc.EaseExponentialInOut# */{ /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { - if( time != 1 && time !== 0) { - time *= 2; - if (time < 1) - time = 0.5 * Math.pow(2, 10 * (time - 1)); + update:function (dt) { + if( dt !== 1 && dt !== 0) { + dt *= 2; + if (dt < 1) + dt = 0.5 * Math.pow(2, 10 * (dt - 1)); else - time = 0.5 * (-Math.pow(2, -10 * (time - 1)) + 2); + dt = 0.5 * (-Math.pow(2, -10 * (dt - 1)) + 2); } - this._inner.update(time); + this._inner.update(dt); }, /** + * Create a cc.EaseExponentialInOut action. Opposite with the original motion trajectory. * @return {cc.EaseExponentialInOut} */ reverse:function () { - return cc.EaseExponentialInOut.create(this._inner.reverse()); + return new cc.EaseExponentialInOut(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseExponentialInOut} + */ clone:function(){ var action = new cc.EaseExponentialInOut(); action.initWithAction(this._inner.clone()); @@ -422,39 +771,95 @@ cc.EaseExponentialInOut = cc.ActionEase.extend(/** @lends cc.EaseExponentialInOu } }); -/** creates the action +/** + * creates an EaseExponentialInOut action.
+ * Reference easeInOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeExponentialInOut) * @param {cc.ActionInterval} action * @return {cc.EaseExponentialInOut} + * * @example - * // example - * var moveEaseExponentialInOut = cc.EaseExponentialInOut.create(action); + * //The old usage + * cc.EaseExponentialInOut.create(action); + * //The new usage + * action.easing(cc.easeExponentialInOut()); */ cc.EaseExponentialInOut.create = function (action) { return new cc.EaseExponentialInOut(action); }; +cc._easeExponentialInOutObj = { + easing: function(dt){ + if( dt !== 1 && dt !== 0) { + dt *= 2; + if (dt < 1) + return 0.5 * Math.pow(2, 10 * (dt - 1)); + else + return 0.5 * (-Math.pow(2, -10 * (dt - 1)) + 2); + } + return dt; + }, + reverse: function(){ + return cc._easeExponentialInOutObj; + } +}; + +/** + * creates an EaseExponentialInOut action easing object.
+ * Reference easeInOutExpo:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeExponentialInOut()); + */ +cc.easeExponentialInOut = function(){ + return cc._easeExponentialInOutObj; +}; /** - * Ease Sine In + * Ease Sine In.
+ * Reference easeInSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeSineIn()) + * + * @example + * //The old usage + * cc.EaseSineIn.create(action); + * //The new usage + * action.easing(cc.easeSineIn()); */ cc.EaseSineIn = cc.ActionEase.extend(/** @lends cc.EaseSineIn# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - time1 = time1===0 || time1==1 ? time1 : -1 * Math.cos(time1 * Math.PI / 2) + 1; - this._inner.update(time1); + update:function (dt) { + dt = dt===0 || dt===1 ? dt : -1 * Math.cos(dt * Math.PI / 2) + 1; + this._inner.update(dt); }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseSineOut action. Opposite with the original motion trajectory. + * @return {cc.EaseSineOut} */ reverse:function () { - return cc.EaseSineOut.create(this._inner.reverse()); + return new cc.EaseSineOut(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseSineIn} + */ clone:function(){ var action = new cc.EaseSineIn(); action.initWithAction(this._inner.clone()); @@ -462,37 +867,87 @@ cc.EaseSineIn = cc.ActionEase.extend(/** @lends cc.EaseSineIn# */{ } }); -/** creates the action +/** + * creates an EaseSineIn action.
+ * Reference easeInSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeSineIn()) * @param {cc.ActionInterval} action * @return {cc.EaseSineIn} + * * @example - * // example - * var moveSineIn = cc.EaseSineIn.create(action); + * //The old usage + * cc.EaseSineIn.create(action); + * //The new usage + * action.easing(cc.easeSineIn()); */ cc.EaseSineIn.create = function (action) { return new cc.EaseSineIn(action); }; + +cc._easeSineInObj = { + easing: function(dt){ + return (dt===0 || dt===1) ? dt : -1 * Math.cos(dt * Math.PI / 2) + 1; + }, + reverse: function(){ + return cc._easeSineOutObj; + } +}; +/** + * creates an EaseSineIn action.
+ * Reference easeInSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeSineIn()); + */ +cc.easeSineIn = function(){ + return cc._easeSineInObj; +}; + /** - * Ease Sine Out + * Ease Sine Out.
+ * Reference easeOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeSineOut()) + * + * @example + * //The old usage + * cc.EaseSineOut.create(action); + * //The new usage + * action.easing(cc.easeSineOut()); */ cc.EaseSineOut = cc.ActionEase.extend(/** @lends cc.EaseSineOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - time1 = time1===0 || time1==1 ? time1 : Math.sin(time1 * Math.PI / 2); - this._inner.update(time1); + update:function (dt) { + dt = dt===0 || dt===1 ? dt : Math.sin(dt * Math.PI / 2); + this._inner.update(dt); }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseSineIn action. Opposite with the original motion trajectory. + * @return {cc.EaseSineIn} */ reverse:function () { - return cc.EaseSineIn.create(this._inner.reverse()); + return new cc.EaseSineIn(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseSineOut} + */ clone:function(){ var action = new cc.EaseSineOut(); action.initWithAction(this._inner.clone()); @@ -500,34 +955,80 @@ cc.EaseSineOut = cc.ActionEase.extend(/** @lends cc.EaseSineOut# */{ } }); - -/** creates the action +/** + * Creates an EaseSineOut action.
+ * Reference easeOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeSineOut()) * @param {cc.ActionInterval} action * @return {cc.EaseSineOut} + * * @example - * // example - * var moveEaseOut = cc.EaseSineOut.create(action); + * //The old usage + * cc.EaseSineOut.create(action); + * //The new usage + * action.easing(cc.easeSineOut()); */ cc.EaseSineOut.create = function (action) { return new cc.EaseSineOut(action); }; +cc._easeSineOutObj = { + easing: function(dt){ + return (dt===0 || dt===1) ? dt : Math.sin(dt * Math.PI / 2); + }, + reverse: function(){ + return cc._easeSineInObj; + } +}; + +/** + * Creates an EaseSineOut action easing object.
+ * Reference easeOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeSineOut()); + */ +cc.easeSineOut = function(){ + return cc._easeSineOutObj; +}; /** - * Ease Sine InOut + * Ease Sine InOut.
+ * Reference easeInOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeSineInOut()) + * + * @example + * //The old usage + * cc.EaseSineInOut.create(action); + * //The new usage + * action.easing(cc.easeSineInOut()); */ cc.EaseSineInOut = cc.ActionEase.extend(/** @lends cc.EaseSineInOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - time1 = time1===0 || time1==1 ? time1 : -0.5 * (Math.cos(Math.PI * time1) - 1); - this._inner.update(time1); - + update:function (dt) { + dt = dt===0 || dt===1 ? dt : -0.5 * (Math.cos(Math.PI * dt) - 1); + this._inner.update(dt); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseSineInOut} + */ clone:function(){ var action = new cc.EaseSineInOut(); action.initWithAction(this._inner.clone()); @@ -535,41 +1036,72 @@ cc.EaseSineInOut = cc.ActionEase.extend(/** @lends cc.EaseSineInOut# */{ }, /** - * @return {cc.ActionInterval} + * Create a cc.EaseSineInOut action. Opposite with the original motion trajectory. + * @return {cc.EaseSineInOut} */ reverse:function () { - return cc.EaseSineInOut.create(this._inner.reverse()); + return new cc.EaseSineInOut(this._inner.reverse()); } }); -/** creates the action +/** + * Creates the action.
+ * Reference easeInOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static * @param {cc.ActionInterval} action * @return {cc.EaseSineInOut} + * @deprecated since v3.0
Please use action.easing(cc.easeSineInOut()) + * * @example - * // example - * var moveEaseSineInOut = cc.EaseSineInOut.create(action); + * //The old usage + * cc.EaseSineInOut.create(action); + * //The new usage + * action.easing(cc.easeSineInOut()); */ cc.EaseSineInOut.create = function (action) { return new cc.EaseSineInOut(action); }; +cc._easeSineInOutObj = { + easing: function(dt){ + return (dt === 0 || dt === 1) ? dt : -0.5 * (Math.cos(Math.PI * dt) - 1); + }, + reverse: function(){ + return cc._easeSineInOutObj; + } +}; + /** - * Ease Elastic abstract class + * creates the action easing object.
+ * Reference easeInOutSine:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @return {Object} + * @example + * // example + * action.easing(cc.easeSineInOut()); + */ +cc.easeSineInOut = function(){ + return cc._easeSineInOutObj; +}; + +/** + * Ease Elastic abstract class. * @class * @extends cc.ActionEase + * @param {cc.ActionInterval} action + * @param {Number} [period=0.3] + * + * @deprecated since v3.0 Does not recommend the use of the base object. */ cc.EaseElastic = cc.ActionEase.extend(/** @lends cc.EaseElastic# */{ _period: 0.3, - /** Creates the action with the inner action and the period in radians (default is 0.3) - * - * @constructor + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with the inner action and the period in radians (default is 0.3). * @param {cc.ActionInterval} action * @param {Number} [period=0.3] - * - * @example - * // example - * var moveEaseElastic = new cc.EaseElastic(action, 3.0); */ ctor:function(action, period){ cc.ActionEase.prototype.ctor.call(this); @@ -577,21 +1109,24 @@ cc.EaseElastic = cc.ActionEase.extend(/** @lends cc.EaseElastic# */{ action && this.initWithAction(action, period); }, - /** get period of the wave in radians. default is 0.3 + /** + * get period of the wave in radians. default is 0.3 * @return {Number} */ getPeriod:function () { return this._period; }, - /** set period of the wave in radians. + /** + * set period of the wave in radians. * @param {Number} period */ setPeriod:function (period) { this._period = period; }, - /** Initializes the action with the inner action and the period in radians (default is 0.3) + /** + * Initializes the action with the inner action and the period in radians (default is 0.3) * @param {cc.ActionInterval} action * @param {Number} [period=0.3] * @return {Boolean} @@ -603,12 +1138,21 @@ cc.EaseElastic = cc.ActionEase.extend(/** @lends cc.EaseElastic# */{ }, /** - * @return {Null} + * Create a action. Opposite with the original motion trajectory.
+ * Will be overwrite. + * @return {null} */ reverse:function () { cc.log("cc.EaseElastic.reverse(): it should be overridden in subclass."); + return null; }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseElastic} + */ clone:function(){ var action = new cc.EaseElastic(); action.initWithAction(this._inner.clone(), this._period); @@ -616,47 +1160,66 @@ cc.EaseElastic = cc.ActionEase.extend(/** @lends cc.EaseElastic# */{ } }); -/** Creates the action with the inner action and the period in radians (default is 0.3) +/** + * Creates the action with the inner action and the period in radians (default is 0.3). + * @static + * @deprecated since v3.0 Does not recommend the use of the base object. * @param {cc.ActionInterval} action * @param {Number} [period=0.3] * @return {cc.EaseElastic} - * @example - * // example - * var moveEaseElastic = cc.EaseElastic.create(action, 3.0); */ cc.EaseElastic.create = function (action, period) { return new cc.EaseElastic(action, period); }; /** - * Ease Elastic In action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * Ease Elastic In action.
+ * Reference easeInElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseElastic + * + * @deprecated since v3.0 please use action.easing(cc.easeElasticIn()) + * + * @example + * //The old usage + * cc.EaseElasticIn.create(action, period); + * //The new usage + * action.easing(cc.easeElasticIn(period)); */ cc.EaseElasticIn = cc.EaseElastic.extend(/** @lends cc.EaseElasticIn# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var newT = 0; - if (time1 === 0 || time1 === 1) { - newT = time1; + if (dt === 0 || dt === 1) { + newT = dt; } else { var s = this._period / 4; - time1 = time1 - 1; - newT = -Math.pow(2, 10 * time1) * Math.sin((time1 - s) * Math.PI * 2 / this._period); + dt = dt - 1; + newT = -Math.pow(2, 10 * dt) * Math.sin((dt - s) * Math.PI * 2 / this._period); } this._inner.update(newT); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseElasticOut} */ reverse:function () { - return cc.EaseElasticOut.create(this._inner.reverse(), this._period); + return new cc.EaseElasticOut(this._inner.reverse(), this._period); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseElasticIn} + */ clone:function(){ var action = new cc.EaseElasticIn(); action.initWithAction(this._inner.clone(), this._period); @@ -664,48 +1227,116 @@ cc.EaseElasticIn = cc.EaseElastic.extend(/** @lends cc.EaseElasticIn# */{ } }); - -/** Creates the action with the inner action and the period in radians (default is 0.3) +/** + * Creates the action with the inner action and the period in radians (default is 0.3).
+ * Reference easeInElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @deprecated since v3.0
Please use action.easing(cc.easeElasticIn(period)) + * + * @example + * //The old usage + * cc.EaseElasticIn.create(action, period); + * //The new usage + * action.easing(cc.easeElasticIn(period)); + * * @param {cc.ActionInterval} action - * @param {Number} [period=] + * @param {Number} [period=0.3] * @return {cc.EaseElasticIn} - * @example - * // example - * var moveEaseElasticIn = cc.EaseElasticIn.create(action, 3.0); */ cc.EaseElasticIn.create = function (action, period) { return new cc.EaseElasticIn(action, period); }; +//default ease elastic in object (period = 0.3) +cc._easeElasticInObj = { + easing:function(dt){ + if (dt === 0 || dt === 1) + return dt; + dt = dt - 1; + return -Math.pow(2, 10 * dt) * Math.sin((dt - (0.3 / 4)) * Math.PI * 2 / 0.3); + }, + reverse:function(){ + return cc._easeElasticOutObj; + } +}; + +/** + * Creates the action easing obejct with the period in radians (default is 0.3).
+ * Reference easeInElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @param {Number} [period=0.3] + * @return {Object} + * @example + * // example + * action.easing(cc.easeElasticIn(3.0)); + */ +cc.easeElasticIn = function (period) { + if(period && period !== 0.3){ + return { + _period: period, + easing: function (dt) { + if (dt === 0 || dt === 1) + return dt; + dt = dt - 1; + return -Math.pow(2, 10 * dt) * Math.sin((dt - (this._period / 4)) * Math.PI * 2 / this._period); + }, + reverse:function () { + return cc.easeElasticOut(this._period); + } + }; + } + return cc._easeElasticInObj; +}; + /** - * Ease Elastic Out action. + * Ease Elastic Out action.
+ * Reference easeOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseElastic + * + * @deprecated since v3.0
Please use action.easing(cc.easeElasticOut(period)) + * + * @example + * //The old usage + * cc.EaseElasticOut.create(action, period); + * //The new usage + * action.easing(cc.easeElasticOut(period)); */ cc.EaseElasticOut = cc.EaseElastic.extend(/** @lends cc.EaseElasticOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var newT = 0; - if (time1 === 0 || time1 == 1) { - newT = time1; + if (dt === 0 || dt === 1) { + newT = dt; } else { var s = this._period / 4; - newT = Math.pow(2, -10 * time1) * Math.sin((time1 - s) * Math.PI * 2 / this._period) + 1; + newT = Math.pow(2, -10 * dt) * Math.sin((dt - s) * Math.PI * 2 / this._period) + 1; } this._inner.update(newT); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseElasticIn} */ reverse:function () { - return cc.EaseElasticIn.create(this._inner.reverse(), this._period); + return new cc.EaseElasticIn(this._inner.reverse(), this._period); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseElasticOut} + */ clone:function(){ var action = new cc.EaseElasticOut(); action.initWithAction(this._inner.clone(), this._period); @@ -713,56 +1344,116 @@ cc.EaseElasticOut = cc.EaseElastic.extend(/** @lends cc.EaseElasticOut# */{ } }); - -/** Creates the action with the inner action and the period in radians (default is 0.3) +/** + * Creates the action with the inner action and the period in radians (default is 0.3).
+ * Reference easeOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @deprecated since v3.0
Please use action.easing(cc.easeElasticOut(period)) * @param {cc.ActionInterval} action * @param {Number} [period=0.3] * @return {cc.EaseElasticOut} + * * @example - * // example - * var moveEaseElasticOut = cc.EaseElasticOut.create(action, 3.0); + * //The old usage + * cc.EaseElasticOut.create(action, period); + * //The new usage + * action.easing(cc.easeElasticOut(period)); */ cc.EaseElasticOut.create = function (action, period) { return new cc.EaseElasticOut(action, period); }; +//default ease elastic out object (period = 0.3) +cc._easeElasticOutObj = { + easing: function (dt) { + return (dt === 0 || dt === 1) ? dt : Math.pow(2, -10 * dt) * Math.sin((dt - (0.3 / 4)) * Math.PI * 2 / 0.3) + 1; + }, + reverse:function(){ + return cc._easeElasticInObj; + } +}; +/** + * Creates the action easing object with the period in radians (default is 0.3).
+ * Reference easeOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @param {Number} [period=0.3] + * @return {Object} + * @example + * // example + * action.easing(cc.easeElasticOut(3.0)); + */ +cc.easeElasticOut = function (period) { + if(period && period !== 0.3){ + return { + _period: period, + easing: function (dt) { + return (dt === 0 || dt === 1) ? dt : Math.pow(2, -10 * dt) * Math.sin((dt - (this._period / 4)) * Math.PI * 2 / this._period) + 1; + }, + reverse:function(){ + return cc.easeElasticIn(this._period); + } + }; + } + return cc._easeElasticOutObj; +}; + /** - * Ease Elastic InOut action. + * Ease Elastic InOut action.
+ * Reference easeInOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseElastic + * + * @deprecated since v3.0 please use action.easing(cc.easeElasticInOut()) + * + * @example + * //The old usage + * cc.EaseElasticInOut.create(action, period); + * //The new usage + * action.easing(cc.easeElasticInOut(period)); */ cc.EaseElasticInOut = cc.EaseElastic.extend(/** @lends cc.EaseElasticInOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var newT = 0; - var locPeriod = this._period - if (time1 === 0 || time1 == 1) { - newT = time1; + var locPeriod = this._period; + if (dt === 0 || dt === 1) { + newT = dt; } else { - time1 = time1 * 2; + dt = dt * 2; if (!locPeriod) locPeriod = this._period = 0.3 * 1.5; var s = locPeriod / 4; - time1 = time1 - 1; - if (time1 < 0) - newT = -0.5 * Math.pow(2, 10 * time1) * Math.sin((time1 - s) * Math.PI * 2 / locPeriod); + dt = dt - 1; + if (dt < 0) + newT = -0.5 * Math.pow(2, 10 * dt) * Math.sin((dt - s) * Math.PI * 2 / locPeriod); else - newT = Math.pow(2, -10 * time1) * Math.sin((time1 - s) * Math.PI * 2 / locPeriod) * 0.5 + 1; + newT = Math.pow(2, -10 * dt) * Math.sin((dt - s) * Math.PI * 2 / locPeriod) * 0.5 + 1; } this._inner.update(newT); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseElasticInOut} */ reverse:function () { - return cc.EaseElasticInOut.create(this._inner.reverse(), this._period); + return new cc.EaseElasticInOut(this._inner.reverse(), this._period); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseElasticInOut} + */ clone:function(){ var action = new cc.EaseElasticInOut(); action.initWithAction(this._inner.clone(), this._period); @@ -770,24 +1461,73 @@ cc.EaseElasticInOut = cc.EaseElastic.extend(/** @lends cc.EaseElasticInOut# */{ } }); -/** Creates the action with the inner action and the period in radians (default is 0.3) +/** + * Creates the action with the inner action and the period in radians (default is 0.3).
+ * Reference easeInOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @deprecated since v3.0
Please use action.easing(cc.easeElasticInOut(period)) * @param {cc.ActionInterval} action * @param {Number} [period=0.3] * @return {cc.EaseElasticInOut} + * * @example - * // example - * var moveEaseElasticInOut = cc.EaseElasticInOut.create(action, 3.0); + * //The old usage + * cc.EaseElasticInOut.create(action, period); + * //The new usage + * action.easing(cc.easeElasticInOut(period)); */ cc.EaseElasticInOut.create = function (action, period) { return new cc.EaseElasticInOut(action, period); }; /** - * cc.EaseBounce abstract class. - * @class - * @extends cc.ActionEase - */ -cc.EaseBounce = cc.ActionEase.extend(/** @lends cc.EaseBounce# */{ + * Creates the action easing object with the period in radians (default is 0.3).
+ * Reference easeInOutElastic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @param {Number} [period=0.3] + * @return {Object} + * @example + * // example + * action.easing(cc.easeElasticInOut(3.0)); + */ +cc.easeElasticInOut = function (period) { + period = period || 0.3; + return { + _period: period, + easing: function (dt) { + var newT = 0; + var locPeriod = this._period; + if (dt === 0 || dt === 1) { + newT = dt; + } else { + dt = dt * 2; + if (!locPeriod) + locPeriod = this._period = 0.3 * 1.5; + var s = locPeriod / 4; + dt = dt - 1; + if (dt < 0) + newT = -0.5 * Math.pow(2, 10 * dt) * Math.sin((dt - s) * Math.PI * 2 / locPeriod); + else + newT = Math.pow(2, -10 * dt) * Math.sin((dt - s) * Math.PI * 2 / locPeriod) * 0.5 + 1; + } + return newT; + }, + reverse: function(){ + return cc.easeElasticInOut(this._period); + } + }; +}; + +/** + * cc.EaseBounce abstract class. + * + * @deprecated since v3.0 Does not recommend the use of the base object. + * + * @class + * @extends cc.ActionEase + */ +cc.EaseBounce = cc.ActionEase.extend(/** @lends cc.EaseBounce# */{ /** * @param {Number} time1 * @return {Number} @@ -807,6 +1547,12 @@ cc.EaseBounce = cc.ActionEase.extend(/** @lends cc.EaseBounce# */{ return 7.5625 * time1 * time1 + 0.984375; }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBounce} + */ clone:function(){ var action = new cc.EaseBounce(); action.initWithAction(this._inner.clone()); @@ -814,46 +1560,65 @@ cc.EaseBounce = cc.ActionEase.extend(/** @lends cc.EaseBounce# */{ }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBounce} */ reverse:function () { - return cc.EaseBounce.create(this._inner.reverse()); + return new cc.EaseBounce(this._inner.reverse()); } }); -/** creates the action +/** + * Creates an ease bounce action. + * @static + * @deprecated since v3.0 Does not recommend the use of the base object. * @param {cc.ActionInterval} action * @return {cc.EaseBounce} - * @example - * // example - * var moveEaseBounce = cc.EaseBounce.create(action); */ cc.EaseBounce.create = function (action) { return new cc.EaseBounce(action); }; /** - * cc.EaseBounceIn action. + * cc.EaseBounceIn action.
+ * Eased bounce effect at the beginning. * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseBounce + * + * @deprecated since v3.0 please use action.easing(cc.easeBounceIn()) + * + * @example + * //The old usage + * cc.EaseBounceIn.create(action); + * //The new usage + * action.easing(cc.easeBounceIn()); */ cc.EaseBounceIn = cc.EaseBounce.extend(/** @lends cc.EaseBounceIn# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - var newT = 1 - this.bounceTime(1 - time1); + update:function (dt) { + var newT = 1 - this.bounceTime(1 - dt); this._inner.update(newT); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBounceOut} */ reverse:function () { - return cc.EaseBounceOut.create(this._inner.reverse()); + return new cc.EaseBounceOut(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBounceIn} + */ clone:function(){ var action = new cc.EaseBounceIn(); action.initWithAction(this._inner.clone()); @@ -861,38 +1626,101 @@ cc.EaseBounceIn = cc.EaseBounce.extend(/** @lends cc.EaseBounceIn# */{ } }); -/** creates the action +/** + * Creates the action.
+ * Eased bounce effect at the beginning. + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeBounceIn()) * @param {cc.ActionInterval} action * @return {cc.EaseBounceIn} + * * @example - * // example - * var moveEaseBounceIn = cc.EaseBounceIn.create(action); + * //The old usage + * cc.EaseBounceIn.create(action); + * //The new usage + * action.easing(cc.easeBounceIn()); */ cc.EaseBounceIn.create = function (action) { return new cc.EaseBounceIn(action); }; + +cc._bounceTime = function (time1) { + if (time1 < 1 / 2.75) { + return 7.5625 * time1 * time1; + } else if (time1 < 2 / 2.75) { + time1 -= 1.5 / 2.75; + return 7.5625 * time1 * time1 + 0.75; + } else if (time1 < 2.5 / 2.75) { + time1 -= 2.25 / 2.75; + return 7.5625 * time1 * time1 + 0.9375; + } + + time1 -= 2.625 / 2.75; + return 7.5625 * time1 * time1 + 0.984375; +}; + +cc._easeBounceInObj = { + easing: function(dt){ + return 1 - cc._bounceTime(1 - dt); + }, + reverse: function(){ + return cc._easeBounceOutObj; + } +}; + +/** + * Creates the action easing object.
+ * Eased bounce effect at the beginning. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBounceIn()); + */ +cc.easeBounceIn = function(){ + return cc._easeBounceInObj; +}; + /** - * cc.EaseBounceOut action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * cc.EaseBounceOut action.
+ * Eased bounce effect at the ending. + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseBounce + * + * @deprecated since v3.0 please use action.easing(cc.easeBounceOut()) + * + * @example + * //The old usage + * cc.EaseBounceOut.create(action); + * //The new usage + * action.easing(cc.easeBounceOut()); */ cc.EaseBounceOut = cc.EaseBounce.extend(/** @lends cc.EaseBounceOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { - var newT = this.bounceTime(time1); + update:function (dt) { + var newT = this.bounceTime(dt); this._inner.update(newT); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBounceIn} */ reverse:function () { - return cc.EaseBounceIn.create(this._inner.reverse()); + return new cc.EaseBounceIn(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBounceOut} + */ clone:function(){ var action = new cc.EaseBounceOut(); action.initWithAction(this._inner.clone()); @@ -900,38 +1728,84 @@ cc.EaseBounceOut = cc.EaseBounce.extend(/** @lends cc.EaseBounceOut# */{ } }); -/** creates the action +/** + * Creates the action.
+ * Eased bounce effect at the ending. + * @static + * @deprecated since v3.0 please use action.easing(cc.easeBounceOut()) * @param {cc.ActionInterval} action * @return {cc.EaseBounceOut} + * * @example - * // example - * var moveEaseBounceOut = cc.EaseBounceOut.create(action); + * //The old usage + * cc.EaseBounceOut.create(action); + * //The new usage + * action.easing(cc.easeBounceOut()); */ cc.EaseBounceOut.create = function (action) { return new cc.EaseBounceOut(action); }; +cc._easeBounceOutObj = { + easing: function(dt){ + return cc._bounceTime(dt); + }, + reverse:function () { + return cc._easeBounceInObj; + } +}; + +/** + * Creates the action easing object.
+ * Eased bounce effect at the ending. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBounceOut()); + */ +cc.easeBounceOut = function(){ + return cc._easeBounceOutObj; +}; + /** - * cc.EaseBounceInOut action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * cc.EaseBounceInOut action.
+ * Eased bounce effect at the begining and ending. + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.EaseBounce + * + * @deprecated since v3.0
Please use acton.easing(cc.easeBounceInOut()) + * + * @example + * //The old usage + * cc.EaseBounceInOut.create(action); + * //The new usage + * action.easing(cc.easeBounceInOut()); */ cc.EaseBounceInOut = cc.EaseBounce.extend(/** @lends cc.EaseBounceInOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var newT = 0; - if (time1 < 0.5) { - time1 = time1 * 2; - newT = (1 - this.bounceTime(1 - time1)) * 0.5; + if (dt < 0.5) { + dt = dt * 2; + newT = (1 - this.bounceTime(1 - dt)) * 0.5; } else { - newT = this.bounceTime(time1 * 2 - 1) * 0.5 + 0.5; + newT = this.bounceTime(dt * 2 - 1) * 0.5 + 0.5; } this._inner.update(newT); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBounceInOut} + */ clone:function(){ var action = new cc.EaseBounceInOut(); action.initWithAction(this._inner.clone()); @@ -939,47 +1813,102 @@ cc.EaseBounceInOut = cc.EaseBounce.extend(/** @lends cc.EaseBounceInOut# */{ }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBounceInOut} */ reverse:function () { - return cc.EaseBounceInOut.create(this._inner.reverse()); + return new cc.EaseBounceInOut(this._inner.reverse()); } }); -/** creates the action +/** + * Creates the action.
+ * Eased bounce effect at the begining and ending. + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeBounceInOut()) * @param {cc.ActionInterval} action * @return {cc.EaseBounceInOut} + * * @example - * // example - * var moveEaseBounceInOut = cc.EaseBounceInOut.create(action); + * //The old usage + * cc.EaseBounceInOut.create(action); + * //The new usage + * action.easing(cc.easeBounceInOut()); */ cc.EaseBounceInOut.create = function (action) { return new cc.EaseBounceInOut(action); }; +cc._easeBounceInOutObj = { + easing: function (time1) { + var newT; + if (time1 < 0.5) { + time1 = time1 * 2; + newT = (1 - cc._bounceTime(1 - time1)) * 0.5; + } else { + newT = cc._bounceTime(time1 * 2 - 1) * 0.5 + 0.5; + } + return newT; + }, + reverse: function(){ + return cc._easeBounceInOutObj; + } +}; + +/** + * Creates the action easing object.
+ * Eased bounce effect at the begining and ending. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBounceInOut()); + */ +cc.easeBounceInOut = function(){ + return cc._easeBounceInOutObj; +}; + /** - * cc.EaseBackIn action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * cc.EaseBackIn action.
+ * In the opposite direction to move slowly, and then accelerated to the right direction. + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeBackIn()) + * + * @example + * //The old usage + * cc.EaseBackIn.create(action); + * //The new usage + * action.easing(cc.easeBackIn()); */ cc.EaseBackIn = cc.ActionEase.extend(/** @lends cc.EaseBackIn# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var overshoot = 1.70158; - time1 = time1===0 || time1==1 ? time1 : time1 * time1 * ((overshoot + 1) * time1 - overshoot); - this._inner.update(time1); + dt = dt===0 || dt===1 ? dt : dt * dt * ((overshoot + 1) * dt - overshoot); + this._inner.update(dt); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBackOut} */ reverse:function () { - return cc.EaseBackOut.create(this._inner.reverse()); + return new cc.EaseBackOut(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBackIn} + */ clone:function(){ var action = new cc.EaseBackIn(); action.initWithAction(this._inner.clone()); @@ -988,41 +1917,88 @@ cc.EaseBackIn = cc.ActionEase.extend(/** @lends cc.EaseBackIn# */{ }); -/** creates the action +/** + * Creates the cc.EaseBackIn.
+ * In the opposite direction to move slowly, and then accelerated to the right direction. + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeBackIn()) * @param {cc.ActionInterval} action * @return {cc.EaseBackIn} + * * @example - * // example - * var moveEaseBackIn = cc.EaseBackIn.create(action); + * //The old usage + * cc.EaseBackIn.create(action); + * //The new usage + * action.easing(cc.easeBackIn()); */ cc.EaseBackIn.create = function (action) { return new cc.EaseBackIn(action); }; +cc._easeBackInObj = { + easing: function (time1) { + var overshoot = 1.70158; + return (time1===0 || time1===1) ? time1 : time1 * time1 * ((overshoot + 1) * time1 - overshoot); + }, + reverse: function(){ + return cc._easeBackOutObj; + } +}; + +/** + * Creates the action easing object.
+ * In the opposite direction to move slowly, and then accelerated to the right direction. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBackIn()); + */ +cc.easeBackIn = function(){ + return cc._easeBackInObj; +}; + /** - * cc.EaseBackOut action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * cc.EaseBackOut action.
+ * Fast moving more than the finish, and then slowly back to the finish. + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.ActionEase + * + * @deprecated since v3.0 please use action.easing(cc.easeBackOut()); + * + * @example + * //The old usage + * cc.EaseBackOut.create(action); + * //The new usage + * action.easing(cc.easeBackOut()); */ cc.EaseBackOut = cc.ActionEase.extend(/** @lends cc.EaseBackOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var overshoot = 1.70158; - - time1 = time1 - 1; - this._inner.update(time1 * time1 * ((overshoot + 1) * time1 + overshoot) + 1); + dt = dt - 1; + this._inner.update(dt * dt * ((overshoot + 1) * dt + overshoot) + 1); }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBackIn} */ reverse:function () { - return cc.EaseBackIn.create(this._inner.reverse()); + return new cc.EaseBackIn(this._inner.reverse()); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBackOut} + */ clone:function(){ var action = new cc.EaseBackOut(); action.initWithAction(this._inner.clone()); @@ -1030,39 +2006,86 @@ cc.EaseBackOut = cc.ActionEase.extend(/** @lends cc.EaseBackOut# */{ } }); -/** creates the action +/** + * Creates the action.
+ * Fast moving more than the finish, and then slowly back to the finish. + * @static + * @deprecated since v3.0
Please use action.easing(cc.easeBackOut()); * @param {cc.ActionInterval} action * @return {cc.EaseBackOut} + * * @example - * // example - * var moveEaseBackOut = cc.EaseBackOut.create(action); + * //The old usage + * cc.EaseBackOut.create(action); + * //The new usage + * action.easing(cc.easeBackOut()); */ cc.EaseBackOut.create = function (action) { return new cc.EaseBackOut(action); }; +cc._easeBackOutObj = { + easing: function (time1) { + var overshoot = 1.70158; + time1 = time1 - 1; + return time1 * time1 * ((overshoot + 1) * time1 + overshoot) + 1; + }, + reverse: function(){ + return cc._easeBackInObj; + } +}; + +/** + * Creates the action easing object.
+ * Fast moving more than the finish, and then slowly back to the finish. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBackOut()); + */ +cc.easeBackOut = function(){ + return cc._easeBackOutObj; +}; + /** - * cc.EaseBackInOut action. - * @warning This action doesn't use a bijective fucntion. Actions like Sequence might have an unexpected result when used with this action. + * cc.EaseBackInOut action.
+ * Begining of cc.EaseBackIn. Ending of cc.EaseBackOut. + * @warning This action doesn't use a bijective function. Actions like Sequence might have an unexpected result when used with this action. * @class * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeBackInOut()) + * + * @example + * //The old usage + * cc.EaseBackInOut.create(action); + * //The new usage + * action.easing(cc.easeBackInOut()); */ cc.EaseBackInOut = cc.ActionEase.extend(/** @lends cc.EaseBackInOut# */{ /** - * @param {Number} time1 + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time1) { + update:function (dt) { var overshoot = 1.70158 * 1.525; - - time1 = time1 * 2; - if (time1 < 1) { - this._inner.update((time1 * time1 * ((overshoot + 1) * time1 - overshoot)) / 2); + dt = dt * 2; + if (dt < 1) { + this._inner.update((dt * dt * ((overshoot + 1) * dt - overshoot)) / 2); } else { - time1 = time1 - 2; - this._inner.update((time1 * time1 * ((overshoot + 1) * time1 + overshoot)) / 2 + 1); + dt = dt - 2; + this._inner.update((dt * dt * ((overshoot + 1) * dt + overshoot)) / 2 + 1); } }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBackInOut} + */ clone:function(){ var action = new cc.EaseBackInOut(); action.initWithAction(this._inner.clone()); @@ -1070,22 +2093,1589 @@ cc.EaseBackInOut = cc.ActionEase.extend(/** @lends cc.EaseBackInOut# */{ }, /** - * @return {cc.ActionInterval} + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBackInOut} */ reverse:function () { - return cc.EaseBackInOut.create(this._inner.reverse()); + return new cc.EaseBackInOut(this._inner.reverse()); } }); -/** creates the action +/** + * Creates the action.
+ * Begining of cc.EaseBackIn. Ending of cc.EaseBackOut. + * @static * @param {cc.ActionInterval} action * @return {cc.EaseBackInOut} + * + * @deprecated since v3.0
Please use action.easing(cc.easeBackInOut()) + * * @example - * // example - * var moveEaseBackInOut = cc.EaseBackInOut.create(action); + * //The old usage + * cc.EaseBackInOut.create(action); + * //The new usage + * action.easing(cc.easeBackInOut()); */ cc.EaseBackInOut.create = function (action) { return new cc.EaseBackInOut(action); }; +cc._easeBackInOutObj = { + easing: function (time1) { + var overshoot = 1.70158 * 1.525; + time1 = time1 * 2; + if (time1 < 1) { + return (time1 * time1 * ((overshoot + 1) * time1 - overshoot)) / 2; + } else { + time1 = time1 - 2; + return (time1 * time1 * ((overshoot + 1) * time1 + overshoot)) / 2 + 1; + } + }, + reverse: function(){ + return cc._easeBackInOutObj; + } +}; + +/** + * Creates the action easing object.
+ * Begining of cc.EaseBackIn. Ending of cc.EaseBackOut. + * @function + * @return {Object} + * @example + * // example + * action.easing(cc.easeBackInOut()); + */ +cc.easeBackInOut = function(){ + return cc._easeBackInOutObj; +}; + +/** + * cc.EaseBezierAction action.
+ * Manually set a 4 order Bessel curve.
+ * According to the set point, calculate the trajectory. + * @class + * @extends cc.ActionEase + * @param {cc.Action} action + * + * @deprecated since v3.0
Please use action.easing(cc.easeBezierAction()) + * + * @example + * //The old usage + * var action = cc.EaseBezierAction.create(action); + * action.setBezierParamer(0.5, 0.5, 1.0, 1.0); + * //The new usage + * action.easing(cc.easeBezierAction(0.5, 0.5, 1.0, 1.0)); + */ +cc.EaseBezierAction = cc.ActionEase.extend(/** @lends cc.EaseBezierAction# */{ + + _p0: null, + _p1: null, + _p2: null, + _p3: null, + + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Initialization requires the application of Bessel curve of action. + * @param {cc.Action} action + */ + ctor: function(action){ + cc.ActionEase.prototype.ctor.call(this, action); + }, + + _updateTime: function(a, b, c, d, t){ + return (Math.pow(1-t,3) * a + 3*t*(Math.pow(1-t,2))*b + 3*Math.pow(t,2)*(1-t)*c + Math.pow(t,3)*d ); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + var t = this._updateTime(this._p0, this._p1, this._p2, this._p3, dt); + this._inner.update(t); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseBezierAction} + */ + clone: function(){ + var action = new cc.EaseBezierAction(); + action.initWithAction(this._inner.clone()); + action.setBezierParamer(this._p0, this._p1, this._p2, this._p3); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseBezierAction} + */ + reverse: function(){ + var action = new cc.EaseBezierAction(this._inner.reverse()); + action.setBezierParamer(this._p3, this._p2, this._p1, this._p0); + return action; + }, + + /** + * Set of 4 reference point + * @param p0 + * @param p1 + * @param p2 + * @param p3 + */ + setBezierParamer: function(p0, p1, p2, p3){ + this._p0 = p0 || 0; + this._p1 = p1 || 0; + this._p2 = p2 || 0; + this._p3 = p3 || 0; + } +}); + +/** + * Creates the action.
+ * After creating the cc.EaseBezierAction, also need to manually call setBezierParamer.
+ * According to the set point, calculate the trajectory. + * @static + * @param action + * @returns {cc.EaseBezierAction} + * + * @deprecated since v3.0
Please use action.easing(cc.easeBezierAction()) + * + * @example + * //The old usage + * var action = cc.EaseBezierAction.create(action); + * action.setBezierParamer(0.5, 0.5, 1.0, 1.0); + * //The new usage + * action.easing(cc.easeBezierAction(0.5, 0.5, 1.0, 1.0)); + */ +cc.EaseBezierAction.create = function(action){ + return new cc.EaseBezierAction(action); +}; + +/** + * Creates the action easing object.
+ * Into the 4 reference point.
+ * To calculate the motion curve. + * @param {Number} p0 The first bezier parameter + * @param {Number} p1 The second bezier parameter + * @param {Number} p2 The third bezier parameter + * @param {Number} p3 The fourth bezier parameter + * @returns {Object} + * @example + * // example + * action.easing(cc.easeBezierAction(0.5, 0.5, 1.0, 1.0)); + */ +cc.easeBezierAction = function(p0, p1, p2, p3){ + return { + easing: function(time){ + return cc.EaseBezierAction.prototype._updateTime(p0, p1, p2, p3, time); + }, + reverse: function(){ + return cc.easeBezierAction(p3, p2, p1, p0); + } + }; +}; + +/** + * cc.EaseQuadraticActionIn action.
+ * Reference easeInQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticAction()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionIn()); + */ +cc.EaseQuadraticActionIn = cc.ActionEase.extend(/** @lends cc.EaseQuadraticActionIn# */{ + + _updateTime: function(time){ + return Math.pow(time, 2); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuadraticActionIn} + */ + clone: function(){ + var action = new cc.EaseQuadraticActionIn(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuadraticActionIn} + */ + reverse: function(){ + return new cc.EaseQuadraticActionIn(this._inner.reverse()); + } + +}); + +/** + * Creates the cc.EaseQuadRaticActionIn.
+ * Reference easeInQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @param action + * @returns {cc.EaseQuadraticActionIn} + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticAction()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionIn()); + */ +cc.EaseQuadraticActionIn.create = function(action){ + return new cc.EaseQuadraticActionIn(action); +}; + +cc._easeQuadraticActionIn = { + easing: cc.EaseQuadraticActionIn.prototype._updateTime, + reverse: function(){ + return cc._easeQuadraticActionIn; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuadraticActionIn()); + */ +cc.easeQuadraticActionIn = function(){ + return cc._easeQuadraticActionIn; +}; + +/** + * cc.EaseQuadraticActionIn action.
+ * Reference easeOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionOut()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionOut()); + */ +cc.EaseQuadraticActionOut = cc.ActionEase.extend(/** @lends cc.EaseQuadraticActionOut# */{ + + _updateTime: function(time){ + return -time*(time-2); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuadraticActionOut} + */ + clone: function(){ + var action = new cc.EaseQuadraticActionOut(); + action.initWithAction(); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuadraticActionOut} + */ + reverse: function(){ + return new cc.EaseQuadraticActionOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * @param action + * @returns {cc.EaseQuadraticActionOut} + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionOut()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionOut()); + */ +cc.EaseQuadraticActionOut.create = function(action){ + return new cc.EaseQuadraticActionOut(action); +}; + +cc._easeQuadraticActionOut = { + easing: cc.EaseQuadraticActionOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuadraticActionOut; + } +}; +/** + * Creates the action easing object.
+ * Reference easeOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuadraticActionOut()); + */ +cc.easeQuadraticActionOut = function(){ + return cc._easeQuadraticActionOut; +}; + +/** + * cc.EaseQuadraticActionInOut action.
+ * Reference easeInOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionInOut()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionInOut()); + */ +cc.EaseQuadraticActionInOut = cc.ActionEase.extend(/** @lends cc.EaseQuadraticActionInOut# */{ + _updateTime: function(time){ + var resultTime = time; + time *= 2; + if(time < 1){ + resultTime = time * time * 0.5; + }else{ + --time; + resultTime = -0.5 * ( time * ( time - 2 ) - 1) + } + return resultTime; + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuadraticActionInOut} + */ + clone: function(){ + var action = new cc.EaseQuadraticActionInOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuadraticActionInOut} + */ + reverse: function(){ + return new cc.EaseQuadraticActionInOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionInOut()) + * + * @example + * //The old usage + * cc.EaseQuadraticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionInOut()); + * + * @param action + * @returns {cc.EaseQuadraticActionInOut} + */ +cc.EaseQuadraticActionInOut.create = function(action){ + return new cc.EaseQuadraticActionInOut(action); +}; + +cc._easeQuadraticActionInOut = { + easing: cc.EaseQuadraticActionInOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuadraticActionInOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInOutQuad:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuadraticActionInOut()); + */ +cc.easeQuadraticActionInOut = function(){ + return cc._easeQuadraticActionInOut; +}; + +/** + * cc.EaseQuarticActionIn action.
+ * Reference easeInQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuarticActionIn()); + * + * @example + * //The old usage + * cc.EaseQuarticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuarticActionIn()); + */ +cc.EaseQuarticActionIn = cc.ActionEase.extend(/** @lends cc.EaseQuarticActionIn# */{ + _updateTime: function(time){ + return time * time * time * time; + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuarticActionIn} + */ + clone: function(){ + var action = new cc.EaseQuarticActionIn(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuarticActionIn} + */ + reverse: function(){ + return new cc.EaseQuarticActionIn(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuarticActionIn()); + * + * @example + * //The old usage + * cc.EaseQuarticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuarticActionIn()); + * + * @param action + * @returns {cc.EaseQuarticActionIn} + */ +cc.EaseQuarticActionIn.create = function(action){ + return new cc.EaseQuarticActionIn(action); +}; + +cc._easeQuarticActionIn = { + easing: cc.EaseQuarticActionIn.prototype._updateTime, + reverse: function(){ + return cc._easeQuarticActionIn; + } +}; +/** + * Creates the action easing object.
+ * Reference easeIntQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuarticActionIn()); + */ +cc.easeQuarticActionIn = function(){ + return cc._easeQuarticActionIn; +}; + +/** + * cc.EaseQuarticActionOut action.
+ * Reference easeOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.QuarticActionOut()); + * + * @example + * //The old usage + * cc.EaseQuarticActionOut.create(action); + * //The new usage + * action.easing(cc.EaseQuarticActionOut()); + */ +cc.EaseQuarticActionOut = cc.ActionEase.extend(/** @lends cc.EaseQuarticActionOut# */{ + _updateTime: function(time){ + time -= 1; + return -(time * time * time * time - 1); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuarticActionOut} + */ + clone: function(){ + var action = new cc.EaseQuarticActionOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuarticActionOut} + */ + reverse: function(){ + return new cc.EaseQuarticActionOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.QuarticActionOut()); + * + * @example + * //The old usage + * cc.EaseQuarticActionOut.create(action); + * //The new usage + * action.easing(cc.EaseQuarticActionOut()); + * + * @param action + * @returns {cc.EaseQuarticActionOut} + */ +cc.EaseQuarticActionOut.create = function(action){ + return new cc.EaseQuarticActionOut(action); +}; + +cc._easeQuarticActionOut = { + easing: cc.EaseQuarticActionOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuarticActionOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.QuarticActionOut()); + */ +cc.easeQuarticActionOut = function(){ + return cc._easeQuarticActionOut; +}; + +/** + * cc.EaseQuarticActionInOut action.
+ * Reference easeInOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuarticActionInOut()); + * + * @example + * //The old usage + * cc.EaseQuarticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuarticActionInOut()); + */ +cc.EaseQuarticActionInOut = cc.ActionEase.extend(/** @lends cc.EaseQuarticActionInOut# */{ + _updateTime: function(time){ + time = time*2; + if (time < 1) + return 0.5 * time * time * time * time; + time -= 2; + return -0.5 * (time * time * time * time - 2); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuarticActionInOut} + */ + clone: function(){ + var action = new cc.EaseQuarticActionInOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuarticActionInOut} + */ + reverse: function(){ + return new cc.EaseQuarticActionInOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuarticActionInOut()); + * + * @example + * //The old usage + * cc.EaseQuarticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuarticActionInOut()); + * + * @param action + * @returns {cc.EaseQuarticActionInOut} + */ +cc.EaseQuarticActionInOut.create = function(action){ + return new cc.EaseQuarticActionInOut(action); +}; + +cc._easeQuarticActionInOut = { + easing: cc.EaseQuarticActionInOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuarticActionInOut; + } +}; +/** + * Creates the action easing object.
+ * Reference easeInOutQuart:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + */ +cc.easeQuarticActionInOut = function(){ + return cc._easeQuarticActionInOut; +}; + +/** + * cc.EaseQuinticActionIn action.
+ * Reference easeInQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuinticActionIn()); + * + * @example + * //The old usage + * cc.EaseQuinticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuinticActionIn()); + */ +cc.EaseQuinticActionIn = cc.ActionEase.extend(/** @lends cc.EaseQuinticActionIn# */{ + _updateTime: function(time){ + return time * time * time * time * time; + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuinticActionIn} + */ + clone: function(){ + var action = new cc.EaseQuinticActionIn(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuinticActionIn} + */ + reverse: function(){ + return new cc.EaseQuinticActionIn(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuinticActionIn()); + * + * @example + * //The old usage + * cc.EaseQuinticActionIn.create(action); + * //The new usage + * action.easing(cc.easeQuinticActionIn()); + * + * @param action + * @returns {cc.EaseQuinticActionIn} + */ +cc.EaseQuinticActionIn.create = function(action){ + return new cc.EaseQuinticActionIn(action); +}; + +cc._easeQuinticActionIn = { + easing: cc.EaseQuinticActionIn.prototype._updateTime, + reverse: function(){ + return cc._easeQuinticActionIn; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuinticActionIn()); + */ +cc.easeQuinticActionIn = function(){ + return cc._easeQuinticActionIn; +}; + +/** + * cc.EaseQuinticActionOut action.
+ * Reference easeQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionOut()); + * + * @example + * //The old usage + * cc.EaseQuinticActionOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionOut()); + */ +cc.EaseQuinticActionOut = cc.ActionEase.extend(/** @lends cc.EaseQuinticActionOut# */{ + _updateTime: function(time){ + time -=1; + return (time * time * time * time * time + 1); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuinticActionOut} + */ + clone: function(){ + var action = new cc.EaseQuinticActionOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuinticActionOut} + */ + reverse: function(){ + return new cc.EaseQuinticActionOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeOutQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuadraticActionOut()); + * + * @example + * //The old usage + * cc.EaseQuinticActionOut.create(action); + * //The new usage + * action.easing(cc.easeQuadraticActionOut()); + * + * @param action + * @returns {cc.EaseQuinticActionOut} + */ +cc.EaseQuinticActionOut.create = function(action){ + return new cc.EaseQuinticActionOut(action); +}; + +cc._easeQuinticActionOut = { + easing: cc.EaseQuinticActionOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuinticActionOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeOutQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuadraticActionOut()); + */ +cc.easeQuinticActionOut = function(){ + return cc._easeQuinticActionOut; +}; + +/** + * cc.EaseQuinticActionInOut action.
+ * Reference easeInOutQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuinticActionInOut()); + * + * @example + * //The old usage + * cc.EaseQuinticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuinticActionInOut()); + */ +cc.EaseQuinticActionInOut = cc.ActionEase.extend(/** @lends cc.EaseQuinticActionInOut# */{ + _updateTime: function(time){ + time = time*2; + if (time < 1) + return 0.5 * time * time * time * time * time; + time -= 2; + return 0.5 * (time * time * time * time * time + 2); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseQuinticActionInOut} + */ + clone: function(){ + var action = new cc.EaseQuinticActionInOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseQuinticActionInOut} + */ + reverse: function(){ + return new cc.EaseQuinticActionInOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInOutQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeQuinticActionInOut()); + * + * @example + * //The old usage + * cc.EaseQuinticActionInOut.create(action); + * //The new usage + * action.easing(cc.easeQuinticActionInOut()); + * + * @param action + * @returns {cc.EaseQuinticActionInOut} + */ +cc.EaseQuinticActionInOut.create = function(action){ + return new cc.EaseQuinticActionInOut(action); +}; + +cc._easeQuinticActionInOut = { + easing: cc.EaseQuinticActionInOut.prototype._updateTime, + reverse: function(){ + return cc._easeQuinticActionInOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInOutQuint:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeQuinticActionInOut()); + */ +cc.easeQuinticActionInOut = function(){ + return cc._easeQuinticActionInOut; +}; + +/** + * cc.EaseCircleActionIn action.
+ * Reference easeInCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionIn()); + * + * @example + * //The old usage + * cc.EaseCircleActionIn.create(action); + * //The new usage + * action.easing(cc.easeCircleActionIn()); + */ +cc.EaseCircleActionIn = cc.ActionEase.extend(/** @lends cc.EaseCircleActionIn# */{ + _updateTime: function(time){ + return -1 * (Math.sqrt(1 - time * time) - 1); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCircleActionIn} + */ + clone: function(){ + var action = new cc.EaseCircleActionIn(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCircleActionIn} + */ + reverse: function(){ + return new cc.EaseCircleActionIn(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionIn()); + * + * @example + * //The old usage + * cc.EaseCircleActionIn.create(action); + * //The new usage + * action.easing(cc.easeCircleActionIn()); + * + * @param action + * @returns {cc.EaseCircleActionIn} + */ +cc.EaseCircleActionIn.create = function(action){ + return new cc.EaseCircleActionIn(action); +}; + +cc._easeCircleActionIn = { + easing: cc.EaseCircleActionIn.prototype._updateTime, + reverse: function(){ + return cc._easeCircleActionIn; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeCircleActionIn()); + */ +cc.easeCircleActionIn = function(){ + return cc._easeCircleActionIn; +}; + +/** + * cc.EaseCircleActionOut action.
+ * Reference easeOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionOut()); + * + * @example + * //The old usage + * cc.EaseCircleActionOut.create(action); + * //The new usage + * action.easing(cc.easeCircleActionOut()); + */ +cc.EaseCircleActionOut = cc.ActionEase.extend(/** @lends cc.EaseCircleActionOut# */{ + _updateTime: function(time){ + time = time - 1; + return Math.sqrt(1 - time * time); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCircleActionOut} + */ + clone: function(){ + var action = new cc.EaseCircleActionOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCircleActionOut} + */ + reverse: function(){ + return new cc.EaseCircleActionOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionOut()); + * + * @example + * //The old usage + * cc.EaseCircleActionOut.create(action); + * //The new usage + * action.easing(cc.easeCircleActionOut()); + * + * @param action + * @returns {cc.EaseCircleActionOut} + */ +cc.EaseCircleActionOut.create = function(action){ + return new cc.EaseCircleActionOut(action); +}; + +cc._easeCircleActionOut = { + easing: cc.EaseCircleActionOut.prototype._updateTime, + reverse: function(){ + return cc._easeCircleActionOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @exampple + * //example + * actioneasing(cc.easeCircleActionOut()); + */ +cc.easeCircleActionOut = function(){ + return cc._easeCircleActionOut; +}; + +/** + * cc.EaseCircleActionInOut action.
+ * Reference easeInOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionInOut()); + * + * @example + * //The old usage + * cc.EaseCircleActionInOut.create(action); + * //The new usage + * action.easing(cc.easeCircleActionInOut()); + */ +cc.EaseCircleActionInOut = cc.ActionEase.extend(/** @lends cc.EaseCircleActionInOut# */{ + _updateTime: function(time){ + time = time * 2; + if (time < 1) + return -0.5 * (Math.sqrt(1 - time * time) - 1); + time -= 2; + return 0.5 * (Math.sqrt(1 - time * time) + 1); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCircleActionInOut} + */ + clone: function(){ + var action = new cc.EaseCircleActionInOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCircleActionInOut} + */ + reverse: function(){ + return new cc.EaseCircleActionInOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeCircleActionInOut()); + * + * @example + * //The old usage + * cc.EaseCircleActionInOut.create(action); + * //The new usage + * action.easing(cc.easeCircleActionInOut()); + * + * @param action + * @returns {cc.EaseCircleActionInOut} + */ +cc.EaseCircleActionInOut.create = function(action){ + return new cc.EaseCircleActionInOut(action); +}; + +cc._easeCircleActionInOut = { + easing: cc.EaseCircleActionInOut.prototype._updateTime, + reverse: function(){ + return cc._easeCircleActionInOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInOutCirc:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeCircleActionInOut()); + */ +cc.easeCircleActionInOut = function(){ + return cc._easeCircleActionInOut; +}; + +/** + * cc.EaseCubicActionIn action.
+ * Reference easeInCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
action.easing(cc.easeCubicActionIn()); + * + * @example + * //The old usage + * cc.EaseCubicActionIn.create(action); + * //The new usage + * action.easing(cc.easeCubicActionIn()); + */ +cc.EaseCubicActionIn = cc.ActionEase.extend(/** @lends cc.EaseCubicActionIn# */{ + _updateTime: function(time){ + return time * time * time; + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCubicActionIn} + */ + clone: function(){ + var action = new cc.EaseCubicActionIn(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCubicActionIn} + */ + reverse: function(){ + return new cc.EaseCubicActionIn(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
action.easing(cc.easeCubicActionIn()); + * + * @example + * //The old usage + * cc.EaseCubicActionIn.create(action); + * //The new usage + * action.easing(cc.easeCubicActionIn()); + * + * @param action + * @returns {cc.EaseCubicActionIn} + */ +cc.EaseCubicActionIn.create = function(action){ + return new cc.EaseCubicActionIn(action); +}; + +cc._easeCubicActionIn = { + easing: cc.EaseCubicActionIn.prototype._updateTime, + reverse: function(){ + return cc._easeCubicActionIn; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeCubicActionIn()); + */ +cc.easeCubicActionIn = function(){ + return cc._easeCubicActionIn; +}; + +/** + * cc.EaseCubicActionOut action.
+ * Reference easeOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeCubicActionOut()); + * + * @example + * //The old usage + * cc.EaseCubicActionOut.create(action); + * //The new usage + * action.easing(cc.easeCubicActionOut()); + */ +cc.EaseCubicActionOut = cc.ActionEase.extend(/** @lends cc.EaseCubicActionOut# */{ + _updateTime: function(time){ + time -= 1; + return (time * time * time + 1); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCubicActionOut} + */ + clone: function(){ + var action = new cc.EaseCubicActionOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCubicActionOut} + */ + reverse: function(){ + return new cc.EaseCubicActionOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeCubicActionOut()); + * + * @example + * //The old usage + * cc.EaseCubicActionOut.create(action); + * //The new usage + * action.easing(cc.easeCubicActionOut()); + * + * @param action + * @returns {cc.EaseCubicActionOut} + */ +cc.EaseCubicActionOut.create = function(action){ + return new cc.EaseCubicActionOut(action); +}; + +cc._easeCubicActionOut = { + easing: cc.EaseCubicActionOut.prototype._updateTime, + reverse: function(){ + return cc._easeCubicActionOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + * @example + * //example + * action.easing(cc.easeCubicActionOut()); + */ +cc.easeCubicActionOut = function(){ + return cc._easeCubicActionOut; +}; + +/** + * cc.EaseCubicActionInOut action.
+ * Reference easeInOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @class + * @extends cc.ActionEase + * + * @deprecated since v3.0
Please use action.easing(cc.easeCubicActionInOut()); + * + * @example + * //The old usage + * cc.EaseCubicActionInOut.create(action); + * //The new usage + * action.easing(cc.easeCubicActionInOut()); + */ +cc.EaseCubicActionInOut = cc.ActionEase.extend(/** @lends cc.EaseCubicActionInOut# */{ + _updateTime: function(time){ + time = time*2; + if (time < 1) + return 0.5 * time * time * time; + time -= 2; + return 0.5 * (time * time * time + 2); + }, + + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update: function(dt){ + this._inner.update(this._updateTime(dt)); + }, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @returns {cc.EaseCubicActionInOut} + */ + clone: function(){ + var action = new cc.EaseCubicActionInOut(); + action.initWithAction(this._inner.clone()); + return action; + }, + + /** + * Create a action. Opposite with the original motion trajectory. + * @return {cc.EaseCubicActionInOut} + */ + reverse: function(){ + return new cc.EaseCubicActionInOut(this._inner.reverse()); + } +}); + +/** + * Creates the action.
+ * Reference easeInOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @static + * + * @deprecated since v3.0
Please use action.easing(cc.easeCubicActionInOut()); + * + * @example + * //The old usage + * cc.EaseCubicActionInOut.create(action); + * //The new usage + * action.easing(cc.easeCubicActionInOut()); + * + * @param action + * @returns {cc.EaseCubicActionInOut} + */ +cc.EaseCubicActionInOut.create = function(action){ + return new cc.EaseCubicActionInOut(action); +}; + +cc._easeCubicActionInOut = { + easing: cc.EaseCubicActionInOut.prototype._updateTime, + reverse: function(){ + return cc._easeCubicActionInOut; + } +}; + +/** + * Creates the action easing object.
+ * Reference easeInOutCubic:
+ * {@link http://www.zhihu.com/question/21981571/answer/19925418} + * @function + * @returns {Object} + */ +cc.easeCubicActionInOut = function(){ + return cc._easeCubicActionInOut; +}; + diff --git a/cocos2d/actions/CCActionInstant.js b/cocos2d/actions/CCActionInstant.js index b2313e64a6..55f3c09be0 100644 --- a/cocos2d/actions/CCActionInstant.js +++ b/cocos2d/actions/CCActionInstant.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,13 +25,14 @@ ****************************************************************************/ /** - * Instant actions are immediate actions. They don't have a duration like + * Instant actions are immediate actions. They don't have a duration like. * the CCIntervalAction actions. * @class * @extends cc.FiniteTimeAction */ cc.ActionInstant = cc.FiniteTimeAction.extend(/** @lends cc.ActionInstant# */{ /** + * return true if the action has finished. * @return {Boolean} */ isDone:function () { @@ -39,6 +40,8 @@ cc.ActionInstant = cc.FiniteTimeAction.extend(/** @lends cc.ActionInstant# */{ }, /** + * called every frame with it's delta time.
+ * DON'T override unless you know what you are doing. * @param {Number} dt */ step:function (dt) { @@ -46,135 +49,230 @@ cc.ActionInstant = cc.FiniteTimeAction.extend(/** @lends cc.ActionInstant# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { //nothing }, + /** + * returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * @returns {cc.Action} + */ reverse:function(){ return this.clone(); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.FiniteTimeAction} + */ clone:function(){ return new cc.ActionInstant(); } }); -/** Show the node +/** + * Show the node. * @class * @extends cc.ActionInstant */ cc.Show = cc.ActionInstant.extend(/** @lends cc.Show# */{ + /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { this.target.visible = true; }, /** - * @return {cc.FiniteTimeAction} + * returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * @returns {cc.Hide} */ reverse:function () { - return cc.Hide.create(); + return new cc.Hide(); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.FiniteTimeAction} + */ clone:function(){ return new cc.Show(); } }); + /** + * Show the Node. + * @function * @return {cc.Show} * @example * // example - * var showAction = cc.Show.create(); + * var showAction = cc.show(); */ -cc.Show.create = function () { +cc.show = function () { return new cc.Show(); }; /** - * Hide the node + * Show the Node. Please use cc.show instead. + * @static + * @deprecated since v3.0
Please use cc.show instead. + * @return {cc.Show} + */ +cc.Show.create = cc.show; + +/** + * Hide the node. * @class * @extends cc.ActionInstant */ cc.Hide = cc.ActionInstant.extend(/** @lends cc.Hide# */{ + /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { this.target.visible = false; }, /** - * @return {cc.FiniteTimeAction} + * returns a reversed action.
+ * For example:
+ * - The action will be x coordinates of 0 move to 100.
+ * - The reversed action will be x of 100 move to 0. + * - Will be rewritten + * @returns {cc.Show} */ reverse:function () { - return cc.Show.create(); + return new cc.Show(); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.Hide} + */ clone:function(){ return new cc.Hide(); } }); + /** + * Hide the node. + * @function * @return {cc.Hide} * @example * // example - * var hideAction = cc.Hide.create(); + * var hideAction = cc.hide(); */ -cc.Hide.create = function () { +cc.hide = function () { return new cc.Hide(); }; +/** + * Hide the node. Please use cc.hide instead. + * @static + * @deprecated since v3.0
Please use cc.hide instead. + * @return {cc.Hide} + * @example + * // example + * var hideAction = cc.hide(); + */ +cc.Hide.create = cc.hide; -/** Toggles the visibility of a node +/** + * Toggles the visibility of a node. * @class * @extends cc.ActionInstant */ cc.ToggleVisibility = cc.ActionInstant.extend(/** @lends cc.ToggleVisibility# */{ + /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { this.target.visible = !this.target.visible; }, /** - * @return {cc.ToggleVisibility} + * returns a reversed action. + * @returns {cc.ToggleVisibility} */ reverse:function () { return new cc.ToggleVisibility(); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.ToggleVisibility} + */ clone:function(){ return new cc.ToggleVisibility(); } }); /** + * Toggles the visibility of a node. + * @function * @return {cc.ToggleVisibility} * @example * // example - * var toggleVisibilityAction = cc.ToggleVisibility.create(); + * var toggleVisibilityAction = cc.toggleVisibility(); */ -cc.ToggleVisibility.create = function () { +cc.toggleVisibility = function () { return new cc.ToggleVisibility(); }; +/** + * Toggles the visibility of a node. Please use cc.toggleVisibility instead. + * @static + * @deprecated since v3.0
Please use cc.toggleVisibility instead. + * @return {cc.ToggleVisibility} + */ +cc.ToggleVisibility.create = cc.toggleVisibility; + +/** + * Delete self in the next frame. + * @class + * @extends cc.ActionInstant + * @param {Boolean} [isNeedCleanUp=true] + * + * @example + * // example + * var removeSelfAction = new cc.RemoveSelf(false); + */ cc.RemoveSelf = cc.ActionInstant.extend({ _isNeedCleanUp: true, /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
* Create a RemoveSelf object with a flag indicate whether the target should be cleaned up while removing. - * - * @constructor * @param {Boolean} [isNeedCleanUp=true] - * - * @example - * // example - * var removeSelfAction = new cc.RemoveSelf(false); */ ctor:function(isNeedCleanUp){ cc.FiniteTimeAction.prototype.ctor.call(this); @@ -182,19 +280,38 @@ cc.RemoveSelf = cc.ActionInstant.extend({ isNeedCleanUp !== undefined && this.init(isNeedCleanUp); }, - update:function(time){ + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function(dt){ this.target.removeFromParent(this._isNeedCleanUp); }, + /** + * Initialization of the node, please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. + * @param isNeedCleanUp + * @returns {boolean} + */ init:function(isNeedCleanUp){ this._isNeedCleanUp = isNeedCleanUp; return true; }, + /** + * returns a reversed action. + */ reverse:function(){ return new cc.RemoveSelf(this._isNeedCleanUp); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.RemoveSelf} + */ clone:function(){ return new cc.RemoveSelf(this._isNeedCleanUp); } @@ -203,33 +320,45 @@ cc.RemoveSelf = cc.ActionInstant.extend({ /** * Create a RemoveSelf object with a flag indicate whether the target should be cleaned up while removing. * + * @function * @param {Boolean} [isNeedCleanUp=true] * @return {cc.RemoveSelf} * * @example * // example - * var removeSelfAction = cc.RemoveSelf.create(); + * var removeSelfAction = cc.removeSelf(); */ -cc.RemoveSelf.create = function(isNeedCleanUp){ +cc.removeSelf = function(isNeedCleanUp){ return new cc.RemoveSelf(isNeedCleanUp); }; /** - * Flips the sprite horizontally + * Please use cc.removeSelf instead. + * Create a RemoveSelf object with a flag indicate whether the target should be cleaned up while removing. + * + * @static + * @deprecated since v3.0
Please use cc.removeSelf instead. + * @param {Boolean} [isNeedCleanUp=true] + * @return {cc.RemoveSelf} + */ +cc.RemoveSelf.create = cc.removeSelf; + +/** + * Flips the sprite horizontally. * @class * @extends cc.ActionInstant + * @param {Boolean} flip Indicate whether the target should be flipped or not + * + * @example + * var flipXAction = new cc.FlipX(true); */ cc.FlipX = cc.ActionInstant.extend(/** @lends cc.FlipX# */{ _flippedX:false, /** - * Create a FlipX action to flip or unflip the target - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a FlipX action to flip or unflip the target. * @param {Boolean} flip Indicate whether the target should be flipped or not - * - * @example - * var flipXAction = new cc.FlipX(true); */ ctor:function(flip){ cc.FiniteTimeAction.prototype.ctor.call(this); @@ -238,6 +367,7 @@ cc.FlipX = cc.ActionInstant.extend(/** @lends cc.FlipX# */{ }, /** + * initializes the action with a set flipX. * @param {Boolean} flip * @return {Boolean} */ @@ -247,19 +377,28 @@ cc.FlipX = cc.ActionInstant.extend(/** @lends cc.FlipX# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { this.target.flippedX = this._flippedX; }, /** - * @return {cc.FiniteTimeAction} + * returns a reversed action. + * @return {cc.FlipX} */ reverse:function () { - return cc.FlipX.create(!this._flippedX); + return new cc.FlipX(!this._flippedX); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.FiniteTimeAction} + */ clone:function(){ var action = new cc.FlipX(); action.initWithFlipX(this._flippedX); @@ -268,32 +407,45 @@ cc.FlipX = cc.ActionInstant.extend(/** @lends cc.FlipX# */{ }); /** - * Create a FlipX action to flip or unflip the target + * Create a FlipX action to flip or unflip the target. * + * @function * @param {Boolean} flip Indicate whether the target should be flipped or not * @return {cc.FlipX} * @example - * var flipXAction = cc.FlipX.create(true); + * var flipXAction = cc.flipX(true); */ -cc.FlipX.create = function (flip) { +cc.flipX = function (flip) { return new cc.FlipX(flip); }; +/** + * Plese use cc.flipX instead. + * Create a FlipX action to flip or unflip the target + * + * @static + * @deprecated since v3.0
Plese use cc.flipX instead. + * @param {Boolean} flip Indicate whether the target should be flipped or not + * @return {cc.FlipX} + */ +cc.FlipX.create = cc.flipX; + /** * Flips the sprite vertically * @class * @extends cc.ActionInstant + * @param {Boolean} flip + * @example + * var flipYAction = new cc.FlipY(true); */ cc.FlipY = cc.ActionInstant.extend(/** @lends cc.FlipY# */{ _flippedY:false, /** - * Create a FlipY action to flip or unflip the target + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a FlipY action to flip or unflip the target. * - * @constructor * @param {Boolean} flip - * @example - * var flipYAction = new cc.FlipY(true); */ ctor: function(flip){ cc.FiniteTimeAction.prototype.ctor.call(this); @@ -301,7 +453,9 @@ cc.FlipY = cc.ActionInstant.extend(/** @lends cc.FlipY# */{ flip !== undefined && this.initWithFlipY(flip); }, + /** + * initializes the action with a set flipY. * @param {Boolean} flip * @return {Boolean} */ @@ -311,56 +465,78 @@ cc.FlipY = cc.ActionInstant.extend(/** @lends cc.FlipY# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { - //this._super(); + update:function (dt) { this.target.flippedY = this._flippedY; }, /** - * @return {cc.FiniteTimeAction} + * returns a reversed action. + * @return {cc.FlipY} */ reverse:function () { - return cc.FlipY.create(!this._flippedY); + return new cc.FlipY(!this._flippedY); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.FlipY} + */ clone:function(){ var action = new cc.FlipY(); action.initWithFlipY(this._flippedY); return action; } }); + /** - * Create a FlipY action to flip or unflip the target + * Create a FlipY action to flip or unflip the target. * + * @function * @param {Boolean} flip * @return {cc.FlipY} * @example - * var flipYAction = cc.FlipY.create(true); + * var flipYAction = cc.flipY(true); */ -cc.FlipY.create = function (flip) { +cc.flipY = function (flip) { return new cc.FlipY(flip); }; +/** + * Please use cc.flipY instead + * Create a FlipY action to flip or unflip the target + * + * @static + * @deprecated since v3.0
Please use cc.flipY instead. + * @param {Boolean} flip + * @return {cc.FlipY} + */ +cc.FlipY.create = cc.flipY; -/** Places the node in a certain position +/** + * Places the node in a certain position * @class * @extends cc.ActionInstant + * @param {cc.Point|Number} pos + * @param {Number} [y] + * @example + * var placeAction = new cc.Place(cc.p(200, 200)); + * var placeAction = new cc.Place(200, 200); */ cc.Place = cc.ActionInstant.extend(/** @lends cc.Place# */{ _x: 0, _y: 0, /** - * Creates a Place action with a position - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates a Place action with a position. * @param {cc.Point|Number} pos * @param {Number} [y] - * @example - * var placeAction = new cc.Place.create(cc.p(200, 200)); - * var placeAction = new cc.Place.create(200, 200); */ ctor:function(pos, y){ cc.FiniteTimeAction.prototype.ctor.call(this); @@ -376,8 +552,10 @@ cc.Place = cc.ActionInstant.extend(/** @lends cc.Place# */{ } }, - /** Initializes a Place action with a position - * @param {cc.Point} pos + /** + * Initializes a Place action with a position + * @param {number} x + * @param {number} y * @return {Boolean} */ initWithPosition: function (x, y) { @@ -387,36 +565,68 @@ cc.Place = cc.ActionInstant.extend(/** @lends cc.Place# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { + update:function (dt) { this.target.setPosition(this._x, this._y); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.Place} + */ clone:function(){ var action = new cc.Place(); action.initWithPosition(this._x, this._y); return action; } }); + /** - * Creates a Place action with a position + * Creates a Place action with a position. + * @function * @param {cc.Point|Number} pos * @param {Number} [y] * @return {cc.Place} * @example * // example - * var placeAction = cc.Place.create(cc.p(200, 200)); - * var placeAction = cc.Place.create(200, 200); + * var placeAction = cc.place(cc.p(200, 200)); + * var placeAction = cc.place(200, 200); */ -cc.Place.create = function (pos, y) { +cc.place = function (pos, y) { return new cc.Place(pos, y); }; +/** + * Please use cc.place instead. + * Creates a Place action with a position. + * @static + * @deprecated since v3.0
Please use cc.place instead. + * @param {cc.Point|Number} pos + * @param {Number} [y] + * @return {cc.Place} + */ +cc.Place.create = cc.place; + -/** Calls a 'callback' +/** + * Calls a 'callback'. * @class * @extends cc.ActionInstant + * @param {function} selector + * @param {object|null} [selectorTarget] + * @param {*|null} [data] data for function, it accepts all data types. + * @example + * // example + * // CallFunc without data + * var finish = new cc.CallFunc(this.removeSprite, this); + * + * // CallFunc with data + * var finish = new cc.CallFunc(this.removeFromParentAndCleanup, this, true); */ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ _selectorTarget:null, @@ -425,19 +635,11 @@ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ _data:null, /** - * Creates a CallFunc action with the callback - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates a CallFunc action with the callback. * @param {function} selector * @param {object|null} [selectorTarget] * @param {*|null} [data] data for function, it accepts all data types. - * @example - * // example - * // CallFunc without data - * var finish = new cc.CallFunc(this.removeSprite, this); - * - * // CallFunc with data - * var finish = new cc.CallFunc(this.removeFromParentAndCleanup, this, true); */ ctor:function(selector, selectorTarget, data){ cc.FiniteTimeAction.prototype.ctor.call(this); @@ -478,14 +680,16 @@ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ - update:function (time) { - //this._super(target); + update:function (dt) { this.execute(); }, /** + * Get selectorTarget. * @return {object} */ getTargetCallback:function () { @@ -493,26 +697,23 @@ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ }, /** + * Set selectorTarget. * @param {object} sel */ setTargetCallback:function (sel) { - if (sel != this._selectorTarget) { + if (sel !== this._selectorTarget) { if (this._selectorTarget) this._selectorTarget = null; this._selectorTarget = sel; } }, - copy:function() { - var n = new cc.CallFunc(); - if(this._selectorTarget){ - n.initWithFunction(this._callFunc, this._selectorTarget, this._data) - }else if(this._function){ - n.initWithFunction(this._function); - } - return n; - }, - + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.CallFunc} + */ clone:function(){ var action = new cc.CallFunc(); if(this._selectorTarget){ @@ -523,8 +724,10 @@ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ return action; } }); + /** * Creates the action with the callback + * @function * @param {function} selector * @param {object|null} [selectorTarget] * @param {*|null} [data] data for function, it accepts all data types. @@ -532,11 +735,23 @@ cc.CallFunc = cc.ActionInstant.extend(/** @lends cc.CallFunc# */{ * @example * // example * // CallFunc without data - * var finish = cc.CallFunc.create(this.removeSprite, this); + * var finish = cc.callFunc(this.removeSprite, this); * * // CallFunc with data - * var finish = cc.CallFunc.create(this.removeFromParentAndCleanup, this._grossini, true); + * var finish = cc.callFunc(this.removeFromParentAndCleanup, this._grossini, true); */ -cc.CallFunc.create = function (selector, selectorTarget, data) { +cc.callFunc = function (selector, selectorTarget, data) { return new cc.CallFunc(selector, selectorTarget, data); }; + +/** + * Please use cc.callFunc instead. + * Creates the action with the callback. + * @static + * @deprecated since v3.0
Please use cc.callFunc instead. + * @param {function} selector + * @param {object|null} [selectorTarget] + * @param {*|null} [data] data for function, it accepts all data types. + * @return {cc.CallFunc} + */ +cc.CallFunc.create = cc.callFunc; diff --git a/cocos2d/actions/CCActionInterval.js b/cocos2d/actions/CCActionInterval.js index 9eece2b601..67e1b853e1 100644 --- a/cocos2d/actions/CCActionInterval.js +++ b/cocos2d/actions/CCActionInterval.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -39,34 +39,45 @@ * * @class * @extends cc.FiniteTimeAction - * @Example - * // example - * var pingPongAction = cc.Sequence.create(action, action.reverse()); + * @param {Number} d duration in seconds + * @example + * var actionInterval = new cc.ActionInterval(3); */ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ _elapsed:0, _firstTick:false, + _easeList: null, + _timesForRepeat:1, + _repeatForever: false, + _repeatMethod: false,//Compatible with repeat class, Discard after can be deleted + _speed: 1, + _speedMethod: false,//Compatible with speed class, Discard after can be deleted /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} d duration in seconds - * @example - * var actionInterval = new cc.ActionInterval(3); */ ctor:function (d) { + this._speed = 1; + this._timesForRepeat = 1; + this._repeatForever = false; + this.MAX_VALUE = 2; + this._repeatMethod = false;//Compatible with repeat class, Discard after can be deleted + this._speedMethod = false;//Compatible with repeat class, Discard after can be deleted cc.FiniteTimeAction.prototype.ctor.call(this); - d !== undefined && this.initWithDuration(d); }, - /** how many seconds had elapsed since the actions started to run. + /** + * How many seconds had elapsed since the actions started to run. * @return {Number} */ getElapsed:function () { return this._elapsed; }, - /** initializes the action + /** + * Initializes the action. * @param {Number} d duration in seconds * @return {Boolean} */ @@ -80,7 +91,8 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ return true; }, - /** returns true if the action has finished + /** + * Returns true if the action has finished. * @return {Boolean} */ isDone:function () { @@ -88,15 +100,71 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ }, /** - * returns a new clone of the action + * Some additional parameters of cloning. + * @param {cc.Action} action + * @private + */ + _cloneDecoration: function(action){ + action._repeatForever = this._repeatForever; + action._speed = this._speed; + action._timesForRepeat = this._timesForRepeat; + action._easeList = this._easeList; + action._speedMethod = this._speedMethod; + action._repeatMethod = this._repeatMethod; + }, + + _reverseEaseList: function(action){ + if(this._easeList){ + action._easeList = []; + for(var i=0; i + * DON'T override unless you know what you are doing. + * + * @param {Number} dt */ step:function (dt) { if (this._firstTick) { @@ -110,9 +178,24 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ var t = this._elapsed / (this._duration > 0.0000001192092896 ? this._duration : 0.0000001192092896); t = (1 > t ? t : 1); this.update(t > 0 ? t : 0); + + //Compatible with repeat class, Discard after can be deleted (this._repeatMethod) + if(this._repeatMethod && this._timesForRepeat > 1 && this.isDone()){ + if(!this._repeatForever){ + this._timesForRepeat--; + } + //var diff = locInnerAction.getElapsed() - locInnerAction._duration; + this.startWithTarget(this.target); + // to prevent jerk. issue #390 ,1247 + //this._innerAction.step(0); + //this._innerAction.step(diff); + this.step(this._elapsed - this._duration); + + } }, /** + * Start this action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -122,7 +205,10 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ }, /** - * @return {Null} + * returns a reversed action.
+ * Will be overwrite. + * + * @return {null} */ reverse:function () { cc.log("cc.IntervalAction: reverse not implemented."); @@ -130,6 +216,8 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ }, /** + * Set amplitude rate. + * @warning It should be overridden in subclass. * @param {Number} amp */ setAmplitudeRate:function (amp) { @@ -138,45 +226,127 @@ cc.ActionInterval = cc.FiniteTimeAction.extend(/** @lends cc.ActionInterval# */{ }, /** - * @return {Number} + * Get amplitude rate. + * @warning It should be overridden in subclass. + * @return {Number} 0 */ getAmplitudeRate:function () { // Abstract class needs implementation cc.log("cc.ActionInterval.getAmplitudeRate(): it should be overridden in subclass."); + return 0; + }, + + /** + * Changes the speed of an action, making it take longer (speed>1) + * or less (speed<1) time.
+ * Useful to simulate 'slow motion' or 'fast forward' effect. + * + * @param speed + * @returns {cc.Action} + */ + speed: function(speed){ + if(speed <= 0){ + cc.log("The speed parameter error"); + return this; + } + + this._speedMethod = true;//Compatible with repeat class, Discard after can be deleted + this._speed *= speed; + return this; + }, + + /** + * Get this action speed. + * @return {Number} + */ + getSpeed: function(){ + return this._speed; + }, + + /** + * Set this action speed. + * @param {Number} speed + * @returns {cc.ActionInterval} + */ + setSpeed: function(speed){ + this._speed = speed; + return this; + }, + + /** + * Repeats an action a number of times. + * To repeat an action forever use the CCRepeatForever action. + * @param times + * @returns {cc.ActionInterval} + */ + repeat: function(times){ + times = Math.round(times); + if(isNaN(times) || times < 1){ + cc.log("The repeat parameter error"); + return this; + } + this._repeatMethod = true;//Compatible with repeat class, Discard after can be deleted + this._timesForRepeat *= times; + return this; + }, + + /** + * Repeats an action for ever.
+ * To repeat the an action for a limited number of times use the Repeat action.
+ * @returns {cc.ActionInterval} + */ + repeatForever: function(){ + this._repeatMethod = true;//Compatible with repeat class, Discard after can be deleted + this._timesForRepeat = this.MAX_VALUE; + this._repeatForever = true; + return this; } }); /** + * An interval action is an action that takes place within a certain period of time. + * @function * @param {Number} d duration in seconds * @return {cc.ActionInterval} * @example * // example - * var actionInterval = cc.ActionInterval.create(3); + * var actionInterval = cc.actionInterval(3); */ -cc.ActionInterval.create = function (d) { +cc.actionInterval = function (d) { return new cc.ActionInterval(d); }; +/** + * Please use cc.actionInterval instead. + * An interval action is an action that takes place within a certain period of time. + * @static + * @deprecated since v3.0
Please use cc.actionInterval instead. + * @param {Number} d duration in seconds + * @return {cc.ActionInterval} + */ +cc.ActionInterval.create = cc.actionInterval; -/** Runs actions sequentially, one after another +/** + * Runs actions sequentially, one after another. * @class * @extends cc.ActionInterval + * @param {Array|cc.FiniteTimeAction} tempArray + * @example + * // create sequence with actions + * var seq = new cc.Sequence(act1, act2); + * + * // create sequence with array + * var seq = new cc.Sequence(actArray); */ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ _actions:null, _split:null, _last:0, - /** Create an array of sequenceable actions - * @constructor + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create an array of sequenceable actions. * @param {Array|cc.FiniteTimeAction} tempArray - * @return {cc.Sequence} - * @example - * // create sequence with actions - * var seq = new cc.Sequence(act1, act2); - * - * // create sequence with array - * var seq = new cc.Sequence(actArray); */ ctor:function (tempArray) { cc.ActionInterval.prototype.ctor.call(this); @@ -187,20 +357,20 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ if ((last >= 0) && (paramArray[last] == null)) cc.log("parameters should not be ending with null in Javascript"); - if (last >= 0) { - var prev = paramArray[0], action1; - for (var i = 1; i < last; i++) { - if (paramArray[i]) { - action1 = prev; - prev = cc.Sequence.create(); - prev.initWithTwoActions(action1, paramArray[i]); - } - } - this.initWithTwoActions(prev, paramArray[last]); - } + if (last >= 0) { + var prev = paramArray[0], action1; + for (var i = 1; i < last; i++) { + if (paramArray[i]) { + action1 = prev; + prev = cc.Sequence._actionOneTwo(action1, paramArray[i]); + } + } + this.initWithTwoActions(prev, paramArray[last]); + } }, - /** initializes the action
+ /** + * Initializes the action
* @param {cc.FiniteTimeAction} actionOne * @param {cc.FiniteTimeAction} actionTwo * @return {Boolean} @@ -209,7 +379,7 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ if(!actionOne || !actionTwo) throw "cc.Sequence.initWithTwoActions(): arguments must all be non nil"; - var d = actionOne.getDuration() + actionTwo.getDuration(); + var d = actionOne._duration + actionTwo._duration; this.initWithDuration(d); this._actions[0] = actionOne; @@ -223,21 +393,23 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ */ clone:function () { var action = new cc.Sequence(); + this._cloneDecoration(action); action.initWithTwoActions(this._actions[0].clone(), this._actions[1].clone()); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); - this._split = this._actions[0].getDuration() / this._duration; + this._split = this._actions[0]._duration / this._duration; this._last = -1; }, /** - * stop the action + * stop the action. */ stop:function () { // Issue #1305 @@ -247,14 +419,17 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { var new_t, found = 0; - var locSplit = this._split, locActions = this._actions, locLast = this._last; - if (time < locSplit) { + var locSplit = this._split, locActions = this._actions, locLast = this._last, actionFound; + + dt = this._computeEaseTime(dt); + if (dt < locSplit) { // action[0] - new_t = (locSplit !== 0) ? time / locSplit : 1; + new_t = (locSplit !== 0) ? dt / locSplit : 1; if (found === 0 && locLast === 1) { // Reverse mode ? @@ -267,7 +442,7 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ } else { // action[1] found = 1; - new_t = (locSplit === 1) ? 1 : (time - locSplit) / (1 - locSplit); + new_t = (locSplit === 1) ? 1 : (dt - locSplit) / (1 - locSplit); if (locLast === -1) { // action[0] was skipped, execute it. @@ -282,57 +457,81 @@ cc.Sequence = cc.ActionInterval.extend(/** @lends cc.Sequence# */{ } } + actionFound = locActions[found]; // Last action found and it is done. - if (locLast === found && locActions[found].isDone()) + if (locLast === found && actionFound.isDone()) return; // Last action found and it is done if (locLast !== found) - locActions[found].startWithTarget(this.target); + actionFound.startWithTarget(this.target); - locActions[found].update(new_t); + new_t = new_t * actionFound._timesForRepeat; + actionFound.update(new_t > 1 ? new_t % 1 : new_t); this._last = found; }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.Sequence} */ reverse:function () { - return cc.Sequence._actionOneTwo(this._actions[1].reverse(), this._actions[0].reverse()); - }, - - /** - * to copy object with deep copy. - * @return {object} - */ - copy:function () { - return this.clone(); + var action = cc.Sequence._actionOneTwo(this._actions[1].reverse(), this._actions[0].reverse()); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); + /** helper constructor to create an array of sequenceable actions + * @function * @param {Array|cc.FiniteTimeAction} tempArray * @return {cc.Sequence} * @example * // example * // create sequence with actions - * var seq = cc.Sequence.create(act1, act2); + * var seq = cc.sequence(act1, act2); * * // create sequence with array - * var seq = cc.Sequence.create(actArray); + * var seq = cc.sequence(actArray); + * todo: It should be use new */ -cc.Sequence.create = function (/*Multiple Arguments*/tempArray) { +cc.sequence = function (/*Multiple Arguments*/tempArray) { var paramArray = (tempArray instanceof Array) ? tempArray : arguments; if ((paramArray.length > 0) && (paramArray[paramArray.length - 1] == null)) cc.log("parameters should not be ending with null in Javascript"); - var prev = paramArray[0]; - for (var i = 1; i < paramArray.length; i++) { - if (paramArray[i]) - prev = cc.Sequence._actionOneTwo(prev, paramArray[i]); + var result, current, i, repeat; + while(paramArray && paramArray.length > 0){ + current = Array.prototype.shift.call(paramArray); + repeat = current._timesForRepeat || 1; + current._repeatMethod = false; + current._timesForRepeat = 1; + + i = 0; + if(!result){ + result = current; + i = 1; + } + + for(i; i Please use cc.sequence instead. + * @param {Array|cc.FiniteTimeAction} tempArray + * @return {cc.Sequence} + */ +cc.Sequence.create = cc.sequence; + /** creates the action * @param {cc.FiniteTimeAction} actionOne * @param {cc.FiniteTimeAction} actionTwo @@ -345,12 +544,15 @@ cc.Sequence._actionOneTwo = function (actionOne, actionTwo) { return sequence; }; - /** * Repeats an action a number of times. * To repeat an action forever use the CCRepeatForever action. * @class * @extends cc.ActionInterval + * @param {cc.FiniteTimeAction} action + * @param {Number} times + * @example + * var rep = new cc.Repeat(cc.sequence(jump2, jump1), 5); */ cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{ _times:0, @@ -360,12 +562,10 @@ cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{ _innerAction:null, //CCFiniteTimeAction /** - * Creates a Repeat action. Times is an unsigned integer between 1 and pow(2,30) - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates a Repeat action. Times is an unsigned integer between 1 and pow(2,30). * @param {cc.FiniteTimeAction} action * @param {Number} times - * @example - * var rep = new cc.Repeat(cc.Sequence.create(jump2, jump1), 5); */ ctor: function (action, times) { cc.ActionInterval.prototype.ctor.call(this); @@ -379,13 +579,15 @@ cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{ * @return {Boolean} */ initWithAction:function (action, times) { - var duration = action.getDuration() * times; + var duration = action._duration * times; if (this.initWithDuration(duration)) { this._times = times; this._innerAction = action; - if (action instanceof cc.ActionInstant) + if (action instanceof cc.ActionInstant){ + this._actionInstant = true; this._times -= 1; + } this._total = 0; return true; } @@ -398,16 +600,18 @@ cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{ */ clone:function () { var action = new cc.Repeat(); + this._cloneDecoration(action); action.initWithAction(this._innerAction.clone(), this._times); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { this._total = 0; - this._nextDt = this._innerAction.getDuration() / this._duration; + this._nextDt = this._innerAction._duration / this._duration; cc.ActionInterval.prototype.startWithTarget.call(this, target); this._innerAction.startWithTarget(target); }, @@ -421,102 +625,125 @@ cc.Repeat = cc.ActionInterval.extend(/** @lends cc.Repeat# */{ }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); var locInnerAction = this._innerAction; var locDuration = this._duration; var locTimes = this._times; var locNextDt = this._nextDt; - if (time >= locNextDt) { - while (time > locNextDt && this._total < locTimes) { + if (dt >= locNextDt) { + while (dt > locNextDt && this._total < locTimes) { locInnerAction.update(1); this._total++; locInnerAction.stop(); locInnerAction.startWithTarget(this.target); - locNextDt += locInnerAction.getDuration() / locDuration; + locNextDt += locInnerAction._duration / locDuration; this._nextDt = locNextDt; } // fix for issue #1288, incorrect end value of repeat - if (time >= 1.0 && this._total < locTimes) + if (dt >= 1.0 && this._total < locTimes) this._total++; - // don't set a instantaction back or update it, it has no use because it has no duration - if (this._actionInstant) { - if (this._total == locTimes) { + // don't set a instant action back or update it, it has no use because it has no duration + if (!this._actionInstant) { + if (this._total === locTimes) { locInnerAction.update(1); locInnerAction.stop(); } else { // issue #390 prevent jerk, use right update - locInnerAction.update(time - (locNextDt - locInnerAction.getDuration() / locDuration)); + locInnerAction.update(dt - (locNextDt - locInnerAction._duration / locDuration)); } } } else { - locInnerAction.update((time * locTimes) % 1.0); + locInnerAction.update((dt * locTimes) % 1.0); } }, /** + * Return true if the action has finished. * @return {Boolean} */ isDone:function () { - return this._total == this._times; + return this._total === this._times; }, /** - * @return {cc.ActionInterval} + * returns a reversed action. + * @return {cc.Repeat} */ reverse:function () { - return cc.Repeat.create(this._innerAction.reverse(), this._times); + var action = new cc.Repeat(this._innerAction.reverse(), this._times); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; }, /** + * Set inner Action. * @param {cc.FiniteTimeAction} action */ setInnerAction:function (action) { - if (this._innerAction != action) { + if (this._innerAction !== action) { this._innerAction = action; } }, /** + * Get inner Action. * @return {cc.FiniteTimeAction} */ getInnerAction:function () { return this._innerAction; } }); + /** * Creates a Repeat action. Times is an unsigned integer between 1 and pow(2,30) + * @function * @param {cc.FiniteTimeAction} action * @param {Number} times * @return {cc.Repeat} * @example * // example - * var rep = cc.Repeat.create(cc.Sequence.create(jump2, jump1), 5); + * var rep = cc.repeat(cc.sequence(jump2, jump1), 5); */ -cc.Repeat.create = function (action, times) { +cc.repeat = function (action, times) { return new cc.Repeat(action, times); }; +/** + * Please use cc.repeat instead + * Creates a Repeat action. Times is an unsigned integer between 1 and pow(2,30) + * @static + * @deprecated since v3.0
Please use cc.repeat instead. + * @param {cc.FiniteTimeAction} action + * @param {Number} times + * @return {cc.Repeat} + */ +cc.Repeat.create = cc.repeat; + /** Repeats an action for ever.
* To repeat the an action for a limited number of times use the Repeat action.
- * @warning This action can't be Sequencable because it is not an IntervalAction + * @warning This action can't be Sequenceable because it is not an IntervalAction * @class * @extends cc.ActionInterval + * @param {cc.FiniteTimeAction} action + * @example + * var rep = new cc.RepeatForever(cc.sequence(jump2, jump1), 5); */ - cc.RepeatForever = cc.ActionInterval.extend(/** @lends cc.RepeatForever# */{ _innerAction:null, //CCActionInterval /** - * Create a acton which repeat forever + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a acton which repeat forever. * @param {cc.FiniteTimeAction} action - * @example - * var repeat = new cc.RepeatForever(cc.RotateBy.create(1.0, 360)); */ ctor:function (action) { cc.ActionInterval.prototype.ctor.call(this); @@ -543,11 +770,13 @@ cc.RepeatForever = cc.ActionInterval.extend(/** @lends cc.RepeatForever# */{ */ clone:function () { var action = new cc.RepeatForever(); + this._cloneDecoration(action); action.initWithAction(this._innerAction.clone()); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -556,22 +785,25 @@ cc.RepeatForever = cc.ActionInterval.extend(/** @lends cc.RepeatForever# */{ }, /** + * called every frame with it's delta time.
+ * DON'T override unless you know what you are doing. * @param dt delta time in seconds */ step:function (dt) { var locInnerAction = this._innerAction; locInnerAction.step(dt); if (locInnerAction.isDone()) { - //var diff = locInnerAction.getElapsed() - locInnerAction.getDuration(); + //var diff = locInnerAction.getElapsed() - locInnerAction._duration; locInnerAction.startWithTarget(this.target); // to prevent jerk. issue #390 ,1247 //this._innerAction.step(0); //this._innerAction.step(diff); - locInnerAction.step(locInnerAction.getElapsed() - locInnerAction.getDuration()); + locInnerAction.step(locInnerAction.getElapsed() - locInnerAction._duration); } }, /** + * Return true if the action has finished. * @return {Boolean} */ isDone:function () { @@ -579,41 +811,61 @@ cc.RepeatForever = cc.ActionInterval.extend(/** @lends cc.RepeatForever# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.RepeatForever} */ reverse:function () { - return (cc.RepeatForever.create(this._innerAction.reverse())); + var action = new cc.RepeatForever(this._innerAction.reverse()); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; }, /** - * + * Set inner action. * @param {cc.ActionInterval} action */ setInnerAction:function (action) { - if (this._innerAction != action) { + if (this._innerAction !== action) { this._innerAction = action; } }, /** + * Get inner action. * @return {cc.ActionInterval} */ getInnerAction:function () { return this._innerAction; } }); + /** * Create a acton which repeat forever + * @function * @param {cc.FiniteTimeAction} action * @return {cc.RepeatForever} * @example * // example - * var repeat = cc.RepeatForever.create(cc.RotateBy.create(1.0, 360)); + * var repeat = cc.repeatForever(cc.rotateBy(1.0, 360)); */ -cc.RepeatForever.create = function (action) { +cc.repeatForever = function (action) { return new cc.RepeatForever(action); }; +/** + * Please use cc.repeatForever instead + * Create a acton which repeat forever + * @static + * @deprecated since v3.0
Please use cc.repeatForever instead. + * @param {cc.FiniteTimeAction} action + * @return {cc.RepeatForever} + * @param {Array|cc.FiniteTimeAction} tempArray + * @example + * var action = new cc.Spawn(cc.jumpBy(2, cc.p(300, 0), 50, 4), cc.rotateBy(2, 720)); + */ +cc.RepeatForever.create = cc.repeatForever; + /** Spawn a new action immediately * @class @@ -624,10 +876,8 @@ cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{ _two:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Array|cc.FiniteTimeAction} tempArray - * @example - * var action = new cc.Spawn(cc.JumpBy.create(2, cc.p(300, 0), 50, 4), cc.RotateBy.create(2, 720)); */ ctor:function (tempArray) { cc.ActionInterval.prototype.ctor.call(this); @@ -639,17 +889,16 @@ cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{ if ((last >= 0) && (paramArray[last] == null)) cc.log("parameters should not be ending with null in Javascript"); - if (last >= 0) { - var prev = paramArray[0], action1; - for (var i = 1; i < last; i++) { - if (paramArray[i]) { - action1 = prev; - prev = cc.Spwan.create(); - prev.initWithTwoActions(action1, paramArray[i]); - } - } - this.initWithTwoActions(prev, paramArray[last]); - } + if (last >= 0) { + var prev = paramArray[0], action1; + for (var i = 1; i < last; i++) { + if (paramArray[i]) { + action1 = prev; + prev = cc.Spawn._actionOneTwo(action1, paramArray[i]); + } + } + this.initWithTwoActions(prev, paramArray[last]); + } }, /** initializes the Spawn action with the 2 actions to spawn @@ -663,17 +912,17 @@ cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{ var ret = false; - var d1 = action1.getDuration(); - var d2 = action2.getDuration(); + var d1 = action1._duration; + var d2 = action2._duration; if (this.initWithDuration(Math.max(d1, d2))) { this._one = action1; this._two = action2; if (d1 > d2) { - this._two = cc.Sequence._actionOneTwo(action2, cc.DelayTime.create(d1 - d2)); + this._two = cc.Sequence._actionOneTwo(action2, cc.delayTime(d1 - d2)); } else if (d1 < d2) { - this._one = cc.Sequence._actionOneTwo(action1, cc.DelayTime.create(d2 - d1)); + this._one = cc.Sequence._actionOneTwo(action1, cc.delayTime(d2 - d1)); } ret = true; @@ -687,11 +936,13 @@ cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{ */ clone:function () { var action = new cc.Spawn(); + this._cloneDecoration(action); action.initWithTwoActions(this._one.clone(), this._two.clone()); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -710,31 +961,40 @@ cc.Spawn = cc.ActionInterval.extend(/** @lends cc.Spawn# */{ }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this._one) - this._one.update(time); + this._one.update(dt); if (this._two) - this._two.update(time); + this._two.update(dt); }, /** - * @return {cc.FiniteTimeAction} + * Returns a reversed action. + * @return {cc.Spawn} */ reverse:function () { - return cc.Spawn._actionOneTwo(this._one.reverse(), this._two.reverse()); + var action = cc.Spawn._actionOneTwo(this._one.reverse(), this._two.reverse()); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * Create a spawn action which runs several actions in parallel. + * @function * @param {Array|cc.FiniteTimeAction}tempArray * @return {cc.FiniteTimeAction} * @example * // example - * var action = cc.Spawn.create(cc.JumpBy.create(2, cc.p(300, 0), 50, 4), cc.RotateBy.create(2, 720)); + * var action = cc.spawn(cc.jumpBy(2, cc.p(300, 0), 50, 4), cc.rotateBy(2, 720)); + * todo:It should be the direct use new */ -cc.Spawn.create = function (/*Multiple Arguments*/tempArray) { +cc.spawn = function (/*Multiple Arguments*/tempArray) { var paramArray = (tempArray instanceof Array) ? tempArray : arguments; if ((paramArray.length > 0) && (paramArray[paramArray.length - 1] == null)) cc.log("parameters should not be ending with null in Javascript"); @@ -742,11 +1002,21 @@ cc.Spawn.create = function (/*Multiple Arguments*/tempArray) { var prev = paramArray[0]; for (var i = 1; i < paramArray.length; i++) { if (paramArray[i] != null) - prev = this._actionOneTwo(prev, paramArray[i]); + prev = cc.Spawn._actionOneTwo(prev, paramArray[i]); } return prev; }; +/** + * Please use cc.spawn instead. + * Create a spawn action which runs several actions in parallel. + * @static + * @deprecated since v3.0
Please use cc.spawn instead. + * @param {Array|cc.FiniteTimeAction}tempArray + * @return {cc.FiniteTimeAction} + */ +cc.Spawn.create = cc.spawn; + /** * @param {cc.FiniteTimeAction} action1 * @param {cc.FiniteTimeAction} action2 @@ -760,11 +1030,17 @@ cc.Spawn._actionOneTwo = function (action1, action2) { }; -/** Rotates a cc.Node object to a certain angle by modifying it's +/** + * Rotates a cc.Node object to a certain angle by modifying it's. * rotation attribute.
* The direction will be decided by the shortest angle. * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} deltaAngleX deltaAngleX in degrees. + * @param {Number} [deltaAngleY] deltaAngleY in degrees. + * @example + * var rotateTo = new cc.RotateTo(2, 61.0); */ cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{ _dstAngleX:0, @@ -776,13 +1052,11 @@ cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{ _diffAngleY:0, /** - * Creates a RotateTo action with x and y rotation angles - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates a RotateTo action with x and y rotation angles. * @param {Number} duration duration in seconds * @param {Number} deltaAngleX deltaAngleX in degrees. * @param {Number} [deltaAngleY] deltaAngleY in degrees. - * @example - * var rotateTo = new cc.RotateTo(2, 61.0); */ ctor:function (duration, deltaAngleX, deltaAngleY) { cc.ActionInterval.prototype.ctor.call(this); @@ -791,6 +1065,7 @@ cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{ }, /** + * Initializes the action. * @param {Number} duration * @param {Number} deltaAngleX * @param {Number} deltaAngleY @@ -811,11 +1086,13 @@ cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{ */ clone:function () { var action = new cc.RotateTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._dstAngleX, this._dstAngleY); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -842,41 +1119,66 @@ cc.RotateTo = cc.ActionInterval.extend(/** @lends cc.RotateTo# */{ }, /** - * RotateTo reverse not implemented + * RotateTo reverse not implemented. + * Will be overridden. */ reverse:function () { cc.log("cc.RotateTo.reverse(): it should be overridden in subclass."); }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { - this.target.rotationX = this._startAngleX + this._diffAngleX * time; - this.target.rotationY = this._startAngleY + this._diffAngleY * time; + this.target.rotationX = this._startAngleX + this._diffAngleX * dt; + this.target.rotationY = this._startAngleY + this._diffAngleY * dt; } } }); /** - * Creates a RotateTo action with separate rotation angles + * Creates a RotateTo action with separate rotation angles. + * To specify the angle of rotation. + * @function * @param {Number} duration duration in seconds * @param {Number} deltaAngleX deltaAngleX in degrees. * @param {Number} [deltaAngleY] deltaAngleY in degrees. * @return {cc.RotateTo} * @example * // example - * var rotateTo = cc.RotateTo.create(2, 61.0); + * var rotateTo = cc.rotateTo(2, 61.0); */ -cc.RotateTo.create = function (duration, deltaAngleX, deltaAngleY) { +cc.rotateTo = function (duration, deltaAngleX, deltaAngleY) { return new cc.RotateTo(duration, deltaAngleX, deltaAngleY); }; +/** + * Please use cc.rotateTo instead + * Creates a RotateTo action with separate rotation angles. + * To specify the angle of rotation. + * @static + * @deprecated since v3.0
Please use cc.rotateTo instead. + * @param {Number} duration duration in seconds + * @param {Number} deltaAngleX deltaAngleX in degrees. + * @param {Number} [deltaAngleY] deltaAngleY in degrees. + * @return {cc.RotateTo} + */ +cc.RotateTo.create = cc.rotateTo; -/** Rotates a cc.Node object clockwise a number of degrees by modifying it's rotation attribute. + +/** + * Rotates a cc.Node object clockwise a number of degrees by modifying it's rotation attribute. + * Relative to its properties to modify. * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} deltaAngleX deltaAngleX in degrees + * @param {Number} [deltaAngleY] deltaAngleY in degrees + * @example + * var actionBy = new cc.RotateBy(2, 360); */ cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{ _angleX:0, @@ -885,12 +1187,10 @@ cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{ _startAngleY:0, /** - * @constructor - * @param {Number} duration druation in seconds + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} duration duration in seconds * @param {Number} deltaAngleX deltaAngleX in degrees * @param {Number} [deltaAngleY] deltaAngleY in degrees - * @example - * var actionBy = new cc.RotateBy(2, 360); */ ctor: function (duration, deltaAngleX, deltaAngleY) { cc.ActionInterval.prototype.ctor.call(this); @@ -899,6 +1199,7 @@ cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{ }, /** + * Initializes the action. * @param {Number} duration duration in seconds * @param {Number} deltaAngleX deltaAngleX in degrees * @param {Number} [deltaAngleY=] deltaAngleY in degrees @@ -919,11 +1220,13 @@ cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{ */ clone:function () { var action = new cc.RotateBy(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._angleX, this._angleY); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -933,37 +1236,56 @@ cc.RotateBy = cc.ActionInterval.extend(/** @lends cc.RotateBy# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { - this.target.rotationX = this._startAngleX + this._angleX * time; - this.target.rotationY = this._startAngleY + this._angleY * time; + this.target.rotationX = this._startAngleX + this._angleX * dt; + this.target.rotationY = this._startAngleY + this._angleY * dt; } }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.RotateBy} */ reverse:function () { - return cc.RotateBy.create(this._duration, -this._angleX, -this._angleY); + var action = new cc.RotateBy(this._duration, -this._angleX, -this._angleY); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** - * @param {Number} duration druation in seconds + * Rotates a cc.Node object clockwise a number of degrees by modifying it's rotation attribute. + * Relative to its properties to modify. + * @function + * @param {Number} duration duration in seconds * @param {Number} deltaAngleX deltaAngleX in degrees * @param {Number} [deltaAngleY] deltaAngleY in degrees * @return {cc.RotateBy} * @example * // example - * var actionBy = cc.RotateBy.create(2, 360); + * var actionBy = cc.rotateBy(2, 360); */ -cc.RotateBy.create = function (duration, deltaAngleX, deltaAngleY) { - var rotateBy = new cc.RotateBy(); - rotateBy.initWithDuration(duration, deltaAngleX, deltaAngleY); - return rotateBy; +cc.rotateBy = function (duration, deltaAngleX, deltaAngleY) { + return new cc.RotateBy(duration, deltaAngleX, deltaAngleY); }; +/** + * Please use cc.rotateBy instead. + * Rotates a cc.Node object clockwise a number of degrees by modifying it's rotation attribute. + * Relative to its properties to modify. + * @static + * @deprecated since v3.0
Please use cc.rotateBy instead. + * @param {Number} duration duration in seconds + * @param {Number} deltaAngleX deltaAngleX in degrees + * @param {Number} [deltaAngleY] deltaAngleY in degrees + * @return {cc.RotateBy} + */ +cc.RotateBy.create = cc.rotateBy; /** @@ -975,6 +1297,11 @@ cc.RotateBy.create = function (duration, deltaAngleX, deltaAngleY) { *

* @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {cc.Point|Number} deltaPos + * @param {Number} [deltaY] + * @example + * var actionTo = cc.moveBy(2, cc.p(windowSize.width - 40, windowSize.height - 40)); */ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ _positionDelta:null, @@ -982,12 +1309,10 @@ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ _previousPosition:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration duration in seconds * @param {cc.Point|Number} deltaPos * @param {Number} [deltaY] - * @example - * var actionTo = cc.MoveBy.create(2, cc.p(windowSize.width - 40, windowSize.height - 40)); */ ctor:function (duration, deltaPos, deltaY) { cc.ActionInterval.prototype.ctor.call(this); @@ -1000,6 +1325,7 @@ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ }, /** + * Initializes the action. * @param {Number} duration duration in seconds * @param {cc.Point} position * @param {Number} [y] @@ -1025,12 +1351,14 @@ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ */ clone:function () { var action = new cc.MoveBy(); - action.initWithDuration(this._duration, this._positionDelta) + this._cloneDecoration(action); + action.initWithDuration(this._duration, this._positionDelta); return action; }, /** - * @param {Number} target + * Start the action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); @@ -1043,12 +1371,14 @@ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { - var x = this._positionDelta.x * time; - var y = this._positionDelta.y * time; + var x = this._positionDelta.x * dt; + var y = this._positionDelta.y * dt; var locStartPosition = this._startPosition; if (cc.ENABLE_STACKABLE_ACTIONS) { var targetX = this.target.getPositionX(); @@ -1070,24 +1400,42 @@ cc.MoveBy = cc.ActionInterval.extend(/** @lends cc.MoveBy# */{ /** * MoveTo reverse is not implemented + * @return {cc.MoveBy} */ reverse:function () { - return cc.MoveBy.create(this._duration, cc.p(-this._positionDelta.x, -this._positionDelta.y)); + var action = new cc.MoveBy(this._duration, cc.p(-this._positionDelta.x, -this._positionDelta.y)); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * Create the action. + * Relative to its coordinate moves a certain distance. + * @function * @param {Number} duration duration in seconds - * @param {cc.Point|Number} deltaPosition + * @param {cc.Point|Number} deltaPos * @param {Number} deltaY * @return {cc.MoveBy} * @example * // example - * var actionTo = cc.MoveBy.create(2, cc.p(windowSize.width - 40, windowSize.height - 40)); + * var actionTo = cc.moveBy(2, cc.p(windowSize.width - 40, windowSize.height - 40)); */ -cc.MoveBy.create = function (duration, deltaPos, deltaY) { +cc.moveBy = function (duration, deltaPos, deltaY) { return new cc.MoveBy(duration, deltaPos, deltaY); }; +/** + * Please use cc.moveBy instead. + * Relative to its coordinate moves a certain distance. + * @static + * @deprecated since v3.0 please use cc.moveBy instead. + * @param {Number} duration duration in seconds + * @param {cc.Point|Number} deltaPos + * @param {Number} deltaY + * @return {cc.MoveBy} + */ +cc.MoveBy.create = cc.moveBy; /** @@ -1096,17 +1444,20 @@ cc.MoveBy.create = function (duration, deltaPos, deltaY) { * movement will be the sum of individual movements. * @class * @extends cc.MoveBy + * @param {Number} duration duration in seconds + * @param {cc.Point|Number} position + * @param {Number} y + * @example + * var actionBy = new cc.MoveTo(2, cc.p(80, 80)); */ cc.MoveTo = cc.MoveBy.extend(/** @lends cc.MoveTo# */{ _endPosition:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration duration in seconds * @param {cc.Point|Number} position * @param {Number} y - * @example - * var actionBy = cc.MoveTo.create(2, cc.p(80, 80)); */ ctor:function (duration, position, y) { cc.MoveBy.prototype.ctor.call(this); @@ -1116,6 +1467,7 @@ cc.MoveTo = cc.MoveBy.extend(/** @lends cc.MoveTo# */{ }, /** + * Initializes the action. * @param {Number} duration duration in seconds * @param {cc.Point} position * @param {Number} y @@ -1141,11 +1493,13 @@ cc.MoveTo = cc.MoveBy.extend(/** @lends cc.MoveTo# */{ */ clone:function () { var action = new cc.MoveTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._endPosition); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1154,23 +1508,43 @@ cc.MoveTo = cc.MoveBy.extend(/** @lends cc.MoveTo# */{ this._positionDelta.y = this._endPosition.y - target.getPositionY(); } }); + /** + * Create new action. + * Moving to the specified coordinates. + * @function * @param {Number} duration duration in seconds * @param {cc.Point} position * @param {Number} y * @return {cc.MoveBy} * @example * // example - * var actionBy = cc.MoveTo.create(2, cc.p(80, 80)); + * var actionBy = cc.moveTo(2, cc.p(80, 80)); */ -cc.MoveTo.create = function (duration, position, y) { +cc.moveTo = function (duration, position, y) { return new cc.MoveTo(duration, position, y); }; +/** + * Please use cc.moveTo instead. + * Moving to the specified coordinates. + * @static + * @deprecated since v3.0
Please use cc.moveTo instead. + * @param {Number} duration duration in seconds + * @param {cc.Point} position + * @param {Number} y + * @return {cc.MoveBy} + */ +cc.MoveTo.create = cc.moveTo; /** * Skews a cc.Node object to given angles by modifying it's skewX and skewY attributes * @class * @extends cc.ActionInterval + * @param {Number} t time in seconds + * @param {Number} sx + * @param {Number} sy + * @example + * var actionTo = new cc.SkewTo(2, 37.2, -37.2); */ cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{ _skewX:0, @@ -1183,12 +1557,10 @@ cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{ _deltaY:0, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} t time in seconds * @param {Number} sx * @param {Number} sy - * @example - * var actionTo = new cc.SkewTo(2, 37.2, -37.2); */ ctor: function (t, sx, sy) { cc.ActionInterval.prototype.ctor.call(this); @@ -1197,6 +1569,7 @@ cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{ }, /** + * Initializes the action. * @param {Number} t time in seconds * @param {Number} sx * @param {Number} sy @@ -1218,11 +1591,13 @@ cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{ */ clone:function () { var action = new cc.SkewTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._endSkewX, this._endSkewY); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1244,34 +1619,57 @@ cc.SkewTo = cc.ActionInterval.extend(/** @lends cc.SkewTo# */{ }, /** - * @param {Number} t time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (t) { - this.target.skewX = this._startSkewX + this._deltaX * t; - this.target.skewY = this._startSkewY + this._deltaY * t; + update:function (dt) { + dt = this._computeEaseTime(dt); + this.target.skewX = this._startSkewX + this._deltaX * dt; + this.target.skewY = this._startSkewY + this._deltaY * dt; } }); /** + * Create new action. + * Skews a cc.Node object to given angles by modifying it's skewX and skewY attributes. + * Changes to the specified value. + * @function * @param {Number} t time in seconds * @param {Number} sx * @param {Number} sy * @return {cc.SkewTo} * @example * // example - * var actionTo = cc.SkewTo.create(2, 37.2, -37.2); + * var actionTo = cc.skewTo(2, 37.2, -37.2); */ -cc.SkewTo.create = function (t, sx, sy) { +cc.skewTo = function (t, sx, sy) { return new cc.SkewTo(t, sx, sy); }; +/** + * Please use cc.skewTo instead. + * Skews a cc.Node object to given angles by modifying it's skewX and skewY attributes。 + * Changes to the specified value. + * @static + * @deprecated since v3.0
Please use cc.skewTo instead. + * @param {Number} t time in seconds + * @param {Number} sx + * @param {Number} sy + * @return {cc.SkewTo} + */ +cc.SkewTo.create = cc.skewTo; -/** Skews a cc.Node object by skewX and skewY degrees +/** + * Skews a cc.Node object by skewX and skewY degrees. + * Relative to its attribute modification. * @class * @extends cc.SkewTo + * @param {Number} t time in seconds + * @param {Number} sx skew in degrees for X axis + * @param {Number} sy skew in degrees for Y axis */ cc.SkewBy = cc.SkewTo.extend(/** @lends cc.SkewBy# */{ /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} t time in seconds * @param {Number} sx skew in degrees for X axis * @param {Number} sy skew in degrees for Y axis @@ -1282,6 +1680,7 @@ cc.SkewBy = cc.SkewTo.extend(/** @lends cc.SkewBy# */{ }, /** + * Initializes the action. * @param {Number} t time in seconds * @param {Number} deltaSkewX skew in degrees for X axis * @param {Number} deltaSkewY skew in degrees for Y axis @@ -1303,11 +1702,13 @@ cc.SkewBy = cc.SkewTo.extend(/** @lends cc.SkewBy# */{ */ clone:function () { var action = new cc.SkewBy(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._skewX, this._skewY); return action; }, /** + * Start the action width target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1319,32 +1720,59 @@ cc.SkewBy = cc.SkewTo.extend(/** @lends cc.SkewBy# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.SkewBy} */ reverse:function () { - return cc.SkewBy.create(this._duration, -this._skewX, -this._skewY); + var action = new cc.SkewBy(this._duration, -this._skewX, -this._skewY); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); + /** + * Skews a cc.Node object by skewX and skewY degrees.
+ * Relative to its attribute modification. + * @function * @param {Number} t time in seconds * @param {Number} sx sx skew in degrees for X axis * @param {Number} sy sy skew in degrees for Y axis * @return {cc.SkewBy} * @example * // example - * var actionBy = cc.SkewBy.create(2, 0, -90); + * var actionBy = cc.skewBy(2, 0, -90); */ -cc.SkewBy.create = function (t, sx, sy) { - var skewBy = new cc.SkewBy(); - if (skewBy) - skewBy.initWithDuration(t, sx, sy); - return skewBy; +cc.skewBy = function (t, sx, sy) { + return new cc.SkewBy(t, sx, sy); }; +/** + * Please use cc.skewBy instead.
+ * Skews a cc.Node object by skewX and skewY degrees.
+ * Relative to its attribute modification. + * @static + * @deprecated since v3.0 please use cc.skewBy instead. + * @param {Number} t time in seconds + * @param {Number} sx sx skew in degrees for X axis + * @param {Number} sy sy skew in degrees for Y axis + * @return {cc.SkewBy} + */ +cc.SkewBy.create = cc.skewBy; -/** Moves a cc.Node object simulating a parabolic jump movement by modifying it's position attribute. +/** + * Moves a cc.Node object simulating a parabolic jump movement by modifying it's position attribute. + * Relative to its movement. * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + * @example + * var actionBy = new cc.JumpBy(2, cc.p(300, 0), 50, 4); + * var actionBy = new cc.JumpBy(2, 300, 0, 50, 4); */ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ _startPosition:null, @@ -1354,15 +1782,12 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ _previousPosition:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration * @param {cc.Point|Number} position * @param {Number} [y] * @param {Number} height * @param {Number} jumps - * @example - * var actionBy = new cc.JumpBy(2, cc.p(300, 0), 50, 4); - * var actionBy = new cc.JumpBy(2, 300, 0, 50, 4); */ ctor:function (duration, position, y, height, jumps) { cc.ActionInterval.prototype.ctor.call(this); @@ -1373,6 +1798,7 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ height !== undefined && this.initWithDuration(duration, position, y, height, jumps); }, /** + * Initializes the action. * @param {Number} duration * @param {cc.Point|Number} position * @param {Number} [y] @@ -1406,11 +1832,13 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ */ clone:function () { var action = new cc.JumpBy(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._delta, this._height, this._jumps); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1424,15 +1852,17 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { - var frac = time * this._jumps % 1.0; + var frac = dt * this._jumps % 1.0; var y = this._height * 4 * frac * (1 - frac); - y += this._delta.y * time; + y += this._delta.y * dt; - var x = this._delta.x * time; + var x = this._delta.x * dt; var locStartPosition = this._startPosition; if (cc.ENABLE_STACKABLE_ACTIONS) { var targetX = this.target.getPositionX(); @@ -1453,14 +1883,21 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.JumpBy} */ reverse:function () { - return cc.JumpBy.create(this._duration, cc.p(-this._delta.x, -this._delta.y), this._height, this._jumps); + var action = new cc.JumpBy(this._duration, cc.p(-this._delta.x, -this._delta.y), this._height, this._jumps); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * Moves a cc.Node object simulating a parabolic jump movement by modifying it's position attribute. + * Relative to its movement. + * @function * @param {Number} duration * @param {cc.Point|Number} position * @param {Number} [y] @@ -1469,26 +1906,90 @@ cc.JumpBy = cc.ActionInterval.extend(/** @lends cc.JumpBy# */{ * @return {cc.JumpBy} * @example * // example - * var actionBy = cc.JumpBy.create(2, cc.p(300, 0), 50, 4); - * var actionBy = cc.JumpBy.create(2, 300, 0, 50, 4); + * var actionBy = cc.jumpBy(2, cc.p(300, 0), 50, 4); + * var actionBy = cc.jumpBy(2, 300, 0, 50, 4); */ -cc.JumpBy.create = function (duration, position, y, height, jumps) { +cc.jumpBy = function (duration, position, y, height, jumps) { return new cc.JumpBy(duration, position, y, height, jumps); }; +/** + * Please use cc.jumpBy instead.
+ * Moves a cc.Node object simulating a parabolic jump movement by modifying it's position attribute.
+ * Relative to its movement. + * @static + * @deprecated since v3.0 please use cc.jumpBy instead. + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + * @return {cc.JumpBy} + */ +cc.JumpBy.create = cc.jumpBy; -/** Moves a cc.Node object to a parabolic position simulating a jump movement by modifying it's position attribute. +/** + * Moves a cc.Node object to a parabolic position simulating a jump movement by modifying it's position attribute.
+ * Jump to the specified location. * @class * @extends cc.JumpBy + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + * @example + * var actionTo = new cc.JumpTo(2, cc.p(300, 0), 50, 4); + * var actionTo = new cc.JumpTo(2, 300, 0, 50, 4); */ cc.JumpTo = cc.JumpBy.extend(/** @lends cc.JumpTo# */{ + _endPosition:null, - /** + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + */ + ctor:function (duration, position, y, height, jumps) { + cc.JumpBy.prototype.ctor.call(this); + this._endPosition = cc.p(0, 0); + + height !== undefined && this.initWithDuration(duration, position, y, height, jumps); + }, + /** + * Initializes the action. + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + * @return {Boolean} + * @example + * actionTo.initWithDuration(2, cc.p(300, 0), 50, 4); + * actionTo.initWithDuration(2, 300, 0, 50, 4); + */ + initWithDuration:function (duration, position, y, height, jumps) { + if (cc.JumpBy.prototype.initWithDuration.call(this, duration, position, y, height, jumps)) { + if (jumps === undefined) { + y = position.y; + position = position.x; + } + this._endPosition.x = position; + this._endPosition.y = y; + return true; + } + return false; + }, + /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { cc.JumpBy.prototype.startWithTarget.call(this, target); - this._delta.x = this._delta.x - this._startPosition.x; - this._delta.y = this._delta.y - this._startPosition.y; + this._delta.x = this._endPosition.x - this._startPosition.x; + this._delta.y = this._endPosition.y - this._startPosition.y; }, /** @@ -1497,12 +1998,16 @@ cc.JumpTo = cc.JumpBy.extend(/** @lends cc.JumpTo# */{ */ clone:function () { var action = new cc.JumpTo(); - action.initWithDuration(this._duration, this._delta, this._height, this._jumps); + this._cloneDecoration(action); + action.initWithDuration(this._duration, this._endPosition, this._height, this._jumps); return action; } }); /** + * Moves a cc.Node object to a parabolic position simulating a jump movement by modifying it's position attribute.
+ * Jump to the specified location. + * @function * @param {Number} duration * @param {cc.Point|Number} position * @param {Number} [y] @@ -1511,12 +2016,26 @@ cc.JumpTo = cc.JumpBy.extend(/** @lends cc.JumpTo# */{ * @return {cc.JumpTo} * @example * // example - * var actionTo = cc.JumpTo.create(2, cc.p(300, 300), 50, 4); - * var actionTo = cc.JumpTo.create(2, 300, 300, 50, 4); + * var actionTo = cc.jumpTo(2, cc.p(300, 300), 50, 4); + * var actionTo = cc.jumpTo(2, 300, 300, 50, 4); */ -cc.JumpTo.create = function (duration, position, y, height, jumps) { +cc.jumpTo = function (duration, position, y, height, jumps) { return new cc.JumpTo(duration, position, y, height, jumps); }; +/** + * Please use cc.jumpTo instead. + * Moves a cc.Node object to a parabolic position simulating a jump movement by modifying it's position attribute.
+ * Jump to the specified location. + * @static + * @deprecated since v3.0 please use cc.jumpTo instead. + * @param {Number} duration + * @param {cc.Point|Number} position + * @param {Number} [y] + * @param {Number} height + * @param {Number} jumps + * @return {cc.JumpTo} + */ +cc.JumpTo.create = cc.jumpTo; /** * @function @@ -1535,8 +2054,14 @@ cc.bezierAt = function (a, b, c, d, t) { }; /** An action that moves the target with a cubic Bezier curve by a certain distance. + * Relative to its movement. * @class * @extends cc.ActionInterval + * @param {Number} t time in seconds + * @param {Array} c Array of points + * @example + * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; + * var bezierForward = new cc.BezierBy(3, bezier); */ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ _config:null, @@ -1544,12 +2069,9 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ _previousPosition:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} t time in seconds * @param {Array} c Array of points - * @example - * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; - * var bezierForward = new cc.BezierBy(3, bezier); */ ctor:function (t, c) { cc.ActionInterval.prototype.ctor.call(this); @@ -1559,7 +2081,9 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ c && this.initWithDuration(t, c); }, + /** + * Initializes the action. * @param {Number} t time in seconds * @param {Array} c Array of points * @return {Boolean} @@ -1578,6 +2102,7 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ */ clone:function () { var action = new cc.BezierBy(); + this._cloneDecoration(action); var newConfigs = []; for (var i = 0; i < this._config.length; i++) { var selConf = this._config[i]; @@ -1588,6 +2113,7 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1601,9 +2127,11 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { var locConfig = this._config; var xa = 0; @@ -1616,8 +2144,8 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ var yc = locConfig[1].y; var yd = locConfig[2].y; - var x = cc.bezierAt(xa, xb, xc, xd, time); - var y = cc.bezierAt(ya, yb, yc, yd, time); + var x = cc.bezierAt(xa, xb, xc, xd, dt); + var y = cc.bezierAt(ya, yb, yc, yd, dt); var locStartPosition = this._startPosition; if (cc.ENABLE_STACKABLE_ACTIONS) { @@ -1639,7 +2167,8 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.BezierBy} */ reverse:function () { var locConfig = this._config; @@ -1647,37 +2176,57 @@ cc.BezierBy = cc.ActionInterval.extend(/** @lends cc.BezierBy# */{ cc.pAdd(locConfig[1], cc.pNeg(locConfig[2])), cc.pAdd(locConfig[0], cc.pNeg(locConfig[2])), cc.pNeg(locConfig[2]) ]; - return cc.BezierBy.create(this._duration, r); + var action = new cc.BezierBy(this._duration, r); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * An action that moves the target with a cubic Bezier curve by a certain distance. + * Relative to its movement. + * @function * @param {Number} t time in seconds * @param {Array} c Array of points * @return {cc.BezierBy} * @example * // example * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; - * var bezierForward = cc.BezierBy.create(3, bezier); + * var bezierForward = cc.bezierBy(3, bezier); */ -cc.BezierBy.create = function (t, c) { +cc.bezierBy = function (t, c) { return new cc.BezierBy(t, c); }; +/** + * Please use cc.bezierBy instead. + * An action that moves the target with a cubic Bezier curve by a certain distance. + * Relative to its movement. + * @static + * @deprecated since v3.0 please use cc.bezierBy instead. + * @param {Number} t time in seconds + * @param {Array} c Array of points + * @return {cc.BezierBy} + */ +cc.BezierBy.create = cc.bezierBy; /** An action that moves the target with a cubic Bezier curve to a destination point. * @class * @extends cc.BezierBy + * @param {Number} t + * @param {Array} c array of points + * @example + * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; + * var bezierTo = new cc.BezierTo(2, bezier); */ cc.BezierTo = cc.BezierBy.extend(/** @lends cc.BezierTo# */{ _toConfig:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} t * @param {Array} c array of points - * @example - * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; * var bezierTo = new cc.BezierTo(2, bezier); */ ctor:function (t, c) { @@ -1687,6 +2236,7 @@ cc.BezierTo = cc.BezierBy.extend(/** @lends cc.BezierTo# */{ }, /** + * Initializes the action. * @param {Number} t time in seconds * @param {Array} c Array of points * @return {Boolean} @@ -1705,11 +2255,13 @@ cc.BezierTo = cc.BezierBy.extend(/** @lends cc.BezierTo# */{ */ clone:function () { var action = new cc.BezierTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._toConfig); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1724,23 +2276,43 @@ cc.BezierTo = cc.BezierBy.extend(/** @lends cc.BezierTo# */{ } }); /** + * An action that moves the target with a cubic Bezier curve to a destination point. + * @function * @param {Number} t * @param {Array} c array of points * @return {cc.BezierTo} * @example * // example * var bezier = [cc.p(0, windowSize.height / 2), cc.p(300, -windowSize.height / 2), cc.p(300, 100)]; - * var bezierTo = cc.BezierTo.create(2, bezier); + * var bezierTo = cc.bezierTo(2, bezier); */ -cc.BezierTo.create = function (t, c) { +cc.bezierTo = function (t, c) { return new cc.BezierTo(t, c); }; +/** + * Please use cc.bezierTo instead + * @static + * @deprecated since v3.0 please use cc.bezierTo instead. + * @param {Number} t + * @param {Array} c array of points + * @return {cc.BezierTo} + */ +cc.BezierTo.create = cc.bezierTo; /** Scales a cc.Node object to a zoom factor by modifying it's scale attribute. * @warning This action doesn't support "reverse" * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {Number} sx scale parameter in X + * @param {Number} [sy] scale parameter in Y, if Null equal to sx + * @example + * // It scales to 0.5 in both X and Y. + * var actionTo = new cc.ScaleTo(2, 0.5); + * + * // It scales to 0.5 in x and 2 in Y + * var actionTo = new cc.ScaleTo(2, 0.5, 2); */ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ _scaleX:1, @@ -1753,16 +2325,10 @@ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ _deltaY:0, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration * @param {Number} sx scale parameter in X * @param {Number} [sy] scale parameter in Y, if Null equal to sx - * @example - * // It scales to 0.5 in both X and Y. - * var actionTo = new cc.ScaleTo(2, 0.5); - * - * // It scales to 0.5 in x and 2 in Y - * var actionTo = new cc.ScaleTo(2, 0.5, 2); */ ctor:function (duration, sx, sy) { cc.ActionInterval.prototype.ctor.call(this); @@ -1770,6 +2336,7 @@ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ }, /** + * Initializes the action. * @param {Number} duration * @param {Number} sx * @param {Number} [sy=] @@ -1790,11 +2357,13 @@ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ */ clone:function () { var action = new cc.ScaleTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._endScaleX, this._endScaleY); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1806,16 +2375,20 @@ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target) { - this.target.scaleX = this._startScaleX + this._deltaX * time; - this.target.scaleY = this._startScaleY + this._deltaY * time; + this.target.scaleX = this._startScaleX + this._deltaX * dt; + this.target.scaleY = this._startScaleY + this._deltaY * dt; } } }); /** + * Scales a cc.Node object to a zoom factor by modifying it's scale attribute. + * @function * @param {Number} duration * @param {Number} sx scale parameter in X * @param {Number} [sy] scale parameter in Y, if Null equal to sx @@ -1823,25 +2396,36 @@ cc.ScaleTo = cc.ActionInterval.extend(/** @lends cc.ScaleTo# */{ * @example * // example * // It scales to 0.5 in both X and Y. - * var actionTo = cc.ScaleTo.create(2, 0.5); + * var actionTo = cc.scaleTo(2, 0.5); * * // It scales to 0.5 in x and 2 in Y - * var actionTo = cc.ScaleTo.create(2, 0.5, 2); + * var actionTo = cc.scaleTo(2, 0.5, 2); */ -cc.ScaleTo.create = function (duration, sx, sy) { //function overload - var scaleTo = new cc.ScaleTo(); - scaleTo.initWithDuration(duration, sx, sy); - return scaleTo; +cc.scaleTo = function (duration, sx, sy) { //function overload + return new cc.ScaleTo(duration, sx, sy); }; +/** + * Please use cc.scaleTo instead. + * Scales a cc.Node object to a zoom factor by modifying it's scale attribute. + * @static + * @deprecated since v3.0 please use cc.scaleTo instead. + * @param {Number} duration + * @param {Number} sx scale parameter in X + * @param {Number} [sy] scale parameter in Y, if Null equal to sx + * @return {cc.ScaleTo} + */ +cc.ScaleTo.create = cc.scaleTo; /** Scales a cc.Node object a zoom factor by modifying it's scale attribute. + * Relative to its changes. * @class * @extends cc.ScaleTo */ cc.ScaleBy = cc.ScaleTo.extend(/** @lends cc.ScaleBy# */{ /** - * @param {Number} target + * Start the action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { cc.ScaleTo.prototype.startWithTarget.call(this, target); @@ -1850,10 +2434,14 @@ cc.ScaleBy = cc.ScaleTo.extend(/** @lends cc.ScaleBy# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.ScaleBy} */ reverse:function () { - return cc.ScaleBy.create(this._duration, 1 / this._endScaleX, 1 / this._endScaleY); + var action = new cc.ScaleBy(this._duration, 1 / this._endScaleX, 1 / this._endScaleY); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; }, /** @@ -1862,40 +2450,58 @@ cc.ScaleBy = cc.ScaleTo.extend(/** @lends cc.ScaleBy# */{ */ clone:function () { var action = new cc.ScaleBy(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._endScaleX, this._endScaleY); return action; } }); /** + * Scales a cc.Node object a zoom factor by modifying it's scale attribute. + * Relative to its changes. + * @function * @param {Number} duration duration in seconds * @param {Number} sx sx scale parameter in X * @param {Number|Null} [sy=] sy scale parameter in Y, if Null equal to sx * @return {cc.ScaleBy} * @example * // example without sy, it scales by 2 both in X and Y - * var actionBy = cc.ScaleBy.create(2, 2); + * var actionBy = cc.scaleBy(2, 2); * * //example with sy, it scales by 0.25 in X and 4.5 in Y - * var actionBy2 = cc.ScaleBy.create(2, 0.25, 4.5); + * var actionBy2 = cc.scaleBy(2, 0.25, 4.5); */ -cc.ScaleBy.create = function (duration, sx, sy) { +cc.scaleBy = function (duration, sx, sy) { return new cc.ScaleBy(duration, sx, sy); }; +/** + * Please use cc.scaleBy instead. + * Scales a cc.Node object a zoom factor by modifying it's scale attribute. + * Relative to its changes. + * @static + * @deprecated since v3.0 please use cc.scaleBy() instead. + * @param {Number} duration duration in seconds + * @param {Number} sx sx scale parameter in X + * @param {Number|Null} [sy=] sy scale parameter in Y, if Null equal to sx + * @return {cc.ScaleBy} + */ +cc.ScaleBy.create = cc.scaleBy; /** Blinks a cc.Node object by modifying it's visible attribute * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} blinks blinks in times + * @example + * var action = new cc.Blink(2, 10); */ cc.Blink = cc.ActionInterval.extend(/** @lends cc.Blink# */{ _times:0, _originalState:false, /** - * @constructor - * @param {Number} duration duration in seconds - * @param (Number) blinks blinks in times - * @example - * var action = new cc.Blink(2, 10); + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} duration duration in seconds + * @param {Number} blinks blinks in times */ ctor:function (duration, blinks) { cc.ActionInterval.prototype.ctor.call(this); @@ -1903,6 +2509,7 @@ cc.Blink = cc.ActionInterval.extend(/** @lends cc.Blink# */{ }, /** + * Initializes the action. * @param {Number} duration duration in seconds * @param {Number} blinks blinks in times * @return {Boolean} @@ -1921,67 +2528,93 @@ cc.Blink = cc.ActionInterval.extend(/** @lends cc.Blink# */{ */ clone:function () { var action = new cc.Blink(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._times); return action; }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt time in seconds */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this.target && !this.isDone()) { var slice = 1.0 / this._times; - var m = time % slice; + var m = dt % slice; this.target.visible = (m > (slice / 2)); } }, + /** + * Start the action with target. + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); this._originalState = target.visible; }, + /** + * stop the action + */ stop:function () { this.target.visible = this._originalState; cc.ActionInterval.prototype.stop.call(this); }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.Blink} */ reverse:function () { - return cc.Blink.create(this._duration, this._times); + var action = new cc.Blink(this._duration, this._times); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * Blinks a cc.Node object by modifying it's visible attribute. + * @function * @param {Number} duration duration in seconds * @param blinks blinks in times * @return {cc.Blink} * @example * // example - * var action = cc.Blink.create(2, 10); + * var action = cc.blink(2, 10); */ -cc.Blink.create = function (duration, blinks) { - var blink = new cc.Blink(); - blink.initWithDuration(duration, blinks); - return blink; +cc.blink = function (duration, blinks) { + return new cc.Blink(duration, blinks); }; +/** + * Please use cc.blink instead. + * Blinks a cc.Node object by modifying it's visible attribute. + * @static + * @deprecated since v3.0 please use cc.blink instead. + * @param {Number} duration duration in seconds + * @param blinks blinks in times + * @return {cc.Blink} + */ +cc.Blink.create = cc.blink; /** Fades an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from the current value to a custom one. * @warning This action doesn't support "reverse" * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {Number} opacity 0-255, 0 is transparent + * @example + * var action = new cc.FadeTo(1.0, 0); */ cc.FadeTo = cc.ActionInterval.extend(/** @lends cc.FadeTo# */{ _toOpacity:0, _fromOpacity:0, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration * @param {Number} opacity 0-255, 0 is transparent - * @example - * var action = new cc.FadeTo(1.0, 0); */ ctor:function (duration, opacity) { cc.ActionInterval.prototype.ctor.call(this); @@ -1989,6 +2622,7 @@ cc.FadeTo = cc.ActionInterval.extend(/** @lends cc.FadeTo# */{ }, /** + * Initializes the action. * @param {Number} duration duration in seconds * @param {Number} opacity * @return {Boolean} @@ -2007,56 +2641,84 @@ cc.FadeTo = cc.ActionInterval.extend(/** @lends cc.FadeTo# */{ */ clone:function () { var action = new cc.FadeTo(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._toOpacity); return action; }, /** + * Called once per frame. Time is the number of seconds of a frame interval. * @param {Number} time time in seconds */ update:function (time) { - if (this.target.RGBAProtocol) { - var fromOpacity = this._fromOpacity; - this.target.opacity = fromOpacity + (this._toOpacity - fromOpacity) * time; - } + time = this._computeEaseTime(time); + var fromOpacity = this._fromOpacity !== undefined ? this._fromOpacity : 255; + this.target.opacity = fromOpacity + (this._toOpacity - fromOpacity) * time; }, /** - * @param {cc.Sprite} target + * Start this action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); - if(this.target.RGBAProtocol){ - this._fromOpacity = target.opacity; - } + this._fromOpacity = target.opacity; } }); /** + * Fades an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from the current value to a custom one. + * @function * @param {Number} duration * @param {Number} opacity 0-255, 0 is transparent * @return {cc.FadeTo} * @example * // example - * var action = cc.FadeTo.create(1.0, 0); + * var action = cc.fadeTo(1.0, 0); */ -cc.FadeTo.create = function (duration, opacity) { +cc.fadeTo = function (duration, opacity) { return new cc.FadeTo(duration, opacity); }; +/** + * Please use cc.fadeTo instead. + * Fades an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from the current value to a custom one. + * @static + * @deprecated since v3.0 please use cc.fadeTo instead. + * @param {Number} duration + * @param {Number} opacity 0-255, 0 is transparent + * @return {cc.FadeTo} + */ +cc.FadeTo.create = cc.fadeTo; /** Fades In an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 0 to 255.
* The "reverse" of this action is FadeOut * @class * @extends cc.FadeTo + * @param {Number} duration duration in seconds */ cc.FadeIn = cc.FadeTo.extend(/** @lends cc.FadeIn# */{ _reverseAction: null, + /** - * @return {cc.ActionInterval} + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} duration duration in seconds + */ + ctor:function (duration) { + cc.FadeTo.prototype.ctor.call(this); + if (duration == null) + duration = 0; + this.initWithDuration(duration, 255); + }, + + /** + * Returns a reversed action. + * @return {cc.FadeOut} */ reverse:function () { var action = new cc.FadeOut(); action.initWithDuration(this._duration, 0); + this._cloneDecoration(action); + this._reverseEaseList(action); return action; }, @@ -2066,12 +2728,14 @@ cc.FadeIn = cc.FadeTo.extend(/** @lends cc.FadeIn# */{ */ clone:function () { var action = new cc.FadeIn(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._toOpacity); return action; }, /** - * @param {cc.Sprite} target + * Start the action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { if(this._reverseAction) @@ -2081,33 +2745,57 @@ cc.FadeIn = cc.FadeTo.extend(/** @lends cc.FadeIn# */{ }); /** + * Fades In an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 0 to 255. + * @function * @param {Number} duration duration in seconds - * @param {Number} [toOpacity] to opacity * @return {cc.FadeIn} * @example * //example - * var action = cc.FadeIn.create(1.0); + * var action = cc.fadeIn(1.0); */ -cc.FadeIn.create = function (duration, toOpacity) { - if(toOpacity == null) - toOpacity = 255; - return new cc.FadeIn(duration, toOpacity); +cc.fadeIn = function (duration) { + return new cc.FadeIn(duration); }; +/** + * Please use cc.fadeIn instead. + * Fades In an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 0 to 255. + * @static + * @deprecated since v3.0 please use cc.fadeIn() instead. + * @param {Number} duration duration in seconds + * @return {cc.FadeIn} + */ +cc.FadeIn.create = cc.fadeIn; /** Fades Out an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 255 to 0. * The "reverse" of this action is FadeIn * @class * @extends cc.FadeTo + * @param {Number} duration duration in seconds */ cc.FadeOut = cc.FadeTo.extend(/** @lends cc.FadeOut# */{ + /** - * @return {cc.ActionInterval} + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} duration duration in seconds + */ + ctor:function (duration) { + cc.FadeTo.prototype.ctor.call(this); + if (duration == null) + duration = 0; + this.initWithDuration(duration, 0); + }, + + /** + * Returns a reversed action. + * @return {cc.FadeIn} */ reverse:function () { var action = new cc.FadeIn(); action._reverseAction = this; action.initWithDuration(this._duration, 255); + this._cloneDecoration(action); + this._reverseEaseList(action); return action; }, @@ -2117,41 +2805,55 @@ cc.FadeOut = cc.FadeTo.extend(/** @lends cc.FadeOut# */{ */ clone:function () { var action = new cc.FadeOut(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._toOpacity); return action; } }); /** + * Fades Out an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 255 to 0. + * @function * @param {Number} d duration in seconds * @return {cc.FadeOut} * @example * // example - * var action = cc.FadeOut.create(1.0); + * var action = cc.fadeOut(1.0); */ -cc.FadeOut.create = function (d) { - var action = new cc.FadeOut(); - action.initWithDuration(d, 0); - return action; +cc.fadeOut = function (d) { + return new cc.FadeOut(d); }; +/** + * Please use cc.fadeOut instead. + * Fades Out an object that implements the cc.RGBAProtocol protocol. It modifies the opacity from 255 to 0. + * @static + * @deprecated since v3.0 please use cc.fadeOut instead. + * @param {Number} d duration in seconds + * @return {cc.FadeOut} + */ +cc.FadeOut.create = cc.fadeOut; /** Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. * @warning This action doesn't support "reverse" * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {Number} red 0-255 + * @param {Number} green 0-255 + * @param {Number} blue 0-255 + * @example + * var action = new cc.TintTo(2, 255, 0, 255); */ cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{ _to:null, _from:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration * @param {Number} red 0-255 * @param {Number} green 0-255 * @param {Number} blue 0-255 - * @example - * var action = new cc.TintTo(2, 255, 0, 255); */ ctor:function (duration, red, green, blue) { cc.ActionInterval.prototype.ctor.call(this); @@ -2162,6 +2864,7 @@ cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{ }, /** + * Initializes the action. * @param {Number} duration * @param {Number} red 0-255 * @param {Number} green 0-255 @@ -2182,35 +2885,40 @@ cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{ */ clone:function () { var action = new cc.TintTo(); + this._cloneDecoration(action); var locTo = this._to; action.initWithDuration(this._duration, locTo.r, locTo.g, locTo.b); return action; }, /** - * @param {cc.Sprite} target + * Start the action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); - if (this.target.RGBAProtocol) { - this._from = this.target.color; - } + + this._from = this.target.color; }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt time in seconds */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); var locFrom = this._from, locTo = this._to; - if (this.target.RGBAProtocol) { - this.target.color = cc.color(locFrom.r + (locTo.r - locFrom.r) * time, - locFrom.g + (locTo.g - locFrom.g) * time, - locFrom.b + (locTo.b - locFrom.b) * time); + if (locFrom) { + this.target.color = cc.color(locFrom.r + (locTo.r - locFrom.r) * dt, + locFrom.g + (locTo.g - locFrom.g) * dt, + locFrom.b + (locTo.b - locFrom.b) * dt); } } }); /** + * Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. + * @function * @param {Number} duration * @param {Number} red 0-255 * @param {Number} green 0-255 @@ -2218,16 +2926,35 @@ cc.TintTo = cc.ActionInterval.extend(/** @lends cc.TintTo# */{ * @return {cc.TintTo} * @example * // example - * var action = cc.TintTo.create(2, 255, 0, 255); + * var action = cc.tintTo(2, 255, 0, 255); */ -cc.TintTo.create = function (duration, red, green, blue) { +cc.tintTo = function (duration, red, green, blue) { return new cc.TintTo(duration, red, green, blue); }; +/** + * Please use cc.tintTo instead. + * Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. + * @static + * @deprecated since v3.0 please use cc.tintTo instead. + * @param {Number} duration + * @param {Number} red 0-255 + * @param {Number} green 0-255 + * @param {Number} blue 0-255 + * @return {cc.TintTo} + */ +cc.TintTo.create = cc.tintTo; /** Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. + * Relative to their own color change. * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} deltaRed + * @param {Number} deltaGreen + * @param {Number} deltaBlue + * @example + * var action = new cc.TintBy(2, -127, -255, -127); */ cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{ _deltaR:0, @@ -2239,13 +2966,11 @@ cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{ _fromB:0, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration duration in seconds * @param {Number} deltaRed * @param {Number} deltaGreen * @param {Number} deltaBlue - * @example - * var action = new cc.TintBy(2, -127, -255, -127); */ ctor:function (duration, deltaRed, deltaGreen, deltaBlue) { cc.ActionInterval.prototype.ctor.call(this); @@ -2253,6 +2978,7 @@ cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{ }, /** + * Initializes the action. * @param {Number} duration * @param {Number} deltaRed 0-255 * @param {Number} deltaGreen 0-255 @@ -2275,43 +3001,54 @@ cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{ */ clone:function () { var action = new cc.TintBy(); + this._cloneDecoration(action); action.initWithDuration(this._duration, this._deltaR, this._deltaG, this._deltaB); return action; }, /** - * @param {cc.Sprite} target + * Start the action with target. + * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); - if (target.RGBAProtocol) { - var color = target.color; - this._fromR = color.r; - this._fromG = color.g; - this._fromB = color.b; - } + + var color = target.color; + this._fromR = color.r; + this._fromG = color.g; + this._fromB = color.b; + }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt time in seconds */ - update:function (time) { - if (this.target.RGBAProtocol) { - this.target.color = cc.color(this._fromR + this._deltaR * time, - this._fromG + this._deltaG * time, - this._fromB + this._deltaB * time); - } + update:function (dt) { + dt = this._computeEaseTime(dt); + + this.target.color = cc.color(this._fromR + this._deltaR * dt, + this._fromG + this._deltaG * dt, + this._fromB + this._deltaB * dt); + }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.TintBy} */ reverse:function () { - return cc.TintBy.create(this._duration, -this._deltaR, -this._deltaG, -this._deltaB); + var action = new cc.TintBy(this._duration, -this._deltaR, -this._deltaG, -this._deltaB); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; } }); /** + * Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. + * Relative to their own color change. + * @function * @param {Number} duration duration in seconds * @param {Number} deltaRed * @param {Number} deltaGreen @@ -2319,11 +3056,24 @@ cc.TintBy = cc.ActionInterval.extend(/** @lends cc.TintBy# */{ * @return {cc.TintBy} * @example * // example - * var action = cc.TintBy.create(2, -127, -255, -127); + * var action = cc.tintBy(2, -127, -255, -127); */ -cc.TintBy.create = function (duration, deltaRed, deltaGreen, deltaBlue) { +cc.tintBy = function (duration, deltaRed, deltaGreen, deltaBlue) { return new cc.TintBy(duration, deltaRed, deltaGreen, deltaBlue); }; +/** + * Please use cc.tintBy instead. + * Tints a cc.Node that implements the cc.NodeRGB protocol from current tint to a custom one. + * Relative to their own color change. + * @static + * @deprecated since v3.0 please use cc.tintBy instead. + * @param {Number} duration duration in seconds + * @param {Number} deltaRed + * @param {Number} deltaGreen + * @param {Number} deltaBlue + * @return {cc.TintBy} + */ +cc.TintBy.create = cc.tintBy; /** Delays the action a certain amount of seconds * @class @@ -2331,16 +3081,21 @@ cc.TintBy.create = function (duration, deltaRed, deltaGreen, deltaBlue) { */ cc.DelayTime = cc.ActionInterval.extend(/** @lends cc.DelayTime# */{ /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * Will be overwrite. + * @param {Number} dt time in seconds */ - update:function (time) { - }, + update:function (dt) {}, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.DelayTime} */ reverse:function () { - return cc.DelayTime.create(this._duration); + var action = new cc.DelayTime(this._duration); + this._cloneDecoration(action); + this._reverseEaseList(action); + return action; }, /** @@ -2349,39 +3104,53 @@ cc.DelayTime = cc.ActionInterval.extend(/** @lends cc.DelayTime# */{ */ clone:function () { var action = new cc.DelayTime(); + this._cloneDecoration(action); action.initWithDuration(this._duration); return action; } }); /** + * Delays the action a certain amount of seconds + * @function * @param {Number} d duration in seconds * @return {cc.DelayTime} * @example * // example - * var delay = cc.DelayTime.create(1); + * var delay = cc.delayTime(1); */ -cc.DelayTime.create = function (d) { +cc.delayTime = function (d) { return new cc.DelayTime(d); }; +/** + * Please use cc.delayTime instead. + * Delays the action a certain amount of seconds + * @static + * @deprecated since v3.0 please use cc.delaTime instead. + * @param {Number} d duration in seconds + * @return {cc.DelayTime} + */ +cc.DelayTime.create = cc.delayTime; /** - * Executes an action in reverse order, from time=duration to time=0 - * @warning Use this action carefully. This action is not - * sequenceable. Use it as the default "reversed" method - * of your own actions, but using it outside the "reversed" + *

+ * Executes an action in reverse order, from time=duration to time=0
+ * @warning Use this action carefully. This action is not sequenceable.
+ * Use it as the default "reversed" method of your own actions, but using it outside the "reversed"
* scope is not recommended. + *

* @class * @extends cc.ActionInterval + * @param {cc.FiniteTimeAction} action + * @example + * var reverse = new cc.ReverseTime(this); */ cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{ _other:null, /** - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {cc.FiniteTimeAction} action - * @example - * var reverse = new cc.ReverseTime(this); */ ctor:function (action) { cc.ActionInterval.prototype.ctor.call(this); @@ -2397,10 +3166,10 @@ cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{ initWithAction:function (action) { if(!action) throw "cc.ReverseTime.initWithAction(): action must be non null"; - if(action == this._other) + if(action === this._other) throw "cc.ReverseTime.initWithAction(): the action was already passed in."; - if (cc.ActionInterval.prototype.initWithDuration.call(this, action.getDuration())) { + if (cc.ActionInterval.prototype.initWithDuration.call(this, action._duration)) { // Don't leak if action is reused this._other = action; return true; @@ -2414,11 +3183,13 @@ cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{ */ clone:function () { var action = new cc.ReverseTime(); + this._cloneDecoration(action); action.initWithAction(this._other.clone()); return action; }, /** + * Start the action with target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -2427,14 +3198,17 @@ cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{ }, /** - * @param {Number} time time in seconds + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt time in seconds */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); if (this._other) - this._other.update(1 - time); + this._other.update(1 - dt); }, /** + * Returns a reversed action. * @return {cc.ActionInterval} */ reverse:function () { @@ -2451,20 +3225,35 @@ cc.ReverseTime = cc.ActionInterval.extend(/** @lends cc.ReverseTime# */{ }); /** + * Executes an action in reverse order, from time=duration to time=0. + * @function * @param {cc.FiniteTimeAction} action * @return {cc.ReverseTime} * @example * // example - * var reverse = cc.ReverseTime.create(this); + * var reverse = cc.reverseTime(this); */ -cc.ReverseTime.create = function (action) { +cc.reverseTime = function (action) { return new cc.ReverseTime(action); }; +/** + * Please use cc.reverseTime instead. + * Executes an action in reverse order, from time=duration to time=0. + * @static + * @deprecated since v3.0 please use cc.reverseTime instead. + * @param {cc.FiniteTimeAction} action + * @return {cc.ReverseTime} + */ +cc.ReverseTime.create = cc.reverseTime; /** Animates a sprite given the name of an Animation * @class * @extends cc.ActionInterval + * @param {cc.Animation} animation + * @example + * // create the animation with animation + * var anim = new cc.Animate(dance_grey); */ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ _animation:null, @@ -2474,12 +3263,9 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ _splitTimes:null, /** - * @constructor - * create the animate with animation + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * create the animate with animation. * @param {cc.Animation} animation - * @example - * // create the animation with animation - * var anim = new cc.Animate(dance_grey); */ ctor:function (animation) { cc.ActionInterval.prototype.ctor.call(this); @@ -2542,11 +3328,13 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ */ clone:function () { var action = new cc.Animate(); + this._cloneDecoration(action); action.initWithAnimation(this._animation.clone()); return action; }, /** + * Start the action with target. * @param {cc.Sprite} target */ startWithTarget:function (target) { @@ -2558,28 +3346,30 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { + update:function (dt) { + dt = this._computeEaseTime(dt); // if t==1, ignore. Animation should finish with t==1 - if (time < 1.0) { - time *= this._animation.getLoops(); + if (dt < 1.0) { + dt *= this._animation.getLoops(); // new loop? If so, reset frame counter - var loopNumber = 0 | time; + var loopNumber = 0 | dt; if (loopNumber > this._executedLoops) { this._nextFrame = 0; this._executedLoops++; } // new t for animations - time = time % 1.0; + dt = dt % 1.0; } var frames = this._animation.getFrames(); var numberOfFrames = frames.length, locSplitTimes = this._splitTimes; for (var i = this._nextFrame; i < numberOfFrames; i++) { - if (locSplitTimes[i] <= time) { + if (locSplitTimes[i] <= dt) { this.target.setSpriteFrame(frames[i].getSpriteFrame()); this._nextFrame = i + 1; } else { @@ -2590,7 +3380,8 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ }, /** - * @return {cc.ActionInterval} + * Returns a reversed action. + * @return {cc.Animate} */ reverse:function () { var locAnimation = this._animation; @@ -2605,9 +3396,13 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ newArray.push(element.clone()); } } - var newAnim = cc.Animation.create(newArray, locAnimation.getDelayPerUnit(), locAnimation.getLoops()); + var newAnim = new cc.Animation(newArray, locAnimation.getDelayPerUnit(), locAnimation.getLoops()); newAnim.setRestoreOriginalFrame(locAnimation.getRestoreOriginalFrame()); - return cc.Animate.create(newAnim); + var action = new cc.Animate(newAnim); + this._cloneDecoration(action); + this._reverseEaseList(action); + + return action; }, /** @@ -2622,16 +3417,26 @@ cc.Animate = cc.ActionInterval.extend(/** @lends cc.Animate# */{ /** * create the animate with animation + * @function * @param {cc.Animation} animation * @return {cc.Animate} * @example * // example * // create the animation with animation - * var anim = cc.Animate.create(dance_grey); + * var anim = cc.animate(dance_grey); */ -cc.Animate.create = function (animation) { +cc.animate = function (animation) { return new cc.Animate(animation); }; +/** + * Please use cc.animate instead + * create the animate with animation + * @static + * @deprecated since v3.0 please use cc.animate instead. + * @param {cc.Animation} animation + * @return {cc.Animate} + */ +cc.Animate.create = cc.animate; /** *

@@ -2640,14 +3445,16 @@ cc.Animate.create = function (animation) { *

* @class * @extends cc.ActionInterval + * @param {cc.Node} target + * @param {cc.FiniteTimeAction} action */ cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{ _action:null, _forcedTarget:null, /** - * Create an action with the specified action and forced target - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create an action with the specified action and forced target. * @param {cc.Node} target * @param {cc.FiniteTimeAction} action */ @@ -2663,7 +3470,7 @@ cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{ * @return {Boolean} */ initWithTarget:function (target, action) { - if (this.initWithDuration(action.getDuration())) { + if (this.initWithDuration(action._duration)) { this._forcedTarget = target; this._action = action; return true; @@ -2677,21 +3484,34 @@ cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{ */ clone:function () { var action = new cc.TargetedAction(); + this._cloneDecoration(action); action.initWithTarget(this._forcedTarget, this._action.clone()); return action; }, + /** + * Start the action with target. + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); this._action.startWithTarget(this._forcedTarget); }, + /** + * stop the action + */ stop:function () { this._action.stop(); }, - update:function (time) { - this._action.update(time); + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { + dt = this._computeEaseTime(dt); + this._action.update(dt); }, /** @@ -2707,17 +3527,28 @@ cc.TargetedAction = cc.ActionInterval.extend(/** @lends cc.TargetedAction# */{ * @param {cc.Node} forcedTarget */ setForcedTarget:function (forcedTarget) { - if (this._forcedTarget != forcedTarget) + if (this._forcedTarget !== forcedTarget) this._forcedTarget = forcedTarget; } }); /** * Create an action with the specified action and forced target + * @function * @param {cc.Node} target * @param {cc.FiniteTimeAction} action * @return {cc.TargetedAction} */ -cc.TargetedAction.create = function (target, action) { +cc.targetedAction = function (target, action) { return new cc.TargetedAction(target, action); }; +/** + * Please use cc.targetedAction instead + * Create an action with the specified action and forced target + * @static + * @deprecated since v3.0 please use cc.targetedAction instead. + * @param {cc.Node} target + * @param {cc.FiniteTimeAction} action + * @return {cc.TargetedAction} + */ +cc.TargetedAction.create = cc.targetedAction; diff --git a/cocos2d/actions/CCActionTween.js b/cocos2d/actions/CCActionTween.js index 5877e8c93b..12490a4146 100644 --- a/cocos2d/actions/CCActionTween.js +++ b/cocos2d/actions/CCActionTween.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,13 +25,18 @@ ****************************************************************************/ /** + * * @class * @extends cc.Class */ cc.ActionTweenDelegate = cc.Class.extend(/** @lends cc.ActionTweenDelegate */{ - updateTweenAction:function(value, key){ - } + /** + * Update Tween Action. + * @param value + * @param key + */ + updateTweenAction:function(value, key){} }); /** @@ -42,13 +47,17 @@ cc.ActionTweenDelegate = cc.Class.extend(/** @lends cc.ActionTweenDelegate */{ * @extends cc.ActionInterval * @example * //For example, if you want to modify the "width" property of a target from 200 to 300 in 2 seconds, then: - * var modifyWidth = cc.ActionTween.create(2,"width",200,300) + * var modifyWidth = cc.actionTween(2,"width",200,300) * target.runAction(modifyWidth); * * //Another example: cc.ScaleTo action could be rewriten using cc.PropertyAction: * // scaleA and scaleB are equivalents - * var scaleA = cc.ScaleTo.create(2,3); - * var scaleB = cc.ActionTween.create(2,"scale",1,3); + * var scaleA = cc.scaleTo(2,3); + * var scaleB = cc.actionTween(2,"scale",1,3); + * @param {Number} duration + * @param {String} key + * @param {Number} from + * @param {Number} to */ cc.ActionTween = cc.ActionInterval.extend(/** @lends cc.ActionTween */{ key:"", @@ -57,8 +66,8 @@ cc.ActionTween = cc.ActionInterval.extend(/** @lends cc.ActionTween */{ delta:0, /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
* Creates an initializes the action with the property name (key), and the from and to parameters. - * @constructor * @param {Number} duration * @param {String} key * @param {Number} from @@ -88,8 +97,10 @@ cc.ActionTween = cc.ActionInterval.extend(/** @lends cc.ActionTween */{ } return false; }, + /** - * @param {cc.Node} target + * Start this tween with target. + * @param {cc.ActionTweenDelegate} target */ startWithTarget:function (target) { if(!target || !target.updateTweenAction) @@ -97,19 +108,30 @@ cc.ActionTween = cc.ActionInterval.extend(/** @lends cc.ActionTween */{ cc.ActionInterval.prototype.startWithTarget.call(this, target); this.delta = this.to - this.from; }, + /** - * @param {Number} dt + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt */ update:function (dt) { this.target.updateTweenAction(this.to - this.delta * (1 - dt), this.key); }, + /** + * returns a reversed action. * @return {cc.ActionTween} */ reverse:function () { - return cc.ActionTween.create(this.duration, this.key, this.to, this.from); + return new cc.ActionTween(this.duration, this.key, this.to, this.from); }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.ActionTween} + */ clone:function(){ var action = new cc.ActionTween(); action.initWithDuration(this._duration, this.key, this.from, this.to); @@ -119,15 +141,26 @@ cc.ActionTween = cc.ActionInterval.extend(/** @lends cc.ActionTween */{ /** * Creates an initializes the action with the property name (key), and the from and to parameters. + * @function * @param {Number} duration * @param {String} key * @param {Number} from * @param {Number} to * @return {cc.ActionTween} */ -cc.ActionTween.create = function (duration, key, from, to) { - var ret = new cc.ActionTween(); - if (ret.initWithDuration(duration, key, from, to)) - return ret; - return null; +cc.actionTween = function (duration, key, from, to) { + return new cc.ActionTween(duration, key, from, to); }; + +/** + * Please use cc.actionTween instead. + * Creates an initializes the action with the property name (key), and the from and to parameters. + * @static + * @deprecated since v3.0
Please use cc.actionTween instead. + * @param {Number} duration + * @param {String} key + * @param {Number} from + * @param {Number} to + * @return {cc.ActionTween} + */ +cc.ActionTween.create = cc.actionTween; \ No newline at end of file diff --git a/cocos2d/actions3d/CCActionGrid.js b/cocos2d/actions3d/CCActionGrid.js index 8f7feea8f7..38b5c8a37f 100644 --- a/cocos2d/actions3d/CCActionGrid.js +++ b/cocos2d/actions3d/CCActionGrid.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2013 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -28,13 +28,15 @@ * Base class for Grid actions * @class * @extends cc.ActionInterval + * @param {Number} duration + * @param {cc.Size} gridSize */ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ _gridSize:null, + _gridNodeTarget:null, /** - * Creates a grid action with duration and grid size - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} duration * @param {cc.Size} gridSize */ @@ -46,6 +48,14 @@ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ gridSize && this.initWithDuration(duration, gridSize); }, + _cacheTargetAsGridNode: function(){}, + + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.Action} + */ clone:function(){ var action = new cc.GridAction(); var locGridSize = this._gridSize; @@ -53,14 +63,20 @@ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ return action; }, + /** + * called before the action start. It will also set the target. + * + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); + cc.renderer.childrenOrderDirty = true; var newGrid = this.getGrid(); var t = this.target; var targetGrid = t.grid; if (targetGrid && targetGrid.getReuseGrid() > 0) { var locGridSize = targetGrid.getGridSize(); - if (targetGrid.isActive() && (locGridSize.width == this._gridSize.width) && (locGridSize.height == this._gridSize.height)) + if (targetGrid.isActive() && (locGridSize.width === this._gridSize.width) && (locGridSize.height === this._gridSize.height)) targetGrid.reuse(); } else { if (targetGrid && targetGrid.isActive()) @@ -70,12 +86,16 @@ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ } }, + /** + * Create a cc.ReverseTime action. Opposite with the original motion trajectory. + * @return {cc.ReverseTime} + */ reverse:function () { - return cc.ReverseTime.create(this); + return new cc.ReverseTime(this); }, /** - * initializes the action with size and duration + * Initializes the action with size and duration. * @param {Number} duration * @param {cc.Size} gridSize * @return {Boolean} @@ -90,7 +110,7 @@ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ }, /** - * returns the grid + * Returns the grid. * @return {cc.GridBase} */ getGrid:function () { @@ -101,16 +121,28 @@ cc.GridAction = cc.ActionInterval.extend(/** @lends cc.GridAction# */{ /** * creates the action with size and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.GridAction} */ -cc.GridAction.create = function (duration, gridSize) { +cc.gridAction = function (duration, gridSize) { return new cc.GridAction(duration, gridSize); }; /** - * Base class for cc.Grid3D actions.
+ * Please use cc.gridAction instead.
+ * Creates the action with size and duration. + * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.GridAction} + * @static + * @deprecated since v3.0
Please use cc.gridAction instead. + */ +cc.GridAction.create = cc.gridAction; + +/** + * Base class for cc.Grid3D actions.
* Grid3D actions can modify a non-tiled grid. * @class * @extends cc.GridAction @@ -119,27 +151,47 @@ cc.Grid3DAction = cc.GridAction.extend(/** @lends cc.Grid3DAction# */{ /** * returns the grid - * @return {cc.GridBase} + * @return {cc.Grid3D} */ getGrid:function () { - return cc.Grid3D.create(this._gridSize); + return new cc.Grid3D(this._gridSize); }, /** - * returns the vertex than belongs to certain position in the grid + * returns the vertex than belongs to certain position in the grid.
+ * It will be deprecated in future, please use getVertex instead. * @param {cc.Point} position * @return {cc.Vertex3F} */ vertex:function (position) { - return this.target.grid.vertex(position); + return this.getVertex(position); }, /** - * returns the non-transformed vertex than belongs to certain position in the grid + * returns the vertex than belongs to certain position in the grid * @param {cc.Point} position - * @return {*} + * @return {cc.Vertex3F} + */ + getVertex: function(position){ + return this.target.grid.getVertex(position); + }, + + /** + * returns the non-transformed vertex than belongs to certain position in the grid
+ * It will be deprecated in future, please use getVertex instead. + * @param {cc.Point} position + * @return {cc.Vertex3F} */ originalVertex:function (position) { + return this.getOriginalVertex(position); + }, + + /** + * returns the non-transformed vertex than belongs to certain position in the grid + * @param {cc.Point} position + * @return {cc.Vertex3F} + */ + getOriginalVertex:function (position) { return this.target.grid.originalVertex(position); }, @@ -155,36 +207,67 @@ cc.Grid3DAction = cc.GridAction.extend(/** @lends cc.Grid3DAction# */{ /** * creates the action with size and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.Grid3DAction} */ -cc.Grid3DAction.create = function (duration, gridSize) { +cc.grid3DAction = function (duration, gridSize) { return new cc.Grid3DAction(duration, gridSize); }; +/** + * Please use cc.grid3DAction instead.
+ * creates the action with size and duration.
+ * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.Grid3DAction} + * @static + * @deprecated since v3.0
Please use cc.grid3DAction instead. + */ +cc.Grid3DAction.create = cc.grid3DAction; /** - * Base class for cc.TiledGrid3D actions + * Base class for cc.TiledGrid3D actions. * @class * @extends cc.GridAction */ cc.TiledGrid3DAction = cc.GridAction.extend(/** @lends cc.TiledGrid3DAction# */{ /** - * returns the tile that belongs to a certain position of the grid + * returns the tile that belongs to a certain position of the grid
+ * It will be deprecated in future, please use getTile instead. * @param {cc.Point} position * @return {cc.Quad3} */ tile:function (position) { + return this.getTile(position); + }, + + /** + * returns the tile that belongs to a certain position of the grid + * @param {cc.Point} position + * @return {cc.Quad3} + */ + getTile:function (position) { return this.target.grid.tile(position); }, /** - * returns the non-transformed tile that belongs to a certain position of the grid + * returns the non-transformed tile that belongs to a certain position of the grid
+ * It will be deprecated in future, please use getOriginalTile instead. * @param {cc.Point} position * @return {cc.Quad3} */ originalTile:function (position) { + return this.getOriginalTile(position); + }, + + /** + * returns the non-transformed tile that belongs to a certain position of the grid + * @param {cc.Point} position + * @return {cc.Quad3} + */ + getOriginalTile:function (position) { return this.target.grid.originalTile(position); }, @@ -199,36 +282,55 @@ cc.TiledGrid3DAction = cc.GridAction.extend(/** @lends cc.TiledGrid3DAction# */{ /** * returns the grid - * @return {cc.GridBase} + * @return {cc.TiledGrid3D} */ getGrid:function () { - return cc.TiledGrid3D.create(this._gridSize); + return new cc.TiledGrid3D(this._gridSize); } }); /** * Creates the action with duration and grid size + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.TiledGrid3DAction} */ -cc.TiledGrid3DAction.create = function (duration, gridSize) { +cc.tiledGrid3DAction = function (duration, gridSize) { return new cc.TiledGrid3DAction(duration, gridSize); }; +/** + * Please use cc.tiledGrid3DAction instead + * Creates the action with duration and grid size + * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.TiledGrid3DAction} + * @static + * @deprecated since v3.0
Please use cc.tiledGrid3DAction instead. + */ +cc.TiledGrid3DAction.create = cc.tiledGrid3DAction; + /** *

* cc.StopGrid action.
* @warning Don't call this action if another grid action is active.
* Call if you want to remove the the grid effect. Example:
- * cc.Sequence.create(Lens.action(...), cc.StopGrid.create(...), null);
+ * cc.sequence(Lens.action(...), cc.stopGrid(...), null);
*

* @class * @extends cc.ActionInstant */ cc.StopGrid = cc.ActionInstant.extend(/** @lends cc.StopGrid# */{ + + /** + * called before the action start. It will also set the target. + * + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.ActionInstant.prototype.startWithTarget.call(this, target); + cc.renderer.childrenOrderDirty = true; var grid = this.target.grid; if (grid && grid.isActive()) grid.setActive(false); @@ -237,23 +339,32 @@ cc.StopGrid = cc.ActionInstant.extend(/** @lends cc.StopGrid# */{ /** * Allocates and initializes the action + * @function * @return {cc.StopGrid} */ -cc.StopGrid.create = function () { +cc.stopGrid = function () { return new cc.StopGrid(); }; +/** + * Please use cc.stopGrid instead + * Allocates and initializes the action + * @return {cc.StopGrid} + * @static + * @deprecated since v3.0
Please use cc.stopGrid instead. + */ +cc.StopGrid.create = cc.stopGrid; /** * cc.ReuseGrid action * @class * @extends cc.ActionInstant + * @param {Number} times */ cc.ReuseGrid = cc.ActionInstant.extend(/** @lends cc.ReuseGrid# */{ _times:null, /** - * creates an action with the number of times that the current grid will be reused - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {Number} times */ ctor: function(times) { @@ -271,8 +382,14 @@ cc.ReuseGrid = cc.ActionInstant.extend(/** @lends cc.ReuseGrid# */{ return true; }, + /** + * called before the action start. It will also set the target. + * + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.ActionInstant.prototype.startWithTarget.call(this, target); + cc.renderer.childrenOrderDirty = true; if (this.target.grid && this.target.grid.isActive()) this.target.grid.setReuseGrid(this.target.grid.getReuseGrid() + this._times); } @@ -280,9 +397,19 @@ cc.ReuseGrid = cc.ActionInstant.extend(/** @lends cc.ReuseGrid# */{ /** * creates an action with the number of times that the current grid will be reused + * @function * @param {Number} times * @return {cc.ReuseGrid} */ -cc.ReuseGrid.create = function (times) { +cc.reuseGrid = function (times) { return new cc.ReuseGrid(times); }; +/** + * Please use cc.reuseGrid instead + * creates an action with the number of times that the current grid will be reused + * @param {Number} times + * @return {cc.ReuseGrid} + * @static + * @deprecated since v3.0
Please use cc.reuseGrid instead. + */ +cc.ReuseGrid.create = cc.reuseGrid; diff --git a/cocos2d/actions3d/CCActionGrid3D.js b/cocos2d/actions3d/CCActionGrid3D.js index f1387f1d9c..31be9c2e9a 100644 --- a/cocos2d/actions3d/CCActionGrid3D.js +++ b/cocos2d/actions3d/CCActionGrid3D.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,9 +25,14 @@ ****************************************************************************/ /** - * cc.Waves3D action + * cc.Waves3D action.
+ * Reference the test cases (Effects Advanced Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude */ cc.Waves3D = cc.Grid3DAction.extend(/** @lends cc.Waves3D# */{ _waves: 0, @@ -35,7 +40,8 @@ cc.Waves3D = cc.Grid3DAction.extend(/** @lends cc.Waves3D# */{ _amplitudeRate: 0, /** - * Create a wave 3d action with duration, grid size, waves and amplitude + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a wave 3d action with duration, grid size, waves and amplitude. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves @@ -96,7 +102,12 @@ cc.Waves3D = cc.Grid3DAction.extend(/** @lends cc.Waves3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var locGridSize = this._gridSize; var locAmplitude = this._amplitude, locPos = cc.p(0, 0); var locAmplitudeRate = this._amplitudeRate, locWaves = this._waves; @@ -105,8 +116,8 @@ cc.Waves3D = cc.Grid3DAction.extend(/** @lends cc.Waves3D# */{ locPos.x = i; locPos.y = j; var v = this.originalVertex(locPos); - v.z += (Math.sin(Math.PI * time * locWaves * 2 + (v.y + v.x) * 0.01) * locAmplitude * locAmplitudeRate); - //cc.log("v.z offset is" + (Math.sin(Math.PI * time * this._waves * 2 + (v.y + v.x) * 0.01) * this._amplitude * this._amplitudeRate)); + v.z += (Math.sin(Math.PI * dt * locWaves * 2 + (v.y + v.x) * 0.01) * locAmplitude * locAmplitudeRate); + //cc.log("v.z offset is" + (Math.sin(Math.PI * dt * this._waves * 2 + (v.y + v.x) * 0.01) * this._amplitude * this._amplitudeRate)); this.setVertex(locPos, v); } } @@ -114,26 +125,41 @@ cc.Waves3D = cc.Grid3DAction.extend(/** @lends cc.Waves3D# */{ }); /** - * Create a wave 3d action with duration, grid size, waves and amplitude + * Create a wave 3d action with duration, grid size, waves and amplitude. + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves * @param {Number} amplitude */ -cc.Waves3D.create = function (duration, gridSize, waves, amplitude) { +cc.waves3D = function (duration, gridSize, waves, amplitude) { return new cc.Waves3D(duration, gridSize, waves, amplitude); }; +/** + * Please use cc.waves3D instead.
+ * Create a wave 3d action with duration, grid size, waves and amplitude. + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude + * @static + * @deprecated since v3.0
Please use cc.waves3D instead. + */ +cc.Waves3D.create = cc.waves3D; /** - * cc.FlipX3D action + * cc.FlipX3D action.
+ * Flip around.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration */ cc.FlipX3D = cc.Grid3DAction.extend(/** @lends cc.FlipX3D# */{ /** - * Create a Flip X 3D action with duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a Flip X 3D action with duration. * @param {Number} duration */ ctor: function(duration) { @@ -158,7 +184,7 @@ cc.FlipX3D = cc.Grid3DAction.extend(/** @lends cc.FlipX3D# */{ * @return {Boolean} */ initWithSize:function (gridSize, duration) { - if (gridSize.width != 1 || gridSize.height != 1) { + if (gridSize.width !== 1 || gridSize.height !== 1) { // Grid size must be (1,1) cc.log("Grid size must be (1,1)"); return false; @@ -166,8 +192,13 @@ cc.FlipX3D = cc.Grid3DAction.extend(/** @lends cc.FlipX3D# */{ return cc.Grid3DAction.prototype.initWithDuration.call(this, duration, gridSize); }, - update:function (time) { - var angle = Math.PI * time; // 180 degrees + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { + var angle = Math.PI * dt; // 180 degrees var mz = Math.sin(angle); angle = angle / 2.0; // x calculates degrees from 0 to 90 var mx = Math.cos(angle); @@ -230,24 +261,40 @@ cc.FlipX3D = cc.Grid3DAction.extend(/** @lends cc.FlipX3D# */{ }); /** - * Create a Flip X 3D action with duration + * Create a Flip X 3D action with duration.
+ * Flip around. + * @function * @param {Number} duration * @return {cc.FlipX3D} */ -cc.FlipX3D.create = function (duration) { +cc.flipX3D = function (duration) { return new cc.FlipX3D(duration); }; /** - * cc.FlipY3D action + * Please use cc.flipX3D instead.
+ * Create a Flip X 3D action with duration.
+ * Flip around. + * @param {Number} duration + * @return {cc.FlipX3D} + * @static + * @deprecated since v3.0
Please use cc.flipX3D instead. + */ +cc.FlipX3D.create = cc.flipX3D; + +/** + * cc.FlipY3D action.
+ * Upside down.
+ * Reference the test cases (Effects Test) * @class * @extends cc.FlipX3D + * @param {Number} duration */ cc.FlipY3D = cc.FlipX3D.extend(/** @lends cc.FlipY3D# */{ /** - * Create a flip Y 3d action with duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a flip Y 3d action with duration. * @param {Number} duration */ ctor: function(duration) { @@ -256,8 +303,13 @@ cc.FlipY3D = cc.FlipX3D.extend(/** @lends cc.FlipY3D# */{ else cc.GridAction.prototype.ctor.call(this); }, - update:function (time) { - var angle = Math.PI * time; // 180 degrees + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { + var angle = Math.PI * dt; // 180 degrees var mz = Math.sin(angle); angle = angle / 2.0; // x calculates degrees from 0 to 90 var my = Math.cos(angle); @@ -321,32 +373,50 @@ cc.FlipY3D = cc.FlipX3D.extend(/** @lends cc.FlipY3D# */{ }); /** - * Create a flip Y 3d action with duration + * Create a flip Y 3d action with duration.
+ * Upside down. + * @function * @param {Number} duration * @return {cc.FlipY3D} */ -cc.FlipY3D.create = function (duration) { +cc.flipY3D = function (duration) { return new cc.FlipY3D(duration); }; /** - * cc.Lens3D action + * Please use cc.flipY3D instead.
+ * Create a flip Y 3d action with duration. + * @param {Number} duration + * @return {cc.FlipY3D} + * @static + * @deprecated since v3.0
Please use cc.flipY3D instead. + */ +cc.FlipY3D.create = cc.flipY3D; + +/** + * cc.Lens3D action.
+ * Upside down.
+ * Reference the test cases (Effects Test) * @class - * @extends cc.FlipX3D + * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} radius */ cc.Lens3D = cc.Grid3DAction.extend(/** @lends cc.Lens3D# */{ - /* lens center position */ + //lens center position _position:null, _radius:0, - /** lens effect. Defaults to 0.7 - 0 means no effect, 1 is very strong effect */ + //lens effect. Defaults to 0.7 - 0 means no effect, 1 is very strong effect _lensEffect:0, - /** lens is concave. (true = concave, false = convex) default is convex i.e. false */ + //lens is concave. (true = concave, false = convex) default is convex i.e. false _concave:false, _dirty:false, /** - * creates a lens 3d action with center position, radius - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates a lens 3d action with center position, radius. * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position @@ -422,7 +492,12 @@ cc.Lens3D = cc.Grid3DAction.extend(/** @lends cc.Lens3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { if (this._dirty) { var locGridSizeWidth = this._gridSize.width, locGridSizeHeight = this._gridSize.height; var locRadius = this._radius, locLensEffect = this._lensEffect; @@ -441,7 +516,7 @@ cc.Lens3D = cc.Grid3DAction.extend(/** @lends cc.Lens3D# */{ if (r < locRadius) { r = locRadius - r; pre_log = r / locRadius; - if (pre_log == 0) + if (pre_log === 0) pre_log = 0.001; l = Math.log(pre_log) * locLensEffect; @@ -467,20 +542,41 @@ cc.Lens3D = cc.Grid3DAction.extend(/** @lends cc.Lens3D# */{ /** * creates a lens 3d action with center position, radius + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position * @param {Number} radius * @return {cc.Lens3D} */ -cc.Lens3D.create = function (duration, gridSize, position, radius) { +cc.lens3D = function (duration, gridSize, position, radius) { return new cc.Lens3D(duration, gridSize, position, radius); }; /** - * cc.Ripple3D action + * Please use cc.lens3D instead + * creates a lens 3d action with center position, radius + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} radius + * @return {cc.Lens3D} + * @static + * @deprecated since v3.0
Please use cc.lens3D instead. + */ +cc.Lens3D.create = cc.lens3D; + +/** + * cc.Ripple3D action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} radius + * @param {Number} waves + * @param {Number} amplitude */ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ /* center position */ @@ -491,8 +587,8 @@ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ _amplitudeRate: 0, /** - * creates a ripple 3d action with radius, number of waves, amplitude - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates a ripple 3d action with radius, number of waves, amplitude. * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position @@ -578,7 +674,12 @@ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var locGridSizeWidth = this._gridSize.width, locGridSizeHeight = this._gridSize.height; var locPos = cc.p(0, 0), locRadius = this._radius; var locWaves = this._waves, locAmplitude = this._amplitude, locAmplitudeRate = this._amplitudeRate; @@ -596,7 +697,7 @@ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ if (r < locRadius) { r = locRadius - r; var rate = Math.pow(r / locRadius, 2); - v.z += (Math.sin(time * Math.PI * locWaves * 2 + r * 0.1) * locAmplitude * locAmplitudeRate * rate); + v.z += (Math.sin(dt * Math.PI * locWaves * 2 + r * 0.1) * locAmplitude * locAmplitudeRate * rate); } this.setVertex(locPos, v); } @@ -606,6 +707,7 @@ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ /** * creates a ripple 3d action with radius, number of waves, amplitude + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position @@ -614,22 +716,42 @@ cc.Ripple3D = cc.Grid3DAction.extend(/** @lends cc.Ripple3D# */{ * @param {Number} amplitude * @return {cc.Ripple3D} */ -cc.Ripple3D.create = function (duration, gridSize, position, radius, waves, amplitude) { +cc.ripple3D = function (duration, gridSize, position, radius, waves, amplitude) { return new cc.Ripple3D(duration, gridSize, position, radius, waves, amplitude); }; /** - * cc.Shaky3D action + * Please use cc.ripple3D instead + * creates a ripple 3d action with radius, number of waves, amplitude + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} radius + * @param {Number} waves + * @param {Number} amplitude + * @return {cc.Ripple3D} + * @static + * @deprecated since v3.0
Please use cc.ripple3D instead. + */ +cc.Ripple3D.create = cc.ripple3D; + +/** + * cc.Shaky3D action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shakeZ */ cc.Shaky3D = cc.Grid3DAction.extend(/** @lends cc.Shaky3D# */{ _randRange: 0, _shakeZ: false, /** - * Create a shaky3d action with a range, shake Z vertices - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a shaky3d action with a range, shake Z vertices. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range @@ -657,7 +779,12 @@ cc.Shaky3D = cc.Grid3DAction.extend(/** @lends cc.Shaky3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var locGridSizeWidth = this._gridSize.width, locGridSizeHeight = this._gridSize.height; var locRandRange = this._randRange, locShakeZ = this._shakeZ, locP = cc.p(0, 0); var v; @@ -678,20 +805,39 @@ cc.Shaky3D = cc.Grid3DAction.extend(/** @lends cc.Shaky3D# */{ /** * creates the action with a range, shake Z vertices, a grid and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range * @param {Boolean} shakeZ * @return {cc.Shaky3D} */ -cc.Shaky3D.create = function (duration, gridSize, range, shakeZ) { +cc.shaky3D = function (duration, gridSize, range, shakeZ) { return new cc.Shaky3D(duration, gridSize, range, shakeZ); }; /** - * cc.Liquid action + * Please use cc.shaky3D instead + * creates the action with a range, shake Z vertices, a grid and duration + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shakeZ + * @return {cc.Shaky3D} + * @static + * @deprecated since v3.0
Please use cc.shaky3D instead. + */ +cc.Shaky3D.create = cc.shaky3D; + +/** + * cc.Liquid action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude */ cc.Liquid = cc.Grid3DAction.extend(/** @lends cc.Liquid# */{ _waves: 0, @@ -699,9 +845,8 @@ cc.Liquid = cc.Grid3DAction.extend(/** @lends cc.Liquid# */{ _amplitudeRate: 0, /** - * Create a liquid action with amplitude, a grid and duration - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a liquid action with amplitude, a grid and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves @@ -762,7 +907,12 @@ cc.Liquid = cc.Grid3DAction.extend(/** @lends cc.Liquid# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var locSizeWidth = this._gridSize.width, locSizeHeight = this._gridSize.height, locPos = cc.p(0, 0); var locWaves = this._waves, locAmplitude = this._amplitude, locAmplitudeRate = this._amplitudeRate; var v; @@ -771,8 +921,8 @@ cc.Liquid = cc.Grid3DAction.extend(/** @lends cc.Liquid# */{ locPos.x = i; locPos.y = j; v = this.originalVertex(locPos); - v.x = (v.x + (Math.sin(time * Math.PI * locWaves * 2 + v.x * .01) * locAmplitude * locAmplitudeRate)); - v.y = (v.y + (Math.sin(time * Math.PI * locWaves * 2 + v.y * .01) * locAmplitude * locAmplitudeRate)); + v.x = (v.x + (Math.sin(dt * Math.PI * locWaves * 2 + v.x * .01) * locAmplitude * locAmplitudeRate)); + v.y = (v.y + (Math.sin(dt * Math.PI * locWaves * 2 + v.y * .01) * locAmplitude * locAmplitudeRate)); this.setVertex(locPos, v); } } @@ -781,20 +931,41 @@ cc.Liquid = cc.Grid3DAction.extend(/** @lends cc.Liquid# */{ /** * creates the action with amplitude, a grid and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves * @param {Number} amplitude * @return {cc.Liquid} */ -cc.Liquid.create = function (duration, gridSize, waves, amplitude) { +cc.liquid = function (duration, gridSize, waves, amplitude) { return new cc.Liquid(duration, gridSize, waves, amplitude); }; /** - * cc.Waves action + * Please use cc.liquid instead + * creates the action with amplitude, a grid and duration + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude + * @return {cc.Liquid} + * @static + * @deprecated since v3.0
Please use cc.liquid instead. + */ +cc.Liquid.create = cc.liquid; + +/** + * cc.Waves action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude + * @param {Boolean} horizontal + * @param {Boolean} vertical */ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ _waves: 0, @@ -804,9 +975,8 @@ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ _horizontal: false, /** - * Create a wave action with amplitude, horizontal sin, vertical sin, a grid and duration - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a wave action with amplitude, horizontal sin, vertical sin, a grid and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves @@ -873,7 +1043,12 @@ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var locSizeWidth = this._gridSize.width, locSizeHeight = this._gridSize.height, locPos = cc.p(0, 0); var locVertical = this._vertical, locHorizontal = this._horizontal; var locWaves = this._waves, locAmplitude = this._amplitude, locAmplitudeRate = this._amplitudeRate; @@ -884,9 +1059,9 @@ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ locPos.y = j; v = this.originalVertex(locPos); if (locVertical) - v.x = (v.x + (Math.sin(time * Math.PI * locWaves * 2 + v.y * .01) * locAmplitude * locAmplitudeRate)); + v.x = (v.x + (Math.sin(dt * Math.PI * locWaves * 2 + v.y * .01) * locAmplitude * locAmplitudeRate)); if (locHorizontal) - v.y = (v.y + (Math.sin(time * Math.PI * locWaves * 2 + v.x * .01) * locAmplitude * locAmplitudeRate)); + v.y = (v.y + (Math.sin(dt * Math.PI * locWaves * 2 + v.x * .01) * locAmplitude * locAmplitudeRate)); this.setVertex(locPos, v); } } @@ -895,6 +1070,7 @@ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ /** * initializes the action with amplitude, horizontal sin, vertical sin, a grid and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves @@ -903,15 +1079,36 @@ cc.Waves = cc.Grid3DAction.extend(/** @lends cc.Waves# */{ * @param {Boolean} vertical * @return {cc.Waves} */ -cc.Waves.create = function (duration, gridSize, waves, amplitude, horizontal, vertical) { +cc.waves = function (duration, gridSize, waves, amplitude, horizontal, vertical) { return new cc.Waves(duration, gridSize, waves, amplitude, horizontal, vertical); }; +/** + * Please use cc.waves instead + * initializes the action with amplitude, horizontal sin, vertical sin, a grid and duration + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude + * @param {Boolean} horizontal + * @param {Boolean} vertical + * @return {cc.Waves} + * @static + * @deprecated since v3.0
Please use cc.waves instead. + */ +cc.Waves.create = cc.waves; + /** @brief */ /** - * cc.Twirl action + * cc.Twirl action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.Grid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} twirls + * @param {Number} amplitude */ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ /* twirl center */ @@ -921,9 +1118,8 @@ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ _amplitudeRate: 0, /** - * Create a grid 3d action with center position, number of twirls, amplitude, a grid size and duration - * - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a grid 3d action with center position, number of twirls, amplitude, a grid size and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position @@ -998,7 +1194,12 @@ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * + * @param {Number} dt + */ + update:function (dt) { var c = this._position; var locSizeWidth = this._gridSize.width, locSizeHeight = this._gridSize.height, locPos = cc.p(0, 0); var amp = 0.1 * this._amplitude * this._amplitudeRate; @@ -1013,7 +1214,7 @@ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ avg.x = i - (locSizeWidth / 2.0); avg.y = j - (locSizeHeight / 2.0); - a = cc.pLength(avg) * Math.cos(Math.PI / 2.0 + time * Math.PI * locTwirls * 2) * amp; + a = cc.pLength(avg) * Math.cos(Math.PI / 2.0 + dt * Math.PI * locTwirls * 2) * amp; dX = Math.sin(a) * (v.y - c.y) + Math.cos(a) * (v.x - c.x); dY = Math.cos(a) * (v.y - c.y) - Math.sin(a) * (v.x - c.x); @@ -1029,6 +1230,7 @@ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ /** * creates the action with center position, number of twirls, amplitude, a grid size and duration + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {cc.Point} position @@ -1036,6 +1238,20 @@ cc.Twirl = cc.Grid3DAction.extend(/** @lends cc.Twirl# */{ * @param {Number} amplitude * @return {cc.Twirl} */ -cc.Twirl.create = function (duration, gridSize, position, twirls, amplitude) { +cc.twirl = function (duration, gridSize, position, twirls, amplitude) { return new cc.Twirl(duration, gridSize, position, twirls, amplitude); }; + +/** + * Please use cc.twirl instead + * creates the action with center position, number of twirls, amplitude, a grid size and duration + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {cc.Point} position + * @param {Number} twirls + * @param {Number} amplitude + * @return {cc.Twirl} + * @static + * @deprecated since v3.0
Please use cc.twirl instead. + */ +cc.Twirl.create = cc.twirl; \ No newline at end of file diff --git a/cocos2d/actions3d/CCActionPageTurn3D.js b/cocos2d/actions3d/CCActionPageTurn3D.js index dae59a11ee..a28f0d4852 100644 --- a/cocos2d/actions3d/CCActionPageTurn3D.js +++ b/cocos2d/actions3d/CCActionPageTurn3D.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -36,6 +36,18 @@ * @extends cc.Grid3DAction */ cc.PageTurn3D = cc.Grid3DAction.extend(/** @lends cc.PageTurn3D# */{ + getGrid: function(){ + var result = new cc.Grid3D(this._gridSize); + result.setNeedDepthTestForBlit(true); + return result; + }, + + clone: function(){ + var ret = new cc.PageTurn3D(); + ret.initWithDuration(this._duration, this._gridSize); + return ret; + }, + /** * Update each tick
* Time is the percentage of the way through the duration @@ -58,7 +70,7 @@ cc.PageTurn3D = cc.Grid3DAction.extend(/** @lends cc.PageTurn3D# */{ locVer.x = i; locVer.y = j; // Get original vertex - var p = this.originalVertex(locVer); + var p = this.getOriginalVertex(locVer); var R = Math.sqrt((p.x * p.x) + ((p.y - ay) * (p.y - ay))); var r = R * sinTheta; @@ -93,10 +105,21 @@ cc.PageTurn3D = cc.Grid3DAction.extend(/** @lends cc.PageTurn3D# */{ /** * create PageTurn3D action + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.PageTurn3D} */ -cc.PageTurn3D.create = function (duration, gridSize) { +cc.pageTurn3D = function (duration, gridSize) { return new cc.PageTurn3D(duration, gridSize); }; +/** + * Please use cc.pageTurn3D instead + * create PageTurn3D action + * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.PageTurn3D} + * @static + * @deprecated since v3.0 please use cc.pageTurn3D instead. + */ +cc.PageTurn3D.create = cc.pageTurn3D; \ No newline at end of file diff --git a/cocos2d/actions3d/CCActionTiledGrid.js b/cocos2d/actions3d/CCActionTiledGrid.js index b146e8a355..dae3d8daa2 100644 --- a/cocos2d/actions3d/CCActionTiledGrid.js +++ b/cocos2d/actions3d/CCActionTiledGrid.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,17 +25,22 @@ ****************************************************************************/ /** - * cc.ShakyTiles3D action + * cc.ShakyTiles3D action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shakeZ */ cc.ShakyTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShakyTiles3D# */{ _randRange:0, _shakeZ:false, /** - * creates the action with a range, whether or not to shake Z vertices, a grid size, and duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with a range, whether or not to shake Z vertices, a grid size, and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range @@ -47,7 +52,7 @@ cc.ShakyTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShakyTiles3D# */{ }, /** - * initializes the action with a range, whether or not to shake Z vertices, a grid size, and duration + * Initializes the action with a range, whether or not to shake Z vertices, a grid size, and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range @@ -63,7 +68,11 @@ cc.ShakyTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShakyTiles3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval.
+ * @param {Number} dt + */ + update:function (dt) { var locGridSize = this._gridSize, locRandRange = this._randRange; var locPos = cc.p(0, 0); for (var i = 0; i < locGridSize.width; ++i) { @@ -98,21 +107,42 @@ cc.ShakyTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShakyTiles3D# */{ }); /** - * creates the action with a range, whether or not to shake Z vertices, a grid size, and duration + * Creates the action with a range, whether or not to shake Z vertices, a grid size, and duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range * @param {Boolean} shakeZ * @return {cc.ShakyTiles3D} */ -cc.ShakyTiles3D.create = function (duration, gridSize, range, shakeZ) { +cc.shakyTiles3D = function (duration, gridSize, range, shakeZ) { return new cc.ShakyTiles3D(duration, gridSize, range, shakeZ); }; /** - * cc.ShatteredTiles3D action + * Please use cc.shakyTiles3D instead.
+ * creates the action with a range, whether or not to shake Z vertices, a grid size, and duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shakeZ + * @return {cc.ShakyTiles3D} + * @static + * @deprecated since v3.0
Please use cc.shakyTiles3D instead. + */ +cc.ShakyTiles3D.create = cc.shakyTiles3D; + +/** + * cc.ShatteredTiles3D action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shatterZ */ cc.ShatteredTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShatteredTiles3D# */{ _randRange:0, @@ -120,8 +150,8 @@ cc.ShatteredTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShatteredTiles3D _shatterZ:false, /** - * creates the action with a range, whether of not to shatter Z vertices, a grid size and duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with a range, whether of not to shatter Z vertices, a grid size and duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range @@ -133,7 +163,7 @@ cc.ShatteredTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShatteredTiles3D }, /** - * initializes the action with a range, whether or not to shatter Z vertices, a grid size and duration + * Initializes the action with a range, whether or not to shatter Z vertices, a grid size and duration.
* @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range @@ -150,7 +180,11 @@ cc.ShatteredTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShatteredTiles3D return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval.
+ * @param {Number} dt + */ + update:function (dt) { if (this._once === false) { var locGridSize = this._gridSize, locRandRange = this._randRange; var coords, locPos = cc.p(0, 0); @@ -187,19 +221,35 @@ cc.ShatteredTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.ShatteredTiles3D }); /** - * creates the action with a range, whether of not to shatter Z vertices, a grid size and duration + * Creates the action with a range, whether of not to shatter Z vertices, a grid size and duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} range * @param {Boolean} shatterZ * @return {cc.ShatteredTiles3D} */ -cc.ShatteredTiles3D.create = function (duration, gridSize, range, shatterZ) { +cc.shatteredTiles3D = function (duration, gridSize, range, shatterZ) { return new cc.ShatteredTiles3D(duration, gridSize, range, shatterZ); }; /** - * A Tile composed of position, startPosition and delta + * Please use cc.shatteredTiles3D instead.
+ * Creates the action with a range, whether of not to shatter Z vertices, a grid size and duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} range + * @param {Boolean} shatterZ + * @return {cc.ShatteredTiles3D} + * @static + * @deprecated since v3.0
Please use cc.shatteredTiles3D instead. + */ +cc.ShatteredTiles3D.create = cc.shatteredTiles3D; + +/** + * A Tile composed of position, startPosition and delta. * @Class * @constructor * @param {cc.Point} [position=cc.p(0,0)] @@ -213,9 +263,13 @@ cc.Tile = function (position, startPosition, delta) { }; /** - * cc.ShuffleTiles action, Shuffle the tiles in random order + * cc.ShuffleTiles action, Shuffle the tiles in random order.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} seed */ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ _seed:0, @@ -224,8 +278,8 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ _tiles:null, /** - * creates the action with a random seed, the grid size and the duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with a random seed, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} seed @@ -239,7 +293,7 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }, /** - * initializes the action with a random seed, the grid size and the duration + * Initializes the action with a random seed, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} seed @@ -256,7 +310,7 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }, /** - * shuffle + * Shuffle * @param {Array} array * @param {Number} len */ @@ -270,7 +324,7 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }, /** - * get Delta + * Get Delta * @param {cc.Size} pos */ getDelta:function (pos) { @@ -281,7 +335,7 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }, /** - * place Tile + * Place Tile * @param {cc.Point} pos * @param {cc.Tile} tile */ @@ -306,7 +360,7 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }, /** - * start with target + * Start with target * @param {cc.Node} target */ startWithTarget:function (target) { @@ -341,7 +395,11 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ } }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { var tileIndex = 0, locGridSize = this._gridSize, locTiles = this._tiles; var selTile, locPos = cc.p(0, 0); for (var i = 0; i < locGridSize.width; ++i) { @@ -349,8 +407,8 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ locPos.x = i; locPos.y = j; selTile = locTiles[tileIndex]; - selTile.position.x = selTile.delta.width * time; - selTile.position.y = selTile.delta.height * time; + selTile.position.x = selTile.delta.width * dt; + selTile.position.y = selTile.delta.height * dt; this.placeTile(locPos, selTile); ++tileIndex; } @@ -359,36 +417,53 @@ cc.ShuffleTiles = cc.TiledGrid3DAction.extend(/** @lends cc.ShuffleTiles# */{ }); /** - * creates the action with a random seed, the grid size and the duration + * Creates the action with a random seed, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} seed * @return {cc.ShuffleTiles} */ -cc.ShuffleTiles.create = function (duration, gridSize, seed) { +cc.shuffleTiles = function (duration, gridSize, seed) { return new cc.ShuffleTiles(duration, gridSize, seed); }; /** - * cc.FadeOutTRTiles action. Fades out the tiles in a Top-Right direction + * Please use cc.shuffleTiles instead.
+ * Creates the action with a random seed, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} seed + * @return {cc.ShuffleTiles} + * @static + * @deprecated since v3.0
Please use cc.shuffleTiles instead. + */ +cc.ShuffleTiles.create = cc.shuffleTiles; + +/** + * cc.FadeOutTRTiles action. Fades out the tiles in a Top-Right direction.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction */ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */{ /** + * Test function * @param {cc.Size} pos * @param {Number} time */ testFunc:function (pos, time) { var locX = this._gridSize.width * time; var locY = this._gridSize.height * time; - if ((locX + locY) == 0.0) + if ((locX + locY) === 0.0) return 1.0; return Math.pow((pos.width + pos.height) / (locX + locY), 6); }, /** - * turn on Tile + * Turn on Tile * @param {cc.Point} pos */ turnOnTile:function (pos) { @@ -396,7 +471,7 @@ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */ }, /** - * turn Off Tile + * Turn Off Tile * @param {cc.Point} pos */ turnOffTile:function (pos) { @@ -404,7 +479,7 @@ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */ }, /** - * transform tile + * Transform tile * @param {cc.Point} pos * @param {Number} distance */ @@ -427,7 +502,11 @@ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */ this.setTile(pos, coords); }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { var locGridSize = this._gridSize; var locPos = cc.p(0, 0), locSize = cc.size(0, 0), distance; for (var i = 0; i < locGridSize.width; ++i) { @@ -436,8 +515,8 @@ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */ locPos.y = j; locSize.width = i; locSize.height = j; - distance = this.testFunc(locSize, time); - if (distance == 0) + distance = this.testFunc(locSize, dt); + if (distance === 0) this.turnOffTile(locPos); else if (distance < 1) this.transformTile(locPos, distance); @@ -449,29 +528,45 @@ cc.FadeOutTRTiles = cc.TiledGrid3DAction.extend(/** @lends cc.FadeOutTRTiles# */ }); /** - * creates the action with the grid size and the duration + * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param duration * @param gridSize * @return {cc.FadeOutTRTiles} */ -cc.FadeOutTRTiles.create = function (duration, gridSize) { +cc.fadeOutTRTiles = function (duration, gridSize) { return new cc.FadeOutTRTiles(duration, gridSize); }; /** - * cc.FadeOutBLTiles action. Fades out the tiles in a Bottom-Left direction + * Please use cc.fadeOutTRTiles instead.
+ * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param duration + * @param gridSize + * @return {cc.FadeOutTRTiles} + * @static + * @deprecated since v3.0
Please use cc.fadeOutTRTiles instead. + */ +cc.FadeOutTRTiles.create = cc.fadeOutTRTiles; + +/** + * cc.FadeOutBLTiles action. Fades out the tiles in a Bottom-Left direction.
+ * Reference the test cases (Effects Test) * @class * @extends cc.FadeOutTRTiles */ cc.FadeOutBLTiles = cc.FadeOutTRTiles.extend(/** @lends cc.FadeOutBLTiles# */{ /** + * Test function * @param {cc.Size} pos * @param {Number} time */ testFunc:function (pos, time) { var locX = this._gridSize.width * (1.0 - time); var locY = this._gridSize.height * (1.0 - time); - if ((pos.width + pos.height) == 0) + if ((pos.width + pos.height) === 0) return 1.0; return Math.pow((locX + locY) / (pos.width + pos.height), 6); @@ -479,24 +574,39 @@ cc.FadeOutBLTiles = cc.FadeOutTRTiles.extend(/** @lends cc.FadeOutBLTiles# */{ }); /** - * creates the action with the grid size and the duration + * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param duration * @param gridSize * @return {cc.FadeOutBLTiles} */ -cc.FadeOutBLTiles.create = function (duration, gridSize) { +cc.fadeOutBLTiles = function (duration, gridSize) { return new cc.FadeOutBLTiles(duration, gridSize); }; /** - * cc.FadeOutUpTiles action. Fades out the tiles in upwards direction + * Please use cc.fadeOutBLTiles instead.
+ * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param duration + * @param gridSize + * @return {cc.FadeOutBLTiles} + * @static + * @deprecated since v3.0
Please use cc.fadeOutBLTiles instead. + */ +cc.FadeOutBLTiles.create = cc.fadeOutBLTiles; + +/** + * cc.FadeOutUpTiles action. Fades out the tiles in upwards direction.
+ * Reference the test cases (Effects Test) * @class * @extends cc.FadeOutTRTiles */ cc.FadeOutUpTiles = cc.FadeOutTRTiles.extend(/** @lends cc.FadeOutUpTiles# */{ testFunc:function (pos, time) { var locY = this._gridSize.height * time; - if (locY == 0.0) + if (locY === 0.0) return 1.0; return Math.pow(pos.height / locY, 6); }, @@ -515,45 +625,82 @@ cc.FadeOutUpTiles = cc.FadeOutTRTiles.extend(/** @lends cc.FadeOutUpTiles# */{ }); /** - * creates the action with the grid size and the duration + * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.FadeOutUpTiles} */ -cc.FadeOutUpTiles.create = function (duration, gridSize) { +cc.fadeOutUpTiles = function (duration, gridSize) { return new cc.FadeOutUpTiles(duration, gridSize); }; /** - * cc.FadeOutDownTiles action. Fades out the tiles in downwards direction + * Please use cc.fadeOutUpTiles instead.
+ * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.FadeOutUpTiles} + * @static + * @deprecated since v3.0
Please use cc.fadeOutUpTiles instead. + */ +cc.FadeOutUpTiles.create = cc.fadeOutUpTiles; + +/** + * cc.FadeOutDownTiles action. Fades out the tiles in downwards direction.
+ * Reference the test cases (Effects Test) * @class * @extends cc.FadeOutUpTiles */ cc.FadeOutDownTiles = cc.FadeOutUpTiles.extend(/** @lends cc.FadeOutDownTiles# */{ testFunc:function (pos, time) { var locY = this._gridSize.height * (1.0 - time); - if (pos.height == 0) + if (pos.height === 0) return 1.0; return Math.pow(locY / pos.height, 6); } }); /** - * creates the action with the grid size and the duration + * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @return {cc.FadeOutDownTiles} */ -cc.FadeOutDownTiles.create = function (duration, gridSize) { +cc.fadeOutDownTiles = function (duration, gridSize) { return new cc.FadeOutDownTiles(duration, gridSize); }; - +/** + * Please use cc.fadeOutDownTiles instead.
+ * Creates the action with the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @return {cc.FadeOutDownTiles} + * @static + * @deprecated since v3.0
Please use cc.fadeOutDownTiles instead. + */ +cc.FadeOutDownTiles.create = cc.fadeOutDownTiles; /** * cc.TurnOffTiles action.
- * Turn off the files in random order + * Turn off the files in random order.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number|Null} [seed=0] + * @example + * // turnOffTiles without seed + * var toff = new cc.TurnOffTiles(this._duration, cc.size(x, y)); + * + * // turnOffTiles with seed + * var toff = new cc.TurnOffTiles(this._duration, cc.size(x, y), 0); */ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ _seed:null, @@ -561,16 +708,11 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ _tilesOrder:null, /** - * creates the action with a random seed, the grid size and the duration + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with a random seed, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number|Null} [seed=0] - * @example - * // turnOffTiles without seed - * var toff = new cc.TurnOffTiles(this._duration, cc.size(x, y)); - * - * // turnOffTiles with seed - * var toff = new cc.TurnOffTiles(this._duration, cc.size(x, y), 0); */ ctor:function (duration, gridSize, seed) { cc.GridAction.prototype.ctor.call(this); @@ -579,7 +721,8 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ gridSize !== undefined && this.initWithDuration(duration, gridSize, seed); }, - /** initializes the action with a random seed, the grid size and the duration + /** + * Initializes the action with a random seed, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number|Null} [seed=0] @@ -595,6 +738,7 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }, /** + * Shuffle * @param {Array} array * @param {Number} len */ @@ -608,6 +752,7 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }, /** + * Turn on tile. * @param {cc.Point} pos */ turnOnTile:function (pos) { @@ -615,6 +760,7 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }, /** + * Turn off title. * @param {cc.Point} pos */ turnOffTile:function (pos) { @@ -622,6 +768,7 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }, /** + * called before the action start. It will also set the target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -636,10 +783,11 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }, /** - * @param {Number} time + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt */ - update:function (time) { - var l = 0 | (time * this._tilesCount), locGridSize = this._gridSize; + update:function (dt) { + var l = 0 | (dt * this._tilesCount), locGridSize = this._gridSize; var t,tilePos = cc.p(0,0), locTilesOrder = this._tilesOrder; for (var i = 0; i < this._tilesCount; i++) { t = locTilesOrder[i]; @@ -654,7 +802,9 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ }); /** - * creates the action with a random seed, the grid size and the duration + * Creates the action with a random seed, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number|Null} [seed=0] @@ -662,19 +812,36 @@ cc.TurnOffTiles = cc.TiledGrid3DAction.extend(/** @lends cc.TurnOffTiles# */{ * @example * // example * // turnOffTiles without seed - * var toff = cc.TurnOffTiles.create(this._duration, cc.size(x, y)); + * var toff = cc.turnOffTiles(this._duration, cc.size(x, y)); * * // turnOffTiles with seed - * var toff = cc.TurnOffTiles.create(this._duration, cc.size(x, y), 0); + * var toff = cc.turnOffTiles(this._duration, cc.size(x, y), 0); */ -cc.TurnOffTiles.create = function (duration, gridSize, seed) { +cc.turnOffTiles = function (duration, gridSize, seed) { return new cc.TurnOffTiles(duration, gridSize, seed); }; +/** + * Please use cc.turnOffTiles instead.
+ * Creates the action with a random seed, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number|Null} [seed=0] + * @return {cc.TurnOffTiles} + * @static + * @deprecated since v3.0
Please use cc.turnOffTiles instead. + */ +cc.TurnOffTiles.create = cc.turnOffTiles; /** - * cc.WavesTiles3D action. + * cc.WavesTiles3D action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude */ cc.WavesTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.WavesTiles3D# */{ _waves:0, @@ -682,8 +849,8 @@ cc.WavesTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.WavesTiles3D# */{ _amplitudeRate:0, /** - * creates the action with a number of waves, the waves amplitude, the grid size and the duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates the action with a number of waves, the waves amplitude, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves @@ -744,7 +911,11 @@ cc.WavesTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.WavesTiles3D# */{ return false; }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { var locGridSize = this._gridSize, locWaves = this._waves, locAmplitude = this._amplitude, locAmplitudeRate = this._amplitudeRate; var locPos = cc.p(0, 0), coords; for (var i = 0; i < locGridSize.width; i++) { @@ -752,7 +923,7 @@ cc.WavesTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.WavesTiles3D# */{ locPos.x = i; locPos.y = j; coords = this.originalTile(locPos); - coords.bl.z = (Math.sin(time * Math.PI * locWaves * 2 + + coords.bl.z = (Math.sin(dt * Math.PI * locWaves * 2 + (coords.bl.y + coords.bl.x) * 0.01) * locAmplitude * locAmplitudeRate); coords.br.z = coords.bl.z; coords.tl.z = coords.bl.z; @@ -764,21 +935,41 @@ cc.WavesTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.WavesTiles3D# */{ }); /** - * creates the action with a number of waves, the waves amplitude, the grid size and the duration + * creates the action with a number of waves, the waves amplitude, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} waves * @param {Number} amplitude * @return {cc.WavesTiles3D} */ -cc.WavesTiles3D.create = function (duration, gridSize, waves, amplitude) { +cc.wavesTiles3D = function (duration, gridSize, waves, amplitude) { return new cc.WavesTiles3D(duration, gridSize, waves, amplitude); }; +/** + * Please use cc.wavesTiles3D instead + * creates the action with a number of waves, the waves amplitude, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} waves + * @param {Number} amplitude + * @return {cc.WavesTiles3D} + * @static + * @deprecated since v3.0
Please use cc.wavesTiles3D instead. + */ +cc.WavesTiles3D.create = cc.wavesTiles3D; /** - * cc.JumpTiles3D action. A sin function is executed to move the tiles across the Z axis + * cc.JumpTiles3D action. A sin function is executed to move the tiles across the Z axis.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} numberOfJumps + * @param {Number} amplitude */ cc.JumpTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.JumpTiles3D# */{ _jumps:0, @@ -786,8 +977,8 @@ cc.JumpTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.JumpTiles3D# */{ _amplitudeRate:0, /** - * creates the action with the number of jumps, the sin amplitude, the grid size and the duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates the action with the number of jumps, the sin amplitude, the grid size and the duration. * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} numberOfJumps @@ -847,9 +1038,13 @@ cc.JumpTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.JumpTiles3D# */{ return false; }, - update:function (time) { - var sinz = (Math.sin(Math.PI * time * this._jumps * 2) * this._amplitude * this._amplitudeRate ); - var sinz2 = (Math.sin(Math.PI * (time * this._jumps * 2 + 1)) * this._amplitude * this._amplitudeRate ); + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { + var sinz = (Math.sin(Math.PI * dt * this._jumps * 2) * this._amplitude * this._amplitudeRate ); + var sinz2 = (Math.sin(Math.PI * (dt * this._jumps * 2 + 1)) * this._amplitude * this._amplitudeRate ); var locGridSize = this._gridSize; var locGrid = this.target.grid; @@ -862,7 +1057,7 @@ cc.JumpTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.JumpTiles3D# */{ //var coords = this.originalTile(cc.p(i, j)); coords = locGrid.originalTile(locPos); - if (((i + j) % 2) == 0) { + if (((i + j) % 2) === 0) { coords.bl.z += sinz; coords.br.z += sinz; coords.tl.z += sinz; @@ -882,29 +1077,48 @@ cc.JumpTiles3D = cc.TiledGrid3DAction.extend(/** @lends cc.JumpTiles3D# */{ }); /** - * creates the action with the number of jumps, the sin amplitude, the grid size and the duration + * creates the action with the number of jumps, the sin amplitude, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {cc.Size} gridSize * @param {Number} numberOfJumps * @param {Number} amplitude * @return {cc.JumpTiles3D} */ -cc.JumpTiles3D.create = function (duration, gridSize, numberOfJumps, amplitude) { +cc.jumpTiles3D = function (duration, gridSize, numberOfJumps, amplitude) { return new cc.JumpTiles3D(duration, gridSize, numberOfJumps, amplitude); }; /** - * cc.SplitRows action + * Please use cc.jumpTiles3D instead + * creates the action with the number of jumps, the sin amplitude, the grid size and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {cc.Size} gridSize + * @param {Number} numberOfJumps + * @param {Number} amplitude + * @return {cc.JumpTiles3D} + * @static + * @deprecated since v3.0
Please use cc.jumpTiles3D instead. + */ +cc.JumpTiles3D.create = cc.jumpTiles3D; + +/** + * cc.SplitRows action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {Number} rows */ cc.SplitRows = cc.TiledGrid3DAction.extend(/** @lends cc.SplitRows# */{ _rows:0, _winSize:null, /** - * creates the action with the number of rows to split and the duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * creates the action with the number of rows to split and the duration. * @param {Number} duration * @param {Number} rows */ @@ -924,7 +1138,11 @@ cc.SplitRows = cc.TiledGrid3DAction.extend(/** @lends cc.SplitRows# */{ return cc.TiledGrid3DAction.prototype.initWithDuration.call(this, duration, cc.size(1, rows)); }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { var locGridSize = this._gridSize, locWinSizeWidth = this._winSize.width; var coords, direction, locPos = cc.p(0, 0); for (var j = 0; j < locGridSize.height; ++j) { @@ -932,18 +1150,22 @@ cc.SplitRows = cc.TiledGrid3DAction.extend(/** @lends cc.SplitRows# */{ coords = this.originalTile(locPos); direction = 1; - if ((j % 2 ) == 0) + if ((j % 2 ) === 0) direction = -1; - coords.bl.x += direction * locWinSizeWidth * time; - coords.br.x += direction * locWinSizeWidth * time; - coords.tl.x += direction * locWinSizeWidth * time; - coords.tr.x += direction * locWinSizeWidth * time; + coords.bl.x += direction * locWinSizeWidth * dt; + coords.br.x += direction * locWinSizeWidth * dt; + coords.tl.x += direction * locWinSizeWidth * dt; + coords.tr.x += direction * locWinSizeWidth * dt; this.setTile(locPos, coords); } }, + /** + * called before the action start. It will also set the target. + * @param {cc.Node} target + */ startWithTarget:function (target) { cc.TiledGrid3DAction.prototype.startWithTarget.call(this, target); this._winSize = cc.director.getWinSizeInPixels(); @@ -951,27 +1173,44 @@ cc.SplitRows = cc.TiledGrid3DAction.extend(/** @lends cc.SplitRows# */{ }); /** - * creates the action with the number of rows to split and the duration + * creates the action with the number of rows to split and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {Number} rows * @return {cc.SplitRows} */ -cc.SplitRows.create = function (duration, rows) { +cc.splitRows = function (duration, rows) { return new cc.SplitRows(duration, rows); }; /** - * cc.SplitCols action + * Please use cc.splitRows instead + * creates the action with the number of rows to split and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {Number} rows + * @return {cc.SplitRows} + * @static + * @deprecated since v3.0
Please use cc.splitRows instead. + */ +cc.SplitRows.create = cc.splitRows; + +/** + * cc.SplitCols action.
+ * Reference the test cases (Effects Test) * @class * @extends cc.TiledGrid3DAction + * @param {Number} duration + * @param {Number} cols */ cc.SplitCols = cc.TiledGrid3DAction.extend(/** @lends cc.SplitCols# */{ _cols:0, _winSize:null, /** - * Creates the action with the number of columns to split and the duration - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Creates the action with the number of columns to split and the duration. * @param {Number} duration * @param {Number} cols */ @@ -990,7 +1229,11 @@ cc.SplitCols = cc.TiledGrid3DAction.extend(/** @lends cc.SplitCols# */{ return cc.TiledGrid3DAction.prototype.initWithDuration.call(this, duration, cc.size(cols, 1)); }, - update:function (time) { + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @param {Number} dt + */ + update:function (dt) { var locGridSizeWidth = this._gridSize.width, locWinSizeHeight = this._winSize.height; var coords, direction, locPos = cc.p(0, 0); for (var i = 0; i < locGridSizeWidth; ++i) { @@ -998,19 +1241,21 @@ cc.SplitCols = cc.TiledGrid3DAction.extend(/** @lends cc.SplitCols# */{ coords = this.originalTile(locPos); direction = 1; - if ((i % 2 ) == 0) + if ((i % 2 ) === 0) direction = -1; - coords.bl.y += direction * locWinSizeHeight * time; - coords.br.y += direction * locWinSizeHeight * time; - coords.tl.y += direction * locWinSizeHeight * time; - coords.tr.y += direction * locWinSizeHeight * time; + coords.bl.y += direction * locWinSizeHeight * dt; + coords.br.y += direction * locWinSizeHeight * dt; + coords.tl.y += direction * locWinSizeHeight * dt; + coords.tr.y += direction * locWinSizeHeight * dt; this.setTile(locPos, coords); } + cc.renderer.childrenOrderDirty = true; }, /** + * called before the action start. It will also set the target. * @param {cc.Node} target */ startWithTarget:function (target) { @@ -1020,11 +1265,25 @@ cc.SplitCols = cc.TiledGrid3DAction.extend(/** @lends cc.SplitCols# */{ }); /** - * creates the action with the number of columns to split and the duration + * creates the action with the number of columns to split and the duration.
+ * Reference the test cases (Effects Test) + * @function * @param {Number} duration * @param {Number} cols * @return {cc.SplitCols} */ -cc.SplitCols.create = function (duration, cols) { +cc.splitCols = function (duration, cols) { return new cc.SplitCols(duration, cols); -}; \ No newline at end of file +}; + +/** + * Please use cc.splitCols instead. + * creates the action with the number of columns to split and the duration.
+ * Reference the test cases (Effects Test) + * @param {Number} duration + * @param {Number} cols + * @return {cc.SplitCols} + * @static + * @deprecated since v3.0
Please use cc.splitCols instead. + */ +cc.SplitCols.create = cc.splitCols; \ No newline at end of file diff --git a/cocos2d/audio/CCAudio.js b/cocos2d/audio/CCAudio.js index 2c11b66c59..e3890afd59 100644 --- a/cocos2d/audio/CCAudio.js +++ b/cocos2d/audio/CCAudio.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,1012 +24,1027 @@ THE SOFTWARE. ****************************************************************************/ -if (cc.sys._supportWebAudio) { - var _ctx = cc.webAudioContext = new (window.AudioContext || window.webkitAudioContext || window.mozAudioContext)(); - /** - * A class of Web Audio. - * @class - * @extends cc.Class - */ - cc.WebAudio = cc.Class.extend({ - _events: null, - _buffer: null, - _sourceNode: null, - _volumeNode: null, - - src: null, - preload: null,//"none" or "metadata" or "auto" or "" (empty string) or empty TODO not used here - autoplay: null, //"autoplay" or "" (empty string) or empty - controls: null, //"controls" or "" (empty string) or empty TODO not used here - mediagroup: null, - - //The following IDL attributes and methods are exposed to dynamic scripts. - currentTime: 0, - startTime: 0, - duration: 0, // TODO not used here - - _loop: null, //"loop" or "" (empty string) or empty - _volume: 1, - - _pauseTime: 0, - _paused: false, - _stopped: true, - - _loadState: -1,//-1 : not loaded, 0 : waiting, 1 : loaded, -2 : load failed - - ctor: function (src) { - var self = this; - self._events = {}; - self.src = src; - - if (_ctx["createGain"]) - self._volumeNode = _ctx["createGain"](); - else - self._volumeNode = _ctx["createGainNode"](); - - self._onSuccess1 = self._onSuccess.bind(this); - self._onError1 = self._onError.bind(this); - }, +/** + * Audio support in the browser + * + * multichannel : Multiple audio while playing - If it doesn't, you can only play background music + * webAudio : Support for WebAudio - Support W3C WebAudio standards, all of the audio can be played + * auto : Supports auto-play audio - if Don‘t support it, On a touch detecting background music canvas, and then replay + * replay : The first music will fail, must be replay after touchstart + * emptied : Whether to use the emptied event to replace load callback + * delay : delay created the context object - only webAudio + * + * May be modifications for a few browser version + */ +(function(){ + + var DEBUG = false; + + var sys = cc.sys; + + var supportTable = { + "common" : {multichannel: true , webAudio: cc.sys._supportWebAudio , auto: true } + }; + supportTable[sys.BROWSER_TYPE_IE] = {multichannel: true , webAudio: cc.sys._supportWebAudio , auto: true, emptied: true}; + // ANDROID // + supportTable[sys.BROWSER_TYPE_ANDROID] = {multichannel: false, webAudio: false, auto: false}; + supportTable[sys.BROWSER_TYPE_CHROME] = {multichannel: true , webAudio: true , auto: false}; + supportTable[sys.BROWSER_TYPE_FIREFOX] = {multichannel: true , webAudio: true , auto: true , delay: true}; + supportTable[sys.BROWSER_TYPE_UC] = {multichannel: true , webAudio: false, auto: false}; + supportTable[sys.BROWSER_TYPE_QQ] = {multichannel: false, webAudio: false, auto: true }; + supportTable[sys.BROWSER_TYPE_OUPENG] = {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + supportTable[sys.BROWSER_TYPE_WECHAT] = {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + supportTable[sys.BROWSER_TYPE_360] = {multichannel: false, webAudio: false, auto: true }; + supportTable[sys.BROWSER_TYPE_MIUI] = {multichannel: false, webAudio: false, auto: true }; + supportTable[sys.BROWSER_TYPE_LIEBAO] = {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + supportTable[sys.BROWSER_TYPE_SOUGOU] = {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + //"Baidu" browser can automatically play + //But because it may be play failed, so need to replay and auto + supportTable[sys.BROWSER_TYPE_BAIDU] = {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + supportTable[sys.BROWSER_TYPE_BAIDU_APP]= {multichannel: false, webAudio: false, auto: false, replay: true , emptied: true }; + + // APPLE // + supportTable[sys.BROWSER_TYPE_SAFARI] = {multichannel: true , webAudio: true , auto: false, webAudioCallback: function(realUrl){ + document.createElement("audio").src = realUrl; + }}; + + /* Determine the browser version number */ + var version, tmp; + try{ + var ua = navigator.userAgent.toLowerCase(); + switch(sys.browserType){ + case sys.BROWSER_TYPE_IE: + tmp = ua.match(/(msie |rv:)([\d.]+)/); + break; + case sys.BROWSER_TYPE_FIREFOX: + tmp = ua.match(/(firefox\/|rv:)([\d.]+)/); + break; + case sys.BROWSER_TYPE_CHROME: + tmp = ua.match(/chrome\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_BAIDU: + tmp = ua.match(/baidubrowser\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_UC: + tmp = ua.match(/ucbrowser\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_QQ: + tmp = ua.match(/qqbrowser\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_OUPENG: + tmp = ua.match(/oupeng\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_WECHAT: + tmp = ua.match(/micromessenger\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_SAFARI: + tmp = ua.match(/safari\/([\d.]+)/); + break; + case sys.BROWSER_TYPE_MIUI: + tmp = ua.match(/miuibrowser\/([\d.]+)/); + break; + } + version = tmp ? tmp[1] : ""; + }catch(e){ + console.log(e); + } - _play: function (offset) { - var self = this; - var sourceNode = self._sourceNode = _ctx["createBufferSource"](); - var volumeNode = self._volumeNode; - - sourceNode.buffer = self._buffer; - volumeNode["gain"].value = self._volume; - sourceNode["connect"](volumeNode); - volumeNode["connect"](_ctx["destination"]); - sourceNode.loop = self._loop; - - self._paused = false; - self._stopped = false; - - /* - * Safari on iOS 6 only supports noteOn(), noteGrainOn(), and noteOff() now.(iOS 6.1.3) - * The latest version of chrome has supported start() and stop() - * start() & stop() are specified in the latest specification (written on 04/26/2013) - * Reference: https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html - * noteOn(), noteGrainOn(), and noteOff() are specified in Draft 13 version (03/13/2012) - * Reference: http://www.w3.org/2011/audio/drafts/2WD/Overview.html - */ - if (sourceNode.start) { - // starting from offset means resuming from where it paused last time - sourceNode.start(0, offset); - } else if (sourceNode["noteGrainOn"]) { - var duration = sourceNode.buffer.duration; - if (self.loop) { - /* - * On Safari on iOS 6, if loop == true, the passed in @param duration will be the duration from now on. - * In other words, the sound will keep playing the rest of the music all the time. - * On latest chrome desktop version, the passed in duration will only be the duration in this cycle. - * Now that latest chrome would have start() method, it is prepared for iOS here. - */ - sourceNode["noteGrainOn"](0, offset, duration); - } else { - sourceNode["noteGrainOn"](0, offset, duration - offset); + /////////////////////////// + // Browser compatibility// + /////////////////////////// + if(version){ + switch(sys.browserType){ + case sys.BROWSER_TYPE_CHROME: + if(parseInt(version) < 30){ + supportTable[sys.BROWSER_TYPE_CHROME] = {multichannel: false , webAudio: true , auto: false}; } - } else { - // if only noteOn() is supported, resuming sound will NOT work - sourceNode["noteOn"](0); - } - self._pauseTime = 0; - }, - _stop: function () { - var self = this, sourceNode = self._sourceNode; - if (self._stopped) return; - if (sourceNode.stop) sourceNode.stop(0); - else sourceNode.noteOff(0); - self._stopped = true; - }, - play: function () { - var self = this; - if (self._loadState == -1) { - self._loadState = 0; - return; - } else if (self._loadState != 1) return; - - var sourceNode = self._sourceNode; - if (!self._stopped && sourceNode && sourceNode["playbackState"] == 2) return;//playing - self.startTime = _ctx.currentTime; - this._play(0); - }, - pause: function () { - this._pauseTime = _ctx.currentTime; - this._paused = true; - this._stop(); - }, - resume: function () { - var self = this; - if (self._paused) { - var offset = self._buffer ? (self._pauseTime - self.startTime) % self._buffer.duration : 0; - this._play(offset); - } - }, - stop: function () { - this._pauseTime = 0; - this._paused = false; - this._stop(); - }, - load: function () { - var self = this; - if (self._loadState == 1) return; - self._loadState = -1;//not loaded - - self.played = false; - self.ended = true; - var request = new XMLHttpRequest(); - request.open("GET", self.src, true); - request.responseType = "arraybuffer"; - - // Our asynchronous callback - request.onload = function () { - _ctx["decodeAudioData"](request.response, self._onSuccess1, self._onError1); - }; - request.send(); - }, - - addEventListener: function (eventName, event) { - this._events[eventName] = event.bind(this); - }, - removeEventListener: function (eventName) { - delete this._events[eventName]; - }, - - canplay: function () { - return cc.sys._supportWebAudio; - }, - _onSuccess: function (buffer) { - var self = this; - self._buffer = buffer; - - var success = self._events["success"], canplaythrough = self._events["canplaythrough"]; - if (success) success(); - if (canplaythrough) canplaythrough(); - if (self._loadState == 0 || self.autoplay == "autoplay" || self.autoplay == true) self._play(); - self._loadState = 1;//loaded - }, - _onError: function () { - var error = this._events["error"] - if (error) error(); - this._loadState = -2;//load failed - }, - cloneNode: function () { - var self = this, obj = new cc.WebAudio(self.src); - obj.volume = self.volume; - obj._loadState = self._loadState; - obj._buffer = self._buffer; - if (obj._loadState == 0 || obj._loadState == -1) obj.load(); - return obj; + break; + case sys.BROWSER_TYPE_MIUI: + version = version.match(/\d+/g); + if(version[0] < 2 || (version[0] === 2 && version[1] === 0 && version[2] <= 1)){ + supportTable[sys.BROWSER_TYPE_MIUI].auto = false; + } + break; } + } - }); - var _p = cc.WebAudio.prototype; - /** @expose */ - _p.loop; - cc.defineGetterSetter(_p, "loop", function () { - return this._loop; - }, function (loop) { - this._loop = loop; - if (this._sourceNode) this._sourceNode.loop = loop; - }); - /** @expose */ - _p.volume; - cc.defineGetterSetter(_p, "volume", function () { - return this._volume; - }, function (volume) { - this._volume = volume; - this._volumeNode["gain"].value = volume; - }); - /** @expose */ - _p.ended; - cc.defineGetterSetter(_p, "paused", function () { - return this._paused; - }); - /** @expose */ - _p.ended; - cc.defineGetterSetter(_p, "ended", function () { - var sourceNode = this._sourceNode; - return !this._paused && (this._stopped || !sourceNode || sourceNode["playbackState"] == 3); - }); - /** @expose */ - _p.played; - cc.defineGetterSetter(_p, "played", function () { - var sourceNode = this._sourceNode; - return sourceNode && sourceNode["playbackState"] == 2; - }); + if(cc.sys.isMobile){ + if(cc.sys.os !== cc.sys.OS_IOS) + cc.__audioSupport = supportTable[sys.browserType] || supportTable["common"]; + else + cc.__audioSupport = supportTable[sys.BROWSER_TYPE_SAFARI]; + }else{ + switch(sys.browserType){ + case sys.BROWSER_TYPE_IE: + cc.__audioSupport = supportTable[sys.BROWSER_TYPE_IE]; + break; + case sys.BROWSER_TYPE_FIREFOX: + cc.__audioSupport = supportTable[sys.BROWSER_TYPE_FIREFOX]; + break; + default: + cc.__audioSupport = supportTable["common"]; + } + } + + if(DEBUG){ + setTimeout(function(){ + cc.log("browse type: " + sys.browserType); + cc.log("browse version: " + version); + cc.log("multichannel: " + cc.__audioSupport.multichannel); + cc.log("webAudio: " + cc.__audioSupport.webAudio); + cc.log("auto: " + cc.__audioSupport.auto); + }, 0); + } -} +})(); /** - * @namespace A simple Audio Engine engine API. - * @name cc.audioEngine + * Encapsulate DOM and webAudio */ -cc.AudioEngine = cc.Class.extend(/** @lends cc.audioEngine# */{ - _soundSupported: false, // if sound is not enabled, this engine's init() will return false - - _currMusic: null, - _currMusicPath: null, - _musicPlayState: 0, //0 : stopped, 1 : paused, 2 : playing +cc.Audio = cc.Class.extend({ + //TODO Maybe loader shift in will be better + volume: 1, + loop: false, + src: null, + _touch: false, + + _playing: false, + _AUDIO_TYPE: "AUDIO", + _pause: false, + + //Web Audio + _buffer: null, + _currentSource: null, + _startTime: null, + _currentTime: null, + _context: null, + _volume: null, + + _ignoreEnded: false, + + //DOM Audio + _element: null, + + ctor: function(context, volume, url){ + context && (this._context = context); + volume && (this._volume = volume); + if(context && volume){ + this._AUDIO_TYPE = "WEBAUDIO"; + } + this.src = url; + }, - _audioID: 0, - _effects: {}, //effects cache - _audioPool: {}, //audio pool for effects - _effectsVolume: 1, // the volume applied to all effects - _maxAudioInstance: 5,//max count of audios that has same url + _setBufferCallback: null, + setBuffer: function(buffer){ + if(!buffer) return; + var playing = this._playing; + this._AUDIO_TYPE = "WEBAUDIO"; - _effectPauseCb: null, + if(this._buffer && this._buffer !== buffer && this.getPlaying()) + this.stop(); - _playings: [],//only store when window is hidden + this._buffer = buffer; + if(playing) + this.play(); - ctor: function () { - var self = this; - self._soundSupported = cc._audioLoader._supportedAudioTypes.length > 0; - if (self._effectPauseCb) self._effectPauseCb = self._effectPauseCb.bind(self); + this._volume["gain"].value = this.volume; + this._setBufferCallback && this._setBufferCallback(buffer); }, - /** - * Indicates whether any background music can be played or not. - * @returns {boolean} true if the background music is playing, otherwise false - */ - willPlayMusic: function () { - return false; - }, + _setElementCallback: null, + setElement: function(element){ + if(!element) return; + var playing = this._playing; + this._AUDIO_TYPE = "AUDIO"; - /** - * The volume of the effects max value is 1.0,the min value is 0.0 . - * @return {Number} - * @example - * //example - * var effectVolume = cc.audioEngine.getEffectsVolume(); - */ - getEffectsVolume: function () { - return this._effectsVolume; + if(this._element && this._element !== element && this.getPlaying()) + this.stop(); + + this._element = element; + if(playing) + this.play(); + + element.volume = this.volume; + element.loop = this.loop; + this._setElementCallback && this._setElementCallback(element); }, - //music begin - /** - * Play music. - * @param {String} url The path of the music file without filename extension. - * @param {Boolean} loop Whether the music loop or not. - * @example - * //example - * cc.audioEngine.playMusic(path, false); - */ - playMusic: function (url, loop) { - var self = this; - if (!self._soundSupported) return; - - var audio = self._currMusic; - if (audio) this._stopAudio(audio); - if (url != self._currMusicPath) { - audio = self._getAudioByUrl(url); - self._currMusic = audio; - self._currMusicPath = url; + play: function(offset, loop){ + this._playing = true; + this.loop = loop === undefined ? this.loop : loop; + if(this._AUDIO_TYPE === "AUDIO"){ + this._playOfAudio(offset); + }else{ + this._playOfWebAudio(offset); } - if (!audio) return; - audio.loop = loop || false; - self._playMusic(audio); }, - _getAudioByUrl: function (url) { - var locLoader = cc.loader, audio = locLoader.getRes(url); - if (!audio) { - locLoader.load(url); - audio = locLoader.getRes(url); - } - return audio; - }, - _playMusic: function (audio) { - if (!audio.ended) { - if (audio.stop) {//cc.WebAudio - audio.stop(); - } else { - audio.pause(); - audio.duration && (audio.currentTime = audio.duration); - } + + getPlaying: function(){ + if(!this._playing){ + return this._playing; } - this._musicPlayState = 2; - audio.play(); - }, - /** - * Stop playing music. - * @param {Boolean} releaseData If release the music data or not.As default value is false. - * @example - * //example - * cc.audioEngine.stopMusic(); - */ - stopMusic: function (releaseData) { - if (this._musicPlayState > 0) { - var audio = this._currMusic; - if (!audio) return; - this._stopAudio(audio); - if (releaseData) cc.loader.release(this._currMusicPath); - this._currMusic = null; - this._currMusicPath = null; - this._musicPlayState = 0; + if(this._AUDIO_TYPE === "AUDIO"){ + var audio = this._element; + if(!audio || this._pause){ + this._playing = false; + return false; + }else if(audio.ended){ + this._playing = false; + return false; + }else + return true; + }else{ + var sourceNode = this._currentSource; + if(!sourceNode) + return true; + if(sourceNode["playbackState"] == null) + return this._playing; + else + return this._currentTime + this._context.currentTime - this._startTime < this._currentSource.buffer.duration; } }, - _stopAudio: function (audio) { - if (audio && !audio.ended) { - if (audio.stop) {//cc.WebAudio - audio.stop(); + _playOfWebAudio: function(offset){ + var cs = this._currentSource; + if(!this._buffer){ + return; + } + if(!this._pause && cs){ + if(this._context.currentTime === 0 || this._currentTime + this._context.currentTime - this._startTime > this._currentSource.buffer.duration) + this._stopOfWebAudio(); + else + return; + } + var audio = this._context["createBufferSource"](); + audio.buffer = this._buffer; + audio["connect"](this._volume); + audio.loop = this.loop; + this._startTime = this._context.currentTime; + this._currentTime = offset || 0; + + /* + * Safari on iOS 6 only supports noteOn(), noteGrainOn(), and noteOff() now.(iOS 6.1.3) + * The latest version of chrome has supported start() and stop() + * start() & stop() are specified in the latest specification (written on 04/26/2013) + * Reference: https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html + * noteOn(), noteGrainOn(), and noteOff() are specified in Draft 13 version (03/13/2012) + * Reference: http://www.w3.org/2011/audio/drafts/2WD/Overview.html + */ + if(audio.start){ + audio.start(0, offset || 0); + }else if(audio["noteGrainOn"]){ + var duration = audio.buffer.duration; + if (this.loop) { + /* + * On Safari on iOS 6, if loop == true, the passed in @param duration will be the duration from now on. + * In other words, the sound will keep playing the rest of the music all the time. + * On latest chrome desktop version, the passed in duration will only be the duration in this cycle. + * Now that latest chrome would have start() method, it is prepared for iOS here. + */ + audio["noteGrainOn"](0, offset, duration); } else { - audio.pause(); - audio.duration && (audio.currentTime = audio.duration); + audio["noteGrainOn"](0, offset, duration - offset); } + }else { + // if only noteOn() is supported, resuming sound will NOT work + audio["noteOn"](0); } + this._currentSource = audio; + var self = this; + audio["onended"] = function(){ + if(self._ignoreEnded){ + self._ignoreEnded = false; + }else{ + self._playing = false; + } + }; }, - /** - * Pause playing music. - * @example - * //example - * cc.audioEngine.pauseMusic(); - */ - pauseMusic: function () { - if (this._musicPlayState == 2) { - this._currMusic.pause(); - this._musicPlayState = 1; + _playOfAudio: function(){ + var audio = this._element; + if(audio){ + audio.loop = this.loop; + audio.play(); } }, - /** - * Resume playing music. - * @example - * //example - * cc.audioEngine.resumeMusic(); - */ - resumeMusic: function () { - if (this._musicPlayState == 1) { - var audio = this._currMusic; - this._resumeAudio(audio); - this._musicPlayState = 2; - } - }, - _resumeAudio: function (audio) { - if (audio && !audio.ended) { - if (audio.resume) audio.resume();//cc.WebAudio - else audio.play(); + stop: function(){ + this._playing = false; + if(this._AUDIO_TYPE === "AUDIO"){ + this._stopOfAudio(); + }else{ + this._stopOfWebAudio(); } }, - /** - * Rewind playing music. - * @example - * //example - * cc.audioEngine.rewindMusic(); - */ - rewindMusic: function () { - if (this._currMusic) this._playMusic(this._currMusic); - }, - - /** - * The volume of the music max value is 1.0,the min value is 0.0 . - * @return {Number} - * @example - * //example - * var volume = cc.audioEngine.getMusicVolume(); - */ - getMusicVolume: function () { - return this._musicPlayState == 0 ? 0 : this._currMusic.volume; - }, - - /** - * Set the volume of music. - * @param {Number} volume Volume must be in 0.0~1.0 . - * @example - * //example - * cc.audioEngine.setMusicVolume(0.5); - */ - setMusicVolume: function (volume) { - if (this._musicPlayState > 0) { - this._currMusic.volume = Math.min(Math.max(volume, 0), 1); + _stopOfWebAudio: function(){ + var audio = this._currentSource; + this._ignoreEnded = true; + if(audio){ + audio.stop(0); + this._currentSource = null; } }, - /** - * Whether the music is playing. - * @return {Boolean} If is playing return true,or return false. - * @example - * //example - * if (cc.audioEngine.isMusicPlaying()) { - * cc.log("music is playing"); - * } - * else { - * cc.log("music is not playing"); - * } - */ - isMusicPlaying: function () { - return this._musicPlayState == 2 && this._currMusic && !this._currMusic.ended; - }, - //music end - //effect begin - _getEffectList: function (url) { - var list = this._audioPool[url]; - if (!list) list = this._audioPool[url] = []; - return list; - }, - _getEffect: function (url) { - var self = this, audio; - if (!self._soundSupported) return null; - - var effList = this._getEffectList(url); - for (var i = 0, li = effList.length; i < li; i++) { - var eff = effList[i]; - if (eff.ended) { - audio = eff; + _stopOfAudio: function(){ + var audio = this._element; + if(audio){ + audio.pause(); + if (audio.duration && audio.duration !== Infinity) audio.currentTime = 0; - if (window.chrome) audio.load(); - break; - } - } - if (!audio) { - if (effList.length >= this._maxAudioInstance) { - cc.log("Error: " + url + " greater than " + this._maxAudioInstance); - return null; - } - audio = self._getAudioByUrl(url); - if (!audio) return null; - audio = audio.cloneNode(true); - if (self._effectPauseCb) cc._addEventListener(audio, "pause", self._effectPauseCb); - audio.volume = this._effectsVolume; - effList.push(audio); } - return audio; - }, - /** - * Play sound effect. - * @param {String} url The path of the sound effect with filename extension. - * @param {Boolean} loop Whether to loop the effect playing, default value is false - * @return {Number|null} the audio id - * @example - * //example - * var soundId = cc.audioEngine.playEffect(path); - */ - playEffect: function (url, loop) { - var audio = this._getEffect(url); - if (!audio) return null; - audio.loop = loop || false; - audio.play(); - var audioId = this._audioID++; - this._effects[audioId] = audio; - return audioId; }, - /** - * Set the volume of sound effects. - * @param {Number} volume Volume must be in 0.0~1.0 . - * @example - * //example - * cc.audioEngine.setEffectsVolume(0.5); - */ - setEffectsVolume: function (volume) { - volume = this._effectsVolume = Math.min(Math.max(volume, 0), 1); - var effects = this._effects; - for (var key in effects) { - effects[key].volume = volume; + pause: function(){ + if(this.getPlaying() === false) + return; + this._playing = false; + this._pause = true; + if(this._AUDIO_TYPE === "AUDIO"){ + this._pauseOfAudio(); + }else{ + this._pauseOfWebAudio(); } }, - /** - * Pause playing sound effect. - * @param {Number} audioID The return value of function playEffect. - * @example - * //example - * cc.audioEngine.pauseEffect(audioID); - */ - pauseEffect: function (audioID) { - var audio = this._effects[audioID]; - if (audio && !audio.ended) { - audio.pause(); + _pauseOfWebAudio: function(){ + this._currentTime += this._context.currentTime - this._startTime; + var audio = this._currentSource; + if(audio){ + audio.stop(0); } }, - /** - * Pause all playing sound effect. - * @example - * //example - * cc.audioEngine.pauseAllEffects(); - */ - pauseAllEffects: function () { - var effects = this._effects; - for (var key in effects) { - var eff = effects[key]; - if (!eff.ended) eff.pause(); + _pauseOfAudio: function(){ + var audio = this._element; + if(audio){ + audio.pause(); } }, - /** - * Resume playing sound effect. - * @param {Number} effectId The return value of function playEffect. - * @audioID - * //example - * cc.audioEngine.resumeEffect(audioID); - */ - resumeEffect: function (effectId) { - this._resumeAudio(this._effects[effectId]) - }, - - /** - * Resume all playing sound effect - * @example - * //example - * cc.audioEngine.resumeAllEffects(); - */ - resumeAllEffects: function () { - var effects = this._effects; - for (var key in effects) { - this._resumeAudio(effects[key]); + resume: function(){ + if(this._pause){ + if(this._AUDIO_TYPE === "AUDIO"){ + this._resumeOfAudio(); + }else{ + this._resumeOfWebAudio(); + } + this._pause = false; + this._playing = true; } }, - /** - * Stop playing sound effect. - * @param {Number} effectId The return value of function playEffect. - * @example - * //example - * cc.audioEngine.stopEffect(audioID); - */ - stopEffect: function (effectId) { - this._stopAudio(this._effects[effectId]); - delete this._effects[effectId]; + _resumeOfWebAudio: function(){ + var audio = this._currentSource; + if(audio){ + this._startTime = this._context.currentTime; + var offset = this._currentTime % audio.buffer.duration; + this._playOfWebAudio(offset); + } }, - /** - * Stop all playing sound effects. - * @example - * //example - * cc.audioEngine.stopAllEffects(); - */ - stopAllEffects: function () { - var effects = this._effects; - for (var key in effects) { - this._stopAudio(effects[key]); - delete effects[key]; + _resumeOfAudio: function(){ + var audio = this._element; + if(audio){ + audio.play(); } }, - /** - * Unload the preloaded effect from internal buffer - * @param {String} url - * @example - * //example - * cc.audioEngine.unloadEffect(EFFECT_FILE); - */ - unloadEffect: function (url) { - var locLoader = cc.loader, locEffects = this._effects, effectList = this._getEffectList(url); - locLoader.release(url);//release the resource in cc.loader first. - if (effectList.length == 0) return; - var realUrl = effectList[0].src; - delete this._audioPool[url]; - for (var key in locEffects) { - if (locEffects[key].src == realUrl) { - this._stopAudio(locEffects[key]); - delete locEffects[key]; + setVolume: function(volume){ + if(volume > 1) volume = 1; + if(volume < 0) volume = 0; + this.volume = volume; + if(this._AUDIO_TYPE === "AUDIO"){ + if(this._element){ + this._element.volume = volume; + } + }else{ + if(this._volume){ + this._volume["gain"].value = volume; } } }, - //effect end - /** - * End music and effects. - */ - end: function () { - this.stopMusic(); - this.stopAllEffects(); + getVolume: function(){ + return this.volume; }, - /** - * Called only when the hidden event of window occurs. - * @private - */ - _pausePlaying: function () {//in this function, do not change any status of audios - var self = this, effects = self._effects, eff; - for (var key in effects) { - eff = effects[key]; - if (eff && !eff.ended && !eff.paused) { - self._playings.push(eff); - eff.pause(); + cloneNode: function(){ + var audio, self; + if(this._AUDIO_TYPE === "AUDIO"){ + audio = new cc.Audio(); + + var elem = document.createElement("audio"); + elem.src = this.src; + audio.setElement(elem); + }else{ + var volume = this._context["createGain"](); + volume["gain"].value = 1; + volume["connect"](this._context["destination"]); + audio = new cc.Audio(this._context, volume, this.src); + if(this._buffer){ + audio.setBuffer(this._buffer); + }else{ + self = this; + this._setBufferCallback = function(buffer){ + audio.setBuffer(buffer); + self._setBufferCallback = null; + }; } } - if (self.isMusicPlaying()) { - self._playings.push(self._currMusic); - self._currMusic.pause(); + audio._AUDIO_TYPE = this._AUDIO_TYPE; + return audio; + } + +}); + +(function(polyfill){ + + var SWA = polyfill.webAudio, + SWB = polyfill.multichannel, + SWC = polyfill.auto; + + var support = []; + + (function(){ + var audio = document.createElement("audio"); + if(audio.canPlayType) { + var ogg = audio.canPlayType('audio/ogg; codecs="vorbis"'); + if (ogg && ogg !== "") support.push(".ogg"); + var mp3 = audio.canPlayType("audio/mpeg"); + if (mp3 && mp3 !== "") support.push(".mp3"); + var wav = audio.canPlayType('audio/wav; codecs="1"'); + if (wav && wav !== "") support.push(".wav"); + var mp4 = audio.canPlayType("audio/mp4"); + if (mp4 && mp4 !== "") support.push(".mp4"); + var m4a = audio.canPlayType("audio/x-m4a"); + if (m4a && m4a !== "") support.push(".m4a"); } - }, - /** - * Called only when the hidden event of window occurs. - * @private - */ - _resumePlaying: function () {//in this function, do not change any status of audios - var self = this, playings = this._playings; - for (var i = 0, li = playings.length; i < li; i++) { - self._resumeAudio(playings[i]); + })(); + try{ + if(SWA){ + var context = new (window.AudioContext || window.webkitAudioContext || window.mozAudioContext)(); + if(polyfill.delay) + setTimeout(function(){ context = new (window.AudioContext || window.webkitAudioContext || window.mozAudioContext)(); }, 0); } - playings.length = 0; + }catch(error){ + SWA = false; + cc.log("browser don't support webAudio"); } -}); + var loader = { + + cache: {}, + + load: function(realUrl, url, res, cb){ + + if(support.length === 0) + return cb("can not support audio!"); + + var i; + + var extname = cc.path.extname(realUrl); + + var typeList = [extname]; + for(i=0; itrue if the background music is playing, otherwise false + */ + willPlayMusic: function(){return false;}, + + /** + * Play music. + * @param {String} url The path of the music file without filename extension. + * @param {Boolean} loop Whether the music loop or not. + * @example + * //example + * cc.audioEngine.playMusic(path, false); + */ + playMusic: function(url, loop){ + var bgMusic = this._currMusic; + if(bgMusic && bgMusic.src !== url && bgMusic.getPlaying()){ + bgMusic.stop(); } + var audio = loader.cache[url]; + if(!audio){ + cc.loader.load(url); + audio = loader.cache[url]; + } + audio.play(0, loop); + audio.setVolume(this._musicVolume); + this._currMusic = audio; }, - playEffect: function (url, loop) { - var self = this, currEffect = self._currEffect; - var audio = loop ? self._getEffect(url) : self._getSingleEffect(url); - if (!audio) return null; - audio.loop = loop || false; - var audioId = self._audioID++; - self._effects[audioId] = audio; - - if (self.isMusicPlaying()) { - self.pauseMusic(); - self._needToResumeMusic = true; + /** + * Stop playing music. + * @param {Boolean} [releaseData] If release the music data or not.As default value is false. + * @example + * //example + * cc.audioEngine.stopMusic(); + */ + stopMusic: function(releaseData){ + var audio = this._currMusic; + if(audio){ + audio.stop(); + if (releaseData) + cc.loader.release(audio.src); } - if (currEffect) { - if (currEffect != audio) self._waitingEffIds.push(self._currEffectId); - self._waitingEffIds.push(audioId); - currEffect.pause(); - } else { - self._currEffect = audio; - self._currEffectId = audioId; + }, + + /** + * Pause playing music. + * @example + * //example + * cc.audioEngine.pauseMusic(); + */ + pauseMusic: function(){ + var audio = this._currMusic; + if(audio) + audio.pause(); + }, + + /** + * Resume playing music. + * @example + * //example + * cc.audioEngine.resumeMusic(); + */ + resumeMusic: function(){ + var audio = this._currMusic; + if(audio) + audio.resume(); + }, + + /** + * Rewind playing music. + * @example + * //example + * cc.audioEngine.rewindMusic(); + */ + rewindMusic: function(){ + var audio = this._currMusic; + if(audio){ + audio.stop(); audio.play(); } - return audioId; }, - pauseEffect: function (effectId) { - cc.log("pauseEffect not supported in single audio mode!") -// var currEffect = this._currEffect; -// if(this._currEffectId != effectId || !currEffect || currEffect.ended) return; -// this._pausedEffIds.push(this._currEffectId); -// currEffect.pause(); + + /** + * The volume of the music max value is 1.0,the min value is 0.0 . + * @return {Number} + * @example + * //example + * var volume = cc.audioEngine.getMusicVolume(); + */ + getMusicVolume: function(){ + return this._musicVolume; }, - pauseAllEffects: function () { - var self = this, waitings = self._waitingEffIds, pauseds = self._pausedEffIds, currEffect = self._currEffect; - if (!currEffect) return; - for (var i = 0, li = waitings.length; i < li; i++) { - pauseds.push(waitings[i]); + + /** + * Set the volume of music. + * @param {Number} volume Volume must be in 0.0~1.0 . + * @example + * //example + * cc.audioEngine.setMusicVolume(0.5); + */ + setMusicVolume: function(volume){ + volume = volume - 0; + if(isNaN(volume)) volume = 1; + if(volume > 1) volume = 1; + if(volume < 0) volume = 0; + + this._musicVolume = volume; + var audio = this._currMusic; + if(audio){ + audio.setVolume(volume); } - waitings.length = 0;//clear - pauseds.push(self._currEffectId); - currEffect.pause(); }, - resumeEffect: function (effectId) { - cc.log("resumeEffect not supported in single audio mode!") -// var self = this, currEffect = self._currEffect, pauseds = self._pausedEffIds; -// if(self._currEffectId == effectId) return;//the effect is playing -// var index = pauseds.indexOf(effectId); -// if(index >= 0){ -// pauseds.splice(index, 1);//delete item -// var eff = self._effects[effectId]; -// var expendTime = currEffect ? currEffect.currentTime - (currEffect.startTime || 0) : 0; -// if(eff && eff.currentTime + expendTime < eff.duration) { -// self._waitingEffIds.push(self._currEffectId); -// self._waitingEffIds.push(effectId); -// self._currEffect.pause(); -// } -// } + + /** + * Whether the music is playing. + * @return {Boolean} If is playing return true,or return false. + * @example + * //example + * if (cc.audioEngine.isMusicPlaying()) { + * cc.log("music is playing"); + * } + * else { + * cc.log("music is not playing"); + * } + */ + isMusicPlaying: function(){ + var audio = this._currMusic; + if(audio){ + return audio.getPlaying(); + }else{ + return false; + } }, - resumeAllEffects: function () { - var self = this, waitings = self._waitingEffIds, pauseds = self._pausedEffIds; - if (self.isMusicPlaying()) {//if music is playing, pause it first - self.pauseMusic(); - self._needToResumeMusic = true; + _audioPool: {}, + _maxAudioInstance: 5, + _effectVolume: 1, + /** + * Play sound effect. + * @param {String} url The path of the sound effect with filename extension. + * @param {Boolean} loop Whether to loop the effect playing, default value is false + * @return {Number|null} the audio id + * @example + * //example + * var soundId = cc.audioEngine.playEffect(path); + */ + playEffect: function(url, loop){ + //If the browser just support playing single audio + if(!SWB){ + //Must be forced to shut down + //Because playing multichannel audio will be stuck in chrome 28 (android) + return null; } - for (var i = 0, li = pauseds.length; i < li; i++) {//move pauseds to waitings - waitings.push(pauseds[i]); + var effectList = this._audioPool[url]; + if(!effectList){ + effectList = this._audioPool[url] = []; } - pauseds.length = 0;//clear - if (!self._currEffect && waitings.length >= 0) {//is none currEff, resume the newest effect in waitings - var effId = waitings.pop(); - var eff = self._effects[effId]; - if (eff) { - self._currEffectId = effId; - self._currEffect = eff; - self._resumeAudio(eff); + + var i; + + for(i=0; i= 0) { - waitings.splice(index, 1); - } else { - index = pauseds.indexOf(effectId); - if (index >= 0) pauseds.splice(index, 1); + + if(effectList[i]){ + audio = effectList[i]; + audio.setVolume(this._effectVolume); + audio.play(0, loop); + }else if(!SWA && i > this._maxAudioInstance){ + cc.log("Error: %s greater than %d", url, this._maxAudioInstance); + }else{ + var audio = loader.cache[url]; + if(!audio){ + cc.loader.load(url); + audio = loader.cache[url]; } + audio = audio.cloneNode(); + audio.setVolume(this._effectVolume); + audio.loop = loop || false; + audio.play(); + effectList.push(audio); } + + return audio; }, - stopAllEffects: function () { - var self = this; - self._stopAllEffects(); - if (!self._currEffect && self._needToResumeMusic) {//need to resume music - self._resumeAudio(self._currMusic); - self._musicPlayState = 2; - self._needToResumeMusic = false; - self._expendTime4Music = 0; + + /** + * Set the volume of sound effects. + * @param {Number} volume Volume must be in 0.0~1.0 . + * @example + * //example + * cc.audioEngine.setEffectsVolume(0.5); + */ + setEffectsVolume: function(volume){ + volume = volume - 0; + if(isNaN(volume)) volume = 1; + if(volume > 1) volume = 1; + if(volume < 0) volume = 0; + + this._effectVolume = volume; + var audioPool = this._audioPool; + for(var p in audioPool){ + var audioList = audioPool[p]; + if(Array.isArray(audioList)) + for(var i=0; i 0 ? effectList[0].src : effCache[url].src; - delete self._audioPool[url]; - delete effCache[url]; - for (var key in locEffects) { - if (locEffects[key].src == realUrl) { - delete locEffects[key]; - } - } - if (currEffect && currEffect.src == realUrl) self._stopAudio(currEffect);//need to stop currEff + /** + * The volume of the effects max value is 1.0,the min value is 0.0 . + * @return {Number} + * @example + * //example + * var effectVolume = cc.audioEngine.getEffectsVolume(); + */ + getEffectsVolume: function(){ + return this._effectVolume; }, /** - * When `loop == false`, one url one audio. - * @param url - * @returns {*} - * @private + * Pause playing sound effect. + * @param {Number} cc.Audio The return value of function playEffect. + * @example + * //example + * cc.audioEngine.pauseEffect(audioID); */ - _getSingleEffect: function (url) { - var self = this, audio = self._effectCache4Single[url], locLoader = cc.loader, - waitings = self._waitingEffIds, pauseds = self._pausedEffIds, effects = self._effects; - if (audio) { - audio.duration && (audio.currentTime = 0);//reset current time - } else { - audio = self._getAudioByUrl(url); - if (!audio) return null; - audio = audio.cloneNode(true); - if (self._effectPauseCb) - cc._addEventListener(audio, "pause", self._effectPauseCb); - audio.volume = self._effectsVolume; - self._effectCache4Single[url] = audio; - } - for (var i = 0, li = waitings.length; i < li;) {//reset waitings - if (effects[waitings[i]] == audio) { - waitings.splice(i, 1); - } else i++; - } - for (var i = 0, li = pauseds.length; i < li;) {//reset pauseds - if (effects[pauseds[i]] == audio) { - pauseds.splice(i, 1); - } else i++; + pauseEffect: function(audio){ + if(audio){ + audio.pause(); } - audio._isToPlay = true;//custom flag - return audio; }, - _stopAllEffects: function () { - var self = this, currEffect = self._currEffect, audioPool = self._audioPool, sglCache = self._effectCache4Single, - waitings = self._waitingEffIds, pauseds = self._pausedEffIds; - if (!currEffect && waitings.length == 0 && pauseds.length == 0) return; - for (var key in sglCache) { - var eff = sglCache[key]; - eff.duration && (eff.currentTime = eff.duration); - } - waitings.length = 0; - pauseds.length = 0; - for (var key in audioPool) {//reset audios in pool to be ended - var list = audioPool[key]; - for (var i = 0, li = list.length; i < li; i++) { - var eff = list[i]; - eff.loop = false; - eff.duration && (eff.currentTime = eff.duration); + + /** + * Pause all playing sound effect. + * @example + * //example + * cc.audioEngine.pauseAllEffects(); + */ + pauseAllEffects: function(){ + var ap = this._audioPool; + for(var p in ap){ + var list = ap[p]; + for(var i=0; i 0) { - self._resumeAudio(playings[0]); - playings.length = 0; - } - } - }); -} + /** + * End music and effects. + */ + end: function(){ + this.stopMusic(); + this.stopAllEffects(); + }, -/** - * Resource loader for audio. - */ -cc._audioLoader = { - _supportedAudioTypes: null, - getBasePath: function () { - return cc.loader.audioPath; - }, - _load: function (realUrl, url, res, count, tryArr, audio, cb) { - var self = this, locLoader = cc.loader, path = cc.path; - var types = this._supportedAudioTypes; - var extname = ""; - if (types.length == 0) return cb("can not support audio!"); - if (count == -1) { - extname = (path.extname(realUrl) || "").toLowerCase(); - if (!self.audioTypeSupported(extname)) { - extname = types[0]; - count = 0; + _pauseCache: [], + _pausePlaying: function(){ + var bgMusic = this._currMusic; + if(bgMusic && bgMusic.getPlaying()){ + bgMusic.pause(); + this._pauseCache.push(bgMusic); } - } else if (count < types.length) { - extname = types[count]; - } else { - return cb("can not found the resource of audio! Last match url is : " + realUrl); - } - if (tryArr.indexOf(extname) >= 0) return self._load(realUrl, url, res, count + 1, tryArr, audio, cb); - realUrl = path.changeExtname(realUrl, extname); - tryArr.push(extname); - audio = self._loadAudio(realUrl, audio, function (err) { - if (err) return self._load(realUrl, url, res, count + 1, tryArr, audio, cb);//can not found - cb(null, audio); - }); - locLoader.cache[url] = audio; - }, + var ap = this._audioPool; + for(var p in ap){ + var list = ap[p]; + for(var i=0; i= 0; - }, - _loadAudio: function (url, audio, cb) { - var _Audio = cc.WebAudio || Audio; - if (arguments.length == 2) { - cb = audio, audio = new _Audio(); - } else if (arguments.length == 3 && !audio) { - audio = new _Audio(); - } - audio.src = url; - audio.preload = "auto"; - - var ua = navigator.userAgent; - if (/Mobile/.test(ua) && (/iPhone OS/.test(ua) || /iPad/.test(ua) || /Firefox/.test(ua)) || /MSIE/.test(ua)) { - audio.load(); - cb(null, audio); - } else { - var canplaythrough = "canplaythrough", error = "error"; - cc._addEventListener(audio, canplaythrough, function () { - cb(null, audio); - this.removeEventListener(canplaythrough, arguments.callee, false); - this.removeEventListener(error, arguments.callee, false); - }, false); - cc._addEventListener(audio, error, function () { - cb("load " + url + " failed") - this.removeEventListener(canplaythrough, arguments.callee, false); - this.removeEventListener(error, arguments.callee, false); - }, false); - audio.load(); + _resumePlaying: function(){ + var list = this._pauseCache; + for(var i=0; i tag is supported, go on - var _check = function (typeStr) { - var result = au.canPlayType(typeStr); - return result != "no" && result != ""; + }; + + /** + * ome browsers must click on the page + */ + if(!SWC){ + + //TODO Did not complete loading + var reBGM = function(){ + var bg = cc.audioEngine._currMusic; + if( + bg && + bg._touch === false && + bg._playing && + bg.getPlaying() + ){ + bg._touch = true; + bg.play(0, bg.loop); + !polyfill.replay && cc._canvas.removeEventListener("touchstart", reBGM); + } + }; - if (_check('audio/ogg; codecs="vorbis"')) arr.push(".ogg"); - if (_check("audio/mpeg")) arr.push(".mp3"); - if (_check('audio/wav; codecs="1"')) arr.push(".wav"); - if (_check("audio/mp4")) arr.push(".mp4"); - if (_check("audio/x-m4a") || _check("audio/aac")) arr.push(".m4a"); + + setTimeout(function(){ + if(cc._canvas){ + cc._canvas.addEventListener("touchstart", reBGM, false); + } + }, 150); } - return arr; -}(); -cc.loader.register(["mp3", "ogg", "wav", "mp4", "m4a"], cc._audioLoader); - -// Initialize Audio engine singleton -cc.audioEngine = cc.AudioEngineForSingle ? new cc.AudioEngineForSingle() : new cc.AudioEngine(); -cc.eventManager.addCustomListener(cc.game.EVENT_HIDE, function () { - cc.audioEngine._pausePlaying(); -}); -cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { - cc.audioEngine._resumePlaying(); -}); + + cc.eventManager.addCustomListener(cc.game.EVENT_HIDE, function () { + cc.audioEngine._pausePlaying(); + }); + cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { + cc.audioEngine._resumePlaying(); + }); + +})(cc.__audioSupport); diff --git a/cocos2d/clipping-nodes/CCClippingNode.js b/cocos2d/clipping-nodes/CCClippingNode.js index 397ce18470..65a10b45cf 100644 --- a/cocos2d/clipping-nodes/CCClippingNode.js +++ b/cocos2d/clipping-nodes/CCClippingNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2013 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2012 Pierre-David Bélanger http://www.cocos2d-x.org @@ -31,390 +31,106 @@ */ cc.stencilBits = -1; -cc.setProgram = function (node, program) { - node.shaderProgram = program; - - var children = node.children; - if (!children) - return; - - for (var i = 0; i < children.length; i++) - cc.setProgram(children[i], program); -}; - /** *

* cc.ClippingNode is a subclass of cc.Node.
- * It draws its content (childs) clipped using a stencil.
+ * It draws its content (children) clipped using a stencil.
* The stencil is an other cc.Node that will not be drawn.
* The clipping is done using the alpha part of the stencil (adjusted with an alphaThreshold). *

* @class * @extends cc.Node + * @param {cc.Node} [stencil=null] * * @property {Number} alphaThreshold - Threshold for alpha value. * @property {Boolean} inverted - Indicate whether in inverted mode. - * @property {cc.Node} stencil - he cc.Node to use as a stencil to do the clipping. */ +//@property {cc.Node} stencil - he cc.Node to use as a stencil to do the clipping. cc.ClippingNode = cc.Node.extend(/** @lends cc.ClippingNode# */{ alphaThreshold: 0, inverted: false, _stencil: null, - _godhelpme: false, + _className: "ClippingNode", /** - * Creates and initializes a clipping node with an other node as its stencil. - * The stencil node will be retained. - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {cc.Node} [stencil=null] */ ctor: function (stencil) { + stencil = stencil || null; cc.Node.prototype.ctor.call(this); - this._stencil = null; - this.alphaThreshold = 0; + this._stencil = stencil; + this.alphaThreshold = 1; this.inverted = false; - - stencil = stencil || null; - cc.ClippingNode.prototype.init.call(this, stencil); + this._renderCmd.initStencilBits(); }, /** - * Initializes a clipping node with an other node as its stencil.
- * The stencil node will be retained, and its parent will be set to this clipping node. + * Initialization of the node, please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. + * @function * @param {cc.Node} [stencil=null] */ - init: null, - _className: "ClippingNode", - - _initForWebGL: function (stencil) { + init: function (stencil) { this._stencil = stencil; - this.alphaThreshold = 1; this.inverted = false; - // get (only once) the number of bits of the stencil buffer - cc.ClippingNode._init_once = true; - if (cc.ClippingNode._init_once) { - cc.stencilBits = cc._renderContext.getParameter(cc._renderContext.STENCIL_BITS); - if (cc.stencilBits <= 0) - cc.log("Stencil buffer is not enabled."); - cc.ClippingNode._init_once = false; - } + this._renderCmd.initStencilBits(); return true; }, - _initForCanvas: function (stencil) { - this._stencil = stencil; - this.alphaThreshold = 1; - this.inverted = false; - }, - + /** + *

+ * Event callback that is invoked every time when node enters the 'stage'.
+ * If the CCNode enters the 'stage' with a transition, this event is called when the transition starts.
+ * During onEnter you can't access a "sister/brother" node.
+ * If you override onEnter, you must call its parent's onEnter function with this._super(). + *

+ * @function + */ onEnter: function () { cc.Node.prototype.onEnter.call(this); this._stencil.onEnter(); }, + /** + *

+ * Event callback that is invoked when the node enters in the 'stage'.
+ * If the node enters the 'stage' with a transition, this event is called when the transition finishes.
+ * If you override onEnterTransitionDidFinish, you shall call its parent's onEnterTransitionDidFinish with this._super() + *

+ * @function + */ onEnterTransitionDidFinish: function () { cc.Node.prototype.onEnterTransitionDidFinish.call(this); this._stencil.onEnterTransitionDidFinish(); }, + /** + *

+ * callback that is called every time the node leaves the 'stage'.
+ * If the node leaves the 'stage' with a transition, this callback is called when the transition starts.
+ * If you override onExitTransitionDidStart, you shall call its parent's onExitTransitionDidStart with this._super() + *

+ * @function + */ onExitTransitionDidStart: function () { this._stencil.onExitTransitionDidStart(); cc.Node.prototype.onExitTransitionDidStart.call(this); }, - onExit: function () { - this._stencil.onExit(); - cc.Node.prototype.onExit.call(this); - }, - - visit: null, - - _visitForWebGL: function (ctx) { - var gl = ctx || cc._renderContext; - - // if stencil buffer disabled - if (cc.stencilBits < 1) { - // draw everything, as if there where no stencil - cc.Node.prototype.visit.call(this, ctx); - return; - } - - // return fast (draw nothing, or draw everything if in inverted mode) if: - // - nil stencil node - // - or stencil node invisible: - if (!this._stencil || !this._stencil.visible) { - if (this.inverted) - cc.Node.prototype.visit.call(this, ctx); // draw everything - return; - } - - // store the current stencil layer (position in the stencil buffer), - // this will allow nesting up to n CCClippingNode, - // where n is the number of bits of the stencil buffer. - cc.ClippingNode._layer = -1; - - // all the _stencilBits are in use? - if (cc.ClippingNode._layer + 1 == cc.stencilBits) { - // warn once - cc.ClippingNode._visit_once = true; - if (cc.ClippingNode._visit_once) { - cc.log("Nesting more than " + cc.stencilBits + "stencils is not supported. Everything will be drawn without stencil for this node and its childs."); - cc.ClippingNode._visit_once = false; - } - // draw everything, as if there where no stencil - cc.Node.prototype.visit.call(this, ctx); - return; - } - - /////////////////////////////////// - // INIT - - // increment the current layer - cc.ClippingNode._layer++; - - // mask of the current layer (ie: for layer 3: 00000100) - var mask_layer = 0x1 << cc.ClippingNode._layer; - // mask of all layers less than the current (ie: for layer 3: 00000011) - var mask_layer_l = mask_layer - 1; - // mask of all layers less than or equal to the current (ie: for layer 3: 00000111) - var mask_layer_le = mask_layer | mask_layer_l; - - // manually save the stencil state - var currentStencilEnabled = gl.isEnabled(gl.STENCIL_TEST); - var currentStencilWriteMask = gl.getParameter(gl.STENCIL_WRITEMASK); - var currentStencilFunc = gl.getParameter(gl.STENCIL_FUNC); - var currentStencilRef = gl.getParameter(gl.STENCIL_REF); - var currentStencilValueMask = gl.getParameter(gl.STENCIL_VALUE_MASK); - var currentStencilFail = gl.getParameter(gl.STENCIL_FAIL); - var currentStencilPassDepthFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL); - var currentStencilPassDepthPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS); - - // enable stencil use - gl.enable(gl.STENCIL_TEST); - // check for OpenGL error while enabling stencil test - //cc.checkGLErrorDebug(); - - // all bits on the stencil buffer are readonly, except the current layer bit, - // this means that operation like glClear or glStencilOp will be masked with this value - gl.stencilMask(mask_layer); - - // manually save the depth test state - //GLboolean currentDepthTestEnabled = GL_TRUE; - //currentDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST); - var currentDepthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK); - - // disable depth test while drawing the stencil - //glDisable(GL_DEPTH_TEST); - // disable update to the depth buffer while drawing the stencil, - // as the stencil is not meant to be rendered in the real scene, - // it should never prevent something else to be drawn, - // only disabling depth buffer update should do - gl.depthMask(false); - - /////////////////////////////////// - // CLEAR STENCIL BUFFER - - // manually clear the stencil buffer by drawing a fullscreen rectangle on it - // setup the stencil test func like this: - // for each pixel in the fullscreen rectangle - // never draw it into the frame buffer - // if not in inverted mode: set the current layer value to 0 in the stencil buffer - // if in inverted mode: set the current layer value to 1 in the stencil buffer - gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); - gl.stencilOp(!this.inverted ? gl.ZERO : gl.REPLACE, gl.KEEP, gl.KEEP); - - // draw a fullscreen solid rectangle to clear the stencil buffer - //ccDrawSolidRect(CCPointZero, ccpFromSize([[CCDirector sharedDirector] winSize]), ccc4f(1, 1, 1, 1)); - cc._drawingUtil.drawSolidRect(cc.p(0, 0), cc.pFromSize(cc.director.getWinSize()), cc.color(255, 255, 255, 255)); - - /////////////////////////////////// - // DRAW CLIPPING STENCIL - - // setup the stencil test func like this: - // for each pixel in the stencil node - // never draw it into the frame buffer - // if not in inverted mode: set the current layer value to 1 in the stencil buffer - // if in inverted mode: set the current layer value to 0 in the stencil buffer - gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); - gl.stencilOp(!this.inverted ? gl.REPLACE : gl.ZERO, gl.KEEP, gl.KEEP); - - if (this.alphaThreshold < 1) { - // since glAlphaTest do not exists in OES, use a shader that writes - // pixel only if greater than an alpha threshold - var program = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLORALPHATEST); - var alphaValueLocation = gl.getUniformLocation(program.getProgram(), cc.UNIFORM_ALPHA_TEST_VALUE_S); - // set our alphaThreshold - cc.glUseProgram(program.getProgram()); - program.setUniformLocationWith1f(alphaValueLocation, this.alphaThreshold); - // we need to recursively apply this shader to all the nodes in the stencil node - // XXX: we should have a way to apply shader to all nodes without having to do this - cc.setProgram(this._stencil, program); - } - - // draw the stencil node as if it was one of our child - // (according to the stencil test func/op and alpha (or alpha shader) test) - cc.kmGLPushMatrix(); - this.transform(); - this._stencil.visit(); - cc.kmGLPopMatrix(); - - // restore alpha test state - //if (this.alphaThreshold < 1) { - // XXX: we need to find a way to restore the shaders of the stencil node and its childs - //} - - // restore the depth test state - gl.depthMask(currentDepthWriteMask); - //if (currentDepthTestEnabled) { - // glEnable(GL_DEPTH_TEST); - //} - - /////////////////////////////////// - // DRAW CONTENT - - // setup the stencil test func like this: - // for each pixel of this node and its childs - // if all layers less than or equals to the current are set to 1 in the stencil buffer - // draw the pixel and keep the current layer in the stencil buffer - // else - // do not draw the pixel but keep the current layer in the stencil buffer - gl.stencilFunc(gl.EQUAL, mask_layer_le, mask_layer_le); - gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); - - // draw (according to the stencil test func) this node and its childs - cc.Node.prototype.visit.call(this, ctx); - - /////////////////////////////////// - // CLEANUP - - // manually restore the stencil state - gl.stencilFunc(currentStencilFunc, currentStencilRef, currentStencilValueMask); - gl.stencilOp(currentStencilFail, currentStencilPassDepthFail, currentStencilPassDepthPass); - gl.stencilMask(currentStencilWriteMask); - if (!currentStencilEnabled) - gl.disable(gl.STENCIL_TEST); - - // we are done using this layer, decrement - cc.ClippingNode._layer--; - }, - - _visitForCanvas: function (ctx) { - // return fast (draw nothing, or draw everything if in inverted mode) if: - // - nil stencil node - // - or stencil node invisible: - if (!this._stencil || !this._stencil.visible) { - if (this.inverted) - cc.Node.prototype.visit.call(this, ctx); // draw everything - return; - } - - var context = ctx || cc._renderContext; - // Composition mode, costy but support texture stencil - if (this._cangodhelpme() || this._stencil instanceof cc.Sprite) { - // Cache the current canvas, for later use (This is a little bit heavy, replace this solution with other walkthrough) - var canvas = context.canvas; - var locCache = cc.ClippingNode._getSharedCache(); - locCache.width = canvas.width; - locCache.height = canvas.height; - var locCacheCtx = locCache.getContext("2d"); - locCacheCtx.drawImage(canvas, 0, 0); - - context.save(); - // Draw everything first using node visit function - cc.Node.prototype.visit.call(this, context); - - context.globalCompositeOperation = this.inverted ? "destination-out" : "destination-in"; - - this.transform(context); - this._stencil.visit(); - - context.restore(); - - // Redraw the cached canvas, so that the cliped area shows the background etc. - context.save(); - context.setTransform(1, 0, 0, 1, 0, 0); - context.globalCompositeOperation = "destination-over"; - context.drawImage(locCache, 0, 0); - context.restore(); - } - // Clip mode, fast, but only support cc.DrawNode - else { - var i, children = this._children, locChild; - - context.save(); - this.transform(context); - this._stencil.visit(context); - context.clip(); - - // Clip mode doesn't support recusive stencil, so once we used a clip stencil, - // so if it has ClippingNode as a child, the child must uses composition stencil. - this._cangodhelpme(true); - var len = children.length; - if (len > 0) { - this.sortAllChildren(); - // draw children zOrder < 0 - for (i = 0; i < len; i++) { - locChild = children[i]; - if (locChild._localZOrder < 0) - locChild.visit(context); - else - break; - } - this.draw(context); - for (; i < len; i++) { - children[i].visit(context); - } - } else - this.draw(context); - this._cangodhelpme(false); - - context.restore(); - } - }, - - /** - * The cc.Node to use as a stencil to do the clipping.
- * The stencil node will be retained. This default to nil. - * @return {cc.Node} - */ - getStencil: function () { - return this._stencil; - }, - /** + *

+ * callback that is called every time the node leaves the 'stage'.
+ * If the node leaves the 'stage' with a transition, this callback is called when the transition finishes.
+ * During onExit you can't access a sibling node.
+ * If you override onExit, you shall call its parent's onExit with this._super(). + *

* @function - * @param {cc.Node} stencil */ - setStencil: null, - - _setStencilForWebGL: function (stencil) { - this._stencil = stencil; - }, - - _setStencilForCanvas: function (stencil) { - this._stencil = stencil; - var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); - var locContext = cc._renderContext; - // For texture stencil, use the sprite itself - if (stencil instanceof cc.Sprite) { - return; - } - // For shape stencil, rewrite the draw of stencil ,only init the clip path and draw nothing. - else if (stencil instanceof cc.DrawNode) { - stencil.draw = function () { - for (var i = 0; i < stencil._buffer.length; i++) { - var element = stencil._buffer[i]; - var vertices = element.verts; - var firstPoint = vertices[0]; - locContext.beginPath(); - locContext.moveTo(firstPoint.x * locEGL_ScaleX, -firstPoint.y * locEGL_ScaleY); - for (var j = 1, len = vertices.length; j < len; j++) - locContext.lineTo(vertices[j].x * locEGL_ScaleX, -vertices[j].y * locEGL_ScaleY); - } - } - } + onExit: function () { + this._stencil.onExit(); + cc.Node.prototype.onExit.call(this); }, /** @@ -450,7 +166,6 @@ cc.ClippingNode = cc.Node.extend(/** @lends cc.ClippingNode# */{ return this.inverted; }, - /** * set whether or not invert of stencil * @param {Boolean} inverted @@ -459,46 +174,50 @@ cc.ClippingNode = cc.Node.extend(/** @lends cc.ClippingNode# */{ this.inverted = inverted; }, - _cangodhelpme: function (godhelpme) { - if (godhelpme === true || godhelpme === false) - cc.ClippingNode.prototype._godhelpme = godhelpme; - return cc.ClippingNode.prototype._godhelpme; + /** + * The cc.Node to use as a stencil to do the clipping.
+ * The stencil node will be retained. This default to nil. + * @return {cc.Node} + */ + getStencil: function () { + return this._stencil; + }, + + /** + * Set stencil. + * @function + * @param {cc.Node} stencil + */ + setStencil: function (stencil) { + if(this._stencil === stencil) + return; + this._renderCmd.setStencil(stencil); + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ClippingNode.CanvasRenderCmd(this); + else + return new cc.ClippingNode.WebGLRenderCmd(this); } }); var _p = cc.ClippingNode.prototype; -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - //WebGL - _p.init = _p._initForWebGL; - _p.visit = _p._visitForWebGL; - _p.setStencil = _p._setStencilForWebGL; -} else { - _p.init = _p._initForCanvas; - _p.visit = _p._visitForCanvas; - _p.setStencil = _p._setStencilForCanvas; -} - // Extended properties cc.defineGetterSetter(_p, "stencil", _p.getStencil, _p.setStencil); /** @expose */ _p.stencil; - -cc.ClippingNode._init_once = null; -cc.ClippingNode._visit_once = null; -cc.ClippingNode._layer = null; -cc.ClippingNode._sharedCache = null; - -cc.ClippingNode._getSharedCache = function () { - return (cc.ClippingNode._sharedCache) || (cc.ClippingNode._sharedCache = document.createElement("canvas")); -}; - /** - * Creates and initializes a clipping node with an other node as its stencil.
+ * Creates and initializes a clipping node with an other node as its stencil.
* The stencil node will be retained. + * @deprecated since v3.0, please use "new cc.ClippingNode(stencil)" instead * @param {cc.Node} [stencil=null] * @return {cc.ClippingNode} + * @example + * //example + * new cc.ClippingNode(stencil); */ cc.ClippingNode.create = function (stencil) { return new cc.ClippingNode(stencil); diff --git a/cocos2d/clipping-nodes/CCClippingNodeCanvasRenderCmd.js b/cocos2d/clipping-nodes/CCClippingNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..9a0a0d8d2d --- /dev/null +++ b/cocos2d/clipping-nodes/CCClippingNodeCanvasRenderCmd.js @@ -0,0 +1,227 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//-------------------------- ClippingNode's canvas render cmd -------------------------------- +(function(){ + cc.ClippingNode.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + + this._godhelpme = false; + this._clipElemType = false; + + this._rendererSaveCmd = new cc.CustomRenderCmd(this, this._saveCmdCallback); + this._rendererClipCmd = new cc.CustomRenderCmd(this, this._clipCmdCallback); + this._rendererRestoreCmd = new cc.CustomRenderCmd(this, this._restoreCmdCallback); + }; + var proto = cc.ClippingNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.ClippingNode.CanvasRenderCmd; + + proto.initStencilBits = function(){}; + + proto.setStencil = function(stencil){ + if(stencil == null) + return; + + this._node._stencil = stencil; + + // For shape stencil, rewrite the draw of stencil ,only init the clip path and draw nothing. + //else + if (stencil instanceof cc.DrawNode) { + if(stencil._buffer){ + for(var i=0; i 0) { + node.sortAllChildren(); + for (i = 0; i < len; i++) + children[i]._renderCmd.visit(this); + } + this._cangodhelpme(false); + } + + cc.renderer.pushRenderCommand(this._rendererRestoreCmd); + this._dirtyFlag = 0; + }; + + cc.ClippingNode.CanvasRenderCmd._sharedCache = null; + cc.ClippingNode.CanvasRenderCmd._getSharedCache = function () { + return (cc.ClippingNode.CanvasRenderCmd._sharedCache) || (cc.ClippingNode.CanvasRenderCmd._sharedCache = document.createElement("canvas")); + }; +})(); \ No newline at end of file diff --git a/cocos2d/clipping-nodes/CCClippingNodeWebGLRenderCmd.js b/cocos2d/clipping-nodes/CCClippingNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..0e199ff3b7 --- /dev/null +++ b/cocos2d/clipping-nodes/CCClippingNodeWebGLRenderCmd.js @@ -0,0 +1,238 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +// ------------------------------- ClippingNode's WebGL render cmd ------------------------------ +(function(){ + cc.ClippingNode.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + + this._beforeVisitCmd = new cc.CustomRenderCmd(this, this._onBeforeVisit); + this._afterDrawStencilCmd = new cc.CustomRenderCmd(this, this._onAfterDrawStencil); + this._afterVisitCmd = new cc.CustomRenderCmd(this, this._onAfterVisit); + + this._currentStencilFunc = null; + this._currentStencilRef = null; + this._currentStencilValueMask = null; + this._currentStencilFail = null; + this._currentStencilPassDepthFail = null; + this._currentStencilPassDepthPass = null; + this._currentStencilWriteMask = null; + this._currentStencilEnabled = null; + this._currentDepthWriteMask = null; + this._mask_layer_le = null; + }; + + var proto = cc.ClippingNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.ClippingNode.WebGLRenderCmd; + + cc.ClippingNode.WebGLRenderCmd._init_once = null; + cc.ClippingNode.WebGLRenderCmd._visit_once = null; + cc.ClippingNode.WebGLRenderCmd._layer = -1; + + proto.initStencilBits = function(){ + // get (only once) the number of bits of the stencil buffer + cc.ClippingNode.WebGLRenderCmd._init_once = true; + if (cc.ClippingNode.WebGLRenderCmd._init_once) { + cc.stencilBits = cc._renderContext.getParameter(cc._renderContext.STENCIL_BITS); + if (cc.stencilBits <= 0) + cc.log("Stencil buffer is not enabled."); + cc.ClippingNode.WebGLRenderCmd._init_once = false; + } + }; + + proto.transform = function(parentCmd, recursive){ + var node = this._node; + cc.Node.WebGLRenderCmd.prototype.transform.call(this, parentCmd, recursive); + if(node._stencil) + node._stencil._renderCmd.transform(this, recursive); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + if( node._parent && node._parent._renderCmd) + this._curLevel = node._parent._renderCmd._curLevel + 1; + + // if stencil buffer disabled + if (cc.stencilBits < 1) { + // draw everything, as if there where no stencil + cc.Node.WebGLRenderCmd.prototype.visit.call(this, parentCmd); + return; + } + + if (!node._stencil || !node._stencil.visible) { + if (node.inverted) + cc.Node.WebGLRenderCmd.prototype.visit.call(this, parentCmd); // draw everything + return; + } + + if (cc.ClippingNode.WebGLRenderCmd._layer + 1 === cc.stencilBits) { + cc.ClippingNode.WebGLRenderCmd._visit_once = true; + if (cc.ClippingNode.WebGLRenderCmd._visit_once) { + cc.log("Nesting more than " + cc.stencilBits + "stencils is not supported. Everything will be drawn without stencil for this node and its children."); + cc.ClippingNode.WebGLRenderCmd._visit_once = false; + } + // draw everything, as if there where no stencil + cc.Node.WebGLRenderCmd.prototype.visit.call(this, parentCmd); + return; + } + + cc.renderer.pushRenderCommand(this._beforeVisitCmd); + + //optimize performance for javascript + var currentStack = cc.current_stack; + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + currentStack.top = this._stackMatrix; + + //this._stencil._stackMatrix = this._stackMatrix; + node._stencil._renderCmd.visit(this); + + cc.renderer.pushRenderCommand(this._afterDrawStencilCmd); + + // draw (according to the stencil test func) this node and its children + var locChildren = node._children; + if (locChildren && locChildren.length > 0) { + var childLen = locChildren.length; + node.sortAllChildren(); + // draw children zOrder < 0 + for (var i = 0; i < childLen; i++) { + locChildren[i]._renderCmd.visit(this); + } + } + + cc.renderer.pushRenderCommand(this._afterVisitCmd); + + this._dirtyFlag = 0; + //optimize performance for javascript + currentStack.top = currentStack.stack.pop(); + }; + + proto.setStencil = function(stencil){ + var node = this._node; + if(node._stencil) + node._stencil._parent = null; + node._stencil = stencil; + if(node._stencil) + node._stencil._parent = node; + }; + + proto._drawFullScreenQuadClearStencil = function () { + // draw a fullscreen solid rectangle to clear the stencil buffer + var projStack = cc.projection_matrix_stack; + //cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + //cc.kmGLPushMatrix(); + //cc.kmGLLoadIdentity(); + projStack.push(); + projStack.top.identity(); + + //cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + //cc.kmGLPushMatrix(); + //cc.kmGLLoadIdentity(); + var modelViewStack = cc.modelview_matrix_stack; + modelViewStack.push(); + modelViewStack.top.identity(); + + cc._drawingUtil.drawSolidRect(cc.p(-1, -1), cc.p(1, 1), cc.color(255, 255, 255, 255)); + + //cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + //cc.kmGLPopMatrix(); + projStack.pop(); + + //cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + //cc.kmGLPopMatrix(); + modelViewStack.pop(); + }; + + proto._onBeforeVisit = function(ctx){ + var gl = ctx || cc._renderContext, node = this._node; + cc.ClippingNode.WebGLRenderCmd._layer++; + + // mask of the current layer (ie: for layer 3: 00000100) + var mask_layer = 0x1 << cc.ClippingNode.WebGLRenderCmd._layer; + // mask of all layers less than the current (ie: for layer 3: 00000011) + var mask_layer_l = mask_layer - 1; + // mask of all layers less than or equal to the current (ie: for layer 3: 00000111) + //var mask_layer_le = mask_layer | mask_layer_l; + this._mask_layer_le = mask_layer | mask_layer_l; + // manually save the stencil state + this._currentStencilEnabled = gl.isEnabled(gl.STENCIL_TEST); + this._currentStencilWriteMask = gl.getParameter(gl.STENCIL_WRITEMASK); + this._currentStencilFunc = gl.getParameter(gl.STENCIL_FUNC); + this._currentStencilRef = gl.getParameter(gl.STENCIL_REF); + this._currentStencilValueMask = gl.getParameter(gl.STENCIL_VALUE_MASK); + this._currentStencilFail = gl.getParameter(gl.STENCIL_FAIL); + this._currentStencilPassDepthFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL); + this._currentStencilPassDepthPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS); + + // enable stencil use + gl.enable(gl.STENCIL_TEST); + gl.stencilMask(mask_layer); + this._currentDepthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK); + + gl.depthMask(false); + + gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); + gl.stencilOp(!node.inverted ? gl.ZERO : gl.REPLACE, gl.KEEP, gl.KEEP); + + this._drawFullScreenQuadClearStencil(); + + gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); + gl.stencilOp(!node.inverted ? gl.REPLACE : gl.ZERO, gl.KEEP, gl.KEEP); + + if (node.alphaThreshold < 1) { //TODO desktop + var program = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLORALPHATEST); + var alphaValueLocation = gl.getUniformLocation(program.getProgram(), cc.UNIFORM_ALPHA_TEST_VALUE_S); + // set our alphaThreshold + cc.glUseProgram(program.getProgram()); + program.setUniformLocationWith1f(alphaValueLocation, node.alphaThreshold); + cc.setProgram(node._stencil, program); + } + }; + + proto._onAfterDrawStencil = function(ctx){ + var gl = ctx || cc._renderContext; + gl.depthMask(this._currentDepthWriteMask); + + gl.stencilFunc(gl.EQUAL, this._mask_layer_le, this._mask_layer_le); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + }; + + proto._onAfterVisit = function(ctx){ + var gl = ctx || cc._renderContext; + + gl.stencilFunc(this._currentStencilFunc, this._currentStencilRef, this._currentStencilValueMask); + gl.stencilOp(this._currentStencilFail, this._currentStencilPassDepthFail, this._currentStencilPassDepthPass); + gl.stencilMask(this._currentStencilWriteMask); + if (!this._currentStencilEnabled) + gl.disable(gl.STENCIL_TEST); + + // we are done using this layer, decrement + cc.ClippingNode.WebGLRenderCmd._layer--; + } +})(); diff --git a/cocos2d/compression/base64.js b/cocos2d/compression/base64.js index dbbf5b9f70..adb0d68871 100644 --- a/cocos2d/compression/base64.js +++ b/cocos2d/compression/base64.js @@ -42,10 +42,10 @@ cc.Codec.Base64.decode = function Jacob__Codec__Base64__decode(input) { output.push(String.fromCharCode(chr1)); - if (enc3 != 64) { + if (enc3 !== 64) { output.push(String.fromCharCode(chr2)); } - if (enc4 != 64) { + if (enc4 !== 64) { output.push(String.fromCharCode(chr3)); } } @@ -82,7 +82,7 @@ cc.Codec.Base64.decodeAsArray = function Jacob__Codec__Base64___decodeAsArray(in }; cc.uint8ArrayToUint32Array = function(uint8Arr){ - if(uint8Arr.length % 4 != 0) + if(uint8Arr.length % 4 !== 0) return null; var arrLen = uint8Arr.length /4; diff --git a/cocos2d/compression/gzip.js b/cocos2d/compression/gzip.js index 65c7d79eda..baed633cef 100644 --- a/cocos2d/compression/gzip.js +++ b/cocos2d/compression/gzip.js @@ -157,7 +157,7 @@ cc.Codec.GZip.prototype.readBit = function () { this.bits++; carry = (this.bb & 1); this.bb >>= 1; - if (this.bb == 0) { + if (this.bb === 0) { this.bb = this.readByte(); carry = (this.bb & 1); this.bb = (this.bb >> 1) | 0x80; @@ -182,13 +182,13 @@ cc.Codec.GZip.prototype.flushBuffer = function () { cc.Codec.GZip.prototype.addBuffer = function (a) { this.buf32k[this.bIdx++] = a; this.outputArr.push(String.fromCharCode(a)); - if (this.bIdx == 0x8000) this.bIdx = 0; + if (this.bIdx === 0x8000) this.bIdx = 0; }; cc.Codec.GZip.prototype.IsPat = function () { while (1) { if (this.fpos[this.len] >= this.fmax) return -1; - if (this.flens[this.fpos[this.len]] == this.len) return this.fpos[this.len]++; + if (this.flens[this.fpos[this.len]] === this.len) return this.fpos[this.len]++; this.fpos[this.len]++; } }; @@ -197,7 +197,7 @@ cc.Codec.GZip.prototype.Rec = function () { var curplace = this.Places[this.treepos]; var tmp; //if (this.debug) document.write("
len:"+this.len+" treepos:"+this.treepos); - if (this.len == 17) { //war 17 + if (this.len === 17) { //war 17 return -1; } this.treepos++; @@ -304,7 +304,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { last = this.readBit(); type = this.readBits(2); - if (type == 0) { + if (type === 0) { var blockLen, cSum; // Stored @@ -322,7 +322,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { c = this.readByte(); this.addBuffer(c); } - } else if (type == 1) { + } else if (type === 1) { var j; /* Fixed Huffman tables -- fixed decode routine */ @@ -368,7 +368,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { } if (j < 256) { this.addBuffer(j); - } else if (j == 256) { + } else if (j === 256) { /* EOF */ break; // FIXME: make this the loop-condition } else { @@ -394,7 +394,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { } } // while - } else if (type == 2) { + } else if (type === 2) { var j, n, literalCodes, distCodes, lenCodes; var ll = new Array(288 + 32); // "static" just to preserve stack @@ -436,7 +436,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { // if (this.debug) document.write("
"+z+" i:"+i+" decode: "+j+" bits "+this.bits+"
"); if (j < 16) { // length of code in bits (0..15) ll[i++] = j; - } else if (j == 16) { // repeat last length 3 to 6 times + } else if (j === 16) { // repeat last length 3 to 6 times var l; j = 3 + this.readBits(2); if (i + j > n) { @@ -448,7 +448,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { ll[i++] = l; } } else { - if (j == 17) { // 3 to 10 zero length codes + if (j === 17) { // 3 to 10 zero length codes j = 3 + this.readBits(3); } else { // j == 18: 11 to 138 zero length codes j = 11 + this.readBits(7); @@ -485,7 +485,7 @@ cc.Codec.GZip.prototype.DeflateLoop = function () { if (j >= 256) { // In C64: if carry set var len, dist; j -= 256; - if (j == 0) { + if (j === 0) { // EOF break; } @@ -520,7 +520,7 @@ cc.Codec.GZip.prototype.unzipFile = function (name) { var i; this.gunzip(); for (i = 0; i < this.unzipped.length; i++) { - if (this.unzipped[i][1] == name) { + if (this.unzipped[i][1] === name) { return this.unzipped[i][0]; } } @@ -537,25 +537,25 @@ cc.Codec.GZip.prototype.nextFile = function () { tmp[1] = this.readByte(); // if (this.debug) alert("type: "+tmp[0]+" "+tmp[1]); - if (tmp[0] == 0x78 && tmp[1] == 0xda) { //GZIP + if (tmp[0] === 0x78 && tmp[1] === 0xda) { //GZIP // if (this.debug) alert("GEONExT-GZIP"); this.DeflateLoop(); // if (this.debug) alert(this.outputArr.join('')); this.unzipped[this.files] = [this.outputArr.join(''), "geonext.gxt"]; this.files++; } - if (tmp[0] == 0x1f && tmp[1] == 0x8b) { //GZIP + if (tmp[0] === 0x1f && tmp[1] === 0x8b) { //GZIP // if (this.debug) alert("GZIP"); this.skipdir(); // if (this.debug) alert(this.outputArr.join('')); this.unzipped[this.files] = [this.outputArr.join(''), "file"]; this.files++; } - if (tmp[0] == 0x50 && tmp[1] == 0x4b) { //ZIP + if (tmp[0] === 0x50 && tmp[1] === 0x4b) { //ZIP this.modeZIP = true; tmp[2] = this.readByte(); tmp[3] = this.readByte(); - if (tmp[2] == 0x03 && tmp[3] == 0x04) { + if (tmp[2] === 0x03 && tmp[3] === 0x04) { //MODE_ZIP tmp[0] = this.readByte(); tmp[1] = this.readByte(); @@ -602,7 +602,7 @@ cc.Codec.GZip.prototype.nextFile = function () { this.nameBuf = []; while (filelen--) { var c = this.readByte(); - if (c == "/" | c == ":") { + if (c === "/" | c === ":") { i = 0; } else if (i < cc.Codec.GZip.NAMEMAX - 1) { this.nameBuf[i++] = String.fromCharCode(c); @@ -622,7 +622,7 @@ cc.Codec.GZip.prototype.nextFile = function () { // //skipdir // // if (this.debug) alert("skipdir"); // } - if (method == 8) { + if (method === 8) { this.DeflateLoop(); // if (this.debug) alert(this.outputArr.join('')); this.unzipped[this.files] = [this.outputArr.join(''), this.nameBuf.join('')]; @@ -666,7 +666,7 @@ cc.Codec.GZip.prototype.skipdir = function () { if (this.modeZIP) this.nextFile(); tmp[0] = this.readByte(); - if (tmp[0] != 8) { + if (tmp[0] !== 8) { // if (this.debug) alert("Unknown compression method!"); return 0; } @@ -695,7 +695,7 @@ cc.Codec.GZip.prototype.skipdir = function () { i = 0; this.nameBuf = []; while (c = this.readByte()) { - if (c == "7" || c == ":") + if (c === "7" || c === ":") i = 0; if (i < cc.Codec.GZip.NAMEMAX - 1) this.nameBuf[i++] = c; diff --git a/cocos2d/core/CCActionManager.js b/cocos2d/core/CCActionManager.js index d2351263a7..ac061e3f5a 100644 --- a/cocos2d/core/CCActionManager.js +++ b/cocos2d/core/CCActionManager.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,6 +27,8 @@ /** * @class * @extends cc.Class + * @example + * var element = new cc.HashElement(); */ cc.HashElement = cc.Class.extend(/** @lends cc.HashElement# */{ actions:null, @@ -51,17 +53,19 @@ cc.HashElement = cc.Class.extend(/** @lends cc.HashElement# */{ }); /** - * cc.ActionManager is a singleton that manages all the actions.
- * Normally you won't need to use this singleton directly. 99% of the cases you will use the CCNode interface, - * which uses this singleton. - * But there are some cases where you might need to use this singleton.
+ * cc.ActionManager is a class that can manage actions.
+ * Normally you won't need to use this class directly. 99% of the cases you will use the CCNode interface, + * which uses this class's singleton object. + * But there are some cases where you might need to use this class.
* Examples:
* - When you want to run an action where the target is different from a CCNode.
* - When you want to pause / resume the actions
* @class * @extends cc.Class + * @example + * var mng = new cc.ActionManager(); */ -cc.ActionManager = cc.Class.extend({ +cc.ActionManager = cc.Class.extend(/** @lends cc.ActionManager# */{ _hashTargets:null, _arrayTargets:null, _currentTarget:null, @@ -69,15 +73,12 @@ cc.ActionManager = cc.Class.extend({ _searchElementByTarget:function (arr, target) { for (var k = 0; k < arr.length; k++) { - if (target == arr[k].target) + if (target === arr[k].target) return arr[k]; } return null; }, - /** - * Constructor - */ ctor:function () { this._hashTargets = {}; this._arrayTargets = []; @@ -142,7 +143,7 @@ cc.ActionManager = cc.Class.extend({ element.currentActionSalvaged = true; element.actions.length = 0; - if (this._currentTarget == element && !forceDelete) { + if (this._currentTarget === element && !forceDelete) { this._currentTargetSalvaged = true; } else { this._deleteHashElement(element); @@ -161,7 +162,7 @@ cc.ActionManager = cc.Class.extend({ if (element) { for (var i = 0; i < element.actions.length; i++) { - if (element.actions[i] == action) { + if (element.actions[i] === action) { element.actions.splice(i, 1); break; } @@ -176,7 +177,7 @@ cc.ActionManager = cc.Class.extend({ * @param {object} target */ removeActionByTag:function (tag, target) { - if(tag == cc.ACTION_TAG_INVALID) + if(tag === cc.ACTION_TAG_INVALID) cc.log(cc._LogInfos.ActionManager_addAction); cc.assert(target, cc._LogInfos.ActionManager_addAction); @@ -187,7 +188,7 @@ cc.ActionManager = cc.Class.extend({ var limit = element.actions.length; for (var i = 0; i < limit; ++i) { var action = element.actions[i]; - if (action && action.getTag() === tag && action.getOriginalTarget() == target) { + if (action && action.getTag() === tag && action.getOriginalTarget() === target) { this._removeActionAtIndex(i, element); break; } @@ -201,7 +202,7 @@ cc.ActionManager = cc.Class.extend({ * @return {cc.Action|Null} return the Action with the given tag on success */ getActionByTag:function (tag, target) { - if(tag == cc.ACTION_TAG_INVALID) + if(tag === cc.ACTION_TAG_INVALID) cc.log(cc._LogInfos.ActionManager_getActionByTag); var element = this._hashTargets[target.__instanceId]; @@ -286,14 +287,14 @@ cc.ActionManager = cc.Class.extend({ * because it uses this, so it can not be static */ purgeSharedManager:function () { - cc.director.getScheduler().unscheduleUpdateForTarget(this); + cc.director.getScheduler().unscheduleUpdate(this); }, //protected _removeActionAtIndex:function (index, element) { var action = element.actions[index]; - if ((action == element.currentAction) && (!element.currentActionSalvaged)) + if ((action === element.currentAction) && (!element.currentActionSalvaged)) element.currentActionSalvaged = true; element.actions.splice(index, 1); @@ -302,8 +303,8 @@ cc.ActionManager = cc.Class.extend({ if (element.actionIndex >= index) element.actionIndex--; - if (element.actions.length == 0) { - if (this._currentTarget == element) { + if (element.actions.length === 0) { + if (this._currentTarget === element) { this._currentTargetSalvaged = true; } else { this._deleteHashElement(element); @@ -338,14 +339,16 @@ cc.ActionManager = cc.Class.extend({ //this._currentTargetSalvaged = false; if (!locCurrTarget.paused) { // The 'actions' CCMutableArray may change while inside this loop. - for (locCurrTarget.actionIndex = 0; locCurrTarget.actionIndex < locCurrTarget.actions.length; + for (locCurrTarget.actionIndex = 0; + locCurrTarget.actionIndex < (locCurrTarget.actions ? locCurrTarget.actions.length : 0); locCurrTarget.actionIndex++) { locCurrTarget.currentAction = locCurrTarget.actions[locCurrTarget.actionIndex]; if (!locCurrTarget.currentAction) continue; locCurrTarget.currentActionSalvaged = false; - locCurrTarget.currentAction.step(dt); + //use for speed + locCurrTarget.currentAction.step(dt * ( locCurrTarget.currentAction._speedMethod ? locCurrTarget.currentAction._speed : 1 ) ); if (locCurrTarget.currentActionSalvaged) { // The currentAction told the node to remove it. To prevent the action from // accidentally deallocating itself before finishing its step, we retained diff --git a/cocos2d/core/CCCamera.js b/cocos2d/core/CCCamera.js index ac01fd8e6f..ea6c6db8c7 100644 --- a/cocos2d/core/CCCamera.js +++ b/cocos2d/core/CCCamera.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -42,10 +42,8 @@ *
* - It is recommended to use it ONLY if you are going to create 3D effects. For 2D effecs, use the action CCFollow or position/scale/rotate. * *

- * @class - * @extends cc.Class */ -cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ +cc.Camera = cc.Class.extend({ _eyeX:null, _eyeY:null, _eyeZ:null, @@ -58,11 +56,13 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ _upY:null, _upZ:null, - _dirty:null, + _dirty:false, _lookupMatrix:null, - + /** + * constructor of cc.Camera + */ ctor:function () { - this._lookupMatrix = new cc.kmMat4(); + this._lookupMatrix = new cc.math.Matrix4(); this.restore(); }, @@ -103,7 +103,7 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ this._upY = 1.0; this._upZ = 0.0; - cc.kmMat4Identity( this._lookupMatrix ); + this._lookupMatrix.identity(); this._dirty = false; }, @@ -113,25 +113,32 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ */ locate:function () { if (this._dirty) { - var eye = new cc.kmVec3(), center = new cc.kmVec3(), up = new cc.kmVec3(); - - cc.kmVec3Fill( eye, this._eyeX, this._eyeY , this._eyeZ ); - cc.kmVec3Fill( center, this._centerX, this._centerY, this._centerZ); - - cc.kmVec3Fill( up, this._upX, this._upY, this._upZ); - cc.kmMat4LookAt( this._lookupMatrix, eye, center, up); - + var eye = new cc.math.Vec3(this._eyeX, this._eyeY , this._eyeZ), + center = new cc.math.Vec3(this._centerX, this._centerY, this._centerZ), + up = new cc.math.Vec3(this._upX, this._upY, this._upZ); + this._lookupMatrix.lookAt(eye, center, up); this._dirty = false; } cc.kmGLMultMatrix( this._lookupMatrix); }, + _locateForRenderer: function(matrix){ + if (this._dirty) { + var eye = new cc.math.Vec3(this._eyeX, this._eyeY , this._eyeZ), + center = new cc.math.Vec3(this._centerX, this._centerY, this._centerZ), + up = new cc.math.Vec3(this._upX, this._upY, this._upZ); + this._lookupMatrix.lookAt(eye, center, up); + this._dirty = false; + } + matrix.multiply(this._lookupMatrix); + }, + /** * sets the eye values in points * @param {Number} eyeX * @param {Number} eyeY * @param {Number} eyeZ - * @deprecated This function will be deprecated sooner or later. + * @deprecated This function will be deprecated sooner or later please use setEye instead. */ setEyeXYZ:function (eyeX, eyeY, eyeZ) { this.setEye(eyeX,eyeY,eyeZ); @@ -156,7 +163,7 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ * @param {Number} centerX * @param {Number} centerY * @param {Number} centerZ - * @deprecated This function will be deprecated sooner or later. + * @deprecated This function will be deprecated sooner or later please use setCenter instead. */ setCenterXYZ:function (centerX, centerY, centerZ) { this.setCenter(centerX,centerY,centerZ); @@ -207,7 +214,7 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ * @param {Number} eyeY * @param {Number} eyeZ * @return {Object} - * @deprecated This function will be deprecated sooner or later. + * @deprecated This function will be deprecated sooner or later, please use getEye instead. */ getEyeXYZ:function (eyeX, eyeY, eyeZ) { return {x:this._eyeX , y:this._eyeY , z: this._eyeZ }; @@ -227,7 +234,7 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ * @param {Number} centerY * @param {Number} centerZ * @return {Object} - * @deprecated This function will be deprecated sooner or later. + * @deprecated This function will be deprecated sooner or later,please use getCenter instead. */ getCenterXYZ:function (centerX, centerY, centerZ) { return {x:this._centerX ,y:this._centerY ,z:this._centerZ }; @@ -247,7 +254,7 @@ cc.Camera = cc.Class.extend(/** @lends cc.Action# */{ * @param {Number} upY * @param {Number} upZ * @return {Object} - * @deprecated This function will be deprecated sooner or later. + * @deprecated This function will be deprecated sooner or later,please use getUp instead. */ getUpXYZ:function (upX, upY, upZ) { return {x:this._upX,y:this._upY,z:this._upZ}; diff --git a/cocos2d/core/CCConfiguration.js b/cocos2d/core/CCConfiguration.js index 7efd9fac60..e2be6b7ba8 100644 --- a/cocos2d/core/CCConfiguration.js +++ b/cocos2d/core/CCConfiguration.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,7 +25,11 @@ ****************************************************************************/ /** - * @namespace cc.configuration contains some openGL variables + * cc.configuration is a singleton object which contains some openGL variables + * @class + * @name cc.configuration + * @example + * var textureSize = cc.configuration.getMaxTextureSize(); */ cc.configuration = /** @lends cc.configuration# */{ // Type constants diff --git a/cocos2d/core/CCDirector.js b/cocos2d/core/CCDirector.js index 4581a54a5b..cd84958624 100644 --- a/cocos2d/core/CCDirector.js +++ b/cocos2d/core/CCDirector.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,32 +27,34 @@ cc.g_NumberOfDraws = 0; cc.GLToClipTransform = function (transformOut) { - var projection = new cc.kmMat4(); - cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, projection); + //var projection = new cc.math.Matrix4(); + //cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, projection); + cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, transformOut); - var modelview = new cc.kmMat4(); + var modelview = new cc.math.Matrix4(); cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, modelview); - cc.kmMat4Multiply(transformOut, projection, modelview); + transformOut.multiply(modelview); }; //---------------------------------------------------------------------------------------------------------------------- /** - * @namespace

- * cc.director is a singleton of DisplayLinkDirector type director.
+ *

+ * ATTENTION: USE cc.director INSTEAD OF cc.Director.
+ * cc.director is a singleton object which manage your game's logic flow.
* Since the cc.director is a singleton, you don't need to call any constructor or create functions,
* the standard way to use it is by calling:
* - cc.director.methodName();
* * It creates and handle the main Window and manages how and when to execute the Scenes.
*
- * The cc.Director is also responsible for:
+ * The cc.director is also responsible for:
* - initializing the OpenGL context
* - setting the OpenGL pixel format (default on is RGB565)
* - setting the OpenGL pixel format (default on is RGB565)
* - setting the OpenGL buffer depth (default one is 0-bit)
* - setting the projection (default one is 3D)
- * - setting the orientation (default one is Protrait)
+ * - setting the orientation (default one is Portrait)
*
*
* The cc.director also sets the default OpenGL context:
@@ -62,70 +64,67 @@ cc.GLToClipTransform = function (transformOut) { * - GL_TEXTURE_COORD_ARRAY is enabled
*

*

- * With DisplayLinkDirector functionality, cc.director synchronizes timers with the refresh rate of the display.
+ * cc.director also synchronizes timers with the refresh rate of the display.
* Features and Limitations:
* - Scheduled timers & drawing are synchronizes with the refresh rate of the display
* - Only supports animation intervals of 1/60 1/30 & 1/15
*

- * @name cc.director + * @class + * @name cc.Director */ -cc.Director = cc.Class.extend(/** @lends cc.director# */{ +cc.Director = cc.Class.extend(/** @lends cc.Director# */{ //Variables - _landscape:false, - _nextDeltaTimeZero:false, - _paused:false, - _purgeDirectorInNextLoop:false, - _sendCleanupToScene:false, - _animationInterval:0.0, - _oldAnimationInterval:0.0, - _projection:0, - _accumDt:0.0, - _contentScaleFactor:1.0, - - _displayStats:false, - _deltaTime:0.0, - _frameRate:0.0, - - _FPSLabel:null, - _SPFLabel:null, - _drawsLabel:null, - - _winSizeInPoints:null, - - _lastUpdate:null, - _nextScene:null, - _notificationNode:null, - _openGLView:null, - _scenesStack:null, - _projectionDelegate:null, - _runningScene:null, - - _frames:0, - _totalFrames:0, - _secondsPerFrame:0, - - _dirtyRegion:null, - - _scheduler:null, - _actionManager:null, + _landscape: false, + _nextDeltaTimeZero: false, + _paused: false, + _purgeDirectorInNextLoop: false, + _sendCleanupToScene: false, + _animationInterval: 0.0, + _oldAnimationInterval: 0.0, + _projection: 0, + _accumDt: 0.0, + _contentScaleFactor: 1.0, + + _displayStats: false, + _deltaTime: 0.0, + _frameRate: 0.0, + + _FPSLabel: null, + _SPFLabel: null, + _drawsLabel: null, + + _winSizeInPoints: null, + + _lastUpdate: null, + _nextScene: null, + _notificationNode: null, + _openGLView: null, + _scenesStack: null, + _projectionDelegate: null, + _runningScene: null, + + _frames: 0, + _totalFrames: 0, + _secondsPerFrame: 0, + + _dirtyRegion: null, + + _scheduler: null, + _actionManager: null, _eventProjectionChanged: null, _eventAfterDraw: null, _eventAfterVisit: null, _eventAfterUpdate: null, - ctor:function () { + ctor: function () { var self = this; self._lastUpdate = Date.now(); - cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function(){ + cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { self._lastUpdate = Date.now(); }); }, - /** - * initializes cc.director - * @return {Boolean} - */ - init:function () { + init: function () { // scenes this._oldAnimationInterval = this._animationInterval = 1.0 / cc.defaultFPS; this._scenesStack = []; @@ -155,8 +154,12 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ //scheduler this._scheduler = new cc.Scheduler(); //action manager - this._actionManager = cc.ActionManager ? new cc.ActionManager() : null; - this._scheduler.scheduleUpdateForTarget(this._actionManager, cc.Scheduler.PRIORITY_SYSTEM, false); + if(cc.ActionManager){ + this._actionManager = new cc.ActionManager(); + this._scheduler.scheduleUpdate(this._actionManager, cc.Scheduler.PRIORITY_SYSTEM, false); + }else{ + this._actionManager = null; + } this._eventAfterDraw = new cc.EventCustom(cc.Director.EVENT_AFTER_DRAW); this._eventAfterDraw.setUserData(this); @@ -173,7 +176,7 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ /** * calculates delta time since last time it was called */ - calculateDeltaTime:function () { + calculateDeltaTime: function () { var now = Date.now(); // new delta time. @@ -191,14 +194,30 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - * convertToGL move to CCDirectorWebGL - * convertToUI move to CCDirectorWebGL + * Converts a view coordinate to an WebGL coordinate
+ * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape)
+ * Implementation can be found in CCDirectorWebGL + * @function + * @param {cc.Point} uiPoint + * @return {cc.Point} + */ + convertToGL: null, + + /** + * Converts an WebGL coordinate to a view coordinate
+ * Useful to convert node points to window points for calls such as glScissor
+ * Implementation can be found in CCDirectorWebGL + * @function + * @param {cc.Point} glPoint + * @return {cc.Point} */ + convertToUI: null, /** * Draw the scene. This method is called every frame. Don't call it manually. */ - drawScene: function() { + drawScene: function () { + var renderer = cc.renderer; // calculate "global" dt this.calculateDeltaTime(); @@ -216,11 +235,19 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ this.setNextScene(); } - if (this._beforeVisitScene) this._beforeVisitScene(); + if (this._beforeVisitScene) + this._beforeVisitScene(); // draw the scene if (this._runningScene) { - this._runningScene.visit(); + if (renderer.childrenOrderDirty === true) { + cc.renderer.clearRenderCommands(); + this._runningScene._renderCmd._curLevel = 0; //level start from 0; + this._runningScene.visit(); + renderer.resetFlag(); + } else if (renderer.transformDirty() === true) + renderer.transform(); + cc.eventManager.dispatchEvent(this._eventAfterVisit); } @@ -231,9 +258,10 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ if (this._displayStats) this._showStats(); - if (this._afterVisitScene) this._afterVisitScene(); + if (this._afterVisitScene) + this._afterVisitScene(); - //TODO + renderer.rendering(cc._renderContext); cc.eventManager.dispatchEvent(this._eventAfterDraw); this._totalFrames++; @@ -245,55 +273,47 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ _afterVisitScene: null, /** - * end director + * End the life of director in the next frame */ - end:function () { + end: function () { this._purgeDirectorInNextLoop = true; }, /** - *

get the size in pixels of the surface. It could be different than the screen size.
- * High-res devices might have a higher surface size than the screen size.
- * Only available when compiled using SDK >= 4.0. - *

+ * Returns the size in pixels of the surface. It could be different than the screen size.
+ * High-res devices might have a higher surface size than the screen size. * @return {Number} */ - getContentScaleFactor:function () { + getContentScaleFactor: function () { return this._contentScaleFactor; }, /** - *

- * This object will be visited after the main scene is visited.
- * This object MUST implement the "visit" selector.
- * Useful to hook a notification object, like CCNotifications (http://github.com/manucorporat/CCNotifications) - *

+ * This object will be visited after the main scene is visited.
+ * This object MUST implement the "visit" selector.
+ * Useful to hook a notification object * @return {cc.Node} */ - getNotificationNode:function () { + getNotificationNode: function () { return this._notificationNode; }, /** - *

- * returns the size of the OpenGL view in points.
- * It takes into account any possible rotation (device orientation) of the window - *

+ * Returns the size of the WebGL view in points.
+ * It takes into account any possible rotation (device orientation) of the window * @return {cc.Size} */ - getWinSize:function () { - return this._winSizeInPoints; + getWinSize: function () { + return cc.size(this._winSizeInPoints); }, /** - *

- * returns the size of the OpenGL view in pixels.
- * It takes into account any possible rotation (device orientation) of the window.
- * On Mac winSize and winSizeInPixels return the same value. - *

+ * Returns the size of the OpenGL view in pixels.
+ * It takes into account any possible rotation (device orientation) of the window.
+ * On Mac winSize and winSizeInPixels return the same value. * @return {cc.Size} */ - getWinSizeInPixels:function () { + getWinSizeInPixels: function () { return cc.size(this._winSizeInPoints.width * this._contentScaleFactor, this._winSizeInPoints.height * this._contentScaleFactor); }, @@ -303,9 +323,30 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ */ /** - * pause director + * Returns the visible size of the running scene + * @function + * @return {cc.Size} + */ + getVisibleSize: null, + + /** + * Returns the visible origin of the running scene + * @function + * @return {cc.Point} + */ + getVisibleOrigin: null, + + /** + * Returns the z eye, only available in WebGL mode + * @function + * @return {Number} + */ + getZEye: null, + + /** + * Pause the director's ticker */ - pause:function () { + pause: function () { if (this._paused) return; @@ -316,21 +357,19 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - *

- * Pops out a scene from the queue.
- * This scene will replace the running one.
- * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.
- * ONLY call it if there is a running scene. - *

+ * Pops out a scene from the queue.
+ * This scene will replace the running one.
+ * The running scene will be deleted. If there are no more scenes in the stack the execution is terminated.
+ * ONLY call it if there is a running scene. */ - popScene:function () { + popScene: function () { cc.assert(this._runningScene, cc._LogInfos.Director_popScene); this._scenesStack.pop(); var c = this._scenesStack.length; - if (c == 0) + if (c === 0) this.end(); else { this._sendCleanupToScene = true; @@ -341,21 +380,21 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ /** * Removes cached all cocos2d cached data. It will purge the cc.textureCache, cc.spriteFrameCache, cc.animationCache */ - purgeCachedData:function () { - cc.animationCache._clear(); - cc.spriteFrameCache._clear(); - cc.textureCache._clear(); + purgeCachedData: function () { + cc.animationCache._clear(); + cc.spriteFrameCache._clear(); + cc.textureCache._clear(); }, /** - * purge Director + * Purge the cc.director itself, including unschedule all schedule, remove all event listeners, clean up and exit the running scene, stops all animations, clear cached data. */ - purgeDirector:function () { + purgeDirector: function () { //cleanup scheduler - this.getScheduler().unscheduleAllCallbacks(); + this.getScheduler().unscheduleAll(); // Disable event dispatching - if(cc.eventManager) + if (cc.eventManager) cc.eventManager.setEnabled(false); // don't release the event handlers @@ -383,15 +422,13 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - *

- * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.
- * The new scene will be executed.
- * Try to avoid big stacks of pushed scenes to reduce memory allocation.
- * ONLY call it if there is a running scene. - *

+ * Suspends the execution of the running scene, pushing it on the stack of suspended scenes.
+ * The new scene will be executed.
+ * Try to avoid big stacks of pushed scenes to reduce memory allocation.
+ * ONLY call it if there is a running scene. * @param {cc.Scene} scene */ - pushScene:function (scene) { + pushScene: function (scene) { cc.assert(scene, cc._LogInfos.Director_pushScene); @@ -402,21 +439,21 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - * Run a scene. Replaces the running scene with a new one when the scene is running. + * Run a scene. Replaces the running scene with a new one or enter the first scene. * @param {cc.Scene} scene */ - runScene:function(scene){ + runScene: function (scene) { cc.assert(scene, cc._LogInfos.Director_pushScene); - if(!this._runningScene){ + if (!this._runningScene) { //start scene this.pushScene(scene); this.startAnimation(); - }else{ + } else { //replace scene var i = this._scenesStack.length; - if(i === 0){ + if (i === 0) { this._sendCleanupToScene = true; this._scenesStack[i] = scene; this._nextScene = scene; @@ -429,9 +466,9 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - * resume director + * Resume director after pause, if the current scene is not paused, nothing will happen. */ - resume:function () { + resume: function () { if (!this._paused) { return; } @@ -447,48 +484,46 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - *

- * The size in pixels of the surface. It could be different than the screen size.
- * High-res devices might have a higher surface size than the screen size.
- * Only available when compiled using SDK >= 4.0. - *

+ * The size in pixels of the surface. It could be different than the screen size.
+ * High-res devices might have a higher surface size than the screen size. * @param {Number} scaleFactor */ - setContentScaleFactor:function (scaleFactor) { - if (scaleFactor != this._contentScaleFactor) { + setContentScaleFactor: function (scaleFactor) { + if (scaleFactor !== this._contentScaleFactor) { this._contentScaleFactor = scaleFactor; this._createStatsLabel(); } }, /** - * enables/disables OpenGL depth test + * Enables or disables WebGL depth test.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js + * @function * @param {Boolean} on - * - * setDepthTest move to CCDirectorCanvas/CCDirectorWebGL */ + setDepthTest: null, /** - * sets the default values based on the CCConfiguration info + * Sets the default values based on the CCConfiguration info */ - setDefaultValues:function(){ + setDefaultValues: function () { }, /** - * set next delta time is zero + * Sets whether next delta time equals to zero * @param {Boolean} nextDeltaTimeZero */ - setNextDeltaTimeZero:function (nextDeltaTimeZero) { + setNextDeltaTimeZero: function (nextDeltaTimeZero) { this._nextDeltaTimeZero = nextDeltaTimeZero; }, /** - * set next scene + * Starts the registered next scene */ - setNextScene:function () { + setNextScene: function () { var runningIsTransition = false, newIsTransition = false; - if(cc.TransitionScene){ + if (cc.TransitionScene) { runningIsTransition = this._runningScene ? this._runningScene instanceof cc.TransitionScene : false; newIsTransition = this._nextScene ? this._nextScene instanceof cc.TransitionScene : false; } @@ -508,52 +543,86 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ } this._runningScene = this._nextScene; + cc.renderer.childrenOrderDirty = true; this._nextScene = null; - if ((!runningIsTransition) && (this._runningScene != null)) { + if ((!runningIsTransition) && (this._runningScene !== null)) { this._runningScene.onEnter(); this._runningScene.onEnterTransitionDidFinish(); } }, /** - * set Notification Node + * Sets Notification Node * @param {cc.Node} node */ - setNotificationNode:function (node) { + setNotificationNode: function (node) { this._notificationNode = node; }, /** - * CCDirector delegate. It shall implemente the CCDirectorDelegate protocol - * @return {cc.DirectorDelegate} + * Returns the cc.director delegate. + * @return {cc.DirectorDelegate} */ - getDelegate:function () { + getDelegate: function () { return this._projectionDelegate; }, - setDelegate:function (delegate) { + /** + * Sets the cc.director delegate. It shall implement the CCDirectorDelegate protocol + * @return {cc.DirectorDelegate} + */ + setDelegate: function (delegate) { this._projectionDelegate = delegate; }, /** - * Set the CCEGLView, where everything is rendered - * @param {*} openGLView - * - * setOpenGLView move to CCDirectorCanvas/CCDirectorWebGL - * setViewport move to CCDirectorWebGL + * Sets the view, where everything is rendered, do not call this function.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function + * @param {cc.view} openGLView */ + setOpenGLView: null, /** - * Sets an OpenGL projection + * Sets an OpenGL projection.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function * @param {Number} projection - * - * setProjection move to CCDiretorCanvas/CCDiretorWebGL */ + setProjection: null, + + /** + * Update the view port.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function + */ + setViewport: null, /** - * shows the FPS in the screen + * Get the CCEGLView, where everything is rendered.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function + * @return {cc.view} + */ + getOpenGLView: null, + + /** + * Sets an OpenGL projection.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function + * @return {Number} */ + getProjection: null, + + /** + * Enables/disables OpenGL alpha blending.
+ * Implementation can be found in CCDirectorCanvas.js/CCDirectorWebGL.js. + * @function + * @param {Boolean} on + */ + setAlphaBlending: null, + _showStats: function () { this._frames++; this._accumDt += this._deltaTime; @@ -577,109 +646,102 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - *

- * Whether or not the replaced scene will receive the cleanup message.
- * If the new scene is pushed, then the old scene won't receive the "cleanup" message.
- * If the new scene replaces the old one, the it will receive the "cleanup" message. - *

+ * Returns whether or not the replaced scene will receive the cleanup message.
+ * If the new scene is pushed, then the old scene won't receive the "cleanup" message.
+ * If the new scene replaces the old one, the it will receive the "cleanup" message. * @return {Boolean} */ - isSendCleanupToScene:function () { + isSendCleanupToScene: function () { return this._sendCleanupToScene; }, /** - * Get current running Scene. Director can only run one Scene at the time + * Returns current running Scene. Director can only run one Scene at the time * @return {cc.Scene} */ - getRunningScene:function () { + getRunningScene: function () { return this._runningScene; }, /** - * Get the FPS value + * Returns the FPS value * @return {Number} */ - getAnimationInterval:function () { + getAnimationInterval: function () { return this._animationInterval; }, /** - * Whether or not to display the FPS on the bottom-left corner + * Returns whether or not to display the FPS informations * @return {Boolean} */ - isDisplayStats:function () { + isDisplayStats: function () { return this._displayStats; }, /** - * Display the FPS on the bottom-left corner + * Sets whether display the FPS on the bottom-left corner * @param {Boolean} displayStats */ - setDisplayStats:function (displayStats) { + setDisplayStats: function (displayStats) { this._displayStats = displayStats; }, /** - * seconds per frame + * Returns seconds per frame * @return {Number} */ - getSecondsPerFrame:function () { + getSecondsPerFrame: function () { return this._secondsPerFrame; }, /** - * is next delta time zero + * Returns whether next delta time equals to zero * @return {Boolean} */ - isNextDeltaTimeZero:function () { + isNextDeltaTimeZero: function () { return this._nextDeltaTimeZero; }, /** - * Whether or not the Director is paused + * Returns whether or not the Director is paused * @return {Boolean} */ - isPaused:function () { + isPaused: function () { return this._paused; }, /** - * How many frames were called since the director started + * Returns how many frames were called since the director started * @return {Number} */ - getTotalFrames:function () { + getTotalFrames: function () { return this._totalFrames; }, /** - *

- * Pops out all scenes from the queue until the root scene in the queue.
- * This scene will replace the running one.
- * Internally it will call `popToSceneStackLevel(1)` - *

+ * Pops out all scenes from the queue until the root scene in the queue.
+ * This scene will replace the running one.
+ * Internally it will call "popToSceneStackLevel(1)" */ - popToRootScene:function () { + popToRootScene: function () { this.popToSceneStackLevel(1); }, /** - *

- * Pops out all scenes from the queue until it reaches `level`.
- * If level is 0, it will end the director.
- * If level is 1, it will pop all scenes until it reaches to root scene.
- * If level is <= than the current stack level, it won't do anything. - *

+ * Pops out all scenes from the queue until it reaches "level".
+ * If level is 0, it will end the director.
+ * If level is 1, it will pop all scenes until it reaches to root scene.
+ * If level is <= than the current stack level, it won't do anything. * @param {Number} level */ popToSceneStackLevel: function (level) { - cc.assert(this._runningScene, cc._LogInfos.Director_popToSceneStackLevel_2); var locScenesStack = this._scenesStack; var c = locScenesStack.length; - if (c == 0) { + if (c === 0) { this.end(); return; } @@ -702,28 +764,45 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ }, /** - * (cc.Scheduler associated with this director) + * Returns the cc.Scheduler associated with this director + * @return {cc.Scheduler} */ - getScheduler:function () { + getScheduler: function () { return this._scheduler; }, - setScheduler:function (scheduler) { - if (this._scheduler != scheduler) { + /** + * Sets the cc.Scheduler associated with this director + * @param {cc.Scheduler} scheduler + */ + setScheduler: function (scheduler) { + if (this._scheduler !== scheduler) { this._scheduler = scheduler; } }, - getActionManager:function () { + /** + * Returns the cc.ActionManager associated with this director + * @return {cc.ActionManager} + */ + getActionManager: function () { return this._actionManager; }, - setActionManager:function (actionManager) { - if (this._actionManager != actionManager) { + /** + * Sets the cc.ActionManager associated with this director + * @param {cc.ActionManager} actionManager + */ + setActionManager: function (actionManager) { + if (this._actionManager !== actionManager) { this._actionManager = actionManager; } }, - getDeltaTime:function(){ + /** + * Returns the delta time since last frame + * @return {Number} + */ + getDeltaTime: function () { return this._deltaTime; }, @@ -735,29 +814,68 @@ cc.Director = cc.Class.extend(/** @lends cc.director# */{ } }); +/** + * The event projection changed of cc.Director + * @constant + * @type {string} + * @example + * cc.eventManager.addCustomListener(cc.Director.EVENT_PROJECTION_CHANGED, function(event) { + * cc.log("Projection changed."); + * }); + */ cc.Director.EVENT_PROJECTION_CHANGED = "director_projection_changed"; + +/** + * The event after draw of cc.Director + * @constant + * @type {string} + * @example + * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_DRAW, function(event) { + * cc.log("after draw event."); + * }); + */ cc.Director.EVENT_AFTER_DRAW = "director_after_draw"; + +/** + * The event after visit of cc.Director + * @constant + * @type {string} + * @example + * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_VISIT, function(event) { + * cc.log("after visit event."); + * }); + */ cc.Director.EVENT_AFTER_VISIT = "director_after_visit"; + +/** + * The event after update of cc.Director + * @constant + * @type {string} + * @example + * cc.eventManager.addCustomListener(cc.Director.EVENT_AFTER_UPDATE, function(event) { + * cc.log("after update event."); + * }); + */ cc.Director.EVENT_AFTER_UPDATE = "director_after_update"; /*************************************************** * implementation of DisplayLinkDirector **************************************************/ -cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.director# */{ - invalid:false, +cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.Director# */{ + invalid: false, /** - * start Animation + * Starts Animation */ - startAnimation:function () { + startAnimation: function () { this._nextDeltaTimeZero = true; this.invalid = false; }, /** - * main loop of director + * Run main loop of director */ - mainLoop:function () { + mainLoop: function () { if (this._purgeDirectorInNextLoop) { this._purgeDirectorInNextLoop = false; this.purgeDirector(); @@ -768,17 +886,17 @@ cc.DisplayLinkDirector = cc.Director.extend(/** @lends cc.director# */{ }, /** - * stop animation + * Stops animation */ - stopAnimation:function () { + stopAnimation: function () { this.invalid = true; }, /** - * set Animation Interval - * @param {Number} value + * Sets animation interval + * @param {Number} value the animation interval desired */ - setAnimationInterval:function (value) { + setAnimationInterval: function (value) { this._animationInterval = value; if (!this.invalid) { this.stopAnimation(); @@ -800,37 +918,37 @@ cc.Director._getInstance = function () { }; /** - * set default fps to 60 - * @type Number + * Default fps is 60 + * @type {Number} */ cc.defaultFPS = 60; //Possible OpenGL projections used by director /** - * sets a 2D projection (orthogonal projection) + * Constant for 2D projection (orthogonal projection) * @constant - * @type Number + * @type {Number} */ cc.Director.PROJECTION_2D = 0; /** - * sets a 3D projection with a fovy=60, znear=0.5f and zfar=1500. + * Constant for 3D projection with a fovy=60, znear=0.5f and zfar=1500. * @constant - * @type Number + * @type {Number} */ cc.Director.PROJECTION_3D = 1; /** - * it calls "updateProjection" on the projection delegate. + * Constant for custom projection, if cc.Director's projection set to it, it calls "updateProjection" on the projection delegate. * @constant - * @type Number + * @type {Number} */ cc.Director.PROJECTION_CUSTOM = 3; /** - * Default projection is 3D projection + * Constant for default projection of cc.Director, default projection is 3D projection * @constant - * @type Number + * @type {Number} */ cc.Director.PROJECTION_DEFAULT = cc.Director.PROJECTION_3D; @@ -851,17 +969,18 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { this._winSizeInPoints.width = cc._canvas.width; //this._openGLView.getDesignResolutionSize(); this._winSizeInPoints.height = cc._canvas.height; this._openGLView = openGLView || cc.view; - if(cc.eventManager) + if (cc.eventManager) cc.eventManager.setEnabled(true); }; - _p._clear = function() { + _p._clear = function () { var viewport = this._openGLView.getViewPortRect(); - cc._renderContext.clearRect(-viewport.x, viewport.y, viewport.width, -viewport.height); + var context = cc._renderContext.getContext(); + context.setTransform(1,0,0,1, 0, 0); + context.clearRect(-viewport.x, viewport.y, viewport.width, viewport.height); }; - - _p._createStatsLabel = function(){ + _p._createStatsLabel = function () { var _t = this; var fontSize = 0; if (_t._winSizeInPoints.width > _t._winSizeInPoints.height) @@ -869,9 +988,9 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { else fontSize = 0 | (_t._winSizeInPoints.width / 320 * 24); - _t._FPSLabel = cc.LabelTTF.create("000.0", "Arial", fontSize); - _t._SPFLabel = cc.LabelTTF.create("0.000", "Arial", fontSize); - _t._drawsLabel = cc.LabelTTF.create("0000", "Arial", fontSize); + _t._FPSLabel = new cc.LabelTTF("000.0", "Arial", fontSize); + _t._SPFLabel = new cc.LabelTTF("0.000", "Arial", fontSize); + _t._drawsLabel = new cc.LabelTTF("0000", "Arial", fontSize); var locStatsPosition = cc.DIRECTOR_STATS_POSITION; _t._drawsLabel.setPosition(_t._drawsLabel.width / 2 + locStatsPosition.x, _t._drawsLabel.height * 5 / 2 + locStatsPosition.y); @@ -891,15 +1010,15 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { //if (this._openGLView) { //return this._openGLView.getVisibleOrigin(); //} else { - return cc.p(0,0); + return cc.p(0, 0); //} }; -}else { +} else { cc.Director._fpsImage = new Image(); cc._addEventListener(cc.Director._fpsImage, "load", function () { cc.Director._fpsImageLoaded = true; }); - if(cc._fpsImage){ + if (cc._fpsImage) { cc.Director._fpsImage.src = cc._fpsImage; } } \ No newline at end of file diff --git a/cocos2d/core/CCDirectorWebGL.js b/cocos2d/core/CCDirectorWebGL.js index 5351a14ae5..bdd9d62fb6 100644 --- a/cocos2d/core/CCDirectorWebGL.js +++ b/cocos2d/core/CCDirectorWebGL.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,328 +24,297 @@ THE SOFTWARE. ****************************************************************************/ -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { +if (cc._renderType === cc._RENDER_TYPE_WEBGL) { + (function () { - /** - * OpenGL projection protocol - * @class - * @extends cc.Class - */ - cc.DirectorDelegate = cc.Class.extend(/** @lends cc.DirectorDelegate# */{ /** - * Called by CCDirector when the projection is updated, and "custom" projection is used - */ - updateProjection:function () { - } - }); - - var _p = cc.Director.prototype; - - _p.setProjection = function (projection) { - var _t = this; - var size = _t._winSizeInPoints; - - _t.setViewport(); - - switch (projection) { - case cc.Director.PROJECTION_2D: - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLLoadIdentity(); - var orthoMatrix = new cc.kmMat4(); - cc.kmMat4OrthographicProjection(orthoMatrix, 0, size.width, 0, size.height, -1024, 1024); - cc.kmGLMultMatrix(orthoMatrix); - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLLoadIdentity(); - break; - case cc.Director.PROJECTION_3D: - var zeye = _t.getZEye(); - var matrixPerspective = new cc.kmMat4(), matrixLookup = new cc.kmMat4(); - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLLoadIdentity(); - - // issue #1334 - cc.kmMat4PerspectiveProjection(matrixPerspective, 60, size.width / size.height, 0.1, zeye * 2); - - cc.kmGLMultMatrix(matrixPerspective); - - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLLoadIdentity(); - var eye = cc.kmVec3Fill(null, size.width / 2, size.height / 2, zeye); - var center = cc.kmVec3Fill(null, size.width / 2, size.height / 2, 0.0); - var up = cc.kmVec3Fill(null, 0.0, 1.0, 0.0); - cc.kmMat4LookAt(matrixLookup, eye, center, up); - cc.kmGLMultMatrix(matrixLookup); - break; - case cc.Director.PROJECTION_CUSTOM: - if (_t._projectionDelegate) - _t._projectionDelegate.updateProjection(); - break; - default: - cc.log(cc._LogInfos.Director_setProjection); - break; - } - _t._projection = projection; - cc.eventManager.dispatchEvent(_t._eventProjectionChanged); - cc.setProjectionMatrixDirty(); - }; - - _p.setDepthTest = function (on) { - - var loc_gl= cc._renderContext; - if (on) { - loc_gl.clearDepth(1.0); - loc_gl.enable(loc_gl.DEPTH_TEST); - loc_gl.depthFunc(loc_gl.LEQUAL); - //cc._renderContext.hint(cc._renderContext.PERSPECTIVE_CORRECTION_HINT, cc._renderContext.NICEST); - } else { - loc_gl.disable(loc_gl.DEPTH_TEST); - } - //cc.checkGLErrorDebug(); - }; - - _p.setOpenGLView = function (openGLView) { - var _t = this; - // set size - _t._winSizeInPoints.width = cc._canvas.width; //_t._openGLView.getDesignResolutionSize(); - _t._winSizeInPoints.height = cc._canvas.height; - _t._openGLView = openGLView || cc.view; - - // Configuration. Gather GPU info - var conf = cc.configuration; - conf.gatherGPUInfo(); - conf.dumpInfo(); - - // set size - //_t._winSizeInPoints = _t._openGLView.getDesignResolutionSize(); - //_t._winSizeInPixels = cc.size(_t._winSizeInPoints.width * _t._contentScaleFactor, _t._winSizeInPoints.height * _t._contentScaleFactor); - - //if (_t._openGLView != openGLView) { - // because EAGLView is not kind of CCObject - - _t._createStatsLabel(); - - //if (_t._openGLView) - _t.setGLDefaultValues(); - - /* if (_t._contentScaleFactor != 1) { - _t.updateContentScaleFactor(); - }*/ - - //} - if(cc.eventManager) - cc.eventManager.setEnabled(true); - }; - - _p._clear = function() { - var gl = cc._renderContext; - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - }; - - _p._beforeVisitScene = function() { - cc.kmGLPushMatrix(); - }; - - _p._afterVisitScene = function() { - cc.kmGLPopMatrix(); - }; - - _p._createStatsLabel = function(){ - var _t = this; - if(!cc.LabelAtlas) - return _t._createStatsLabelForCanvas(); - - if((cc.Director._fpsImageLoaded == null) || (cc.Director._fpsImageLoaded == false)) - return; - - var texture = new cc.Texture2D(); - texture.initWithElement(cc.Director._fpsImage); - texture.handleLoadedTexture(); - - /* - We want to use an image which is stored in the file named ccFPSImage.c - for any design resolutions and all resource resolutions. - - To achieve this, - - Firstly, we need to ignore 'contentScaleFactor' in 'CCAtlasNode' and 'CCLabelAtlas'. - So I added a new method called 'setIgnoreContentScaleFactor' for 'CCAtlasNode', - this is not exposed to game developers, it's only used for displaying FPS now. - - Secondly, the size of this image is 480*320, to display the FPS label with correct size, - a factor of design resolution ratio of 480x320 is also needed. + * OpenGL projection protocol + * @class + * @extends cc.Class */ - var factor = cc.view.getDesignResolutionSize().height / 320.0; - if(factor === 0) - factor = _t._winSizeInPoints.height / 320.0; - - var tmpLabel = new cc.LabelAtlas(); - tmpLabel._setIgnoreContentScaleFactor(true); - tmpLabel.initWithString("00.0", texture, 12, 32 , '.'); - tmpLabel.scale = factor; - _t._FPSLabel = tmpLabel; - - tmpLabel = new cc.LabelAtlas(); - tmpLabel._setIgnoreContentScaleFactor(true); - tmpLabel.initWithString("0.000", texture, 12, 32, '.'); - tmpLabel.scale = factor; - _t._SPFLabel = tmpLabel; - - tmpLabel = new cc.LabelAtlas(); - tmpLabel._setIgnoreContentScaleFactor(true); - tmpLabel.initWithString("000", texture, 12, 32, '.'); - tmpLabel.scale = factor; - _t._drawsLabel = tmpLabel; - - var locStatsPosition = cc.DIRECTOR_STATS_POSITION; - _t._drawsLabel.setPosition(locStatsPosition.x, 34 * factor + locStatsPosition.y); - _t._SPFLabel.setPosition(locStatsPosition.x, 17 * factor + locStatsPosition.y); - _t._FPSLabel.setPosition(locStatsPosition); - }; - - _p._createStatsLabelForCanvas = function(){ - var _t = this; - //The original _createStatsLabelForCanvas method - //Because the referenced by a cc.Director.prototype._createStatsLabel - var fontSize = 0; - if (_t._winSizeInPoints.width > _t._winSizeInPoints.height) - fontSize = 0 | (_t._winSizeInPoints.height / 320 * 24); - else - fontSize = 0 | (_t._winSizeInPoints.width / 320 * 24); - - _t._FPSLabel = cc.LabelTTF.create("000.0", "Arial", fontSize); - _t._SPFLabel = cc.LabelTTF.create("0.000", "Arial", fontSize); - _t._drawsLabel = cc.LabelTTF.create("0000", "Arial", fontSize); - - var locStatsPosition = cc.DIRECTOR_STATS_POSITION; - _t._drawsLabel.setPosition(_t._drawsLabel.width / 2 + locStatsPosition.x, _t._drawsLabel.height * 5 / 2 + locStatsPosition.y); - _t._SPFLabel.setPosition(_t._SPFLabel.width / 2 + locStatsPosition.x, _t._SPFLabel.height * 3 / 2 + locStatsPosition.y); - _t._FPSLabel.setPosition(_t._FPSLabel.width / 2 + locStatsPosition.x, _t._FPSLabel.height / 2 + locStatsPosition.y); - }; - - - /** - *

- * converts a UIKit coordinate to an OpenGL coordinate
- * Useful to convert (multi) touches coordinates to the current layout (portrait or landscape) - *

- * @param {cc.Point} uiPoint - * @return {cc.Point} - * - * convertToGL move to CCDirectorWebGL - */ - _p.convertToGL = function (uiPoint) { - var transform = new cc.kmMat4(); - cc.GLToClipTransform(transform); - - var transformInv = new cc.kmMat4(); - cc.kmMat4Inverse(transformInv, transform); - - // Calculate z=0 using -> transform*[0, 0, 0, 1]/w - var zClip = transform.mat[14] / transform.mat[15]; - - var glSize = this._openGLView.getDesignResolutionSize(); - var clipCoord = new cc.kmVec3(2.0 * uiPoint.x / glSize.width - 1.0, 1.0 - 2.0 * uiPoint.y / glSize.height, zClip); - - var glCoord = new cc.kmVec3(); - cc.kmVec3TransformCoord(glCoord, clipCoord, transformInv); - - return cc.p(glCoord.x, glCoord.y); - }; - - /** - *

converts an OpenGL coordinate to a UIKit coordinate
- * Useful to convert node points to window points for calls such as glScissor

- * @param {cc.Point} glPoint - * @return {cc.Point} - */ - _p.convertToUI = function (glPoint) { - var transform = new cc.kmMat4(); - cc.GLToClipTransform(transform); - - var clipCoord = new cc.kmVec3(); - // Need to calculate the zero depth from the transform. - var glCoord = new cc.kmVec3(glPoint.x, glPoint.y, 0.0); - cc.kmVec3TransformCoord(clipCoord, glCoord, transform); - - var glSize = this._openGLView.getDesignResolutionSize(); - return cc.p(glSize.width * (clipCoord.x * 0.5 + 0.5), glSize.height * (-clipCoord.y * 0.5 + 0.5)); - }; - - - - - _p.getVisibleSize = function () { - //if (this._openGLView) { - return this._openGLView.getVisibleSize(); - //} else { - //return this.getWinSize(); - //} - }; - - _p.getVisibleOrigin = function () { - //if (this._openGLView) { - return this._openGLView.getVisibleOrigin(); - //} else { - //return cc.p(0,0); - //} - }; - - _p.getZEye = function () { - return (this._winSizeInPoints.height / 1.1566 ); - }; - - /** - * Sets the glViewport - */ - _p.setViewport = function(){ - if(this._openGLView) { - var locWinSizeInPoints = this._winSizeInPoints; - this._openGLView.setViewPortInPoints(0,0, locWinSizeInPoints.width, locWinSizeInPoints.height); - } - }; - - /** - * Get the CCEGLView, where everything is rendered - * @return {*} - */ - _p.getOpenGLView = function () { - return this._openGLView; - }; - - /** - * Sets an OpenGL projection - * @return {Number} - */ - _p.getProjection = function () { - return this._projection; - }; - - /** - * enables/disables OpenGL alpha blending - * @param {Boolean} on - */ - _p.setAlphaBlending = function (on) { - if (on) - cc.glBlendFunc(cc.BLEND_SRC, cc.BLEND_DST); - else - cc.glBlendFunc(cc._renderContext.ONE, cc._renderContext.ZERO); - //cc.checkGLErrorDebug(); - }; - - - /** - * sets the OpenGL default values - */ - _p.setGLDefaultValues = function () { - var _t = this; - _t.setAlphaBlending(true); - // XXX: Fix me, should enable/disable depth test according the depth format as cocos2d-iphone did - // [self setDepthTest: view_.depthFormat]; - _t.setDepthTest(false); - _t.setProjection(_t._projection); - - // set other opengl default values - cc._renderContext.clearColor(0.0, 0.0, 0.0, 1.0); - }; -} \ No newline at end of file + cc.DirectorDelegate = cc.Class.extend(/** @lends cc.DirectorDelegate# */{ + /** + * Called by CCDirector when the projection is updated, and "custom" projection is used + */ + updateProjection: function () { + } + }); + + var _p = cc.Director.prototype; + + _p.setProjection = function (projection) { + var _t = this; + var size = _t._winSizeInPoints; + + _t.setViewport(); + + var view = _t._openGLView, + ox = view._viewPortRect.x / view._scaleX, + oy = view._viewPortRect.y / view._scaleY; + + switch (projection) { + case cc.Director.PROJECTION_2D: + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLLoadIdentity(); + var orthoMatrix = cc.math.Matrix4.createOrthographicProjection( + -ox, + size.width - ox, + -oy, + size.height - oy, + -1024, 1024); + cc.kmGLMultMatrix(orthoMatrix); + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLLoadIdentity(); + break; + case cc.Director.PROJECTION_3D: + var zeye = _t.getZEye(); + var matrixPerspective = new cc.math.Matrix4(), matrixLookup = new cc.math.Matrix4(); + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLLoadIdentity(); + + // issue #1334 + matrixPerspective = cc.math.Matrix4.createPerspectiveProjection(60, size.width / size.height, 0.1, zeye * 2); + + cc.kmGLMultMatrix(matrixPerspective); + + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLLoadIdentity(); + var eye = new cc.math.Vec3(-ox + size.width / 2, -oy + size.height / 2, zeye); + var center = new cc.math.Vec3( -ox + size.width / 2, -oy + size.height / 2, 0.0); + var up = new cc.math.Vec3( 0.0, 1.0, 0.0); + matrixLookup.lookAt(eye, center, up); + cc.kmGLMultMatrix(matrixLookup); + break; + case cc.Director.PROJECTION_CUSTOM: + if (_t._projectionDelegate) + _t._projectionDelegate.updateProjection(); + break; + default: + cc.log(cc._LogInfos.Director_setProjection); + break; + } + _t._projection = projection; + cc.eventManager.dispatchEvent(_t._eventProjectionChanged); + cc.setProjectionMatrixDirty(); + cc.renderer.childrenOrderDirty = true; + }; + + _p.setDepthTest = function (on) { + + var loc_gl = cc._renderContext; + if (on) { + loc_gl.clearDepth(1.0); + loc_gl.enable(loc_gl.DEPTH_TEST); + loc_gl.depthFunc(loc_gl.LEQUAL); + //cc._renderContext.hint(cc._renderContext.PERSPECTIVE_CORRECTION_HINT, cc._renderContext.NICEST); + } else { + loc_gl.disable(loc_gl.DEPTH_TEST); + } + //cc.checkGLErrorDebug(); + }; + + _p.setOpenGLView = function (openGLView) { + var _t = this; + // set size + _t._winSizeInPoints.width = cc._canvas.width; //_t._openGLView.getDesignResolutionSize(); + _t._winSizeInPoints.height = cc._canvas.height; + _t._openGLView = openGLView || cc.view; + + // Configuration. Gather GPU info + var conf = cc.configuration; + conf.gatherGPUInfo(); + conf.dumpInfo(); + + // set size + //_t._winSizeInPoints = _t._openGLView.getDesignResolutionSize(); + //_t._winSizeInPixels = cc.size(_t._winSizeInPoints.width * _t._contentScaleFactor, _t._winSizeInPoints.height * _t._contentScaleFactor); + + //if (_t._openGLView != openGLView) { + // because EAGLView is not kind of CCObject + + _t._createStatsLabel(); + + //if (_t._openGLView) + _t.setGLDefaultValues(); + + /* if (_t._contentScaleFactor != 1) { + _t.updateContentScaleFactor(); + }*/ + + //} + if (cc.eventManager) + cc.eventManager.setEnabled(true); + }; + + _p._clear = function () { + var gl = cc._renderContext; + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + }; + + _p._beforeVisitScene = function () { + cc.kmGLPushMatrix(); + }; + + _p._afterVisitScene = function () { + cc.kmGLPopMatrix(); + }; + + _p._createStatsLabel = function () { + var _t = this; + if (!cc.LabelAtlas){ + _t._createStatsLabelForCanvas(); + return + } + + if ((cc.Director._fpsImageLoaded == null) || (cc.Director._fpsImageLoaded === false)) + return; + + var texture = new cc.Texture2D(); + texture.initWithElement(cc.Director._fpsImage); + texture.handleLoadedTexture(); + + /* + We want to use an image which is stored in the file named ccFPSImage.c + for any design resolutions and all resource resolutions. + + To achieve this, + + Firstly, we need to ignore 'contentScaleFactor' in 'CCAtlasNode' and 'CCLabelAtlas'. + So I added a new method called 'setIgnoreContentScaleFactor' for 'CCAtlasNode', + this is not exposed to game developers, it's only used for displaying FPS now. + + Secondly, the size of this image is 480*320, to display the FPS label with correct size, + a factor of design resolution ratio of 480x320 is also needed. + */ + var factor = cc.view.getDesignResolutionSize().height / 320.0; + if (factor === 0) + factor = _t._winSizeInPoints.height / 320.0; + + var tmpLabel = new cc.LabelAtlas(); + tmpLabel._setIgnoreContentScaleFactor(true); + tmpLabel.initWithString("00.0", texture, 12, 32, '.'); + tmpLabel.scale = factor; + _t._FPSLabel = tmpLabel; + + tmpLabel = new cc.LabelAtlas(); + tmpLabel._setIgnoreContentScaleFactor(true); + tmpLabel.initWithString("0.000", texture, 12, 32, '.'); + tmpLabel.scale = factor; + _t._SPFLabel = tmpLabel; + + tmpLabel = new cc.LabelAtlas(); + tmpLabel._setIgnoreContentScaleFactor(true); + tmpLabel.initWithString("000", texture, 12, 32, '.'); + tmpLabel.scale = factor; + _t._drawsLabel = tmpLabel; + + var locStatsPosition = cc.DIRECTOR_STATS_POSITION; + _t._drawsLabel.setPosition(locStatsPosition.x, 34 * factor + locStatsPosition.y); + _t._SPFLabel.setPosition(locStatsPosition.x, 17 * factor + locStatsPosition.y); + _t._FPSLabel.setPosition(locStatsPosition); + }; + + _p._createStatsLabelForCanvas = function () { + var _t = this; + //The original _createStatsLabelForCanvas method + //Because the referenced by a cc.Director.prototype._createStatsLabel + var fontSize = 0; + if (_t._winSizeInPoints.width > _t._winSizeInPoints.height) + fontSize = 0 | (_t._winSizeInPoints.height / 320 * 24); + else + fontSize = 0 | (_t._winSizeInPoints.width / 320 * 24); + + _t._FPSLabel = new cc.LabelTTF("000.0", "Arial", fontSize); + _t._SPFLabel = new cc.LabelTTF("0.000", "Arial", fontSize); + _t._drawsLabel = new cc.LabelTTF("0000", "Arial", fontSize); + + var locStatsPosition = cc.DIRECTOR_STATS_POSITION; + _t._drawsLabel.setPosition(_t._drawsLabel.width / 2 + locStatsPosition.x, _t._drawsLabel.height * 5 / 2 + locStatsPosition.y); + _t._SPFLabel.setPosition(_t._SPFLabel.width / 2 + locStatsPosition.x, _t._SPFLabel.height * 3 / 2 + locStatsPosition.y); + _t._FPSLabel.setPosition(_t._FPSLabel.width / 2 + locStatsPosition.x, _t._FPSLabel.height / 2 + locStatsPosition.y); + }; + + _p.convertToGL = function (uiPoint) { + var transform = new cc.math.Matrix4(); + cc.GLToClipTransform(transform); + + var transformInv = transform.inverse(); + + // Calculate z=0 using -> transform*[0, 0, 0, 1]/w + var zClip = transform.mat[14] / transform.mat[15]; + var glSize = this._openGLView.getDesignResolutionSize(); + var glCoord = new cc.math.Vec3(2.0 * uiPoint.x / glSize.width - 1.0, 1.0 - 2.0 * uiPoint.y / glSize.height, zClip); + glCoord.transformCoord(transformInv); + return cc.p(glCoord.x, glCoord.y); + }; + + _p.convertToUI = function (glPoint) { + var transform = new cc.math.Matrix4(); + cc.GLToClipTransform(transform); + + var clipCoord = new cc.math.Vec3(glPoint.x, glPoint.y, 0.0); + // Need to calculate the zero depth from the transform. + clipCoord.transformCoord(transform); + + var glSize = this._openGLView.getDesignResolutionSize(); + return cc.p(glSize.width * (clipCoord.x * 0.5 + 0.5), glSize.height * (-clipCoord.y * 0.5 + 0.5)); + }; + + _p.getVisibleSize = function () { + //if (this._openGLView) { + return this._openGLView.getVisibleSize(); + //} else { + //return this.getWinSize(); + //} + }; + + _p.getVisibleOrigin = function () { + //if (this._openGLView) { + return this._openGLView.getVisibleOrigin(); + //} else { + //return cc.p(0,0); + //} + }; + + _p.getZEye = function () { + return (this._winSizeInPoints.height / 1.1566 ); + }; + + _p.setViewport = function () { + var view = this._openGLView; + if (view) { + var locWinSizeInPoints = this._winSizeInPoints; + view.setViewPortInPoints(-view._viewPortRect.x/view._scaleX, -view._viewPortRect.y/view._scaleY, locWinSizeInPoints.width, locWinSizeInPoints.height); + } + }; + + _p.getOpenGLView = function () { + return this._openGLView; + }; + + _p.getProjection = function () { + return this._projection; + }; + + _p.setAlphaBlending = function (on) { + if (on) + cc.glBlendFunc(cc.BLEND_SRC, cc.BLEND_DST); + else + cc.glBlendFunc(cc._renderContext.ONE, cc._renderContext.ZERO); + //cc.checkGLErrorDebug(); + }; + + _p.setGLDefaultValues = function () { + var _t = this; + _t.setAlphaBlending(true); + // XXX: Fix me, should enable/disable depth test according the depth format as cocos2d-iphone did + // [self setDepthTest: view_.depthFormat]; + _t.setDepthTest(false); + _t.setProjection(_t._projection); + + // set other opengl default values + cc._renderContext.clearColor(0.0, 0.0, 0.0, 1.0); + }; + })(); +} diff --git a/cocos2d/core/CCDrawingPrimitivesCanvas.js b/cocos2d/core/CCDrawingPrimitivesCanvas.js index 66a9b540cc..a08dfbe38c 100644 --- a/cocos2d/core/CCDrawingPrimitivesCanvas.js +++ b/cocos2d/core/CCDrawingPrimitivesCanvas.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -21,20 +23,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ - +/** + * @const + * @type {number} + */ cc.PI2 = Math.PI * 2; /** - * Canvas of DrawingPrimitive implement version + * Canvas of DrawingPrimitive implement version use for canvasMode * @class * @extends cc.Class + * @param {CanvasRenderingContext2D} renderContext */ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas# */{ _cacheArray:[], _renderContext:null, /** - * Constructor - * @param {CanvasRenderingContext2D} renderContext + * Constructor of cc.DrawingPrimitiveCanvas + * @param {cc.CanvasContextWrapper} renderContext */ ctor:function (renderContext) { this._renderContext = renderContext; @@ -52,10 +58,11 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas } var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); var newPoint = cc.p(point.x * locScaleX, point.y * locScaleY); - this._renderContext.beginPath(); - this._renderContext.arc(newPoint.x, -newPoint.y, size * locScaleX, 0, Math.PI * 2, false); - this._renderContext.closePath(); - this._renderContext.fill(); + var ctx = this._renderContext.getContext(); + ctx.beginPath(); + ctx.arc(newPoint.x, -newPoint.y, size * locScaleX, 0, Math.PI * 2, false); + ctx.closePath(); + ctx.fill(); }, /** @@ -66,13 +73,13 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {Number} size */ drawPoints:function (points, numberOfPoints, size) { - if (points == null) { + if (points == null) return; - } + if (!size) { size = 1; } - var locContext = this._renderContext,locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); + var locContext = this._renderContext.getContext(),locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); locContext.beginPath(); for (var i = 0, len = points.length; i < len; i++) @@ -88,7 +95,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {cc.Point} destination */ drawLine:function (origin, destination) { - var locContext = this._renderContext, locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); + var locContext = this._renderContext.getContext(), locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); locContext.beginPath(); locContext.moveTo(origin.x * locScaleX, -origin.y * locScaleY); locContext.lineTo(destination.x * locScaleX, -destination.y * locScaleY); @@ -102,6 +109,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {cc.Point} destination */ drawRect:function (origin, destination) { + //todo need optimize for performance this.drawLine(cc.p(origin.x, origin.y), cc.p(destination.x, origin.y)); this.drawLine(cc.p(destination.x, origin.y), cc.p(destination.x, destination.y)); this.drawLine(cc.p(destination.x, destination.y), cc.p(origin.x, destination.y)); @@ -142,7 +150,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas if (vertices.length < 3) throw new Error("Polygon's point must greater than 2"); - var firstPoint = vertices[0], locContext = this._renderContext; + var firstPoint = vertices[0], locContext = this._renderContext.getContext(); var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); locContext.beginPath(); locContext.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); @@ -180,7 +188,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas */ drawCircle: function (center, radius, angle, segments, drawLineToCenter) { drawLineToCenter = drawLineToCenter || false; - var locContext = this._renderContext; + var locContext = this._renderContext.getContext(); var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); locContext.beginPath(); var endAngle = angle - Math.PI * 2; @@ -261,7 +269,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas */ drawCardinalSpline:function (config, tension, segments) { //lazy_init(); - cc._renderContext.strokeStyle = "rgba(255,255,255,1)"; + cc._renderContext.setStrokeStyle("rgba(255,255,255,1)"); var points = this._cacheArray; points.length = 0; var p, lt; @@ -271,7 +279,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas var dt = i / segments; // border - if (dt == 1) { + if (dt === 1) { p = config.length - 1; lt = 1; } else { @@ -302,16 +310,17 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas */ drawImage:function (image, sourcePoint, sourceSize, destPoint, destSize) { var len = arguments.length; + var ctx = this._renderContext.getContext(); switch (len) { case 2: var height = image.height; - this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + height)); + ctx.drawImage(image, sourcePoint.x, -(sourcePoint.y + height)); break; case 3: - this._renderContext.drawImage(image, sourcePoint.x, -(sourcePoint.y + sourceSize.height), sourceSize.width, sourceSize.height); + ctx.drawImage(image, sourcePoint.x, -(sourcePoint.y + sourceSize.height), sourceSize.width, sourceSize.height); break; case 5: - this._renderContext.drawImage(image, sourcePoint.x, sourcePoint.y, sourceSize.width, sourceSize.height, destPoint.x, -(destPoint.y + destSize.height), + ctx.drawImage(image, sourcePoint.x, sourcePoint.y, sourceSize.width, sourceSize.height, destPoint.x, -(destPoint.y + destSize.height), destSize.width, destSize.height); break; default: @@ -322,15 +331,17 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas /** * draw a star - * @param {CanvasRenderingContext2D} ctx canvas context + * @param {cc.CanvasContextWrapper} ctx canvas context * @param {Number} radius * @param {cc.Color} color */ drawStar:function (ctx, radius, color) { - var context = ctx || this._renderContext; + var wrapper = ctx || this._renderContext; + var context = wrapper.getContext(); radius *= cc.view.getScaleX(); var colorStr = "rgba(" + (0 | color.r) + "," + (0 | color.g) + "," + (0 | color.b); - context.fillStyle = colorStr + ",1)"; + wrapper.setFillStyle(colorStr + ",1)"); + //context.fillStyle = colorStr + ",1)"; var subRadius = radius / 10; context.beginPath(); @@ -346,11 +357,12 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas context.closePath(); context.fill(); - var g1 = context.createRadialGradient(0, 0, subRadius, 0, 0, radius); - g1.addColorStop(0, colorStr + ", 1)"); - g1.addColorStop(0.3, colorStr + ", 0.8)"); - g1.addColorStop(1.0, colorStr + ", 0.0)"); - context.fillStyle = g1; + var rg = context.createRadialGradient(0, 0, subRadius, 0, 0, radius); + rg.addColorStop(0, colorStr + ", 1)"); + rg.addColorStop(0.3, colorStr + ", 0.8)"); + rg.addColorStop(1.0, colorStr + ", 0.0)"); + wrapper.setFillStyle(rg); + //context.fillStyle = g1; context.beginPath(); var startAngle_1 = 0; var endAngle_1 = cc.PI2; @@ -361,12 +373,13 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas /** * draw a color ball - * @param {CanvasRenderingContext2D} ctx canvas context + * @param {cc.CanvasContextWrapper} ctx canvas context * @param {Number} radius * @param {cc.Color} color */ drawColorBall:function (ctx, radius, color) { - var context = ctx || this._renderContext; + var wrapper = ctx || this._renderContext; + var context = wrapper.getContext(); radius *= cc.view.getScaleX(); var colorStr = "rgba(" +(0|color.r) + "," + (0|color.g) + "," + (0|color.b); var subRadius = radius / 10; @@ -376,7 +389,8 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas g1.addColorStop(0.3, colorStr + ", 0.8)"); g1.addColorStop(0.6, colorStr + ", 0.4)"); g1.addColorStop(1.0, colorStr + ", 0.0)"); - context.fillStyle = g1; + wrapper.setFillStyle(g1); + //context.fillStyle = g1; context.beginPath(); var startAngle_1 = 0; var endAngle_1 = cc.PI2; @@ -392,7 +406,7 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {Number} y */ fillText:function (strText, x, y) { - this._renderContext.fillText(strText, x, -y); + this._renderContext.getContext().fillText(strText, x, -y); }, /** @@ -403,8 +417,8 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {Number} a Alpha value (0 to 255) */ setDrawColor:function (r, g, b, a) { - this._renderContext.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"; - this._renderContext.strokeStyle = "rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"; + this._renderContext.setFillStyle("rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"); + this._renderContext.setStrokeStyle("rgba(" + r + "," + g + "," + b + "," + a / 255 + ")"); }, /** @@ -419,6 +433,6 @@ cc.DrawingPrimitiveCanvas = cc.Class.extend(/** @lends cc.DrawingPrimitiveCanvas * @param {Number} width */ setLineWidth:function (width) { - this._renderContext.lineWidth = width * cc.view.getScaleX(); + this._renderContext.getContext().lineWidth = width * cc.view.getScaleX(); } }); \ No newline at end of file diff --git a/cocos2d/core/CCDrawingPrimitivesWebGL.js b/cocos2d/core/CCDrawingPrimitivesWebGL.js index d156c83fc1..c3942a9981 100644 --- a/cocos2d/core/CCDrawingPrimitivesWebGL.js +++ b/cocos2d/core/CCDrawingPrimitivesWebGL.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +25,7 @@ ****************************************************************************/ /** - * Canvas of DrawingPrimitive implement version + * Canvas of DrawingPrimitive implement version use for WebGlMode * @class * @extends cc.Class */ @@ -35,6 +37,10 @@ cc.DrawingPrimitiveWebGL = cc.Class.extend(/** @lends cc.DrawingPrimitiveWebGL# _colorArray: null, _pointSizeLocation:-1, _pointSize:-1, + /** + * contructor of cc.DrawingPrimitiveWebGL + * @param ctx rendercontext + */ ctor:function (ctx) { if (ctx == null) ctx = cc._renderContext; @@ -98,7 +104,7 @@ cc.DrawingPrimitiveWebGL = cc.Class.extend(/** @lends cc.DrawingPrimitiveWebGL# * @param {Number} numberOfPoints */ drawPoints:function (points, numberOfPoints) { - if (!points || points.length == 0) + if (!points || points.length === 0) return; this.lazy_init(); @@ -389,7 +395,7 @@ cc.DrawingPrimitiveWebGL = cc.Class.extend(/** @lends cc.DrawingPrimitiveWebGL# var dt = i / segments; // border - if (dt == 1) { + if (dt === 1) { p = config.length - 1; lt = 1; } else { @@ -397,7 +403,7 @@ cc.DrawingPrimitiveWebGL = cc.Class.extend(/** @lends cc.DrawingPrimitiveWebGL# lt = (dt - deltaT * p) / deltaT; } - var newPos = cc.CardinalSplineAt( + var newPos = cc.cardinalSplineAt( cc.getControlPointAt(config, p - 1), cc.getControlPointAt(config, p), cc.getControlPointAt(config, p + 1), diff --git a/cocos2d/core/CCScheduler.js b/cocos2d/core/CCScheduler.js index 10428ac16a..688726099e 100644 --- a/cocos2d/core/CCScheduler.js +++ b/cocos2d/core/CCScheduler.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -32,80 +32,23 @@ */ cc.PRIORITY_NON_SYSTEM = cc.PRIORITY_SYSTEM + 1; -/** - * Verify Array's Type - * @param {Array} arr - * @param {function} type - * @return {Boolean} - * @function - */ -cc.arrayVerifyType = function (arr, type) { - if (arr && arr.length > 0) { - for (var i = 0; i < arr.length; i++) { - if (!(arr[i] instanceof type)) { - cc.log(cc._LogInfos.arrayVerifyType); - return false; - } - } - } - return true; -}; - -/** - * Searches for the first occurance of object and removes it. If object is not found the function has no effect. - * @function - * @param {Array} arr Source Array - * @param {*} delObj remove object - */ -cc.arrayRemoveObject = function (arr, delObj) { - for (var i = 0, l = arr.length; i < l; i++) { - if (arr[i] == delObj) { - arr.splice(i, 1); - break; - } - } -}; - -/** - * Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. - * @function - * @param {Array} arr Source Array - * @param {Array} minusArr minus Array - */ -cc.arrayRemoveArray = function (arr, minusArr) { - for (var i = 0, l = minusArr.length; i < l; i++) { - cc.arrayRemoveObject(arr, minusArr[i]); - } -}; - -/** - * Inserts some objects at index - * @function - * @param {Array} arr - * @param {Array} addObjs - * @param {Number} index - * @return {Array} - */ -cc.arrayAppendObjectsToIndex = function(arr, addObjs,index){ - arr.splice.apply(arr, [index, 0].concat(addObjs)); - return arr; -}; - //data structures /** * A list double-linked list used for "updates with priority" * @Class - * @Construct + * @name cc.ListEntry * @param {cc.ListEntry} prev * @param {cc.ListEntry} next + * @param {function} callback * @param {cc.Class} target not retained (retained by hashUpdateEntry) * @param {Number} priority * @param {Boolean} paused * @param {Boolean} markedForDeletion selector will no longer be called and entry will be removed at end of the next tick */ -cc.ListEntry = function (prev, next, target, priority, paused, markedForDeletion) { +cc.ListEntry = function (prev, next, callback, target, priority, paused, markedForDeletion) { this.prev = prev; this.next = next; + this.callback = callback; this.target = target; this.priority = priority; this.paused = paused; @@ -113,18 +56,20 @@ cc.ListEntry = function (prev, next, target, priority, paused, markedForDeletion }; /** - * a update entry list + * A update entry list * @Class - * @Construct - * @param {cc.ListEntry} list Which list does it belong to ? + * @name cc.HashUpdateEntry + * @param {Array} list Which list does it belong to ? * @param {cc.ListEntry} entry entry in the list * @param {cc.Class} target hash key (retained) + * @param {function} callback * @param {Array} hh */ -cc.HashUpdateEntry = function (list, entry, target, hh) { +cc.HashUpdateEntry = function (list, entry, target, callback, hh) { this.list = list; this.entry = entry; this.target = target; + this.callback = callback; this.hh = hh; }; @@ -132,7 +77,6 @@ cc.HashUpdateEntry = function (list, entry, target, hh) { /** * Hash Element used for "selectors with interval" * @Class - * @Construct * @param {Array} timers * @param {cc.Class} target hash key (retained) * @param {Number} timerIndex @@ -141,7 +85,7 @@ cc.HashUpdateEntry = function (list, entry, target, hh) { * @param {Boolean} paused * @param {Array} hh */ -cc.HashTimerEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) { +cc.HashTimerEntry = cc.hashSelectorEntry = function (timers, target, timerIndex, currentTimer, currentTimerSalvaged, paused, hh) { var _t = this; _t.timers = timers; _t.target = target; @@ -158,17 +102,14 @@ cc.HashTimerEntry = function (timers, target, timerIndex, currentTimer, currentT * @extends cc.Class */ cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{ - _interval:0.0, - _callback:null,//is called _callback before - - _target:null,//target of _callback + _scheduler: null, _elapsed:0.0, - _runForever:false, _useDelay:false, _timesExecuted:0, _repeat:0, //0 = once, 1 is 2 x executed _delay:0, + _interval:0.0, /** * @return {Number} returns interval of timer @@ -179,39 +120,36 @@ cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{ */ setInterval : function(interval){this._interval = interval;}, - /** - * @return {String|function} returns callback - */ - getCallback : function(){return this._callback}, + setupTimerWithInterval: function(seconds, repeat, delay){ + this._elapsed = -1; + this._interval = seconds; + this._delay = delay; + this._useDelay = (this._delay > 0); + this._repeat = repeat; + this._runForever = (this._repeat === cc.REPEAT_FOREVER); + }, + + trigger: function(){ + return 0; + }, + cancel: function(){ + return 0; + }, /** * cc.Timer's Constructor - * @constructor - * @param {cc.Class} target target - * @param {String|function} callback Selector - * @param {Number} [interval=0] second - * @param {Number} [repeat=cc.REPEAT_FOREVER] repeat times - * @param {Number} [delay=0] delay + * Constructor of cc.Timer */ - ctor:function (target, callback, interval, repeat, delay) { - var self = this; - self._target = target; - self._callback = callback; - self._elapsed = -1; - self._interval = interval || 0; - self._delay = delay || 0; - self._useDelay = self._delay > 0; - self._repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; - self._runForever = (self._repeat == cc.REPEAT_FOREVER); - }, - - _doCallback:function(){ - var self = this; - if (typeof(self._callback) == "string") - self._target[self._callback](self._elapsed); - else // if (typeof(this._callback) == "function") { - self._callback.call(self._target, self._elapsed); + ctor:function () { + this._scheduler = null; + this._elapsed = -1; + this._runForever = false; + this._useDelay = false; + this._timesExecuted = 0; + this._repeat = 0; + this._delay = 0; + this._interval = 0; }, /** @@ -219,47 +157,117 @@ cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{ * @param {Number} dt delta time */ update:function (dt) { - var self = this; - if (self._elapsed == -1) { - self._elapsed = 0; - self._timesExecuted = 0; + if (this._elapsed === -1) { + this._elapsed = 0; + this._timesExecuted = 0; } else { - var locTarget = self._target, locCallback = self._callback; - self._elapsed += dt;//standard timer usage - if (self._runForever && !self._useDelay) { - if (self._elapsed >= self._interval) { - if (locTarget && locCallback) - self._doCallback(); - self._elapsed = 0; + this._elapsed += dt; + if (this._runForever && !this._useDelay) {//standard timer usage + if (this._elapsed >= this._interval) { + this.trigger(); + this._elapsed = 0; } - } else { - //advanced usage - if (self._useDelay) { - if (self._elapsed >= self._delay) { - if (locTarget && locCallback) - self._doCallback(); - - self._elapsed = self._elapsed - self._delay; - self._timesExecuted += 1; - self._useDelay = false; + } else {//advanced usage + if (this._useDelay) { + if (this._elapsed >= this._delay) { + this.trigger(); + + this._elapsed -= this._delay; + this._timesExecuted += 1; + this._useDelay = false; } } else { - if (self._elapsed >= self._interval) { - if (locTarget && locCallback) - self._doCallback(); + if (this._elapsed >= this._interval) { + this.trigger(); - self._elapsed = 0; - self._timesExecuted += 1; + this._elapsed = 0; + this._timesExecuted += 1; } } - if (self._timesExecuted > self._repeat) - cc.director.getScheduler().unscheduleCallbackForTarget(locTarget, locCallback); + if (!this._runForever && this._timesExecuted > this._repeat) + this.cancel(); } } } }); +cc.TimerTargetSelector = cc.Timer.extend({ + _target: null, + _selector: null, + + ctor: function(){ + this._target = null; + this._selector = null; + }, + + initWithSelector: function(scheduler, selector, target, seconds, repeat, delay){ + this._scheduler = scheduler; + this._target = target; + this._selector = selector; + this.setupTimerWithInterval(seconds, repeat, delay); + return true; + }, + + getSelector: function(){ + return this._selector; + }, + + trigger: function(){ + //override + if (this._target && this._selector){ + this._target.call(this._selector, this._elapsed); + } + }, + + cancel: function(){ + //override + this._scheduler.unschedule(this._selector, this._target); + } + +}); + +cc.TimerTargetCallback = cc.Timer.extend({ + + _target: null, + _callback: null, + _key: null, + + ctor: function(){ + this._target = null; + this._callback = null; + }, + + initWithCallback: function(scheduler, callback, target, key, seconds, repeat, delay){ + this._scheduler = scheduler; + this._target = target; + this._callback = callback; + this._key = key; + this.setupTimerWithInterval(seconds, repeat, delay); + return true; + }, + + getCallback: function(){ + return this._callback; + }, + + getKey: function(){ + return this._key; + }, + + trigger: function(){ + //override + if(this._callback) + this._callback.call(this._target, this._elapsed); + }, + + cancel: function(){ + //override + this._scheduler.unschedule(this._callback, this._target); + } + +}); + /** *

* Scheduler is responsible of triggering the scheduled callbacks.
@@ -276,43 +284,78 @@ cc.Timer = cc.Class.extend(/** @lends cc.Timer# */{ * * @example * //register a schedule to scheduler - * cc.director.getScheduler().scheduleSelector(callback, this, interval, !this._isRunning); + * cc.director.getScheduler().schedule(callback, this, interval, !this._isRunning); */ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ _timeScale:1.0, - _updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0, - - _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc - _arrayForUpdates:null, + //_updates : null, //_updates[0] list of priority < 0, _updates[1] list of priority == 0, _updates[2] list of priority > 0, + _updatesNegList: null, + _updates0List: null, + _updatesPosList: null, _hashForTimers:null, //Used for "selectors with interval" - _arrayForTimes:null, + _arrayForTimers:null, //Speed up indexing + _hashForUpdates:null, // hash used to fetch quickly the list entries for pause,delete,etc + //_arrayForUpdates:null, //Speed up indexing _currentTarget:null, _currentTargetSalvaged:false, _updateHashLocked:false, //If true unschedule will not remove anything from a hash. Elements will only be marked for deletion. - /** - * Constructor - */ + ctor:function () { - var self = this; - self._timeScale = 1.0; - self._updates = [[], [], []]; + this._timeScale = 1.0; + this._updatesNegList = []; + this._updates0List = []; + this._updatesPosList = []; - self._hashForUpdates = {}; - self._arrayForUpdates = []; + this._hashForUpdates = {}; + this._hashForTimers = {}; + this._currentTarget = null; + this._currentTargetSalvaged = false; + this._updateHashLocked = false; - self._hashForTimers = {}; - self._arrayForTimers = []; + this._arrayForTimers = []; + //this._arrayForUpdates = []; - self._currentTarget = null; - self._currentTargetSalvaged = false; - self._updateHashLocked = false; }, //-----------------------private method---------------------- + + _schedulePerFrame: function(callback, target, priority, paused){ + var hashElement = this._hashForUpdates[target.__instanceId]; + if (hashElement && hashElement.entry){ + // check if priority has changed + if (hashElement.entry.priority !== priority){ + if (this._updateHashLocked){ + cc.log("warning: you CANNOT change update priority in scheduled function"); + hashElement.entry.markedForDeletion = false; + hashElement.entry.paused = paused; + return; + }else{ + // will be added again outside if (hashElement). + this.unscheduleUpdate(target); + } + }else{ + hashElement.entry.markedForDeletion = false; + hashElement.entry.paused = paused; + return; + } + } + + // most of the updates are going to be 0, that's way there + // is an special list for updates with priority 0 + if (priority === 0){ + this._appendIn(this._updates0List, callback, target, paused); + }else if (priority < 0){ + this._priorityIn(this._updatesNegList, callback, target, priority, paused); + }else{ + // priority > 0 + this._priorityIn(this._updatesPosList, callback, target, priority, paused); + } + }, + _removeHashElement:function (element) { delete this._hashForTimers[element.target.__instanceId]; cc.arrayRemoveObject(this._arrayForTimers, element); @@ -328,7 +371,7 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ cc.arrayRemoveObject(element.list, element.entry); delete self._hashForUpdates[element.target.__instanceId]; - cc.arrayRemoveObject(self._arrayForUpdates, element); + //cc.arrayRemoveObject(self._hashForUpdates, element); element.entry = null; //hash entry @@ -336,8 +379,9 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ } }, - _priorityIn:function (ppList, target, priority, paused) { - var self = this, listElement = new cc.ListEntry(null, null, target, priority, paused, false); + _priorityIn:function (ppList, callback, target, priority, paused) { + var self = this, + listElement = new cc.ListEntry(null, null, callback, target, priority, paused, false); // empey list ? if (!ppList) { @@ -355,21 +399,17 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ } //update hash entry for quick access - var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null); - self._arrayForUpdates.push(hashElement); - self._hashForUpdates[target.__instanceId] = hashElement; + self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null); return ppList; }, - _appendIn:function (ppList, target, paused) { - var self = this, listElement = new cc.ListEntry(null, null, target, 0, paused, false); + _appendIn:function (ppList, callback, target, paused) { + var self = this, listElement = new cc.ListEntry(null, null, callback, target, 0, paused, false); ppList.push(listElement); //update hash entry for quicker access - var hashElement = new cc.HashUpdateEntry(ppList, listElement, target, null); - self._arrayForUpdates.push(hashElement); - self._hashForUpdates[target.__instanceId] = hashElement; + self._hashForUpdates[target.__instanceId] = new cc.HashUpdateEntry(ppList, listElement, target, null, null); }, //-----------------------public method------------------------- @@ -388,7 +428,7 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ }, /** - * returns time scale of scheduler + * Returns time scale of scheduler * @return {Number} */ getTimeScale:function () { @@ -400,33 +440,40 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ * @param {Number} dt delta time */ update:function (dt) { - var self = this; - var locUpdates = self._updates, locArrayForTimers = self._arrayForTimers; - var tmpEntry, elt, i, li; - self._updateHashLocked = true; - - if (this._timeScale != 1.0) { + this._updateHashLocked = true; + if(this._timeScale !== 1) dt *= this._timeScale; + + var i, list, len, entry; + + for(i=0,list=this._updatesNegList, len = list.length; i= 0; i++){ - var update = self._updates[i]; - for(var j = 0, lj = update.length; j < lj; j++){ - tmpEntry = update[j]; - if ((!tmpEntry.paused) && (!tmpEntry.markedForDeletion)) tmpEntry.target.update(dt); - } + for(i=0, list=this._updates0List, len=list.length; i * delay is the amount of time the action will wait before it'll start
*

+ * @deprecated since v3.4 please use .schedule * @param {cc.Class} target * @param {function} callback_fn * @param {Number} interval @@ -474,116 +541,131 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ * //register a schedule to scheduler * cc.director.getScheduler().scheduleCallbackForTarget(this, function, interval, repeat, delay, !this._isRunning ); */ - scheduleCallbackForTarget:function (target, callback_fn, interval, repeat, delay, paused) { + scheduleCallbackForTarget: function(target, callback_fn, interval, repeat, delay, paused){ + //cc.log("scheduleCallbackForTarget is deprecated. Please use schedule."); + this.schedule(callback_fn, target, interval, repeat, delay, paused, target.__instanceId + ""); + }, - cc.assert(callback_fn, cc._LogInfos.Scheduler_scheduleCallbackForTarget_2); + schedule: function(callback, target, interval, repeat, delay, paused, key){ + var isSelector = false; + if(typeof callback !== "function"){ + var selector = callback; + isSelector = true; + } - cc.assert(target, cc._LogInfos.Scheduler_scheduleCallbackForTarget_3); + if(isSelector === false){ + //callback, target, interval, repeat, delay, paused, key + //callback, target, interval, paused, key + if(arguments.length === 5){ + key = delay; + paused = repeat; + delay = 0; + repeat = cc.REPEAT_FOREVER; + } + }else{ + //selector, target, interval, repeat, delay, paused + //selector, target, interval, paused + if(arguments.length === 4){ + paused = repeat; + repeat = cc.REPEAT_FOREVER; + delay = 0; + } + } - // default arguments - interval = interval || 0; - repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; - delay = delay || 0; - paused = paused || false; + cc.assert(target, cc._LogInfos.Scheduler_scheduleCallbackForTarget_3); + if(isSelector === false) + cc.assert(key, "key should not be empty!"); - var self = this, timer; - var element = self._hashForTimers[target.__instanceId]; + var element = this._hashForTimers[target.__instanceId]; - if (!element) { + if(!element){ // Is this the 1st element ? Then set the pause level to all the callback_fns of this target element = new cc.HashTimerEntry(null, target, 0, null, null, paused, null); - self._arrayForTimers.push(element); - self._hashForTimers[target.__instanceId] = element; + this._arrayForTimers.push(element); + this._hashForTimers[target.__instanceId] = element; + }else{ + cc.assert(element.paused === paused, ""); } + var timer, i; if (element.timers == null) { element.timers = []; - } else { - for (var i = 0; i < element.timers.length; i++) { + } else if(isSelector === false) { + for (i = 0; i < element.timers.length; i++) { timer = element.timers[i]; - if (callback_fn == timer._callback) { + if (callback === timer._callback) { cc.log(cc._LogInfos.Scheduler_scheduleCallbackForTarget, timer.getInterval().toFixed(4), interval.toFixed(4)); timer._interval = interval; return; } } + }else{ + for (i = 0; i < element.timers.length; ++i){ + timer =element.timers[i]; + if (timer && selector === timer.getSelector()){ + cc.log("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer.getInterval(), interval); + timer.setInterval(interval); + return; + } + } + //ccArrayEnsureExtraCapacity(element->timers, 1); } - timer = new cc.Timer(target, callback_fn, interval, repeat, delay); - element.timers.push(timer); + if(isSelector === false){ + timer = new cc.TimerTargetCallback(); + timer.initWithCallback(this, callback, target, key, interval, repeat, delay); + element.timers.push(timer); + }else{ + timer = new cc.TimerTargetSelector(); + timer.initWithSelector(this, selector, target, interval, repeat, delay); + element.timers.push(timer); + } }, - /** - *

- * Schedules the 'update' callback_fn for a given target with a given priority.
- * The 'update' callback_fn will be called every frame.
- * The lower the priority, the earlier it is called. - *

- * @param {cc.Class} target - * @param {Number} priority - * @param {Boolean} paused - * @example - * //register this object to scheduler - * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning ); - */ - scheduleUpdateForTarget:function (target, priority, paused) { - if(target === null) - return; - var self = this, locUpdates = self._updates; - var hashElement = self._hashForUpdates[target.__instanceId]; - - if (hashElement) { - // TODO: check if priority has changed! - hashElement.entry.markedForDeletion = false; - return; - } + scheduleUpdate: function(target, priority, paused){ + this._schedulePerFrame(function(dt){ + target.update(dt); + }, target, priority, paused); + }, - // most of the updates are going to be 0, that's way there - // is an special list for updates with priority 0 - if (priority == 0) { - self._appendIn(locUpdates[1], target, paused); - } else if (priority < 0) { - locUpdates[0] = self._priorityIn(locUpdates[0], target, priority, paused); - } else { - // priority > 0 - locUpdates[2] = self._priorityIn(locUpdates[2], target, priority, paused); + _getUnscheduleMark: function(key, timer){ + //key, callback, selector + switch (typeof key){ + case "number": + case "string": + return key === timer.getKey(); + case "function": + return key === timer._callback; + default: + return key === timer.getSelector(); } }, + unschedule: function(key, target){ + //key, target + //selector, target + //callback, target - This is in order to increase compatibility - /** - *

- * Unschedule a callback function for a given target.
- * If you want to unschedule the "update", use unscheudleUpdateForTarget. - *

- * @param {cc.Class} target - * @param {function} callback_fn - * @example - * //unschedule a callback of target - * cc.director.getScheduler().unscheduleCallbackForTarget(function, this); - */ - unscheduleCallbackForTarget:function (target, callback_fn) { // explicity handle nil arguments when removing an object - if ((target == null) || (callback_fn == null)) { + if (!target || !key) return; - } var self = this, element = self._hashForTimers[target.__instanceId]; if (element) { var timers = element.timers; for(var i = 0, li = timers.length; i < li; i++){ var timer = timers[i]; - if (callback_fn == timer._callback) { - if ((timer == element.currentTimer) && (!element.currentTimerSalvaged)) { + if (this._getUnscheduleMark(key, timer)) { + if ((timer === element.currentTimer) && (!element.currentTimerSalvaged)) { element.currentTimerSalvaged = true; } - timers.splice(i, 1) + timers.splice(i, 1); //update timerIndex in case we are in tick;, looping over the actions if (element.timerIndex >= i) { element.timerIndex--; } - if (timers.length == 0) { - if (self._currentTarget == element) { + if (timers.length === 0) { + if (self._currentTarget === element) { self._currentTargetSalvaged = true; } else { self._removeHashElement(element); @@ -595,86 +677,120 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ } }, - /** - * Unschedules the update callback function for a given target - * @param {cc.Class} target - * @example - * //unschedules the "update" method. - * cc.director.getScheduler().unscheduleUpdateForTarget(this); - */ - unscheduleUpdateForTarget:function (target) { - if (target == null) { + unscheduleUpdate: function(target){ + if (target == null) return; - } - var self = this, element = self._hashForUpdates[target.__instanceId]; - if (element != null) { - if (self._updateHashLocked) { + var element = this._hashForUpdates[target.__instanceId]; + + if (element){ + if (this._updateHashLocked){ element.entry.markedForDeletion = true; - } else { - self._removeUpdateFromHash(element.entry); + }else{ + this._removeUpdateFromHash(element.entry); } } }, - /** - * Unschedules all function callbacks for a given target. This also includes the "update" callback function. - * @param {cc.Class} target - */ - unscheduleAllCallbacksForTarget:function (target) { - //explicit NULL handling - if (target == null) { + unscheduleAllForTarget: function(target){ + // explicit nullptr handling + if (target == null){ return; } - var self = this, element = self._hashForTimers[target.__instanceId]; - if (element) { - var timers = element.timers; - if ((!element.currentTimerSalvaged) && (timers.indexOf(element.currentTimer) >= 0)) { + // Custom Selectors + var element = this._hashForTimers[target.__instanceId]; + + if (element){ + if (element.timers.indexOf(element.currentTimer) > -1 + && (! element.currentTimerSalvaged)){ element.currentTimerSalvaged = true; } - timers.length = 0; + // ccArrayRemoveAllObjects(element.timers); + element.timers.length = 0; - if (self._currentTarget == element) { - self._currentTargetSalvaged = true; - } else { - self._removeHashElement(element); + if (this._currentTarget === element){ + this._currentTargetSalvaged = true; + }else{ + this._removeHashElement(element); } } - // update callback - self.unscheduleUpdateForTarget(target); + + // update selector + this.unscheduleUpdate(target); }, - /** - *

- * Unschedules all function callbacks from all targets.
- * You should NEVER call this method, unless you know what you are doing. - *

- */ - unscheduleAllCallbacks:function () { - this.unscheduleAllCallbacksWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM); + unscheduleAll: function(){ + this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM); }, - /** - *

- * Unschedules all function callbacks from all targets with a minimum priority.
- * You should only call this with kCCPriorityNonSystemMin or higher. - *

- * @param {Number} minPriority - */ - unscheduleAllCallbacksWithMinPriority:function (minPriority) { + unscheduleAllWithMinPriority: function(minPriority){ // Custom Selectors - var self = this, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates; - for(var i = 0, li = locArrayForTimers.length; i < li; i++){ - // element may be removed in unscheduleAllCallbacksForTarget - self.unscheduleAllCallbacksForTarget(locArrayForTimers[i].target); - } - for(var i = 2; i >= 0; i--){ - if((i == 1 && minPriority > 0) || (i == 0 && minPriority >= 0)) continue; - var updates = locUpdates[i]; - for(var j = 0, lj = updates.length; j < lj; j++){ - self.unscheduleUpdateForTarget(updates[j].target); + var i, element, arr = this._arrayForTimers; + for(i=0; i= minPriority) + this.unscheduleUpdate(entry.target); + if (temp_length == this._updatesNegList.length) + i++; + } + } + + if(minPriority <= 0){ + for(i=0; i= minPriority) + this.unscheduleUpdate(entry.target); + if (temp_length == this._updatesPosList.length) + i++; + } + }, + + isScheduled: function(key, target){ + //key, target + //selector, target + cc.assert(key, "Argument key must not be empty"); + cc.assert(target, "Argument target must be non-nullptr"); + + var element = this._hashForUpdates[target.__instanceId]; + + if (!element){ + return false; + } + + if (element.timers == null){ + return false; + }else{ + var timers = element.timers; + for (var i = 0; i < timers.length; ++i){ + var timer = timers[i]; + + if (key === timer.getKey()){ + return true; + } } + return false; } }, @@ -691,37 +807,62 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ /** * Pause all selectors from all targets with a minimum priority.
* You should only call this with kCCPriorityNonSystemMin or higher. - * @param minPriority + * @param {Number} minPriority */ pauseAllTargetsWithMinPriority:function (minPriority) { var idsWithSelectors = []; - var self = this, element, locArrayForTimers = self._arrayForTimers, locUpdates = self._updates; + var self = this, element, locArrayForTimers = self._arrayForTimers; + var i, li; // Custom Selectors - for(var i = 0, li = locArrayForTimers.length; i < li; i++){ + for(i = 0, li = locArrayForTimers.length; i < li; i++){ element = locArrayForTimers[i]; if (element) { element.paused = true; idsWithSelectors.push(element.target); } } - for(var i = 0, li = locUpdates.length; i < li; i++){ - var updates = locUpdates[i]; - for(var j = 0, lj = updates.length; j < lj; j++){ - element = updates[j]; - if (element) { - element.paused = true; - idsWithSelectors.push(element.target); + + var entry; + if(minPriority < 0){ + for(i=0; i= minPriority){ + entry.paused = true; + idsWithSelectors.push(entry.target); + } + } + } + } + + if(minPriority <= 0){ + for(i=0; i= minPriority){ + entry.paused = true; + idsWithSelectors.push(entry.target); + } + } + } + return idsWithSelectors; }, /** * Resume selectors on a set of targets.
* This can be useful for undoing a call to pauseAllCallbacks. - * @param targetsToResume + * @param {Array} targetsToResume */ resumeTargets:function (targetsToResume) { if (!targetsToResume) @@ -796,7 +937,95 @@ cc.Scheduler = cc.Class.extend(/** @lends cc.Scheduler# */{ if (element) { return element.paused; } + var elementUpdate = this._hashForUpdates[target.__instanceId]; + if (elementUpdate) { + return elementUpdate.entry.paused; + } return false; + }, + + /** + *

+ * Schedules the 'update' callback_fn for a given target with a given priority.
+ * The 'update' callback_fn will be called every frame.
+ * The lower the priority, the earlier it is called. + *

+ * @deprecated since v3.4 please use .scheduleUpdate + * @param {cc.Class} target + * @param {Number} priority + * @param {Boolean} paused + * @example + * //register this object to scheduler + * cc.director.getScheduler().scheduleUpdateForTarget(this, priority, !this._isRunning ); + */ + scheduleUpdateForTarget: function(target, priority, paused){ + //cc.log("scheduleUpdateForTarget is deprecated. Please use scheduleUpdate."); + this.scheduleUpdate(target, priority, paused); + }, + + /** + *

+ * Unschedule a callback function for a given target.
+ * If you want to unschedule the "update", use unscheudleUpdateForTarget. + *

+ * @deprecated since v3.4 please use .unschedule + * @param {cc.Class} target + * @param {function} callback callback[Function] or key[String] + * @example + * //unschedule a callback of target + * cc.director.getScheduler().unscheduleCallbackForTarget(function, this); + */ + unscheduleCallbackForTarget:function (target, callback) { + //cc.log("unscheduleCallbackForTarget is deprecated. Please use unschedule."); + this.unschedule(callback, target); + }, + + /** + * Unschedules the update callback function for a given target + * @param {cc.Class} target + * @deprecated since v3.4 please use .unschedule + * @example + * //unschedules the "update" method. + * cc.director.getScheduler().unscheduleUpdateForTarget(this); + */ + unscheduleUpdateForTarget:function (target) { + //cc.log("unscheduleUpdateForTarget is deprecated. Please use unschedule."); + this.unscheduleUpdate(target); + }, + + /** + * Unschedules all function callbacks for a given target. This also includes the "update" callback function. + * @deprecated since v3.4 please use .unscheduleAll + * @param {cc.Class} target + */ + unscheduleAllCallbacksForTarget: function(target){ + //cc.log("unscheduleAllCallbacksForTarget is deprecated. Please use unscheduleAll."); + this.unschedule(target.__instanceId + "", target); + }, + + /** + *

+ * Unschedules all function callbacks from all targets.
+ * You should NEVER call this method, unless you know what you are doing. + *

+ * @deprecated since v3.4 please use .unscheduleAllWithMinPriority + */ + unscheduleAllCallbacks: function(){ + //cc.log("unscheduleAllCallbacks is deprecated. Please use unscheduleAll."); + this.unscheduleAllWithMinPriority(cc.Scheduler.PRIORITY_SYSTEM); + }, + + /** + *

+ * Unschedules all function callbacks from all targets with a minimum priority.
+ * You should only call this with kCCPriorityNonSystemMin or higher. + *

+ * @deprecated since v3.4 please use .unscheduleAllWithMinPriority + * @param {Number} minPriority + */ + unscheduleAllCallbacksWithMinPriority:function (minPriority) { + //cc.log("unscheduleAllCallbacksWithMinPriority is deprecated. Please use unscheduleAllWithMinPriority."); + this.unscheduleAllWithMinPriority(minPriority); } }); /** diff --git a/cocos2d/core/base-nodes/BaseNodesPropertyDefine.js b/cocos2d/core/base-nodes/BaseNodesPropertyDefine.js index 2af9fe5d9a..2b2639cd89 100644 --- a/cocos2d/core/base-nodes/BaseNodesPropertyDefine.js +++ b/cocos2d/core/base-nodes/BaseNodesPropertyDefine.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,28 +24,19 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.PrototypeCCNode = function () { +cc._tmp.PrototypeCCNode = function () { var _p = cc.Node.prototype; cc.defineGetterSetter(_p, "x", _p.getPositionX, _p.setPositionX); cc.defineGetterSetter(_p, "y", _p.getPositionY, _p.setPositionY); /** @expose */ - //_p.pos; - //cc.defineGetterSetter(_p, "pos", _p.getPosition, _p.setPosition); - /** @expose */ _p.width; cc.defineGetterSetter(_p, "width", _p._getWidth, _p._setWidth); /** @expose */ _p.height; cc.defineGetterSetter(_p, "height", _p._getHeight, _p._setHeight); /** @expose */ - //_p.size; - //cc.defineGetterSetter(_p, "size", _p.getContentSize, _p.setContentSize); - /** @expose */ - //_p.anchor; - //cc.defineGetterSetter(_p, "anchor", _p._getAnchor, _p._setAnchor); - /** @expose */ _p.anchorX; cc.defineGetterSetter(_p, "anchorX", _p._getAnchorX, _p._setAnchorX); /** @expose */ @@ -117,20 +108,13 @@ _tmp.PrototypeCCNode = function () { /** @expose */ _p.shaderProgram; cc.defineGetterSetter(_p, "shaderProgram", _p.getShaderProgram, _p.setShaderProgram); - /** @expose */ - _p.glServerState; - cc.defineGetterSetter(_p, "glServerState", _p.getGLServerState, _p.setGLServerState); -}; -_tmp.PrototypeCCNodeRGBA = function () { - - var _p = cc.NodeRGBA.prototype; /** @expose */ _p.opacity; cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); /** @expose */ _p.opacityModifyRGB; - cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); + cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB); /** @expose */ _p.cascadeOpacity; cc.defineGetterSetter(_p, "cascadeOpacity", _p.isCascadeOpacityEnabled, _p.setCascadeOpacityEnabled); @@ -140,6 +124,4 @@ _tmp.PrototypeCCNodeRGBA = function () { /** @expose */ _p.cascadeColor; cc.defineGetterSetter(_p, "cascadeColor", _p.isCascadeColorEnabled, _p.setCascadeColorEnabled); -}; - - +}; \ No newline at end of file diff --git a/cocos2d/core/base-nodes/BaseNodesWebGL.js b/cocos2d/core/base-nodes/BaseNodesWebGL.js deleted file mode 100644 index 6216f5cbbf..0000000000 --- a/cocos2d/core/base-nodes/BaseNodesWebGL.js +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -_tmp.WebGLCCNode = function () { - - /** - * CCNode - * @type {Object|Function|cc.Node|*} - * @private - */ - var _p = cc.Node.prototype; - - _p._transform4x4 = null; - _p._stackMatrix = null; - _p._glServerState = null; - _p._camera = null; - - _p.ctor = function () { - var _t = this; - _t._initNode(); - - //WebGL - var mat4 = new cc.kmMat4(); - mat4.mat[2] = mat4.mat[3] = mat4.mat[6] = mat4.mat[7] = mat4.mat[8] = mat4.mat[9] = mat4.mat[11] = mat4.mat[14] = 0.0; - mat4.mat[10] = mat4.mat[15] = 1.0; - _t._transform4x4 = mat4; - _t._glServerState = 0; - _t._stackMatrix = new cc.kmMat4(); - }; - - _p.setNodeDirty = function () { - this._transformDirty === false && (this._transformDirty = this._inverseDirty = true); - }; - - _p.visit = function () { - var _t = this; - // quick return if not visible - if (!_t._visible) - return; - var context = cc._renderContext, i, currentStack = cc.current_stack; - - //cc.kmGLPushMatrixWitMat4(_t._stackMatrix); - //optimize performance for javascript - currentStack.stack.push(currentStack.top); - cc.kmMat4Assign(_t._stackMatrix, currentStack.top); - currentStack.top = _t._stackMatrix; - - var locGrid = _t.grid; - if (locGrid && locGrid._active) - locGrid.beforeDraw(); - - _t.transform(); - - var locChildren = _t._children; - if (locChildren && locChildren.length > 0) { - var childLen = locChildren.length; - _t.sortAllChildren(); - // draw children zOrder < 0 - for (i = 0; i < childLen; i++) { - if (locChildren[i] && locChildren[i]._localZOrder < 0) - locChildren[i].visit(); - else - break; - } - _t.draw(context); - // draw children zOrder >= 0 - for (; i < childLen; i++) { - if (locChildren[i]) { - locChildren[i].visit(); - } - } - } else - _t.draw(context); - - _t.arrivalOrder = 0; - if (locGrid && locGrid._active) - locGrid.afterDraw(_t); - - //cc.kmGLPopMatrix(); - //optimize performance for javascript - currentStack.top = currentStack.stack.pop(); - }; - - _p.transform = function () { - var _t = this; - //optimize performance for javascript - var t4x4 = _t._transform4x4, topMat4 = cc.current_stack.top; - - // Convert 3x3 into 4x4 matrix - //cc.CGAffineToGL(_t.nodeToParentTransform(), _t._transform4x4.mat); - var trans = _t.nodeToParentTransform(); - var t4x4Mat = t4x4.mat; - t4x4Mat[0] = trans.a; - t4x4Mat[4] = trans.c; - t4x4Mat[12] = trans.tx; - t4x4Mat[1] = trans.b; - t4x4Mat[5] = trans.d; - t4x4Mat[13] = trans.ty; - - // Update Z vertex manually - //_t._transform4x4.mat[14] = _t._vertexZ; - t4x4Mat[14] = _t._vertexZ; - - //optimize performance for Javascript - cc.kmMat4Multiply(topMat4, topMat4, t4x4); // = cc.kmGLMultMatrix(_t._transform4x4); - - // XXX: Expensive calls. Camera should be integrated into the cached affine matrix - if (_t._camera != null && !(_t.grid != null && _t.grid.isActive())) { - var apx = _t._anchorPointInPoints.x, apy = _t._anchorPointInPoints.y; - var translate = (apx !== 0.0 || apy !== 0.0); - if (translate){ - if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { - apx = 0 | apx; - apy = 0 | apy; - } - cc.kmGLTranslatef(apx, apy, 0); - _t._camera.locate(); - cc.kmGLTranslatef(-apx, -apy, 0); - } else { - _t._camera.locate(); - } - } - }; - - _p.nodeToParentTransform = _p._nodeToParentTransformForWebGL; - -}; diff --git a/cocos2d/core/base-nodes/CCAtlasNode.js b/cocos2d/core/base-nodes/CCAtlasNode.js index ec305cd204..c2b543931a 100644 --- a/cocos2d/core/base-nodes/CCAtlasNode.js +++ b/cocos2d/core/base-nodes/CCAtlasNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,27 +24,33 @@ THE SOFTWARE. ****************************************************************************/ -/**

cc.AtlasNode is a subclass of cc.Node that implements the cc.RGBAProtocol and
- * cc.TextureProtocol protocol

+/** + *

cc.AtlasNode is a subclass of cc.Node, it knows how to render a TextureAtlas object.

* - *

It knows how to render a TextureAtlas object.
- * If you are going to render a TextureAtlas consider subclassing cc.AtlasNode (or a subclass of cc.AtlasNode)

+ *

If you are going to render a TextureAtlas consider subclassing cc.AtlasNode (or a subclass of cc.AtlasNode)

+ * + *

All features from cc.Node are valid

+ * + *

You can create a cc.AtlasNode with an Atlas file, the width, the height of each item and the quantity of items to render

* - *

All features from cc.Node are valid, plus the following features:
- * - opacity and RGB colors

* @class - * @extends cc.NodeRGBA + * @extends cc.Node + * + * @param {String} tile + * @param {Number} tileWidth + * @param {Number} tileHeight + * @param {Number} itemsToRender + * @example + * var node = new cc.AtlasNode("pathOfTile", 16, 16, 1); * * @property {cc.Texture2D} texture - Current used texture * @property {cc.TextureAtlas} textureAtlas - Texture atlas for cc.AtlasNode * @property {Number} quadsToDraw - Number of quads to draw - * */ -cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ +cc.AtlasNode = cc.Node.extend(/** @lends cc.AtlasNode# */{ textureAtlas: null, quadsToDraw: 0, - RGBAProtocol: true, //! chars per row _itemsPerRow: 0, //! chars per column @@ -54,67 +60,81 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ //! height of each char _itemHeight: 0, - _colorUnmodified: null, - // protocol variables _opacityModifyRGB: false, _blendFunc: null, - _ignoreContentScaleFactor: false, // This variable is only used for CCLabelAtlas FPS display. So plz don't modify its value. + // This variable is only used for CCLabelAtlas FPS display. So plz don't modify its value. + _ignoreContentScaleFactor: false, _className: "AtlasNode", + _textureForCanvas: null, + /** - * Creates a cc.AtlasNode with an Atlas file the width and height of each item and the quantity of items to render - * @constructor + *

Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.

* @param {String} tile * @param {Number} tileWidth * @param {Number} tileHeight * @param {Number} itemsToRender - * @example - * var node = new cc.AtlasNode("pathOfTile", 16, 16, 1); */ ctor: function (tile, tileWidth, tileHeight, itemsToRender) { - cc.NodeRGBA.prototype.ctor.call(this); - this._colorUnmodified = cc.color.WHITE; + cc.Node.prototype.ctor.call(this); this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; this._ignoreContentScaleFactor = false; - itemsToRender !== undefined && this.initWithTileFile(tile, tileWidth, tileHeight, itemsToRender); }, - /** updates the Atlas (indexed vertex array). - * Shall be overridden in subclasses + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + this._renderCmd = new cc.AtlasNode.CanvasRenderCmd(this); + else + this._renderCmd = new cc.AtlasNode.WebGLRenderCmd(this); + }, + + /** + * Updates the Atlas (indexed vertex array). + * Empty implementation, shall be overridden in subclasses + * @function */ updateAtlasValues: function () { - cc.log("cc.AtlasNode.updateAtlasValues(): Shall be overridden in subclasses"); + cc.log(cc._LogInfos.AtlasNode_updateAtlasValues); }, - /** cc.AtlasNode - RGBA protocol + /** + * Get color value of the atlas node + * @function * @return {cc.Color} */ getColor: function () { if (this._opacityModifyRGB) - return this._colorUnmodified; - return cc.NodeRGBA.prototype.getColor.call(this); + return this._renderCmd._colorUnmodified; + return cc.Node.prototype.getColor.call(this); }, /** + * Set whether color should be changed with the opacity value, + * if true, node color will change while opacity changes. + * @function * @param {Boolean} value */ setOpacityModifyRGB: function (value) { var oldColor = this.color; this._opacityModifyRGB = value; - this.color = oldColor; + this.setColor(oldColor); }, /** + * Get whether color should be changed with the opacity value + * @function * @return {Boolean} */ isOpacityModifyRGB: function () { return this._opacityModifyRGB; }, - /** cc.AtlasNode - CocosNodeTexture protocol + /** + * Get node's blend function + * @function * @return {cc.BlendFunc} */ getBlendFunc: function () { @@ -122,7 +142,9 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ }, /** - * BlendFunc setter + * Set node's blend function + * This function accept either cc.BlendFunc object or source value and destination value + * @function * @param {Number | cc.BlendFunc} src * @param {Number} dst */ @@ -134,13 +156,17 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ }, /** - * @param {cc.TextureAtlas} value + * Set the atlas texture + * @function + * @param {cc.TextureAtlas} value The texture */ setTextureAtlas: function (value) { this.textureAtlas = value; }, /** + * Get the atlas texture + * @function * @return {cc.TextureAtlas} */ getTextureAtlas: function () { @@ -148,6 +174,8 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ }, /** + * Get the number of quads to be rendered + * @function * @return {Number} */ getQuadsToDraw: function () { @@ -155,23 +183,21 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ }, /** + * Set the number of quads to be rendered + * @function * @param {Number} quadsToDraw */ setQuadsToDraw: function (quadsToDraw) { this.quadsToDraw = quadsToDraw; }, - _textureForCanvas: null, - _originalTexture: null, - - _uniformColor: null, - _colorF32Array: null, - - /** initializes an cc.AtlasNode with an Atlas file the width and height of each item and the quantity of items to render - * @param {String} tile - * @param {Number} tileWidth - * @param {Number} tileHeight - * @param {Number} itemsToRender + /** + * Initializes an cc.AtlasNode object with an atlas texture file name, the width, the height of each tile and the quantity of tiles to render + * @function + * @param {String} tile The atlas texture file name + * @param {Number} tileWidth The width of each tile + * @param {Number} tileHeight The height of each tile + * @param {Number} itemsToRender The quantity of tiles to be rendered * @return {Boolean} */ initWithTileFile: function (tile, tileWidth, tileHeight, itemsToRender) { @@ -182,216 +208,52 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ }, /** - * initializes an CCAtlasNode with a texture the width and height of each item measured in points and the quantity of items to render - * @param {cc.Texture2D} texture - * @param {Number} tileWidth - * @param {Number} tileHeight - * @param {Number} itemsToRender + * Initializes an CCAtlasNode with an atlas texture, the width, the height of each tile and the quantity of tiles to render + * @function + * @param {cc.Texture2D} texture The atlas texture + * @param {Number} tileWidth The width of each tile + * @param {Number} tileHeight The height of each tile + * @param {Number} itemsToRender The quantity of tiles to be rendered * @return {Boolean} */ - initWithTexture: null, - - _initWithTextureForCanvas: function (texture, tileWidth, tileHeight, itemsToRender) { - this._itemWidth = tileWidth; - this._itemHeight = tileHeight; - - this._opacityModifyRGB = true; - this._originalTexture = texture; - if (!this._originalTexture) { - cc.log("cocos2d: Could not initialize cc.AtlasNode. Invalid Texture."); - return false; - } - this._textureForCanvas = this._originalTexture; - this._calculateMaxItems(); - - this.quadsToDraw = itemsToRender; - return true; - }, - - _initWithTextureForWebGL: function (texture, tileWidth, tileHeight, itemsToRender) { - this._itemWidth = tileWidth; - this._itemHeight = tileHeight; - this._colorUnmodified = cc.color.WHITE; - this._opacityModifyRGB = true; - - this._blendFunc.src = cc.BLEND_SRC; - this._blendFunc.dst = cc.BLEND_DST; - - var locRealColor = this._realColor; - this._colorF32Array = new Float32Array([locRealColor.r / 255.0, locRealColor.g / 255.0, locRealColor.b / 255.0, this._realOpacity / 255.0]); - this.textureAtlas = new cc.TextureAtlas(); - this.textureAtlas.initWithTexture(texture, itemsToRender); - - if (!this.textureAtlas) { - cc.log("cocos2d: Could not initialize cc.AtlasNode. Invalid Texture."); - return false; - } - - this._updateBlendFunc(); - this._updateOpacityModifyRGB(); - this._calculateMaxItems(); - this.quadsToDraw = itemsToRender; - - //shader stuff - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE_UCOLOR); - this._uniformColor = cc._renderContext.getUniformLocation(this.shaderProgram.getProgram(), "u_color"); - return true; - }, - - draw: null, - - /** - * @param {WebGLRenderingContext} ctx renderContext - */ - _drawForWebGL: function (ctx) { - var context = ctx || cc._renderContext; - cc.nodeDrawSetup(this); - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - context.uniform4fv(this._uniformColor, this._colorF32Array); - this.textureAtlas.drawNumberOfQuads(this.quadsToDraw, 0); + initWithTexture: function(texture, tileWidth, tileHeight, itemsToRender){ + return this._renderCmd.initWithTexture(texture, tileWidth, tileHeight, itemsToRender); }, /** + * Set node's color * @function - * @param {cc.Color} color3 + * @param {cc.Color} color Color object created with cc.color(r, g, b). */ - setColor: null, - - _setColorForCanvas: function (color3) { - var locRealColor = this._realColor; - if ((locRealColor.r == color3.r) && (locRealColor.g == color3.g) && (locRealColor.b == color3.b)) - return; - var temp = cc.color(color3.r, color3.g, color3.b); - this._colorUnmodified = color3; - - if (this._opacityModifyRGB) { - var locDisplayedOpacity = this._displayedOpacity; - temp.r = temp.r * locDisplayedOpacity / 255; - temp.g = temp.g * locDisplayedOpacity / 255; - temp.b = temp.b * locDisplayedOpacity / 255; - } - cc.NodeRGBA.prototype.setColor.call(this, color3); - - if (this.texture) { - var element = this._originalTexture.getHtmlElementObj(); - if (!element) - return; - var cacheTextureForColor = cc.textureCache.getTextureColors(element); - if (cacheTextureForColor) { - var textureRect = cc.rect(0, 0, element.width, element.height); - element = cc.generateTintImage(element, cacheTextureForColor, this._realColor, textureRect); - var locTexture = new cc.Texture2D(); - locTexture.initWithElement(element); - locTexture.handleLoadedTexture(); - this.texture = locTexture; - } - } - }, - - _setColorForWebGL: function (color3) { - var temp = cc.color(color3.r, color3.g, color3.b); - this._colorUnmodified = color3; - var locDisplayedOpacity = this._displayedOpacity; - if (this._opacityModifyRGB) { - temp.r = temp.r * locDisplayedOpacity / 255; - temp.g = temp.g * locDisplayedOpacity / 255; - temp.b = temp.b * locDisplayedOpacity / 255; - } - cc.NodeRGBA.prototype.setColor.call(this, color3); - var locDisplayedColor = this._displayedColor; - this._colorF32Array = new Float32Array([locDisplayedColor.r / 255.0, locDisplayedColor.g / 255.0, - locDisplayedColor.b / 255.0, locDisplayedOpacity / 255.0]); + setColor: function(color){ + this._renderCmd.setColor(color); }, /** + * Set node's opacity * @function - * @param {Number} opacity + * @param {Number} opacity The opacity value */ setOpacity: function (opacity) { + this._renderCmd.setOpacity(opacity); }, - _setOpacityForCanvas: function (opacity) { - cc.NodeRGBA.prototype.setOpacity.call(this, opacity); - // special opacity for premultiplied textures - if (this._opacityModifyRGB) { - this.color = this._colorUnmodified; - } - }, - - _setOpacityForWebGL: function (opacity) { - cc.NodeRGBA.prototype.setOpacity.call(this, opacity); - // special opacity for premultiplied textures - if (this._opacityModifyRGB) { - this.color = this._colorUnmodified; - } else { - var locDisplayedColor = this._displayedColor; - this._colorF32Array = new Float32Array([locDisplayedColor.r / 255.0, locDisplayedColor.g / 255.0, - locDisplayedColor.b / 255.0, this._displayedOpacity / 255.0]); - } - }, - - // cc.Texture protocol /** - * returns the used texture + * Get the current texture * @function * @return {cc.Texture2D} */ - getTexture: null, - - _getTextureForCanvas: function () { - return this._textureForCanvas; - }, - - _getTextureForWebGL: function () { - return this.textureAtlas.texture; + getTexture: function(){ + return this._renderCmd.getTexture(); }, /** - * sets a new texture. it will be retained + * Replace the current texture with a new one * @function - * @param {cc.Texture2D} texture + * @param {cc.Texture2D} texture The new texture */ - setTexture: null, - - _setTextureForCanvas: function (texture) { - this._textureForCanvas = texture; - }, - - _setTextureForWebGL: function (texture) { - this.textureAtlas.texture = texture; - this._updateBlendFunc(); - this._updateOpacityModifyRGB(); - }, - - _calculateMaxItems: null, - - _calculateMaxItemsForCanvas: function () { - var selTexture = this.texture; - var size = selTexture.getContentSize(); - - this._itemsPerColumn = 0 | (size.height / this._itemHeight); - this._itemsPerRow = 0 | (size.width / this._itemWidth); - }, - - _calculateMaxItemsForWebGL: function () { - var selTexture = this.texture; - var size = selTexture.getContentSize(); - if (this._ignoreContentScaleFactor) - size = selTexture.getContentSizeInPixels(); - - this._itemsPerColumn = 0 | (size.height / this._itemHeight); - this._itemsPerRow = 0 | (size.width / this._itemWidth); - }, - - _updateBlendFunc: function () { - if (!this.textureAtlas.texture.hasPremultipliedAlpha()) { - this._blendFunc.src = cc.SRC_ALPHA; - this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; - } - }, - - _updateOpacityModifyRGB: function () { - this._opacityModifyRGB = this.textureAtlas.texture.hasPremultipliedAlpha(); + setTexture: function(texture){ + this._renderCmd.setTexture(texture); }, _setIgnoreContentScaleFactor: function (ignoreContentScaleFactor) { @@ -399,25 +261,8 @@ cc.AtlasNode = cc.NodeRGBA.extend(/** @lends cc.AtlasNode# */{ } }); -var _p = cc.AtlasNode.prototype; -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _p.initWithTexture = _p._initWithTextureForWebGL; - _p.draw = _p._drawForWebGL; - _p.setColor = _p._setColorForWebGL; - _p.setOpacity = _p._setOpacityForWebGL; - _p.getTexture = _p._getTextureForWebGL; - _p.setTexture = _p._setTextureForWebGL; - _p._calculateMaxItems = _p._calculateMaxItemsForWebGL; -} else { - _p.initWithTexture = _p._initWithTextureForCanvas; - _p.draw = cc.Node.prototype.draw; - _p.setColor = _p._setColorForCanvas; - _p.setOpacity = _p._setOpacityForCanvas; - _p.getTexture = _p._getTextureForCanvas; - _p.setTexture = _p._setTextureForCanvas; - _p._calculateMaxItems = _p._calculateMaxItemsForCanvas; -} +var _p = cc.AtlasNode.prototype; // Override properties cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); cc.defineGetterSetter(_p, "color", _p.getColor, _p.setColor); @@ -431,18 +276,19 @@ _p.textureAtlas; /** @expose */ _p.quadsToDraw; +cc.EventHelper.prototype.apply(_p); -/** creates a cc.AtlasNode with an Atlas file the width and height of each item and the quantity of items to render +/** + * Creates a cc.AtlasNode with an Atlas file the width and height of each item and the quantity of items to render + * @deprecated since v3.0, please use new construction instead + * @function + * @static * @param {String} tile * @param {Number} tileWidth * @param {Number} tileHeight * @param {Number} itemsToRender * @return {cc.AtlasNode} - * @example - * // example - * var node = cc.AtlasNode.create("pathOfTile", 16, 16, 1); */ cc.AtlasNode.create = function (tile, tileWidth, tileHeight, itemsToRender) { return new cc.AtlasNode(tile, tileWidth, tileHeight, itemsToRender); -}; - +}; \ No newline at end of file diff --git a/cocos2d/core/base-nodes/CCAtlasNodeCanvasRenderCmd.js b/cocos2d/core/base-nodes/CCAtlasNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..64e557c966 --- /dev/null +++ b/cocos2d/core/base-nodes/CCAtlasNodeCanvasRenderCmd.js @@ -0,0 +1,138 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.AtlasNode's rendering objects of Canvas + */ +(function(){ + cc.AtlasNode.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = false; + this._colorUnmodified = cc.color.WHITE; + this._originalTexture = null; + this._texture = null; + }; + + var proto = cc.AtlasNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.AtlasNode.CanvasRenderCmd; + + proto.initWithTexture = function(texture, tileWidth, tileHeight, itemsToRender){ + var node = this._node; + node._itemWidth = tileWidth; + node._itemHeight = tileHeight; + + node._opacityModifyRGB = true; + this._originalTexture = texture; + if (!this._originalTexture) { + cc.log(cc._LogInfos.AtlasNode__initWithTexture); + return false; + } + this._texture = this._originalTexture; + this._calculateMaxItems(); + + node.quadsToDraw = itemsToRender; + return true; + }; + + proto.setColor = function(color3){ + var node = this._node; + var locRealColor = node._realColor; + if ((locRealColor.r === color3.r) && (locRealColor.g === color3.g) && (locRealColor.b === color3.b)) + return; + this._colorUnmodified = color3; + this._changeTextureColor(); + }; + + if(cc.sys._supportCanvasNewBlendModes) + proto._changeTextureColor = function(){ + var node = this._node; + var locTexture = node.getTexture(); + if (locTexture && this._originalTexture) { + var element = this._originalTexture.getHtmlElementObj(); + if(!element) + return; + var locElement = locTexture.getHtmlElementObj(); + var textureRect = cc.rect(0, 0, element.width, element.height); + if (locElement instanceof HTMLCanvasElement) + cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(element, this._colorUnmodified, textureRect, locElement); + else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(element, this._colorUnmodified, textureRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.setTexture(locTexture); + } + } + }; + else + proto._changeTextureColor = function(){ + var node = this._node; + var locElement, locTexture = node.getTexture(); + if (locTexture && this._originalTexture) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + var element = this._originalTexture.getHtmlElementObj(); + var cacheTextureForColor = cc.textureCache.getTextureColors(element); + if (cacheTextureForColor) { + var textureRect = cc.rect(0, 0, element.width, element.height); + if (locElement instanceof HTMLCanvasElement) + cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, this._displayedColor, textureRect, locElement); + else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, this._displayedColor, textureRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.setTexture(locTexture); + } + } + } + }; + + proto.setOpacity = function(opacity){ + var node = this._node; + cc.Node.prototype.setOpacity.call(node, opacity); + // special opacity for premultiplied textures + //if (node._opacityModifyRGB) { + // node.color = this._colorUnmodified; + //} + }; + + proto.getTexture = function(){ + return this._texture; + }; + + proto.setTexture = function (texture) { + this._texture = texture; + }; + + proto._calculateMaxItems = function(){ + var node = this._node; + var selTexture = this._texture; + var size = selTexture.getContentSize(); + + node._itemsPerColumn = 0 | (size.height / node._itemHeight); + node._itemsPerRow = 0 | (size.width / node._itemWidth); + }; +})(); diff --git a/cocos2d/core/base-nodes/CCAtlasNodeWebGLRenderCmd.js b/cocos2d/core/base-nodes/CCAtlasNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..d398f20eef --- /dev/null +++ b/cocos2d/core/base-nodes/CCAtlasNodeWebGLRenderCmd.js @@ -0,0 +1,145 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.AtlasNode's rendering objects of WebGL + */ +(function(){ + cc.AtlasNode.WebGLRenderCmd = function(renderableObject){ + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + this._textureAtlas = null; + this._colorUnmodified = cc.color.WHITE; + this._colorF32Array = null; + this._uniformColor = null; + + //shader stuff + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE_UCOLOR); + this._uniformColor = cc._renderContext.getUniformLocation(this._shaderProgram.getProgram(), "u_color"); + }; + + var proto = cc.AtlasNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.AtlasNode.WebGLRenderCmd; + + proto._updateBlendFunc = function () { + var node = this._node; + if (!this._textureAtlas.texture.hasPremultipliedAlpha()) { + node._blendFunc.src = cc.SRC_ALPHA; + node._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + } + }; + + proto._updateOpacityModifyRGB = function () { + this._node._opacityModifyRGB = this._textureAtlas.texture.hasPremultipliedAlpha(); + }; + + proto.rendering = function (ctx) { + var context = ctx || cc._renderContext, node = this._node; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + if (this._uniformColor && this._colorF32Array) { + context.uniform4fv(this._uniformColor, this._colorF32Array); + this._textureAtlas.drawNumberOfQuads(node.quadsToDraw, 0); + } + }; + + proto.initWithTexture = function(texture, tileWidth, tileHeight, itemsToRender){ + var node = this._node; + node._itemWidth = tileWidth; + node._itemHeight = tileHeight; + this._colorUnmodified = cc.color.WHITE; + node._opacityModifyRGB = true; + + node._blendFunc.src = cc.BLEND_SRC; + node._blendFunc.dst = cc.BLEND_DST; + + var locRealColor = node._realColor; + this._colorF32Array = new Float32Array([locRealColor.r / 255.0, locRealColor.g / 255.0, locRealColor.b / 255.0, node._realOpacity / 255.0]); + this._textureAtlas = new cc.TextureAtlas(); + this._textureAtlas.initWithTexture(texture, itemsToRender); + + if (!this._textureAtlas) { + cc.log(cc._LogInfos.AtlasNode__initWithTexture); + return false; + } + + this._updateBlendFunc(); + this._updateOpacityModifyRGB(); + this._calculateMaxItems(); + node.quadsToDraw = itemsToRender; + + return true; + }; + + proto.setColor = function(color3){ + var temp = cc.color(color3.r, color3.g, color3.b), node = this._node; + this._colorUnmodified = color3; + var locDisplayedOpacity = this._displayedOpacity; + if (node._opacityModifyRGB) { + temp.r = temp.r * locDisplayedOpacity / 255; + temp.g = temp.g * locDisplayedOpacity / 255; + temp.b = temp.b * locDisplayedOpacity / 255; + } + cc.Node.prototype.setColor.call(node, temp); + }; + + proto.setOpacity = function(opacity){ + var node = this._node; + cc.Node.prototype.setOpacity.call(node, opacity); + // special opacity for premultiplied textures + if (node._opacityModifyRGB) { + node.color = this._colorUnmodified; + } + }; + + proto._updateColor = function(){ + var locDisplayedColor = this._displayedColor; + this._colorF32Array = new Float32Array([locDisplayedColor.r / 255.0, locDisplayedColor.g / 255.0, + locDisplayedColor.b / 255.0, this._displayedOpacity / 255.0]); + }; + + proto.getTexture = function(){ + return this._textureAtlas.texture; + }; + + proto.setTexture = function(texture){ + this._textureAtlas.texture = texture; + this._updateBlendFunc(); + this._updateOpacityModifyRGB(); + }; + + proto._calculateMaxItems = function(){ + var node = this._node; + var selTexture = this._textureAtlas.texture; + var size = selTexture.getContentSize(); + if (node._ignoreContentScaleFactor) + size = selTexture.getContentSizeInPixels(); + + node._itemsPerColumn = 0 | (size.height / node._itemHeight); + node._itemsPerRow = 0 | (size.width / node._itemWidth); + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/base-nodes/CCNode.js b/cocos2d/core/base-nodes/CCNode.js index 8435931689..5184a42b9c 100644 --- a/cocos2d/core/base-nodes/CCNode.js +++ b/cocos2d/core/base-nodes/CCNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -30,104 +30,103 @@ * @type Number */ cc.NODE_TAG_INVALID = -1; -/** - * Node on enter - * @constant - */ -cc.NODE_ON_ENTER = null; -/** - * Node on exit - * @constant - */ -cc.NODE_ON_EXIT = null; /** - * XXX: Yes, nodes might have a sort problem once every 15 days if the game runs at 60 FPS and each frame sprites are reordered. - * @type Number + * XXX: Yes, nodes might have a sort problem once every 15 days if the game runs at 60 FPS and each frame sprites are reordered. */ cc.s_globalOrderOfArrival = 1; -/**

cc.Node is the main element. Anything thats gets drawn or contains things that get drawn is a cc.Node.
- The most popular cc.Nodes are: cc.Scene, cc.Layer, cc.Sprite, cc.Menu.

- -

The main features of a cc.Node are:
- - They can contain other cc.Node nodes (addChild, getChildByTag, removeChild, etc)
- - They can schedule periodic callback (schedule, unschedule, etc)
- - They can execute actions (runAction, stopAction, etc)

- -

Some cc.Node nodes provide extra functionality for them or their children.

- -

Subclassing a cc.Node usually means (one/all) of:
- - overriding init to initialize resources and schedule callbacks
- - create callbacks to handle the advancement of time
- - overriding draw to render the node

- -

Features of cc.Node:
- - position
- - scale (x, y)
- - rotation (in degrees, clockwise)
- - anchor point
- - size
- - visible
- - z-order
- - openGL z position

- -

Default values:
- - rotation: 0
- - position: (x=0,y=0)
- - scale: (x=1,y=1)
- - contentSize: (x=0,y=0)
- - anchorPoint: (x=0,y=0)

- -

Limitations:
- - A cc.Node is a "void" object. It doesn't have a texture

- -

Order in transformations with grid disabled
- -# The node will be translated (position)
- -# The node will be rotated (rotation)
- -# The node will be scaled (scale)
- -

Order in transformations with grid enabled
- -# The node will be translated (position)
- -# The node will be rotated (rotation)
- -# The node will be scaled (scale)
- -# The grid will capture the screen
- -# The node will be moved according to the camera values (camera)
- -# The grid will render the captured screen

+/** + *

cc.Node is the root class of all node. Anything that gets drawn or contains things that get drawn is a cc.Node.
+ * The most popular cc.Nodes are: cc.Scene, cc.Layer, cc.Sprite, cc.Menu.

+ * + *

The main features of a cc.Node are:
+ * - They can contain other cc.Node nodes (addChild, getChildByTag, removeChild, etc)
+ * - They can schedule periodic callback (schedule, unschedule, etc)
+ * - They can execute actions (runAction, stopAction, etc)

+ * + *

Some cc.Node nodes provide extra functionality for them or their children.

+ * + *

Subclassing a cc.Node usually means (one/all) of:
+ * - overriding constructor function "ctor" to initialize resources and schedule callbacks
+ * - create callbacks to handle the advancement of time

+ * + *

Features of cc.Node:
+ * - position
+ * - scale (x, y)
+ * - rotation (in degrees, clockwise)
+ * - anchor point
+ * - size
+ * - color
+ * - opacity
+ * - visible
+ * - z-order
+ * - WebGL z position

+ * + *

Default values:
+ * - rotation: 0
+ * - position: (x=0,y=0)
+ * - scale: (x=1,y=1)
+ * - contentSize: (x=0,y=0)
+ * - anchorPoint: (x=0,y=0)
+ * - color: (r=255,g=255,b=255)
+ * - opacity: 255

+ * + *

Limitations:
+ * - A cc.Node is a "void" object. It doesn't have a texture

+ * + *

Order in transformations with grid disabled
+ * -# The node will be translated (position)
+ * -# The node will be rotated (rotation)
+ * -# The node will be scaled (scale)
+ * + *

Order in transformations with grid enabled
+ * -# The node will be translated (position)
+ * -# The node will be rotated (rotation)
+ * -# The node will be scaled (scale)
+ * -# The grid will capture the screen
+ * -# The node will be moved according to the camera values (camera)
+ * -# The grid will render the captured screen

+ * * @class * @extends cc.Class * - * @property {Number} x - x axis position of node - * @property {Number} y - y axis position of node - * @property {Number} width - Width of node - * @property {Number} height - Height of node - * @property {Number} anchorX - Anchor point's position on x axis - * @property {Number} anchorY - Anchor point's position on y axis - * @property {Number} skewX - Skew x - * @property {Number} skewY - Skew y - * @property {Number} zIndex - Z order in depth which stands for the drawing order - * @property {Number} vertexZ - WebGL Z vertex of this node, z order works OK if all the nodes uses the same openGL Z vertex - * @property {Number} rotation - Rotation of node - * @property {Number} rotationX - Rotation on x axis - * @property {Number} rotationY - Rotation on y axis - * @property {Number} scale - Scale of node - * @property {Number} scaleX - Scale on x axis - * @property {Number} scaleY - Scale on y axis - * @property {Array} children - <@readonly> All children nodes - * @property {Number} childrenCount - <@readonly> Number of children - * @property {cc.Node} parent - Parent node - * @property {Boolean} visible - Indicate whether node is visible or not - * @property {Boolean} running - <@readonly> Indicate whether node is running or not - * @property {Boolean} ignoreAnchor - Indicate whether ignore the anchor point property for positionning - * @property {Number} tag - Tag of node - * @property {Object} userData - Custom user data - * @property {Object} userObject - User assigned CCObject, similar to userData, but instead of holding a void* it holds an id - * @property {Number} arrivalOrder - The arrival order, indicates which children is added previously - * @property {cc.ActionManager} actionManager - The CCActionManager object that is used by all actions. - * @property {cc.Scheduler} scheduler - cc.Scheduler used to schedule all "updates" and timers. - * @property {cc.GridBase} grid - grid object that is used when applying effects - * @property {cc.GLProgram} shaderProgram - The shader program currently used for this node - * @property {Number} glServerState - The state of OpenGL server side + * @property {Number} x - x axis position of node + * @property {Number} y - y axis position of node + * @property {Number} width - Width of node + * @property {Number} height - Height of node + * @property {Number} anchorX - Anchor point's position on x axis + * @property {Number} anchorY - Anchor point's position on y axis + * @property {Boolean} ignoreAnchor - Indicate whether ignore the anchor point property for positioning + * @property {Number} skewX - Skew x + * @property {Number} skewY - Skew y + * @property {Number} zIndex - Z order in depth which stands for the drawing order + * @property {Number} vertexZ - WebGL Z vertex of this node, z order works OK if all the nodes uses the same openGL Z vertex + * @property {Number} rotation - Rotation of node + * @property {Number} rotationX - Rotation on x axis + * @property {Number} rotationY - Rotation on y axis + * @property {Number} scale - Scale of node + * @property {Number} scaleX - Scale on x axis + * @property {Number} scaleY - Scale on y axis + * @property {Boolean} visible - Indicate whether node is visible or not + * @property {cc.Color} color - Color of node, default value is white: (255, 255, 255) + * @property {Boolean} cascadeColor - Indicate whether node's color value affect its child nodes, default value is false + * @property {Number} opacity - Opacity of node, default value is 255 + * @property {Boolean} opacityModifyRGB - Indicate whether opacity affect the color value, default value is false + * @property {Boolean} cascadeOpacity - Indicate whether node's opacity value affect its child nodes, default value is false + * @property {Array} children - <@readonly> All children nodes + * @property {Number} childrenCount - <@readonly> Number of children + * @property {cc.Node} parent - Parent node + * @property {Boolean} running - <@readonly> Indicate whether node is running or not + * @property {Number} tag - Tag of node + * @property {Object} userData - Custom user data + * @property {Object} userObject - User assigned CCObject, similar to userData, but instead of holding a void* it holds an id + * @property {Number} arrivalOrder - The arrival order, indicates which children is added previously + * @property {cc.ActionManager} actionManager - The CCActionManager object that is used by all actions. + * @property {cc.Scheduler} scheduler - cc.Scheduler used to schedule all "updates" and timers. + * @property {cc.GridBase} grid - grid object that is used when applying effects + * @property {cc.GLProgram} shaderProgram - The shader program currently used for this node + * @property {Number} glServerState - The state of OpenGL server side */ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ _localZOrder: 0, ///< Local order (relative to its siblings) used to sort the node @@ -139,6 +138,11 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ _scaleX: 1.0, _scaleY: 1.0, _position: null, + + _normalizedPosition:null, + _usingNormalizedPosition: false, + _normalizedPositionDirty: false, + _skewX: 0.0, _skewY: 0.0, // children (lazy allocs), @@ -146,24 +150,16 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ // lazy alloc, _visible: true, _anchorPoint: null, - _anchorPointInPoints: null, _contentSize: null, _running: false, _parent: null, + // "whole screen" objects. like Scenes and Layers, should set _ignoreAnchorPointForPosition to true _ignoreAnchorPointForPosition: false, tag: cc.NODE_TAG_INVALID, - // userData is always inited as nil + // userData is always initialized as nil userData: null, userObject: null, - _transformDirty: true, - _inverseDirty: true, - _cacheDirty: true, - // Cached parent serves to construct the cached parent chain - _cachedParent: null, - _transformGLDirty: null, - _transform: null, - _inverse: null, //since 2.0 api _reorderChildDirty: false, @@ -174,57 +170,72 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ _scheduler: null, _eventDispatcher: null, - _initializedNode: false, _additionalTransformDirty: false, _additionalTransform: null, _componentContainer: null, _isTransitionFinished: false, - _rotationRadiansX: 0, - _rotationRadiansY: 0, _className: "Node", _showNode: false, + _name: "", ///Properties configuration function
- * All properties in attrs will be set to the node,
- * when the setter of the node is available,
- * the property will be set via setter function.
- *

+ *

Properties configuration function
+ * All properties in attrs will be set to the node,
+ * when the setter of the node is available,
+ * the property will be set via setter function.
+ *

+ * @function * @param {Object} attrs Properties to be set to node */ attr: function (attrs) { @@ -301,12 +308,13 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - *

get the skew degrees in X
- * The X skew angle of the node in degrees.
- * This angle describes the shear distortion in the X direction.
- * Thus, it is the angle between the Y axis and the left edge of the shape
- * The default skewX angle is 0. Positive values distort the node in a CW direction.
- *

+ *

Returns the skew degrees in X
+ * The X skew angle of the node in degrees.
+ * This angle describes the shear distortion in the X direction.
+ * Thus, it is the angle between the Y axis and the left edge of the shape
+ * The default skewX angle is 0. Positive values distort the node in a CW direction.
+ *

+ * @function * @return {Number} The X skew angle of the node in degrees. */ getSkewX: function () { @@ -315,26 +323,28 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

- * Changes the X skew angle of the node in degrees.
- *
- * This angle describes the shear distortion in the X direction.
- * Thus, it is the angle between the Y axis and the left edge of the shape
- * The default skewX angle is 0. Positive values distort the node in a CW direction. + * Changes the X skew angle of the node in degrees.
+ *
+ * This angle describes the shear distortion in the X direction.
+ * Thus, it is the angle between the Y axis and the left edge of the shape
+ * The default skewX angle is 0. Positive values distort the node in a CW direction. *

+ * @function * @param {Number} newSkewX The X skew angle of the node in degrees. */ setSkewX: function (newSkewX) { this._skewX = newSkewX; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** - *

get the skew degrees in Y
+ *

Returns the skew degrees in Y
* The Y skew angle of the node in degrees.
* This angle describes the shear distortion in the Y direction.
* Thus, it is the angle between the X axis and the bottom edge of the shape
* The default skewY angle is 0. Positive values distort the node in a CCW direction.
*

+ * @function * @return {Number} The Y skew angle of the node in degrees. */ getSkewY: function () { @@ -349,11 +359,12 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Thus, it is the angle between the X axis and the bottom edge of the shape
* The default skewY angle is 0. Positive values distort the node in a CCW direction.
*

+ * @function * @param {Number} newSkewY The Y skew angle of the node in degrees. */ setSkewY: function (newSkewY) { this._skewY = newSkewY; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** @@ -362,10 +373,12 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * The Node's parent will sort all its children based ont the LocalZOrder value.
* If two nodes have the same LocalZOrder, then the node that was added first to the children's array
* will be in front of the other node in the array.
- *
- * Also, the Scene Graph is traversed using the "In-Order" tree traversal algorithm ( http://en.wikipedia.org/wiki/Tree_traversal#In-order )
+ *
+ * Also, the Scene Graph is traversed using the "In-Order" tree traversal algorithm ( http://en.wikipedia.org/wiki/Tree_traversal#In-order ) + *
* And Nodes that have LocalZOder values < 0 are the "left" subtree
* While Nodes with LocalZOder >=0 are the "right" subtree.

+ * @function * @param {Number} localZOrder */ setLocalZOrder: function (localZOrder) { @@ -375,17 +388,14 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ cc.eventManager._setDirtyForNode(this); }, - /** - * Helper function used by `setLocalZOrder`. Don't use it unless you know what you are doing. - * @param {Number} localZOrder - * @private - */ + //Helper function used by `setLocalZOrder`. Don't use it unless you know what you are doing. _setLocalZOrder: function (localZOrder) { this._localZOrder = localZOrder; }, /** - * Gets the local Z order of this node. + * Returns the local Z order of this node. + * @function * @returns {Number} The local (relative to its siblings) Z order. */ getLocalZOrder: function () { @@ -393,9 +403,10 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * zOrder getter + * Returns z order of this node + * @function * @return {Number} - * @deprecated + * @deprecated since 3.0, please use getLocalZOrder instead */ getZOrder: function () { cc.log(cc._LogInfos.Node_getZOrder); @@ -411,8 +422,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * The larger number it is, the later this node will be drawn in each message loop.
* Please refer to setVertexZ(float) for the difference. *

+ * @function * @param {Number} z Z order of this node. - * @deprecated + * @deprecated since 3.0, please use setLocalZOrder instead */ setZOrder: function (z) { cc.log(cc._LogInfos.Node_setZOrder); @@ -432,17 +444,19 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ *
* Limitations: Global Z Order can't be used used by Nodes that have SpriteBatchNode as one of their ancestors.
* And if ClippingNode is one of the ancestors, then "global Z order" will be relative to the ClippingNode.

+ * @function * @param {Number} globalZOrder */ setGlobalZOrder: function (globalZOrder) { - if (this._globalZOrder != globalZOrder) { + if (this._globalZOrder !== globalZOrder) { this._globalZOrder = globalZOrder; cc.eventManager._setDirtyForNode(this); } }, /** - * Returns the Node's Global Z Order. + * Return the Node's Global Z Order. + * @function * @returns {number} The node's global Z order */ getGlobalZOrder: function () { @@ -450,7 +464,8 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Gets WebGL Z vertex of this node. + * Returns WebGL Z vertex of this node. + * @function * @return {Number} WebGL Z vertex of this node */ getVertexZ: function () { @@ -462,12 +477,13 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Sets the real WebGL Z vertex.
*
* Differences between openGL Z vertex and cocos2d Z order:
- * - OpenGL Z modifies the Z vertex, and not the Z order in the relation between parent-children
- * - OpenGL Z might require to set 2D projection
- * - cocos2d Z order works OK if all the nodes uses the same openGL Z vertex. eg: vertexZ = 0
+ * - WebGL Z modifies the Z vertex, and not the Z order in the relation between parent-children
+ * - WebGL Z might require to set 2D projection
+ * - cocos2d Z order works OK if all the nodes uses the same WebGL Z vertex. eg: vertexZ = 0
*
* @warning Use it at your own risk since it might break the cocos2d parent-children z order *

+ * @function * @param {Number} Var */ setVertexZ: function (Var) { @@ -475,7 +491,8 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * The rotation (angle) of the node in degrees. 0 is the default rotation angle. Positive values rotate node CW. + * Returns the rotation (angle) of the node in degrees. 0 is the default rotation angle. Positive values rotate node clockwise. + * @function * @return {Number} The rotation of the node in degrees. */ getRotation: function () { @@ -491,19 +508,19 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * 0 is the default rotation angle.
* Positive values rotate node clockwise, and negative values for anti-clockwise. *

+ * @function * @param {Number} newRotation The rotation of the node in degrees. */ setRotation: function (newRotation) { this._rotationX = this._rotationY = newRotation; - this._rotationRadiansX = this._rotationX * 0.017453292519943295; //(Math.PI / 180); - this._rotationRadiansY = this._rotationY * 0.017453292519943295; //(Math.PI / 180); - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** - * The rotation (angle) of the node in degrees. 0 is the default rotation angle.
- * Positive values rotate node CW. It only modifies the X rotation performing a horizontal rotational skew . - * (support only in WebGl rendering mode) + * Returns the X axis rotation (angle) which represent a horizontal rotational skew of the node in degrees.
+ * 0 is the default rotation angle. Positive values rotate node clockwise
+ * (support only in WebGL rendering mode) + * @function * @return {Number} The X rotation in degrees. */ getRotationX: function () { @@ -513,7 +530,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

* Sets the X rotation (angle) of the node in degrees which performs a horizontal rotational skew.
- *
+ * (support only in WebGL rendering mode)
* 0 is the default rotation angle.
* Positive values rotate node clockwise, and negative values for anti-clockwise. *

@@ -521,13 +538,14 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ */ setRotationX: function (rotationX) { this._rotationX = rotationX; - this._rotationRadiansX = this._rotationX * 0.017453292519943295; //(Math.PI / 180); - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** - * The rotation (angle) of the node in degrees. 0 is the default rotation angle.
- * Positive values rotate node CW. It only modifies the Y rotation performing a vertical rotational skew . + * Returns the Y axis rotation (angle) which represent a vertical rotational skew of the node in degrees.
+ * 0 is the default rotation angle. Positive values rotate node clockwise
+ * (support only in WebGL rendering mode) + * @function * @return {Number} The Y rotation in degrees. */ getRotationY: function () { @@ -537,21 +555,22 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

* Sets the Y rotation (angle) of the node in degrees which performs a vertical rotational skew.
- *
- * 0 is the default rotation angle.
- * Positive values rotate node clockwise, and negative values for anti-clockwise. + * (support only in WebGL rendering mode)
+ * 0 is the default rotation angle.
+ * Positive values rotate node clockwise, and negative values for anti-clockwise. *

* @param rotationY The Y rotation in degrees. */ setRotationY: function (rotationY) { this._rotationY = rotationY; - this._rotationRadiansY = this._rotationY * 0.017453292519943295; //(Math.PI / 180); - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, - /** Get the scale factor of the node. - * @warning: Assert when _scaleX != _scaleY. - * @return {Number} + /** + * Returns the scale factor of the node. + * @warning: Assertion will fail when _scaleX != _scaleY. + * @function + * @return {Number} The scale factor */ getScale: function () { if (this._scaleX !== this._scaleY) @@ -560,18 +579,20 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * The scale factor of the node. 1.0 is the default scale factor. It modifies the X and Y scale at the same time. + * Sets the scale factor of the node. 1.0 is the default scale factor. This function can modify the X and Y scale at the same time. + * @function * @param {Number} scale or scaleX value * @param {Number} [scaleY=] */ setScale: function (scale, scaleY) { this._scaleX = scale; this._scaleY = (scaleY || scaleY === 0) ? scaleY : scale; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** * Returns the scale factor on X axis of this node + * @function * @return {Number} The scale factor on X axis. */ getScaleX: function () { @@ -581,17 +602,19 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

* Changes the scale factor on X axis of this node
- * The deafult value is 1.0 if you haven't changed it before + * The default value is 1.0 if you haven't changed it before *

+ * @function * @param {Number} newScaleX The scale factor on X axis. */ setScaleX: function (newScaleX) { this._scaleX = newScaleX; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** * Returns the scale factor on Y axis of this node + * @function * @return {Number} The scale factor on Y axis. */ getScaleY: function () { @@ -603,41 +626,70 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Changes the scale factor on Y axis of this node
* The Default value is 1.0 if you haven't changed it before. *

+ * @function * @param {Number} newScaleY The scale factor on Y axis. */ setScaleY: function (newScaleY) { this._scaleY = newScaleY; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** *

- * Changes the position (x,y) of the node in OpenGL coordinates - * Usually we use ccp(x,y) to compose CCPoint object. - * The original point (0,0) is at the left-bottom corner of screen. - * and Passing two numbers (x,y) is much efficient than passing CCPoint object. + * Changes the position (x,y) of the node in cocos2d coordinates.
+ * The original point (0,0) is at the left-bottom corner of screen.
+ * Usually we use cc.p(x,y) to compose CCPoint object.
+ * and Passing two numbers (x,y) is more efficient than passing CCPoint object. *

- * @param {cc.Point|Number} newPosOrxValue The position (x,y) of the node in coordinates or X coordinate for position + * @function + * @param {cc.Point|Number} newPosOrxValue The position (x,y) of the node in coordinates or the X coordinate for position * @param {Number} [yValue] Y coordinate for position * @example - * var size = cc.director.getWinSize(); + * var size = cc.winSize; * node.setPosition(size.width/2, size.height/2); */ setPosition: function (newPosOrxValue, yValue) { var locPosition = this._position; if (yValue === undefined) { + if(locPosition.x === newPosOrxValue.x && locPosition.y === newPosOrxValue.y) + return; locPosition.x = newPosOrxValue.x; locPosition.y = newPosOrxValue.y; } else { + if(locPosition.x === newPosOrxValue && locPosition.y === yValue) + return; locPosition.x = newPosOrxValue; locPosition.y = yValue; } - this.setNodeDirty(); + this._usingNormalizedPosition = false; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); + }, + + /** + *

+ * Sets the position (x,y) using values between 0 and 1.
+ * The positions in pixels is calculated like the following:
+ * _position = _normalizedPosition * parent.getContentSize() + *

+ * @param {cc.Point|Number} posOrX + * @param {Number} [y] + */ + setNormalizedPosition: function(posOrX, y){ + var locPosition = this._normalizedPosition; + if (y === undefined) { + locPosition.x = posOrX.x; + locPosition.y = posOrX.y; + } else { + locPosition.x = posOrX; + locPosition.y = y; + } + this._normalizedPositionDirty = this._usingNormalizedPosition = true; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** - *

Position (x,y) of the node in OpenGL coordinates. (0,0) is the left-bottom corner.

- * @const + *

Returns a copy of the position (x,y) of the node in cocos2d coordinates. (0,0) is the left-bottom corner.

+ * @function * @return {cc.Point} The position (x,y) of the node in OpenGL coordinates */ getPosition: function () { @@ -645,6 +697,16 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** + * returns the normalized position + * @returns {cc.Point} + */ + getNormalizedPosition: function(){ + return cc.p(this._normalizedPosition); + }, + + /** + *

Returns the x axis position of the node in cocos2d coordinates.

+ * @function * @return {Number} */ getPositionX: function () { @@ -652,14 +714,18 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * @param {Number} x + *

Sets the x axis position of the node in cocos2d coordinates.

+ * @function + * @param {Number} x The new position in x axis */ setPositionX: function (x) { this._position.x = x; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** + *

Returns the y axis position of the node in cocos2d coordinates.

+ * @function * @return {Number} */ getPositionY: function () { @@ -667,15 +733,18 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * @param {Number} y + *

Sets the y axis position of the node in cocos2d coordinates.

+ * @function + * @param {Number} y The new position in y axis */ setPositionY: function (y) { this._position.y = y; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** - * Get the amount of children. + * Returns the amount of children. + * @function * @return {Number} The amount of children. */ getChildrenCount: function () { @@ -683,23 +752,25 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Return an array of children
+ * Returns an array of all children
* Composing a "tree" structure is a very important feature of CCNode + * @function * @return {Array} An array of children * @example * //This sample code traverses all children nodes, and set their position to (0,0) * var allChildren = parent.getChildren(); - * for(var i = 0; i< allChildren.length; i++) { - * allChildren[i].setPosition(0,0); - * } + * for(var i = 0; i< allChildren.length; i++) { + * allChildren[i].setPosition(0,0); + * } */ getChildren: function () { return this._children; }, /** - * Determines if the node is visible - * @see setVisible(bool) + * Returns if the node is visible + * @function + * @see cc.Node#setVisible * @return {Boolean} true if the node is visible, false if the node is hidden. */ isVisible: function () { @@ -708,39 +779,46 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Sets whether the node is visible
- * The default value is true, a node is default to visible - * @param {Boolean} Var true if the node is visible, false if the node is hidden. - */ - setVisible: function (Var) { - this._visible = Var; - this.setNodeDirty(); + * The default value is true + * @function + * @param {Boolean} visible Pass true to make the node visible, false to hide the node. + */ + setVisible: function (visible) { + if(this._visible !== visible){ + this._visible = visible; + //if(visible) + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); + cc.renderer.childrenOrderDirty = true; + } }, /** - *

anchorPoint is the point around which all transformations and positioning manipulations take place.
+ *

Returns a copy of the anchor point.
+ * Anchor point is the point around which all transformations and positioning manipulations take place.
* It's like a pin in the node where it is "attached" to its parent.
* The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner.
* But you can use values higher than (1,1) and lower than (0,0) too.
- * The default anchorPoint is (0.5,0.5), so it starts in the center of the node.

- * @const + * The default anchor point is (0.5,0.5), so it starts at the center of the node.

+ * @function * @return {cc.Point} The anchor point of node. */ getAnchorPoint: function () { - return this._anchorPoint; + return cc.p(this._anchorPoint); }, /** *

* Sets the anchor point in percent.
*
- * anchorPoint is the point around which all transformations and positioning manipulations take place.
+ * anchor point is the point around which all transformations and positioning manipulations take place.
* It's like a pin in the node where it is "attached" to its parent.
* The anchorPoint is normalized, like a percentage. (0,0) means the bottom-left corner and (1,1) means the top-right corner.
* But you can use values higher than (1,1) and lower than (0,0) too.
- * The default anchorPoint is (0.5,0.5), so it starts in the center of the node. + * The default anchor point is (0.5,0.5), so it starts at the center of the node. *

- * @param {cc.Point|Number} point The anchor point of node or The anchor point.x of node. - * @param {Number} [y] The anchor point.y of node. + * @function + * @param {cc.Point|Number} point The anchor point of node or The x axis anchor of node. + * @param {Number} [y] The y axis anchor of node. */ setAnchorPoint: function (point, y) { var locAnchorPoint = this._anchorPoint; @@ -755,35 +833,16 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ locAnchorPoint.x = point; locAnchorPoint.y = y; } - var locAPP = this._anchorPointInPoints, locSize = this._contentSize; - locAPP.x = locSize.width * locAnchorPoint.x; - locAPP.y = locSize.height * locAnchorPoint.y; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, - _getAnchor: function () { - return this._anchorPoint; - }, - _setAnchor: function (p) { - var x = p.x, y = p.y; - if (this._anchorPoint.x !== x) { - this._anchorPoint.x = x; - this._anchorPointInPoints.x = this._contentSize.width * x; - } - if (this._anchorPoint.y !== y) { - this._anchorPoint.y = y; - this._anchorPointInPoints.y = this._contentSize.height * y; - } - this.setNodeDirty(); - }, _getAnchorX: function () { return this._anchorPoint.x; }, _setAnchorX: function (x) { if (this._anchorPoint.x === x) return; this._anchorPoint.x = x; - this._anchorPointInPoints.x = this._contentSize.width * x; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, _getAnchorY: function () { return this._anchorPoint.y; @@ -791,19 +850,18 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ _setAnchorY: function (y) { if (this._anchorPoint.y === y) return; this._anchorPoint.y = y; - this._anchorPointInPoints.y = this._contentSize.height * y; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, /** - * The anchorPoint in absolute pixels.
- * you can only read it. If you wish to modify it, use anchorPoint instead - * @see getAnchorPoint() - * @const + * Returns a copy of the anchor point in absolute pixels.
+ * you can only read it. If you wish to modify it, use setAnchorPoint + * @see cc.Node#getAnchorPoint + * @function * @return {cc.Point} The anchor point in absolute pixels. */ getAnchorPointInPoints: function () { - return this._anchorPointInPoints; + return this._renderCmd.getAnchorPointInPoints(); }, _getWidth: function () { @@ -811,27 +869,25 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, _setWidth: function (width) { this._contentSize.width = width; - this._anchorPointInPoints.x = width * this._anchorPoint.x; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, _getHeight: function () { return this._contentSize.height; }, _setHeight: function (height) { this._contentSize.height = height; - this._anchorPointInPoints.y = height * this._anchorPoint.y; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, /** - *

The untransformed size of the node.
+ *

Returns a copy the untransformed size of the node.
* The contentSize remains the same no matter the node is scaled or rotated.
- * All nodes has a size. Layer and Scene has the same size of the screen.

- * @const + * All nodes has a size. Layer and Scene has the same size of the screen by default.

+ * @function * @return {cc.Size} The untransformed size of the node. */ getContentSize: function () { - return this._contentSize; + return cc.size(this._contentSize); }, /** @@ -841,6 +897,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * The contentSize remains the same no matter the node is scaled or rotated.
* All nodes has a size. Layer and Scene has the same size of the screen. *

+ * @function * @param {cc.Size|Number} size The untransformed size of the node or The untransformed size's width of the node. * @param {Number} [height] The untransformed size's height of the node. */ @@ -857,10 +914,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ locContentSize.width = size; locContentSize.height = height; } - var locAPP = this._anchorPointInPoints, locAnchorPoint = this._anchorPoint; - locAPP.x = locContentSize.width * locAnchorPoint.x; - locAPP.y = locContentSize.height * locAnchorPoint.y; - this.setNodeDirty(); + this._renderCmd._updateAnchorPointInPoint(); }, /** @@ -868,6 +922,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Returns whether or not the node accepts event callbacks.
* Running means the node accept event callbacks like onEnter(), onExit(), update() *

+ * @function * @return {Boolean} Whether or not the node is running. */ isRunning: function () { @@ -875,8 +930,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Returns a pointer to the parent node - * @return {cc.Node} A pointer to the parent node + * Returns a reference to the parent node + * @function + * @return {cc.Node} A reference to the parent node */ getParent: function () { return this._parent; @@ -884,16 +940,18 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Sets the parent node - * @param {cc.Node} Var A pointer to the parent node + * @param {cc.Node} parent A reference to the parent node */ - setParent: function (Var) { - this._parent = Var; + setParent: function (parent) { + this._parent = parent; }, /** - * Gets whether the anchor point will be (0,0) when you position this node. - * @see ignoreAnchorPointForPosition(bool) - * @return {Boolean} true if the anchor point will be (0,0) when you position this node. + * Returns whether the anchor point will be ignored when you position this node.
+ * When anchor point ignored, position will be calculated based on the origin point (0, 0) in parent's coordinates. + * @function + * @see cc.Node#ignoreAnchorPointForPosition + * @return {Boolean} true if the anchor point will be ignored when you position this node. */ isIgnoreAnchorPointForPosition: function () { return this._ignoreAnchorPointForPosition; @@ -901,23 +959,24 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

- * Sets whether the anchor point will be (0,0) when you position this node.
- *
+ * Sets whether the anchor point will be ignored when you position this node.
+ * When anchor point ignored, position will be calculated based on the origin point (0, 0) in parent's coordinates.
* This is an internal method, only used by CCLayer and CCScene. Don't call it outside framework.
* The default value is false, while in CCLayer and CCScene are true *

- * @param {Boolean} newValue true if anchor point will be (0,0) when you position this node + * @function + * @param {Boolean} newValue true if anchor point will be ignored when you position this node */ ignoreAnchorPointForPosition: function (newValue) { - if (newValue != this._ignoreAnchorPointForPosition) { + if (newValue !== this._ignoreAnchorPointForPosition) { this._ignoreAnchorPointForPosition = newValue; - this.setNodeDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); } }, /** * Returns a tag that is used to identify the node easily. - * + * @function * @return {Number} An integer that identifies the node. * @example * //You can set tags to node then identify them easily. @@ -948,10 +1007,30 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Changes the tag that is used to identify the node easily.
* Please refer to getTag for the sample code. - * @param {Number} Var A integer that identifies the node. + * @function + * @see cc.Node#getTag + * @param {Number} tag A integer that identifies the node. */ - setTag: function (Var) { - this.tag = Var; + setTag: function (tag) { + this.tag = tag; + }, + + /** + * Changes the name that is used to identify the node easily. + * @function + * @param {String} name + */ + setName: function(name){ + this._name = name; + }, + + /** + * Returns a string that is used to identify the node. + * @function + * @returns {string} A string that identifies the node. + */ + getName: function(){ + return this._name; }, /** @@ -959,6 +1038,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Returns a custom user data pointer
* You can set everything in UserData pointer, a data block, a structure or an object. *

+ * @function * @return {object} A custom user data pointer */ getUserData: function () { @@ -967,10 +1047,11 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

- * Sets a custom user data pointer
- * You can set everything in UserData pointer, a data block, a structure or an object, etc. + * Sets a custom user data reference
+ * You can set everything in UserData reference, a data block, a structure or an object, etc. *

- * @warning Don't forget to release the memory manually,especially before you change this data pointer, and before this node is autoreleased. + * @function + * @warning Don't forget to release the memory manually in JSB, especially before you change this data pointer, and before this node is autoreleased. * @param {object} Var A custom user data */ setUserData: function (Var) { @@ -978,8 +1059,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Returns a user assigned CCObject.
- * Similar to userData, but instead of holding a void* it holds an id + * Returns a user assigned cocos2d object.
+ * Similar to userData, but instead of holding all kinds of data it can only hold a cocos2d object + * @function * @return {object} A user assigned CCObject */ getUserObject: function () { @@ -988,22 +1070,22 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

- * Returns a user assigned CCObject
- * Similar to UserData, but instead of holding a void* it holds an object.
- * The UserObject will be retained once in this method, and the previous UserObject (if existed) will be release.
+ * Sets a user assigned cocos2d object
+ * Similar to UserData, but instead of holding all kinds of data it can only hold a cocos2d object
+ * In JSB, the UserObject will be retained once in this method, and the previous UserObject (if existed) will be release.
* The UserObject will be released in CCNode's destruction. *

- * @param {object} newValue A user assigned CCObject + * @param {object} newValue A user cocos2d object */ setUserObject: function (newValue) { - if (this.userObject != newValue) { + if (this.userObject !== newValue) this.userObject = newValue; - } }, /** - * Returns the arrival order, indicates which children is added previously. + * Returns the arrival order, indicates which children should be added previously. + * @function * @return {Number} The arrival order. */ getOrderOfArrival: function () { @@ -1017,6 +1099,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * A node which called addChild subsequently will take a larger arrival order,
* If two children have the same Z order, the child with larger arrival order will be drawn later. *

+ * @function * @warning This method is used internally for zOrder sorting, don't change this manually * @param {Number} Var The arrival order. */ @@ -1025,25 +1108,26 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - *

Gets the CCActionManager object that is used by all actions.
+ *

Returns the CCActionManager object that is used by all actions.
* (IMPORTANT: If you set a new cc.ActionManager, then previously created actions are going to be removed.)

- * @see setActionManager() + * @function + * @see cc.Node#setActionManager * @return {cc.ActionManager} A CCActionManager object. */ getActionManager: function () { - if (!this._actionManager) { + if (!this._actionManager) this._actionManager = cc.director.getActionManager(); - } return this._actionManager; }, /** *

Sets the cc.ActionManager object that is used by all actions.

+ * @function * @warning If you set a new CCActionManager, then previously created actions will be removed. * @param {cc.ActionManager} actionManager A CCActionManager object that is used by all actions. */ setActionManager: function (actionManager) { - if (this._actionManager != actionManager) { + if (this._actionManager !== actionManager) { this.stopAllActions(); this._actionManager = actionManager; } @@ -1051,27 +1135,28 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** *

- * cc.Scheduler used to schedule all "updates" and timers.
- * IMPORTANT: If you set a new cc.Scheduler, then previously created timers/update are going to be removed. + * Returns the cc.Scheduler object used to schedule all "updates" and timers. *

+ * @function * @return {cc.Scheduler} A CCScheduler object. */ getScheduler: function () { - if (!this._scheduler) { + if (!this._scheduler) this._scheduler = cc.director.getScheduler(); - } return this._scheduler; }, /** *

* Sets a CCScheduler object that is used to schedule all "updates" and timers.
+ * IMPORTANT: If you set a new cc.Scheduler, then previously created timers/update are going to be removed. *

+ * @function * @warning If you set a new CCScheduler, then previously created timers/update are going to be removed. * @param scheduler A cc.Scheduler object that is used to schedule all "update" and timers. */ setScheduler: function (scheduler) { - if (this._scheduler != scheduler) { + if (this._scheduler !== scheduler) { this.unscheduleAllCallbacks(); this._scheduler = scheduler; } @@ -1079,18 +1164,28 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Returns a "local" axis aligned bounding box of the node.
- * The returned box is relative only to its parent. - * @note This method returns a temporary variable, so it can't returns const CCRect& - * @const + * @deprecated since v3.0, please use getBoundingBox instead * @return {cc.Rect} */ + boundingBox: function(){ + cc.log(cc._LogInfos.Node_boundingBox); + return this.getBoundingBox(); + }, + + /** + * Returns a "local" axis aligned bounding box of the node.
+ * The returned box is relative only to its parent. + * @function + * @return {cc.Rect} The calculated bounding box of the node + */ getBoundingBox: function () { var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); - return cc._RectApplyAffineTransformIn(rect, this.nodeToParentTransform()); + return cc._rectApplyAffineTransformIn(rect, this.getNodeToParentTransform()); }, /** * Stops all running actions and schedulers + * @function */ cleanup: function () { // actions @@ -1101,63 +1196,101 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ cc.eventManager.removeListeners(this); // timers - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.cleanup); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.cleanup); }, // composition: GET /** - * Gets a child from the container given its tag + * Returns a child from the container given its tag + * @function * @param {Number} aTag An identifier to find the child node. * @return {cc.Node} a CCNode object whose tag equals to the input parameter */ getChildByTag: function (aTag) { var __children = this._children; - if (__children != null) { + if (__children !== null) { for (var i = 0; i < __children.length; i++) { var node = __children[i]; - if (node && node.tag == aTag) + if (node && node.tag === aTag) return node; } } - //throw "not found"; return null; }, + + /** + * Returns a child from the container given its name + * @function + * @param {String} name A name to find the child node. + * @return {cc.Node} a CCNode object whose name equals to the input parameter + */ + getChildByName: function(name){ + if(!name){ + cc.log("Invalid name"); + return null; + } + + var locChildren = this._children; + for(var i = 0, len = locChildren.length; i < len; i++){ + if(locChildren[i]._name === name) + return locChildren[i]; + } + return null; + }, + // composition: ADD - /**

"add" logic MUST only be on this method

+ /**

"add" logic MUST only be in this method

* *

If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately.

- * + * @function * @param {cc.Node} child A child node * @param {Number} [localZOrder=] Z order for drawing priority. Please refer to setZOrder(int) * @param {Number} [tag=] A integer to identify the node easily. Please refer to setTag(int) */ addChild: function (child, localZOrder, tag) { + localZOrder = localZOrder === undefined ? child._localZOrder : localZOrder; + var name, setTag = false; + if(cc.isUndefined(tag)){ + tag = undefined; + name = child._name; + } else if(cc.isString(tag)){ + name = tag; + tag = undefined; + } else if(cc.isNumber(tag)){ + setTag = true; + name = ""; + } cc.assert(child, cc._LogInfos.Node_addChild_3); + cc.assert(child._parent === null, "child already added. It can't be added again"); - if (child === this) { - cc.log(cc._LogInfos.Node_addChild); - return; - } + this._addChildHelper(child, localZOrder, tag, name, setTag); + }, - if (child._parent !== null) { - cc.log(cc._LogInfos.Node_addChild_2); - return; - } + _addChildHelper: function(child, localZOrder, tag, name, setTag){ + if(!this._children) + this._children = []; + + this._insertChild(child, localZOrder); + if(setTag) + child.setTag(tag); + else + child.setName(name); - var tmpzOrder = (localZOrder != null) ? localZOrder : child._localZOrder; - child.tag = (tag != null) ? tag : child.tag; - this._insertChild(child, tmpzOrder); - child._parent = this; - this._cachedParent && (child._cachedParent = this._cachedParent); + child.setParent(this); + child.setOrderOfArrival(cc.s_globalOrderOfArrival++); - if (this._running) { + if( this._running ){ child.onEnter(); // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter if (this._isTransitionFinished) child.onEnterTransitionDidFinish(); } + if (this._cascadeColorEnabled) + child._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); + if (this._cascadeOpacityEnabled) + child._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); }, // composition: REMOVE @@ -1165,12 +1298,13 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Remove itself from its parent node. If cleanup is true, then also remove all actions and callbacks.
* If the cleanup parameter is not passed, it will force a cleanup.
* If the node orphan, then nothing happens. - * @param {Boolean} cleanup true if all actions and callbacks on this node should be removed, false otherwise. - * @see removeFromParentAndCleanup(bool) + * @function + * @param {Boolean} [cleanup=true] true if all actions and callbacks on this node should be removed, false otherwise. + * @see cc.Node#removeFromParentAndCleanup */ removeFromParent: function (cleanup) { if (this._parent) { - if (cleanup == null) + if (cleanup === undefined) cleanup = true; this._parent.removeChild(this, cleanup); } @@ -1179,8 +1313,8 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Removes this node itself from its parent node.
* If the node orphan, then nothing happens. - * @deprecated - * @param {Boolean} cleanup true if all actions and callbacks on this node should be removed, false otherwise. + * @deprecated since v3.0, please use removeFromParent() instead + * @param {Boolean} [cleanup=true] true if all actions and callbacks on this node should be removed, false otherwise. */ removeFromParentAndCleanup: function (cleanup) { cc.log(cc._LogInfos.Node_removeFromParentAndCleanup); @@ -1189,39 +1323,41 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /**

Removes a child from the container. It will also cleanup all running actions depending on the cleanup parameter.

* If the cleanup parameter is not passed, it will force a cleanup.
- *

"remove" logic MUST only be on this method
+ *

"remove" logic MUST only be on this method
* If a class wants to extend the 'removeChild' behavior it only needs
* to override this method

- * + * @function * @param {cc.Node} child The child node which will be removed. - * @param {Boolean|null} [cleanup=null] true if all running actions and callbacks on the child node will be cleanup, false otherwise. + * @param {Boolean} [cleanup=true] true if all running actions and callbacks on the child node will be cleanup, false otherwise. */ removeChild: function (child, cleanup) { // explicit nil handling if (this._children.length === 0) return; - if (cleanup == null) + if (cleanup === undefined) cleanup = true; if (this._children.indexOf(child) > -1) this._detachChild(child, cleanup); - this.setNodeDirty(); + //this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.visibleDirty); + cc.renderer.childrenOrderDirty = true; }, /** * Removes a child from the container by tag value. It will also cleanup all running actions depending on the cleanup parameter. * If the cleanup parameter is not passed, it will force a cleanup.
+ * @function * @param {Number} tag An integer number that identifies a child node - * @param {Boolean} cleanup true if all running actions and callbacks on the child node will be cleanup, false otherwise. - * @see removeChildByTag(int, bool) + * @param {Boolean} [cleanup=true] true if all running actions and callbacks on the child node will be cleanup, false otherwise. + * @see cc.Node#removeChildByTag */ removeChildByTag: function (tag, cleanup) { if (tag === cc.NODE_TAG_INVALID) cc.log(cc._LogInfos.Node_removeChildByTag); var child = this.getChildByTag(tag); - if (child == null) + if (!child) cc.log(cc._LogInfos.Node_removeChildByTag_2, tag); else this.removeChild(child, cleanup); @@ -1229,50 +1365,46 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter. - * @deprecated - * @param {Boolean | null } cleanup + * @param {Boolean} [cleanup=true] */ removeAllChildrenWithCleanup: function (cleanup) { - cc.log(cc._LogInfos.Node_removeAllChildrenWithCleanup); this.removeAllChildren(cleanup); }, /** * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter.
* If the cleanup parameter is not passed, it will force a cleanup.
- * @param {Boolean | null } cleanup true if all running actions on all children nodes should be cleanup, false otherwise. + * @function + * @param {Boolean} [cleanup=true] true if all running actions on all children nodes should be cleanup, false otherwise. */ removeAllChildren: function (cleanup) { // not using detachChild improves speed here var __children = this._children; - if (__children != null) { - if (cleanup == null) + if (__children !== null) { + if (cleanup === undefined) cleanup = true; for (var i = 0; i < __children.length; i++) { var node = __children[i]; if (node) { - // IMPORTANT: - // -1st do onExit - // -2nd cleanup if (this._running) { node.onExitTransitionDidStart(); node.onExit(); } + + // If you don't do cleanup, the node's actions will not get removed and the if (cleanup) node.cleanup(); + // set parent nil at the end node.parent = null; + node._renderCmd.detachFromParent(); } } this._children.length = 0; + cc.renderer.childrenOrderDirty = true; } }, - /** - * @param {cc.Node} child - * @param {Boolean} doCleanup - * @private - */ _detachChild: function (child, doCleanup) { // IMPORTANT: // -1st do onExit @@ -1283,39 +1415,37 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ } // If you don't do cleanup, the child's actions will not get removed and the - // its scheduledSelectors_ dict will not get released! if (doCleanup) child.cleanup(); // set parent nil at the end child.parent = null; - + child._renderCmd.detachFromParent(); cc.arrayRemoveObject(this._children, child); }, - /** helper used by reorderChild & add - * @param {cc.Node} child - * @param {Number} z - * @private - */ _insertChild: function (child, z) { - this._reorderChildDirty = true; + cc.renderer.childrenOrderDirty = this._reorderChildDirty = true; this._children.push(child); child._setLocalZOrder(z); }, + setNodeDirty: function(){ + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); + }, + /** Reorders a child according to a new z value.
* The child MUST be already added. + * @function * @param {cc.Node} child An already added child node. It MUST be already added. * @param {Number} zOrder Z order for drawing priority. Please refer to setZOrder(int) */ reorderChild: function (child, zOrder) { - cc.assert(child, cc._LogInfos.Node_reorderChild) - this._reorderChildDirty = true; + cc.assert(child, cc._LogInfos.Node_reorderChild); + cc.renderer.childrenOrderDirty = this._reorderChildDirty = true; child.arrivalOrder = cc.s_globalOrderOfArrival; cc.s_globalOrderOfArrival++; child._setLocalZOrder(zOrder); - this.setNodeDirty(); }, /** @@ -1323,27 +1453,31 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Sorts the children array once before drawing, instead of every time when a child is added or reordered.
* This approach can improves the performance massively. *

+ * @function * @note Don't call this manually unless a child added needs to be removed in the same frame */ sortAllChildren: function () { if (this._reorderChildDirty) { var _children = this._children; - var i, j, length = _children.length, tempChild; // insertion sort - for (i = 0; i < length; i++) { - var tempItem = _children[i]; + var len = _children.length, i, j, tmp; + for(i=1; i= 0 && ( tempItem._localZOrder < tempChild._localZOrder || - ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { - _children[j + 1] = tempChild; - j = j - 1; - tempChild = _children[j]; + while(j >= 0){ + if(tmp._localZOrder < _children[j]._localZOrder){ + _children[j+1] = _children[j]; + }else if(tmp._localZOrder === _children[j]._localZOrder && tmp.arrivalOrder < _children[j].arrivalOrder){ + _children[j+1] = _children[j]; + }else{ + break; + } + j--; } - _children[j + 1] = tempItem; + _children[j+1] = tmp; } //don't need to check children recursively, that's done in visit of each child @@ -1351,18 +1485,10 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ } }, - // draw - /**

Override this method to draw your own node.
- * The following GL states will be enabled by default:
- - glEnableClientState(GL_VERTEX_ARRAY);
- - glEnableClientState(GL_COLOR_ARRAY);
- - glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- - glEnable(GL_TEXTURE_2D);

- -

AND YOU SHOULD NOT DISABLE THEM AFTER DRAWING YOUR NODE

- -

But if you enable any other GL state, you should disable it after drawing your node.

- * @param {CanvasContext} ctx + /** + * Render function using the canvas 2d context or WebGL context, internal usage only, please do not call this function + * @function + * @param {CanvasRenderingContext2D | WebGLRenderingContext} ctx The render context */ draw: function (ctx) { // override me @@ -1370,12 +1496,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ // DON'T draw your stuff outside this method }, - /** performs OpenGL view-matrix transformation of it's ancestors.
- * Generally the ancestors are already transformed, but in certain cases (eg: attaching a FBO)
- * it's necessary to transform the ancestors again. - */ + // Internal use only, do not call it by yourself, transformAncestors: function () { - if (this._parent != null) { + if (this._parent !== null) { this._parent.transformAncestors(); this._parent.transform(); } @@ -1387,13 +1510,14 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Event callback that is invoked every time when CCNode enters the 'stage'.
* If the CCNode enters the 'stage' with a transition, this event is called when the transition starts.
* During onEnter you can't access a "sister/brother" node.
- * If you override onEnter, you shall call its parent's one, e.g., CCNode::onEnter(). + * If you override onEnter, you must call its parent's onEnter function with this._super(). *

+ * @function */ onEnter: function () { this._isTransitionFinished = false; this._running = true;//should be running before resumeSchedule - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnter); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.onEnter); this.resume(); }, @@ -1401,20 +1525,23 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ *

* Event callback that is invoked when the CCNode enters in the 'stage'.
* If the CCNode enters the 'stage' with a transition, this event is called when the transition finishes.
- * If you override onEnterTransitionDidFinish, you shall call its parent's one, e.g. CCNode::onEnterTransitionDidFinish() + * If you override onEnterTransitionDidFinish, you shall call its parent's onEnterTransitionDidFinish with this._super() *

+ * @function */ onEnterTransitionDidFinish: function () { this._isTransitionFinished = true; - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onEnterTransitionDidFinish); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.onEnterTransitionDidFinish); }, /** *

callback that is called every time the cc.Node leaves the 'stage'.
- * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition starts.

+ * If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition starts.
+ * If you override onExitTransitionDidStart, you shall call its parent's onExitTransitionDidStart with this._super()

+ * @function */ onExitTransitionDidStart: function () { - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExitTransitionDidStart); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.onExitTransitionDidStart); }, /** @@ -1422,28 +1549,27 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * callback that is called every time the cc.Node leaves the 'stage'.
* If the cc.Node leaves the 'stage' with a transition, this callback is called when the transition finishes.
* During onExit you can't access a sibling node.
- * If you override onExit, you shall call its parent's one, e.g., CCNode::onExit(). + * If you override onExit, you shall call its parent's onExit with this._super(). *

+ * @function */ onExit: function () { this._running = false; this.pause(); - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.onExit); - if (this._componentContainer) { - this._componentContainer.removeAll(); - } + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.onExit); + this.removeAllComponents(); }, // actions /** * Executes an action, and returns the action that is executed.
- * The node becomes the action's target. Refer to CCAction::getTarget() + * The node becomes the action's target. Refer to cc.Action's getTarget() + * @function * @warning Starting from v0.8 actions don't retain their target anymore. * @param {cc.Action} action * @return {cc.Action} An Action pointer */ runAction: function (action) { - cc.assert(action, cc._LogInfos.Node_runAction); this.actionManager.addAction(action, this, !this._running); @@ -1452,6 +1578,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Stops and removes all actions from the running action list . + * @function */ stopAllActions: function () { this.actionManager && this.actionManager.removeAllActionsFromTarget(this); @@ -1459,6 +1586,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Stops and removes an action from the running action list. + * @function * @param {cc.Action} action An action object to be removed. */ stopAction: function (action) { @@ -1467,6 +1595,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Removes an action from the running action list by its tag. + * @function * @param {Number} tag A tag that indicates the action to be removed. */ stopActionByTag: function (tag) { @@ -1478,8 +1607,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Gets an action from the running action list by its tag. - * @see setTag(int), getTag(). + * Returns an action from the running action list by its tag. + * @function + * @see cc.Node#getTag and cc.Node#setTag * @param {Number} tag * @return {cc.Action} The action object with the given tag. */ @@ -1491,10 +1621,11 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ return this.actionManager.getActionByTag(tag, this); }, - /** Returns the numbers of actions that are running plus the ones that are schedule to run (actions in actionsToAdd and actions arrays).
+ /**

Returns the numbers of actions that are running plus the ones that are schedule to run (actions in actionsToAdd and actions arrays).
* Composable actions are counted as 1 action. Example:
* If you are running 1 Sequence of 7 actions, it will return 1.
- * If you are running 7 Sequences of 2 actions, it will return 7. + * If you are running 7 Sequences of 2 actions, it will return 7.

+ * @function * @return {Number} The number of actions that are running plus the ones that are schedule to run */ getNumberOfRunningActions: function () { @@ -1504,10 +1635,11 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ // cc.Node - Callbacks // timers /** - * schedules the "update" method.
+ *

schedules the "update" method.
* It will use the order number 0. This method will be called every frame.
* Scheduled methods with a lower order value will be called before the ones that have a higher order value.
- * Only one "update" method could be scheduled per node. + * Only one "update" method could be scheduled per node.

+ * @function */ scheduleUpdate: function () { this.scheduleUpdateWithPriority(0); @@ -1520,77 +1652,137 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Scheduled callback functions with a lower priority will be called before the ones that have a higher value.
* Only one "update" callback function could be scheduled per node (You can't have 2 'update' callback functions).
*

+ * @function * @param {Number} priority */ scheduleUpdateWithPriority: function (priority) { - this.scheduler.scheduleUpdateForTarget(this, priority, !this._running); + this.scheduler.scheduleUpdate(this, priority, !this._running); }, /** - * unschedules the "update" method. - * @see scheduleUpdate(); + * Unschedules the "update" method. + * @function + * @see cc.Node#scheduleUpdate */ unscheduleUpdate: function () { - this.scheduler.unscheduleUpdateForTarget(this); + this.scheduler.unscheduleUpdate(this); }, /** - * Schedules a custom selector.
- * If the selector is already scheduled, then the interval parameter will be updated without scheduling it again. - * - * @param {function} callback_fn A function wrapped as a selector + *

Schedules a custom selector.
+ * If the selector is already scheduled, then the interval parameter will be updated without scheduling it again.

+ * @function + * @param {function} callback A function wrapped as a selector * @param {Number} interval Tick interval in seconds. 0 means tick every frame. If interval = 0, it's recommended to use scheduleUpdate() instead. * @param {Number} repeat The selector will be executed (repeat + 1) times, you can use kCCRepeatForever for tick infinitely. * @param {Number} delay The amount of time that the first tick will wait before execution. - */ - schedule: function (callback_fn, interval, repeat, delay) { - interval = interval || 0; - - cc.assert(callback_fn, cc._LogInfos.Node_schedule); + * @param {String} key The only string identifying the callback + */ + schedule: function (callback, interval, repeat, delay, key) { + var len = arguments.length; + if(typeof callback === "function"){ + //callback, interval, repeat, delay, key + if(len === 1){ + //callback + interval = 0; + repeat = cc.REPEAT_FOREVER; + delay = 0; + key = this.__instanceId; + }else if(len === 2){ + if(typeof interval === "number"){ + //callback, interval + repeat = cc.REPEAT_FOREVER; + delay = 0; + key = this.__instanceId; + }else{ + //callback, key + key = interval; + interval = 0; + repeat = cc.REPEAT_FOREVER; + delay = 0; + } + }else if(len === 3){ + if(typeof repeat === "string"){ + //callback, interval, key + key = repeat; + repeat = cc.REPEAT_FOREVER; + }else{ + //callback, interval, repeat + key = this.__instanceId; + } + delay = 0; + }else if(len === 4){ + key = this.__instanceId; + } + }else{ + //selector + //selector, interval + //selector, interval, repeat, delay + if(len === 1){ + interval = 0; + repeat = cc.REPEAT_FOREVER; + delay = 0; + }else if(len === 2){ + repeat = cc.REPEAT_FOREVER; + delay = 0; + } + } + cc.assert(callback, cc._LogInfos.Node_schedule); cc.assert(interval >= 0, cc._LogInfos.Node_schedule_2); + interval = interval || 0; repeat = (repeat == null) ? cc.REPEAT_FOREVER : repeat; delay = delay || 0; - this.scheduler.scheduleCallbackForTarget(this, callback_fn, interval, repeat, delay, !this._running); + this.scheduler.schedule(callback, this, interval, repeat, delay, !this._running, key); }, /** * Schedules a callback function that runs only once, with a delay of 0 or larger - * @see schedule(SEL_SCHEDULE, float, unsigned int, float) - * @param {function} callback_fn A function wrapped as a selector + * @function + * @see cc.Node#schedule + * @param {function} callback A function wrapped as a selector * @param {Number} delay The amount of time that the first tick will wait before execution. + * @param {String} key The only string identifying the callback */ - scheduleOnce: function (callback_fn, delay) { - this.schedule(callback_fn, 0.0, 0, delay); + scheduleOnce: function (callback, delay, key) { + //selector, delay + //callback, delay, key + if(key === undefined) + key = this.__instanceId; + this.schedule(callback, 0, 0, delay, key); }, /** * unschedules a custom callback function. - * @see schedule(SEL_SCHEDULE, float, unsigned int, float) + * @function + * @see cc.Node#schedule * @param {function} callback_fn A function wrapped as a selector */ unschedule: function (callback_fn) { - // explicit nil handling + //key + //selector if (!callback_fn) return; - this.scheduler.unscheduleCallbackForTarget(this, callback_fn); + this.scheduler.unschedule(callback_fn, this); }, /** - * unschedule all scheduled callback functions: custom callback functions, and the 'update' callback function.
- * Actions are not affected by this method. + *

unschedule all scheduled callback functions: custom callback functions, and the 'update' callback function.
+ * Actions are not affected by this method.

+ * @function */ unscheduleAllCallbacks: function () { - this.scheduler.unscheduleAllCallbacksForTarget(this); + this.scheduler.unscheduleAllForTarget(this); }, /** * Resumes all scheduled selectors and actions.
* This method is called internally by onEnter - * @deprecated + * @function + * @deprecated since v3.0, please use resume() instead */ resumeSchedulerAndActions: function () { cc.log(cc._LogInfos.Node_resumeSchedulerAndActions); @@ -1598,8 +1790,8 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Resumes all scheduled selectors and actions.
- * This method is called internally by onEnter + *

Resumes all scheduled selectors and actions.
+ * This method is called internally by onEnter

*/ resume: function () { this.scheduler.resumeTarget(this); @@ -1608,9 +1800,10 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Pauses all scheduled selectors and actions.
- * This method is called internally by onExit - * @deprecated + *

Pauses all scheduled selectors and actions.
+ * This method is called internally by onExit

+ * @deprecated since v3.0, please use pause instead + * @function */ pauseSchedulerAndActions: function () { cc.log(cc._LogInfos.Node_pauseSchedulerAndActions); @@ -1618,8 +1811,9 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - * Pauses all scheduled selectors and actions.
- * This method is called internally by onExit + *

Pauses all scheduled selectors and actions.
+ * This method is called internally by onExit

+ * @function */ pause: function () { this.scheduler.pauseTarget(this); @@ -1628,18 +1822,20 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** - *

Sets the additional transform.
- * The additional transform will be concatenated at the end of nodeToParentTransform.
+ *

Sets the additional transform.
+ * The additional transform will be concatenated at the end of getNodeToParentTransform.
* It could be used to simulate `parent-child` relationship between two nodes (e.g. one is in BatchNode, another isn't).
*

+ * @function + * @param {cc.AffineTransform} additionalTransform The additional transform * @example * // create a batchNode - * var batch= cc.SpriteBatchNode.create("Icon-114.png"); + * var batch = new cc.SpriteBatchNode("Icon-114.png"); * this.addChild(batch); * * // create two sprites, spriteA will be added to batchNode, they are using different textures. - * var spriteA = cc.Sprite.create(batch->getTexture()); - * var spriteB = cc.Sprite.create("Icon-72.png"); + * var spriteA = new cc.Sprite(batch->getTexture()); + * var spriteB = new cc.Sprite("Icon-72.png"); * * batch.addChild(spriteA); * @@ -1651,7 +1847,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * spriteA.setPosition(ccp(200, 200)); * * // Gets the spriteA's transform. - * var t = spriteA.nodeToParentTransform(); + * var t = spriteA.getNodeToParentTransform(); * * // Sets the additional transform to spriteB, spriteB's position will based on its pseudo parent i.e. spriteA. * spriteB.setAdditionalTransform(t); @@ -1660,7 +1856,7 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * spriteA.setScale(2); * * // Gets the spriteA's transform. - * t = spriteA.nodeToParentTransform(); + * t = spriteA.getNodeToParentTransform(); * * // Sets the additional transform to spriteB, spriteB's scale will based on its pseudo parent i.e. spriteA. * spriteB.setAdditionalTransform(t); @@ -1669,85 +1865,117 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * spriteA.setRotation(20); * * // Gets the spriteA's transform. - * t = spriteA.nodeToParentTransform(); + * t = spriteA.getNodeToParentTransform(); * * // Sets the additional transform to spriteB, spriteB's rotation will based on its pseudo parent i.e. spriteA. * spriteB.setAdditionalTransform(t); */ setAdditionalTransform: function (additionalTransform) { + if(additionalTransform === undefined) + return this._additionalTransformDirty = false; this._additionalTransform = additionalTransform; - this._transformDirty = true; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); this._additionalTransformDirty = true; }, /** * Returns the matrix that transform parent's space coordinates to the node's (local) space coordinates.
* The matrix is in Pixels. + * @function * @return {cc.AffineTransform} */ + getParentToNodeTransform: function () { + this._renderCmd.getParentToNodeTransform(); + }, + + /** + * @function + * @deprecated since v3.0, please use getParentToNodeTransform instead + */ parentToNodeTransform: function () { - if (this._inverseDirty) { - this._inverse = cc.AffineTransformInvert(this.nodeToParentTransform()); - this._inverseDirty = false; - } - return this._inverse; + return this.getParentToNodeTransform(); }, /** - * Returns the world affine transform matrix. The matrix is in Pixels. + * Returns the world affine transform matrix. The matrix is in Pixels. + * @function * @return {cc.AffineTransform} */ - nodeToWorldTransform: function () { - var t = this.nodeToParentTransform(); - for (var p = this._parent; p != null; p = p.parent) - t = cc.AffineTransformConcat(t, p.nodeToParentTransform()); + getNodeToWorldTransform: function () { + //TODO renderCmd has a WorldTransform + var t = this.getNodeToParentTransform(); + for (var p = this._parent; p !== null; p = p.parent) + t = cc.affineTransformConcat(t, p.getNodeToParentTransform()); return t; }, + /** + * @function + * @deprecated since v3.0, please use getNodeToWorldTransform instead + */ + nodeToWorldTransform: function(){ + return this.getNodeToWorldTransform(); + }, + /** * Returns the inverse world affine transform matrix. The matrix is in Pixels. + * @function * @return {cc.AffineTransform} */ + getWorldToNodeTransform: function () { + return cc.affineTransformInvert(this.getNodeToWorldTransform()); + }, + + /** + * @function + * @deprecated since v3.0, please use getWorldToNodeTransform instead + */ worldToNodeTransform: function () { - return cc.AffineTransformInvert(this.nodeToWorldTransform()); + return this.getWorldToNodeTransform(); }, /** * Converts a Point to node (local) space coordinates. The result is in Points. + * @function * @param {cc.Point} worldPoint * @return {cc.Point} */ convertToNodeSpace: function (worldPoint) { - return cc.PointApplyAffineTransform(worldPoint, this.worldToNodeTransform()); + return cc.pointApplyAffineTransform(worldPoint, this.getWorldToNodeTransform()); }, /** * Converts a Point to world space coordinates. The result is in Points. + * @function * @param {cc.Point} nodePoint * @return {cc.Point} */ convertToWorldSpace: function (nodePoint) { - return cc.PointApplyAffineTransform(nodePoint, this.nodeToWorldTransform()); + nodePoint = nodePoint || cc.p(0,0); + return cc.pointApplyAffineTransform(nodePoint, this.getNodeToWorldTransform()); }, /** * Converts a Point to node (local) space coordinates. The result is in Points.
* treating the returned/received node point as anchor relative. + * @function * @param {cc.Point} worldPoint * @return {cc.Point} */ convertToNodeSpaceAR: function (worldPoint) { - return cc.pSub(this.convertToNodeSpace(worldPoint), this._anchorPointInPoints); + return cc.pSub(this.convertToNodeSpace(worldPoint), this._renderCmd.getAnchorPointInPoints()); }, /** * Converts a local Point to world space coordinates.The result is in Points.
* treating the returned/received node point as anchor relative. + * @function * @param {cc.Point} nodePoint * @return {cc.Point} */ convertToWorldSpaceAR: function (nodePoint) { - var pt = cc.pAdd(nodePoint, this._anchorPointInPoints); + nodePoint = nodePoint || cc.p(0,0); + var pt = cc.pAdd(nodePoint, this._renderCmd.getAnchorPointInPoints()); return this.convertToWorldSpace(pt); }, @@ -1757,31 +1985,32 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ }, /** convenience methods which take a cc.Touch instead of cc.Point - * @param {cc.Touch} touch + * @function + * @param {cc.Touch} touch The touch object * @return {cc.Point} */ convertTouchToNodeSpace: function (touch) { var point = touch.getLocation(); - //TODO This point needn't convert to GL in HTML5 - //point = cc.director.convertToGL(point); return this.convertToNodeSpace(point); }, /** - * converts a cc.Touch (world coordinates) into a local coordiante. This method is AR (Anchor Relative). - * @param {cc.Touch}touch + * converts a cc.Touch (world coordinates) into a local coordinate. This method is AR (Anchor Relative). + * @function + * @param {cc.Touch} touch The touch object * @return {cc.Point} */ convertTouchToNodeSpaceAR: function (touch) { - var point = touch.getLocation(); - point = cc.director.convertToGL(point); + var point = cc.director.convertToGL(touch.getLocation()); return this.convertToNodeSpaceAR(point); }, /** - * Update will be called automatically every frame if "scheduleUpdate" is called, and the node is "live"
- * (override me) - * @param {Number} dt deltaTime + * Update will be called automatically every frame if "scheduleUpdate" is called when the node is "live".
+ * The default behavior is to invoke the visit function of node's componentContainer.
+ * Override me to implement your own update logic. + * @function + * @param {Number} dt Delta time since last update */ update: function (dt) { if (this._componentContainer && !this._componentContainer.isEmpty()) @@ -1796,115 +2025,161 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * As the result, you apply CCSpriteBatchNode's optimization on your customed CCNode.
* e.g., batchNode->addChild(myCustomNode), while you can only addChild(sprite) before. *

+ * @function */ updateTransform: function () { // Recursively iterate over children - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.updateTransform); }, /** - * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. - * This is a hack, and should be removed once JSB fixes the retain/release bug + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created an engine object and haven't added it into the scene graph during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.Node#release */ retain: function () { }, + /** + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created an engine object and haven't added it into the scene graph during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.Node#retain + */ release: function () { }, /** - * gets a component by its name - * @param {String} name - * @return {cc.Component} gets a component by its name + * Returns a component identified by the name given. + * @function + * @param {String} name The name to search for + * @return {cc.Component} The component found */ getComponent: function (name) { - return this._componentContainer.getComponent(name); + if(this._componentContainer) + return this._componentContainer.getComponent(name); + return null; }, /** - * adds a component + * Adds a component to the node's component container. + * @function * @param {cc.Component} component */ addComponent: function (component) { - this._componentContainer.add(component); + if(this._componentContainer) + this._componentContainer.add(component); }, /** - * removes a component by its name or a component - * @param {String|cc.Component} name + * Removes a component identified by the given name or removes the component object given + * @function + * @param {String|cc.Component} component */ - removeComponent: function (name) { - return this._componentContainer.remove(name); + removeComponent: function (component) { + if(this._componentContainer) + return this._componentContainer.remove(component); + return false; }, /** - * removes all components + * Removes all components of cc.Node, it called when cc.Node is exiting from stage. + * @function */ removeAllComponents: function () { - this._componentContainer.removeAll(); + if(this._componentContainer) + this._componentContainer.removeAll(); }, grid: null, - ctor: null, - /** * Recursive method that visit its children and draw them * @function - * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx + * @param {cc.Node.RenderCmd} parentCmd */ - visit: null, + visit: function(parentCmd){ + this._renderCmd.visit(parentCmd); + }, /** - * Performs OpenGL view-matrix transformation based on position, scale, rotation and other attributes. + * Performs view-matrix transformation based on position, scale, rotation and other attributes. * @function - * @param {CanvasRenderingContext2D|null} ctx Render context + * @param {cc.Node.RenderCmd} parentCmd parent's render command + * @param {boolean} recursive whether call its children's transform */ - transform: null, + transform: function(parentCmd, recursive){ + this._renderCmd.transform(parentCmd, recursive); + }, /** - * Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates.
- * The matrix is in Pixels. + *

Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates.
+ * The matrix is in Pixels.

* @function * @return {cc.AffineTransform} + * @deprecated since v3.0, please use getNodeToParentTransform instead */ - nodeToParentTransform: null, - - _setNodeDirtyForCache: function () { - if (this._cacheDirty === false) { - this._cacheDirty = true; + nodeToParentTransform: function(){ + return this.getNodeToParentTransform(); + }, - var cachedP = this._cachedParent; - cachedP && cachedP != this && cachedP._setNodeDirtyForCache(); - } + /** + * Returns the matrix that transform the node's (local) space coordinates into the parent's space coordinates.
+ * The matrix is in Pixels. + * @function + * @return {cc.AffineTransform} The affine transform object + */ + getNodeToParentTransform: function(){ + return this._renderCmd.getNodeToParentTransform(); }, /** * Returns a camera object that lets you move the node using a gluLookAt + * @function * @return {cc.Camera} A CCCamera object that lets you move the node using a gluLookAt + * @deprecated since v3.0, no alternative function * @example * var camera = node.getCamera(); * camera.setEye(0, 0, 415/2); * camera.setCenter(0, 0, 0); */ getCamera: function () { - if (!this._camera) { + if (!this._camera) this._camera = new cc.Camera(); - } return this._camera; }, /** - * Returns a grid object that is used when applying effects + *

Returns a grid object that is used when applying effects.
+ * This function have been deprecated, please use cc.NodeGrid to run grid actions

+ * @function * @return {cc.GridBase} A CCGrid object that is used when applying effects + * @deprecated since v3.0, no alternative function */ getGrid: function () { return this.grid; }, /** - * Changes a grid object that is used when applying effects + *

Changes a grid object that is used when applying effects
+ * This function have been deprecated, please use cc.NodeGrid to run grid actions

+ * @function * @param {cc.GridBase} grid A CCGrid object that is used when applying effects + * @deprecated since v3.0, no alternative function */ setGrid: function (grid) { this.grid = grid; @@ -1912,10 +2187,11 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ /** * Return the shader program currently used for this node - * @return {cc.GLProgram} The shader program currelty used for this node + * @function + * @return {cc.GLProgram} The shader program currently used for this node */ getShaderProgram: function () { - return this._shaderProgram; + return this._renderCmd.getShaderProgram(); }, /** @@ -1925,38 +2201,43 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ * Since v2.0, each rendering node must set its shader program. * It should be set in initialize phase. *

- * @param {cc.GLProgram} newShaderProgram The shader program which fetchs from CCShaderCache. + * @function + * @param {cc.GLProgram} newShaderProgram The shader program which fetches from CCShaderCache. * @example - * node.setShaderProgram(cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); + * node.setGLProgram(cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); */ setShaderProgram: function (newShaderProgram) { - this._shaderProgram = newShaderProgram; + this._renderCmd.setShaderProgram(newShaderProgram); }, /** * Returns the state of OpenGL server side. + * @function * @return {Number} The state of OpenGL server side. + * @deprecated since v3.0, no need anymore */ getGLServerState: function () { - return this._glServerState; + return 0; }, /** * Sets the state of OpenGL server side. + * @function * @param {Number} state The state of OpenGL server side. + * @deprecated since v3.0, no need anymore */ setGLServerState: function (state) { - this._glServerState = state; }, - /** returns a "world" axis aligned bounding box of the node.
+ /** + * Returns a "world" axis aligned bounding box of the node. + * @function * @return {cc.Rect} */ getBoundingBoxToWorld: function () { var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); - var trans = this.nodeToWorldTransform(); - rect = cc.RectApplyAffineTransform(rect, this.nodeToWorldTransform()); - //rect = cc.rect(0 | rect.x - 4, 0 | rect.y - 4, 0 | rect.width + 8, 0 | rect.height + 8); + var trans = this.getNodeToWorldTransform(); + rect = cc.rectApplyAffineTransform(rect, trans); //query child's BoundingBox if (!this._children) @@ -1976,8 +2257,8 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ _getBoundingBoxToCurrentNode: function (parentTransform) { var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); - var trans = (parentTransform == null) ? this.nodeToParentTransform() : cc.AffineTransformConcat(this.nodeToParentTransform(), parentTransform); - rect = cc.RectApplyAffineTransform(rect, trans); + var trans = (parentTransform === undefined) ? this.getNodeToParentTransform() : cc.affineTransformConcat(this.getNodeToParentTransform(), parentTransform); + rect = cc.rectApplyAffineTransform(rect, trans); //query child's BoundingBox if (!this._children) @@ -1994,270 +2275,10 @@ cc.Node = cc.Class.extend(/** @lends cc.Node# */{ } return rect; }, - _nodeToParentTransformForWebGL: function () { - var _t = this; - if (_t._transformDirty) { - // Translate values - var x = _t._position.x; - var y = _t._position.y; - var apx = _t._anchorPointInPoints.x, napx = -apx; - var apy = _t._anchorPointInPoints.y, napy = -apy; - var scx = _t._scaleX, scy = _t._scaleY; - - if (_t._ignoreAnchorPointForPosition) { - x += apx; - y += apy; - } - - // Rotation values - // Change rotation code to handle X and Y - // If we skew with the exact same value for both x and y then we're simply just rotating - var cx = 1, sx = 0, cy = 1, sy = 0; - if (_t._rotationX !== 0 || _t._rotationY !== 0) { - cx = Math.cos(-_t._rotationRadiansX); - sx = Math.sin(-_t._rotationRadiansX); - cy = Math.cos(-_t._rotationRadiansY); - sy = Math.sin(-_t._rotationRadiansY); - } - var needsSkewMatrix = ( _t._skewX || _t._skewY ); - - // optimization: - // inline anchor point calculation if skew is not needed - // Adjusted transform calculation for rotational skew - if (!needsSkewMatrix && (apx !== 0 || apy !== 0)) { - x += cy * napx * scx + -sx * napy * scy; - y += sy * napx * scx + cx * napy * scy; - } - - // Build Transform Matrix - // Adjusted transform calculation for rotational skew - var t = _t._transform; - t.a = cy * scx; - t.b = sy * scx; - t.c = -sx * scy; - t.d = cx * scy; - t.tx = x; - t.ty = y; - - // XXX: Try to inline skew - // If skew is needed, apply skew and then anchor point - if (needsSkewMatrix) { - t = cc.AffineTransformConcat({a: 1.0, b: Math.tan(cc.degreesToRadians(_t._skewY)), - c: Math.tan(cc.degreesToRadians(_t._skewX)), d: 1.0, tx: 0.0, ty: 0.0}, t); - - // adjust anchor point - if (apx !== 0 || apy !== 0) - t = cc.AffineTransformTranslate(t, napx, napy); - } - - if (_t._additionalTransformDirty) { - t = cc.AffineTransformConcat(t, _t._additionalTransform); - _t._additionalTransformDirty = false; - } - _t._transform = t; - _t._transformDirty = false; - } - return _t._transform; - } -}); - -/** - * allocates and initializes a node. - * @constructs - * @return {cc.Node} - * @example - * // example - * var node = cc.Node.create(); - */ -cc.Node.create = function () { - return new cc.Node(); -}; - -/** - * cc.Node's state callback type - * @constant - * @type Number - */ -cc.Node.StateCallbackType = {onEnter: 1, onExit: 2, cleanup: 3, onEnterTransitionDidFinish: 4, updateTransform: 5, onExitTransitionDidStart: 6, sortAllChildren: 7}; - -if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - - //redefine cc.Node - var _p = cc.Node.prototype; - _p.ctor = function () { - this._initNode(); - }; - - _p.setNodeDirty = function () { - var _t = this; - _t._setNodeDirtyForCache(); - _t._transformDirty === false && (_t._transformDirty = _t._inverseDirty = true); - }; - - _p.visit = function (ctx) { - var _t = this; - // quick return if not visible - if (!_t._visible) - return; - - //visit for canvas - var context = ctx || cc._renderContext, i; - var children = _t._children, child; - context.save(); - _t.transform(context); - var len = children.length; - if (len > 0) { - _t.sortAllChildren(); - // draw children zOrder < 0 - for (i = 0; i < len; i++) { - child = children[i]; - if (child._localZOrder < 0) - child.visit(context); - else - break; - } - _t.draw(context); - for (; i < len; i++) { - children[i].visit(context); - } - } else - _t.draw(context); - - _t.arrivalOrder = 0; - context.restore(); - }; - - _p.transform = function (ctx) { - // transform for canvas - var context = ctx || cc._renderContext, eglViewer = cc.view; - - var t = this.nodeToParentTransform(); - context.transform(t.a, t.c, t.b, t.d, t.tx * eglViewer.getScaleX(), -t.ty * eglViewer.getScaleY()); - }; - - _p.nodeToParentTransform = function () { - var _t = this; - if (_t._transformDirty) { - var t = _t._transform;// quick reference - - // base position - t.tx = _t._position.x; - t.ty = _t._position.y; - - // rotation Cos and Sin - var Cos = 1, Sin = 0; - if (_t._rotationX) { - Cos = Math.cos(_t._rotationRadiansX); - Sin = Math.sin(_t._rotationRadiansX); - } - - // base abcd - t.a = t.d = Cos; - t.b = -Sin; - t.c = Sin; - - var lScaleX = _t._scaleX, lScaleY = _t._scaleY; - var appX = _t._anchorPointInPoints.x, appY = _t._anchorPointInPoints.y; - - // Firefox on Vista and XP crashes - // GPU thread in case of scale(0.0, 0.0) - var sx = (lScaleX < 0.000001 && lScaleX > -0.000001) ? 0.000001 : lScaleX, - sy = (lScaleY < 0.000001 && lScaleY > -0.000001) ? 0.000001 : lScaleY; - - // skew - if (_t._skewX || _t._skewY) { - // offset the anchorpoint - var skx = Math.tan(-_t._skewX * Math.PI / 180); - var sky = Math.tan(-_t._skewY * Math.PI / 180); - var xx = appY * skx * sx; - var yy = appX * sky * sy; - t.a = Cos + -Sin * sky; - t.b = Cos * skx + -Sin; - t.c = Sin + Cos * sky; - t.d = Sin * skx + Cos; - t.tx += Cos * xx + -Sin * yy; - t.ty += Sin * xx + Cos * yy; - } - - // scale - if (lScaleX !== 1 || lScaleY !== 1) { - t.a *= sx; - t.c *= sx; - t.b *= sy; - t.d *= sy; - } - - // adjust anchorPoint - t.tx += Cos * -appX * sx + -Sin * appY * sy; - t.ty -= Sin * -appX * sx + Cos * appY * sy; - - // if ignore anchorPoint - if (_t._ignoreAnchorPointForPosition) { - t.tx += appX; - t.ty += appY; - } - - if (_t._additionalTransformDirty) { - _t._transform = cc.AffineTransformConcat(t, _t._additionalTransform); - _t._additionalTransformDirty = false; - } - - _t._transformDirty = false; - } - return _t._transform; - }; - - _p = null; - -} else { - _tmp.WebGLCCNode(); - delete _tmp.WebGLCCNode; -} -_tmp.PrototypeCCNode(); -delete _tmp.PrototypeCCNode; - - -/** - *

- * cc.NodeRGBA is a subclass of cc.Node that implements the CCRGBAProtocol protocol.
- *
- * All features from CCNode are valid, plus the following new features:
- * - opacity
- * - RGB colors
- *
- * Opacity/Color propagates into children that conform to the CCRGBAProtocol if cascadeOpacity/cascadeColor is enabled.
- *

- * - * @class - * @extends cc.Node - * - * @property {Number} opacity - Opacity of node - * @property {Boolean} opacityModifyRGB - Indicate whether or not the opacity modify color - * @property {Boolean} cascadeOpacity - Indicate whether or not it will set cascade opacity - * @property {cc.Color} color - Color of node - * @property {Boolean} cascadeColor - Indicate whether or not it will set cascade color - */ -cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ - RGBAProtocol: true, - _displayedOpacity: 255, - _realOpacity: 255, - _displayedColor: null, - _realColor: null, - _cascadeColorEnabled: false, - _cascadeOpacityEnabled: false, - - ctor: function () { - cc.Node.prototype.ctor.call(this); - this._displayedOpacity = 255; - this._realOpacity = 255; - this._displayedColor = cc.color(255, 255, 255, 255); - this._realColor = cc.color(255, 255, 255, 255); - this._cascadeColorEnabled = false; - this._cascadeOpacityEnabled = false; - }, /** - * Get the opacity of Node + * Returns the opacity of Node + * @function * @returns {number} opacity */ getOpacity: function () { @@ -2265,46 +2286,38 @@ cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ }, /** - * Get the displayed opacity of Node + * Returns the displayed opacity of Node, + * the difference between displayed opacity and opacity is that displayed opacity is calculated based on opacity and parent node's opacity when cascade opacity enabled. + * @function * @returns {number} displayed opacity */ getDisplayedOpacity: function () { - return this._displayedOpacity; + return this._renderCmd.getDisplayedOpacity(); }, /** - * Set the opacity of Node + * Sets the opacity of Node + * @function * @param {Number} opacity */ setOpacity: function (opacity) { - this._displayedOpacity = this._realOpacity = opacity; - - var parentOpacity = 255, locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeOpacity) - parentOpacity = locParent.getDisplayedOpacity(); - this.updateDisplayedOpacity(parentOpacity); - - this._displayedColor.a = this._realColor.a = opacity; + this._realOpacity = opacity; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); }, /** * Update displayed opacity + * @function * @param {Number} parentOpacity */ updateDisplayedOpacity: function (parentOpacity) { - this._displayedOpacity = this._realOpacity * parentOpacity / 255.0; - if (this._cascadeOpacityEnabled) { - var selChildren = this._children; - for (var i = 0; i < selChildren.length; i++) { - var item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedOpacity(this._displayedOpacity); - } - } + //TODO this API shouldn't be public. + this._renderCmd._updateDisplayOpacity(parentOpacity); }, /** - * whether or not it will set cascade opacity. + * Returns whether node's opacity value affect its child nodes. + * @function * @returns {boolean} */ isCascadeOpacityEnabled: function () { @@ -2312,40 +2325,20 @@ cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ }, /** - * Enable or disable cascade opacity + * Enable or disable cascade opacity, if cascade enabled, child nodes' opacity will be the multiplication of parent opacity and its own opacity. + * @function * @param {boolean} cascadeOpacityEnabled */ setCascadeOpacityEnabled: function (cascadeOpacityEnabled) { if (this._cascadeOpacityEnabled === cascadeOpacityEnabled) return; - this._cascadeOpacityEnabled = cascadeOpacityEnabled; - if (cascadeOpacityEnabled) - this._enableCascadeOpacity(); - else - this._disableCascadeOpacity(); - }, - - _enableCascadeOpacity: function () { - var parentOpacity = 255, locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeOpacity) - parentOpacity = locParent.getDisplayedOpacity(); - this.updateDisplayedOpacity(parentOpacity); - }, - - _disableCascadeOpacity: function () { - this._displayedOpacity = this._realOpacity; - - var selChildren = this._children; - for (var i = 0; i < selChildren.length; i++) { - var item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedOpacity(255); - } + this._renderCmd.setCascadeOpacityEnabledDirty(); }, /** - * Get the color of Node + * Returns the color of Node + * @function * @returns {cc.Color} */ getColor: function () { @@ -2354,57 +2347,43 @@ cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ }, /** - * Get the displayed color of Node + * Returns the displayed color of Node, + * the difference between displayed color and color is that displayed color is calculated based on color and parent node's color when cascade color enabled. + * @function * @returns {cc.Color} */ getDisplayedColor: function () { - return this._displayedColor; + return this._renderCmd.getDisplayedColor(); }, /** - * Set the color of Node. - * @param {cc.Color} color When color not set alpha like cc.color(128,128,128),only change the color. When color set alpha like cc.color(128,128,128,100),then change the color and alpha. + *

Sets the color of Node.
+ * When color doesn't include opacity value like cc.color(128,128,128), this function only change the color.
+ * When color include opacity like cc.color(128,128,128,100), then this function will change the color and the opacity.

+ * @function + * @param {cc.Color} color The new color given */ setColor: function (color) { - var locDisplayedColor = this._displayedColor, locRealColor = this._realColor; - locDisplayedColor.r = locRealColor.r = color.r; - locDisplayedColor.g = locRealColor.g = color.g; - locDisplayedColor.b = locRealColor.b = color.b; - - var parentColor, locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeColor) - parentColor = locParent.getDisplayedColor(); - else - parentColor = cc.color.WHITE; - this.updateDisplayedColor(parentColor); - - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } + var locRealColor = this._realColor; + locRealColor.r = color.r; + locRealColor.g = color.g; + locRealColor.b = color.b; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); }, /** - * update the displayed color of Node + * Update the displayed color of Node + * @function * @param {cc.Color} parentColor */ updateDisplayedColor: function (parentColor) { - var locDispColor = this._displayedColor, locRealColor = this._realColor; - locDispColor.r = 0 | (locRealColor.r * parentColor.r / 255.0); - locDispColor.g = 0 | (locRealColor.g * parentColor.g / 255.0); - locDispColor.b = 0 | (locRealColor.b * parentColor.b / 255.0); - - if (this._cascadeColorEnabled) { - var selChildren = this._children; - for (var i = 0; i < selChildren.length; i++) { - var item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedColor(locDispColor); - } - } + //TODO this API shouldn't be public. + this._renderCmd._updateDisplayColor(parentColor); }, /** - * whether or not it will set cascade color. + * Returns whether node's color value affect its child nodes. + * @function * @returns {boolean} */ isCascadeColorEnabled: function () { @@ -2412,70 +2391,171 @@ cc.NodeRGBA = cc.Node.extend(/** @lends cc.NodeRGBA# */{ }, /** - * Enable or disable cascade color + * Enable or disable cascade color, if cascade enabled, child nodes' opacity will be the cascade value of parent color and its own color. * @param {boolean} cascadeColorEnabled */ setCascadeColorEnabled: function (cascadeColorEnabled) { if (this._cascadeColorEnabled === cascadeColorEnabled) return; this._cascadeColorEnabled = cascadeColorEnabled; - if (this._cascadeColorEnabled) - this._enableCascadeColor(); - else - this._disableCascadeColor(); + this._renderCmd.setCascadeColorEnabledDirty(); }, - _enableCascadeColor: function () { - var parentColor , locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeColor) - parentColor = locParent.getDisplayedColor(); - else - parentColor = cc.color.WHITE; - this.updateDisplayedColor(parentColor); + /** + * Set whether color should be changed with the opacity value, + * useless in cc.Node, but this function is override in some class to have such behavior. + * @function + * @param {Boolean} opacityValue + */ + setOpacityModifyRGB: function (opacityValue) { }, - _disableCascadeColor: function () { - var locDisplayedColor = this._displayedColor, locRealColor = this._realColor; - locDisplayedColor.r = locRealColor.r; - locDisplayedColor.g = locRealColor.g; - locDisplayedColor.b = locRealColor.b; + /** + * Get whether color should be changed with the opacity value + * @function + * @return {Boolean} + */ + isOpacityModifyRGB: function () { + return false; + }, - var selChildren = this._children, whiteColor = cc.color.WHITE; - for (var i = 0; i < selChildren.length; i++) { - var item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedColor(whiteColor); - } + _initRendererCmd: function(){ + this._renderCmd = cc.renderer.getRenderCmd(this); }, - /** - * add a child to node - * @overried - * @param {cc.Node} child A child node - * @param {Number} [zOrder=] Z order for drawing priority. Please refer to setZOrder(int) - * @param {Number} [tag=] A integer to identify the node easily. Please refer to setTag(int) + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.Node.CanvasRenderCmd(this); + else + return new cc.Node.WebGLRenderCmd(this); + }, + + /** Search the children of the receiving node to perform processing for nodes which share a name. + * + * @param name The name to search for, supports c++11 regular expression. + * Search syntax options: + * `//`: Can only be placed at the begin of the search string. This indicates that it will search recursively. + * `..`: The search should move up to the node's parent. Can only be placed at the end of string. + * `/` : When placed anywhere but the start of the search string, this indicates that the search should move to the node's children. + * + * @code + * enumerateChildren("//MyName", ...): This searches the children recursively and matches any node with the name `MyName`. + * enumerateChildren("[[:alnum:]]+", ...): This search string matches every node of its children. + * enumerateChildren("A[[:digit:]]", ...): This searches the node's children and returns any child named `A0`, `A1`, ..., `A9`. + * enumerateChildren("Abby/Normal", ...): This searches the node's grandchildren and returns any node whose name is `Normal` + * and whose parent is named `Abby`. + * enumerateChildren("//Abby/Normal", ...): This searches recursively and returns any node whose name is `Normal` and whose + * parent is named `Abby`. + * @endcode + * + * @warning Only support alpha or number for name, and not support unicode. + * + * @param callback A callback function to execute on nodes that match the `name` parameter. The function takes the following arguments: + * `node` + * A node that matches the name + * And returns a boolean result. Your callback can return `true` to terminate the enumeration. + * */ - addChild: function (child, zOrder, tag) { - cc.Node.prototype.addChild.call(this, child, zOrder, tag); + enumerateChildren: function(name, callback){ + cc.assert(name && name.length != 0, "Invalid name"); + cc.assert(callback != null, "Invalid callback function"); - if (this._cascadeColorEnabled) - this._enableCascadeColor(); - if (this._cascadeOpacityEnabled) - this._enableCascadeOpacity(); - }, + var length = name.length; + var subStrStartPos = 0; + var subStrlength = length; - setOpacityModifyRGB: function (opacityValue) { + // Starts with '//'? + var searchRecursively = false; + if(length > 2 && name[0] === "/" && name[1] === "/"){ + searchRecursively = true; + subStrStartPos = 2; + subStrlength -= 2; + } + + var searchFromParent = false; + if(length > 3 && name[length-3] === "/" && name[length-2] === "." && name[length-1] === "."){ + searchFromParent = true; + subStrlength -= 3; + } + + var newName = name.substr(subStrStartPos, subStrlength); + + if(searchFromParent) + newName = "[[:alnum:]]+/" + newName; + + if(searchRecursively) + this.doEnumerateRecursive(this, newName, callback); + else + this.doEnumerate(newName, callback); + }, + + doEnumerateRecursive: function(node, name, callback){ + var ret = false; + if(node.doEnumerate(name,callback)){ + ret = true; + }else{ + var child, + children = node.getChildren(), + length = children.length; + // search its children + for (var i=0; i -0.000001) ? 0.000001 : lScaleX, + sy = (lScaleY < 0.000001 && lScaleY > -0.000001) ? 0.000001 : lScaleY; + + // scale + if (lScaleX !== 1 || lScaleY !== 1) { + a = t.a *= sx; + b = t.b *= sx; + c = t.c *= sy; + d = t.d *= sy; + } + + // skew + if (node._skewX || node._skewY) { + // offset the anchorpoint + var skx = Math.tan(-node._skewX * Math.PI / 180); + var sky = Math.tan(-node._skewY * Math.PI / 180); + if (skx === Infinity) + skx = 99999999; + if (sky === Infinity) + sky = 99999999; + var xx = appY * skx; + var yy = appX * sky; + t.a = a - c * sky; + t.b = b - d * sky; + t.c = c - a * skx; + t.d = d - b * skx; + t.tx += a * xx + c * yy; + t.ty += b * xx + d * yy; + } + + // adjust anchorPoint + t.tx -= a * appX + c * appY; + t.ty -= b * appX + d * appY; + + // if ignore anchorPoint + if (node._ignoreAnchorPointForPosition) { + t.tx += appX; + t.ty += appY; + } + + if (node._additionalTransformDirty) + this._transform = cc.affineTransformConcat(t, node._additionalTransform); + } + return this._transform; + }; + + proto.visit = function (parentCmd) { + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + parentCmd = parentCmd || this.getParentRenderCmd(); + if (parentCmd) + this._curLevel = parentCmd._curLevel + 1; + + //visit for canvas + var i, children = node._children, child; + this._syncStatus(parentCmd); + var len = children.length; + if (len > 0) { + node.sortAllChildren(); + // draw children zOrder < 0 + for (i = 0; i < len; i++) { + child = children[i]; + if (child._localZOrder < 0) + child._renderCmd.visit(this); + else + break; + } + cc.renderer.pushRenderCommand(this); + for (; i < len; i++) + children[i]._renderCmd.visit(this); + } else { + cc.renderer.pushRenderCommand(this); + } + this._dirtyFlag = 0; + }; + + proto._syncStatus = function (parentCmd) { + // In the visit logic does not restore the _dirtyFlag + // Because child elements need parent's _dirtyFlag to change himself + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + // There is a possibility: + // The parent element changed color, child element not change + // This will cause the parent element changed color + // But while the child element does not enter the circulation + // Here will be reset state in last + // In order the child elements get the parent state + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty, + transformDirty = locFlag & flags.transformDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + //update the color + this._syncDisplayColor(); + + if (opacityDirty) + //update the opacity + this._syncDisplayOpacity(); + + if(colorDirty) + this._updateColor(); + + if (transformDirty){ + //update the transform + this.transform(parentCmd); + } + }; + + proto.setDirtyFlag = function (dirtyFlag) { + cc.Node.RenderCmd.prototype.setDirtyFlag.call(this, dirtyFlag); + this._setCacheDirty(); //TODO it should remove from here. + if(this._cachedParent) + this._cachedParent.setDirtyFlag(dirtyFlag); + }; + + proto._setCacheDirty = function () { + if (this._cacheDirty === false) { + this._cacheDirty = true; + var cachedP = this._cachedParent; + cachedP && cachedP !== this && cachedP._setNodeDirtyForCache && cachedP._setNodeDirtyForCache(); + } + }; + + proto._setCachedParent = function (cachedParent) { + if (this._cachedParent === cachedParent) + return; + + this._cachedParent = cachedParent; + var children = this._node._children; + for (var i = 0, len = children.length; i < len; i++) + children[i]._renderCmd._setCachedParent(cachedParent); + }; + + proto.detachFromParent = function () { + this._cachedParent = null; + var selChildren = this._node._children, item; + for (var i = 0, len = selChildren.length; i < len; i++) { + item = selChildren[i]; + if (item && item._renderCmd) + item._renderCmd.detachFromParent(); + } + }; + + proto.setShaderProgram = function (shaderProgram) { + //do nothing. + }; + + proto.getShaderProgram = function () { + return null; + }; + + //util functions + cc.Node.CanvasRenderCmd._getCompositeOperationByBlendFunc = function (blendFunc) { + if (!blendFunc) + return "source-over"; + else { + if (( blendFunc.src === cc.SRC_ALPHA && blendFunc.dst === cc.ONE) || (blendFunc.src === cc.ONE && blendFunc.dst === cc.ONE)) + return "lighter"; + else if (blendFunc.src === cc.ZERO && blendFunc.dst === cc.SRC_ALPHA) + return "destination-in"; + else if (blendFunc.src === cc.ZERO && blendFunc.dst === cc.ONE_MINUS_SRC_ALPHA) + return "destination-out"; + else + return "source-over"; + } + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/base-nodes/CCNodeWebGLRenderCmd.js b/cocos2d/core/base-nodes/CCNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..ce62ce39e3 --- /dev/null +++ b/cocos2d/core/base-nodes/CCNodeWebGLRenderCmd.js @@ -0,0 +1,254 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ +// ------------------------------ The cc.Node's render command for WebGL ---------------------------------- +(function() { + cc.Node.WebGLRenderCmd = function (renderable) { + cc.Node.RenderCmd.call(this, renderable); + + var mat4 = new cc.math.Matrix4(), mat = mat4.mat; + mat[2] = mat[3] = mat[6] = mat[7] = mat[8] = mat[9] = mat[11] = mat[14] = 0.0; + mat[10] = mat[15] = 1.0; + this._transform4x4 = mat4; + this._stackMatrix = new cc.math.Matrix4(); + this._shaderProgram = null; + + this._camera = null; + }; + + var proto = cc.Node.WebGLRenderCmd.prototype = Object.create(cc.Node.RenderCmd.prototype); + proto.constructor = cc.Node.WebGLRenderCmd; + + proto.getNodeToParentTransform = function () { + var node = this._node; + if (node._usingNormalizedPosition && node._parent) { //TODO need refactor + var conSize = node._parent._contentSize; + node._position.x = node._normalizedPosition.x * conSize.width; + node._position.y = node._normalizedPosition.y * conSize.height; + node._normalizedPositionDirty = false; + } + if (this._dirtyFlag & cc.Node._dirtyFlags.transformDirty) { + // Translate values + var x = node._position.x, y = node._position.y; + var apx = this._anchorPointInPoints.x, napx = -apx; + var apy = this._anchorPointInPoints.y, napy = -apy; + var scx = node._scaleX, scy = node._scaleY; + var rotationRadiansX = node._rotationX * 0.017453292519943295; //0.017453292519943295 = (Math.PI / 180); for performance + var rotationRadiansY = node._rotationY * 0.017453292519943295; + + if (node._ignoreAnchorPointForPosition) { + x += apx; + y += apy; + } + + // Rotation values + // Change rotation code to handle X and Y + // If we skew with the exact same value for both x and y then we're simply just rotating + var cx = 1, sx = 0, cy = 1, sy = 0; + if (node._rotationX !== 0 || node._rotationY !== 0) { + cx = Math.cos(-rotationRadiansX); + sx = Math.sin(-rotationRadiansX); + cy = Math.cos(-rotationRadiansY); + sy = Math.sin(-rotationRadiansY); + } + var needsSkewMatrix = ( node._skewX || node._skewY ); + + // optimization: + // inline anchor point calculation if skew is not needed + // Adjusted transform calculation for rotational skew + if (!needsSkewMatrix && (apx !== 0 || apy !== 0)) { + x += cy * napx * scx + -sx * napy * scy; + y += sy * napx * scx + cx * napy * scy; + } + + // Build Transform Matrix + // Adjusted transform calculation for rotational skew + var t = this._transform; + t.a = cy * scx; + t.b = sy * scx; + t.c = -sx * scy; + t.d = cx * scy; + t.tx = x; + t.ty = y; + + // XXX: Try to inline skew + // If skew is needed, apply skew and then anchor point + if (needsSkewMatrix) { + t = cc.affineTransformConcat({a: 1.0, b: Math.tan(cc.degreesToRadians(node._skewY)), + c: Math.tan(cc.degreesToRadians(node._skewX)), d: 1.0, tx: 0.0, ty: 0.0}, t); + + // adjust anchor point + if (apx !== 0 || apy !== 0) + t = cc.affineTransformTranslate(t, napx, napy); + } + + if (node._additionalTransformDirty) { + t = cc.affineTransformConcat(t, node._additionalTransform); + node._additionalTransformDirty = false; + } + this._transform = t; + } + return this._transform; + }; + + proto._syncStatus = function (parentCmd) { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + this._syncDisplayColor(); + + if (opacityDirty) + this._syncDisplayOpacity(); + + if(colorDirty || opacityDirty) + this._updateColor(); + + //if (locFlag & flags.transformDirty) { //need update the stackMatrix every calling visit, because when projection changed, need update all scene graph element. + //update the transform + this.transform(parentCmd); + //} + }; + + proto._updateColor = function(){}; + + proto.visit = function (parentCmd) { + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + parentCmd = parentCmd || this.getParentRenderCmd(); + if (node._parent && node._parent._renderCmd) + this._curLevel = node._parent._renderCmd._curLevel + 1; + + var i, currentStack = cc.current_stack; + + //optimize performance for javascript + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + currentStack.top = this._stackMatrix; + + var locChildren = node._children; + if (locChildren && locChildren.length > 0) { + var childLen = locChildren.length; + node.sortAllChildren(); + // draw children zOrder < 0 + for (i = 0; i < childLen; i++) { + if (locChildren[i] && locChildren[i]._localZOrder < 0) + locChildren[i]._renderCmd.visit(this); + else + break; + } + + cc.renderer.pushRenderCommand(this); + // draw children zOrder >= 0 + for (; i < childLen; i++) { + if (locChildren[i]) + locChildren[i]._renderCmd.visit(this); + } + } else + cc.renderer.pushRenderCommand(this); + + this._dirtyFlag = 0; + //optimize performance for javascript + currentStack.top = currentStack.stack.pop(); + }; + + proto.transform = function (parentCmd, recursive) { + var t4x4 = this._transform4x4, stackMatrix = this._stackMatrix, node = this._node; + parentCmd = parentCmd || this.getParentRenderCmd(); + var parentMatrix = (parentCmd ? parentCmd._stackMatrix : cc.current_stack.top); + + // Convert 3x3 into 4x4 matrix + var trans = this.getNodeToParentTransform(); + + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.transformDirty ^ this._dirtyFlag; + + var t4x4Mat = t4x4.mat; + t4x4Mat[0] = trans.a; + t4x4Mat[4] = trans.c; + t4x4Mat[12] = trans.tx; + t4x4Mat[1] = trans.b; + t4x4Mat[5] = trans.d; + t4x4Mat[13] = trans.ty; + + // Update Z vertex manually + t4x4Mat[14] = node._vertexZ; + + //optimize performance for Javascript + cc.kmMat4Multiply(stackMatrix, parentMatrix, t4x4); + + // XXX: Expensive calls. Camera should be integrated into the cached affine matrix + if (node._camera !== null && !(node.grid !== null && node.grid.isActive())) { + var apx = this._anchorPointInPoints.x, apy = this._anchorPointInPoints.y; + var translate = (apx !== 0.0 || apy !== 0.0); + if (translate){ + if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { + apx = 0 | apx; + apy = 0 | apy; + } + //cc.kmGLTranslatef(apx, apy, 0); + var translation = cc.math.Matrix4.createByTranslation(apx, apy, 0, t4x4); //t4x4 as a temp matrix + stackMatrix.multiply(translation); + + node._camera._locateForRenderer(stackMatrix); + + //cc.kmGLTranslatef(-apx, -apy, 0); optimize at here : kmGLTranslatef + translation = cc.math.Matrix4.createByTranslation(-apx, -apy, 0, translation); + stackMatrix.multiply(translation); + t4x4.identity(); //reset t4x4; + } else { + node._camera._locateForRenderer(stackMatrix); + } + } + if(!recursive || !node._children || node._children.length === 0) + return; + var i, len, locChildren = node._children; + for(i = 0, len = locChildren.length; i< len; i++){ + locChildren[i]._renderCmd.transform(this, recursive); + } + }; + + proto.setShaderProgram = function (shaderProgram) { + this._shaderProgram = shaderProgram; + }; + + proto.getShaderProgram = function () { + return this._shaderProgram; + }; +})(); diff --git a/cocos2d/core/cocoa/CCAffineTransform.js b/cocos2d/core/cocoa/CCAffineTransform.js index 150875a0fb..d979b9d61b 100644 --- a/cocos2d/core/cocoa/CCAffineTransform.js +++ b/cocos2d/core/cocoa/CCAffineTransform.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,14 +25,17 @@ ****************************************************************************/ /** - * @memberOf cc - * @function + *

cc.AffineTransform class represent an affine transform matrix. It's composed basically by translation, rotation, scale transformations.
+ * Please do not use its constructor directly, use cc.affineTransformMake alias function instead. + *

+ * @class cc.AffineTransform * @param {Number} a * @param {Number} b * @param {Number} c * @param {Number} d * @param {Number} tx * @param {Number} ty + * @see cc.affineTransformMake */ cc.AffineTransform = function (a, b, c, d, tx, ty) { this.a = a; @@ -44,8 +47,9 @@ cc.AffineTransform = function (a, b, c, d, tx, ty) { }; /** - * @memberOf cc + * Create a cc.AffineTransform object with all contents in the matrix * @function + * * @param {Number} a * @param {Number} b * @param {Number} c @@ -53,79 +57,93 @@ cc.AffineTransform = function (a, b, c, d, tx, ty) { * @param {Number} tx * @param {Number} ty * @return {cc.AffineTransform} - * Constructor */ -cc.AffineTransformMake = function (a, b, c, d, tx, ty) { +cc.affineTransformMake = function (a, b, c, d, tx, ty) { return {a: a, b: b, c: c, d: d, tx: tx, ty: ty}; }; /** - * @memberOf cc + * Apply the affine transformation on a point. * @function - * @param {cc.Point} point - * @param {cc.AffineTransform} t + * + * @param {cc.Point|Number} point or x + * @param {cc.AffineTransform|Number} transOrY transform matrix or y + * @param {cc.AffineTransform} t transform matrix or y * @return {cc.Point} - * Constructor */ -cc.PointApplyAffineTransform = function (point, t) { - return {x: t.a * point.x + t.c * point.y + t.tx, y: t.b * point.x + t.d * point.y + t.ty}; +cc.pointApplyAffineTransform = function (point, transOrY, t) { + var x, y; + if (t === undefined) { + t = transOrY; + x = point.x; + y = point.y; + } else { + x = point; + y = transOrY; + } + return {x: t.a * x + t.c * y + t.tx, y: t.b * x + t.d * y + t.ty}; }; -cc._PointApplyAffineTransform = function (x, y, t) { - return {x: t.a * x + t.c * y + t.tx, - y: t.b * x + t.d * y + t.ty}; +cc._pointApplyAffineTransform = function (x, y, t) { //it will remove. + return cc.pointApplyAffineTransform(x, y, t); }; /** - * @memberOf cc + * Apply the affine transformation on a size. * @function + * * @param {cc.Size} size * @param {cc.AffineTransform} t * @return {cc.Size} - * Constructor */ -cc.SizeApplyAffineTransform = function (size, t) { +cc.sizeApplyAffineTransform = function (size, t) { return {width: t.a * size.width + t.c * size.height, height: t.b * size.width + t.d * size.height}; }; /** - * @memberOf cc + *

Create a identity transformation matrix:
+ * [ 1, 0, 0,
+ * 0, 1, 0 ]

* @function + * * @return {cc.AffineTransform} - * Constructor */ -cc.AffineTransformMakeIdentity = function () { +cc.affineTransformMakeIdentity = function () { return {a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0}; }; /** - * @memberOf cc + *

Create a identity transformation matrix:
+ * [ 1, 0, 0,
+ * 0, 1, 0 ]

* @function + * * @return {cc.AffineTransform} - * Constructor + * @deprecated since v3.0, please use cc.affineTransformMakeIdentity() instead + * @see cc.affineTransformMakeIdentity */ -cc.AffineTransformIdentity = function () { +cc.affineTransformIdentity = function () { return {a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0}; }; /** - * @memberOf cc + * Apply the affine transformation on a rect. * @function + * * @param {cc.Rect} rect * @param {cc.AffineTransform} anAffineTransform * @return {cc.Rect} - * Constructor */ -cc.RectApplyAffineTransform = function (rect, anAffineTransform) { +cc.rectApplyAffineTransform = function (rect, anAffineTransform) { var top = cc.rectGetMinY(rect); var left = cc.rectGetMinX(rect); var right = cc.rectGetMaxX(rect); var bottom = cc.rectGetMaxY(rect); - var topLeft = cc._PointApplyAffineTransform(left, top, anAffineTransform); - var topRight = cc._PointApplyAffineTransform(right, top, anAffineTransform); - var bottomLeft = cc._PointApplyAffineTransform(left, bottom, anAffineTransform); - var bottomRight = cc._PointApplyAffineTransform(right, bottom, anAffineTransform); + var topLeft = cc.pointApplyAffineTransform(left, top, anAffineTransform); + var topRight = cc.pointApplyAffineTransform(right, top, anAffineTransform); + var bottomLeft = cc.pointApplyAffineTransform(left, bottom, anAffineTransform); + var bottomRight = cc.pointApplyAffineTransform(right, bottom, anAffineTransform); var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); @@ -135,16 +153,16 @@ cc.RectApplyAffineTransform = function (rect, anAffineTransform) { return cc.rect(minX, minY, (maxX - minX), (maxY - minY)); }; -cc._RectApplyAffineTransformIn = function(rect, anAffineTransform){ +cc._rectApplyAffineTransformIn = function(rect, anAffineTransform){ var top = cc.rectGetMinY(rect); var left = cc.rectGetMinX(rect); var right = cc.rectGetMaxX(rect); var bottom = cc.rectGetMaxY(rect); - var topLeft = cc._PointApplyAffineTransform(left, top, anAffineTransform); - var topRight = cc._PointApplyAffineTransform(right, top, anAffineTransform); - var bottomLeft = cc._PointApplyAffineTransform(left, bottom, anAffineTransform); - var bottomRight = cc._PointApplyAffineTransform(right, bottom, anAffineTransform); + var topLeft = cc.pointApplyAffineTransform(left, top, anAffineTransform); + var topRight = cc.pointApplyAffineTransform(right, top, anAffineTransform); + var bottomLeft = cc.pointApplyAffineTransform(left, bottom, anAffineTransform); + var bottomRight = cc.pointApplyAffineTransform(right, bottom, anAffineTransform); var minX = Math.min(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); var maxX = Math.max(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x); @@ -159,15 +177,15 @@ cc._RectApplyAffineTransformIn = function(rect, anAffineTransform){ }; /** - * @memberOf cc + * Create a new affine transformation with a base transformation matrix and a translation based on it. * @function - * @param {cc.AffineTransform} t - * @param {Number} tx - * @param {Number}ty + * + * @param {cc.AffineTransform} t The base affine transform object + * @param {Number} tx The translation on x axis + * @param {Number} ty The translation on y axis * @return {cc.AffineTransform} - * Constructor */ -cc.AffineTransformTranslate = function (t, tx, ty) { +cc.affineTransformTranslate = function (t, tx, ty) { return { a: t.a, b: t.b, @@ -179,27 +197,25 @@ cc.AffineTransformTranslate = function (t, tx, ty) { }; /** - * @memberOf cc + * Create a new affine transformation with a base transformation matrix and a scale based on it. * @function - * @param {cc.AffineTransform} t - * @param {Number} sx - * @param {Number} sy + * @param {cc.AffineTransform} t The base affine transform object + * @param {Number} sx The scale on x axis + * @param {Number} sy The scale on y axis * @return {cc.AffineTransform} - * Constructor */ -cc.AffineTransformScale = function (t, sx, sy) { +cc.affineTransformScale = function (t, sx, sy) { return {a: t.a * sx, b: t.b * sx, c: t.c * sy, d: t.d * sy, tx: t.tx, ty: t.ty}; }; /** - * @memberOf cc + * Create a new affine transformation with a base transformation matrix and a rotation based on it. * @function - * @param {cc.AffineTransform} aTransform - * @param {Number} anAngle + * @param {cc.AffineTransform} aTransform The base affine transform object + * @param {Number} anAngle The angle to rotate * @return {cc.AffineTransform} - * Constructor */ -cc.AffineTransformRotate = function (aTransform, anAngle) { +cc.affineTransformRotate = function (aTransform, anAngle) { var fSin = Math.sin(anAngle); var fCos = Math.cos(anAngle); @@ -212,16 +228,14 @@ cc.AffineTransformRotate = function (aTransform, anAngle) { }; /** - * Concatenate `t2' to `t1' and return the result:
+ * Concatenate a transform matrix to another and return the result:
* t' = t1 * t2 - * @memberOf cc * @function - * @param {cc.AffineTransform} t1 - * @param {cc.AffineTransform} t2 - * @return {cc.AffineTransform} - * Constructor + * @param {cc.AffineTransform} t1 The first transform object + * @param {cc.AffineTransform} t2 The transform object to concatenate + * @return {cc.AffineTransform} The result of concatenation */ -cc.AffineTransformConcat = function (t1, t2) { +cc.affineTransformConcat = function (t1, t2) { return {a: t1.a * t2.a + t1.b * t2.c, //a b: t1.a * t2.b + t1.b * t2.d, //b c: t1.c * t2.a + t1.d * t2.c, //c @@ -231,27 +245,23 @@ cc.AffineTransformConcat = function (t1, t2) { }; /** - * Return true if `t1' and `t2' are equal, false otherwise. - * @memberOf cc + * Return true if an affine transform equals to another, false otherwise. * @function * @param {cc.AffineTransform} t1 * @param {cc.AffineTransform} t2 * @return {Boolean} - * Constructor */ -cc.AffineTransformEqualToTransform = function (t1, t2) { +cc.affineTransformEqualToTransform = function (t1, t2) { return ((t1.a === t2.a) && (t1.b === t2.b) && (t1.c === t2.c) && (t1.d === t2.d) && (t1.tx === t2.tx) && (t1.ty === t2.ty)); }; /** - * Get the invert value of an AffineTransform object - * @memberOf cc + * Get the invert transform of an AffineTransform object * @function * @param {cc.AffineTransform} t - * @return {cc.AffineTransform} - * Constructor + * @return {cc.AffineTransform} The inverted transform object */ -cc.AffineTransformInvert = function (t) { +cc.affineTransformInvert = function (t) { var determinant = 1 / (t.a * t.d - t.b * t.c); return {a: determinant * t.d, b: -determinant * t.b, c: -determinant * t.c, d: determinant * t.a, tx: determinant * (t.c * t.ty - t.d * t.tx), ty: determinant * (t.b * t.tx - t.a * t.ty)}; diff --git a/cocos2d/core/cocoa/CCGeometry.js b/cocos2d/core/cocoa/CCGeometry.js index 11ace91ee1..0eeffd5ad2 100644 --- a/cocos2d/core/cocoa/CCGeometry.js +++ b/cocos2d/core/cocoa/CCGeometry.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,16 +24,12 @@ THE SOFTWARE. ****************************************************************************/ -//-------------------------------------------------------- -// -// POINT -// -//-------------------------------------------------------- /** - * @class + * cc.Point is the class for point object, please do not use its constructor to create points, use cc.p() alias function instead. + * @class cc.Point * @param {Number} x * @param {Number} y - * Constructor + * @see cc.p */ cc.Point = function (x, y) { this.x = x || 0; @@ -41,14 +37,16 @@ cc.Point = function (x, y) { }; /** - * Helper macro that creates a cc.Point. + * Helper function that creates a cc.Point. + * @function * @param {Number|cc.Point} x a Number or a size object * @param {Number} y * @return {cc.Point} * @example * var point1 = cc.p(); - * var point2 = cc.p(100,100,100,100); + * var point2 = cc.p(100, 100); * var point3 = cc.p(point2); + * var point4 = cc.p({x: 100, y: 100}); */ cc.p = function (x, y) { // This can actually make use of "hidden classes" in JITs and thus decrease @@ -57,14 +55,15 @@ cc.p = function (x, y) { // but this one will instead flood the heap with newly allocated hash maps // giving little room for optimization by the JIT, // note: we have tested this item on Chrome and firefox, it is faster than cc.p(x, y) - if (x == undefined) + if (x === undefined) return {x: 0, y: 0}; - if (y == undefined) + if (y === undefined) return {x: x.x, y: x.y}; return {x: x, y: y}; }; /** + * Check whether a point's value equals to another * @function * @param {cc.Point} point1 * @param {cc.Point} point2 @@ -75,17 +74,12 @@ cc.pointEqualToPoint = function (point1, point2) { }; -//-------------------------------------------------------- -// -// SIZE -// -//-------------------------------------------------------- - /** - * @class + * cc.Size is the class for size object, please do not use its constructor to create sizes, use cc.size() alias function instead. + * @class cc.Size * @param {Number} width * @param {Number} height - * Constructor + * @see cc.size */ cc.Size = function (width, height) { this.width = width || 0; @@ -93,14 +87,16 @@ cc.Size = function (width, height) { }; /** + * Helper function that creates a cc.Size. * @function * @param {Number|cc.Size} w width or a size object * @param {Number} h height * @return {cc.Size} * @example * var size1 = cc.size(); - * var size2 = cc.size(100,100,100,100); + * var size2 = cc.size(100,100); * var size3 = cc.size(size2); + * var size4 = cc.size({width: 100, height: 100}); */ cc.size = function (w, h) { // This can actually make use of "hidden classes" in JITs and thus decrease @@ -117,29 +113,23 @@ cc.size = function (w, h) { }; /** + * Check whether a point's value equals to another * @function * @param {cc.Size} size1 * @param {cc.Size} size2 * @return {Boolean} */ cc.sizeEqualToSize = function (size1, size2) { - return (size1 && size2 && (size1.width == size2.width) && (size1.height == size2.height)); + return (size1 && size2 && (size1.width === size2.width) && (size1.height === size2.height)); }; -//-------------------------------------------------------- -// -// RECT -// -//-------------------------------------------------------- - /** - * @class - * @param {Number} x a Number value as x - * @param {Number} y a Number value as y + * cc.Rect is the class for rect object, please do not use its constructor to create rects, use cc.rect() alias function instead. + * @class cc.Rect * @param {Number} width * @param {Number} height - * Constructor + * @see cc.rect */ cc.Rect = function (x, y, width, height) { this.x = x||0; @@ -149,7 +139,8 @@ cc.Rect = function (x, y, width, height) { }; /** - * Return a new Rect + * Helper function that creates a cc.Rect. + * @function * @param {Number|cc.Rect} x a number or a rect object * @param {Number} y * @param {Number} w @@ -159,6 +150,7 @@ cc.Rect = function (x, y, width, height) { * var rect1 = cc.rect(); * var rect2 = cc.rect(100,100,100,100); * var rect3 = cc.rect(rect2); + * var rect4 = cc.rect({x: 100, y: 100, width: 100, height: 100}); */ cc.rect = function (x, y, w, h) { if (x === undefined) @@ -169,7 +161,7 @@ cc.rect = function (x, y, w, h) { }; /** - * whether the rect1 equals the rect2 + * Check whether a rect's value equals to another * @function * @param {cc.Rect} rect1 * @param {cc.Rect} rect2 @@ -184,7 +176,7 @@ cc._rectEqualToZero = function(rect){ }; /** - * return whether the rect1 contains rect2 + * Check whether the rect1 contains rect2 * @function * @param {cc.Rect} rect1 * @param {cc.Rect} rect2 @@ -199,39 +191,39 @@ cc.rectContainsRect = function (rect1, rect2) { }; /** - * return the rightmost x-value of 'rect' + * Returns the rightmost x-value of a rect * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The rightmost x value */ cc.rectGetMaxX = function (rect) { return (rect.x + rect.width); }; /** - * return the midpoint x-value of 'rect' + * Return the midpoint x-value of a rect * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The midpoint x value */ cc.rectGetMidX = function (rect) { return (rect.x + rect.width / 2.0); }; /** - * return the leftmost x-value of 'rect' + * Returns the leftmost x-value of a rect * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The leftmost x value */ cc.rectGetMinX = function (rect) { return rect.x; }; /** - * Return the topmost y-value of `rect' + * Return the topmost y-value of a rect * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The topmost y value */ cc.rectGetMaxY = function (rect) { return(rect.y + rect.height); @@ -241,23 +233,24 @@ cc.rectGetMaxY = function (rect) { * Return the midpoint y-value of `rect' * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The midpoint y value */ cc.rectGetMidY = function (rect) { return rect.y + rect.height / 2.0; }; /** - * Return the bottommost y-value of `rect' + * Return the bottommost y-value of a rect * @function * @param {cc.Rect} rect - * @return {Number} + * @return {Number} The bottommost y value */ cc.rectGetMinY = function (rect) { return rect.y; }; /** + * Check whether a rect contains a point * @function * @param {cc.Rect} rect * @param {cc.Point} point @@ -269,19 +262,22 @@ cc.rectContainsPoint = function (rect, point) { }; /** + * Check whether a rect intersect with another * @function * @param {cc.Rect} rectA * @param {cc.Rect} rectB * @return {Boolean} */ -cc.rectIntersectsRect = function (rectA, rectB) { - return !(cc.rectGetMaxX(rectA) < cc.rectGetMinX(rectB) || - cc.rectGetMaxX(rectB) < cc.rectGetMinX(rectA) || - cc.rectGetMaxY(rectA) < cc.rectGetMinY(rectB) || - cc.rectGetMaxY(rectB) < cc.rectGetMinY(rectA)); +cc.rectIntersectsRect = function (ra, rb) { + var maxax = ra.x + ra.width, + maxay = ra.y + ra.height, + maxbx = rb.x + rb.width, + maxby = rb.y + rb.height; + return !(maxax < rb.x || maxbx < ra.x || maxay < rb.y || maxby < ra.y); }; /** + * Check whether a rect overlaps another * @function * @param {cc.Rect} rectA * @param {cc.Rect} rectB diff --git a/cocos2d/core/event-manager/CCEvent.js b/cocos2d/core/event-manager/CCEvent.js index 09535c7500..fa5c47f5a1 100644 --- a/cocos2d/core/event-manager/CCEvent.js +++ b/cocos2d/core/event-manager/CCEvent.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -42,7 +43,8 @@ cc.Event = cc.Class.extend(/** @lends cc.Event# */{ /** * Gets the event type - * @returns {number} + * @function + * @returns {Number} */ getType: function () { return this._type; @@ -50,6 +52,7 @@ cc.Event = cc.Class.extend(/** @lends cc.Event# */{ /** * Stops propagation for current event + * @function */ stopPropagation: function () { this._isStopped = true; @@ -57,6 +60,7 @@ cc.Event = cc.Class.extend(/** @lends cc.Event# */{ /** * Checks whether the event has been stopped + * @function * @returns {boolean} */ isStopped: function () { @@ -69,6 +73,7 @@ cc.Event = cc.Class.extend(/** @lends cc.Event# */{ * note: It only be available when the event listener is associated with node.
* It returns 0 when the listener is associated with fixed priority. *

+ * @function * @returns {cc.Node} The target with which the event associates. */ getCurrentTarget: function () { @@ -101,12 +106,18 @@ cc.Event.ACCELERATION = 2; * @type {number} */ cc.Event.MOUSE = 3; +/** + * The type code of UI focus event. + * @constant + * @type {number} + */ +cc.Event.FOCUS = 4; /** * The type code of Custom event. * @constant * @type {number} */ -cc.Event.CUSTOM = 4; +cc.Event.CUSTOM = 6; /** * The Custom event @@ -116,6 +127,7 @@ cc.Event.CUSTOM = 4; cc.EventCustom = cc.Event.extend(/** @lends cc.EventCustom# */{ _eventName: null, _userData: null, // User data + ctor: function (eventName) { cc.Event.prototype.ctor.call(this, cc.Event.CUSTOM); this._eventName = eventName; @@ -167,7 +179,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * sets scroll data + * Sets scroll data * @param {number} scrollX * @param {number} scrollY */ @@ -177,7 +189,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * gets scrollX data + * Returns the x axis scroll value * @returns {number} */ getScrollX: function () { @@ -185,7 +197,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * gets scrollY data + * Returns the y axis scroll value * @returns {number} */ getScrollY: function () { @@ -193,7 +205,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * Set cursor location + * Sets cursor location * @param {number} x * @param {number} y */ @@ -203,7 +215,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * Get cursor location + * Returns cursor location * @return {cc.Point} location */ getLocation: function () { @@ -211,7 +223,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * returns the current touch location in screen coordinates + * Returns the current cursor location in screen coordinates * @return {cc.Point} */ getLocationInView: function() { @@ -223,14 +235,26 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ this._prevY = y; }, + /** + * Returns the delta distance from the previous location to current location + * @return {cc.Point} + */ getDelta: function () { return {x: this._x - this._prevX, y: this._y - this._prevY}; }, + /** + * Returns the X axis delta distance from the previous location to current location + * @return {Number} + */ getDeltaX: function () { return this._x - this._prevX; }, + /** + * Returns the Y axis delta distance from the previous location to current location + * @return {Number} + */ getDeltaY: function () { return this._y - this._prevY; }, @@ -244,7 +268,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * Gets mouse button + * Returns mouse button * @returns {number} */ getButton: function () { @@ -252,7 +276,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * gets location X axis data + * Returns location X axis data * @returns {number} */ getLocationX: function () { @@ -260,7 +284,7 @@ cc.EventMouse = cc.Event.extend(/** @lends cc.EventMouse# */{ }, /** - * gets location Y axis data + * Returns location Y axis data * @returns {number} */ getLocationY: function () { @@ -371,7 +395,7 @@ cc.EventTouch = cc.Event.extend(/** @lends cc.EventTouch# */{ }, /** - * Gets event code + * Returns event code * @returns {number} */ getEventCode: function () { @@ -379,7 +403,7 @@ cc.EventTouch = cc.Event.extend(/** @lends cc.EventTouch# */{ }, /** - * Get touches of event + * Returns touches of event * @returns {Array} */ getTouches: function () { @@ -395,10 +419,31 @@ cc.EventTouch = cc.Event.extend(/** @lends cc.EventTouch# */{ } }); +/** + * The maximum touch numbers + * @constant + * @type {Number} + */ cc.EventTouch.MAX_TOUCHES = 5; +cc.EventTouch.EventCode = {BEGAN: 0, MOVED: 1, ENDED: 2, CANCELLED: 3}; + /** - * The event code of Touch event. - * @type {Object} + * Focus change event for UI widget + * @class + * @extends cc.Event */ -cc.EventTouch.EventCode = {BEGAN: 0, MOVED: 1, ENDED: 2, CANCELLED: 3}; \ No newline at end of file +cc.EventFocus = cc.Event.extend(/** @lends cc.EventTouch# */{ + _widgetGetFocus: null, + _widgetLoseFocus: null, + /** + * Constructor function. + * @param {ccui.Widget} widgetLoseFocus + * @param {ccui.Widget} widgetGetFocus + */ + ctor: function(widgetLoseFocus, widgetGetFocus){ + cc.Event.prototype.ctor.call(this, cc.Event.FOCUS); + this._widgetGetFocus = widgetGetFocus; + this._widgetLoseFocus = widgetLoseFocus; + } +}); \ No newline at end of file diff --git a/cocos2d/core/event-manager/CCEventExtension.js b/cocos2d/core/event-manager/CCEventExtension.js index 7c3f41f473..a14968f0f7 100644 --- a/cocos2d/core/event-manager/CCEventExtension.js +++ b/cocos2d/core/event-manager/CCEventExtension.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -43,7 +44,6 @@ cc.EventAcceleration = cc.Event.extend(/** @lends cc.EventAcceleration# */{ cc.EventKeyboard = cc.Event.extend(/** @lends cc.EventKeyboard# */{ _keyCode: 0, _isPressed: false, - ctor: function (keyCode, isPressed) { cc.Event.prototype.ctor.call(this, cc.Event.KEYBOARD); this._keyCode = keyCode; @@ -52,11 +52,10 @@ cc.EventKeyboard = cc.Event.extend(/** @lends cc.EventKeyboard# */{ }); - - //Acceleration cc._EventListenerAcceleration = cc.EventListener.extend({ _onAccelerationEvent: null, + ctor: function (callback) { this._onAccelerationEvent = callback; var selfPointer = this; @@ -112,7 +111,7 @@ cc._EventListenerKeyboard = cc.EventListener.extend({ }, checkAvailable: function () { - if (this.onKeyPressed == null && this.onKeyReleased == null) { + if (this.onKeyPressed === null && this.onKeyReleased === null) { cc.log(cc._LogInfos._EventListenerKeyboard_checkAvailable); return false; } diff --git a/cocos2d/core/event-manager/CCEventListener.js b/cocos2d/core/event-manager/CCEventListener.js index 8d5baaf3ac..3c9dbab79d 100644 --- a/cocos2d/core/event-manager/CCEventListener.js +++ b/cocos2d/core/event-manager/CCEventListener.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2014 Chukong Technologies Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -40,7 +41,7 @@ cc.EventListener = cc.Class.extend(/** @lends cc.EventListener# */{ _fixedPriority: 0, // The higher the number, the higher the priority, 0 is for scene graph base priority. _node: null, // scene graph based priority - _paused: false, // Whether the listener is paused + _paused: true, // Whether the listener is paused _isEnabled: true, // Whether the listener is enabled /** @@ -161,7 +162,7 @@ cc.EventListener = cc.Class.extend(/** @lends cc.EventListener# */{ * @returns {boolean} */ checkAvailable: function () { - return this._onEvent != null; + return this._onEvent !== null; }, /** @@ -193,12 +194,33 @@ cc.EventListener = cc.Class.extend(/** @lends cc.EventListener# */{ }, /** - * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. - * This is a hack, and should be removed once JSB fixes the retain/release bug + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created a listener and haven't added it any target node during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.EventListener#release */ retain:function () { }, + /** + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created a listener and haven't added it any target node during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.EventListener#retain + */ release:function () { } }); @@ -240,12 +262,25 @@ cc.EventListener.MOUSE = 4; * @type {number} */ cc.EventListener.ACCELERATION = 5; +/** + * The type code of focus event listener. + * @constant + * @type {number} + */ +cc.EventListener.ACCELERATION = 6; /** * The type code of custom event listener. * @constant * @type {number} */ -cc.EventListener.CUSTOM = 6; +cc.EventListener.CUSTOM = 8; + +/** + * The type code of Focus change event listener. + * @constant + * @type {number} + */ +cc.EventListener.FOCUS = 7; cc._EventListenerCustom = cc.EventListener.extend({ _onCustomEvent: null, @@ -253,7 +288,7 @@ cc._EventListenerCustom = cc.EventListener.extend({ this._onCustomEvent = callback; var selfPointer = this; var listener = function (event) { - if (selfPointer._onCustomEvent != null) + if (selfPointer._onCustomEvent !== null) selfPointer._onCustomEvent(event); }; @@ -261,7 +296,7 @@ cc._EventListenerCustom = cc.EventListener.extend({ }, checkAvailable: function () { - return (cc.EventListener.prototype.checkAvailable.call(this) && this._onCustomEvent != null); + return (cc.EventListener.prototype.checkAvailable.call(this) && this._onCustomEvent !== null); }, clone: function () { @@ -344,6 +379,10 @@ cc._EventListenerTouchOneByOne = cc.EventListener.extend({ this.swallowTouches = needSwallow; }, + isSwallowTouches: function(){ + return this.swallowTouches; + }, + clone: function () { var eventListener = new cc._EventListenerTouchOneByOne(); eventListener.onTouchBegan = this.onTouchBegan; @@ -389,8 +428,8 @@ cc._EventListenerTouchAllAtOnce = cc.EventListener.extend({ }, checkAvailable: function(){ - if (this.onTouchesBegan == null && this.onTouchesMoved == null - && this.onTouchesEnded == null && this.onTouchesCancelled == null) { + if (this.onTouchesBegan === null && this.onTouchesMoved === null + && this.onTouchesEnded === null && this.onTouchesCancelled === null) { cc.log(cc._LogInfos._EventListenerTouchAllAtOnce_checkAvailable); return false; } @@ -406,8 +445,11 @@ cc._EventListenerTouchAllAtOnce.create = function(){ /** * Create a EventListener object by json object + * @function + * @static * @param {object} argObj a json object * @returns {cc.EventListener} + * todo: It should be the direct use new * @example * cc.EventListener.create({ * event: cc.EventListener.TOUCH_ONE_BY_ONE, @@ -441,11 +483,37 @@ cc.EventListener.create = function(argObj){ else if(listenerType === cc.EventListener.ACCELERATION){ listener = new cc._EventListenerAcceleration(argObj.callback); delete argObj.callback; - } + } else if(listenerType === cc.EventListener.FOCUS) + listener = new cc._EventListenerFocus(); for(var key in argObj) { listener[key] = argObj[key]; } return listener; -}; \ No newline at end of file +}; + +cc._EventListenerFocus = cc.EventListener.extend({ + clone: function(){ + var listener = new cc._EventListenerFocus(); + listener.onFocusChanged = this.onFocusChanged; + return listener; + }, + checkAvailable: function(){ + if(!this.onFocusChanged){ + cc.log("Invalid EventListenerFocus!"); + return false; + } + return true; + }, + onFocusChanged: null, + ctor: function(){ + var listener = function(event){ + if(this.onFocusChanged) + this.onFocusChanged(event._widgetLoseFocus, event._widgetGetFocus); + }; + cc.EventListener.prototype.ctor.call(this, cc.EventListener.FOCUS, cc._EventListenerFocus.LISTENER_ID, listener); + } +}); + +cc._EventListenerFocus.LISTENER_ID = "__cc_focus_event"; \ No newline at end of file diff --git a/cocos2d/core/event-manager/CCEventManager.js b/cocos2d/core/event-manager/CCEventManager.js index 9fa5c881b9..46ba136659 100644 --- a/cocos2d/core/event-manager/CCEventManager.js +++ b/cocos2d/core/event-manager/CCEventManager.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,17 +24,8 @@ ****************************************************************************/ /** - * copy an array's item to a new array (its performance is better than Array.slice) - * @param {Array} arr - * @returns {Array} + * @ignore */ -cc.copyArray = function(arr){ - var i, len = arr.length, arr_clone = new Array(len); - for (i = 0; i < len; i += 1) - arr_clone[i] = arr[i]; - return arr_clone; -}; - cc._EventListenerVector = cc.Class.extend({ _fixedListeners: null, _sceneGraphListeners: null, @@ -53,7 +45,7 @@ cc._EventListenerVector = cc.Class.extend({ }, push: function (listener) { - if (listener._getFixedPriority() == 0) + if (listener._getFixedPriority() === 0) this._sceneGraphListeners.push(listener); else this._fixedListeners.push(listener); @@ -91,6 +83,8 @@ cc.__getListenerID = function (event) { return cc._EventListenerKeyboard.LISTENER_ID; if(getType === eventType.MOUSE) return cc._EventListenerMouse.LISTENER_ID; + if(getType === eventType.FOCUS) + return cc._EventListenerFocus.LISTENER_ID; if(getType === eventType.TOUCH){ // Touch listener is very special, it contains two kinds of listeners, EventListenerTouchOneByOne and EventListenerTouchAllAtOnce. // return UNKNOWN instead. @@ -100,12 +94,14 @@ cc.__getListenerID = function (event) { }; /** - * @namespace

- * This class manages event listener subscriptions and event dispatching.
+ *

+ * cc.eventManager is a singleton object which manages event listener subscriptions and event dispatching.
*
- * The EventListener list is managed in such a way that event listeners can be added and removed even
- * from within an EventListener, while events are being dispatched. + * The EventListener list is managed in such way so that event listeners can be added and removed
+ * while events are being dispatched. *

+ * @class + * @name cc.eventManager */ cc.eventManager = /** @lends cc.eventManager# */{ //Priority dirty flag @@ -189,11 +185,11 @@ cc.eventManager = /** @lends cc.eventManager# */{ } listeners.push(listener); - if (listener._getFixedPriority() == 0) { + if (listener._getFixedPriority() === 0) { this._setDirty(listenerID, this.DIRTY_SCENE_GRAPH_PRIORITY); var node = listener._getSceneGraphPriority(); - if (node == null) + if (node === null) cc.log(cc._LogInfos.eventManager__forceAddEventListener); this._associateNodeAndEventListener(node, listener); @@ -208,7 +204,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ }, _updateDirtyFlagForSceneGraph: function () { - if (this._dirtyNodes.length == 0) + if (this._dirtyNodes.length === 0) return; var locDirtyNodes = this._dirtyNodes, selListeners, selListener, locNodeListenersMap = this._nodeListenersMap; @@ -266,7 +262,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ var locToAddedListeners = this._toAddedListeners, listener; for (i = 0; i < locToAddedListeners.length;) { listener = locToAddedListeners[i]; - if (listener && listener._getListenerID() == listenerID) + if (listener && listener._getListenerID() === listenerID) cc.arrayRemoveObject(locToAddedListeners, listener); else ++i; @@ -278,7 +274,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ if (locFlagMap[listenerID]) dirtyFlag = locFlagMap[listenerID]; - if (dirtyFlag != this.DIRTY_NONE) { + if (dirtyFlag !== this.DIRTY_NONE) { // Clear the dirty flag first, if `rootNode` is null, then set its dirty flag of scene graph priority locFlagMap[listenerID] = this.DIRTY_NONE; @@ -315,7 +311,10 @@ cc.eventManager = /** @lends cc.eventManager# */{ }, _sortEventListenersOfSceneGraphPriorityDes : function(l1, l2){ - var locNodePriorityMap = cc.eventManager._nodePriorityMap; + var locNodePriorityMap = cc.eventManager._nodePriorityMap, node1 = l1._getSceneGraphPriority(), + node2 = l2._getSceneGraphPriority(); + if(!l1 || !l2 || !node1 || !node2 || !locNodePriorityMap[node1.__instanceId] || !locNodePriorityMap[node2.__instanceId]) + return -1; return locNodePriorityMap[l2._getSceneGraphPriority().__instanceId] - locNodePriorityMap[l1._getSceneGraphPriority().__instanceId]; }, @@ -382,17 +381,18 @@ cc.eventManager = /** @lends cc.eventManager# */{ _updateListeners: function (event) { var locInDispatch = this._inDispatch; - cc.assert(locInDispatch > 0, "If program goes here, there should be event in dispatch."); - if (event.getType() == cc.Event.TOUCH) { + cc.assert(locInDispatch > 0, cc._LogInfos.EventManager__updateListeners); + + if(locInDispatch > 1) + return; + + if (event.getType() === cc.Event.TOUCH) { this._onUpdateListeners(cc._EventListenerTouchOneByOne.LISTENER_ID); this._onUpdateListeners(cc._EventListenerTouchAllAtOnce.LISTENER_ID); } else this._onUpdateListeners(cc.__getListenerID(event)); - if(locInDispatch > 1) - return; - - cc.assert(locInDispatch == 1, "_inDispatch should be 1 here."); + cc.assert(locInDispatch === 1, cc._LogInfos.EventManager__updateListeners_2); var locListenersMap = this._listenersMap, locPriorityDirtyFlagMap = this._priorityDirtyFlagMap; for (var selKey in locListenersMap) { if (locListenersMap[selKey].empty()) { @@ -419,14 +419,14 @@ cc.eventManager = /** @lends cc.eventManager# */{ var isClaimed = false, removedIdx; var getCode = event.getEventCode(), eventCode = cc.EventTouch.EventCode; - if (getCode == eventCode.BEGAN) { + if (getCode === eventCode.BEGAN) { if (listener.onTouchBegan) { isClaimed = listener.onTouchBegan(selTouch, event); if (isClaimed && listener._registered) listener._claimedTouches.push(selTouch); } } else if (listener._claimedTouches.length > 0 - && ((removedIdx = listener._claimedTouches.indexOf(selTouch)) != -1)) { + && ((removedIdx = listener._claimedTouches.indexOf(selTouch)) !== -1)) { isClaimed = true; if(getCode === eventCode.MOVED && listener.onTouchMoved){ listener.onTouchMoved(selTouch, event); @@ -465,7 +465,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ var allAtOnceListeners = this._getListeners(cc._EventListenerTouchAllAtOnce.LISTENER_ID); // If there aren't any touch listeners, return directly. - if (null == oneByOneListeners && null == allAtOnceListeners) + if (null === oneByOneListeners && null === allAtOnceListeners) return; var originalTouches = event.getTouches(), mutableTouches = cc.copyArray(originalTouches); @@ -501,13 +501,13 @@ cc.eventManager = /** @lends cc.eventManager# */{ var eventCode = cc.EventTouch.EventCode, event = callbackParams.event, touches = callbackParams.touches, getCode = event.getEventCode(); event._setCurrentTarget(listener._node); - if(getCode == eventCode.BEGAN && listener.onTouchesBegan) + if(getCode === eventCode.BEGAN && listener.onTouchesBegan) listener.onTouchesBegan(touches, event); - else if(getCode == eventCode.MOVED && listener.onTouchesMoved) + else if(getCode === eventCode.MOVED && listener.onTouchesMoved) listener.onTouchesMoved(touches, event); - else if(getCode == eventCode.ENDED && listener.onTouchesEnded) + else if(getCode === eventCode.ENDED && listener.onTouchesEnded) listener.onTouchesEnded(touches, event); - else if(getCode == eventCode.CANCELLED && listener.onTouchesCancelled) + else if(getCode === eventCode.CANCELLED && listener.onTouchesCancelled) listener.onTouchesCancelled(touches, event); // If the event was stopped, return directly. @@ -650,27 +650,25 @@ cc.eventManager = /** @lends cc.eventManager# */{ * A lower priority will be called before the ones that have a higher value. 0 priority is forbidden for fixed priority since it's used for scene graph based priority. * The listener must be a cc.EventListener object when adding a fixed priority listener, because we can't remove a fixed priority listener without the listener handler, * except calls removeAllListeners(). + * @return {cc.EventListener} Return the listener. Needed in order to remove the event from the dispatcher. */ addListener: function (listener, nodeOrPriority) { - cc.assert(listener && nodeOrPriority, cc._LogInfos.eventManager_addListener_2); - if(!(listener instanceof cc.EventListener)){ - - cc.assert(typeof nodeOrPriority !== "number", cc._LogInfos.eventManager_addListener_3); - + cc.assert(!cc.isNumber(nodeOrPriority), cc._LogInfos.eventManager_addListener_3); listener = cc.EventListener.create(listener); - } else{ - - cc.assert(!listener._isRegistered(), cc._LogInfos.eventManager_addListener_4); - + } else { + if(listener._isRegistered()){ + cc.log(cc._LogInfos.eventManager_addListener_4); + return; + } } if (!listener.checkAvailable()) return; - if (typeof nodeOrPriority == "number") { - if (nodeOrPriority == 0) { + if (cc.isNumber(nodeOrPriority)) { + if (nodeOrPriority === 0) { cc.log(cc._LogInfos.eventManager_addListener); return; } @@ -686,6 +684,8 @@ cc.eventManager = /** @lends cc.eventManager# */{ listener._setRegistered(true); this._addListener(listener); } + + return listener; }, /** @@ -695,7 +695,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ * @return {cc.EventListener} the generated event. Needed in order to remove the event from the dispatcher */ addCustomListener: function (eventName, callback) { - var listener = cc._EventListenerCustom.create(eventName, callback); + var listener = new cc._EventListenerCustom(eventName, callback); this.addListener(listener, 1); return listener; }, @@ -736,8 +736,9 @@ cc.eventManager = /** @lends cc.eventManager# */{ var locToAddedListeners = this._toAddedListeners; for (var i = 0, len = locToAddedListeners.length; i < len; i++) { var selListener = locToAddedListeners[i]; - if (selListener == listener) { + if (selListener === listener) { cc.arrayRemoveObject(locToAddedListeners, selListener); + selListener._setRegistered(false); break; } } @@ -750,14 +751,14 @@ cc.eventManager = /** @lends cc.eventManager# */{ for (var i = 0, len = listeners.length; i < len; i++) { var selListener = listeners[i]; - if (selListener == listener) { + if (selListener === listener) { selListener._setRegistered(false); if (selListener._getSceneGraphPriority() != null){ this._dissociateNodeAndEventListener(selListener._getSceneGraphPriority(), selListener); selListener._setSceneGraphPriority(null); // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes. } - if (this._inDispatch == 0) + if (this._inDispatch === 0) cc.arrayRemoveObject(listeners, selListener); return true; } @@ -777,14 +778,13 @@ cc.eventManager = /** @lends cc.eventManager# */{ // Don't want any dangling pointers or the possibility of dealing with deleted objects.. delete _t._nodePriorityMap[listenerType.__instanceId]; cc.arrayRemoveObject(_t._dirtyNodes, listenerType); - var listeners = _t._nodeListenersMap[listenerType.__instanceId]; - if (!listeners) - return; - - var listenersCopy = cc.copyArray(listeners), i; - for (i = 0; i < listenersCopy.length; i++) - _t.removeListener(listenersCopy[i]); - listenersCopy.length = 0; + var listeners = _t._nodeListenersMap[listenerType.__instanceId], i; + if (listeners) { + var listenersCopy = cc.copyArray(listeners); + for (i = 0; i < listenersCopy.length; i++) + _t.removeListener(listenersCopy[i]); + listenersCopy.length = 0; + } // Bug fix: ensure there are no references to the node in the list of listeners to be added. // If we find any listeners associated with the destroyed node in this list then remove them. @@ -794,7 +794,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ var locToAddedListeners = _t._toAddedListeners; for (i = 0; i < locToAddedListeners.length; ) { var listener = locToAddedListeners[i]; - if (listener._getSceneGraphPriority() == listenerType) { + if (listener._getSceneGraphPriority() === listenerType) { listener._setSceneGraphPriority(null); // Ensure no dangling ptr to the target node. listener._setRegistered(false); locToAddedListeners.splice(i, 1); @@ -808,15 +808,15 @@ cc.eventManager = /** @lends cc.eventManager# */{ _t.removeListeners(locChildren[i], true); } } else { - if (listenerType == cc.EventListener.TOUCH_ONE_BY_ONE) + if (listenerType === cc.EventListener.TOUCH_ONE_BY_ONE) _t._removeListenersForListenerID(cc._EventListenerTouchOneByOne.LISTENER_ID); - else if (listenerType == cc.EventListener.TOUCH_ALL_AT_ONCE) + else if (listenerType === cc.EventListener.TOUCH_ALL_AT_ONCE) _t._removeListenersForListenerID(cc._EventListenerTouchAllAtOnce.LISTENER_ID); - else if (listenerType == cc.EventListener.MOUSE) + else if (listenerType === cc.EventListener.MOUSE) _t._removeListenersForListenerID(cc._EventListenerMouse.LISTENER_ID); - else if (listenerType == cc.EventListener.ACCELERATION) + else if (listenerType === cc.EventListener.ACCELERATION) _t._removeListenersForListenerID(cc._EventListenerAcceleration.LISTENER_ID); - else if (listenerType == cc.EventListener.KEYBOARD) + else if (listenerType === cc.EventListener.KEYBOARD) _t._removeListenersForListenerID(cc._EventListenerKeyboard.LISTENER_ID); else cc.log(cc._LogInfos.eventManager_removeListeners); @@ -857,7 +857,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ var fixedPriorityListeners = selListeners.getFixedPriorityListeners(); if (fixedPriorityListeners) { var found = fixedPriorityListeners.indexOf(listener); - if (found != -1) { + if (found !== -1) { if(listener._getSceneGraphPriority() != null) cc.log(cc._LogInfos.eventManager_setPriority); if (listener._getFixedPriority() !== fixedPriority) { @@ -898,7 +898,7 @@ cc.eventManager = /** @lends cc.eventManager# */{ this._inDispatch++; if(!event || !event.getType) throw "event is undefined"; - if (event.getType() == cc.Event.TOUCH) { + if (event.getType() === cc.Event.TOUCH) { this._dispatchTouchEvent(event); this._inDispatch--; return; @@ -930,4 +930,98 @@ cc.eventManager = /** @lends cc.eventManager# */{ ev.setUserData(optionalUserData); this.dispatchEvent(ev); } -}; \ No newline at end of file +}; + +// The event helper +cc.EventHelper = function(){}; + +cc.EventHelper.prototype = { + constructor: cc.EventHelper, + + apply: function ( object ) { + object.addEventListener = cc.EventHelper.prototype.addEventListener; + object.hasEventListener = cc.EventHelper.prototype.hasEventListener; + object.removeEventListener = cc.EventHelper.prototype.removeEventListener; + object.dispatchEvent = cc.EventHelper.prototype.dispatchEvent; + }, + + addEventListener: function ( type, listener, target ) { + //check 'type' status, if the status is ready, dispatch event next frame + if(type === "load" && this._textureLoaded){ //only load event checked. + setTimeout(function(){ + listener.call(target); + }, 0); + return; + } + + if ( this._listeners === undefined ) + this._listeners = {}; + + var listeners = this._listeners; + if ( listeners[ type ] === undefined ) + listeners[ type ] = []; + + if ( !this.hasEventListener(type, listener, target)) + listeners[ type ].push( {callback:listener, eventTarget: target} ); + }, + + hasEventListener: function ( type, listener, target ) { + if ( this._listeners === undefined ) + return false; + + var listeners = this._listeners; + if ( listeners[ type ] !== undefined ) { + for(var i = 0, len = listeners.length; i < len ; i++){ + var selListener = listeners[i]; + if(selListener.callback === listener && selListener.eventTarget === target) + return true; + } + } + return false; + }, + + removeEventListener: function( type, target){ + if ( this._listeners === undefined ) + return; + + var listeners = this._listeners; + var listenerArray = listeners[ type ]; + + if ( listenerArray !== undefined ) { + for(var i = 0; i < listenerArray.length ; ){ + var selListener = listenerArray[i]; + if(selListener.eventTarget === target) + listenerArray.splice( i, 1 ); + else + i++ + } + } + }, + + dispatchEvent: function ( event, clearAfterDispatch ) { + if ( this._listeners === undefined ) + return; + + if(clearAfterDispatch == null) + clearAfterDispatch = true; + var listeners = this._listeners; + var listenerArray = listeners[ event]; + + if ( listenerArray !== undefined ) { + var array = []; + var length = listenerArray.length; + + for ( var i = 0; i < length; i ++ ) { + array[ i ] = listenerArray[ i ]; + } + + for ( i = 0; i < length; i ++ ) { + array[ i ].callback.call( array[i].eventTarget, this ); + } + + if(clearAfterDispatch) + listenerArray.length = 0; + } + } +}; + diff --git a/cocos2d/core/event-manager/CCTouch.js b/cocos2d/core/event-manager/CCTouch.js index 2e3849bb7e..8a7c017aad 100644 --- a/cocos2d/core/event-manager/CCTouch.js +++ b/cocos2d/core/event-manager/CCTouch.js @@ -1,5 +1,5 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,9 +24,13 @@ ****************************************************************************/ /** - * The data of touch event + * The touch event class * @class * @extends cc.Class + * + * @param {Number} x + * @param {Number} y + * @param {Number} id */ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ _point:null, @@ -35,26 +39,23 @@ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ _startPointCaptured: false, _startPoint:null, - /** - * Constructor - */ ctor:function (x, y, id) { this._point = cc.p(x || 0, y || 0); this._id = id || 0; }, /** - * returns the current touch location in OpenGL coordinates + * Returns the current touch location in OpenGL coordinates * @return {cc.Point} */ getLocation:function () { //TODO //return cc.director.convertToGL(this._point); - return this._point; + return {x: this._point.x, y: this._point.y}; }, /** - * gets location X axis data + * Returns X axis location value * @returns {number} */ getLocationX: function () { @@ -62,7 +63,7 @@ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ }, /** - * gets location Y axis data + * Returns Y axis location value * @returns {number} */ getLocationY: function () { @@ -70,27 +71,27 @@ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ }, /** - * returns the previous touch location in OpenGL coordinates + * Returns the previous touch location in OpenGL coordinates * @return {cc.Point} */ getPreviousLocation:function () { //TODO //return cc.director.convertToGL(this._prevPoint); - return this._prevPoint; + return {x: this._prevPoint.x, y: this._prevPoint.y}; }, /** - * returns the start touch location in OpenGL coordinates + * Returns the start touch location in OpenGL coordinates * @returns {cc.Point} */ getStartLocation: function() { //TODO //return cc.director.convertToGL(this._startPoint); - return this._startPoint; + return {x: this._startPoint.x, y: this._startPoint.y}; }, /** - * returns the delta of 2 current touches locations in screen coordinates + * Returns the delta distance from the previous touche to the current one in screen coordinates * @return {cc.Point} */ getDelta:function () { @@ -98,30 +99,31 @@ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ }, /** - * returns the current touch location in screen coordinates + * Returns the current touch location in screen coordinates * @return {cc.Point} */ getLocationInView: function() { - return this._point; + return {x: this._point.x, y: this._point.y}; }, /** - * returns the previous touch location in screen coordinates + * Returns the previous touch location in screen coordinates * @return {cc.Point} */ getPreviousLocationInView: function(){ - return this._prevPoint; + return {x: this._prevPoint.x, y: this._prevPoint.y}; }, /** - * returns the start touch location in screen coordinates + * Returns the start touch location in screen coordinates * @return {cc.Point} */ getStartLocationInView: function(){ - return this._startPoint; + return {x: this._startPoint.x, y: this._startPoint.y}; }, /** + * Returns the id of cc.Touch * @return {Number} */ getID:function () { @@ -129,14 +131,17 @@ cc.Touch = cc.Class.extend(/** @lends cc.Touch# */{ }, /** + * Returns the id of cc.Touch * @return {Number} + * @deprecated since v3.0, please use getID() instead */ getId:function () { + cc.log("getId is deprecated. Please use getID instead.") return this._id; }, /** - * set information to touch + * Sets information to touch * @param {Number} id * @param {Number} x * @param {Number} y diff --git a/cocos2d/core/labelttf/CCLabelTTF.js b/cocos2d/core/labelttf/CCLabelTTF.js index 3ef9e764a7..fb4855e6a5 100644 --- a/cocos2d/core/labelttf/CCLabelTTF.js +++ b/cocos2d/core/labelttf/CCLabelTTF.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,13 +25,28 @@ ****************************************************************************/ /** - * cc.LabelTTF is a subclass of cc.TextureNode that knows how to render text labels
- * All features from cc.TextureNode are valid in cc.LabelTTF
- * cc.LabelTTF objects are slow for js-binding on mobile devices.Consider using cc.LabelAtlas or cc.LabelBMFont instead.
+ *

cc.LabelTTF is a subclass of cc.TextureNode that knows how to render text labels with system font or a ttf font file
+ * All features from cc.Sprite are valid in cc.LabelTTF
+ * cc.LabelTTF objects are slow for js-binding on mobile devices.
* Consider using cc.LabelAtlas or cc.LabelBMFont instead.
+ * You can create a cc.LabelTTF from a font name, alignment, dimension and font size or a cc.FontDefinition object.

* @class * @extends cc.Sprite * + * @param {String} text + * @param {String|cc.FontDefinition} [fontName="Arial"] + * @param {Number} [fontSize=16] + * @param {cc.Size} [dimensions=cc.size(0,0)] + * @param {Number} [hAlignment=cc.TEXT_ALIGNMENT_LEFT] + * @param {Number} [vAlignment=cc.VERTICAL_TEXT_ALIGNMENT_TOP] + * @example + * var myLabel = new cc.LabelTTF('label text', 'Times New Roman', 32, cc.size(320,32), cc.TEXT_ALIGNMENT_LEFT); + * + * var fontDef = new cc.FontDefinition(); + * fontDef.fontName = "Arial"; + * fontDef.fontSize = "32"; + * var myLabel = new cc.LabelTTF('label text', fontDef); + * * @property {String} string - Content string of label * @property {Number} textAlign - Horizontal Alignment of label: cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT * @property {Number} verticalAlign - Vertical Alignment of label: cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM @@ -47,7 +62,6 @@ * @property {Number} shadowOffsetY - The y axis offset of shadow * @property {Number} shadowOpacity - The opacity of shadow * @property {Number} shadowBlur - The blur size of shadow - * */ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ _dimensions: null, @@ -57,53 +71,77 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ _fontSize: 0.0, _string: "", _originalText: null, - _isMultiLine: false, - _fontStyleStr: null, // font shadow _shadowEnabled: false, _shadowOffset: null, _shadowOpacity: 0, _shadowBlur: 0, - _shadowColorStr: null, + _shadowColor: null, // font stroke _strokeEnabled: false, _strokeColor: null, _strokeSize: 0, - _strokeColorStr: null, // font tint _textFillColor: null, - _fillColorStr: null, _strokeShadowOffsetX: 0, _strokeShadowOffsetY: 0, _needUpdateTexture: false, - _labelCanvas: null, - _labelContext: null, _lineWidths: null, _className: "LabelTTF", + //for web + _fontStyle: "normal", + _fontWeight: "normal", + _lineHeight: "normal", /** - * creates a cc.LabelTTF from a font name, alignment, dimension and font size - * @constructor - * @param {String} text - * @param {String|cc.FontDefinition} [fontName="Arial"] - * @param {Number} [fontSize=16] - * @param {cc.Size} [dimensions=cc.size(0,0)] - * @param {Number} [hAlignment=cc.TEXT_ALIGNMENT_LEFT] - * @param {Number} [vAlignment=cc.VERTICAL_TEXT_ALIGNMENT_TOP] - * @example - * var myLabel = new cc.LabelTTF('label text', 'Times New Roman', 32, cc.size(320,32), cc.TEXT_ALIGNMENT_LEFT); - * - * var fontDef = new cc.FontDefinition(); - * fontDef.fontName = "Arial"; - * fontDef.fontSize = "32"; - * var myLabel = new cc.LabelTTF('label text', fontDef); + * Initializes the cc.LabelTTF with a font name, alignment, dimension and font size, do not call it by yourself, + * you should pass the correct arguments in constructor to initialize the label. + * @param {String} label string + * @param {String} fontName + * @param {Number} fontSize + * @param {cc.Size} [dimensions=] + * @param {Number} [hAlignment=] + * @param {Number} [vAlignment=] + * @return {Boolean} return false on error */ + initWithString: function (label, fontName, fontSize, dimensions, hAlignment, vAlignment) { + var strInfo; + if (label) + strInfo = label + ""; + else + strInfo = ""; + + fontSize = fontSize || 16; + dimensions = dimensions || cc.size(0, 0/*fontSize*/); + hAlignment = hAlignment || cc.TEXT_ALIGNMENT_LEFT; + vAlignment = vAlignment || cc.VERTICAL_TEXT_ALIGNMENT_TOP; + + this._opacityModifyRGB = false; + this._dimensions = cc.size(dimensions.width, dimensions.height); + this._fontName = fontName || "Arial"; + this._hAlignment = hAlignment; + this._vAlignment = vAlignment; + + this._fontSize = fontSize; + this._renderCmd._setFontStyle(this._fontName, fontSize, this._fontStyle, this._fontWeight); + this.string = strInfo; + this._renderCmd._setColorsString(); + this._renderCmd._updateTexture(); + this._setUpdateTextureDirty(); + return true; + }, + + _setUpdateTextureDirty: function () { + this._needUpdateTexture = true; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.textDirty); + }, + ctor: function (text, fontName, fontSize, dimensions, hAlignment, vAlignment) { cc.Sprite.prototype.ctor.call(this); @@ -111,35 +149,29 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ this._hAlignment = cc.TEXT_ALIGNMENT_LEFT; this._vAlignment = cc.VERTICAL_TEXT_ALIGNMENT_TOP; this._opacityModifyRGB = false; - this._fontStyleStr = ""; this._fontName = "Arial"; - this._isMultiLine = false; this._shadowEnabled = false; this._shadowOffset = cc.p(0, 0); this._shadowOpacity = 0; this._shadowBlur = 0; - this._shadowColorStr = "rgba(128, 128, 128, 0.5)"; this._strokeEnabled = false; this._strokeColor = cc.color(255, 255, 255, 255); this._strokeSize = 0; - this._strokeColorStr = ""; this._textFillColor = cc.color(255, 255, 255, 255); - this._fillColorStr = "rgba(255,255,255,1)"; this._strokeShadowOffsetX = 0; this._strokeShadowOffsetY = 0; this._needUpdateTexture = false; this._lineWidths = []; - - this._setColorsString(); + this._renderCmd._setColorsString(); + this._textureLoaded = true; if (fontName && fontName instanceof cc.FontDefinition) { this.initWithStringAndTextDefinition(text, fontName); - } - else { + } else { cc.LabelTTF.prototype.initWithString.call(this, text, fontName, fontSize, dimensions, hAlignment, vAlignment); } }, @@ -148,91 +180,22 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ return this.initWithString(" ", this._fontName, this._fontSize); }, - _measureConfig: function () { - this._getLabelContext().font = this._fontStyleStr; - }, - _measure: function (text) { - return this._getLabelContext().measureText(text).width; - }, - _checkNextline: function (text, width) { - var tWidth = this._measure(text); - // Estimated word number per line - var baseNb = Math.floor(text.length * width / tWidth); - // Next line is a line with line break - var nextlinebreak = text.indexOf('\n'); - if (baseNb * 0.8 >= nextlinebreak && nextlinebreak > 0) return nextlinebreak + 1; - // Text width smaller than requested width - if (tWidth < width) return text.length; - - var found = false, l = width + 1, idfound = -1, index = baseNb, result, - re = cc.LabelTTF._checkRegEx, - reversre = cc.LabelTTF._reverseCheckRegEx, - enre = cc.LabelTTF._checkEnRegEx, - substr = text.substr(baseNb); - - // Forward check - // Find next special caracter or chinese caracters - while (result = re.exec(substr)) { - index += result[0].length; - var tem = text.substr(0, index); - l = this._measure(tem); - if (result[2] == '\n' && l < width) { - found = true; - idfound = index; - break; - } - if (l > width) { - if (idfound != -1) - found = true; - break; - } - idfound = index; - substr = text.substr(index); - } - if (found) return idfound; - - // Backward check when forward check failed - substr = text.substr(0, baseNb); - idfound = baseNb; - while (result = reversre.exec(substr)) { - // BUG: Not secured if check with result[0] - idfound = result[1].length; - substr = result[1]; - l = this._measure(substr); - if (l < width) { - if (enre.test(result[2])) - idfound++; - break; - } - } - - // Avoid when idfound == 0, the process may enter in a infinite loop - return idfound || 1; - }, - - /** - * Prints out a description of this class - * @return {String} - */ description: function () { return ""; }, - setColor: null, - - _setColorsString: null, - - updateDisplayedColor: null, - setOpacity: null, + getLineHeight: function () { + return !this._lineHeight || this._lineHeight.charAt ? + this._renderCmd._getFontClientHeight() : + this._lineHeight || this._renderCmd._getFontClientHeight(); + }, - updateDisplayedOpacity: null, - updateDisplayedOpacityForCanvas: function (parentOpacity) { - cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); - this._setColorsString(); + setLineHeight: function (lineHeight) { + this._lineHeight = lineHeight; }, /** - * returns the text of the label + * Returns the text of the label * @return {String} */ getString: function () { @@ -240,7 +203,7 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * return Horizontal Alignment of cc.LabelTTF + * Returns Horizontal Alignment of cc.LabelTTF * @return {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} */ getHorizontalAlignment: function () { @@ -248,7 +211,7 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * return Vertical Alignment of cc.LabelTTF + * Returns Vertical Alignment of cc.LabelTTF * @return {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} */ getVerticalAlignment: function () { @@ -256,15 +219,16 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * return Dimensions of cc.LabelTTF + * Returns the dimensions of cc.LabelTTF, the dimension is the maximum size of the label, set it so that label will automatically change lines when necessary. + * @see cc.LabelTTF#setDimensions, cc.LabelTTF#boundingWidth and cc.LabelTTF#boundingHeight * @return {cc.Size} */ getDimensions: function () { - return cc.size(this._dimensions.width, this._dimensions.height); + return cc.size(this._dimensions); }, /** - * return font size of cc.LabelTTF + * Returns font size of cc.LabelTTF * @return {Number} */ getFontSize: function () { @@ -272,7 +236,7 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * return font name of cc.LabelTTF + * Returns font name of cc.LabelTTF * @return {String} */ getFontName: function () { @@ -280,54 +244,21 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * initializes the cc.LabelTTF with a font name, alignment, dimension and font size - * @param {String} label string - * @param {String} fontName - * @param {Number} fontSize - * @param {cc.Size} [dimensions=] - * @param {Number} [hAlignment=] - * @param {Number} [vAlignment=] - * @return {Boolean} return false on error - */ - initWithString: function (label, fontName, fontSize, dimensions, hAlignment, vAlignment) { - var strInfo; - if (label) - strInfo = label + ""; - else - strInfo = ""; - - fontSize = fontSize || 16; - dimensions = dimensions || cc.size(0, fontSize); - hAlignment = hAlignment || cc.TEXT_ALIGNMENT_LEFT; - vAlignment = vAlignment || cc.VERTICAL_TEXT_ALIGNMENT_TOP; - - this._opacityModifyRGB = false; - this._dimensions = cc.size(dimensions.width, dimensions.height); - this._fontName = fontName || "Arial"; - this._hAlignment = hAlignment; - this._vAlignment = vAlignment; - - //this._fontSize = (cc._renderType === cc._RENDER_TYPE_CANVAS) ? fontSize : fontSize * cc.contentScaleFactor(); - this._fontSize = fontSize; - this._fontStyleStr = this._fontSize + "px '" + fontName + "'"; - this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(fontName, this._fontSize); - this.string = strInfo; - this._setColorsString(); - this._updateTexture(); - this._needUpdateTexture = false; - return true; - }, - - /** - * initializes the CCLabelTTF with a font name, alignment, dimension and font size + * Initializes the CCLabelTTF with a font name, alignment, dimension and font size, do not call it by yourself, you should pass the correct arguments in constructor to initialize the label. * @param {String} text * @param {cc.FontDefinition} textDefinition * @return {Boolean} */ - initWithStringAndTextDefinition: null, + initWithStringAndTextDefinition: function (text, textDefinition) { + // prepare everything needed to render the label + this._updateWithTextDefinition(textDefinition, false); + // set the string + this.string = text; + return true; + }, /** - * set the text definition used by this label + * Sets the text definition used by this label * @param {cc.FontDefinition} theDefinition */ setTextDefinition: function (theDefinition) { @@ -336,7 +267,7 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * get the text definition used by this label + * Extract the text definition used by this label * @return {cc.FontDefinition} */ getTextDefinition: function () { @@ -344,31 +275,61 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ }, /** - * enable or disable shadow for the label - * @param {cc.Point} shadowOffset - * @param {Number} shadowOpacity (0 to 1) - * @param {Number} shadowBlur + * Enable or disable shadow for the label + * @param {cc.Color | Number} a Color or The x axis offset of the shadow + * @param {cc.Size | Number} b Size or The y axis offset of the shadow + * @param {Number} c The blur size of the shadow or The opacity of the shadow (0 to 1) + * @param {null | Number} d Null or The blur size of the shadow + * @example + * old: + * labelttf.enableShadow(shadowOffsetX, shadowOffsetY, shadowOpacity, shadowBlur); + * new: + * labelttf.enableShadow(shadowColor, offset, blurRadius); */ - enableShadow: function (shadowOffsetX, shadowOffsetY, shadowOpacity, shadowBlur) { + enableShadow: function (a, b, c, d) { + if (a.r != null && a.g != null && a.b != null && a.a != null) { + this._enableShadow(a, b, c); + } else { + this._enableShadowNoneColor(a, b, c, d) + } + }, + + _enableShadowNoneColor: function (shadowOffsetX, shadowOffsetY, shadowOpacity, shadowBlur) { shadowOpacity = shadowOpacity || 0.5; if (false === this._shadowEnabled) this._shadowEnabled = true; var locShadowOffset = this._shadowOffset; - if (locShadowOffset && (locShadowOffset.x != shadowOffsetX) || (locShadowOffset._y != shadowOffsetY)) { + if (locShadowOffset && (locShadowOffset.x !== shadowOffsetX) || (locShadowOffset._y !== shadowOffsetY)) { locShadowOffset.x = shadowOffsetX; locShadowOffset.y = shadowOffsetY; } - if (this._shadowOpacity != shadowOpacity) { + if (this._shadowOpacity !== shadowOpacity) { this._shadowOpacity = shadowOpacity; } - this._setColorsString(); + this._renderCmd._setColorsString(); - if (this._shadowBlur != shadowBlur) + if (this._shadowBlur !== shadowBlur) this._shadowBlur = shadowBlur; + this._setUpdateTextureDirty(); + }, - this._needUpdateTexture = true; + _enableShadow: function (shadowColor, offset, blurRadius) { + if (!this._shadowColor) { + this._shadowColor = cc.color(255, 255, 255, 128); + } + this._shadowColor.r = shadowColor.r; + this._shadowColor.g = shadowColor.g; + this._shadowColor.b = shadowColor.b; + + var x, y, a, b; + x = offset.width || offset.x || 0; + y = offset.height || offset.y || 0; + a = (shadowColor.a != null) ? (shadowColor.a / 255) : 0.5; + b = blurRadius; + + this._enableShadowNoneColor(x, y, a, b); }, _getShadowOffsetX: function () { @@ -378,9 +339,9 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ if (false === this._shadowEnabled) this._shadowEnabled = true; - if (this._shadowOffset.x != x) { + if (this._shadowOffset.x !== x) { this._shadowOffset.x = x; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, @@ -391,9 +352,9 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ if (false === this._shadowEnabled) this._shadowEnabled = true; - if (this._shadowOffset._y != y) { + if (this._shadowOffset._y !== y) { this._shadowOffset._y = y; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, @@ -404,10 +365,10 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ if (false === this._shadowEnabled) this._shadowEnabled = true; - if (this._shadowOffset.x != offset.x || this._shadowOffset.y != offset.y) { + if (this._shadowOffset.x !== offset.x || this._shadowOffset.y !== offset.y) { this._shadowOffset.x = offset.x; this._shadowOffset.y = offset.y; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, @@ -418,10 +379,10 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ if (false === this._shadowEnabled) this._shadowEnabled = true; - if (this._shadowOpacity != shadowOpacity) { + if (this._shadowOpacity !== shadowOpacity) { this._shadowOpacity = shadowOpacity; - this._setColorsString(); - this._needUpdateTexture = true; + this._renderCmd._setColorsString(); + this._setUpdateTextureDirty(); } }, @@ -432,26 +393,26 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ if (false === this._shadowEnabled) this._shadowEnabled = true; - if (this._shadowBlur != shadowBlur) { + if (this._shadowBlur !== shadowBlur) { this._shadowBlur = shadowBlur; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * disable shadow rendering + * Disable shadow rendering */ disableShadow: function () { if (this._shadowEnabled) { this._shadowEnabled = false; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * enable or disable stroke - * @param {cc.Color} strokeColor - * @param {Number} strokeSize + * Enable label stroke with stroke parameters + * @param {cc.Color} strokeColor The color of stroke + * @param {Number} strokeSize The size of stroke */ enableStroke: function (strokeColor, strokeSize) { if (this._strokeEnabled === false) @@ -462,13 +423,12 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ locStrokeColor.r = strokeColor.r; locStrokeColor.g = strokeColor.g; locStrokeColor.b = strokeColor.b; - this._setColorsString(); + this._renderCmd._setColorsString(); } if (this._strokeSize !== strokeSize) this._strokeSize = strokeSize || 0; - - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); }, _getStrokeStyle: function () { @@ -483,9 +443,8 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ locStrokeColor.r = strokeStyle.r; locStrokeColor.g = strokeStyle.g; locStrokeColor.b = strokeStyle.b; - this._setColorsString(); - - this._needUpdateTexture = true; + this._renderCmd._setColorsString(); + this._setUpdateTextureDirty(); } }, @@ -495,29 +454,37 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ _setLineWidth: function (lineWidth) { if (this._strokeEnabled === false) this._strokeEnabled = true; - if (this._strokeSize !== lineWidth) { this._strokeSize = lineWidth || 0; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * disable stroke + * Disable label stroke */ disableStroke: function () { if (this._strokeEnabled) { this._strokeEnabled = false; - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * set text tinting + * Sets the text fill color * @function - * @param {cc.Color} tintColor + * @param {cc.Color} fillColor The fill color of the label */ - setFontFillColor: null, + setFontFillColor: function (fillColor) { + var locTextFillColor = this._textFillColor; + if (locTextFillColor.r !== fillColor.r || locTextFillColor.g !== fillColor.g || locTextFillColor.b !== fillColor.b) { + locTextFillColor.r = fillColor.r; + locTextFillColor.g = fillColor.g; + locTextFillColor.b = fillColor.b; + this._renderCmd._setColorsString(); + this._needUpdateTexture = true; + } + }, _getFillStyle: function () { return this._textFillColor; @@ -538,8 +505,14 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ this._fontName = textDefinition.fontName; this._fontSize = textDefinition.fontSize || 12; - this._fontStyleStr = this._fontSize + "px '" + this._fontName + "'"; - this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(this._fontName, this._fontSize); + + if(textDefinition.lineHeight) + this._lineHeight = textDefinition.lineHeight + else + this._lineHeight = this._fontSize; + + this._renderCmd._setFontStyle(textDefinition); + // shadow if (textDefinition.shadowEnabled) @@ -556,14 +529,15 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ this.setFontFillColor(textDefinition.fillStyle); if (mustUpdateTexture) - this._updateTexture(); + this._renderCmd._updateTexture(); + var flags = cc.Node._dirtyFlags; + this._renderCmd.setDirtyFlag(flags.colorDirty|flags.opacityDirty|flags.textDirty); }, _prepareTextDefinition: function (adjustForResolution) { var texDef = new cc.FontDefinition(); if (adjustForResolution) { - //texDef.fontSize = (cc._renderType === cc._RENDER_TYPE_CANVAS) ? this._fontSize : this._fontSize * cc.contentScaleFactor(); texDef.fontSize = this._fontSize; texDef.boundingWidth = cc.contentScaleFactor() * this._dimensions.width; texDef.boundingHeight = cc.contentScaleFactor() * this._dimensions.height; @@ -603,62 +577,73 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ return texDef; }, - _fontClientHeight: 18, /** - * changes the string to render + * Changes the text content of the label * @warning Changing the string is as expensive as creating a new cc.LabelTTF. To obtain better performance use cc.LabelAtlas - * @param {String} text text for the label + * @param {String} text Text content for the label */ setString: function (text) { text = String(text); - if (this._originalText != text) { + if (this._originalText !== text) { this._originalText = text + ""; this._updateString(); // Force update - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); } }, _updateString: function () { + if ((!this._string || this._string === "") && this._string !== this._originalText) + cc.renderer.childrenOrderDirty = true; this._string = this._originalText; }, + /** - * set Horizontal Alignment of cc.LabelTTF + * Sets Horizontal Alignment of cc.LabelTTF * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment Horizontal Alignment */ setHorizontalAlignment: function (alignment) { if (alignment !== this._hAlignment) { this._hAlignment = alignment; - // Force update - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * set Vertical Alignment of cc.LabelTTF + * Sets Vertical Alignment of cc.LabelTTF * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} verticalAlignment */ setVerticalAlignment: function (verticalAlignment) { - if (verticalAlignment != this._vAlignment) { + if (verticalAlignment !== this._vAlignment) { this._vAlignment = verticalAlignment; // Force update - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * set Dimensions of cc.LabelTTF - * @param {cc.Size} dim + * Set Dimensions of cc.LabelTTF, the dimension is the maximum size of the label, set it so that label will automatically change lines when necessary. + * @param {cc.Size|Number} dim dimensions or width of dimensions + * @param {Number} [height] height of dimensions */ - setDimensions: function (dim) { - if (dim.width != this._dimensions.width || dim.height != this._dimensions.height) { - this._dimensions = dim; + setDimensions: function (dim, height) { + var width; + if (height === undefined) { + width = dim.width; + height = dim.height; + } else + width = dim; + + if (width !== this._dimensions.width || height !== this._dimensions.height) { + this._dimensions.width = width; + this._dimensions.height = height; this._updateString(); - // Force udpate - this._needUpdateTexture = true; + // Force update + this._setUpdateTextureDirty(); } }, @@ -666,11 +651,11 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ return this._dimensions.width; }, _setBoundingWidth: function (width) { - if (width != this._dimensions.width) { + if (width !== this._dimensions.width) { this._dimensions.width = width; this._updateString(); - // Force udpate - this._needUpdateTexture = true; + // Force update + this._setUpdateTextureDirty(); } }, @@ -678,470 +663,126 @@ cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ return this._dimensions.height; }, _setBoundingHeight: function (height) { - if (height != this._dimensions.height) { + if (height !== this._dimensions.height) { this._dimensions.height = height; this._updateString(); - // Force udpate - this._needUpdateTexture = true; + // Force update + this._setUpdateTextureDirty(); } }, /** - * set font size of cc.LabelTTF + * Sets font size of cc.LabelTTF * @param {Number} fontSize */ setFontSize: function (fontSize) { if (this._fontSize !== fontSize) { this._fontSize = fontSize; - this._fontStyleStr = fontSize + "px '" + this._fontName + "'"; - this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(this._fontName, fontSize); + this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight); // Force update - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, /** - * set font name of cc.LabelTTF + * Sets font name of cc.LabelTTF * @param {String} fontName */ setFontName: function (fontName) { - if (this._fontName && this._fontName != fontName) { + if (this._fontName && this._fontName !== fontName) { this._fontName = fontName; - this._fontStyleStr = this._fontSize + "px '" + fontName + "'"; - this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(fontName, this._fontSize); + this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight); // Force update - this._needUpdateTexture = true; + this._setUpdateTextureDirty(); } }, _getFont: function () { - return this._fontStyleStr; + return this._renderCmd._getFontStyle(); }, _setFont: function (fontStyle) { var res = cc.LabelTTF._fontStyleRE.exec(fontStyle); if (res) { this._fontSize = parseInt(res[1]); this._fontName = res[2]; - this._fontStyleStr = fontStyle; - this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(this._fontName, this._fontSize); - // Force update - this._needUpdateTexture = true; - } - }, + this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight); - _drawTTFInCanvas: function (context) { - if (!context) - return; - var locStrokeShadowOffsetX = this._strokeShadowOffsetX, locStrokeShadowOffsetY = this._strokeShadowOffsetY; - var locContentSizeHeight = this._contentSize.height - locStrokeShadowOffsetY, locVAlignment = this._vAlignment, locHAlignment = this._hAlignment, - locFontHeight = this._fontClientHeight, locStrokeSize = this._strokeSize; - - context.setTransform(1, 0, 0, 1, 0 + locStrokeShadowOffsetX * 0.5, locContentSizeHeight + locStrokeShadowOffsetY * 0.5); - - //this is fillText for canvas - if (context.font != this._fontStyleStr) - context.font = this._fontStyleStr; - context.fillStyle = this._fillColorStr; - - var xOffset = 0, yOffset = 0; - //stroke style setup - var locStrokeEnabled = this._strokeEnabled; - if (locStrokeEnabled) { - context.lineWidth = locStrokeSize * 2; - context.strokeStyle = this._strokeColorStr; - } - - //shadow style setup - if (this._shadowEnabled) { - var locShadowOffset = this._shadowOffset; - context.shadowColor = this._shadowColorStr; - context.shadowOffsetX = locShadowOffset.x; - context.shadowOffsetY = -locShadowOffset.y; - context.shadowBlur = this._shadowBlur; - } - - context.textBaseline = cc.LabelTTF._textBaseline[locVAlignment]; - context.textAlign = cc.LabelTTF._textAlign[locHAlignment]; - - var locContentWidth = this._contentSize.width - locStrokeShadowOffsetX; - if (locHAlignment === cc.TEXT_ALIGNMENT_RIGHT) - xOffset += locContentWidth; - else if (locHAlignment === cc.TEXT_ALIGNMENT_CENTER) - xOffset += locContentWidth / 2; - else - xOffset += 0; - if (this._isMultiLine) { - var locStrLen = this._strings.length; - if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) - yOffset = locFontHeight + locContentSizeHeight - locFontHeight * locStrLen; - else if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_CENTER) - yOffset = locFontHeight / 2 + (locContentSizeHeight - locFontHeight * locStrLen) / 2; - - for (var i = 0; i < locStrLen; i++) { - var line = this._strings[i]; - var tmpOffsetY = -locContentSizeHeight + (locFontHeight * i) + yOffset; - if (locStrokeEnabled) - context.strokeText(line, xOffset, tmpOffsetY); - context.fillText(line, xOffset, tmpOffsetY); - } - } else { - if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) { - if (locStrokeEnabled) - context.strokeText(this._string, xOffset, yOffset); - context.fillText(this._string, xOffset, yOffset); - } else if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_TOP) { - yOffset -= locContentSizeHeight; - if (locStrokeEnabled) - context.strokeText(this._string, xOffset, yOffset); - context.fillText(this._string, xOffset, yOffset); - } else { - yOffset -= locContentSizeHeight * 0.5; - if (locStrokeEnabled) - context.strokeText(this._string, xOffset, yOffset); - context.fillText(this._string, xOffset, yOffset); - } - } - }, - - _getLabelContext: function () { - if (this._labelContext) - return this._labelContext; - - if (!this._labelCanvas) { - var locCanvas = cc.newElement("canvas"); - var labelTexture = new cc.Texture2D(); - labelTexture.initWithElement(locCanvas); - this.texture = labelTexture; - this._labelCanvas = locCanvas; - } - this._labelContext = this._labelCanvas.getContext("2d"); - return this._labelContext; - }, - - _updateTTF: function () { - var locDimensionsWidth = this._dimensions.width, i, strLength; - var locLineWidth = this._lineWidths; - locLineWidth.length = 0; - - this._isMultiLine = false; - this._measureConfig(); - if (locDimensionsWidth !== 0) { - // Content processing - var text = this._string; - this._strings = []; - for (i = 0, strLength = this._string.length; i < strLength;) { - // Find the index of next line - var next = this._checkNextline(text.substr(i), locDimensionsWidth); - var append = text.substr(i, next); - this._strings.push(append); - i += next; - } - } else { - this._strings = this._string.split('\n'); - for (i = 0, strLength = this._strings.length; i < strLength; i++) { - locLineWidth.push(this._measure(this._strings[i])); - } - } - - if (this._strings.length > 0) - this._isMultiLine = true; - - var locSize, locStrokeShadowOffsetX = 0, locStrokeShadowOffsetY = 0; - if (this._strokeEnabled) - locStrokeShadowOffsetX = locStrokeShadowOffsetY = this._strokeSize * 2; - if (this._shadowEnabled) { - var locOffsetSize = this._shadowOffset; - locStrokeShadowOffsetX += Math.abs(locOffsetSize.x) * 2; - locStrokeShadowOffsetY += Math.abs(locOffsetSize.y) * 2; - } - - //get offset for stroke and shadow - if (locDimensionsWidth === 0) { - if (this._isMultiLine) - locSize = cc.size(0 | (Math.max.apply(Math, locLineWidth) + locStrokeShadowOffsetX), - 0 | ((this._fontClientHeight * this._strings.length) + locStrokeShadowOffsetY)); - else - locSize = cc.size(0 | (this._measure(this._string) + locStrokeShadowOffsetX), 0 | (this._fontClientHeight + locStrokeShadowOffsetY)); - } else { - if (this._dimensions.height === 0) { - if (this._isMultiLine) - locSize = cc.size(0 | (locDimensionsWidth + locStrokeShadowOffsetX), 0 | ((this._fontClientHeight * this._strings.length) + locStrokeShadowOffsetY)); - else - locSize = cc.size(0 | (locDimensionsWidth + locStrokeShadowOffsetX), 0 | (this._fontClientHeight + locStrokeShadowOffsetY)); - } else { - //dimension is already set, contentSize must be same as dimension - locSize = cc.size(0 | (locDimensionsWidth + locStrokeShadowOffsetX), 0 | (this._dimensions.height + locStrokeShadowOffsetY)); - } + // Force update + this._setUpdateTextureDirty(); } - this.setContentSize(locSize); - this._strokeShadowOffsetX = locStrokeShadowOffsetX; - this._strokeShadowOffsetY = locStrokeShadowOffsetY; - - // need computing _anchorPointInPoints - var locAP = this._anchorPoint; - this._anchorPointInPoints.x = (locStrokeShadowOffsetX * 0.5) + ((locSize.width - locStrokeShadowOffsetX) * locAP.x); - this._anchorPointInPoints.y = (locStrokeShadowOffsetY * 0.5) + ((locSize.height - locStrokeShadowOffsetY) * locAP.y); }, + /** + * Returns the actual content size of the label, the content size is the real size that the label occupied while dimension is the outer bounding box of the label. + * @returns {cc.Size} The content size + */ getContentSize: function () { if (this._needUpdateTexture) - this._updateTTF(); + this._renderCmd._updateTTF(); return cc.Sprite.prototype.getContentSize.call(this); }, _getWidth: function () { if (this._needUpdateTexture) - this._updateTTF(); + this._renderCmd._updateTTF(); return cc.Sprite.prototype._getWidth.call(this); }, _getHeight: function () { if (this._needUpdateTexture) - this._updateTTF(); + this._renderCmd._updateTTF(); return cc.Sprite.prototype._getHeight.call(this); }, - _updateTexture: function () { - var locContext = this._getLabelContext(), locLabelCanvas = this._labelCanvas; - var locContentSize = this._contentSize; - - if (this._string.length === 0) { - locLabelCanvas.width = 1; - locLabelCanvas.height = locContentSize.height; - this.setTextureRect(cc.rect(0, 0, 1, locContentSize.height)); - return true; - } + setTextureRect: function (rect, rotated, untrimmedSize) { + //set needConvert to false + cc.Sprite.prototype.setTextureRect.call(this, rect, rotated, untrimmedSize, false); + }, - //set size for labelCanvas - locContext.font = this._fontStyleStr; - this._updateTTF(); - var width = locContentSize.width, height = locContentSize.height; - var flag = locLabelCanvas.width == width && locLabelCanvas.height == height; - locLabelCanvas.width = width; - locLabelCanvas.height = height; - if (flag) locContext.clearRect(0, 0, width, height); + _createRenderCmd: function () { + if (cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.LabelTTF.CanvasRenderCmd(this); + else + return new cc.LabelTTF.WebGLRenderCmd(this); + }, - //draw text to labelCanvas - this._drawTTFInCanvas(locContext); - this._texture && this._texture.handleLoadedTexture(); + //For web only + _setFontStyle: function(fontStyle){ + if (this._fontStyle !== fontStyle) { + this._fontStyle = fontStyle; + this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight); + this._setUpdateTextureDirty(); + } + }, - this.setTextureRect(cc.rect(0, 0, width, height)); - return true; + _getFontStyle: function(){ + return this._fontStyle; }, - visit: function (ctx) { - if (!this._string || this._string == "") - return; - if (this._needUpdateTexture) { - this._needUpdateTexture = false; - this._updateTexture(); + _setFontWeight: function(fontWeight){ + if (this._fontWeight !== fontWeight) { + this._fontWeight = fontWeight; + this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight); + this._setUpdateTextureDirty(); } - var context = ctx || cc._renderContext; - cc.Sprite.prototype.visit.call(this, context); }, - /** - * Draw sprite to canvas - * @function - * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx Render context of canvas, 2d or 3d - */ - draw: null, - - _setTextureCoords: function (rect) { - var tex = this._batchNode ? this.textureAtlas.texture : this._texture; - if (!tex) - return; - - var atlasWidth = tex.pixelsWidth; - var atlasHeight = tex.pixelsHeight; - - var left, right, top, bottom, tempSwap, locQuad = this._quad; - if (this._rectRotated) { - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (2 * rect.x + 1) / (2 * atlasWidth); - right = left + (rect.height * 2 - 2) / (2 * atlasWidth); - top = (2 * rect.y + 1) / (2 * atlasHeight); - bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight); - } else { - left = rect.x / atlasWidth; - right = (rect.x + rect.height) / atlasWidth; - top = rect.y / atlasHeight; - bottom = (rect.y + rect.width) / atlasHeight; - }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if (this._flippedX) { - tempSwap = top; - top = bottom; - bottom = tempSwap; - } - - if (this._flippedY) { - tempSwap = left; - left = right; - right = tempSwap; - } - - locQuad.bl.texCoords.u = left; - locQuad.bl.texCoords.v = top; - locQuad.br.texCoords.u = left; - locQuad.br.texCoords.v = bottom; - locQuad.tl.texCoords.u = right; - locQuad.tl.texCoords.v = top; - locQuad.tr.texCoords.u = right; - locQuad.tr.texCoords.v = bottom; - } else { - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (2 * rect.x + 1) / (2 * atlasWidth); - right = left + (rect.width * 2 - 2) / (2 * atlasWidth); - top = (2 * rect.y + 1) / (2 * atlasHeight); - bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight); - } else { - left = rect.x / atlasWidth; - right = (rect.x + rect.width) / atlasWidth; - top = rect.y / atlasHeight; - bottom = (rect.y + rect.height) / atlasHeight; - } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if (this._flippedX) { - tempSwap = left; - left = right; - right = tempSwap; - } - - if (this._flippedY) { - tempSwap = top; - top = bottom; - bottom = tempSwap; - } - - locQuad.bl.texCoords.u = left; - locQuad.bl.texCoords.v = bottom; - locQuad.br.texCoords.u = right; - locQuad.br.texCoords.v = bottom; - locQuad.tl.texCoords.u = left; - locQuad.tl.texCoords.v = top; - locQuad.tr.texCoords.u = right; - locQuad.tr.texCoords.v = top; - } - this._quadDirty = true; + _getFontWeight: function(){ + return this._fontWeight; } }); -if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - - var _p = cc.LabelTTF.prototype; - - _p.setColor = function (color3) { - cc.NodeRGBA.prototype.setColor.call(this, color3); - - this._setColorsString(); - }; - - _p._setColorsString = function () { - this._needUpdateTexture = true; - - var locDisplayColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity; - var locStrokeColor = this._strokeColor, locFontFillColor = this._textFillColor; - - this._shadowColorStr = "rgba(" + (0 | (locDisplayColor.r * 0.5)) + "," + (0 | (locDisplayColor.g * 0.5)) + "," + (0 | (locDisplayColor.b * 0.5)) + "," + this._shadowOpacity + ")"; - this._fillColorStr = "rgba(" + (0 | (locDisplayColor.r / 255 * locFontFillColor.r)) + "," + (0 | (locDisplayColor.g / 255 * locFontFillColor.g)) + "," - + (0 | (locDisplayColor.b / 255 * locFontFillColor.b)) + ", " + locDisplayedOpacity / 255 + ")"; - this._strokeColorStr = "rgba(" + (0 | (locDisplayColor.r / 255 * locStrokeColor.r)) + "," + (0 | (locDisplayColor.g / 255 * locStrokeColor.g)) + "," - + (0 | (locDisplayColor.b / 255 * locStrokeColor.b)) + ", " + locDisplayedOpacity / 255 + ")"; - }; - - _p.updateDisplayedColor = function (parentColor) { - cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor); - this._setColorsString(); - }; - - _p.setOpacity = function (opacity) { - if (this._opacity === opacity) - return; - cc.Sprite.prototype.setOpacity.call(this, opacity); - this._setColorsString(); - this._needUpdateTexture = true; - }; - - //TODO: _p._updateDisplayedOpacityForCanvas - _p.updateDisplayedOpacity = cc.Sprite.prototype.updateDisplayedOpacity; - - _p.initWithStringAndTextDefinition = function (text, textDefinition) { - // prepare everything needed to render the label - this._updateWithTextDefinition(textDefinition, false); - - // set the string - this.string = text; - - return true; - }; - - _p.setFontFillColor = function (tintColor) { - var locTextFillColor = this._textFillColor; - if (locTextFillColor.r != tintColor.r || locTextFillColor.g != tintColor.g || locTextFillColor.b != tintColor.b) { - locTextFillColor.r = tintColor.r; - locTextFillColor.g = tintColor.g; - locTextFillColor.b = tintColor.b; - - this._setColorsString(); - this._needUpdateTexture = true; - } - }; - - _p.draw = cc.Sprite.prototype.draw; - - _p.setTextureRect = function (rect, rotated, untrimmedSize) { - this._rectRotated = rotated || false; - untrimmedSize = untrimmedSize || rect; - - this.setContentSize(untrimmedSize); - this.setVertexRect(rect); - - var locTextureCoordRect = this._textureRect_Canvas; - locTextureCoordRect.x = rect.x; - locTextureCoordRect.y = rect.y; - locTextureCoordRect.width = rect.width; - locTextureCoordRect.height = rect.height; - locTextureCoordRect.validRect = !(locTextureCoordRect.width === 0 || locTextureCoordRect.height === 0 - || locTextureCoordRect.x < 0 || locTextureCoordRect.y < 0); - - var relativeOffset = this._unflippedOffsetPositionFromCenter; - if (this._flippedX) - relativeOffset.x = -relativeOffset.x; - if (this._flippedY) - relativeOffset.y = -relativeOffset.y; - this._offsetPosition.x = relativeOffset.x + (this._contentSize.width - this._rect.width) / 2; - this._offsetPosition.y = relativeOffset.y + (this._contentSize.height - this._rect.height) / 2; - - // rendering using batch node - if (this._batchNode) { - this.dirty = true; - } - }; - _p = null; - -} else { - _tmp.WebGLLabelTTF(); - delete _tmp.WebGLLabelTTF; -} - - -_tmp.PrototypeLabelTTF(); -delete _tmp.PrototypeLabelTTF; - -cc.LabelTTF._textAlign = ["left", "center", "right"]; - -cc.LabelTTF._textBaseline = ["top", "middle", "bottom"]; - -// Class static properties for measure util -cc.LabelTTF._checkRegEx = /(.+?)([\s\n\r\-\/\\\:]|[\u4E00-\u9FA5]|[\uFE30-\uFFA0])/; -cc.LabelTTF._reverseCheckRegEx = /(.*)([\s\n\r\-\/\\\:]|[\u4E00-\u9FA5]|[\uFE30-\uFFA0])/; -cc.LabelTTF._checkEnRegEx = /[\s\-\/\\\:]/; +cc.assert(cc.isFunction(cc._tmp.PrototypeLabelTTF), cc._LogInfos.MissingFile, "LabelTTFPropertyDefine.js"); +cc._tmp.PrototypeLabelTTF(); +delete cc._tmp.PrototypeLabelTTF; // Only support style in this format: "18px Verdana" or "18px 'Helvetica Neue'" cc.LabelTTF._fontStyleRE = /^(\d+)px\s+['"]?([\w\s\d]+)['"]?$/; /** * creates a cc.LabelTTF from a font name, alignment, dimension and font size + * @deprecated since v3.0, please use the new construction instead + * @see cc.LabelTTF + * @static * @param {String} text * @param {String|cc.FontDefinition} [fontName="Arial"] * @param {Number} [fontSize=16] @@ -1149,20 +790,17 @@ cc.LabelTTF._fontStyleRE = /^(\d+)px\s+['"]?([\w\s\d]+)['"]?$/; * @param {Number} [hAlignment=cc.TEXT_ALIGNMENT_LEFT] * @param {Number} [vAlignment=cc.VERTICAL_TEXT_ALIGNMENT_TOP] * @return {cc.LabelTTF|Null} - * @example - * // Example - * 1. - * var myLabel = cc.LabelTTF.create('label text', 'Times New Roman', 32, cc.size(320,32), cc.TEXT_ALIGNMENT_LEFT); - * 2. - * var fontDef = new cc.FontDefinition(); - * fontDef.fontName = "Arial"; - * fontDef.fontSize = "32"; - * var myLabel = cc.LabelTTF.create('label text', fontDef); */ cc.LabelTTF.create = function (text, fontName, fontSize, dimensions, hAlignment, vAlignment) { return new cc.LabelTTF(text, fontName, fontSize, dimensions, hAlignment, vAlignment); }; +/** + * @deprecated since v3.0, please use the new construction instead + * @function + * @static + */ +cc.LabelTTF.createWithFontDefinition = cc.LabelTTF.create; if (cc.USE_LA88_LABELS) cc.LabelTTF._SHADER_PROGRAM = cc.SHADER_POSITION_TEXTURECOLOR; @@ -1175,9 +813,35 @@ cc.LabelTTF.__labelHeightDiv.style.position = "absolute"; cc.LabelTTF.__labelHeightDiv.style.left = "-100px"; cc.LabelTTF.__labelHeightDiv.style.top = "-100px"; cc.LabelTTF.__labelHeightDiv.style.lineHeight = "normal"; -document.body.appendChild(cc.LabelTTF.__labelHeightDiv); + +document.body ? + document.body.appendChild(cc.LabelTTF.__labelHeightDiv) : + cc._addEventListener(window, 'load', function () { + this.removeEventListener('load', arguments.callee, false); + document.body.appendChild(cc.LabelTTF.__labelHeightDiv); + }, false); cc.LabelTTF.__getFontHeightByDiv = function (fontName, fontSize) { + + if(fontName instanceof cc.FontDefinition){ + /** @type cc.FontDefinition */ + var fontDef = fontName; + var clientHeight = cc.LabelTTF.__fontHeightCache[fontDef._getCanvasFontStr()]; + if (clientHeight > 0) return clientHeight; + var labelDiv = cc.LabelTTF.__labelHeightDiv; + labelDiv.innerHTML = "ajghl~!"; + labelDiv.style.fontFamily = fontDef.fontName; + labelDiv.style.fontSize = fontDef.fontSize + "px"; + labelDiv.style.fontStyle = fontDef.fontStyle; + labelDiv.style.fontWeight = fontDef.fontWeight; + + clientHeight = labelDiv.clientHeight; + cc.LabelTTF.__fontHeightCache[fontDef._getCanvasFontStr()] = clientHeight; + labelDiv.innerHTML = ""; + return clientHeight; + } + + //Default var clientHeight = cc.LabelTTF.__fontHeightCache[fontName + "." + fontSize]; if (clientHeight > 0) return clientHeight; var labelDiv = cc.LabelTTF.__labelHeightDiv; @@ -1188,6 +852,7 @@ cc.LabelTTF.__getFontHeightByDiv = function (fontName, fontSize) { cc.LabelTTF.__fontHeightCache[fontName + "." + fontSize] = clientHeight; labelDiv.innerHTML = ""; return clientHeight; + }; cc.LabelTTF.__fontHeightCache = {}; \ No newline at end of file diff --git a/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js b/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js new file mode 100644 index 0000000000..fa687f865a --- /dev/null +++ b/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js @@ -0,0 +1,429 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +cc.LabelTTF._textAlign = ["left", "center", "right"]; +cc.LabelTTF._textBaseline = ["top", "middle", "bottom"]; + +//check the first character +cc.LabelTTF.wrapInspection = true; + +//Support: English French German +//Other as Oriental Language +cc.LabelTTF._wordRex = /([a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]+|\S)/; +cc.LabelTTF._symbolRex = /^[!,.:;}\]%\?>、‘“》?。,!]/; +cc.LabelTTF._lastWordRex = /([a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]+|\S)$/; +cc.LabelTTF._lastEnglish = /[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]+$/; +cc.LabelTTF._firsrEnglish = /^[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]/; + +(function() { + cc.LabelTTF.RenderCmd = function () { + this._fontClientHeight = 18; + this._fontStyleStr = ""; + this._shadowColorStr = "rgba(128, 128, 128, 0.5)"; + this._strokeColorStr = ""; + this._fillColorStr = "rgba(255,255,255,1)"; + + this._labelCanvas = null; + this._labelContext = null; + this._lineWidths = []; + this._strings = []; + this._isMultiLine = false; + }; + var proto = cc.LabelTTF.RenderCmd.prototype; + + proto.constructor = cc.LabelTTF.RenderCmd; + + proto._getLabelContext = function () { + if (this._labelContext) + return this._labelContext; + + var node = this._node; + if (!this._labelCanvas) { + var locCanvas = cc.newElement("canvas"); + locCanvas.width = 1; + locCanvas.height = 1; + var labelTexture = new cc.Texture2D(); + labelTexture.initWithElement(locCanvas); + node.setTexture(labelTexture); + this._labelCanvas = locCanvas; + } + this._labelContext = this._labelCanvas.getContext("2d"); + return this._labelContext; + }; + + proto._setFontStyle = function (fontNameOrFontDef, fontSize, fontStyle, fontWeight) { + + if(fontNameOrFontDef instanceof cc.FontDefinition){ + this._fontStyleStr = fontNameOrFontDef._getCanvasFontStr(); + this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(fontNameOrFontDef); + + }else { + this._fontStyleStr = fontStyle + " " + fontWeight + " " + fontSize + "px '" + fontNameOrFontDef + "'"; + this._fontClientHeight = cc.LabelTTF.__getFontHeightByDiv(fontNameOrFontDef, fontSize); + } + }; + + proto._getFontStyle = function () { + return this._fontStyleStr; + }; + + proto._getFontClientHeight = function () { + return this._fontClientHeight; + }; + + proto._updateTexture = function () { + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.textDirty ^ this._dirtyFlag; + var node = this._node; + var locContext = this._getLabelContext(), locLabelCanvas = this._labelCanvas; + var locContentSize = node._contentSize; + + if (node._string.length === 0) { + locLabelCanvas.width = 1; + locLabelCanvas.height = locContentSize.height || 1; + node._texture && node._texture.handleLoadedTexture(); + node.setTextureRect(cc.rect(0, 0, 1, locContentSize.height)); + return true; + } + + //set size for labelCanvas + locContext.font = this._fontStyleStr; + this._updateTTF(); + var width = locContentSize.width, height = locContentSize.height; + var flag = locLabelCanvas.width === width && locLabelCanvas.height === height; + locLabelCanvas.width = width; + locLabelCanvas.height = height; + if (flag) locContext.clearRect(0, 0, width, height); + + //draw text to labelCanvas + this._drawTTFInCanvas(locContext); + node._texture && node._texture.handleLoadedTexture(); + + node.setTextureRect(cc.rect(0, 0, width, height)); + return true; + }; + + proto._measureConfig = function () { + this._getLabelContext().font = this._fontStyleStr; + }; + + proto._measure = function (text) { + return this._getLabelContext().measureText(text).width; + }; + + proto._updateTTF = function () { + var node = this._node; + var locDimensionsWidth = node._dimensions.width, i, strLength; + var locLineWidth = this._lineWidths; + locLineWidth.length = 0; + + this._isMultiLine = false; + this._measureConfig(); + if (locDimensionsWidth !== 0) { + // Content processing + this._strings = node._string.split('\n'); + + for (i = 0; i < this._strings.length; i++) { + this._checkWarp(this._strings, i, locDimensionsWidth); + } + } else { + this._strings = node._string.split('\n'); + for (i = 0, strLength = this._strings.length; i < strLength; i++) { + locLineWidth.push(this._measure(this._strings[i])); + } + } + + if (this._strings.length > 0) + this._isMultiLine = true; + + var locSize, locStrokeShadowOffsetX = 0, locStrokeShadowOffsetY = 0; + if (node._strokeEnabled) + locStrokeShadowOffsetX = locStrokeShadowOffsetY = node._strokeSize * 2; + if (node._shadowEnabled) { + var locOffsetSize = node._shadowOffset; + locStrokeShadowOffsetX += Math.abs(locOffsetSize.x) * 2; + locStrokeShadowOffsetY += Math.abs(locOffsetSize.y) * 2; + } + + //get offset for stroke and shadow + if (locDimensionsWidth === 0) { + if (this._isMultiLine) + locSize = cc.size(Math.ceil(Math.max.apply(Math, locLineWidth) + locStrokeShadowOffsetX), + Math.ceil((this._fontClientHeight * this._strings.length) + locStrokeShadowOffsetY)); + else + locSize = cc.size(Math.ceil(this._measure(node._string) + locStrokeShadowOffsetX), Math.ceil(this._fontClientHeight + locStrokeShadowOffsetY)); + } else { + if (node._dimensions.height === 0) { + if (this._isMultiLine) + locSize = cc.size(Math.ceil(locDimensionsWidth + locStrokeShadowOffsetX), Math.ceil((node.getLineHeight() * this._strings.length) + locStrokeShadowOffsetY)); + else + locSize = cc.size(Math.ceil(locDimensionsWidth + locStrokeShadowOffsetX), Math.ceil(node.getLineHeight() + locStrokeShadowOffsetY)); + } else { + //dimension is already set, contentSize must be same as dimension + locSize = cc.size(Math.ceil(locDimensionsWidth + locStrokeShadowOffsetX), Math.ceil(node._dimensions.height + locStrokeShadowOffsetY)); + } + } + if(node._getFontStyle() !== "normal"){ //add width for 'italic' and 'oblique' + locSize.width = Math.ceil(locSize.width + node._fontSize * 0.3); + } + node.setContentSize(locSize); + node._strokeShadowOffsetX = locStrokeShadowOffsetX; + node._strokeShadowOffsetY = locStrokeShadowOffsetY; + + // need computing _anchorPointInPoints + var locAP = node._anchorPoint; + this._anchorPointInPoints.x = (locStrokeShadowOffsetX * 0.5) + ((locSize.width - locStrokeShadowOffsetX) * locAP.x); + this._anchorPointInPoints.y = (locStrokeShadowOffsetY * 0.5) + ((locSize.height - locStrokeShadowOffsetY) * locAP.y); + }; + + proto._drawTTFInCanvas = function (context) { + if (!context) + return; + var node = this._node; + var locStrokeShadowOffsetX = node._strokeShadowOffsetX, locStrokeShadowOffsetY = node._strokeShadowOffsetY; + var locContentSizeHeight = node._contentSize.height - locStrokeShadowOffsetY, locVAlignment = node._vAlignment, + locHAlignment = node._hAlignment, locStrokeSize = node._strokeSize; + + context.setTransform(1, 0, 0, 1, locStrokeShadowOffsetX * 0.5, locContentSizeHeight + locStrokeShadowOffsetY * 0.5); + + //this is fillText for canvas + if (context.font !== this._fontStyleStr) + context.font = this._fontStyleStr; + context.fillStyle = this._fillColorStr; + + var xOffset = 0, yOffset = 0; + //stroke style setup + var locStrokeEnabled = node._strokeEnabled; + if (locStrokeEnabled) { + context.lineWidth = locStrokeSize * 2; + context.strokeStyle = this._strokeColorStr; + } + + //shadow style setup + if (node._shadowEnabled) { + var locShadowOffset = node._shadowOffset; + context.shadowColor = this._shadowColorStr; + context.shadowOffsetX = locShadowOffset.x; + context.shadowOffsetY = -locShadowOffset.y; + context.shadowBlur = node._shadowBlur; + } + + context.textBaseline = cc.LabelTTF._textBaseline[locVAlignment]; + context.textAlign = cc.LabelTTF._textAlign[locHAlignment]; + + var locContentWidth = node._contentSize.width - locStrokeShadowOffsetX; + + //lineHeight + var lineHeight = node.getLineHeight(); + var transformTop = (lineHeight - this._fontClientHeight) / 2; + + if (locHAlignment === cc.TEXT_ALIGNMENT_RIGHT) + xOffset += locContentWidth; + else if (locHAlignment === cc.TEXT_ALIGNMENT_CENTER) + xOffset += locContentWidth / 2; + else + xOffset += 0; + if (this._isMultiLine) { + var locStrLen = this._strings.length; + if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) + yOffset = lineHeight - transformTop * 2 + locContentSizeHeight - lineHeight * locStrLen; + else if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_CENTER) + yOffset = (lineHeight - transformTop * 2) / 2 + (locContentSizeHeight - lineHeight * locStrLen) / 2; + + for (var i = 0; i < locStrLen; i++) { + var line = this._strings[i]; + var tmpOffsetY = -locContentSizeHeight + (lineHeight * i + transformTop) + yOffset; + if (locStrokeEnabled) + context.strokeText(line, xOffset, tmpOffsetY); + context.fillText(line, xOffset, tmpOffsetY); + } + } else { + if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) { + //do nothing + } else if (locVAlignment === cc.VERTICAL_TEXT_ALIGNMENT_TOP) { + yOffset -= locContentSizeHeight; + } else { + yOffset -= locContentSizeHeight * 0.5; + } + if (locStrokeEnabled) + context.strokeText(node._string, xOffset, yOffset); + context.fillText(node._string, xOffset, yOffset); + } + }; + + proto._checkWarp = function (strArr, i, maxWidth) { + var text = strArr[i]; + var allWidth = this._measure(text); + if (allWidth > maxWidth && text.length > 1) { + + var fuzzyLen = text.length * ( maxWidth / allWidth ) | 0; + var tmpText = text.substr(fuzzyLen); + var width = allWidth - this._measure(tmpText); + var sLine; + var pushNum = 0; + + //Increased while cycle maximum ceiling. default 100 time + var checkWhile = 0; + + //Exceeded the size + while (width > maxWidth && checkWhile++ < 100) { + fuzzyLen *= maxWidth / width; + fuzzyLen = fuzzyLen | 0; + tmpText = text.substr(fuzzyLen); + width = allWidth - this._measure(tmpText); + } + + checkWhile = 0; + + //Find the truncation point + while (width < maxWidth && checkWhile++ < 100) { + if (tmpText) { + var exec = cc.LabelTTF._wordRex.exec(tmpText); + pushNum = exec ? exec[0].length : 1; + sLine = tmpText; + } + + fuzzyLen = fuzzyLen + pushNum; + tmpText = text.substr(fuzzyLen); + width = allWidth - this._measure(tmpText); + } + + fuzzyLen -= pushNum; + if (fuzzyLen === 0) { + fuzzyLen = 1; + sLine = sLine.substr(1); + } + + var sText = text.substr(0, fuzzyLen), result; + + //symbol in the first + if (cc.LabelTTF.wrapInspection) { + if (cc.LabelTTF._symbolRex.test(sLine || tmpText)) { + result = cc.LabelTTF._lastWordRex.exec(sText); + fuzzyLen -= result ? result[0].length : 0; + + sLine = text.substr(fuzzyLen); + sText = text.substr(0, fuzzyLen); + } + } + + //To judge whether a English words are truncated + if (cc.LabelTTF._firsrEnglish.test(sLine)) { + result = cc.LabelTTF._lastEnglish.exec(sText); + if (result && sText !== result[0]) { + fuzzyLen -= result[0].length; + sLine = text.substr(fuzzyLen); + sText = text.substr(0, fuzzyLen); + } + } + + strArr[i] = sLine || tmpText; + strArr.splice(i, 0, sText); + } + }; +})(); + +(function(){ + cc.LabelTTF.CanvasRenderCmd = function (renderable) { + cc.Sprite.CanvasRenderCmd.call(this, renderable); + cc.LabelTTF.RenderCmd.call(this); + }; + + cc.LabelTTF.CanvasRenderCmd.prototype = Object.create(cc.Sprite.CanvasRenderCmd.prototype); + cc.inject(cc.LabelTTF.RenderCmd.prototype, cc.LabelTTF.CanvasRenderCmd.prototype); + + var proto = cc.LabelTTF.CanvasRenderCmd.prototype; + proto.constructor = cc.LabelTTF.CanvasRenderCmd; + + proto.updateStatus = function () { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + if (colorDirty) + this._updateDisplayColor(); + if (opacityDirty) + this._updateDisplayOpacity(); + + if(colorDirty){ + this._updateColor(); + }else if(locFlag & flags.textDirty) + this._updateTexture(); + + if (this._dirtyFlag & flags.transformDirty){ + this.transform(this.getParentRenderCmd(), true); + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.transformDirty ^ this._dirtyFlag; + } + }; + + proto._syncStatus = function (parentCmd) { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + this._syncDisplayColor(); + if (opacityDirty) + this._syncDisplayOpacity(); + + if(colorDirty){ + this._updateColor(); + }else if(locFlag & flags.textDirty) + this._updateTexture(); + + if (locFlag & flags.transformDirty) //update the transform + this.transform(parentCmd); + }; + + proto._setColorsString = function () { + var locDisplayColor = this._displayedColor, node = this._node, + locShadowColor = node._shadowColor || this._displayedColor; + var locStrokeColor = node._strokeColor, locFontFillColor = node._textFillColor; + var dr = locDisplayColor.r / 255, dg = locDisplayColor.g / 255, db = locDisplayColor.b / 255; + + this._shadowColorStr = "rgba(" + (0 | (dr * locShadowColor.r)) + "," + (0 | ( dg * locShadowColor.g)) + "," + + (0 | (db * locShadowColor.b)) + "," + node._shadowOpacity + ")"; + this._fillColorStr = "rgba(" + (0 | (dr * locFontFillColor.r)) + "," + (0 | (dg * locFontFillColor.g)) + "," + + (0 | (db * locFontFillColor.b)) + ", 1)"; + this._strokeColorStr = "rgba(" + (0 | (dr * locStrokeColor.r)) + "," + (0 | (dg * locStrokeColor.g)) + "," + + (0 | (db * locStrokeColor.b)) + ", 1)"; + }; + + proto._updateColor = function(){ + this._setColorsString(); + this._updateTexture(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/labelttf/CCLabelTTFWebGLRenderCmd.js b/cocos2d/core/labelttf/CCLabelTTFWebGLRenderCmd.js new file mode 100644 index 0000000000..dfa2893e61 --- /dev/null +++ b/cocos2d/core/labelttf/CCLabelTTFWebGLRenderCmd.js @@ -0,0 +1,102 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +// ----------------------------------- LabelTTF WebGL render cmd ---------------------------- +(function() { + cc.LabelTTF.WebGLRenderCmd = function (renderable) { + cc.Sprite.WebGLRenderCmd.call(this, renderable); + cc.LabelTTF.RenderCmd.call(this); + this.setShaderProgram(cc.shaderCache.programForKey(cc.LabelTTF._SHADER_PROGRAM)); + }; + + var proto = cc.LabelTTF.WebGLRenderCmd.prototype = Object.create(cc.Sprite.WebGLRenderCmd.prototype); + cc.inject(cc.LabelTTF.RenderCmd.prototype, proto); //multi-inherit + proto.constructor = cc.LabelTTF.WebGLRenderCmd; + + proto._setColorsString = function () { + this.setDirtyFlag(cc.Node._dirtyFlags.textDirty); + var node = this._node; + var locStrokeColor = node._strokeColor, locFontFillColor = node._textFillColor, + locShadowColor = node._shadowColor || this._displayedColor; + this._shadowColorStr = "rgba(" + (0 | locShadowColor.r) + "," + (0 | locShadowColor.g) + "," + (0 | locShadowColor.b) + "," + node._shadowOpacity + ")"; + this._fillColorStr = "rgba(" + (0 | locFontFillColor.r) + "," + (0 | locFontFillColor.g) + "," + (0 | locFontFillColor.b) + ", 1)"; + this._strokeColorStr = "rgba(" + (0 | locStrokeColor.r) + "," + (0 | locStrokeColor.g) + "," + (0 | locStrokeColor.b) + ", 1)"; + }; + + proto.updateStatus = function () { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + if (colorDirty) + this._updateDisplayColor(); + if (opacityDirty) + this._updateDisplayOpacity(); + + if(colorDirty || opacityDirty){ + this._setColorsString(); + this._updateColor(); + this._updateTexture(); + }else if(locFlag & flags.textDirty) + this._updateTexture(); + + if (this._dirtyFlag & flags.transformDirty){ + this.transform(this.getParentRenderCmd(), true); + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.transformDirty ^ this._dirtyFlag; + } + }; + + proto._syncStatus = function (parentCmd) { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + this._syncDisplayColor(); + if (opacityDirty) + this._syncDisplayOpacity(); + + if(colorDirty || opacityDirty){ + this._setColorsString(); + this._updateColor(); + this._updateTexture(); + }else if(locFlag & flags.textDirty) + this._updateTexture(); + + this.transform(parentCmd); + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/labelttf/LabelTTFPropertyDefine.js b/cocos2d/core/labelttf/LabelTTFPropertyDefine.js index f12b819296..71ff3a964a 100644 --- a/cocos2d/core/labelttf/LabelTTFPropertyDefine.js +++ b/cocos2d/core/labelttf/LabelTTFPropertyDefine.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,7 +25,7 @@ ****************************************************************************/ -_tmp.PrototypeLabelTTF = function () { +cc._tmp.PrototypeLabelTTF = function () { var _p = cc.LabelTTF.prototype; // Override properties diff --git a/cocos2d/core/labelttf/LabelTTFWebGL.js b/cocos2d/core/labelttf/LabelTTFWebGL.js deleted file mode 100644 index 99d05070ed..0000000000 --- a/cocos2d/core/labelttf/LabelTTFWebGL.js +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -_tmp.WebGLLabelTTF = function () { - - var _p = cc.LabelTTF.prototype; - - _p.setColor = cc.Sprite.prototype.setColor; - - _p._setColorsString = function () { - this._needUpdateTexture = true; - var locStrokeColor = this._strokeColor, locFontFillColor = this._textFillColor; - this._shadowColorStr = "rgba(128,128,128," + this._shadowOpacity + ")"; - this._fillColorStr = "rgba(" + (0 | locFontFillColor.r) + "," + (0 | locFontFillColor.g) + "," + (0 | locFontFillColor.b) + ", 1)"; - this._strokeColorStr = "rgba(" + (0 | locStrokeColor.r) + "," + (0 | locStrokeColor.g) + "," + (0 | locStrokeColor.b) + ", 1)"; - }; - - _p.updateDisplayedColor = cc.Sprite.prototype.updateDisplayedColor; - - _p.setOpacity = cc.Sprite.prototype.setOpacity; - - _p.updateDisplayedOpacity = cc.Sprite.prototype.updateDisplayedOpacity; - - _p.initWithStringAndTextDefinition = function (text, textDefinition) { - if (!cc.Sprite.prototype.init.call(this)) - return false; - - // shader program - this.shaderProgram = cc.shaderCache.programForKey(cc.LabelTTF._SHADER_PROGRAM); - - // prepare everything needed to render the label - this._updateWithTextDefinition(textDefinition, false); - - // set the string - this.string = text; - - return true; - }; - - _p.setFontFillColor = function (tintColor) { - var locTextFillColor = this._textFillColor; - if (locTextFillColor.r != tintColor.r || locTextFillColor.g != tintColor.g || locTextFillColor.b != tintColor.b) { - locTextFillColor.r = tintColor.r; - locTextFillColor.g = tintColor.g; - locTextFillColor.b = tintColor.b; - this._setColorsString(); - this._needUpdateTexture = true; - } - }; - - _p.draw = function (ctx) { - if (!this._string || this._string == "") - return; - - var gl = ctx || cc._renderContext, locTexture = this._texture; - - if (locTexture && locTexture._isLoaded) { - this._shaderProgram.use(); - this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); - - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - cc.glBindTexture2D(locTexture); - - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); - if (this._quadDirty) { - gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.STATIC_DRAW); - this._quadDirty = false; - } - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - } - - if (cc.SPRITE_DEBUG_DRAW === 1) { - // draw bounding box - var locQuad = this._quad; - var verticesG1 = [ - cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y), - cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y), - cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y), - cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y) - ]; - cc._drawingUtil.drawPoly(verticesG1, 4, true); - } else if (cc.SPRITE_DEBUG_DRAW === 2) { - // draw texture box - var drawSizeG2 = this.getTextureRect()._size; - var offsetPixG2X = this.offsetX, offsetPixG2Y = this.offsetY; - var verticesG2 = [cc.p(offsetPixG2X, offsetPixG2Y), cc.p(offsetPixG2X + drawSizeG2.width, offsetPixG2Y), - cc.p(offsetPixG2X + drawSizeG2.width, offsetPixG2Y + drawSizeG2.height), cc.p(offsetPixG2X, offsetPixG2Y + drawSizeG2.height)]; - cc._drawingUtil.drawPoly(verticesG2, 4, true); - } // CC_SPRITE_DEBUG_DRAW - cc.g_NumberOfDraws++; - }; - - //TODO: cc.Sprite.prototype._setTextureRectForWebGL - _p.setTextureRect = cc.Sprite.prototype.setTextureRect; -} \ No newline at end of file diff --git a/cocos2d/core/layers/CCLayer.js b/cocos2d/core/layers/CCLayer.js index efb491604c..f80af56a0c 100644 --- a/cocos2d/core/layers/CCLayer.js +++ b/cocos2d/core/layers/CCLayer.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,21 +25,15 @@ ****************************************************************************/ /** cc.Layer is a subclass of cc.Node that implements the TouchEventsDelegate protocol.
- * All features from cc.Node are valid, plus the following new features:
- * It can receive iPhone Touches
- * It can receive Accelerometer input + * All features from cc.Node are valid, plus the bake feature: Baked layer can cache a static layer to improve performance * @class * @extends cc.Node */ cc.Layer = cc.Node.extend(/** @lends cc.Layer# */{ - /** - * init layer - * @return {Boolean} - */ _className: "Layer", /** - * @constructor + *

Constructor of cc.Layer, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.

*/ ctor: function () { var nodep = cc.Node.prototype; @@ -47,306 +41,102 @@ cc.Layer = cc.Node.extend(/** @lends cc.Layer# */{ this._ignoreAnchorPointForPosition = true; nodep.setAnchorPoint.call(this, 0.5, 0.5); nodep.setContentSize.call(this, cc.winSize); - } -}); - -/** - * creates a layer - * @example - * // Example - * var myLayer = cc.Layer.create(); - * //Yes! it's that simple - * @return {cc.Layer|Null} - */ -cc.Layer.create = function () { - var ret = new cc.Layer(); - return ret; - -}; - -/** - *

- * CCLayerRGBA is a subclass of CCLayer that implements the CCRGBAProtocol protocol using a solid color as the background.
- * All features from CCLayer are valid, plus the following new features that propagate into children that conform to the CCRGBAProtocol:
- * - opacity
- * - RGB colors - *

- * @class - * @extends cc.Layer - * - * @property {Number} opacity - Opacity of layer - * @property {Boolean} opacityModifyRGB - Indicate whether or not the opacity modify color - * @property {Boolean} cascadeOpacity - Indicate whether or not it will set cascade opacity - * @property {cc.Color} color - Color of layer - * @property {Boolean} cascadeColor - Indicate whether or not it will set cascade color - */ -cc.LayerRGBA = cc.Layer.extend(/** @lends cc.LayerRGBA# */{ - RGBAProtocol: true, - _displayedOpacity: 255, - _realOpacity: 255, - _displayedColor: null, - _realColor: null, - _cascadeOpacityEnabled: false, - _cascadeColorEnabled: false, - _className: "LayerRGBA", - - /** - * @constructor - */ - ctor: function () { - cc.Layer.prototype.ctor.call(this); - this._displayedColor = cc.color(255, 255, 255, 255); - this._realColor = cc.color(255, 255, 255, 255); - }, - - init: function () { - var nodep = cc.Layer.prototype, _t = this; - _t._ignoreAnchorPointForPosition = true; - nodep.setAnchorPoint.call(_t, 0.5, 0.5); - nodep.setContentSize.call(_t, cc.winSize); - _t.cascadeOpacity = false; - _t.cascadeColor = false; - return true; - }, - - /** - * Get the opacity of Layer - * @returns {number} opacity - */ - getOpacity: function () { - return this._realOpacity; - }, - - /** - * Get the displayed opacity of Layer - * @returns {number} displayed opacity - */ - getDisplayedOpacity: function () { - return this._displayedOpacity; - }, - - /** - * Override synthesized setOpacity to recurse items - * @param {Number} opacity - */ - setOpacity: function (opacity) { - var _t = this; - _t._displayedOpacity = _t._realOpacity = opacity; - - var parentOpacity = 255, locParent = _t._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeOpacity) - parentOpacity = locParent.getDisplayedOpacity(); - _t.updateDisplayedOpacity(parentOpacity); - - _t._displayedColor.a = _t._realColor.a = opacity; }, /** - * Update displayed opacity of Layer - * @param {Number} parentOpacity + * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer */ - updateDisplayedOpacity: function (parentOpacity) { + init: function(){ var _t = this; - _t._displayedOpacity = 0 | (_t._realOpacity * parentOpacity / 255.0); - - if (_t._cascadeOpacityEnabled) { - var locChildren = _t._children, selItem; - for (var i = 0; i < locChildren.length; i++) { - selItem = locChildren[i]; - if (selItem && selItem.RGBAProtocol) - selItem.updateDisplayedOpacity(_t._displayedOpacity); - } - } - }, - - /** - * whether or not it will set cascade opacity. - * @returns {boolean} - */ - isCascadeOpacityEnabled: function () { - return this._cascadeOpacityEnabled; - }, - - /** - * Enable or disable cascade opacity - * @param {boolean} cascadeOpacityEnabled - */ - setCascadeOpacityEnabled: function (cascadeOpacityEnabled) { - if (this._cascadeOpacityEnabled === cascadeOpacityEnabled) - return; - - this._cascadeOpacityEnabled = cascadeOpacityEnabled; - if (cascadeOpacityEnabled) - this._enableCascadeOpacity(); - else - this._disableCascadeOpacity(); - }, - - _enableCascadeOpacity: function () { - var parentOpacity = 255, locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeOpacity) - parentOpacity = locParent.getDisplayedOpacity(); - this.updateDisplayedOpacity(parentOpacity); - }, - - _disableCascadeOpacity: function () { - this._displayedOpacity = this._realOpacity; - var selChildren = this._children, item; - for (var i = 0; i < selChildren.length; i++) { - item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedOpacity(255); - } - }, - - /** - * Get the color of Layer - * @returns {cc.Color} - */ - getColor: function () { - var locRealColor = this._realColor; - return cc.color(locRealColor.r, locRealColor.g, locRealColor.b, locRealColor.a); - }, - - /** - * Get the displayed color of Layer - * @returns {cc.Color} - */ - getDisplayedColor: function () { - var locDisplayedColor = this._displayedColor; - return cc.color(locDisplayedColor.r, locDisplayedColor.g, locDisplayedColor.b); + _t._ignoreAnchorPointForPosition = true; + _t.setAnchorPoint(0.5, 0.5); + _t.setContentSize(cc.winSize); + _t._cascadeColorEnabled = false; + _t._cascadeOpacityEnabled = false; + return true; }, /** - * Set the color of Layer - * @param {cc.Color} color + * Sets the layer to cache all of children to a bake sprite, and draw itself by bake sprite. recommend using it in UI.
+ * This is useful only in html5 engine + * @function + * @see cc.Layer#unbake */ - setColor: function (color) { - var locDisplayed = this._displayedColor, locRealColor = this._realColor; - locDisplayed.r = locRealColor.r = color.r; - locDisplayed.g = locRealColor.g = color.g; - locDisplayed.b = locRealColor.b = color.b; - - var parentColor, locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeColor) - parentColor = locParent.getDisplayedColor(); - else - parentColor = cc.color.WHITE; - this.updateDisplayedColor(parentColor); - - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } + bake: function(){ + this._renderCmd.bake(); }, /** - * update the displayed color of Node - * @param {cc.Color} parentColor + * Cancel the layer to cache all of children to a bake sprite.
+ * This is useful only in html5 engine + * @function + * @see cc.Layer#bake */ - updateDisplayedColor: function (parentColor) { - var locDisplayedColor = this._displayedColor, locRealColor = this._realColor; - locDisplayedColor.r = 0 | (locRealColor.r * parentColor.r / 255.0); - locDisplayedColor.g = 0 | (locRealColor.g * parentColor.g / 255.0); - locDisplayedColor.b = 0 | (locRealColor.b * parentColor.b / 255.0); - - if (this._cascadeColorEnabled) { - var locChildren = this._children, selItem; - for (var i = 0; i < locChildren.length; i++) { - selItem = locChildren[i]; - if (selItem && selItem.RGBAProtocol) - selItem.updateDisplayedColor(locDisplayedColor); - } - } + unbake: function(){ + this._renderCmd.unbake(); }, /** - * whether or not it will set cascade color. + * Determines if the layer is baked. + * @function * @returns {boolean} + * @see cc.Layer#bake and cc.Layer#unbake */ - isCascadeColorEnabled: function () { - return this._cascadeColorEnabled; + isBaked: function(){ + return this._isBaked; }, - /** - * Enable or disable cascade color - * @param {boolean} cascadeColorEnabled - */ - setCascadeColorEnabled: function (cascadeColorEnabled) { - if (this._cascadeColorEnabled === cascadeColorEnabled) - return; - this._cascadeColorEnabled = cascadeColorEnabled; - if (this._cascadeColorEnabled) - this._enableCascadeColor(); - else - this._disableCascadeColor(); + addChild: function(child, localZOrder, tag){ + cc.Node.prototype.addChild.call(this, child, localZOrder, tag); + this._renderCmd._bakeForAddChild(child); }, - _enableCascadeColor: function () { - var parentColor , locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeColor) - parentColor = locParent.getDisplayedColor(); + _createRenderCmd: function(){ + if (cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.Layer.CanvasRenderCmd(this); else - parentColor = cc.color.WHITE; - this.updateDisplayedColor(parentColor); - }, - - _disableCascadeColor: function () { - var locDisplayedColor = this._displayedColor, locRealColor = this._realColor; - locDisplayedColor.r = locRealColor.r; - locDisplayedColor.g = locRealColor.g; - locDisplayedColor.b = locRealColor.b; - - var selChildren = this._children, whiteColor = cc.color.WHITE, item, i; - for (i = 0; i < selChildren.length; i++) { - item = selChildren[i]; - if (item && item.RGBAProtocol) - item.updateDisplayedColor(whiteColor); - } - }, - - /** - * add a child to layer - * @overried - * @param {cc.Node} child A child node - * @param {Number} [zOrder=] Z order for drawing priority. Please refer to setLocalZOrder(int) - * @param {Number} [tag=] A integer to identify the node easily. Please refer to setTag(int) - */ - addChild: function (child, zOrder, tag) { - cc.Node.prototype.addChild.call(this, child, zOrder, tag); - - if (this._cascadeColorEnabled) - this._enableCascadeColor(); - if (this._cascadeOpacityEnabled) - this._enableCascadeOpacity(); - }, - - setOpacityModifyRGB: function (bValue) { - }, - - isOpacityModifyRGB: function () { - return false; + return new cc.Layer.WebGLRenderCmd(this); } }); -_tmp.PrototypeLayerRGBA(); -delete _tmp.PrototypeLayerRGBA; +/** + * Creates a layer + * @deprecated since v3.0, please use the new construction instead + * @see cc.Layer + * @return {cc.Layer|Null} + */ +cc.Layer.create = function () { + return new cc.Layer(); +}; /** *

* CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.
* All features from CCLayer are valid, plus the following new features:
- *

  • opacity

  • - *
  • RGB colors

- *

+ * - opacity
+ * - RGB colors

* @class - * @extends cc.LayerRGBA + * @extends cc.Layer + * + * @param {cc.Color} [color=] The color of the layer + * @param {Number} [width=] The width of the layer + * @param {Number} [height=] The height of the layer + * + * @example + * // Example + * //Create a yellow color layer as background + * var yellowBackground = new cc.LayerColor(cc.color(255,255,0,255)); + * //If you didn't pass in width and height, it defaults to the same size as the canvas + * + * //create a yellow box, 200 by 200 in size + * var yellowBox = new cc.LayerColor(cc.color(255,255,0,255), 200, 200); */ -cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{ +cc.LayerColor = cc.Layer.extend(/** @lends cc.LayerColor# */{ _blendFunc: null, _className: "LayerColor", /** - * blendFunc getter + * Returns the blend function * @return {cc.BlendFunc} */ getBlendFunc: function () { @@ -354,8 +144,9 @@ cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{ }, /** - * change width and height in Points - * @deprecated + * Changes width and height + * @deprecated since v3.0 please use setContentSize instead + * @see cc.Node#setContentSize * @param {Number} w width * @param {Number} h height */ @@ -365,8 +156,9 @@ cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{ }, /** - * change width in Points - * @deprecated + * Changes width in Points + * @deprecated since v3.0 please use setContentSize instead + * @see cc.Node#setContentSize * @param {Number} w width */ changeWidth: function (w) { @@ -375,49 +167,36 @@ cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{ /** * change height in Points - * @deprecated + * @deprecated since v3.0 please use setContentSize instead + * @see cc.Node#setContentSize * @param {Number} h height */ changeHeight: function (h) { this.height = h; }, - /** - * set OpacityModifyRGB of cc.LayerColor - * @param {Boolean} value - */ setOpacityModifyRGB: function (value) { }, - /** - * is OpacityModifyRGB - * @return {Boolean} - */ isOpacityModifyRGB: function () { return false; }, - setColor: function (color) { - cc.LayerRGBA.prototype.setColor.call(this, color); - this._updateColor(); - }, - - setOpacity: function (opacity) { - cc.LayerRGBA.prototype.setOpacity.call(this, opacity); - this._updateColor(); - }, - - _isLighterMode: false, /** - * @constructor + * Constructor of cc.LayerColor * @function * @param {cc.Color} [color=] * @param {Number} [width=] * @param {Number} [height=] */ - ctor: null, + ctor: function(color, width, height){ + cc.Layer.prototype.ctor.call(this); + this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); + cc.LayerColor.prototype.init.call(this, color, width, height); + }, /** + * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer * @param {cc.Color} [color=] * @param {Number} [width=] * @param {Number} [height=] @@ -432,114 +211,76 @@ cc.LayerColor = cc.LayerRGBA.extend(/** @lends cc.LayerColor# */{ width = width === undefined ? winSize.width : width; height = height === undefined ? winSize.height : height; - var locDisplayedColor = this._displayedColor; - locDisplayedColor.r = color.r; - locDisplayedColor.g = color.g; - locDisplayedColor.b = color.b; - var locRealColor = this._realColor; locRealColor.r = color.r; locRealColor.g = color.g; locRealColor.b = color.b; - - this._displayedOpacity = color.a; this._realOpacity = color.a; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty|cc.Node._dirtyFlags.opacityDirty); - var proto = cc.LayerColor.prototype; - proto.setContentSize.call(this, width, height); - proto._updateColor.call(this); + cc.LayerColor.prototype.setContentSize.call(this, width, height); return true; }, /** - * blendFunc setter - * @param {Number} src - * @param {Number} dst + * Sets the blend func, you can pass either a cc.BlendFunc object or source and destination value separately + * @param {Number|cc.BlendFunc} src + * @param {Number} [dst] */ setBlendFunc: function (src, dst) { - var _t = this; - if (dst === undefined) - _t._blendFunc = src; - else - _t._blendFunc = {src: src, dst: dst}; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - _t._isLighterMode = (_t._blendFunc && (_t._blendFunc.src == 1) && (_t._blendFunc.dst == 771)); + var locBlendFunc = this._blendFunc; + if (dst === undefined) { + locBlendFunc.src = src.src; + locBlendFunc.dst = src.dst; + } else { + locBlendFunc.src = src; + locBlendFunc.dst = dst; + } + this._renderCmd.updateBlendFunc(locBlendFunc); }, - _setWidth: null, - - _setHeight: null, - - _updateColor: null, + _setWidth: function(width){ + cc.Node.prototype._setWidth.call(this, width); + this._renderCmd._updateSquareVerticesWidth(width); + }, - updateDisplayedColor: function (parentColor) { - cc.LayerRGBA.prototype.updateDisplayedColor.call(this, parentColor); - this._updateColor(); + _setHeight: function(height){ + cc.Node.prototype._setHeight.call(this, height); + this._renderCmd._updateSquareVerticesHeight(height); }, - updateDisplayedOpacity: function (parentOpacity) { - cc.LayerRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); - this._updateColor(); + setContentSize: function(size, height){ + cc.Layer.prototype.setContentSize.call(this, size, height); + this._renderCmd._updateSquareVertices(size, height); }, - /** - * Renders the layer - * @function - * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx - */ - draw: null + _createRenderCmd: function(){ + if (cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.LayerColor.CanvasRenderCmd(this); + else + return new cc.LayerColor.WebGLRenderCmd(this); + } }); /** - * creates a cc.Layer with color, width and height in Points + * Creates a cc.Layer with color, width and height in Points + * @deprecated since v3.0 please use the new construction instead + * @see cc.LayerColor * @param {cc.Color} color * @param {Number|Null} [width=] * @param {Number|Null} [height=] * @return {cc.LayerColor} - * @example - * // Example - * //Create a yellow color layer as background - * var yellowBackground = cc.LayerColor.create(cc.color(255,255,0,255)); - * //If you didnt pass in width and height, it defaults to the same size as the canvas - * - * //create a yellow box, 200 by 200 in size - * var yellowBox = cc.LayerColor.create(cc.color(255,255,0,255), 200, 200); */ cc.LayerColor.create = function (color, width, height) { return new cc.LayerColor(color, width, height); }; - -if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - //cc.LayerColor define start - var _p = cc.LayerColor.prototype; - _p.ctor = function (color, width, height) { - cc.LayerRGBA.prototype.ctor.call(this); - this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); - cc.LayerColor.prototype.init.call(this, color, width, height); - } - _p._setWidth = cc.LayerRGBA.prototype._setWidth; - _p._setHeight = cc.LayerRGBA.prototype._setHeight; - _p._updateColor = function () { - }; - _p.draw = function (ctx) { - var context = ctx || cc._renderContext, _t = this; - var locEGLViewer = cc.view, locDisplayedColor = _t._displayedColor; - - context.fillStyle = "rgba(" + (0 | locDisplayedColor.r) + "," + (0 | locDisplayedColor.g) + "," - + (0 | locDisplayedColor.b) + "," + _t._displayedOpacity / 255 + ")"; - context.fillRect(0, 0, _t.width * locEGLViewer.getScaleX(), -_t.height * locEGLViewer.getScaleY()); - cc.g_NumberOfDraws++; - }; - //cc.LayerGradient define end - _p = null; -} else { - _tmp.WebGLLayerColor(); - delete _tmp.WebGLLayerColor; -} - -_tmp.PrototypeLayerColor(); -delete _tmp.PrototypeLayerColor; +//LayerColor - Getter Setter +(function(){ + var proto = cc.LayerColor.prototype; + cc.defineGetterSetter(proto, "width", proto._getWidth, proto._setWidth); + cc.defineGetterSetter(proto, "height", proto._getHeight, proto._setHeight); +})(); /** *

@@ -563,61 +304,75 @@ delete _tmp.PrototypeLayerColor; * @class * @extends cc.LayerColor * + * @param {cc.Color} start Starting color + * @param {cc.Color} end Ending color + * @param {cc.Point} [v=cc.p(0, -1)] A vector defines the gradient direction, default direction is from top to bottom + * * @property {cc.Color} startColor - Start color of the color gradient * @property {cc.Color} endColor - End color of the color gradient * @property {Number} startOpacity - Start opacity of the color gradient * @property {Number} endOpacity - End opacity of the color gradient * @property {Number} vector - Direction vector of the color gradient - * @property {Number} compresseInterpolation - Indicate whether or not the interpolation will be compressed + * @property {Number} compressedInterpolation - Indicate whether or not the interpolation will be compressed */ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ - _startColor: null, _endColor: null, _startOpacity: 255, _endOpacity: 255, _alongVector: null, _compressedInterpolation: false, - _gradientStartPoint: null, - _gradientEndPoint: null, _className: "LayerGradient", + _colorStops: [], /** - * @constructor - * @param {cc.Color} start starting color + * Constructor of cc.LayerGradient + * @param {cc.Color} start * @param {cc.Color} end - * @param {cc.Point|Null} v - */ - ctor: function (start, end, v) { - var _t = this; - cc.LayerColor.prototype.ctor.call(_t); - - _t._startColor = cc.color(0, 0, 0, 255); - _t._endColor = cc.color(0, 0, 0, 255); - _t._alongVector = cc.p(0, -1); - _t._startOpacity = 255; - _t._endOpacity = 255; - _t._gradientStartPoint = cc.p(0, 0); - _t._gradientEndPoint = cc.p(0, 0); - cc.LayerGradient.prototype.init.call(_t, start, end, v); - }, - - /** + * @param {cc.Point} [v=cc.p(0, -1)] + * @param {Array|Null} stops + * + * @example Using ColorStops argument: + * //startColor & endColor are for default and backward compatibility + * var layerGradient = new cc.LayerGradient(cc.color.RED, new cc.Color(255,0,0,0), cc.p(0, -1), + * [{p:0, color: cc.color.RED}, + * {p:.5, color: new cc.Color(0,0,0,0)}, + * {p:1, color: cc.color.RED}]); + * //where p = A value between 0.0 and 1.0 that represents the position between start and end in a gradient + * + */ + ctor: function (start, end, v, stops) { + cc.LayerColor.prototype.ctor.call(this); + this._endColor = cc.color(0, 0, 0, 255); + this._alongVector = cc.p(0, -1); + this._startOpacity = 255; + this._endOpacity = 255; + + if(stops && stops instanceof Array){ + this._colorStops = stops; + stops.splice(0, 0, {p:0, color: start || cc.color.BLACK}); + stops.push({p:1, color: end || cc.color.BLACK}); + } else + this._colorStops = [{p:0, color: start || cc.color.BLACK}, {p:1, color: end || cc.color.BLACK}]; + + cc.LayerGradient.prototype.init.call(this, start, end, v, stops); + }, + + /** + * Initialization of the layer, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer * @param {cc.Color} start starting color * @param {cc.Color} end * @param {cc.Point|Null} v + * @param {Array|Null} stops * @return {Boolean} */ - init: function (start, end, v) { + init: function (start, end, v, stops) { start = start || cc.color(0, 0, 0, 255); end = end || cc.color(0, 0, 0, 255); v = v || cc.p(0, -1); var _t = this; // Initializes the CCLayer with a gradient between start and end in the direction of v. - var locStartColor = _t._startColor, locEndColor = _t._endColor; - locStartColor.r = start.r; - locStartColor.g = start.g; - locStartColor.b = start.b; + var locEndColor = _t._endColor; _t._startOpacity = start.a; locEndColor.r = end.r; @@ -627,44 +382,41 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ _t._alongVector = v; _t._compressedInterpolation = true; - _t._gradientStartPoint = cc.p(0, 0); - _t._gradientEndPoint = cc.p(0, 0); cc.LayerColor.prototype.init.call(_t, cc.color(start.r, start.g, start.b, 255)); - cc.LayerGradient.prototype._updateColor.call(_t); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty|cc.Node._dirtyFlags.opacityDirty|cc.Node._dirtyFlags.gradientDirty); return true; }, /** * Sets the untransformed size of the LayerGradient. - * @override * @param {cc.Size|Number} size The untransformed size of the LayerGradient or The untransformed size's width of the LayerGradient. * @param {Number} [height] The untransformed size's height of the LayerGradient. */ setContentSize: function (size, height) { cc.LayerColor.prototype.setContentSize.call(this, size, height); - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty); }, _setWidth: function (width) { cc.LayerColor.prototype._setWidth.call(this, width); - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty); }, _setHeight: function (height) { cc.LayerColor.prototype._setHeight.call(this, height); - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty); }, /** - * get the starting color + * Returns the starting color * @return {cc.Color} */ getStartColor: function () { - return this._realColor; + return cc.color(this._realColor); }, /** - * set the starting color + * Sets the starting color * @param {cc.Color} color * @example * // Example @@ -673,10 +425,18 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ */ setStartColor: function (color) { this.color = color; + //update the color stops + var stops = this._colorStops; + if(stops && stops.length > 0){ + var selColor = stops[0].color; + selColor.r = color.r; + selColor.g = color.g; + selColor.b = color.b; + } }, /** - * set the end gradient color + * Sets the end gradient color * @param {cc.Color} color * @example * // Example @@ -684,29 +444,44 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ * //set the ending gradient to red */ setEndColor: function (color) { - this._endColor = color; - this._updateColor(); + var locColor = this._endColor; + locColor.r = color.r; + locColor.g = color.g; + locColor.b = color.b; + //update the color stops + var stops = this._colorStops; + if(stops && stops.length > 0){ + var selColor = stops[stops.length -1].color; + selColor.r = color.r; + selColor.g = color.g; + selColor.b = color.b; + } + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); }, /** - * get the end color + * Returns the end color * @return {cc.Color} */ getEndColor: function () { - return this._endColor; + return cc.color(this._endColor); }, /** - * set starting gradient opacity + * Sets starting gradient opacity * @param {Number} o from 0 to 255, 0 is transparent */ setStartOpacity: function (o) { this._startOpacity = o; - this._updateColor(); + //update the color stops + var stops = this._colorStops; + if(stops && stops.length > 0) + stops[0].color.a = o; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); }, /** - * get the starting gradient opacity + * Returns the starting gradient opacity * @return {Number} */ getStartOpacity: function () { @@ -714,16 +489,19 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ }, /** - * set the end gradient opacity + * Sets the end gradient opacity * @param {Number} o */ setEndOpacity: function (o) { this._endOpacity = o; - this._updateColor(); + var stops = this._colorStops; + if(stops && stops.length > 0) + stops[stops.length -1].color.a = o; + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); }, /** - * get the end gradient opacity + * Returns the end gradient opacity * @return {Number} */ getEndOpacity: function () { @@ -731,23 +509,25 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ }, /** - * set vector + * Sets the direction vector of the gradient * @param {cc.Point} Var */ setVector: function (Var) { this._alongVector.x = Var.x; this._alongVector.y = Var.y; - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty); }, /** + * Returns the direction vector of the gradient * @return {cc.Point} */ getVector: function () { return cc.p(this._alongVector.x, this._alongVector.y); }, - /** is Compressed Interpolation + /** + * Returns whether compressed interpolation is enabled * @return {Boolean} */ isCompressedInterpolation: function () { @@ -755,80 +535,100 @@ cc.LayerGradient = cc.LayerColor.extend(/** @lends cc.LayerGradient# */{ }, /** + * Sets whether compressed interpolation is enabled * @param {Boolean} compress */ setCompressedInterpolation: function (compress) { this._compressedInterpolation = compress; - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.gradientDirty); }, - _draw: null, + /** + * Return an array of Object representing a colorStop for the gradient, if no stops was specified + * start & endColor will be provided as default values + * @example + * [{p: 0, color: cc.color.RED},{p: 1, color: cc.color.RED},...] + * @returns {Array} + */ + getColorStops: function(){ + return this._colorStops; + }, + /** + * Set the colorStops to create the gradient using multiple point & color + * + * @param colorStops + * + * @example + * //startColor & endColor are for default and backward compatibility + * var layerGradient = new cc.LayerGradient(cc.color.RED, new cc.Color(255,0,0,0), cc.p(0, -1)); + * layerGradient.setColorStops([{p:0, color: cc.color.RED}, + * {p:.5, color: new cc.Color(0,0,0,0)}, + * {p:1, color: cc.color.RED}]); + * //where p = A value between 0.0 and 1.0 that represents the position between start and end in a gradient + * + */ + setColorStops: function(colorStops){ + this._colorStops = colorStops; + //todo need update the start color and end color + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty|cc.Node._dirtyFlags.opacityDirty|cc.Node._dirtyFlags.gradientDirty); + }, - _updateColor: null + _createRenderCmd: function(){ + if (cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.LayerGradient.CanvasRenderCmd(this); + else + return new cc.LayerGradient.WebGLRenderCmd(this); + } }); /** - * creates a gradient layer + * Creates a gradient layer + * @deprecated since v3.0, please use the new construction instead + * @see cc.layerGradient * @param {cc.Color} start starting color * @param {cc.Color} end ending color * @param {cc.Point|Null} v + * @param {Array|NULL} stops * @return {cc.LayerGradient} */ -cc.LayerGradient.create = function (start, end, v) { - return new cc.LayerGradient(start, end, v); +cc.LayerGradient.create = function (start, end, v, stops) { + return new cc.LayerGradient(start, end, v, stops); }; - - -if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - //cc.LayerGradient define start - var _p = cc.LayerGradient.prototype; - _p.draw = function (ctx) { - var context = ctx || cc._renderContext, _t = this; - if (_t._isLighterMode) - context.globalCompositeOperation = 'lighter'; - - context.save(); - var locEGLViewer = cc.view, opacityf = _t._displayedOpacity / 255.0; - var tWidth = _t.width * locEGLViewer.getScaleX(), tHeight = _t.height * locEGLViewer.getScaleY(); - var tGradient = context.createLinearGradient(_t._gradientStartPoint.x, _t._gradientStartPoint.y, - _t._gradientEndPoint.x, _t._gradientEndPoint.y); - var locDisplayedColor = _t._displayedColor, locEndColor = _t._endColor; - tGradient.addColorStop(0, "rgba(" + Math.round(locDisplayedColor.r) + "," + Math.round(locDisplayedColor.g) + "," - + Math.round(locDisplayedColor.b) + "," + (opacityf * (_t._startOpacity / 255)).toFixed(4) + ")"); - tGradient.addColorStop(1, "rgba(" + Math.round(locEndColor.r) + "," + Math.round(locEndColor.g) + "," - + Math.round(locEndColor.b) + "," + (opacityf * (_t._endOpacity / 255)).toFixed(4) + ")"); - context.fillStyle = tGradient; - context.fillRect(0, 0, tWidth, -tHeight); - - if (_t._rotation != 0) - context.rotate(_t._rotationRadians); - context.restore(); - }; - _p._updateColor = function () { - var _t = this; - var locAlongVector = _t._alongVector, tWidth = _t.width * 0.5, tHeight = _t.height * 0.5; - - _t._gradientStartPoint.x = tWidth * (-locAlongVector.x) + tWidth; - _t._gradientStartPoint.y = tHeight * locAlongVector.y - tHeight; - _t._gradientEndPoint.x = tWidth * locAlongVector.x + tWidth; - _t._gradientEndPoint.y = tHeight * (-locAlongVector.y) - tHeight; - }; - //cc.LayerGradient define end - _p = null; -} else { - _tmp.WebGLLayerGradient(); - delete _tmp.WebGLLayerGradient; -} -_tmp.PrototypeLayerGradient(); -delete _tmp.PrototypeLayerGradient; +//LayerGradient - Getter Setter +(function(){ + var proto = cc.LayerGradient.prototype; + // Extended properties + /** @expose */ + proto.startColor; + cc.defineGetterSetter(proto, "startColor", proto.getStartColor, proto.setStartColor); + /** @expose */ + proto.endColor; + cc.defineGetterSetter(proto, "endColor", proto.getEndColor, proto.setEndColor); + /** @expose */ + proto.startOpacity; + cc.defineGetterSetter(proto, "startOpacity", proto.getStartOpacity, proto.setStartOpacity); + /** @expose */ + proto.endOpacity; + cc.defineGetterSetter(proto, "endOpacity", proto.getEndOpacity, proto.setEndOpacity); + /** @expose */ + proto.vector; + cc.defineGetterSetter(proto, "vector", proto.getVector, proto.setVector); + /** @expose */ + proto.colorStops; + cc.defineGetterSetter(proto, "colorStops", proto.getColorStops, proto.setColorStops); +})(); /** * CCMultipleLayer is a CCLayer with the ability to multiplex it's children.
* Features:
*

  • - It supports one or more children
  • *
  • - Only one children will be active a time
- * @class - * @extends cc.Layer + * @class + * @extends cc.Layer + * @param {Array} layers an array of cc.Layer + * @example + * // Example + * var multiLayer = new cc.LayerMultiple(layer1, layer2, layer3);//any number of layers */ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ _enabledLayer: 0, @@ -836,15 +636,19 @@ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ _className: "LayerMultiplex", /** - * @constructor + * Constructor of cc.LayerMultiplex * @param {Array} layers an array of cc.Layer */ ctor: function (layers) { cc.Layer.prototype.ctor.call(this); - layers && cc.LayerMultiplex.prototype.initWithLayers.call(this, layers); + if (layers instanceof Array) + cc.LayerMultiplex.prototype.initWithLayers.call(this, layers); + else + cc.LayerMultiplex.prototype.initWithLayers.call(this, Array.prototype.slice.call(arguments)); }, /** + * Initialization of the layer multiplex, please do not call this function by yourself, you should pass the parameters to constructor to initialize a layer multiplex * @param {Array} layers an array of cc.Layer * @return {Boolean} */ @@ -859,7 +663,7 @@ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ }, /** - * switches to a certain layer indexed by n.
+ * Switches to a certain layer indexed by n.
* The current (old) layer will be removed from it's parent with 'cleanup:YES'. * @param {Number} n the layer index to switch to */ @@ -874,7 +678,8 @@ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ this.addChild(this._layers[n]); }, - /** release the current layer and switches to another layer indexed by n.
+ /** + * Release the current layer and switches to another layer indexed by n.
* The current (old) layer will be removed from it's parent with 'cleanup:YES'. * @param {Number} n the layer index to switch to */ @@ -893,6 +698,7 @@ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ }, /** + * Add a layer to the multiplex layers list * @param {cc.Layer} layer */ addLayer: function (layer) { @@ -905,13 +711,11 @@ cc.LayerMultiplex = cc.Layer.extend(/** @lends cc.LayerMultiplex# */{ }); /** - * creates a cc.LayerMultiplex with one or more layers using a variable argument list. + * Creates a cc.LayerMultiplex with one or more layers using a variable argument list. + * @deprecated since v3.0, please use new construction instead + * @see cc.LayerMultiplex * @return {cc.LayerMultiplex|Null} - * @example - * // Example - * var multiLayer = cc.LayerMultiple.create(layer1, layer2, layer3);//any number of layers */ cc.LayerMultiplex.create = function (/*Multiple Arguments*/) { - return new cc.LayerMultiplex(arguments); -}; - + return new cc.LayerMultiplex(Array.prototype.slice.call(arguments)); +}; \ No newline at end of file diff --git a/cocos2d/core/layers/CCLayerCanvasRenderCmd.js b/cocos2d/core/layers/CCLayerCanvasRenderCmd.js new file mode 100644 index 0000000000..2fb954e115 --- /dev/null +++ b/cocos2d/core/layers/CCLayerCanvasRenderCmd.js @@ -0,0 +1,440 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//-----------------------// +// 1. cc.Layer // +// 2. cc.LayerColor // +// 3. cc.LayerGradient // +//-----------------------// + +/** + * cc.Layer's rendering objects of Canvas + */ +(function(){ + //Layer's canvas render command + cc.Layer.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._isBaked = false; + this._bakeSprite = null; + }; + + var proto = cc.Layer.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.Layer.CanvasRenderCmd; + + proto.bake = function(){ + if (!this._isBaked) { + this._needDraw = true; + cc.renderer.childrenOrderDirty = true; + //limit: 1. its children's blendfunc are invalid. + this._isBaked = this._cacheDirty = true; + + var children = this._node._children; + for(var i = 0, len = children.length; i < len; i++) + children[i]._renderCmd._setCachedParent(this); + + if (!this._bakeSprite){ + this._bakeSprite = new cc.BakeSprite(); + this._bakeSprite.setAnchorPoint(0,0); + } + } + }; + + proto.unbake = function(){ + if (this._isBaked) { + cc.renderer.childrenOrderDirty = true; + this._needDraw = false; + this._isBaked = false; + this._cacheDirty = true; + + var children = this._node._children; + for(var i = 0, len = children.length; i < len; i++) + children[i]._renderCmd._setCachedParent(null); + } + }; + + proto.isBaked = function(){ + return this._isBaked; + }; + + proto.rendering = function(){ + if(this._cacheDirty){ + var node = this._node; + var children = node._children, locBakeSprite = this._bakeSprite; + + //compute the bounding box of the bake layer. + this.transform(this.getParentRenderCmd(), true); + + var boundingBox = this._getBoundingBoxForBake(); + boundingBox.width = 0|(boundingBox.width+0.5); + boundingBox.height = 0|(boundingBox.height+0.5); + + var bakeContext = locBakeSprite.getCacheContext(); + var ctx = bakeContext.getContext(); + locBakeSprite.resetCanvasSize(boundingBox.width, boundingBox.height); + + bakeContext.setOffset(0 - boundingBox.x, ctx.canvas.height - boundingBox.height + boundingBox.y ); + locBakeSprite.setPosition(boundingBox.x, boundingBox.y); + + //visit for canvas + node.sortAllChildren(); + cc.renderer._turnToCacheMode(this.__instanceId); + for (var i = 0, len = children.length; i < len; i++) { + children[i].visit(this); + } + cc.renderer._renderingToCacheCanvas(bakeContext, this.__instanceId); + locBakeSprite.transform(); //because bake sprite's position was changed at rendering. + this._cacheDirty = false; + } + }; + + proto.visit = function(parentCmd){ + if(!this._isBaked){ + cc.Node.CanvasRenderCmd.prototype.visit.call(this, parentCmd); + return; + } + + var node = this._node, children = node._children; + var len = children.length; + // quick return if not visible + if (!node._visible || len === 0) + return; + + this._syncStatus(parentCmd); + cc.renderer.pushRenderCommand(this); + + //the bakeSprite is drawing + this._bakeSprite.visit(this); + this._dirtyFlag = 0; + }; + + proto._bakeForAddChild = function(child){ + if(child._parent === this._node && this._isBaked) + child._renderCmd._setCachedParent(this); + }; + + proto._getBoundingBoxForBake = function(){ + var rect = null, node = this._node; + + //query child's BoundingBox + if (!node._children || node._children.length === 0) + return cc.rect(0, 0, 10, 10); + var trans = node.getNodeToWorldTransform(); + + var locChildren = node._children; + for (var i = 0, len = locChildren.length; i < len; i++) { + var child = locChildren[i]; + if (child && child._visible) { + if(rect){ + var childRect = child._getBoundingBoxToCurrentNode(trans); + if (childRect) + rect = cc.rectUnion(rect, childRect); + }else{ + rect = child._getBoundingBoxToCurrentNode(trans); + } + } + } + return rect; + }; +})(); + +/** + * cc.LayerColor's rendering objects of Canvas + */ +(function(){ + //LayerColor's canvas render command + cc.LayerColor.CanvasRenderCmd = function(renderable){ + cc.Layer.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + this._blendFuncStr = "source-over"; + this._bakeRenderCmd = new cc.CustomRenderCmd(this, this._bakeRendering); + }; + var proto = cc.LayerColor.CanvasRenderCmd.prototype = Object.create(cc.Layer.CanvasRenderCmd.prototype); + proto.constructor = cc.LayerColor.CanvasRenderCmd; + + proto.unbake = function(){ + cc.Layer.CanvasRenderCmd.prototype.unbake.call(this); + this._needDraw = true; + }; + + proto.rendering = function (ctx, scaleX, scaleY) { + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(), + node = this._node, + curColor = this._displayedColor, + opacity = this._displayedOpacity / 255, + locWidth = node._contentSize.width, + locHeight = node._contentSize.height; + + if (opacity === 0) + return; + + wrapper.setCompositeOperation(this._blendFuncStr); + wrapper.setGlobalAlpha(opacity); + wrapper.setFillStyle("rgba(" + (0 | curColor.r) + "," + (0 | curColor.g) + "," + + (0 | curColor.b) + ", 1)"); //TODO: need cache the color string + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + context.fillRect(0, 0, locWidth * scaleX, -locHeight * scaleY); + + cc.g_NumberOfDraws++; + }; + + proto.updateBlendFunc = function(blendFunc){ + this._blendFuncStr = cc.Node.CanvasRenderCmd._getCompositeOperationByBlendFunc(blendFunc); + }; + + proto._updateSquareVertices = + proto._updateSquareVerticesWidth = + proto._updateSquareVerticesHeight = function(){}; + + proto._bakeRendering = function(){ + if(this._cacheDirty){ + var node = this._node; + var locBakeSprite = this._bakeSprite, children = node._children; + var len = children.length, i; + + //compute the bounding box of the bake layer. + this.transform(this.getParentRenderCmd(), true); + //compute the bounding box of the bake layer. + var boundingBox = this._getBoundingBoxForBake(); + boundingBox.width = 0|(boundingBox.width+0.5); + boundingBox.height = 0|(boundingBox.height+0.5); + + var bakeContext = locBakeSprite.getCacheContext(); + var ctx = bakeContext.getContext(); + locBakeSprite.resetCanvasSize(boundingBox.width, boundingBox.height); + + bakeContext.setOffset(0 - boundingBox.x, ctx.canvas.height - boundingBox.height + boundingBox.y ); + locBakeSprite.setPosition(boundingBox.x, boundingBox.y); + + var child; + cc.renderer._turnToCacheMode(this.__instanceId); + //visit for canvas + if (len > 0) { + node.sortAllChildren(); + // draw children zOrder < 0 + for (i = 0; i < len; i++) { + child = children[i]; + if (child._localZOrder < 0) + child._renderCmd.visit(this); + else + break; + } + cc.renderer.pushRenderCommand(this); + for (; i < len; i++) { + children[i]._renderCmd.visit(this); + } + } else + cc.renderer.pushRenderCommand(this); + cc.renderer._renderingToCacheCanvas(bakeContext, this.__instanceId); + locBakeSprite.transform(); + this._cacheDirty = false; + } + }; + + proto.visit = function(parentCmd){ + if(!this._isBaked){ + cc.Node.CanvasRenderCmd.prototype.visit.call(this); + return; + } + + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + this._syncStatus(parentCmd); + + cc.renderer.pushRenderCommand(this._bakeRenderCmd); + + //the bakeSprite is drawing + this._bakeSprite._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); + this._bakeSprite.visit(this); + this._dirtyFlag = 0; + }; + + proto._getBoundingBoxForBake = function(){ + var node = this._node; + //default size + var rect = cc.rect(0, 0, node._contentSize.width, node._contentSize.height); + var trans = node.getNodeToWorldTransform(); + rect = cc.rectApplyAffineTransform(rect, node.getNodeToWorldTransform()); + + //query child's BoundingBox + if (!node._children || node._children.length === 0) + return rect; + + var locChildren = node._children; + for (var i = 0; i < locChildren.length; i++) { + var child = locChildren[i]; + if (child && child._visible) { + var childRect = child._getBoundingBoxToCurrentNode(trans); + rect = cc.rectUnion(rect, childRect); + } + } + return rect; + }; +})(); + +(function () { + cc.LayerGradient.RenderCmd = { + updateStatus: function () { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + if (colorDirty) + this._updateDisplayColor(); + + if (opacityDirty) + this._updateDisplayOpacity(); + + if (locFlag & flags.transformDirty) { + //update the transform + this.transform(null, true); + } + + if (colorDirty || opacityDirty || (locFlag & flags.gradientDirty)){ + this._updateColor(); + } + this._dirtyFlag = 0; + } + }; +})(); + +/** + * cc.LayerGradient's rendering objects of Canvas + */ +(function(){ + cc.LayerGradient.CanvasRenderCmd = function(renderable){ + cc.LayerColor.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + this._startPoint = cc.p(0, 0); + this._endPoint = cc.p(0, 0); + this._startStopStr = null; + this._endStopStr = null; + }; + var proto = cc.LayerGradient.CanvasRenderCmd.prototype = Object.create(cc.LayerColor.CanvasRenderCmd.prototype); + cc.inject(cc.LayerGradient.RenderCmd, proto); + proto.constructor = cc.LayerGradient.CanvasRenderCmd; + + proto.rendering = function (ctx, scaleX, scaleY) { + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(), + node = this._node, + opacity = this._displayedOpacity / 255; + + if (opacity === 0) + return; + + var locWidth = node._contentSize.width, locHeight = node._contentSize.height; + wrapper.setCompositeOperation(this._blendFuncStr); + wrapper.setGlobalAlpha(opacity); + var gradient = context.createLinearGradient(this._startPoint.x*scaleX, this._startPoint.y*scaleY, this._endPoint.x*scaleX, this._endPoint.y*scaleY); + + if(node._colorStops){ //Should always fall here now + for(var i=0; i < node._colorStops.length; i++) { + var stop = node._colorStops[i]; + gradient.addColorStop(stop.p, this._colorStopsStr[i]); + } + }else{ + gradient.addColorStop(0, this._startStopStr); + gradient.addColorStop(1, this._endStopStr); + } + + wrapper.setFillStyle(gradient); + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + context.fillRect(0, 0, locWidth * scaleX, -locHeight * scaleY); + cc.g_NumberOfDraws++; + }; + + proto._syncStatus = function (parentCmd) { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + this._syncDisplayColor(); + + if (opacityDirty) + this._syncDisplayOpacity(); + + if (locFlag & flags.transformDirty) { + //update the transform + this.transform(parentCmd); + } + + if (colorDirty || opacityDirty || (locFlag & flags.gradientDirty)){ + this._updateColor(); + } + }; + + proto._updateColor = function(){ + var node = this._node; + var contentSize = node._contentSize; + var tWidth = contentSize.width * 0.5, tHeight = contentSize.height * 0.5; + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.gradientDirty ^ this._dirtyFlag; + + //fix the bug of gradient layer + var angle = cc.pAngleSigned(cc.p(0, -1), node._alongVector); + var p1 = cc.pRotateByAngle(cc.p(0, -1), cc.p(0,0), angle); + var factor = Math.min(Math.abs(1 / p1.x), Math.abs(1/ p1.y)); + + this._startPoint.x = tWidth * (-p1.x * factor) + tWidth; + this._startPoint.y = tHeight * (p1.y * factor) - tHeight; + this._endPoint.x = tWidth * (p1.x * factor) + tWidth; + this._endPoint.y = tHeight * (-p1.y * factor) - tHeight; + + var locStartColor = this._displayedColor, locEndColor = node._endColor; + var startOpacity = node._startOpacity/255, endOpacity = node._endOpacity/255; + this._startStopStr = "rgba(" + Math.round(locStartColor.r) + "," + Math.round(locStartColor.g) + "," + + Math.round(locStartColor.b) + "," + startOpacity.toFixed(4) + ")"; + this._endStopStr = "rgba(" + Math.round(locEndColor.r) + "," + Math.round(locEndColor.g) + "," + + Math.round(locEndColor.b) + "," + endOpacity.toFixed(4) + ")"; + + if( node._colorStops){ + this._startOpacity = 0; + this._endOpacity = 0; + + this._colorStopsStr = []; + for(var i =0; i < node._colorStops.length; i++){ + var stopColor = node._colorStops[i].color; + var stopOpacity = stopColor.a == null ? 1 : stopColor.a / 255; + this._colorStopsStr.push("rgba(" + Math.round(stopColor.r) + "," + Math.round(stopColor.g) + "," + + Math.round(stopColor.b) + "," + stopOpacity.toFixed(4) + ")"); + } + } + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/layers/CCLayerPropertyDefine.js b/cocos2d/core/layers/CCLayerPropertyDefine.js deleted file mode 100644 index 1eac9fd438..0000000000 --- a/cocos2d/core/layers/CCLayerPropertyDefine.js +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -_tmp.PrototypeLayerRGBA = function () { - var _p = cc.LayerRGBA.prototype; - // Extended properties - /** @expose */ - _p.opacityModifyRGB; - cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); - /** @expose */ - _p.opacity; - cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); - /** @expose */ - _p.cascadeOpacity; - cc.defineGetterSetter(_p, "cascadeOpacity", _p.isCascadeOpacityEnabled, _p.setCascadeOpacityEnabled); - /** @expose */ - _p.color; - cc.defineGetterSetter(_p, "color", _p.getColor, _p.setColor); - /** @expose */ - _p.cascadeColor; - cc.defineGetterSetter(_p, "cascadeColor", _p.isCascadeColorEnabled, _p.setCascadeColorEnabled); -}; - -_tmp.PrototypeLayerColor = function () { - var _p = cc.LayerColor.prototype; - // Override properties - cc.defineGetterSetter(_p, "width", _p._getWidth, _p._setWidth); - cc.defineGetterSetter(_p, "height", _p._getHeight, _p._setHeight); -}; - -_tmp.PrototypeLayerGradient = function () { - var _p = cc.LayerGradient.prototype; - // Extended properties - /** @expose */ - _p.startColor; - cc.defineGetterSetter(_p, "startColor", _p.getStartColor, _p.setStartColor); - /** @expose */ - _p.endColor; - cc.defineGetterSetter(_p, "endColor", _p.getEndColor, _p.setEndColor); - /** @expose */ - _p.startOpacity; - cc.defineGetterSetter(_p, "startOpacity", _p.getStartOpacity, _p.setStartOpacity); - /** @expose */ - _p.endOpacity; - cc.defineGetterSetter(_p, "endOpacity", _p.getEndOpacity, _p.setEndOpacity); - /** @expose */ - _p.vector; - cc.defineGetterSetter(_p, "vector", _p.getVector, _p.setVector); -}; \ No newline at end of file diff --git a/cocos2d/core/layers/CCLayerWebGL.js b/cocos2d/core/layers/CCLayerWebGL.js deleted file mode 100644 index a7b58fda77..0000000000 --- a/cocos2d/core/layers/CCLayerWebGL.js +++ /dev/null @@ -1,180 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -_tmp.WebGLLayerColor = function () { - //cc.LayerColor define start - var _p = cc.LayerColor.prototype; - _p._squareVertices = null; - _p._squareColors = null; - _p._verticesFloat32Buffer = null; - _p._colorsUint8Buffer = null; - _p._squareVerticesAB = null; - _p._squareColorsAB = null; - _p.ctor = function (color, width, height) { - var _t = this; - _t._squareVerticesAB = new ArrayBuffer(32); - _t._squareColorsAB = new ArrayBuffer(16); - - var locSquareVerticesAB = _t._squareVerticesAB, locSquareColorsAB = _t._squareColorsAB; - var locVertex2FLen = cc.Vertex2F.BYTES_PER_ELEMENT, locColorLen = cc.Color.BYTES_PER_ELEMENT; - _t._squareVertices = [new cc.Vertex2F(0, 0, locSquareVerticesAB, 0), - new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen), - new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 2), - new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 3)]; - _t._squareColors = [cc.color(0, 0, 0, 255, locSquareColorsAB, 0), - cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen), - cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen * 2), - cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen * 3)]; - _t._verticesFloat32Buffer = cc._renderContext.createBuffer(); - _t._colorsUint8Buffer = cc._renderContext.createBuffer(); - - cc.LayerRGBA.prototype.ctor.call(_t); - _t._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); - - cc.LayerColor.prototype.init.call(_t, color, width, height); - }; - _p.setContentSize = function (size, height) { - var locSquareVertices = this._squareVertices; - if (height === undefined) { - locSquareVertices[1].x = size.width; - locSquareVertices[2].y = size.height; - locSquareVertices[3].x = size.width; - locSquareVertices[3].y = size.height; - } else { - locSquareVertices[1].x = size; - locSquareVertices[2].y = height; - locSquareVertices[3].x = size; - locSquareVertices[3].y = height; - } - this._bindLayerVerticesBufferData(); - cc.Layer.prototype.setContentSize.call(this, size, height); - }; - _p._setWidth = function (width) { - var locSquareVertices = this._squareVertices; - locSquareVertices[1].x = width; - locSquareVertices[3].x = width; - this._bindLayerVerticesBufferData(); - cc.Layer.prototype._setWidth.call(this, width); - }; - _p._setHeight = function (height) { - var locSquareVertices = this._squareVertices; - locSquareVertices[2].y = height; - locSquareVertices[3].y = height; - this._bindLayerVerticesBufferData(); - cc.Layer.prototype._setHeight.call(this, height); - }; - _p._updateColor = function () { - var locDisplayedColor = this._displayedColor; - var locDisplayedOpacity = this._displayedOpacity, locSquareColors = this._squareColors; - for (var i = 0; i < 4; i++) { - locSquareColors[i].r = locDisplayedColor.r; - locSquareColors[i].g = locDisplayedColor.g; - locSquareColors[i].b = locDisplayedColor.b; - locSquareColors[i].a = locDisplayedOpacity; - } - this._bindLayerColorsBufferData(); - }; - _p.draw = function (ctx) { - var context = ctx || cc._renderContext; - - cc.nodeDrawSetup(this); - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); - - // - // Attributes - // - context.bindBuffer(context.ARRAY_BUFFER, this._verticesFloat32Buffer); - context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, 0, 0); - - context.bindBuffer(context.ARRAY_BUFFER, this._colorsUint8Buffer); - context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, 0, 0); - - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - context.drawArrays(context.TRIANGLE_STRIP, 0, 4); - }; - _p._bindLayerVerticesBufferData = function () { - var glContext = cc._renderContext; - glContext.bindBuffer(glContext.ARRAY_BUFFER, this._verticesFloat32Buffer); - glContext.bufferData(glContext.ARRAY_BUFFER, this._squareVerticesAB, glContext.STATIC_DRAW); - }; - - _p._bindLayerColorsBufferData = function () { - var glContext = cc._renderContext; - glContext.bindBuffer(glContext.ARRAY_BUFFER, this._colorsUint8Buffer); - glContext.bufferData(glContext.ARRAY_BUFFER, this._squareColorsAB, glContext.STATIC_DRAW); - }; - //cc.LayerColor define end -} - -_tmp.WebGLLayerGradient = function () { - //cc.LayerGradient define start - var _p = cc.LayerGradient.prototype; - _p.draw = cc.LayerColor.prototype.draw; - _p._updateColor = function () { - var _t = this; - var locAlongVector = _t._alongVector; - var h = cc.pLength(locAlongVector); - if (h === 0) - return; - - var c = Math.sqrt(2.0), u = cc.p(locAlongVector.x / h, locAlongVector.y / h); - - // Compressed Interpolation mode - if (_t._compressedInterpolation) { - var h2 = 1 / ( Math.abs(u.x) + Math.abs(u.y) ); - u = cc.pMult(u, h2 * c); - } - - var opacityf = _t._displayedOpacity / 255.0; - var locDisplayedColor = _t._displayedColor, locEndColor = _t._endColor; - var S = { r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: _t._startOpacity * opacityf}; - var E = {r: locEndColor.r, g: locEndColor.g, b: locEndColor.b, a: _t._endOpacity * opacityf}; - - // (-1, -1) - var locSquareColors = _t._squareColors; - var locSquareColor0 = locSquareColors[0], locSquareColor1 = locSquareColors[1], locSquareColor2 = locSquareColors[2], locSquareColor3 = locSquareColors[3]; - locSquareColor0.r = ((E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0 * c)))); - locSquareColor0.g = ((E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0 * c)))); - locSquareColor0.b = ((E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0 * c)))); - locSquareColor0.a = ((E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0 * c)))); - // (1, -1) - locSquareColor1.r = ((E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0 * c)))); - locSquareColor1.g = ((E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0 * c)))); - locSquareColor1.b = ((E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0 * c)))); - locSquareColor1.a = ((E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0 * c)))); - // (-1, 1) - locSquareColor2.r = ((E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0 * c)))); - locSquareColor2.g = ((E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0 * c)))); - locSquareColor2.b = ((E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0 * c)))); - locSquareColor2.a = ((E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0 * c)))); - // (1, 1) - locSquareColor3.r = ((E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0 * c)))); - locSquareColor3.g = ((E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0 * c)))); - locSquareColor3.b = ((E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0 * c)))); - locSquareColor3.a = ((E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0 * c)))); - - _t._bindLayerColorsBufferData(); - } - //cc.LayerGradient define end -} \ No newline at end of file diff --git a/cocos2d/core/layers/CCLayerWebGLRenderCmd.js b/cocos2d/core/layers/CCLayerWebGLRenderCmd.js new file mode 100644 index 0000000000..c9314203ac --- /dev/null +++ b/cocos2d/core/layers/CCLayerWebGLRenderCmd.js @@ -0,0 +1,311 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//-----------------------// +// 1. cc.Layer // +// 2. cc.LayerColor // +// 3. cc.LayerGradient // +//-----------------------// + +/** + * cc.Layer's rendering objects of WebGL + */ +(function(){ + cc.Layer.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + }; + + var proto = cc.Layer.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.Layer.WebGLRenderCmd; + + proto.bake = function(){}; + + proto.unbake = function(){}; + + proto._bakeForAddChild = function(){}; +})(); + +/** + * cc.LayerColor's rendering objects of WebGL + */ +(function(){ + cc.LayerColor.WebGLRenderCmd = function(renderable){ + cc.Layer.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + + // + var _t = this; + _t._squareVerticesAB = new ArrayBuffer(32); + _t._squareColorsAB = new ArrayBuffer(16); + + var locSquareVerticesAB = _t._squareVerticesAB, locSquareColorsAB = _t._squareColorsAB; + var locVertex2FLen = cc.Vertex2F.BYTES_PER_ELEMENT, locColorLen = cc.Color.BYTES_PER_ELEMENT; + _t._squareVertices = [new cc.Vertex2F(0, 0, locSquareVerticesAB, 0), + new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen), + new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 2), + new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * 3)]; + _t._squareColors = [cc.color(0, 0, 0, 255, locSquareColorsAB, 0), + cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen), + cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen * 2), + cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen * 3)]; + _t._verticesFloat32Buffer = cc._renderContext.createBuffer(); + _t._colorsUint8Buffer = cc._renderContext.createBuffer(); + }; + var proto = cc.LayerColor.WebGLRenderCmd.prototype = Object.create(cc.Layer.WebGLRenderCmd.prototype); + proto.constructor = cc.LayerColor.WebGLRenderCmd; + + proto.rendering = function (ctx) { + var context = ctx || cc._renderContext; + var node = this._node; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + + // + // Attributes + // + context.bindBuffer(context.ARRAY_BUFFER, this._verticesFloat32Buffer); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, 0, 0); + + context.bindBuffer(context.ARRAY_BUFFER, this._colorsUint8Buffer); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, 0, 0); + + context.drawArrays(context.TRIANGLE_STRIP, 0, this._squareVertices.length); + }; + + proto._updateSquareVertices = function(size, height){ + var locSquareVertices = this._squareVertices; + if (height === undefined) { + locSquareVertices[1].x = size.width; + locSquareVertices[2].y = size.height; + locSquareVertices[3].x = size.width; + locSquareVertices[3].y = size.height; + } else { + locSquareVertices[1].x = size; + locSquareVertices[2].y = height; + locSquareVertices[3].x = size; + locSquareVertices[3].y = height; + } + this._bindLayerVerticesBufferData(); + }; + + proto._updateSquareVerticesWidth = function(width){ + var locSquareVertices = this._squareVertices; + locSquareVertices[1].x = width; + locSquareVertices[3].x = width; + this._bindLayerVerticesBufferData(); + }; + + proto._updateSquareVerticesHeight = function(height){ + var locSquareVertices = this._squareVertices; + locSquareVertices[2].y = height; + locSquareVertices[3].y = height; + this._bindLayerVerticesBufferData(); + }; + + proto._updateColor = function(){ + var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity, + locSquareColors = this._squareColors; + for (var i = 0; i < 4; i++) { + locSquareColors[i].r = locDisplayedColor.r; + locSquareColors[i].g = locDisplayedColor.g; + locSquareColors[i].b = locDisplayedColor.b; + locSquareColors[i].a = locDisplayedOpacity; + } + this._bindLayerColorsBufferData(); + }; + + proto._bindLayerVerticesBufferData = function(){ + var glContext = cc._renderContext; + glContext.bindBuffer(glContext.ARRAY_BUFFER, this._verticesFloat32Buffer); + glContext.bufferData(glContext.ARRAY_BUFFER, this._squareVerticesAB, glContext.STATIC_DRAW); + }; + + proto._bindLayerColorsBufferData = function(){ + var glContext = cc._renderContext; + glContext.bindBuffer(glContext.ARRAY_BUFFER, this._colorsUint8Buffer); + glContext.bufferData(glContext.ARRAY_BUFFER, this._squareColorsAB, glContext.STATIC_DRAW); + }; + + proto.updateBlendFunc = function(blendFunc){}; +})(); + +/** + * cc.LayerGradient's rendering objects of WebGL + */ +(function(){ + cc.LayerGradient.WebGLRenderCmd = function(renderable){ + cc.LayerColor.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + this._clipRect = new cc.Rect(); + this._clippingRectDirty = false; + }; + var proto = cc.LayerGradient.WebGLRenderCmd.prototype = Object.create(cc.LayerColor.WebGLRenderCmd.prototype); + cc.inject(cc.LayerGradient.RenderCmd, proto); + proto.constructor = cc.LayerGradient.WebGLRenderCmd; + + proto._syncStatus = function (parentCmd) { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + + this._dirtyFlag = locFlag; + + if (colorDirty) + this._syncDisplayColor(); + + if (opacityDirty) + this._syncDisplayOpacity(); + + //if (locFlag & flags.transformDirty) { + //update the transform + this.transform(parentCmd); + //} + + if (colorDirty || opacityDirty || (locFlag & flags.gradientDirty)){ + this._updateColor(); + } + }; + + proto._updateColor = function(){ + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.gradientDirty ^ this._dirtyFlag; + var node = this._node, stops = node._colorStops; + if(!stops || stops.length < 2) + return; + + this._clippingRectDirty = true; + var stopsLen = stops.length, verticesLen = stopsLen * 2, i, contentSize = node._contentSize; + this._squareVerticesAB = new ArrayBuffer(verticesLen * 8); + this._squareColorsAB = new ArrayBuffer(verticesLen * 4); + var locVertices = this._squareVertices, locColors = this._squareColors; + locVertices.length = 0; + locColors.length = 0; + + var locSquareVerticesAB = this._squareVerticesAB, locSquareColorsAB = this._squareColorsAB; + var locVertex2FLen = cc.Vertex2F.BYTES_PER_ELEMENT, locColorLen = cc.Color.BYTES_PER_ELEMENT; + for(i = 0; i < verticesLen; i++){ + locVertices.push(new cc.Vertex2F(0, 0, locSquareVerticesAB, locVertex2FLen * i)); + locColors.push(cc.color(0, 0, 0, 255, locSquareColorsAB, locColorLen * i)) + } + + //init vertex + var angle = Math.PI + cc.pAngleSigned(cc.p(0, -1), node._alongVector), locAnchor = cc.p(contentSize.width/2, contentSize.height /2); + var degrees = Math.round(cc.radiansToDegrees(angle)); + var transMat = cc.affineTransformMake(1, 0, 0, 1, locAnchor.x, locAnchor.y); + transMat = cc.affineTransformRotate(transMat, angle); + var a, b; + if(degrees < 90) { + a = cc.p(-locAnchor.x, locAnchor.y); + b = cc.p(locAnchor.x, locAnchor.y); + } else if(degrees < 180) { + a = cc.p(locAnchor.x, locAnchor.y); + b = cc.p(locAnchor.x, -locAnchor.y); + } else if(degrees < 270) { + a = cc.p(locAnchor.x, -locAnchor.y); + b = cc.p(-locAnchor.x, -locAnchor.y); + } else { + a = cc.p(-locAnchor.x, -locAnchor.y); + b = cc.p(-locAnchor.x, locAnchor.y); + } + + var sin = Math.sin(angle), cos = Math.cos(angle); + var tx = Math.abs((a.x * cos - a.y * sin)/locAnchor.x), ty = Math.abs((b.x * sin + b.y * cos)/locAnchor.y); + transMat = cc.affineTransformScale(transMat, tx, ty); + for (i = 0; i < stopsLen; i++) { + var stop = stops[i], y = stop.p * contentSize.height ; + var p0 = cc.pointApplyAffineTransform(- locAnchor.x , y - locAnchor.y, transMat); + locVertices[i * 2].x = p0.x; + locVertices[i * 2].y = p0.y; + var p1 = cc.pointApplyAffineTransform(contentSize.width - locAnchor.x, y - locAnchor.y, transMat); + locVertices[i * 2 + 1].x = p1.x; + locVertices[i * 2 + 1].y = p1.y; + } + + //init color + var opacityf = this._displayedOpacity / 255.0; //, displayColor = this._displayedColor; + for(i = 0; i < stopsLen; i++){ + var stopColor = stops[i].color, locSquareColor0 = locColors[i * 2], locSquareColor1 = locColors[i * 2 + 1]; + locSquareColor0.r = stopColor.r; + locSquareColor0.g = stopColor.g; + locSquareColor0.b = stopColor.b; + locSquareColor0.a = stopColor.a * opacityf; + + locSquareColor1.r = stopColor.r; + locSquareColor1.g = stopColor.g; + locSquareColor1.b = stopColor.b; + locSquareColor1.a = stopColor.a * opacityf; + } + this._bindLayerVerticesBufferData(); + this._bindLayerColorsBufferData(); + }; + + proto.rendering = function (ctx) { + var context = ctx || cc._renderContext, node = this._node; + + //it is too expensive to use stencil to clip, so it use Scissor, + //but it has a bug when layer rotated and layer's content size less than canvas's size. + var clippingRect = this._getClippingRect(); + context.enable(context.SCISSOR_TEST); + cc.view.setScissorInPoints(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); + + //draw gradient layer + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + // + // Attributes + // + context.bindBuffer(context.ARRAY_BUFFER, this._verticesFloat32Buffer); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, 0, 0); + context.bindBuffer(context.ARRAY_BUFFER, this._colorsUint8Buffer); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, 0, 0); + context.drawArrays(context.TRIANGLE_STRIP, 0, this._squareVertices.length); + + context.disable(context.SCISSOR_TEST); + }; + + proto._getClippingRect = function(){ + if(this._clippingRectDirty){ + var node = this._node; + var rect = cc.rect(0, 0, node._contentSize.width, node._contentSize.height); + var trans = node.getNodeToWorldTransform(); + this._clipRect = cc._rectApplyAffineTransformIn(rect, trans); + } + return this._clipRect; + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/platform/CCClass.js b/cocos2d/core/platform/CCClass.js index fa61107aae..2aaf3e6621 100644 --- a/cocos2d/core/platform/CCClass.js +++ b/cocos2d/core/platform/CCClass.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,17 +23,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ -/* Managed JavaScript Inheritance - * Based on John Resig's Simple JavaScript Inheritance http://ejohn.org/blog/simple-javascript-inheritance/ - * MIT Licensed. - */ + +var cc = cc || {}; /** * @namespace + * @name ClassManager */ -var cc = cc || {}; - -// var ClassManager = { id : (0|(Math.random()*998)), @@ -53,7 +49,7 @@ var ClassManager = { //now we have the content of the function, replace this._super //find this._super - while(str.indexOf('this._super')!= -1) + while(str.indexOf('this._super') !== -1) { var sp = str.indexOf('this._super'); //find the first '(' from this._super) @@ -81,8 +77,12 @@ var ClassManager = { }; ClassManager.compileSuper.ClassManager = ClassManager; +/* Managed JavaScript Inheritance + * Based on John Resig's Simple JavaScript Inheritance http://ejohn.org/blog/simple-javascript-inheritance/ + * MIT Licensed. + */ (function () { - var initializing = false, fnTest = /\b_super\b/; + var fnTest = /\b_super\b/; var config = cc.game.config; var releaseMode = config[cc.game.CONFIG_KEY.classReleaseMode]; if(releaseMode) { @@ -98,10 +98,11 @@ ClassManager.compileSuper.ClassManager = ClassManager; /** * Create a new Class that inherits from this Class - * @param {object} prop + * @static + * @param {object} props * @return {function} */ - cc.Class.extend = function (prop) { + cc.Class.extend = function (props) { var _super = this.prototype; // Instantiate a base Class (but only create the instance, @@ -144,63 +145,66 @@ ClassManager.compileSuper.ClassManager = ClassManager; this.__getters__ && (Class.__getters__ = cc.clone(this.__getters__)); this.__setters__ && (Class.__setters__ = cc.clone(this.__setters__)); - for (var name in prop) { - var isFunc = (typeof prop[name] === "function"); - var override = (typeof _super[name] === "function"); - var hasSuperCall = fnTest.test(prop[name]); - - if(releaseMode && isFunc && override && hasSuperCall) { - desc.value = ClassManager.compileSuper(prop[name], name, classId); - Object.defineProperty(prototype, name, desc); - } else if(isFunc && override && hasSuperCall){ - desc.value = (function (name, fn) { - return function () { - var tmp = this._super; - - // Add a new ._super() method that is the same method - // but on the super-Class - this._super = _super[name]; - - // The method only need to be bound temporarily, so we - // remove it when we're done executing - var ret = fn.apply(this, arguments); - this._super = tmp; - - return ret; - }; - })(name, prop[name]); - Object.defineProperty(prototype, name, desc); - } else if(isFunc) { - desc.value = prop[name]; - Object.defineProperty(prototype, name, desc); - } else{ - prototype[name] = prop[name]; + for(var idx = 0, li = arguments.length; idx < li; ++idx) { + var prop = arguments[idx]; + for (var name in prop) { + var isFunc = (typeof prop[name] === "function"); + var override = (typeof _super[name] === "function"); + var hasSuperCall = fnTest.test(prop[name]); + + if (releaseMode && isFunc && override && hasSuperCall) { + desc.value = ClassManager.compileSuper(prop[name], name, classId); + Object.defineProperty(prototype, name, desc); + } else if (isFunc && override && hasSuperCall) { + desc.value = (function (name, fn) { + return function () { + var tmp = this._super; + + // Add a new ._super() method that is the same method + // but on the super-Class + this._super = _super[name]; + + // The method only need to be bound temporarily, so we + // remove it when we're done executing + var ret = fn.apply(this, arguments); + this._super = tmp; + + return ret; + }; + })(name, prop[name]); + Object.defineProperty(prototype, name, desc); + } else if (isFunc) { + desc.value = prop[name]; + Object.defineProperty(prototype, name, desc); + } else { + prototype[name] = prop[name]; + } + + if (isFunc) { + // Override registered getter/setter + var getter, setter, propertyName; + if (this.__getters__ && this.__getters__[name]) { + propertyName = this.__getters__[name]; + for (var i in this.__setters__) { + if (this.__setters__[i] === propertyName) { + setter = i; + break; + } + } + cc.defineGetterSetter(prototype, propertyName, prop[name], prop[setter] ? prop[setter] : prototype[setter], name, setter); + } + if (this.__setters__ && this.__setters__[name]) { + propertyName = this.__setters__[name]; + for (var i in this.__getters__) { + if (this.__getters__[i] === propertyName) { + getter = i; + break; + } + } + cc.defineGetterSetter(prototype, propertyName, prop[getter] ? prop[getter] : prototype[getter], prop[name], getter, name); + } + } } - - if (isFunc) { - // Override registered getter/setter - var getter, setter, propertyName; - if( this.__getters__ && this.__getters__[name] ) { - propertyName = this.__getters__[name]; - for (var i in this.__setters__) { - if (this.__setters__[i] == propertyName) { - setter = i; - break; - } - } - cc.defineGetterSetter(prototype, propertyName, prop[name], prop[setter] ? prop[setter] : prototype[setter], name, setter); - } - if( this.__setters__ && this.__setters__[name] ) { - propertyName = this.__setters__[name]; - for (var i in this.__getters__) { - if (this.__getters__[i] == propertyName) { - getter = i; - break; - } - } - cc.defineGetterSetter(prototype, propertyName, prop[getter] ? prop[getter] : prototype[getter], prop[name], getter, name); - } - } } // And make this Class extendable @@ -214,14 +218,6 @@ ClassManager.compileSuper.ClassManager = ClassManager; }; return Class; }; - - Function.prototype.bind = Function.prototype.bind || function (bind) { - var self = this; - return function () { - var args = Array.prototype.slice.call(arguments); - return self.apply(bind || null, args); - }; - }; })(); /** @@ -253,8 +249,8 @@ cc.defineGetterSetter = function (proto, prop, getter, setter, getterName, sette for (var i = 0; i < props.length; i++) { var name = props[i]; - if( (Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(proto, name) - : proto.__lookupGetter__(name)) + if( (proto.__lookupGetter__ ? proto.__lookupGetter__(name) + : Object.getOwnPropertyDescriptor(proto, name)) || typeof proto[name] !== "function" ) continue; @@ -287,10 +283,10 @@ cc.defineGetterSetter = function (proto, prop, getter, setter, getterName, sette }; /** - * copy an new object + * Create a new object and copy all properties in an exist object to the new object * @function - * @param {object|Array} obj source object - * @return {Array|object} + * @param {object|Array} obj The source object + * @return {Array|object} The created object */ cc.clone = function (obj) { // Cloning is better if the new object is having the same prototype chain @@ -320,7 +316,7 @@ cc.clone = function (obj) { for (var key in obj) { var copy = obj[key]; // Beware that typeof null == "object" ! - if (((typeof copy) == "object") && copy && + if (((typeof copy) === "object") && copy && !(copy instanceof cc.Node) && !(copy instanceof HTMLElement)) { newObj[key] = cc.clone(copy); } else { @@ -330,3 +326,8 @@ cc.clone = function (obj) { return newObj; }; +cc.inject = function(srcPrototype, destPrototype){ + for(var key in srcPrototype) + destPrototype[key] = srcPrototype[key]; +}; + diff --git a/cocos2d/core/platform/CCCommon.js b/cocos2d/core/platform/CCCommon.js index 6f6dc3bd95..2db723b4f9 100644 --- a/cocos2d/core/platform/CCCommon.js +++ b/cocos2d/core/platform/CCCommon.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,6 +24,9 @@ THE SOFTWARE. ****************************************************************************/ +var cc = cc || {}; +cc._tmp = cc._tmp || {}; + /** * Function added for JS bindings compatibility. Not needed in cocos2d-html5. * @function @@ -34,35 +37,40 @@ cc.associateWithNative = function (jsObj, superclass) { }; /** - * keymap - * @example - * //Example - * //to mark a keydown - * cc.keyDown[65] = true; - * //or - * cc.keyMap[cc.KEY.a] + * Key map for keyboard event * - * //to mark a keyup - * do cc.keyDown[65] = false; - * - * //to find out if a key is down, check - * if(cc.keyDown[65]) - * //or - * if,(cc.keyDown[cc.KEY.space]) - * //if its undefined or false or null, its not pressed * @constant - * @type object + * @type {Object} + * @example + cc.eventManager.addListener({ + event: cc.EventListener.KEYBOARD, + onKeyPressed: function(keyCode, event){ + if (cc.KEY["a"] == keyCode) { + cc.log("A is pressed"); + } + } + }, this); */ cc.KEY = { + none:0, + + // android + back:6, + menu:18, + backspace:8, tab:9, + enter:13, + shift:16, //should use shiftkey instead ctrl:17, //should use ctrlkey alt:18, //should use altkey pause:19, capslock:20, + escape:27, + space:32, pageup:33, pagedown:34, end:35, @@ -71,6 +79,8 @@ cc.KEY = { up:38, right:39, down:40, + select:41, + insert:45, Delete:46, 0:48, @@ -109,6 +119,7 @@ cc.KEY = { x:88, y:89, z:90, + num0:96, num1:97, num2:98, @@ -136,13 +147,15 @@ cc.KEY = { f10:121, f11:122, f12:123, + numlock:144, scrolllock:145, + + ';':186, semicolon:186, - ',':186, equal:187, '=':187, - ';':188, + ',':188, comma:188, dash:189, '.':190, @@ -151,83 +164,97 @@ cc.KEY = { grave:192, '[':219, openbracket:219, + backslash:220, ']':221, closebracket:221, - backslash:220, quote:222, - space:32 + + // gamepad controll + dpadLeft:1000, + dpadRight:1001, + dpadUp:1003, + dpadDown:1004, + dpadCenter:1005 }; /** * Image Format:JPG * @constant - * @type Number + * @type {Number} */ cc.FMT_JPG = 0; /** * Image Format:PNG * @constant - * @type Number + * @type {Number} */ cc.FMT_PNG = 1; /** * Image Format:TIFF * @constant - * @type Number + * @type {Number} */ cc.FMT_TIFF = 2; /** * Image Format:RAWDATA * @constant - * @type Number + * @type {Number} */ cc.FMT_RAWDATA = 3; /** * Image Format:WEBP * @constant - * @type Number + * @type {Number} */ cc.FMT_WEBP = 4; /** * Image Format:UNKNOWN * @constant - * @type Number + * @type {Number} */ cc.FMT_UNKNOWN = 5; +/** + * get image format by image data + * @function + * @param {Array} imgData + * @returns {Number} + */ cc.getImageFormatByData = function (imgData) { // if it is a png file buffer. - if (imgData.length > 8 && imgData[0] == 0x89 - && imgData[1] == 0x50 - && imgData[2] == 0x4E - && imgData[3] == 0x47 - && imgData[4] == 0x0D - && imgData[5] == 0x0A - && imgData[6] == 0x1A - && imgData[7] == 0x0A) { + if (imgData.length > 8 && imgData[0] === 0x89 + && imgData[1] === 0x50 + && imgData[2] === 0x4E + && imgData[3] === 0x47 + && imgData[4] === 0x0D + && imgData[5] === 0x0A + && imgData[6] === 0x1A + && imgData[7] === 0x0A) { return cc.FMT_PNG; } // if it is a tiff file buffer. - if (imgData.length > 2 && ((imgData[0] == 0x49 && imgData[1] == 0x49) - || (imgData[0] == 0x4d && imgData[1] == 0x4d) - || (imgData[0] == 0xff && imgData[1] == 0xd8))) { + if (imgData.length > 2 && ((imgData[0] === 0x49 && imgData[1] === 0x49) + || (imgData[0] === 0x4d && imgData[1] === 0x4d) + || (imgData[0] === 0xff && imgData[1] === 0xd8))) { return cc.FMT_TIFF; } return cc.FMT_UNKNOWN; }; -// -// Another way to subclass: Using Google Closure. -// The following code was copied + pasted from goog.base / goog.inherits -// +/** + * Another way to subclass: Using Google Closure. + * The following code was copied + pasted from goog.base / goog.inherits + * @function + * @param {Function} childCtor + * @param {Function} parentCtor + */ cc.inherits = function (childCtor, parentCtor) { - /** @constructor */ function tempCtor() {} tempCtor.prototype = parentCtor.prototype; childCtor.superClass_ = parentCtor.prototype; @@ -240,6 +267,10 @@ cc.inherits = function (childCtor, parentCtor) { // } }; +/** + * @deprecated since v3.0, please use cc.Class.extend and _super + * @cc.Class.extend + */ cc.base = function(me, opt_methodName, var_args) { var caller = arguments.callee.caller; if (caller.superClass_) { diff --git a/cocos2d/core/platform/CCConfig.js b/cocos2d/core/platform/CCConfig.js index 2b52726809..d22450daad 100644 --- a/cocos2d/core/platform/CCConfig.js +++ b/cocos2d/core/platform/CCConfig.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,15 +25,13 @@ ****************************************************************************/ /** - *

- * The current version of Cocos2d-html5 being used.
+ * The current version of Cocos2d-JS being used.
* Please DO NOT remove this String, it is an important flag for bug tracking.
* If you post a bug to forum, please attach this flag. - *

- * @constant - * @type String + * @type {String} + * @name cc.ENGINE_VERSION */ -cc.ENGINE_VERSION = "Cocos2d-html5-v3.0 alpha 2"; +window["CocosEngine"] = cc.ENGINE_VERSION = "Cocos2d-JS v3.6"; /** *

@@ -52,17 +50,19 @@ cc.ENGINE_VERSION = "Cocos2d-html5-v3.0 alpha 2"; * - cc.QuadParticleSystem
* - cc.TileMap
*
- * To enabled set it to 1. Disabled by default. + * To enabled set it to 1. Disabled by default.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL = 0; /** - * Position of the FPS (Default: 0,0 (bottom-left corner)) + * Position of the FPS (Default: 0,0 (bottom-left corner))
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h * @constant - * @type cc.Point + * @type {cc.Point} */ cc.DIRECTOR_STATS_POSITION = cc.p(0, 0); @@ -73,9 +73,10 @@ cc.DIRECTOR_STATS_POSITION = cc.p(0, 0); * Having a bigger number means a more reliable FPS
*
* Default value: 0.1f
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.DIRECTOR_FPS_INTERVAL = 0.5; @@ -84,10 +85,11 @@ cc.DIRECTOR_FPS_INTERVAL = 0.5; * If enabled, the cc.Node objects (cc.Sprite, cc.Label,etc) will be able to render in subpixels.
* If disabled, integer pixels will be used.
*
- * To enable set it to 1. Enabled by default. + * To enable set it to 1. Enabled by default.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.COCOSNODE_RENDER_SUBPIXEL = 1; @@ -96,10 +98,11 @@ cc.COCOSNODE_RENDER_SUBPIXEL = 1; * If enabled, the cc.Sprite objects rendered with cc.SpriteBatchNode will be able to render in subpixels.
* If disabled, integer pixels will be used.
*
- * To enable set it to 1. Enabled by default. + * To enable set it to 1. Enabled by default.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.SPRITEBATCHNODE_RENDER_SUBPIXEL = 1; @@ -108,10 +111,11 @@ cc.SPRITEBATCHNODE_RENDER_SUBPIXEL = 1; * If most of your images have pre-multiplied alpha, set it to 1 (if you are going to use .PNG/.JPG file images).
* Only set to 0 if ALL your images by-pass Apple UIImage loading system (eg: if you use libpng or PVR images)
*
- * To enable set it to a value different than 0. Enabled by default. + * To enable set it to a value different than 0. Enabled by default.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA = 0; @@ -120,10 +124,11 @@ cc.OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA = 0; * Use GL_TRIANGLE_STRIP instead of GL_TRIANGLES when rendering the texture atlas.
* It seems it is the recommend way, but it is much slower, so, enable it at your own risk
*
- * To enable set it to a value different than 0. Disabled by default. + * To enable set it to a value different than 0. Disabled by default.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.TEXTURE_ATLAS_USE_TRIANGLE_STRIP = 0; @@ -134,9 +139,10 @@ cc.TEXTURE_ATLAS_USE_TRIANGLE_STRIP = 0; * So for certain cases, where you might need hundreds of VAO objects, it might be a good idea to disable it.
*
* To disable it set it to 0. disable by default.(Not Supported on WebGL)
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} */ cc.TEXTURE_ATLAS_USE_VAO = 0; @@ -150,10 +156,11 @@ cc.TEXTURE_ATLAS_USE_VAO = 0; * To enable set it to a value different than 0. Disabled by default.
*
* This value governs only the PNG, GIF, BMP, images.
- * This value DOES NOT govern the PVR (PVR.GZ, PVR.CCZ) files. If NPOT PVR is loaded, then it will create an NPOT texture ignoring this value. + * This value DOES NOT govern the PVR (PVR.GZ, PVR.CCZ) files. If NPOT PVR is loaded, then it will create an NPOT texture ignoring this value.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} * @deprecated This value will be removed in 1.1 and NPOT textures will be loaded by default if the device supports it. */ cc.TEXTURE_NPOT_SUPPORT = 0; @@ -166,10 +173,11 @@ cc.TEXTURE_NPOT_SUPPORT = 0; * To enable set it to 1. Use 0 to disable it. Enabled by default.
*
* This value governs only the PNG, GIF, BMP, images.
- * This value DOES NOT govern the PVR (PVR.GZ, PVR.CCZ) files. If NPOT PVR is loaded, then it will create an NPOT texture ignoring this value. + * This value DOES NOT govern the PVR (PVR.GZ, PVR.CCZ) files. If NPOT PVR is loaded, then it will create an NPOT texture ignoring this value.
+ * To modify it, in Web engine please refer to CCConfig.js, in JSB please refer to CCConfig.h *

* @constant - * @type Number + * @type {Number} * @deprecated This value will be removed in 1.1 and NPOT textures will be loaded by default if the device supports it. */ cc.RETINA_DISPLAY_SUPPORT = 1; @@ -184,7 +192,7 @@ cc.RETINA_DISPLAY_SUPPORT = 1; * Platforms: Only used on Retina Display devices like iPhone 4. *

* @constant - * @type String + * @type {String} */ cc.RETINA_DISPLAY_FILENAME_SUFFIX = "-hd"; @@ -197,7 +205,7 @@ cc.RETINA_DISPLAY_FILENAME_SUFFIX = "-hd"; * This feature is enabled by default. *

* @constant - * @type Number + * @type {Number} */ cc.USE_LA88_LABELS = 1; @@ -212,7 +220,7 @@ cc.USE_LA88_LABELS = 1; * 2 -- draw texture box *

* @constant - * @type Number + * @type {Number} */ cc.SPRITE_DEBUG_DRAW = 0; @@ -224,7 +232,7 @@ cc.SPRITE_DEBUG_DRAW = 0; * To enable set it to a value different than 0. Disabled by default. *

* @constant - * @type Number + * @type {Number} */ cc.SPRITEBATCHNODE_DEBUG_DRAW = 0; @@ -236,7 +244,7 @@ cc.SPRITEBATCHNODE_DEBUG_DRAW = 0; * To enable set it to a value different than 0. Disabled by default.
*

* @constant - * @type Number + * @type {Number} */ cc.LABELBMFONT_DEBUG_DRAW = 0; @@ -248,21 +256,21 @@ cc.LABELBMFONT_DEBUG_DRAW = 0; * To enable set it to a value different than 0. Disabled by default. *

* @constant - * @type Number + * @type {Number} */ cc.LABELATLAS_DEBUG_DRAW = 0; /** - * whether or not support retina display + * Whether or not support retina display * @constant - * @type Number + * @type {Number} */ cc.IS_RETINA_DISPLAY_SUPPORTED = 1; /** - * default engine + * Default engine * @constant - * @type String + * @type {String} */ cc.DEFAULT_ENGINE = cc.ENGINE_VERSION + "-canvas"; @@ -290,6 +298,6 @@ cc.ENABLE_STACKABLE_ACTIONS = 1; * If you are migrating your code from GL ES 1.1, then keep it disabled. Once all your code works as expected, turn it on. *

* @constant - * @type Number + * @type {Number} */ cc.ENABLE_GL_STATE_CACHE = 1; \ No newline at end of file diff --git a/cocos2d/core/platform/CCEGLView.js b/cocos2d/core/platform/CCEGLView.js index 4541c1a005..01c58088ed 100644 --- a/cocos2d/core/platform/CCEGLView.js +++ b/cocos2d/core/platform/CCEGLView.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -30,9 +30,93 @@ cc.Touches = []; cc.TouchesIntergerDict = {}; +cc.DENSITYDPI_DEVICE = "device-dpi"; +cc.DENSITYDPI_HIGH = "high-dpi"; +cc.DENSITYDPI_MEDIUM = "medium-dpi"; +cc.DENSITYDPI_LOW = "low-dpi"; + +cc.__BrowserGetter = { + init: function(){ + this.html = document.getElementsByTagName("html")[0]; + }, + availWidth: function(frame){ + if(!frame || frame === this.html) + return window.innerWidth; + else + return frame.clientWidth; + }, + availHeight: function(frame){ + if(!frame || frame === this.html) + return window.innerHeight; + else + return frame.clientHeight; + }, + meta: { + "width": "device-width", + "user-scalable": "no" + }, + adaptationType: cc.sys.browserType +}; + +if(window.navigator.userAgent.indexOf("OS 8_1_") > -1) //this mistake like MIUI, so use of MIUI treatment method + cc.__BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_MIUI; + +if(cc.sys.os === cc.sys.OS_IOS) // All browsers are WebView + cc.__BrowserGetter.adaptationType = cc.sys.BROWSER_TYPE_SAFARI; + +switch(cc.__BrowserGetter.adaptationType){ + case cc.sys.BROWSER_TYPE_SAFARI: + cc.__BrowserGetter.meta["minimal-ui"] = "true"; + cc.__BrowserGetter.availWidth = function(frame){ + return frame.clientWidth; + }; + cc.__BrowserGetter.availHeight = function(frame){ + return frame.clientHeight; + }; + break; + case cc.sys.BROWSER_TYPE_CHROME: + cc.__BrowserGetter.__defineGetter__("target-densitydpi", function(){ + return cc.view._targetDensityDPI; + }); + case cc.sys.BROWSER_TYPE_SOUGOU: + case cc.sys.BROWSER_TYPE_UC: + cc.__BrowserGetter.availWidth = function(frame){ + return frame.clientWidth; + }; + cc.__BrowserGetter.availHeight = function(frame){ + return frame.clientHeight; + }; + break; + case cc.sys.BROWSER_TYPE_MIUI: + cc.__BrowserGetter.init = function(view){ + if(view.__resizeWithBrowserSize) return; + var resize = function(){ + view.setDesignResolutionSize( + view._designResolutionSize.width, + view._designResolutionSize.height, + view._resolutionPolicy + ); + window.removeEventListener("resize", resize, false); + }; + window.addEventListener("resize", resize, false); + }; + break; +} + /** - * @namespace cc.view is the shared view object. + * cc.view is the singleton object which represents the game window.
+ * It's main task include:
+ * - Apply the design resolution policy
+ * - Provide interaction with the window, like resize event on web, retina display support, etc...
+ * - Manage the game view port which can be different with the window
+ * - Manage the content scale and translation
+ *
+ * Since the cc.view is a singleton, you don't need to call any constructor or create functions,
+ * the standard way to use it is by calling:
+ * - cc.view.methodName();
+ * @class * @name cc.view + * @extend cc.Class */ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ _delegate: null, @@ -46,6 +130,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ // The visible rect in content's coordinate in point _visibleRect: null, _retinaEnabled: false, + _autoFullScreen: true, // The device's pixel ratio (for retina displays) _devicePixelRatio: 1, // the view name @@ -78,9 +163,16 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ _frameZoomFactor: 1.0, __resizeWithBrowserSize: false, _isAdjustViewPort: true, + _targetDensityDPI: null, + /** + * Constructor of cc.EGLView + */ ctor: function () { var _t = this, d = document, _strategyer = cc.ContainerStrategy, _strategy = cc.ContentStrategy; + + cc.__BrowserGetter.init(this); + _t._frame = (cc.container.parentNode === d.body) ? d.documentElement : cc.container.parentNode; _t._frameSize = cc.size(0, 0); _t._initFrameSize(); @@ -94,8 +186,8 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ _t._viewName = "Cocos2dHTML5"; var sys = cc.sys; - _t.enableRetina(sys.os == sys.OS_IOS || sys.os == sys.OS_OSX); - cc.visibleRect && cc.visibleRect.init(_t._designResolutionSize); + _t.enableRetina(sys.os === sys.OS_IOS || sys.os === sys.OS_OSX); + cc.visibleRect && cc.visibleRect.init(_t._visibleRect); // Setup system default resolution policies _t._rpExactFit = new cc.ResolutionPolicy(_strategyer.EQUAL_TO_FRAME, _strategy.EXACT_FIT); @@ -106,49 +198,98 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ _t._hDC = cc._canvas; _t._hRC = cc._renderContext; + _t._targetDensityDPI = cc.DENSITYDPI_HIGH; }, // Resize helper functions _resizeEvent: function () { - var width = this._originalDesignResolutionSize.width; - var height = this._originalDesignResolutionSize.height; - if (this._resizeCallback) { - this._initFrameSize(); - this._resizeCallback.call(); + var view; + if(this.setDesignResolutionSize){ + view = this; + }else{ + view = cc.view; + } + + // Check frame size changed or not + var prevFrameW = view._frameSize.width, prevFrameH = view._frameSize.height; + view._initFrameSize(); + if (view._frameSize.width === prevFrameW && view._frameSize.height === prevFrameH) + return; + + // Frame size changed, do resize works + if (view._resizeCallback) { + view._resizeCallback.call(); } + var width = view._originalDesignResolutionSize.width; + var height = view._originalDesignResolutionSize.height; if (width > 0) - this.setDesignResolutionSize(width, height, this._resolutionPolicy); + view.setDesignResolutionSize(width, height, view._resolutionPolicy); + }, + + /** + *

+ * Sets view's target-densitydpi for android mobile browser. it can be set to:
+ * 1. cc.DENSITYDPI_DEVICE, value is "device-dpi"
+ * 2. cc.DENSITYDPI_HIGH, value is "high-dpi" (default value)
+ * 3. cc.DENSITYDPI_MEDIUM, value is "medium-dpi" (browser's default value)
+ * 4. cc.DENSITYDPI_LOW, value is "low-dpi"
+ * 5. Custom value, e.g: "480"
+ *

+ * @param {String} densityDPI + */ + setTargetDensityDPI: function(densityDPI){ + this._targetDensityDPI = densityDPI; + this._setViewPortMeta(); }, + /** + * Returns the current target-densitydpi value of cc.view. + * @returns {String} + */ + getTargetDensityDPI: function(){ + return this._targetDensityDPI; + }, + + /** + * Sets whether resize canvas automatically when browser's size changed.
+ * Useful only on web. + * @param {Boolean} enabled Whether enable automatic resize with browser's resize event + */ resizeWithBrowserSize: function (enabled) { - var adjustSize, _t = this; if (enabled) { //enable - if (!_t.__resizeWithBrowserSize) { - _t.__resizeWithBrowserSize = true; - adjustSize = _t._resizeEvent.bind(_t); - cc._addEventListener(window, 'resize', adjustSize, false); + if (!this.__resizeWithBrowserSize) { + this.__resizeWithBrowserSize = true; + cc._addEventListener(window, 'resize', this._resizeEvent); + cc._addEventListener(window, 'orientationchange', this._resizeEvent); } } else { //disable - if (_t.__resizeWithBrowserSize) { - _t.__resizeWithBrowserSize = true; - adjustSize = _t._resizeEvent.bind(_t); - window.removeEventListener('resize', adjustSize, false); + if (this.__resizeWithBrowserSize) { + this.__resizeWithBrowserSize = false; + window.removeEventListener('resize', this._resizeEvent); + window.removeEventListener('orientationchange', this._resizeEvent); } } }, + /** + * Sets the callback function for cc.view's resize action,
+ * this callback will be invoked before applying resolution policy,
+ * so you can do any additional modifications within the callback.
+ * Useful only on web. + * @param {Function|null} callback The callback function + */ setResizeCallback: function (callback) { - if (typeof callback == "function" || callback == null) { + if (cc.isFunction(callback) || callback == null) { this._resizeCallback = callback; } }, _initFrameSize: function () { var locFrameSize = this._frameSize; - locFrameSize.width = this._frame.clientWidth; - locFrameSize.height = this._frame.clientHeight; + locFrameSize.width = cc.__BrowserGetter.availWidth(this._frame); + locFrameSize.height = cc.__BrowserGetter.availHeight(this._frame); }, // hack @@ -159,40 +300,41 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ this.setDesignResolutionSize(designWidth, designHeight, this._resolutionPolicy); }, - _setViewPortMeta: function (width, height) { + _setViewPortMeta: function () { if (this._isAdjustViewPort) { - var viewportMetas = {"user-scalable": "no", "maximum-scale": "1.0", "initial-scale": "1.0"}, elems = document.getElementsByName("viewport"), vp, content; - if (elems.length == 0) { - vp = cc.newElement("meta"); - vp.name = "viewport"; - vp.content = ""; - document.head.appendChild(vp); + var vp = document.getElementById("cocosMetaElement"); + if(vp){ + document.head.removeChild(vp); } - else vp = elems[0]; - // For avoiding Android Firefox issue, to remove once firefox fixes its issue. - if (cc.sys.isMobile && cc.sys.browserType == cc.sys.BROWSER_TYPE_FIREFOX) { - vp.content = "initial-scale:1"; - return; - } + var viewportMetas, + elems = document.getElementsByName("viewport"), + currentVP = elems ? elems[0] : null, + content; + + vp = cc.newElement("meta"); + vp.id = "cocosMetaElement"; + vp.name = "viewport"; + vp.content = ""; + + viewportMetas = cc.__BrowserGetter.meta; - content = vp.content; + content = currentVP ? currentVP.content : ""; for (var key in viewportMetas) { var pattern = new RegExp(key); if (!pattern.test(content)) { - content += (content == "" ? "" : ",") + key + "=" + viewportMetas[key]; + content += "," + key + "=" + viewportMetas[key]; } } - /* - if(width<=320){ - width = 321; - } - if(height) - content ="height="+height+","+content; - if(width) - content ="width="+width+","+content; - */ + if(/^,/.test(content)) + content = content.substr(1); + vp.content = content; + // For adopting certain android devices which don't support second viewport + if (currentVP) + currentVP.content = content; + + document.head.appendChild(vp); } }, @@ -214,20 +356,25 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ _adjustSizeToBrowser: function () { }, - /** - * init - */ initialize: function () { this._initialized = true; }, + /** + * Sets whether the engine modify the "viewport" meta in your web page.
+ * It's enabled by default, we strongly suggest you not to disable it.
+ * And even when it's enabled, you can still set your own "viewport" meta, it won't be overridden
+ * Only useful on web + * @param {Boolean} enabled Enable automatic modification to "viewport" meta + */ adjustViewPort: function (enabled) { this._isAdjustViewPort = enabled; }, /** - * Retina support is enabled by default for Apple device but disabled for other devices, - * it takes effect only when you called setDesignResolutionPolicy + * Retina support is enabled by default for Apple device but disabled for other devices,
+ * it takes effect only when you called setDesignResolutionPolicy
+ * Only useful on web * @param {Boolean} enabled Enable or disable retina display */ enableRetina: function(enabled) { @@ -235,13 +382,33 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Check whether retina display is enabled. + * Check whether retina display is enabled.
+ * Only useful on web * @return {Boolean} */ isRetinaEnabled: function() { return this._retinaEnabled; }, + /** + * If enabled, the application will try automatically to enter full screen mode on mobile devices
+ * You can pass true as parameter to enable it and disable it by passing false.
+ * Only useful on web + * @param {Boolean} enabled Enable or disable auto full screen on mobile devices + */ + enableAutoFullScreen: function(enabled) { + this._autoFullScreen = enabled ? true : false; + }, + + /** + * Check whether auto full screen is enabled.
+ * Only useful on web + * @return {Boolean} Auto full screen enabled or not + */ + isAutoFullScreenEnabled: function() { + return this._autoFullScreen; + }, + /** * Force destroying EGL view, subclass must implement this method. */ @@ -249,12 +416,12 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get whether render system is ready(no matter opengl or canvas), + * Get whether render system is ready(no matter opengl or canvas),
* this name is for the compatibility with cocos2d-x, subclass must implement this method. * @return {Boolean} */ isOpenGLReady: function () { - return (this._hDC != null && this._hRC != null); + return (this._hDC !== null && this._hRC !== null); }, /* @@ -275,14 +442,13 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ /** * Open or close IME keyboard , subclass must implement this method. + * @param {Boolean} isOpen */ setIMEKeyboardState: function (isOpen) { }, /** - *

- * The resolution translate on EGLView - *

+ * Sets the resolution translate on EGLView * @param {Number} offsetLeft * @param {Number} offsetTop */ @@ -291,9 +457,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - *

- * get the resolution translate on EGLView - *

+ * Returns the resolution translate on EGLView * @return {cc.Size|Object} */ getContentTranslateLeftTop: function () { @@ -301,8 +465,9 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get the frame size of EGL view. - * In general, it returns the screen size since the EGL view is a fullscreen view. + * Returns the frame size of the view.
+ * On native platforms, it returns the screen size since the view is a fullscreen view.
+ * On web, it returns the size of the canvas's outer DOM element. * @return {cc.Size} */ getFrameSize: function () { @@ -310,7 +475,8 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Set the frame size of EGL view. + * On native, it sets the frame size of view.
+ * On web, it sets the size of the canvas's outer DOM element. * @param {Number} width * @param {Number} height */ @@ -324,11 +490,14 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ cc.director.setProjection(cc.director.getProjection()); }, + /** + * Empty function + */ centerWindow: function () { }, /** - * Get the visible area size of OpenGL view port. + * Returns the visible area size of the view port. * @return {cc.Size} */ getVisibleSize: function () { @@ -336,19 +505,24 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get the visible origin of OpenGL view port. + * Returns the visible origin of the view port. * @return {cc.Point} */ getVisibleOrigin: function () { return cc.p(this._visibleRect.x,this._visibleRect.y); }, + /** + * Returns whether developer can set content's scale factor. + * @return {Boolean} + */ canSetContentScaleFactor: function () { return true; }, /** - * Get the current resolution policy + * Returns the current resolution policy + * @see cc.ResolutionPolicy * @return {cc.ResolutionPolicy} */ getResolutionPolicy: function () { @@ -356,7 +530,8 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Set the current resolution policy + * Sets the current resolution policy + * @see cc.ResolutionPolicy * @param {cc.ResolutionPolicy|Number} resolutionPolicy */ setResolutionPolicy: function (resolutionPolicy) { @@ -381,83 +556,90 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Set the design resolution size. + * Sets the resolution policy with designed view size in points.
+ * The resolution policy include:
+ * [1] ResolutionExactFit Fill screen by stretch-to-fit: if the design resolution ratio of width to height is different from the screen resolution ratio, your game view will be stretched.
+ * [2] ResolutionNoBorder Full screen without black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two areas of your game view will be cut.
+ * [3] ResolutionShowAll Full screen with black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two black borders will be shown.
+ * [4] ResolutionFixedHeight Scale the content's height to screen's height and proportionally scale its width
+ * [5] ResolutionFixedWidth Scale the content's width to screen's width and proportionally scale its height
+ * [cc.ResolutionPolicy] [Web only feature] Custom resolution policy, constructed by cc.ResolutionPolicy
* @param {Number} width Design resolution width. * @param {Number} height Design resolution height. - * @param {cc.ResolutionPolicy|Number} resolutionPolicy The resolution policy desired, you may choose: - * [1] ResolutionExactFit Fill screen by stretch-to-fit: if the design resolution ratio of width to height is different from the screen resolution ratio, your game view will be stretched. - * [2] ResolutionNoBorder Full screen without black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two areas of your game view will be cut. - * [3] ResolutionShowAll Full screen with black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two black borders will be shown. - * [4] ResolutionFixedHeight Scale the content's height to screen's height and proportionally scale its width - * [5] ResolutionFixedWidth Scale the content's width to screen's width and proportionally scale its height - * [cc.ResolutionPolicy] Custom resolution policy, constructed by cc.ResolutionPolicy + * @param {cc.ResolutionPolicy|Number} resolutionPolicy The resolution policy desired */ setDesignResolutionSize: function (width, height, resolutionPolicy) { // Defensive code - if (isNaN(width) || width == 0 || isNaN(height) || height == 0) { + if( !(width > 0 || height > 0) ){ cc.log(cc._LogInfos.EGLView_setDesignResolutionSize); return; } - var _t = this; - _t.setResolutionPolicy(resolutionPolicy); - var policy = _t._resolutionPolicy; - if (policy) - policy.preApply(_t); - else { + + this.setResolutionPolicy(resolutionPolicy); + var policy = this._resolutionPolicy; + if (!policy){ cc.log(cc._LogInfos.EGLView_setDesignResolutionSize_2); return; } + policy.preApply(this); // Reinit frame size - var frameW = _t._frameSize.width, frameH = _t._frameSize.height; - if (cc.sys.isMobile) - _t._setViewPortMeta(_t._frameSize.width, _t._frameSize.height); - _t._initFrameSize(); - // No change - if (resolutionPolicy == _t._resolutionPolicy - && width == _t._originalDesignResolutionSize.width && height == _t._originalDesignResolutionSize.height - && frameW == _t._frameSize.width && frameH == _t._frameSize.height) - return; - _t._designResolutionSize = cc.size(width, height); - _t._originalDesignResolutionSize = cc.size(width, height); + if(cc.sys.isMobile) + this._setViewPortMeta(); + + this._initFrameSize(); + + this._originalDesignResolutionSize.width = this._designResolutionSize.width = width; + this._originalDesignResolutionSize.height = this._designResolutionSize.height = height; + + var result = policy.apply(this, this._designResolutionSize); - var result = policy.apply(_t, _t._designResolutionSize); - if (result.scale && result.scale.length == 2) { - _t._scaleX = result.scale[0]; - _t._scaleY = result.scale[1]; + if(result.scale && result.scale.length === 2){ + this._scaleX = result.scale[0]; + this._scaleY = result.scale[1]; } - if (result.viewport) { - var vp = _t._viewPortRect = result.viewport, visible = _t._visibleRect; - visible.width = cc._canvas.width / _t._scaleX; - visible.height = cc._canvas.height / _t._scaleY; - visible.x = -vp.x / _t._scaleX; - visible.y = -vp.y / _t._scaleY; + + if(result.viewport){ + var vp = this._viewPortRect, + vb = this._visibleRect, + rv = result.viewport; + + vp.x = rv.x; + vp.y = rv.y; + vp.width = rv.width; + vp.height = rv.height; + + vb.x = -vp.x / this._scaleX; + vb.y = -vp.y / this._scaleY; + vb.width = cc._canvas.width / this._scaleX; + vb.height = cc._canvas.height / this._scaleY; + cc._renderContext.setOffset && cc._renderContext.setOffset(vp.x, -vp.y) } // reset director's member variables to fit visible rect var director = cc.director; - director._winSizeInPoints = _t.getDesignResolutionSize(); + director._winSizeInPoints.width = this._designResolutionSize.width; + director._winSizeInPoints.height = this._designResolutionSize.height; + policy.postApply(this); cc.winSize.width = director._winSizeInPoints.width; cc.winSize.height = director._winSizeInPoints.height; - policy.postApply(_t); - - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { // reset director's member variables to fit visible rect director._createStatsLabel(); director.setGLDefaultValues(); } - _t._originalScaleX = _t._scaleX; - _t._originalScaleY = _t._scaleY; + this._originalScaleX = this._scaleX; + this._originalScaleY = this._scaleY; // For editbox if (cc.DOM) cc.DOM._resetEGLViewDiv(); - cc.visibleRect && cc.visibleRect.init(_t.getVisibleSize()); + cc.visibleRect && cc.visibleRect.init(this._visibleRect); }, /** - * Get design resolution size. + * Returns the designed size for the view. * Default resolution size is the same as 'getFrameSize'. * @return {cc.Size} */ @@ -466,7 +648,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Set opengl view port rectangle with points. + * Sets view port rectangle with points. * @param {Number} x * @param {Number} y * @param {Number} w width @@ -481,7 +663,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Set Scissor rectangle with points. + * Sets Scissor rectangle with points. * @param {Number} x * @param {Number} y * @param {Number} w @@ -496,7 +678,8 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get whether GL_SCISSOR_TEST is enable + * Returns whether GL_SCISSOR_TEST is enable + * @return {Boolean} */ isScissorEnabled: function () { var gl = cc._renderContext; @@ -504,7 +687,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get the current scissor rectangle + * Returns the current scissor rectangle * @return {cc.Rect} */ getScissorRect: function () { @@ -515,6 +698,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** + * Sets the name of the view * @param {String} viewName */ setViewName: function (viewName) { @@ -524,7 +708,7 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * get view name + * Returns the name of the view * @return {String} */ getViewName: function () { @@ -532,35 +716,43 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ }, /** - * Get the opengl view port rectangle. + * Returns the view port rectangle. + * @return {cc.Rect} */ getViewPortRect: function () { return this._viewPortRect; }, /** - * Get scale factor of the horizontal direction. + * Returns scale factor of the horizontal direction (X axis). + * @return {Number} */ getScaleX: function () { return this._scaleX; }, /** - * Get scale factor of the vertical direction. + * Returns scale factor of the vertical direction (Y axis). + * @return {Number} */ getScaleY: function () { return this._scaleY; }, /** - * Get device pixel ratio for retina display. + * Returns device pixel ratio for retina display. + * @return {Number} */ getDevicePixelRatio: function() { return this._devicePixelRatio; }, /** - * Get the real location in view + * Returns the real location in view for a translation based on a related position + * @param {Number} tx The X axis translation + * @param {Number} ty The Y axis translation + * @param {Object} relatedPos The related position object including "left", "top", "width", "height" informations + * @return {cc.Point} */ convertToLocationInView: function (tx, ty, relatedPos) { return {x: this._devicePixelRatio * (tx - relatedPos.left), y: this._devicePixelRatio * (relatedPos.top + relatedPos.height - ty)}; @@ -586,6 +778,11 @@ cc.EGLView = cc.Class.extend(/** @lends cc.view# */{ } }); +/** + * @function + * @return {cc.EGLView} + * @private + */ cc.EGLView._getInstance = function () { if (!this._instance) { this._instance = this._instance || new cc.EGLView(); @@ -627,7 +824,7 @@ cc.ContainerStrategy = cc.Class.extend(/** @lends cc.ContainerStrategy# */{ _setupContainer: function (view, w, h) { var frame = view._frame; - if (cc.sys.isMobile && frame == document.documentElement) { + if (cc.view._autoFullScreen && cc.sys.isMobile && frame === document.documentElement) { // Automatically full screen when user touches on mobile version cc.screen.autoFullScreen(frame); } @@ -643,6 +840,7 @@ cc.ContainerStrategy = cc.Class.extend(/** @lends cc.ContainerStrategy# */{ // Setup canvas locCanvasElement.width = w * devicePixelRatio; locCanvasElement.height = h * devicePixelRatio; + cc._renderContext.resetCache && cc._renderContext.resetCache(); var body = document.body, style; if (body && (style = body.style)) { @@ -702,8 +900,10 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ contentW, contentH); // Translate the content - if (cc._renderType == cc._RENDER_TYPE_CANVAS) - cc._renderContext.translate(viewport.x, viewport.y + contentH); + if (cc._renderType === cc._RENDER_TYPE_CANVAS){ + //TODO: modify something for setTransform + //cc._renderContext.translate(viewport.x, viewport.y + contentH); + } this._result.scale = [scaleX, scaleY]; this._result.viewport = viewport; @@ -740,12 +940,20 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ (function () { // Container scale strategys + /** + * @class + * @extends cc.ContainerStrategy + */ var EqualToFrame = cc.ContainerStrategy.extend({ apply: function (view) { this._setupContainer(view, view._frameSize.width, view._frameSize.height); } }); + /** + * @class + * @extends cc.ContainerStrategy + */ var ProportionalToFrame = cc.ContainerStrategy.extend({ apply: function (view, designedResolution) { var frameW = view._frameSize.width, frameH = view._frameSize.height, containerStyle = cc.container.style, @@ -770,6 +978,10 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ } }); + /** + * @class + * @extends EqualToFrame + */ var EqualToWindow = EqualToFrame.extend({ preApply: function (view) { this._super(view); @@ -782,6 +994,10 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ } }); + /** + * @class + * @extends ProportionalToFrame + */ var ProportionalToWindow = ProportionalToFrame.extend({ preApply: function (view) { this._super(view); @@ -794,6 +1010,10 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ } }); + /** + * @class + * @extends cc.ContainerStrategy + */ var OriginalContainer = cc.ContainerStrategy.extend({ apply: function (view) { this._setupContainer(view, cc._canvas.width, cc._canvas.height); @@ -896,11 +1116,18 @@ cc.ContentStrategy = cc.Class.extend(/** @lends cc.ContentStrategy# */{ * * @class * @extends cc.Class + * @param {cc.ContainerStrategy} containerStg The container strategy + * @param {cc.ContentStrategy} contentStg The content strategy */ cc.ResolutionPolicy = cc.Class.extend(/** @lends cc.ResolutionPolicy# */{ _containerStrategy: null, _contentStrategy: null, + /** + * Constructor of cc.ResolutionPolicy + * @param {cc.ContainerStrategy} containerStg + * @param {cc.ContentStrategy} contentStg + */ ctor: function (containerStg, contentStg) { this.setContainerStrategy(containerStg); this.setContentStrategy(contentStg); @@ -956,40 +1183,44 @@ cc.ResolutionPolicy = cc.Class.extend(/** @lends cc.ResolutionPolicy# */{ } }); -/* +/** * @memberOf cc.ResolutionPolicy# * @name EXACT_FIT - * @const + * @constant + * @type Number * @static * The entire application is visible in the specified area without trying to preserve the original aspect ratio.
* Distortion can occur, and the application may appear stretched or compressed. */ cc.ResolutionPolicy.EXACT_FIT = 0; -/* +/** * @memberOf cc.ResolutionPolicy# * @name NO_BORDER - * @const + * @constant + * @type Number * @static * The entire application fills the specified area, without distortion but possibly with some cropping,
* while maintaining the original aspect ratio of the application. */ cc.ResolutionPolicy.NO_BORDER = 1; -/* +/** * @memberOf cc.ResolutionPolicy# * @name SHOW_ALL - * @const + * @constant + * @type Number * @static * The entire application is visible in the specified area without distortion while maintaining the original
* aspect ratio of the application. Borders can appear on two sides of the application. */ cc.ResolutionPolicy.SHOW_ALL = 2; -/* +/** * @memberOf cc.ResolutionPolicy# * @name FIXED_HEIGHT - * @const + * @constant + * @type Number * @static * The application takes the height of the design resolution size and modifies the width of the internal
* canvas so that it fits the aspect ratio of the device
@@ -998,10 +1229,11 @@ cc.ResolutionPolicy.SHOW_ALL = 2; */ cc.ResolutionPolicy.FIXED_HEIGHT = 3; -/* +/** * @memberOf cc.ResolutionPolicy# * @name FIXED_WIDTH - * @const + * @constant + * @type Number * @static * The application takes the width of the design resolution size and modifies the height of the internal
* canvas so that it fits the aspect ratio of the device
@@ -1010,10 +1242,11 @@ cc.ResolutionPolicy.FIXED_HEIGHT = 3; */ cc.ResolutionPolicy.FIXED_WIDTH = 4; -/* +/** * @memberOf cc.ResolutionPolicy# * @name UNKNOWN - * @const + * @constant + * @type Number * @static * Unknow policy */ diff --git a/cocos2d/core/platform/CCInputExtension.js b/cocos2d/core/platform/CCInputExtension.js index 5846094d12..470864db02 100644 --- a/cocos2d/core/platform/CCInputExtension.js +++ b/cocos2d/core/platform/CCInputExtension.js @@ -1,5 +1,5 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,6 +27,7 @@ var _p = cc.inputManager; /** * whether enable accelerometer event + * @function * @param {Boolean} isEnable */ _p.setAccelerometerEnabled = function(isEnable){ @@ -38,15 +39,16 @@ _p.setAccelerometerEnabled = function(isEnable){ var scheduler = cc.director.getScheduler(); if(_t._accelEnabled){ _t._accelCurTime = 0; - scheduler.scheduleUpdateForTarget(_t); + scheduler.scheduleUpdate(_t); } else { _t._accelCurTime = 0; - scheduler.unscheduleUpdateForTarget(_t); + scheduler.scheduleUpdate(_t); } }; /** * set accelerometer interval value + * @function * @param {Number} interval */ _p.setAccelerometerInterval = function(interval){ @@ -56,12 +58,16 @@ _p.setAccelerometerInterval = function(interval){ }; _p._registerKeyboardEvent = function(){ - cc._addEventListener(document, "keydown", function (e) { + cc._addEventListener(cc._canvas, "keydown", function (e) { cc.eventManager.dispatchEvent(new cc.EventKeyboard(e.keyCode, true)); - }); - cc._addEventListener(document, "keyup", function (e) { + e.stopPropagation(); + e.preventDefault(); + }, false); + cc._addEventListener(cc._canvas, "keyup", function (e) { cc.eventManager.dispatchEvent(new cc.EventKeyboard(e.keyCode, false)); - }); + e.stopPropagation(); + e.preventDefault(); + }, false); }; _p._registerAccelerometerEvent = function(){ @@ -70,12 +76,12 @@ _p._registerAccelerometerEvent = function(){ _t._accelDeviceEvent = w.DeviceMotionEvent || w.DeviceOrientationEvent; //TODO fix DeviceMotionEvent bug on QQ Browser version 4.1 and below. - if (cc.sys.browserType == cc.sys.BROWSER_TYPE_MOBILE_QQ) + if (cc.sys.browserType === cc.sys.BROWSER_TYPE_MOBILE_QQ) _t._accelDeviceEvent = window.DeviceOrientationEvent; - var _deviceEventType = (_t._accelDeviceEvent == w.DeviceMotionEvent) ? "devicemotion" : "deviceorientation"; + var _deviceEventType = (_t._accelDeviceEvent === w.DeviceMotionEvent) ? "devicemotion" : "deviceorientation"; var ua = navigator.userAgent; - if (/Android/.test(ua) || (/Adr/.test(ua) && cc.sys.browserType == cc.BROWSER_TYPE_UC)) { + if (/Android/.test(ua) || (/Adr/.test(ua) && cc.sys.browserType === cc.BROWSER_TYPE_UC)) { _t._minus = -1; } @@ -88,16 +94,29 @@ _p.didAccelerate = function (eventData) { return; var mAcceleration = _t._acceleration; - if (_t._accelDeviceEvent == window.DeviceMotionEvent) { + + var x, y, z; + + if (_t._accelDeviceEvent === window.DeviceMotionEvent) { var eventAcceleration = eventData["accelerationIncludingGravity"]; - mAcceleration.x = _t._accelMinus * eventAcceleration.x * 0.1; - mAcceleration.y = _t._accelMinus * eventAcceleration.y * 0.1; - mAcceleration.z = eventAcceleration.z * 0.1; + x = _t._accelMinus * eventAcceleration.x * 0.1; + y = _t._accelMinus * eventAcceleration.y * 0.1; + z = eventAcceleration.z * 0.1; } else { - mAcceleration.x = (eventData["gamma"] / 90) * 0.981; - mAcceleration.y = -(eventData["beta"] / 90) * 0.981; - mAcceleration.z = (eventData["alpha"] / 90) * 0.981; + x = (eventData["gamma"] / 90) * 0.981; + y = -(eventData["beta"] / 90) * 0.981; + z = (eventData["alpha"] / 90) * 0.981; } + + if(cc.sys.os === cc.sys.OS_ANDROID){ + mAcceleration.x = -x; + mAcceleration.y = -y; + }else{ + mAcceleration.x = x; + mAcceleration.y = y; + } + mAcceleration.z = z; + mAcceleration.timestamp = eventData.timeStamp || Date.now(); var tmpX = mAcceleration.x; diff --git a/cocos2d/core/platform/CCInputManager.js b/cocos2d/core/platform/CCInputManager.js index 15c5d204f9..545d0b0d90 100644 --- a/cocos2d/core/platform/CCInputManager.js +++ b/cocos2d/core/platform/CCInputManager.js @@ -1,5 +1,5 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -26,19 +26,34 @@ /** * ignore */ -cc.UIInterfaceOrientationLandscapeLeft = -90; +/** + * @constant + * @type {number} + */ +cc.UIInterfaceOrientationLandscapeLeft = -90; +/** + * @constant + * @type {number} + */ cc.UIInterfaceOrientationLandscapeRight = 90; - +/** + * @constant + * @type {number} + */ cc.UIInterfaceOrientationPortraitUpsideDown = 180; - +/** + * @constant + * @type {number} + */ cc.UIInterfaceOrientationPortrait = 0; /** *

* This class manages all events of input. include: touch, mouse, accelerometer, keyboard
*

- * @namespace + * @class + * @name cc.inputManager */ cc.inputManager = /** @lends cc.inputManager# */{ _mousePressed: false, @@ -90,6 +105,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ _glView: null, + /** + * @function + * @param {Array} touches + */ handleTouchesBegin: function (touches) { var selTouch, index, curTouch, touchID, handleTouches = [], locTouchIntDict = this._touchesIntegerDict; for(var i = 0, len = touches.length; i< len; i ++){ @@ -99,11 +118,13 @@ cc.inputManager = /** @lends cc.inputManager# */{ if(index == null){ var unusedIndex = this._getUnUsedIndex(); - if (unusedIndex == -1) { + if (unusedIndex === -1) { cc.log(cc._LogInfos.inputManager_handleTouchesBegin, unusedIndex); continue; } - curTouch = this._touches[unusedIndex] = selTouch; + //curTouch = this._touches[unusedIndex] = selTouch; + curTouch = this._touches[unusedIndex] = new cc.Touch(selTouch._point.x, selTouch._point.y, selTouch.getID()); + curTouch._setPrevPoint(selTouch._prevPoint); locTouchIntDict[touchID] = unusedIndex; handleTouches.push(curTouch); } @@ -116,6 +137,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ } }, + /** + * @function + * @param {Array} touches + */ handleTouchesMove: function(touches){ var selTouch, index, touchID, handleTouches = [], locTouches = this._touches; for(var i = 0, len = touches.length; i< len; i ++){ @@ -141,6 +166,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ } }, + /** + * @function + * @param {Array} touches + */ handleTouchesEnd: function(touches){ var handleTouches = this.getSetOfTouchesEndOrCancel(touches); if(handleTouches.length > 0) { @@ -151,6 +180,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ } }, + /** + * @function + * @param {Array} touches + */ handleTouchesCancel: function(touches){ var handleTouches = this.getSetOfTouchesEndOrCancel(touches); if(handleTouches.length > 0) { @@ -161,6 +194,11 @@ cc.inputManager = /** @lends cc.inputManager# */{ } }, + /** + * @function + * @param {Array} touches + * @returns {Array} + */ getSetOfTouchesEndOrCancel: function(touches) { var selTouch, index, touchID, handleTouches = [], locTouches = this._touches, locTouchesIntDict = this._touchesIntegerDict; for(var i = 0, len = touches.length; i< len; i ++){ @@ -173,7 +211,7 @@ cc.inputManager = /** @lends cc.inputManager# */{ } if(locTouches[index]){ locTouches[index]._setPoint(selTouch._point); - locTouches[index]._setPrevPoint(selTouch._prevPoint); //TODO + locTouches[index]._setPrevPoint(selTouch._prevPoint); handleTouches.push(locTouches[index]); this._removeUsedIndexBit(index); delete locTouchesIntDict[touchID]; @@ -182,11 +220,16 @@ cc.inputManager = /** @lends cc.inputManager# */{ return handleTouches; }, + /** + * @function + * @param {HTMLElement} element + * @return {Object} + */ getHTMLElementPosition: function (element) { var docElem = document.documentElement; var win = window; var box = null; - if (typeof element.getBoundingClientRect === 'function') { + if (cc.isFunction(element.getBoundingClientRect)) { box = element.getBoundingClientRect(); } else { if (element instanceof HTMLCanvasElement) { @@ -213,12 +256,17 @@ cc.inputManager = /** @lends cc.inputManager# */{ }; }, + /** + * @function + * @param {cc.Touch} touch + * @return {cc.Touch} + */ getPreTouch: function(touch){ var preTouch = null; var locPreTouchPool = this._preTouchPool; - var id = touch.getId(); + var id = touch.getID(); for (var i = locPreTouchPool.length - 1; i >= 0; i--) { - if (locPreTouchPool[i].getId() == id) { + if (locPreTouchPool[i].getID() === id) { preTouch = locPreTouchPool[i]; break; } @@ -228,12 +276,16 @@ cc.inputManager = /** @lends cc.inputManager# */{ return preTouch; }, + /** + * @function + * @param {cc.Touch} touch + */ setPreTouch: function(touch){ var find = false; var locPreTouchPool = this._preTouchPool; - var id = touch.getId(); + var id = touch.getID(); for (var i = locPreTouchPool.length - 1; i >= 0; i--) { - if (locPreTouchPool[i].getId() == id) { + if (locPreTouchPool[i].getID() === id) { locPreTouchPool[i] = touch; find = true; break; @@ -249,6 +301,13 @@ cc.inputManager = /** @lends cc.inputManager# */{ } }, + /** + * @function + * @param {Number} tx + * @param {Number} ty + * @param {cc.Point} pos + * @return {cc.Touch} + */ getTouchByXY: function(tx, ty, pos){ var locPreTouch = this._preTouchPoint; var location = this._glView.convertToLocationInView(tx, ty, pos); @@ -259,6 +318,13 @@ cc.inputManager = /** @lends cc.inputManager# */{ return touch; }, + /** + * @function + * @param {cc.Point} location + * @param {cc.Point} pos + * @param {Number} eventType + * @returns {cc.EventMouse} + */ getMouseEvent: function(location, pos, eventType){ var locPreMouse = this._prevMousePoint; this._glView._convertMouseToLocationInView(location, pos); @@ -270,6 +336,12 @@ cc.inputManager = /** @lends cc.inputManager# */{ return mouseEvent; }, + /** + * @function + * @param {Touch} event + * @param {cc.Point} pos + * @return {cc.Point} + */ getPointByEvent: function(event, pos){ if (event.pageX != null) //not avalable in <= IE8 return {x: event.pageX, y: event.pageY}; @@ -279,6 +351,12 @@ cc.inputManager = /** @lends cc.inputManager# */{ return {x: event.clientX, y: event.clientY}; }, + /** + * @function + * @param {Touch} event + * @param {cc.Point} pos + * @returns {Array} + */ getTouchesByEvent: function(event, pos){ var touchArr = [], locView = this._glView; var touch_event, touch, preLocation; @@ -311,6 +389,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ return touchArr; }, + /** + * @function + * @param {HTMLElement} element + */ registerSystemEvent: function(element){ if(this._isRegisterEvent) return; @@ -318,6 +400,17 @@ cc.inputManager = /** @lends cc.inputManager# */{ var selfPointer = this; var supportMouse = ('mouse' in cc.sys.capabilities), supportTouches = ('touches' in cc.sys.capabilities); + //HACK + // - At the same time to trigger the ontouch event and onmouse event + // - The function will execute 2 times + //The known browser: + // liebiao + // miui + // WECHAT + var prohibition = false; + if( cc.sys.isMobile) + prohibition = true; + //register touch event if (supportMouse) { cc._addEventListener(window, 'mousedown', function () { @@ -325,6 +418,7 @@ cc.inputManager = /** @lends cc.inputManager# */{ }, false); cc._addEventListener(window, 'mouseup', function (event) { + if(prohibition) return; var savePressed = selfPointer._mousePressed; selfPointer._mousePressed = false; @@ -334,8 +428,7 @@ cc.inputManager = /** @lends cc.inputManager# */{ var pos = selfPointer.getHTMLElementPosition(element); var location = selfPointer.getPointByEvent(event, pos); if (!cc.rectContainsPoint(new cc.Rect(pos.left, pos.top, pos.width, pos.height), location)){ - if(!supportTouches) - selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); + selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.UP); mouseEvent.setButton(event.button); @@ -345,12 +438,13 @@ cc.inputManager = /** @lends cc.inputManager# */{ //register canvas mouse event cc._addEventListener(element,"mousedown", function (event) { + if(prohibition) return; selfPointer._mousePressed = true; var pos = selfPointer.getHTMLElementPosition(element); var location = selfPointer.getPointByEvent(event, pos); - if(!supportTouches) - selfPointer.handleTouchesBegin([selfPointer.getTouchByXY(location.x, location.y, pos)]); + + selfPointer.handleTouchesBegin([selfPointer.getTouchByXY(location.x, location.y, pos)]); var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.DOWN); mouseEvent.setButton(event.button); @@ -358,16 +452,17 @@ cc.inputManager = /** @lends cc.inputManager# */{ event.stopPropagation(); event.preventDefault(); + element.focus(); }, false); cc._addEventListener(element, "mouseup", function (event) { + if(prohibition) return; selfPointer._mousePressed = false; var pos = selfPointer.getHTMLElementPosition(element); var location = selfPointer.getPointByEvent(event, pos); - if(!supportTouches) - selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); + selfPointer.handleTouchesEnd([selfPointer.getTouchByXY(location.x, location.y, pos)]); var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.UP); mouseEvent.setButton(event.button); @@ -378,17 +473,18 @@ cc.inputManager = /** @lends cc.inputManager# */{ }, false); cc._addEventListener(element, "mousemove", function (event) { - if(!selfPointer._mousePressed) - return; + if(prohibition) return; var pos = selfPointer.getHTMLElementPosition(element); var location = selfPointer.getPointByEvent(event, pos); - if(!supportTouches) - selfPointer.handleTouchesMove([selfPointer.getTouchByXY(location.x, location.y, pos)]); + selfPointer.handleTouchesMove([selfPointer.getTouchByXY(location.x, location.y, pos)]); var mouseEvent = selfPointer.getMouseEvent(location,pos,cc.EventMouse.MOVE); - mouseEvent.setButton(event.button); + if(selfPointer._mousePressed) + mouseEvent.setButton(event.button); + else + mouseEvent.setButton(null); cc.eventManager.dispatchEvent(mouseEvent); event.stopPropagation(); @@ -440,7 +536,6 @@ cc.inputManager = /** @lends cc.inputManager# */{ _touchEvent.call(selfPointer, [selfPointer.getTouchByXY(event.clientX, event.clientY, pos)]); event.stopPropagation(); - event.preventDefault(); }, false); })(eventName, _pointerEventsMap[eventName]); } @@ -457,6 +552,7 @@ cc.inputManager = /** @lends cc.inputManager# */{ selfPointer.handleTouchesBegin(selfPointer.getTouchesByEvent(event, pos)); event.stopPropagation(); event.preventDefault(); + element.focus(); }, false); cc._addEventListener(element, "touchmove", function (event) { @@ -487,7 +583,7 @@ cc.inputManager = /** @lends cc.inputManager# */{ var pos = selfPointer.getHTMLElementPosition(element); pos.left -= document.body.scrollLeft; pos.top -= document.body.scrollTop; - locView.handleTouchesCancel(selfPointer.getTouchesByEvent(event, pos)); + selfPointer.handleTouchesCancel(selfPointer.getTouchesByEvent(event, pos)); event.stopPropagation(); event.preventDefault(); }, false); @@ -506,6 +602,10 @@ cc.inputManager = /** @lends cc.inputManager# */{ _registerAccelerometerEvent: function(){}, + /** + * @function + * @param {Number} dt + */ update:function(dt){ if(this._accelCurTime > this._accelInterval){ this._accelCurTime -= this._accelInterval; diff --git a/cocos2d/core/platform/CCLoaders.js b/cocos2d/core/platform/CCLoaders.js index c7f5608c99..541e3b91c5 100644 --- a/cocos2d/core/platform/CCLoaders.js +++ b/cocos2d/core/platform/CCLoaders.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -29,7 +28,7 @@ cc._txtLoader = { cc.loader.loadTxt(realUrl, cb); } }; -cc.loader.register(["txt", "xml", "vsh", "fsh"], cc._txtLoader); +cc.loader.register(["txt", "xml", "vsh", "fsh", "atlas"], cc._txtLoader); cc._jsonLoader = { load : function(realUrl, url, res, cb){ @@ -38,6 +37,13 @@ cc._jsonLoader = { }; cc.loader.register(["json", "ExportJson"], cc._jsonLoader); +cc._jsLoader = { + load : function(realUrl, url, res, cb){ + cc.loader.loadJs(realUrl, cb); + } +}; +cc.loader.register(["js"], cc._jsLoader); + cc._imgLoader = { load : function(realUrl, url, res, cb){ cc.loader.cache[url] = cc.loader.loadImg(realUrl, function(err, img){ @@ -48,7 +54,7 @@ cc._imgLoader = { }); } }; -cc.loader.register(["png", "jpg", "bmp","jpeg","gif"], cc._imgLoader); +cc.loader.register(["png", "jpg", "bmp","jpeg","gif", "ico"], cc._imgLoader); cc._serverImgLoader = { load : function(realUrl, url, res, cb){ cc.loader.cache[url] = cc.loader.loadImg(res.src, function(err, img){ @@ -74,10 +80,10 @@ cc.loader.register(["plist"], cc._plistLoader); cc._fontLoader = { TYPE : { - "eot" : "embedded-opentype", - "ttf" : "truetype", - "woff" : "woff", - "svg" : "svg" + ".eot" : "embedded-opentype", + ".ttf" : "truetype", + ".woff" : "woff", + ".svg" : "svg" }, _loadFont : function(name, srcs, type){ var doc = document, path = cc.path, TYPE = this.TYPE, fontStyle = cc.newElement("style"); @@ -88,9 +94,9 @@ cc._fontLoader = { if(srcs instanceof Array){ for(var i = 0, li = srcs.length; i < li; i++){ var src = srcs[i]; - type = path.extname(src); + type = path.extname(src).toLowerCase(); fontStr += "url('" + srcs[i] + "') format('" + TYPE[type] + "')"; - fontStr += (i == li - 1) ? ";" : ","; + fontStr += (i === li - 1) ? ";" : ","; } }else{ fontStr += "url('" + srcs + "') format('" + TYPE[type] + "');"; @@ -110,7 +116,7 @@ cc._fontLoader = { load : function(realUrl, url, res, cb){ var self = this; var type = res.type, name = res.name, srcs = res.srcs; - if(typeof res == "string"){ + if(cc.isString(res)){ type = cc.path.extname(res); name = cc.path.basename(res, type); self._loadFont(name, res, type); @@ -126,4 +132,11 @@ cc._binaryLoader = { load : function(realUrl, url, res, cb){ cc.loader.loadBinary(realUrl, cb); } -}; \ No newline at end of file +}; + +cc._csbLoader = { + load: function(realUrl, url, res, cb){ + cc.loader.loadCsb(realUrl, cb); + } +}; +cc.loader.register(["csb"], cc._csbLoader); \ No newline at end of file diff --git a/cocos2d/core/platform/CCMacro.js b/cocos2d/core/platform/CCMacro.js index 16a82fc979..cabb8f2c30 100644 --- a/cocos2d/core/platform/CCMacro.js +++ b/cocos2d/core/platform/CCMacro.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -43,6 +43,12 @@ cc.PI = Math.PI; */ cc.FLT_MAX = parseFloat('3.402823466e+38F'); +/** + * @constant + * @type Number + */ +cc.FLT_MIN = parseFloat("1.175494351e-38F"); + /** * @constant * @type Number @@ -68,14 +74,14 @@ cc.UINT_MAX = 0xffffffff; * modified from c++ macro, you need to pass in the x and y variables names in string,
* and then a reference to the whole object as third variable *

- * @param x - * @param y - * @param ref + * @param {String} x + * @param {String} y + * @param {Object} ref * @function - * @deprecated + * @deprecated since v3.0 */ cc.swap = function (x, y, ref) { - if ((typeof ref) == 'object' && (typeof ref.x) != 'undefined' && (typeof ref.y) != 'undefined') { + if (cc.isObject(ref) && !cc.isUndefined(ref.x) && !cc.isUndefined(ref.y)) { var tmp = ref[x]; ref[x] = ref[y]; ref[y] = tmp; @@ -134,6 +140,15 @@ cc.degreesToRadians = function (angle) { return angle * cc.RAD; }; +/** + * converts radians to degrees + * @param {Number} angle + * @return {Number} + * @function + */ +cc.radiansToDegrees = function (angle) { + return angle * cc.DEG; +}; /** * converts radians to degrees * @param {Number} angle @@ -141,6 +156,7 @@ cc.degreesToRadians = function (angle) { * @function */ cc.radiansToDegress = function (angle) { + cc.log(cc._LogInfos.radiansToDegress); return angle * cc.DEG; }; @@ -239,6 +255,7 @@ cc.FLT_EPSILON = 0.0000001192092896; * On Mac it returns 1;
* On iPhone it returns 2 if RetinaDisplay is On. Otherwise it returns 1 *

+ * @return {Number} * @function */ cc.contentScaleFactor = cc.IS_RETINA_DISPLAY_SUPPORTED ? function () { @@ -260,7 +277,8 @@ cc.pointPointsToPixels = function (points) { /** * Converts a Point in pixels to points - * @param {Point} pixels + * @param {cc.Rect} pixels + * @return {cc.Point} * @function */ cc.pointPixelsToPoints = function (pixels) { @@ -305,6 +323,7 @@ cc._sizePixelsToPointsOut = function (sizeInPixels, outSize) { /** * Converts a rect in pixels to points * @param {cc.Rect} pixel + * @return {cc.Rect} * @function */ cc.rectPixelsToPoints = cc.IS_RETINA_DISPLAY_SUPPORTED ? function (pixel) { @@ -318,6 +337,7 @@ cc.rectPixelsToPoints = cc.IS_RETINA_DISPLAY_SUPPORTED ? function (pixel) { /** * Converts a rect in points to pixels * @param {cc.Rect} point + * @return {cc.Rect} * @function */ cc.rectPointsToPixels = cc.IS_RETINA_DISPLAY_SUPPORTED ? function (point) { @@ -328,6 +348,7 @@ cc.rectPointsToPixels = cc.IS_RETINA_DISPLAY_SUPPORTED ? function (point) { return p; }; +//some gl constant variable /** * @constant * @type Number @@ -406,11 +427,43 @@ cc.ONE_MINUS_CONSTANT_ALPHA = 0x8004; */ cc.ONE_MINUS_CONSTANT_COLOR = 0x8002; +/** + * the constant variable equals gl.LINEAR for texture + * @constant + * @type Number + */ +cc.LINEAR = 0x2601; + +/** + * the constant variable equals gl.REPEAT for texture + * @constant + * @type Number + */ +cc.REPEAT = 0x2901; + +/** + * the constant variable equals gl.CLAMP_TO_EDGE for texture + * @constant + * @type Number + */ +cc.CLAMP_TO_EDGE = 0x812f; + +/** + * the constant variable equals gl.MIRRORED_REPEAT for texture + * @constant + * @type Number + */ +cc.MIRRORED_REPEAT = 0x8370; + +/** + * Check webgl error.Error will be shown in console if exists. + * @function + */ cc.checkGLErrorDebug = function () { - if (cc.renderMode == cc._RENDER_TYPE_WEBGL) { + if (cc.renderMode === cc._RENDER_TYPE_WEBGL) { var _error = cc._renderContext.getError(); if (_error) { - cc.log(CC._localZOrder.checkGLErrorDebug, _error); + cc.log(cc._LogInfos.checkGLErrorDebug, _error); } } }; @@ -700,4 +753,78 @@ cc.SELECTED_TAG = 8802; * @constant * @type Number */ -cc.DISABLE_TAG = 8803; \ No newline at end of file +cc.DISABLE_TAG = 8803; + + +// Array utils + +/** + * Verify Array's Type + * @param {Array} arr + * @param {function} type + * @return {Boolean} + * @function + */ +cc.arrayVerifyType = function (arr, type) { + if (arr && arr.length > 0) { + for (var i = 0; i < arr.length; i++) { + if (!(arr[i] instanceof type)) { + cc.log("element type is wrong!"); + return false; + } + } + } + return true; +}; + +/** + * Searches for the first occurance of object and removes it. If object is not found the function has no effect. + * @function + * @param {Array} arr Source Array + * @param {*} delObj remove object + */ +cc.arrayRemoveObject = function (arr, delObj) { + for (var i = 0, l = arr.length; i < l; i++) { + if (arr[i] === delObj) { + arr.splice(i, 1); + break; + } + } +}; + +/** + * Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. + * @function + * @param {Array} arr Source Array + * @param {Array} minusArr minus Array + */ +cc.arrayRemoveArray = function (arr, minusArr) { + for (var i = 0, l = minusArr.length; i < l; i++) { + cc.arrayRemoveObject(arr, minusArr[i]); + } +}; + +/** + * Inserts some objects at index + * @function + * @param {Array} arr + * @param {Array} addObjs + * @param {Number} index + * @return {Array} + */ +cc.arrayAppendObjectsToIndex = function(arr, addObjs,index){ + arr.splice.apply(arr, [index, 0].concat(addObjs)); + return arr; +}; + +/** + * Copy an array's item to a new array (its performance is better than Array.slice) + * @param {Array} arr + * @return {Array} + */ +cc.copyArray = function(arr){ + var i, len = arr.length, arr_clone = new Array(len); + for (i = 0; i < len; i += 1) + arr_clone[i] = arr[i]; + return arr_clone; +}; \ No newline at end of file diff --git a/cocos2d/core/platform/CCSAXParser.js b/cocos2d/core/platform/CCSAXParser.js index df436b38fd..d0088e8f26 100644 --- a/cocos2d/core/platform/CCSAXParser.js +++ b/cocos2d/core/platform/CCSAXParser.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,14 +25,18 @@ ****************************************************************************/ /** - * - * @namespace A SAX Parser + * A SAX Parser + * @class * @name cc.saxParser + * @extends cc.Class */ cc.SAXParser = cc.Class.extend(/** @lends cc.saxParser# */{ _parser: null, _isSupportDOMParser: null, + /** + * Constructor of cc.SAXParser + */ ctor: function () { if (window.DOMParser) { this._isSupportDOMParser = true; @@ -42,6 +46,11 @@ cc.SAXParser = cc.Class.extend(/** @lends cc.saxParser# */{ } }, + /** + * @function + * @param {String} xmlTxt + * @return {Document} + */ parse : function(xmlTxt){ return this._parseXML(xmlTxt); }, @@ -64,8 +73,10 @@ cc.SAXParser = cc.Class.extend(/** @lends cc.saxParser# */{ /** * - * @namespace A plist Parser + * cc.plistParser is a singleton object for parsing plist files + * @class * @name cc.plistParser + * @extends cc.SAXParser */ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ @@ -77,14 +88,14 @@ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ parse : function (xmlTxt) { var xmlDoc = this._parseXML(xmlTxt); var plist = xmlDoc.documentElement; - if (plist.tagName != 'plist') + if (plist.tagName !== 'plist') throw "Not a plist file!"; // Get first real node var node = null; for (var i = 0, len = plist.childNodes.length; i < len; i++) { node = plist.childNodes[i]; - if (node.nodeType == 1) + if (node.nodeType === 1) break; } xmlDoc = null; @@ -93,12 +104,12 @@ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ _parseNode: function (node) { var data = null, tagName = node.tagName; - if(tagName == "dict"){ + if(tagName === "dict"){ data = this._parseDict(node); - }else if(tagName == "array"){ + }else if(tagName === "array"){ data = this._parseArray(node); - }else if(tagName == "string"){ - if (node.childNodes.length == 1) + }else if(tagName === "string"){ + if (node.childNodes.length === 1) data = node.firstChild.nodeValue; else { //handle Firefox's 4KB nodeValue limit @@ -106,13 +117,13 @@ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ for (var i = 0; i < node.childNodes.length; i++) data += node.childNodes[i].nodeValue; } - }else if(tagName == "false"){ + }else if(tagName === "false"){ data = false; - }else if(tagName == "true"){ + }else if(tagName === "true"){ data = true; - }else if(tagName == "real"){ + }else if(tagName === "real"){ data = parseFloat(node.firstChild.nodeValue); - }else if(tagName == "integer"){ + }else if(tagName === "integer"){ data = parseInt(node.firstChild.nodeValue, 10); } return data; @@ -122,7 +133,7 @@ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ var data = []; for (var i = 0, len = node.childNodes.length; i < len; i++) { var child = node.childNodes[i]; - if (child.nodeType != 1) + if (child.nodeType !== 1) continue; data.push(this._parseNode(child)); } @@ -134,11 +145,11 @@ cc.PlistParser = cc.SAXParser.extend(/** @lends cc.plistParser# */{ var key = null; for (var i = 0, len = node.childNodes.length; i < len; i++) { var child = node.childNodes[i]; - if (child.nodeType != 1) + if (child.nodeType !== 1) continue; // Grab the key, next noe should be the value - if (child.tagName == 'key') + if (child.tagName === 'key') key = child.firstChild.nodeValue; else data[key] = this._parseNode(child); // Parse the value node diff --git a/cocos2d/core/platform/CCScreen.js b/cocos2d/core/platform/CCScreen.js index 874c4b035e..f1730fe015 100644 --- a/cocos2d/core/platform/CCScreen.js +++ b/cocos2d/core/platform/CCScreen.js @@ -1,20 +1,20 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + http://www.cocos2d-x.org - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -25,117 +25,125 @@ ****************************************************************************/ /** - * @namespace The fullscreen API provides an easy way for web content to be presented using the user's entire screen. - * It's invalid on safari,QQbrowser and android browser + * The fullscreen API provides an easy way for web content to be presented using the user's entire screen. + * It's invalid on safari, QQbrowser and android browser + * @class * @name cc.screen */ cc.screen = /** @lends cc.screen# */{ _supportsFullScreen: false, - // the pre fullscreenchange function + // the pre fullscreenchange function _preOnFullScreenChange: null, _touchEvent: "", - _fn: null, - // Function mapping for cross browser support - _fnMap: [ - [ - 'requestFullscreen', - 'exitFullscreen', - 'fullscreenchange', - 'fullscreenEnabled', - 'fullscreenElement' - ], - [ - 'requestFullScreen', - 'exitFullScreen', - 'fullScreenchange', - 'fullScreenEnabled', - 'fullScreenElement' - ], - [ - 'webkitRequestFullScreen', - 'webkitCancelFullScreen', - 'webkitfullscreenchange', - 'webkitIsFullScreen', - 'webkitCurrentFullScreenElement' - ], - [ - 'mozRequestFullScreen', - 'mozCancelFullScreen', - 'mozfullscreenchange', - 'mozFullScreen', - 'mozFullScreenElement' - ], - [ - 'msRequestFullscreen', - 'msExitFullscreen', - 'MSFullscreenChange', - 'msFullscreenEnabled', - 'msFullscreenElement' - ] - ], - + _fn: null, + // Function mapping for cross browser support + _fnMap: [ + [ + 'requestFullscreen', + 'exitFullscreen', + 'fullscreenchange', + 'fullscreenEnabled', + 'fullscreenElement' + ], + [ + 'requestFullScreen', + 'exitFullScreen', + 'fullScreenchange', + 'fullScreenEnabled', + 'fullScreenElement' + ], + [ + 'webkitRequestFullScreen', + 'webkitCancelFullScreen', + 'webkitfullscreenchange', + 'webkitIsFullScreen', + 'webkitCurrentFullScreenElement' + ], + [ + 'mozRequestFullScreen', + 'mozCancelFullScreen', + 'mozfullscreenchange', + 'mozFullScreen', + 'mozFullScreenElement' + ], + [ + 'msRequestFullscreen', + 'msExitFullscreen', + 'MSFullscreenChange', + 'msFullscreenEnabled', + 'msFullscreenElement' + ] + ], + + /** + * initialize + * @function + */ init: function () { - this._fn = {}; - var i, val, map = this._fnMap, valL; - for (i = 0, l = map.length; i < l; i++ ) { - val = map[ i ]; - if ( val && val[1] in document ) { - for ( i = 0, valL = val.length; i < valL; i++ ) { - this._fn[ map[0][ i ] ] = val[ i ]; - } - break; - } - } + this._fn = {}; + var i, val, map = this._fnMap, valL; + for (i = 0, l = map.length; i < l; i++) { + val = map[i]; + if (val && val[1] in document) { + for (i = 0, valL = val.length; i < valL; i++) { + this._fn[map[0][i]] = val[i]; + } + break; + } + } - this._supportsFullScreen = (this._fn.requestFullscreen != undefined); + this._supportsFullScreen = (typeof this._fn.requestFullscreen !== 'undefined'); this._touchEvent = ('ontouchstart' in window) ? 'touchstart' : 'mousedown'; }, - + /** * return true if it's full now. * @returns {Boolean} */ - fullScreen: function() { - return this._supportsFullScreen && document[ this._fn.fullscreenEnabled ]; + fullScreen: function () { + return this._supportsFullScreen && document[this._fn.fullscreenElement]; }, - + /** * change the screen to full mode. * @param {Element} element * @param {Function} onFullScreenChange */ requestFullScreen: function (element, onFullScreenChange) { - if (!this._supportsFullScreen) return; + if (!this._supportsFullScreen) { + return; + } - element = element || document.documentElement; - element[ this._fn.requestFullscreen ](); + element = element || document.documentElement; - if (onFullScreenChange) { - var eventName = this._fn.fullscreenchange; - if (this._preOnFullScreenChange) - document.removeEventListener(eventName, this._preOnFullScreenChange); - this._preOnFullScreenChange = onFullScreenChange; + if (onFullScreenChange) { + var eventName = this._fn.fullscreenchange; + if (this._preOnFullScreenChange) { + document.removeEventListener(eventName, this._preOnFullScreenChange); + } + this._preOnFullScreenChange = onFullScreenChange; cc._addEventListener(document, eventName, onFullScreenChange, false); - } + } - return element[ this._fn.requestFullscreen ](); + return element[this._fn.requestFullscreen](); }, - + /** * exit the full mode. + * @return {Boolean} */ exitFullScreen: function () { - return this._supportsFullScreen ? document[ this._fn.exitFullscreen ]() : true; + return this._supportsFullScreen ? document[this._fn.exitFullscreen]() : true; }, - + /** * Automatically request full screen with a touch/click event * @param {Element} element * @param {Function} onFullScreenChange */ autoFullScreen: function (element, onFullScreenChange) { - element = element || document.body; - var touchTarget = cc._canvas || element; + element = element || document.body; + var touchTarget = cc._canvas || element; var theScreen = this; // Function bind will be too complicated here because we need the callback function's reference to remove the listener function callback() { diff --git a/cocos2d/core/platform/CCTypes.js b/cocos2d/core/platform/CCTypes.js index 3e0acbb699..06ed754cce 100644 --- a/cocos2d/core/platform/CCTypes.js +++ b/cocos2d/core/platform/CCTypes.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,40 +25,55 @@ ****************************************************************************/ /** - * The color class - * @param {Number} r 0 to 255 - * @param {Number} g 0 to 255 - * @param {Number} b 0 to 255 - * @param {Number} a 0 to 255 - * @constructor + * Color class, please use cc.color() to construct a color + * @class cc.Color + * @param {Number} r + * @param {Number} g + * @param {Number} b + * @param {Number} a + * @see cc.color */ cc.Color = function (r, g, b, a) { this.r = r || 0; this.g = g || 0; this.b = b || 0; - this.a = a || 0; + this.a = (a == null) ? 255 : a; }; /** + * Generate a color object based on multiple forms of parameters + * @example + * + * // 1. All channels seperately as parameters + * var color1 = cc.color(255, 255, 255, 255); + * + * // 2. Convert a hex string to a color + * var color2 = cc.color("#000000"); + * + * // 3. An color object as parameter + * var color3 = cc.color({r: 255, g: 255, b: 255, a: 255}); + * + * Alpha channel is optional. Default value is 255 * * @param {Number|String|cc.Color} r * @param {Number} g * @param {Number} b - * @param {Number} a - * @returns {cc.Color} + * @param {Number} [a=255] + * @return {cc.Color} */ cc.color = function (r, g, b, a) { if (r === undefined) return {r: 0, g: 0, b: 0, a: 255}; - if (typeof r === "string") + if (cc.isString(r)) return cc.hexToColor(r); - if (typeof r === "object") - return {r: r.r, g: r.g, b: r.b, a: r.a}; - return {r: r, g: g, b: b, a: a }; + if (cc.isObject(r)) + return {r: r.r, g: r.g, b: r.b, a: (r.a == null) ? 255 : r.a}; + return {r: r, g: g, b: b, a: (a == null ? 255 : a)}; }; /** * returns true if both ccColor3B are equal. Otherwise it returns false. + * @function * @param {cc.Color} color1 * @param {cc.Color} color2 * @return {Boolean} true if both ccColor3B are equal. Otherwise it returns false. @@ -69,6 +84,12 @@ cc.colorEqual = function (color1, color2) { /** * the device accelerometer reports values for each axis in units of g-force + * @class cc.Acceleration + * @constructor + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @param {Number} timestamp */ cc.Acceleration = function (x, y, z, timestamp) { this.x = x || 0; @@ -78,9 +99,8 @@ cc.Acceleration = function (x, y, z, timestamp) { }; /** - * A vertex composed of 2 floats: x, y - * @Class - * @Construct + * @class cc.Vertex2F + * @constructor * @param {Number} x1 * @param {Number} y1 */ @@ -90,7 +110,7 @@ cc.Vertex2F = function (x1, y1) { }; /** - * helper macro that creates an Vertex2F type + * Helper macro that creates an Vertex2F type composed of 2 floats: x, y * @function * @param {Number} x * @param {Number} y @@ -101,9 +121,8 @@ cc.vertex2 = function (x, y) { }; /** - * A vertex composed of 3 floats: x, y, z - * @Class - * @Construct + * @class cc.Vertex3F + * @constructor * @param {Number} x1 * @param {Number} y1 * @param {Number} z1 @@ -115,7 +134,7 @@ cc.Vertex3F = function (x1, y1, z1) { }; /** - * helper macro that creates an Vertex3F type + * Helper macro that creates an Vertex3F type composed of 3 floats: x, y, z * @function * @param {Number} x * @param {Number} y @@ -127,9 +146,8 @@ cc.vertex3 = function (x, y, z) { }; /** - * A texcoord composed of 2 floats: u, y - * @Class - * @Construct + * @class cc.Tex2F + * @constructor * @param {Number} u1 * @param {Number} v1 */ @@ -139,7 +157,7 @@ cc.Tex2F = function (u1, v1) { }; /** - * helper macro that creates an Tex2F type + * Helper macro that creates an Tex2F type: A texcoord composed of 2 floats: u, y * @function * @param {Number} u * @param {Number} v @@ -151,8 +169,8 @@ cc.tex2 = function (u, v) { /** * Blend Function used for textures - * @Class - * @Construct + * @Class cc.BlendFunc + * @Constructor * @param {Number} src1 source blend function * @param {Number} dst1 destination blend function */ @@ -161,6 +179,10 @@ cc.BlendFunc = function (src1, dst1) { this.dst = dst1; }; +/** + * @function + * @returns {cc.BlendFunc} + */ cc.blendFuncDisable = function () { return new cc.BlendFunc(cc.ONE, cc.ZERO); }; @@ -168,6 +190,7 @@ cc.blendFuncDisable = function () { /** * convert a string of color for style to Color. * e.g. "#ff06ff" to : cc.color(255,6,255) + * @function * @param {String} hex * @return {cc.Color} */ @@ -183,6 +206,7 @@ cc.hexToColor = function (hex) { /** * convert Color to a string of color for style. * e.g. cc.color(255,6,255) to : "#ff06ff" + * @function * @param {cc.Color} color * @return {String} */ @@ -313,7 +337,28 @@ cc._Dictionary = cc.Class.extend({ } }); -cc.FontDefinition = function () { +/** + * Common usage: + * + * var fontDef = new cc.FontDefinition(); + * fontDef.fontName = "Arial"; + * fontDef.fontSize = 12; + * ... + * + * OR using inline definition usefull for constructor injection + * + * var fontDef = new cc.FontDefinition({ + * fontName: "Arial", + * fontSize: 12 + * }); + * + * + * + * @class cc.FontDefinition + * @param {Object} properties - (OPTIONAL) Allow inline FontDefinition + * @constructor + */ +cc.FontDefinition = function (properties) { var _t = this; _t.fontName = "Arial"; _t.fontSize = 12; @@ -326,19 +371,38 @@ cc.FontDefinition = function () { _t.strokeEnabled = false; _t.strokeStyle = cc.color(255, 255, 255, 255); _t.lineWidth = 1; + _t.lineHeight = "normal"; + _t.fontStyle = "normal"; + _t.fontWeight = "normal"; _t.shadowEnabled = false; _t.shadowOffsetX = 0; _t.shadowOffsetY = 0; _t.shadowBlur = 0; _t.shadowOpacity = 1.0; + + //properties mapping: + if(properties && properties instanceof Object){ + for(var key in properties){ + _t[key] = properties[key]; + } + } +}; +/** + * Web ONLY + * */ +cc.FontDefinition.prototype._getCanvasFontStr = function(){ + var lineHeight = !this.lineHeight.charAt ? this.lineHeight+"px" : this.lineHeight; + return this.fontStyle + " " + this.fontWeight + " " + this.fontSize + "px/"+lineHeight+" '" + this.fontName + "'"; }; if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _tmp.WebGLColor(); - delete _tmp.WebGLColor; + cc.assert(cc.isFunction(cc._tmp.WebGLColor), cc._LogInfos.MissingFile, "CCTypesWebGL.js"); + cc._tmp.WebGLColor(); + delete cc._tmp.WebGLColor; } -_tmp.PrototypeColor(); -delete _tmp.PrototypeColor; +cc.assert(cc.isFunction(cc._tmp.PrototypeColor), cc._LogInfos.MissingFile, "CCTypesPropertyDefine.js"); +cc._tmp.PrototypeColor(); +delete cc._tmp.PrototypeColor; diff --git a/cocos2d/core/platform/CCTypesPropertyDefine.js b/cocos2d/core/platform/CCTypesPropertyDefine.js index a80e1d3809..f0be5ac1de 100644 --- a/cocos2d/core/platform/CCTypesPropertyDefine.js +++ b/cocos2d/core/platform/CCTypesPropertyDefine.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,7 +24,7 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.PrototypeColor = function () { +cc._tmp.PrototypeColor = function () { var _p = cc.color; /** * White color (255, 255, 255, 255) @@ -134,6 +134,32 @@ _tmp.PrototypeColor = function () { /** @expose */ _p.GRAY; cc.defineGetterSetter(_p, "GRAY", _p._getGray); + + cc.BlendFunc._disable = function(){ + return new cc.BlendFunc(cc.ONE, cc.ZERO); + }; + cc.BlendFunc._alphaPremultiplied = function(){ + return new cc.BlendFunc(cc.ONE, cc.ONE_MINUS_SRC_ALPHA); + }; + cc.BlendFunc._alphaNonPremultiplied = function(){ + return new cc.BlendFunc(cc.SRC_ALPHA, cc.ONE_MINUS_SRC_ALPHA); + }; + cc.BlendFunc._additive = function(){ + return new cc.BlendFunc(cc.SRC_ALPHA, cc.ONE); + }; + + /** @expose */ + cc.BlendFunc.DISABLE; + cc.defineGetterSetter(cc.BlendFunc, "DISABLE", cc.BlendFunc._disable); + /** @expose */ + cc.BlendFunc.ALPHA_PREMULTIPLIED; + cc.defineGetterSetter(cc.BlendFunc, "ALPHA_PREMULTIPLIED", cc.BlendFunc._alphaPremultiplied); + /** @expose */ + cc.BlendFunc.ALPHA_NON_PREMULTIPLIED; + cc.defineGetterSetter(cc.BlendFunc, "ALPHA_NON_PREMULTIPLIED", cc.BlendFunc._alphaNonPremultiplied); + /** @expose */ + cc.BlendFunc.ADDITIVE; + cc.defineGetterSetter(cc.BlendFunc, "ADDITIVE", cc.BlendFunc._additive); }; diff --git a/cocos2d/core/platform/CCTypesWebGL.js b/cocos2d/core/platform/CCTypesWebGL.js index b89758ce5e..dbcd2ad478 100644 --- a/cocos2d/core/platform/CCTypesWebGL.js +++ b/cocos2d/core/platform/CCTypesWebGL.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,20 +24,43 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.WebGLColor = function () { +var cc = cc || {}; +cc._tmp = cc._tmp || {}; + +cc._tmp.WebGLColor = function () { //redefine some types with ArrayBuffer for WebGL + /** + * @class cc.Color + * @param {Number} r + * @param {Number}g + * @param {Number} b + * @param {Number} a + * @param {Array} arrayBuffer + * @param {Number} offset + * @returns {cc.Color} + */ cc.color = function (r, g, b, a, arrayBuffer, offset) { if (r === undefined) return new cc.Color(0, 0, 0, 255, arrayBuffer, offset); - if (typeof r === "string") { + if (cc.isString(r)) { var color = cc.hexToColor(r); return new cc.Color(color.r, color.g, color.b, color.a); } - if (typeof r === "object") + if (cc.isObject(r)) return new cc.Color(r.r, r.g, r.b, r.a, r.arrayBuffer, r.offset); return new cc.Color(r, g, b, a, arrayBuffer, offset); }; //redefine cc.Color + /** + * @class cc.Color + * @param {Number} r + * @param {Number}g + * @param {Number} b + * @param {Number} a + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.Color = function (r, g, b, a, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.Color.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -49,16 +74,17 @@ _tmp.WebGLColor = function () { this._rU8[0] = r || 0; this._gU8[0] = g || 0; this._bU8[0] = b || 0; - this._aU8[0] = a || 0; + this._aU8[0] = (a == null) ? 255 : a; - if (a === undefined) { + if (a === undefined) this.a_undefined = true; - } }; + /** + * @constant + * @type {number} + */ cc.Color.BYTES_PER_ELEMENT = 4; - var _p = cc.Color.prototype; - _p._getR = function () { return this._rU8[0]; }; @@ -96,8 +122,15 @@ _tmp.WebGLColor = function () { _p.a; cc.defineGetterSetter(_p, "a", _p._getA, _p._setA); - //redefine cc.Vertex2F + /** + * @class cc.Vertex2F + * @param {Number} x + * @param {Number}y + * @param {Array} arrayBuffer + * @param {Number}offset + * @constructor + */ cc.Vertex2F = function (x, y, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.Vertex2F.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -107,29 +140,42 @@ _tmp.WebGLColor = function () { this._xF32[0] = x || 0; this._yF32[0] = y || 0; }; + /** + * @constant + * @type {number} + */ cc.Vertex2F.BYTES_PER_ELEMENT = 8; - Object.defineProperties(cc.Vertex2F.prototype, { - x: { - get: function () { - return this._xF32[0]; - }, - set: function (xValue) { - this._xF32[0] = xValue; - }, - enumerable: true - }, - y: { - get: function () { - return this._yF32[0]; - }, - set: function (yValue) { - this._yF32[0] = yValue; - }, - enumerable: true - } - }); + + _p = cc.Vertex2F.prototype; + _p._getX = function () { + return this._xF32[0]; + }; + _p._setX = function (xValue) { + this._xF32[0] = xValue; + }; + _p._getY = function () { + return this._yF32[0]; + }; + _p._setY = function (yValue) { + this._yF32[0] = yValue; + }; + /** @expose */ + _p.x; + cc.defineGetterSetter(_p, "x", _p._getX, _p._setX); + /** @expose */ + _p.y; + cc.defineGetterSetter(_p, "y", _p._getY, _p._setY); // redefine cc.Vertex3F + /** + * @class cc.Vertex3F + * @param {Number} x + * @param {Number} y + * @param {Number}z + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.Vertex3F = function (x, y, z, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.Vertex3F.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -142,38 +188,50 @@ _tmp.WebGLColor = function () { this._zF32 = new Float32Array(locArrayBuffer, locOffset + Float32Array.BYTES_PER_ELEMENT * 2, 1); this._zF32[0] = z || 0; }; + /** + * @constant + * @type {number} + */ cc.Vertex3F.BYTES_PER_ELEMENT = 12; - Object.defineProperties(cc.Vertex3F.prototype, { - x: { - get: function () { - return this._xF32[0]; - }, - set: function (xValue) { - this._xF32[0] = xValue; - }, - enumerable: true - }, - y: { - get: function () { - return this._yF32[0]; - }, - set: function (yValue) { - this._yF32[0] = yValue; - }, - enumerable: true - }, - z: { - get: function () { - return this._zF32[0]; - }, - set: function (zValue) { - this._zF32[0] = zValue; - }, - enumerable: true - } - }); + + _p = cc.Vertex3F.prototype; + _p._getX = function () { + return this._xF32[0]; + }; + _p._setX = function (xValue) { + this._xF32[0] = xValue; + }; + _p._getY = function () { + return this._yF32[0]; + }; + _p._setY = function (yValue) { + this._yF32[0] = yValue; + }; + _p._getZ = function () { + return this._zF32[0]; + }; + _p._setZ = function (zValue) { + this._zF32[0] = zValue; + }; + /** @expose */ + _p.x; + cc.defineGetterSetter(_p, "x", _p._getX, _p._setX); + /** @expose */ + _p.y; + cc.defineGetterSetter(_p, "y", _p._getY, _p._setY); + /** @expose */ + _p.z; + cc.defineGetterSetter(_p, "z", _p._getZ, _p._setZ); // redefine cc.Tex2F + /** + * @class cc.Tex2F + * @param {Number} u + * @param {Number} v + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.Tex2F = function (u, v, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.Tex2F.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -183,29 +241,43 @@ _tmp.WebGLColor = function () { this._uF32[0] = u || 0; this._vF32[0] = v || 0; }; + /** + * @constants + * @type {number} + */ cc.Tex2F.BYTES_PER_ELEMENT = 8; - Object.defineProperties(cc.Tex2F.prototype, { - u: { - get: function () { - return this._uF32[0]; - }, - set: function (xValue) { - this._uF32[0] = xValue; - }, - enumerable: true - }, - v: { - get: function () { - return this._vF32[0]; - }, - set: function (yValue) { - this._vF32[0] = yValue; - }, - enumerable: true - } - }); + + _p = cc.Tex2F.prototype; + _p._getU = function () { + return this._uF32[0]; + }; + _p._setU = function (xValue) { + this._uF32[0] = xValue; + }; + _p._getV = function () { + return this._vF32[0]; + }; + _p._setV = function (yValue) { + this._vF32[0] = yValue; + }; + /** @expose */ + _p.u; + cc.defineGetterSetter(_p, "u", _p._getU, _p._setU); + /** @expose */ + _p.v; + cc.defineGetterSetter(_p, "v", _p._getV, _p._setV); //redefine cc.Quad2 + /** + * @class cc.Quad2 + * @param {cc.Vertex2F} tl + * @param {cc.Vertex2F} tr + * @param {cc.Vertex2F} bl + * @param {cc.Vertex2F} br + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.Quad2 = function (tl, tr, bl, br, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.Quad2.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -216,11 +288,58 @@ _tmp.WebGLColor = function () { this._bl = bl ? new cc.Vertex2F(bl.x, bl.y, locArrayBuffer, locElementLen * 2) : new cc.Vertex2F(0, 0, locArrayBuffer, locElementLen * 2); this._br = br ? new cc.Vertex2F(br.x, br.y, locArrayBuffer, locElementLen * 3) : new cc.Vertex2F(0, 0, locArrayBuffer, locElementLen * 3); }; + /** + * @constant + * @type {number} + */ cc.Quad2.BYTES_PER_ELEMENT = 32; + _p = cc.Quad2.prototype; + _p._getTL = function () { + return this._tl; + }; + _p._setTL = function (tlValue) { + this._tl.x = tlValue.x; + this._tl.y = tlValue.y; + }; + _p._getTR = function () { + return this._tr; + }; + _p._setTR = function (trValue) { + this._tr.x = trValue.x; + this._tr.y = trValue.y; + }; + _p._getBL = function() { + return this._bl; + }; + _p._setBL = function (blValue) { + this._bl.x = blValue.x; + this._bl.y = blValue.y; + }; + _p._getBR = function () { + return this._br; + }; + _p._setBR = function (brValue) { + this._br.x = brValue.x; + this._br.y = brValue.y; + }; + + /** @expose */ + _p.tl; + cc.defineGetterSetter(_p, "tl", _p._getTL, _p._setTL); + /** @expose */ + _p.tr; + cc.defineGetterSetter(_p, "tr", _p._getTR, _p._setTR); + /** @expose */ + _p.bl; + cc.defineGetterSetter(_p, "bl", _p._getBL, _p._setBL); + /** @expose */ + _p.br; + cc.defineGetterSetter(_p, "br", _p._getBR, _p._setBR); + /** * A 3D Quad. 4 * 3 floats - * @Class + * @Class cc.Quad3 * @Construct * @param {cc.Vertex3F} bl1 * @param {cc.Vertex3F} br1 @@ -234,50 +353,16 @@ _tmp.WebGLColor = function () { this.tr = tr1 || new cc.Vertex3F(0, 0, 0); }; - Object.defineProperties(cc.Quad2.prototype, { - tl: { - get: function () { - return this._tl; - }, - set: function (tlValue) { - this._tl.x = tlValue.x; - this._tl.y = tlValue.y; - }, - enumerable: true - }, - tr: { - get: function () { - return this._tr; - }, - set: function (trValue) { - this._tr.x = trValue.x; - this._tr.y = trValue.y; - }, - enumerable: true - }, - bl: { - get: function () { - return this._bl; - }, - set: function (blValue) { - this._bl.x = blValue.x; - this._bl.y = blValue.y; - }, - enumerable: true - }, - br: { - get: function () { - return this._br; - }, - set: function (brValue) { - this._br.x = brValue.x; - this._br.y = brValue.y; - }, - enumerable: true - } - }); - //redefine cc.V3F_C4B_T2F + /** + * @class cc.V3F_C4B_T2F + * @param {cc.Vertex3F} vertices + * @param { cc.color} colors + * @param {cc.Tex2F} texCoords + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.V3F_C4B_T2F = function (vertices, colors, texCoords, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.V3F_C4B_T2F.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -290,46 +375,60 @@ _tmp.WebGLColor = function () { this._texCoords = texCoords ? new cc.Tex2F(texCoords.u, texCoords.v, locArrayBuffer, locOffset + locElementLen + cc.Color.BYTES_PER_ELEMENT) : new cc.Tex2F(0, 0, locArrayBuffer, locOffset + locElementLen + cc.Color.BYTES_PER_ELEMENT); }; + /** + * @constant + * @type {number} + */ cc.V3F_C4B_T2F.BYTES_PER_ELEMENT = 24; - Object.defineProperties(cc.V3F_C4B_T2F.prototype, { - vertices: { - get: function () { - return this._vertices; - }, - set: function (verticesValue) { - var locVertices = this._vertices; - locVertices.x = verticesValue.x; - locVertices.y = verticesValue.y; - locVertices.z = verticesValue.z; - }, - enumerable: true - }, - colors: { - get: function () { - return this._colors; - }, - set: function (colorValue) { - var locColors = this._colors; - locColors.r = colorValue.r; - locColors.g = colorValue.g; - locColors.b = colorValue.b; - locColors.a = colorValue.a; - }, - enumerable: true - }, - texCoords: { - get: function () { - return this._texCoords; - }, - set: function (texValue) { - this._texCoords.u = texValue.u; - this._texCoords.v = texValue.v; - }, - enumerable: true - } - }); + + _p = cc.V3F_C4B_T2F.prototype; + _p._getVertices = function () { + return this._vertices; + }; + _p._setVertices = function (verticesValue) { + var locVertices = this._vertices; + locVertices.x = verticesValue.x; + locVertices.y = verticesValue.y; + locVertices.z = verticesValue.z; + }; + _p._getColor = function () { + return this._colors; + }; + _p._setColor = function (colorValue) { + var locColors = this._colors; + locColors.r = colorValue.r; + locColors.g = colorValue.g; + locColors.b = colorValue.b; + locColors.a = colorValue.a; + }; + _p._getTexCoords = function () { + return this._texCoords; + }; + _p._setTexCoords = function (texValue) { + this._texCoords.u = texValue.u; + this._texCoords.v = texValue.v; + }; + /** @expose */ + _p.vertices; + cc.defineGetterSetter(_p, "vertices", _p._getVertices, _p._setVertices); + /** @expose */ + _p.colors; + cc.defineGetterSetter(_p, "colors", _p._getColor, _p._setColor); + /** @expose */ + _p.texCoords; + cc.defineGetterSetter(_p, "texCoords", _p._getTexCoords, _p._setTexCoords); //redefine cc.V3F_C4B_T2F_Quad + /** + * @cc.class cc.V3F_C4B_T2F_Quad + * @param {cc.V3F_C4B_T2F} tl + * @param {cc.V3F_C4B_T2F} bl + * @param {cc.V3F_C4B_T2F} tr + * @param {cc.V3F_C4B_T2F} br + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.V3F_C4B_T2F_Quad = function (tl, bl, tr, br, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -344,67 +443,81 @@ _tmp.WebGLColor = function () { this._br = br ? new cc.V3F_C4B_T2F(br.vertices, br.colors, br.texCoords, locArrayBuffer, locOffset + locElementLen * 3) : new cc.V3F_C4B_T2F(null, null, null, locArrayBuffer, locOffset + locElementLen * 3); }; + /** + * @constant + * @type {number} + */ cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT = 96; - Object.defineProperties(cc.V3F_C4B_T2F_Quad.prototype, { - tl: { - get: function () { - return this._tl; - }, - set: function (tlValue) { - var locTl = this._tl; - locTl.vertices = tlValue.vertices; - locTl.colors = tlValue.colors; - locTl.texCoords = tlValue.texCoords; - }, - enumerable: true - }, - bl: { - get: function () { - return this._bl; - }, - set: function (blValue) { - var locBl = this._bl; - locBl.vertices = blValue.vertices; - locBl.colors = blValue.colors; - locBl.texCoords = blValue.texCoords; - }, - enumerable: true - }, - tr: { - get: function () { - return this._tr; - }, - set: function (trValue) { - var locTr = this._tr; - locTr.vertices = trValue.vertices; - locTr.colors = trValue.colors; - locTr.texCoords = trValue.texCoords; - }, - enumerable: true - }, - br: { - get: function () { - return this._br; - }, - set: function (brValue) { - var locBr = this._br; - locBr.vertices = brValue.vertices; - locBr.colors = brValue.colors; - locBr.texCoords = brValue.texCoords; - }, - enumerable: true - }, - arrayBuffer: { - get: function () { - return this._arrayBuffer; - }, - enumerable: true - } - }); + _p = cc.V3F_C4B_T2F_Quad.prototype; + _p._getTL = function () { + return this._tl; + }; + _p._setTL = function (tlValue) { + var locTl = this._tl; + locTl.vertices = tlValue.vertices; + locTl.colors = tlValue.colors; + locTl.texCoords = tlValue.texCoords; + }; + _p._getBL = function () { + return this._bl; + }; + _p._setBL = function (blValue) { + var locBl = this._bl; + locBl.vertices = blValue.vertices; + locBl.colors = blValue.colors; + locBl.texCoords = blValue.texCoords; + }; + _p._getTR = function () { + return this._tr; + }; + _p._setTR = function (trValue) { + var locTr = this._tr; + locTr.vertices = trValue.vertices; + locTr.colors = trValue.colors; + locTr.texCoords = trValue.texCoords; + }; + _p._getBR = function () { + return this._br; + }; + _p._setBR = function (brValue) { + var locBr = this._br; + locBr.vertices = brValue.vertices; + locBr.colors = brValue.colors; + locBr.texCoords = brValue.texCoords; + }; + _p._getArrayBuffer = function () { + return this._arrayBuffer; + }; + + /** @expose */ + _p.tl; + cc.defineGetterSetter(_p, "tl", _p._getTL, _p._setTL); + /** @expose */ + _p.tr; + cc.defineGetterSetter(_p, "tr", _p._getTR, _p._setTR); + /** @expose */ + _p.bl; + cc.defineGetterSetter(_p, "bl", _p._getBL, _p._setBL); + /** @expose */ + _p.br; + cc.defineGetterSetter(_p, "br", _p._getBR, _p._setBR); + /** @expose */ + _p.arrayBuffer; + cc.defineGetterSetter(_p, "arrayBuffer", _p._getArrayBuffer, null); + + /** + * @function + * @returns {cc.V3F_C4B_T2F_Quad} + */ cc.V3F_C4B_T2F_QuadZero = function () { return new cc.V3F_C4B_T2F_Quad(); }; + /** + * @function + * @param {cc.V3F_C4B_T2F_Quad} sourceQuad + * @return {cc.V3F_C4B_T2F_Quad} + */ cc.V3F_C4B_T2F_QuadCopy = function (sourceQuad) { if (!sourceQuad) return cc.V3F_C4B_T2F_QuadZero(); @@ -427,6 +540,11 @@ _tmp.WebGLColor = function () { }; }; + /** + * @function + * @param {Array} sourceQuads + * @returns {Array} + */ cc.V3F_C4B_T2F_QuadsCopy = function (sourceQuads) { if (!sourceQuads) return []; @@ -439,6 +557,15 @@ _tmp.WebGLColor = function () { }; //redefine cc.V2F_C4B_T2F + /** + * @class cc.V2F_C4B_T2F + * @param {cc.Vertex2F} vertices + * @param {cc.color} colors + * @param {cc.Tex2F} texCoords + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.V2F_C4B_T2F = function (vertices, colors, texCoords, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.V2F_C4B_T2F.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -451,44 +578,58 @@ _tmp.WebGLColor = function () { this._texCoords = texCoords ? new cc.Tex2F(texCoords.u, texCoords.v, locArrayBuffer, locOffset + locElementLen + cc.Color.BYTES_PER_ELEMENT) : new cc.Tex2F(0, 0, locArrayBuffer, locOffset + locElementLen + cc.Color.BYTES_PER_ELEMENT); }; + + /** + * @constant + * @type {number} + */ cc.V2F_C4B_T2F.BYTES_PER_ELEMENT = 20; - Object.defineProperties(cc.V2F_C4B_T2F.prototype, { - vertices: { - get: function () { - return this._vertices; - }, - set: function (verticesValue) { - this._vertices.x = verticesValue.x; - this._vertices.y = verticesValue.y; - }, - enumerable: true - }, - colors: { - get: function () { - return this._colors; - }, - set: function (colorValue) { - var locColors = this._colors; - locColors.r = colorValue.r; - locColors.g = colorValue.g; - locColors.b = colorValue.b; - locColors.a = colorValue.a; - }, - enumerable: true - }, - texCoords: { - get: function () { - return this._texCoords; - }, - set: function (texValue) { - this._texCoords.u = texValue.u; - this._texCoords.v = texValue.v; - }, - enumerable: true - } - }); + _p = cc.V2F_C4B_T2F.prototype; + _p._getVertices = function () { + return this._vertices; + }; + _p._setVertices = function (verticesValue) { + this._vertices.x = verticesValue.x; + this._vertices.y = verticesValue.y; + }; + _p._getColor = function () { + return this._colors; + }; + _p._setColor = function (colorValue) { + var locColors = this._colors; + locColors.r = colorValue.r; + locColors.g = colorValue.g; + locColors.b = colorValue.b; + locColors.a = colorValue.a; + }; + _p._getTexCoords = function () { + return this._texCoords; + }; + _p._setTexCoords = function (texValue) { + this._texCoords.u = texValue.u; + this._texCoords.v = texValue.v; + }; + + /** @expose */ + _p.vertices; + cc.defineGetterSetter(_p, "vertices", _p._getVertices, _p._setVertices); + /** @expose */ + _p.colors; + cc.defineGetterSetter(_p, "colors", _p._getColor, _p._setColor); + /** @expose */ + _p.texCoords; + cc.defineGetterSetter(_p, "texCoords", _p._getTexCoords, _p._setTexCoords); //redefine cc.V2F_C4B_T2F_Triangle + /** + * @class cc.V2F_C4B_T2F_Triangle + * @param {cc.V2F_C4B_T2F} a + * @param {cc.V2F_C4B_T2F} b + * @param {cc.V2F_C4B_T2F} c + * @param {Array} arrayBuffer + * @param {Number} offset + * @constructor + */ cc.V2F_C4B_T2F_Triangle = function (a, b, c, arrayBuffer, offset) { this._arrayBuffer = arrayBuffer || new ArrayBuffer(cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT); this._offset = offset || 0; @@ -501,43 +642,47 @@ _tmp.WebGLColor = function () { this._c = c ? new cc.V2F_C4B_T2F(c.vertices, c.colors, c.texCoords, locArrayBuffer, locOffset + locElementLen * 2) : new cc.V2F_C4B_T2F(null, null, null, locArrayBuffer, locOffset + locElementLen * 2); }; + /** + * @constant + * @type {number} + */ cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT = 60; - Object.defineProperties(cc.V2F_C4B_T2F_Triangle.prototype, { - a: { - get: function () { - return this._a; - }, - set: function (aValue) { - var locA = this._a; - locA.vertices = aValue.vertices; - locA.colors = aValue.colors; - locA.texCoords = aValue.texCoords; - }, - enumerable: true - }, - b: { - get: function () { - return this._b; - }, - set: function (bValue) { - var locB = this._b; - locB.vertices = bValue.vertices; - locB.colors = bValue.colors; - locB.texCoords = bValue.texCoords; - }, - enumerable: true - }, - c: { - get: function () { - return this._c; - }, - set: function (cValue) { - var locC = this._c; - locC.vertices = cValue.vertices; - locC.colors = cValue.colors; - locC.texCoords = cValue.texCoords; - }, - enumerable: true - } - }); -} \ No newline at end of file + _p = cc.V2F_C4B_T2F_Triangle.prototype; + _p._getA = function () { + return this._a; + }; + _p._setA = function (aValue) { + var locA = this._a; + locA.vertices = aValue.vertices; + locA.colors = aValue.colors; + locA.texCoords = aValue.texCoords; + }; + _p._getB = function () { + return this._b; + }; + _p._setB = function (bValue) { + var locB = this._b; + locB.vertices = bValue.vertices; + locB.colors = bValue.colors; + locB.texCoords = bValue.texCoords; + }; + _p._getC = function () { + return this._c; + }; + _p._setC = function (cValue) { + var locC = this._c; + locC.vertices = cValue.vertices; + locC.colors = cValue.colors; + locC.texCoords = cValue.texCoords; + }; + + /** @expose */ + _p.a; + cc.defineGetterSetter(_p, "a", _p._getA, _p._setA); + /** @expose */ + _p.b; + cc.defineGetterSetter(_p, "b", _p._getB, _p._setB); + /** @expose */ + _p.c; + cc.defineGetterSetter(_p, "c", _p._getC, _p._setC); +}; \ No newline at end of file diff --git a/cocos2d/core/platform/CCVisibleRect.js b/cocos2d/core/platform/CCVisibleRect.js index 98b818f2a2..c6545e9f72 100644 --- a/cocos2d/core/platform/CCVisibleRect.js +++ b/cocos2d/core/platform/CCVisibleRect.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -26,104 +25,76 @@ ****************************************************************************/ /** + * cc.visibleRect is a singleton object which defines the actual visible rect of the current view, + * it should represent the same rect as cc.view.getViewportRect() * - * @type Object + * @property {cc.Point} topLeft - Top left coordinate of the screen related to the game scene + * @property {cc.Point} topRight - Top right coordinate of the screen related to the game scene + * @property {cc.Point} top - Top center coordinate of the screen related to the game scene + * @property {cc.Point} bottomLeft - Bottom left coordinate of the screen related to the game scene + * @property {cc.Point} bottomRight - Bottom right coordinate of the screen related to the game scene + * @property {cc.Point} bottom - Bottom center coordinate of the screen related to the game scene + * @property {cc.Point} center - Center coordinate of the screen related to the game scene + * @property {cc.Point} left - Left center coordinate of the screen related to the game scene + * @property {cc.Point} right - Right center coordinate of the screen related to the game scene + * @property {Number} width - Width of the screen + * @property {Number} height - Height of the screen + * + * @class + * @name cc.visibleRect */ cc.visibleRect = { - _topLeft:cc.p(0,0), - _topRight:cc.p(0,0), - _top:cc.p(0,0), - _bottomLeft:cc.p(0,0), - _bottomRight:cc.p(0,0), - _bottom:cc.p(0,0), - _center:cc.p(0,0), - _left:cc.p(0,0), - _right:cc.p(0,0), - _width:0, - _height:0, - init:function(size){ - this._width = size.width; - this._height = size.height; + topLeft:cc.p(0,0), + topRight:cc.p(0,0), + top:cc.p(0,0), + bottomLeft:cc.p(0,0), + bottomRight:cc.p(0,0), + bottom:cc.p(0,0), + center:cc.p(0,0), + left:cc.p(0,0), + right:cc.p(0,0), + width:0, + height:0, + + /** + * initialize + * @param {cc.Rect} visibleRect + */ + init:function(visibleRect){ - var w = this._width; - var h = this._height; + var w = this.width = visibleRect.width; + var h = this.height = visibleRect.height; + var l = visibleRect.x, + b = visibleRect.y, + t = b + h, + r = l + w; //top - this._topLeft.y = h; - this._topRight.x = w; - this._topRight.y = h; - this._top.x = w/2; - this._top.y = h; + this.topLeft.x = l; + this.topLeft.y = t; + this.topRight.x = r; + this.topRight.y = t; + this.top.x = l + w/2; + this.top.y = t; //bottom - this._bottomRight.x = w; - this._bottom.x = w/2; + this.bottomLeft.x = l; + this.bottomLeft.y = b; + this.bottomRight.x = r; + this.bottomRight.y = b; + this.bottom.x = l + w/2; + this.bottom.y = b; //center - this._center.x = w/2; - this._center.y = h/2; + this.center.x = l + w/2; + this.center.y = b + h/2; //left - this._left.y = h/2; + this.left.x = l; + this.left.y = b + h/2; //right - this._right.x = w; - this._right.y = h/2; + this.right.x = r; + this.right.y = b + h/2; } -}; - -/** @expose */ -cc.visibleRect.width; -cc.defineGetterSetter(cc.visibleRect, "width", function(){ - return this._width; -}); -/** @expose */ -cc.visibleRect.height; -cc.defineGetterSetter(cc.visibleRect, "height", function(){ - return this._height; -}); -/** @expose */ -cc.visibleRect.topLeft; -cc.defineGetterSetter(cc.visibleRect, "topLeft", function(){ - return this._topLeft; -}); -/** @expose */ -cc.visibleRect.topRight; -cc.defineGetterSetter(cc.visibleRect, "topRight", function(){ - return this._topRight; -}); -/** @expose */ -cc.visibleRect.top; -cc.defineGetterSetter(cc.visibleRect, "top", function(){ - return this._top; -}); -/** @expose */ -cc.visibleRect.bottomLeft; -cc.defineGetterSetter(cc.visibleRect, "bottomLeft", function(){ - return this._bottomLeft; -}); -/** @expose */ -cc.visibleRect.bottomRight; -cc.defineGetterSetter(cc.visibleRect, "bottomRight", function(){ - return this._bottomRight; -}); -/** @expose */ -cc.visibleRect.bottom; -cc.defineGetterSetter(cc.visibleRect, "bottom", function(){ - return this._bottom; -}); -/** @expose */ -cc.visibleRect.center; -cc.defineGetterSetter(cc.visibleRect, "center", function(){ - return this._center; -}); -/** @expose */ -cc.visibleRect.left; -cc.defineGetterSetter(cc.visibleRect, "left", function(){ - return this._left; -}); -/** @expose */ -cc.visibleRect.right; -cc.defineGetterSetter(cc.visibleRect, "right", function(){ - return this._right; -}); \ No newline at end of file +}; \ No newline at end of file diff --git a/cocos2d/core/platform/miniFramework.js b/cocos2d/core/platform/miniFramework.js index 10e9397378..048a2db325 100644 --- a/cocos2d/core/platform/miniFramework.js +++ b/cocos2d/core/platform/miniFramework.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -28,12 +28,12 @@ * the dollar sign, classic like jquery, this selector add extra methods to HTMLElement without touching its prototype
* it is also chainable like jquery * @param {HTMLElement|String} x pass in a css selector in string or the whole HTMLElement - * @class + * @function * @return {cc.$} */ cc.$ = function (x) { /** @lends cc.$# */ - var parent = (this == cc) ? document : this; + var parent = (this === cc) ? document : this; var el = (x instanceof HTMLElement) ? x : parent.querySelector(x); diff --git a/cocos2d/core/renderer/RendererCanvas.js b/cocos2d/core/renderer/RendererCanvas.js new file mode 100644 index 0000000000..855207715b --- /dev/null +++ b/cocos2d/core/renderer/RendererCanvas.js @@ -0,0 +1,274 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//if (cc._renderType === cc._RENDER_TYPE_CANVAS) { +cc.rendererCanvas = { + childrenOrderDirty: true, + _transformNodePool: [], //save nodes transform dirty + _renderCmds: [], //save renderer commands + + _isCacheToCanvasOn: false, //a switch that whether cache the rendererCmd to cacheToCanvasCmds + _cacheToCanvasCmds: {}, // an array saves the renderer commands need for cache to other canvas + _cacheInstanceIds: [], + _currentID: 0, + + getRenderCmd: function (renderableObject) { + //TODO Add renderCmd pool here + return renderableObject._createRenderCmd(); + }, + + /** + * drawing all renderer command to context (default is cc._renderContext) + * @param {cc.CanvasContextWrapper} [ctx=cc._renderContext] + */ + rendering: function (ctx) { + var locCmds = this._renderCmds, i, len, + scaleX = cc.view.getScaleX(), + scaleY = cc.view.getScaleY(); + var context = ctx || cc._renderContext; + context.computeRealOffsetY(); + for (i = 0, len = locCmds.length; i < len; i++) { + locCmds[i].rendering(context, scaleX, scaleY); + } + }, + + /** + * drawing all renderer command to cache canvas' context + * @param {cc.CanvasContextWrapper} ctx + * @param {Number} [instanceID] + * @param {Number} [scaleX] + * @param {Number} [scaleY] + */ + _renderingToCacheCanvas: function (ctx, instanceID, scaleX, scaleY) { + if (!ctx) + cc.log("The context of RenderTexture is invalid."); + scaleX = cc.isUndefined(scaleX) ? 1 : scaleX; + scaleY = cc.isUndefined(scaleY) ? 1 : scaleY; + instanceID = instanceID || this._currentID; + var locCmds = this._cacheToCanvasCmds[instanceID], i, len; + ctx.computeRealOffsetY(); + for (i = 0, len = locCmds.length; i < len; i++) { + locCmds[i].rendering(ctx, scaleX, scaleY); + } + locCmds.length = 0; + var locIDs = this._cacheInstanceIds; + delete this._cacheToCanvasCmds[instanceID]; + cc.arrayRemoveObject(locIDs, instanceID); + + if (locIDs.length === 0) + this._isCacheToCanvasOn = false; + else + this._currentID = locIDs[locIDs.length - 1]; + }, + + _turnToCacheMode: function (renderTextureID) { + this._isCacheToCanvasOn = true; + renderTextureID = renderTextureID || 0; + this._cacheToCanvasCmds[renderTextureID] = []; + if(this._cacheInstanceIds.indexOf(renderTextureID) === -1) + this._cacheInstanceIds.push(renderTextureID); + this._currentID = renderTextureID; + }, + + _turnToNormalMode: function () { + this._isCacheToCanvasOn = false; + }, + + resetFlag: function () { + this.childrenOrderDirty = false; + this._transformNodePool.length = 0; + }, + + transform: function () { + var locPool = this._transformNodePool; + //sort the pool + locPool.sort(this._sortNodeByLevelAsc); + + //transform node + for (var i = 0, len = locPool.length; i < len; i++) { + if (locPool[i]._dirtyFlag !== 0) + locPool[i].updateStatus(); + } + locPool.length = 0; + }, + + transformDirty: function () { + return this._transformNodePool.length > 0; + }, + + _sortNodeByLevelAsc: function (n1, n2) { + return n1._curLevel - n2._curLevel; + }, + + pushDirtyNode: function (node) { + this._transformNodePool.push(node); + }, + + clearRenderCommands: function () { + this._renderCmds.length = 0; + }, + + pushRenderCommand: function (cmd) { + if(!cmd._needDraw) + return; + if (this._isCacheToCanvasOn) { + var currentId = this._currentID, locCmdBuffer = this._cacheToCanvasCmds; + var cmdList = locCmdBuffer[currentId]; + if (cmdList.indexOf(cmd) === -1) + cmdList.push(cmd); + } else { + if (this._renderCmds.indexOf(cmd) === -1) + this._renderCmds.push(cmd); + } + } +}; + +if (cc._renderType === cc._RENDER_TYPE_CANVAS) + cc.renderer = cc.rendererCanvas; + +(function () { + cc.CanvasContextWrapper = function (context) { + this._context = context; + + this._saveCount = 0; + this._currentAlpha = context.globalAlpha; + this._currentCompositeOperation = context.globalCompositeOperation; + this._currentFillStyle = context.fillStyle; + this._currentStrokeStyle = context.strokeStyle; + + this._offsetX = 0; + this._offsetY = 0; + this._realOffsetY = this.height; + this._armatureMode = 0; + }; + + var proto = cc.CanvasContextWrapper.prototype; + + proto.resetCache = function(){ + var context = this._context; + //call it after resize cc._canvas, because context will reset. + this._currentAlpha = context.globalAlpha; + this._currentCompositeOperation = context.globalCompositeOperation; + this._currentFillStyle = context.fillStyle; + this._currentStrokeStyle = context.strokeStyle; + this._realOffsetY = this._context.canvas.height + this._offsetY; + }; + + proto.setOffset = function(x, y){ + this._offsetX = x; + this._offsetY = y; + this._realOffsetY = this._context.canvas.height + this._offsetY; + }; + + proto.computeRealOffsetY = function(){ + this._realOffsetY = this._context.canvas.height + this._offsetY; + }; + + proto.setViewScale = function(scaleX, scaleY){ + //call it at cc.renderCanvas.rendering + this._scaleX = scaleX; + this._scaleY = scaleY; + }; + + proto.getContext = function(){ + return this._context; + }; + + proto.save = function () { + this._context.save(); + this._saveCount++; + }; + + proto.restore = function () { + this._context.restore(); + this._saveCount--; + }; + + proto.setGlobalAlpha = function (alpha) { + if (this._saveCount > 0) { + this._context.globalAlpha = alpha; + } else { + if (this._currentAlpha !== alpha) { + this._currentAlpha = alpha; + this._context.globalAlpha = alpha; + } + } + }; + + proto.setCompositeOperation = function(compositionOperation){ + if (this._saveCount > 0) { + this._context.globalCompositeOperation = compositionOperation; + } else { + if (this._currentCompositeOperation !== compositionOperation) { + this._currentCompositeOperation = compositionOperation; + this._context.globalCompositeOperation = compositionOperation; + } + } + }; + + proto.setFillStyle = function(fillStyle){ + if (this._saveCount > 0) { + this._context.fillStyle = fillStyle; + } else { + if (this._currentFillStyle !== fillStyle) { + this._currentFillStyle = fillStyle; + this._context.fillStyle = fillStyle; + } + } + }; + + proto.setStrokeStyle = function(strokeStyle){ + if (this._saveCount > 0) { + this._context.strokeStyle = strokeStyle; + } else { + if (this._currentStrokeStyle !== strokeStyle) { + this._currentStrokeStyle = strokeStyle; + this._context.strokeStyle = strokeStyle; + } + } + }; + + proto.setTransform = function(t, scaleX, scaleY){ + if (this._armatureMode > 0) { + //ugly for armature + this.restore(); + this.save(); + this._context.transform(t.a, -t.b, -t.c, t.d, t.tx * scaleX, -(t.ty * scaleY)); + } else { + this._context.setTransform(t.a, -t.b, -t.c, t.d, this._offsetX + t.tx * scaleX, this._realOffsetY - (t.ty * scaleY)); + } + }; + + proto._switchToArmatureMode = function(enable, t, scaleX, scaleY){ + if(enable){ + this._armatureMode++; + this._context.setTransform(t.a, t.c, t.b, t.d, this._offsetX + t.tx * scaleX, this._realOffsetY - (t.ty * scaleY)); + this.save(); + }else{ + this._armatureMode--; + this.restore(); + } + }; +})(); + diff --git a/cocos2d/core/renderer/RendererWebGL.js b/cocos2d/core/renderer/RendererWebGL.js new file mode 100644 index 0000000000..e9c9284857 --- /dev/null +++ b/cocos2d/core/renderer/RendererWebGL.js @@ -0,0 +1,137 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +cc.rendererWebGL = { + childrenOrderDirty: true, + _transformNodePool: [], //save nodes transform dirty + _renderCmds: [], //save renderer commands + + _isCacheToBufferOn: false, //a switch that whether cache the rendererCmd to cacheToCanvasCmds + _cacheToBufferCmds: {}, // an array saves the renderer commands need for cache to other canvas + _cacheInstanceIds: [], + _currentID: 0, + + getRenderCmd: function (renderableObject) { + //TODO Add renderCmd pool here + return renderableObject._createRenderCmd(); + }, + + /** + * drawing all renderer command to context (default is cc._renderContext) + * @param {WebGLRenderingContext} [ctx=cc._renderContext] + */ + rendering: function (ctx) { + var locCmds = this._renderCmds, + i, + len; + var context = ctx || cc._renderContext; + for (i = 0, len = locCmds.length; i < len; i++) { + locCmds[i].rendering(context); + } + }, + + _turnToCacheMode: function (renderTextureID) { + this._isCacheToBufferOn = true; + renderTextureID = renderTextureID || 0; + this._cacheToBufferCmds[renderTextureID] = []; + this._cacheInstanceIds.push(renderTextureID); + this._currentID = renderTextureID; + }, + + _turnToNormalMode: function () { + this._isCacheToBufferOn = false; + }, + + /** + * drawing all renderer command to cache canvas' context + * @param {Number} [renderTextureId] + */ + _renderingToBuffer: function (renderTextureId) { + renderTextureId = renderTextureId || this._currentID; + var locCmds = this._cacheToBufferCmds[renderTextureId], i, len; + var ctx = cc._renderContext, locIDs = this._cacheInstanceIds; + for (i = 0, len = locCmds.length; i < len; i++) { + locCmds[i].rendering(ctx); + } + locCmds.length = 0; + delete this._cacheToBufferCmds[renderTextureId]; + cc.arrayRemoveObject(locIDs, renderTextureId); + + if (locIDs.length === 0) + this._isCacheToBufferOn = false; + else + this._currentID = locIDs[locIDs.length - 1]; + }, + + //reset renderer's flag + resetFlag: function () { + this.childrenOrderDirty = false; + this._transformNodePool.length = 0; + }, + + //update the transform data + transform: function () { + var locPool = this._transformNodePool; + //sort the pool + locPool.sort(this._sortNodeByLevelAsc); + //transform node + for (var i = 0, len = locPool.length; i < len; i++) { + locPool[i].updateStatus(); + } + locPool.length = 0; + }, + + transformDirty: function () { + return this._transformNodePool.length > 0; + }, + + _sortNodeByLevelAsc: function (n1, n2) { + return n1._curLevel - n2._curLevel; + }, + + pushDirtyNode: function (node) { + //if (this._transformNodePool.indexOf(node) === -1) + this._transformNodePool.push(node); + }, + + clearRenderCommands: function () { + this._renderCmds.length = 0; + }, + + pushRenderCommand: function (cmd) { + if(!cmd._needDraw) + return; + if (this._isCacheToBufferOn) { + var currentId = this._currentID, locCmdBuffer = this._cacheToBufferCmds; + var cmdList = locCmdBuffer[currentId]; + if (cmdList.indexOf(cmd) === -1) + cmdList.push(cmd); + } else { + if (this._renderCmds.indexOf(cmd) === -1) + this._renderCmds.push(cmd); + } + } +}; +if (cc._renderType === cc._RENDER_TYPE_WEBGL) + cc.renderer = cc.rendererWebGL; diff --git a/cocos2d/core/scenes/CCLoaderScene.js b/cocos2d/core/scenes/CCLoaderScene.js index cdd596a123..562b71ff30 100644 --- a/cocos2d/core/scenes/CCLoaderScene.js +++ b/cocos2d/core/scenes/CCLoaderScene.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,26 +22,33 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ - +/** + *

cc.LoaderScene is a scene that you can load it when you loading files

+ *

cc.LoaderScene can present thedownload progress

+ * @class + * @extends cc.Scene + * @example + * var lc = new cc.LoaderScene(); + */ cc.LoaderScene = cc.Scene.extend({ _interval : null, - _length : 0, - _count : 0, _label : null, _className:"LoaderScene", + cb: null, + target: null, + /** + * Contructor of cc.LoaderScene + * @returns {boolean} + */ init : function(){ var self = this; - var winSize = cc.director.getWinSize(); - //logo var logoWidth = 160; var logoHeight = 200; - var centerPos = cc.p(winSize.width / 2, winSize.height / 2); // bg - var bgLayer = self._bgLayer = cc.LayerColor.create(cc.color(32, 32, 32, 255)); - bgLayer.setPosition(0, 0); + var bgLayer = self._bgLayer = new cc.LayerColor(cc.color(32, 32, 32, 255)); self.addChild(bgLayer, 0); //image move to CCSceneFile.js @@ -52,14 +58,14 @@ cc.LoaderScene = cc.Scene.extend({ cc.loader.loadImg(cc._loaderImage, {isCrossOrigin : false }, function(err, img){ logoWidth = img.width; logoHeight = img.height; - self._initStage(img, centerPos); + self._initStage(img, cc.visibleRect.center); }); fontSize = 14; lblHeight = -logoHeight / 2 - 10; } //loading percent - var label = self._label = cc.LabelTTF.create("Loading... 0%", "Arial", fontSize); - label.setPosition(cc.pAdd(centerPos, cc.p(0, lblHeight))); + var label = self._label = new cc.LabelTTF("Loading... 0%", "Arial", fontSize); + label.setPosition(cc.pAdd(cc.visibleRect.center, cc.p(0, lblHeight))); label.setColor(cc.color(180, 180, 180)); bgLayer.addChild(this._label, 10); return true; @@ -70,19 +76,23 @@ cc.LoaderScene = cc.Scene.extend({ var texture2d = self._texture2d = new cc.Texture2D(); texture2d.initWithElement(img); texture2d.handleLoadedTexture(); - var logo = self._logo = cc.Sprite.create(texture2d); + var logo = self._logo = new cc.Sprite(texture2d); logo.setScale(cc.contentScaleFactor()); logo.x = centerPos.x; logo.y = centerPos.y; self._bgLayer.addChild(logo, 10); }, - + /** + * custom onEnter + */ onEnter: function () { var self = this; cc.Node.prototype.onEnter.call(self); self.schedule(self._startLoading, 0.3); }, - + /** + * custom onExit + */ onExit: function () { cc.Node.prototype.onExit.call(this); var tmpStr = "Loading... 0%"; @@ -93,41 +103,51 @@ cc.LoaderScene = cc.Scene.extend({ * init with resources * @param {Array} resources * @param {Function|String} cb + * @param {Object} target */ - initWithResources: function (resources, cb) { - if(typeof resources == "string") resources = [resources]; + initWithResources: function (resources, cb, target) { + if(cc.isString(resources)) + resources = [resources]; this.resources = resources || []; this.cb = cb; + this.target = target; }, _startLoading: function () { var self = this; self.unschedule(self._startLoading); var res = self.resources; - self._length = res.length; - cc.loader.load(res, function(result, count){ self._count = count; }, function(){ - self.cb(); - }); - self.schedule(self._updatePercent); - }, - - _updatePercent: function () { - var self = this; - var count = self._count; - var length = self._length; - var percent = (count / length * 100) | 0; - percent = Math.min(percent, 100); - self._label.setString("Loading... " + percent + "%"); - if(count >= length) self.unschedule(self._updatePercent); + cc.loader.load(res, + function (result, count, loadedCount) { + var percent = (loadedCount / count * 100) | 0; + percent = Math.min(percent, 100); + self._label.setString("Loading... " + percent + "%"); + }, function () { + if (self.cb) + self.cb.call(self.target); + }); } }); -cc.LoaderScene.preload = function(resources, cb){ +/** + *

cc.LoaderScene.preload can present a loaderScene with download progress.

+ *

when all the resource are downloaded it will invoke call function

+ * @param resources + * @param cb + * @param target + * @returns {cc.LoaderScene|*} + * @example + * //Example + * cc.LoaderScene.preload(g_resources, function () { + cc.director.runScene(new HelloWorldScene()); + }, this); + */ +cc.LoaderScene.preload = function(resources, cb, target){ var _cc = cc; if(!_cc.loaderScene) { _cc.loaderScene = new cc.LoaderScene(); _cc.loaderScene.init(); } - _cc.loaderScene.initWithResources(resources, cb); + _cc.loaderScene.initWithResources(resources, cb, target); cc.director.runScene(_cc.loaderScene); return _cc.loaderScene; diff --git a/cocos2d/core/scenes/CCScene.js b/cocos2d/core/scenes/CCScene.js index af8bd9f754..a54a179dcd 100644 --- a/cocos2d/core/scenes/CCScene.js +++ b/cocos2d/core/scenes/CCScene.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -36,10 +36,12 @@ *

It is a good practice to use and cc.Scene as the parent of all your nodes.

* @class * @extends cc.Node + * @example + * var scene = new cc.Scene(); */ cc.Scene = cc.Node.extend(/** @lends cc.Scene# */{ /** - * Constructor + * Constructor of cc.Scene */ _className:"Scene", ctor:function () { @@ -52,12 +54,8 @@ cc.Scene = cc.Node.extend(/** @lends cc.Scene# */{ /** * creates a scene + * @deprecated since v3.0,please use new cc.Scene() instead. * @return {cc.Scene} - * @example - * // Example - * var aScene = cc.Scene.create(); - * //OR - * var aScene = new cc.Scene(); */ cc.Scene.create = function () { return new cc.Scene(); diff --git a/cocos2d/core/scenes/CCSceneFile.js b/cocos2d/core/scenes/CCSceneFile.js deleted file mode 100644 index f0a881e45e..0000000000 --- a/cocos2d/core/scenes/CCSceneFile.js +++ /dev/null @@ -1,27 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -cc._loaderImage = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAlAAD/4QMpaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MCA2MS4xMzQ3NzcsIDIwMTAvMDIvMTItMTc6MzI6MDAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjM4MDBEMDY2QTU1MjExRTFBQTAzQjEzMUNFNzMxRkQwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjM4MDBEMDY1QTU1MjExRTFBQTAzQjEzMUNFNzMxRkQwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU2RTk0OEM4OERCNDExRTE5NEUyRkE3M0M3QkE1NTlEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU2RTk0OEM5OERCNDExRTE5NEUyRkE3M0M3QkE1NTlEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQADQkJCQoJDQoKDRMMCwwTFhENDREWGhUVFhUVGhkUFhUVFhQZGR0fIB8dGScnKionJzk4ODg5QEBAQEBAQEBAQAEODAwOEA4RDw8RFA4RDhQVERISERUfFRUXFRUfKB0ZGRkZHSgjJiAgICYjLCwoKCwsNzc1NzdAQEBAQEBAQEBA/8AAEQgAyACgAwEiAAIRAQMRAf/EALAAAAEFAQEAAAAAAAAAAAAAAAQAAgMFBgcBAQEAAwEBAAAAAAAAAAAAAAAAAQMEAgUQAAIBAgIEBwoLBgQGAwAAAAECAwAEEQUhMRIGQVFxsTITFGGBwdEiQlKSMzWRoeFicqKyI1NzFYJjJDQWB9KjVCbxwkNkJWXik3QRAAIBAgMFBQcDBQEAAAAAAAABAhEDIRIEMUFRcTJhwVIUBZGhsSJyEzOB0ULhYpIjUxX/2gAMAwEAAhEDEQA/AMJSpUqAVKlXuFAeUq9wpUB5XuFe4V6ooDzZHDox0CnGMinzwl7Z8NajaHeoO3vmTBZBtp9YUIqTEV5ROxHKnWRnaU8VRMhFBUjpV7hSoSeUq9pUB5Sr2lhQHlKvcK8oBV7hSFSRrtaKAZs07YNPM1pG2xJIAw1jSeandry/8X4m8VCKkWwaWwam7Xl/4v1W8VLtmX/i/VbxUoKkWwakSM407tmX/i/VbxUmzGwjQsjdY41IARie/U0IbZO0kNtCXnOCkEBeFu4KI3Bs7DNb27ya+jDx3kJeEnpJJEcQVbWDsk17u5urd591ucZkWhym2Vnd9RkCDEpFxDRpbw0bunu5mlp2De2FMLYXOD2wB2xbOeraUcYGJ72mlSUiqzzdzMd3Z3mixltA2yzcK/NlHM1DQyRXce1HocdNOEfJXZ88y9ZojOqhiBszIRiHQ8Y4cK5TvHuzLljHNMqxNoDjLFraHHnjPxcNCGVbxEUzYNTx5jZSxhpW6qTzlwJ+DCvO2Zf+L9VvFSgqyHYNLYNTdssPxfibxUu15f8Ai/VPiqCakOwa82DU/a8v/F+JvFTDdWPBL8R8VKCvYRYV5UzoMAy6QdIIqI0B4KJtxiRQwou16QoGUkntH5Tz0RbZbmF2hktraSVBo2lUkY8tDye0flPPXTslVUyiyVRsjqUOA4yMT8dW2ram2m6UVTNq9S7EIyUVJydMTn/6DnP+im9Wl+g5z/opvVrpteEhQWY4AaSTwAVf5WPiZh/9S5/zj7zltzlmYWkfWXNvJDGTgGcYDHirR7i7mSbwXParsFMrgb7w6jKw/wCmnc9I14kF3vpvCljbMyWMOJL4aEiB8qU/ObUK7HYWVrl1pFZWiCOCBQqKOLjPGTrNZZqKbUXVHq2nNwTuJRk1VpbgXN8s7Rk5ym0UQQzhIG2NAjhxHWbI+gCBVjBBFbwxwQqEiiUJGg1BVGAFe7dV28WYLYZFmF2Th1UD7JGjymGyn1iK5OyzIBGB1HgrLZhamzumQAGJwSqnSCh1q3GOCodxt4cxurdcpzuN4cyhiWaF5Bg09udUmnWw1H/jV9nFuJ7Quo+8h8peThFA+047vduyMtk7fYqTl07YFdfUufMPzT5p71UdtlmYXaGS2t3mQHAsgxANdadYJopLe4QS2867EsZ4QfCNYrCFbjdDPmgkYyWFxgVf04ifJf6ScNdRUW1XBb6FU5TjF5EpSSrGu/s5lN+g5z/opvVpfoOc/wCim9WtdHnatvObJXDW7xLGhB8nrPaY9/HCr+tEdPCVaSeDoYLnqF63lzW4/PFSW3ecxbI84VSzWUwUaSdg0DXXK5nvAipnd6qgKvWnQO7pri9ZUEmm3Vl2j1kr8pRlFRyquBNZjGxQ/S56Y1S2fu9OVueon11Szahoou06QoQUXadIVCD2FJJ7R+U89dMydv8Axdn+TH9muZye0flPPXQstlK5Tbka1gUjlC1q0vVLkeb6r+O3Tx9xcY1nt8c0NrZCyiOE1108NYjGv1joo7Js1jzKyScYLIvkzL6LDwHXVJksH9Sb49dKNq0tj1jA6uriOCL+02FWX7iVtZX1/AzaHTyeoauKn2MX9W79zebiZCuR5MjSrhfXuEtwTrUeZH+yNfdrRNcxI6IzhXlJEak6WIGJ2Rw4ChWnChndtlVBLMdQA0k1gbXNMzzDfDLs6mjaPKppJbWwJ1bOwwxw43OnHh71YT3DpfWUJmFlb5jHHDdeXBHIsrRea5TSqvxqG04cNN62vetoCS4tre5mgnkGE9q+3DKOkuI2WX6LDQRRHWDh1UCtwj7QRg2wdl8Djgw1qe7XvW0BQ3kfZ7mSLgU+T9E6RVbnuVrnWVSWqj+Lt8ZbRuHEdKPkYVcZ2MJY5fSGyeVar45+rkWQHAqccalPE5km1htWK5nK4Wnt5FuUBUwOMG4nGkA/BXUrW4S6torlOjMgcd/xVn7rLo7zKs0uEjCNeSvdwoBhgsZxX1l2j36k3Lu+uyprdj5Vs5A+i/lD48a0aaVJOPi7jB6lbzWozpjB48pf1NDXNN4vfl7+Z4BXS65pvF78vfzPAK71XTHmZ/S/yT+jvJ7L3fHytz1E+upbL+Qj5W56jfXWRnsIYKLtekKEFGWvSFQgyjk9o/Keet3YthlMP/5x9msJJ7R+U89biyb/AMXEv7gD6tadL1T+kwepRrC39ZkLDMbiwMvUHRPG0bjlGg8ore/23sxBldxfMPLupNhT8yL/AORNZbdzJ484scytxgLqJY5LZj6Q2sV5G1Vud1mjjyG0ij0NEGSZToKyhjtqw4waztuiXA3qKTbSxltfGhbZlE95ZtZqxVbgiOZhrER9ph3Svk9+pJILZ4Y4DGBFCUMKjRsGPobPFhUfW0NJmljE2xJcIrcI2vFUEln1lRXd6lrazXT9GCNpD+yNqoI7mOVduNw6nzlOIoPOUa6yye1XXcbMR5GdQ3xY0BSbj31/FcTQZirJ+q431q7anbHCTZ72Bw7lbPrKBMcBWNNgbMBBh+bsjBdni0VJ1lARZs6yWiupxCuMDy6KpS2IwOo6DTr3Mre3e5tZZVUM4ZBjqOOJoWO4jkXajcOOMHGgDISvWIrdAkKR80+TzVl908bPPL3LzxOuHdifxVfiTAg92qI/w+/8gGgSyN/mR7XPVlp0lF/3L3mbVKtu5Hjbk/8AHE2Fc03i9+Xv5ngFdKNc13i9+Xv5ngFaNV0x5nn+l/kn9HeEWXu+PlbnqJ9dS2Xu9OVueon11kZ7CGCjLXpCgxRlr0hUIPYUcntH5Tz1s8vb+Bt1/dqPirGSe0flPPWusG/g4Py15q06XqlyMWvVYQ+ruI9xJOqzO9hOto/sP8tbGOFIrmWeM7IuMDMnAXXQJOUjQeOsJk0nY96ip0CYunrjaHx1t+srPJUbXBm2LrFPikwTOb+T+VhbZxGMrDXp83x1QSy2tucJpUjPETp+Cn5/ftaRvKvtp3Kx48HG3erHMzOxZiWZtLMdJNQSbbL71Vk6yynViOkqnEEfOWtPbXi3EQkGg6mXiNckjeSJxJGxR10qw0GtxuxmvbImD4CZMFlA4fRfv0BqesqqzTMZNMEDbIHtHH2QeCiZJSqMQdOGiue53mz3czQwsRbIcNHnkec3c4qAMuriz68gTIToxwOOnlp0MjxMJYW741Gs3RVldtbygE/dMcHX/moDaxTiWNZB53B3arb8/wC+4SOF4sf/AKxU9kcBsfOGHfoUHtG/RbzY5Die5HHhXdvavqiZ9Q8Jdlq4/gbKua7xe/L38zwCuhpf2Uk/Zo50kmwJKIdogDjw1VzzeL35e/meAVp1LTgqY4nn+mRauzqmqwrjzCLL3fHytz1E+upLL+Qj5W56jfXWRnroYKLtekKEFF2vSFQg9hSSe0flPPWosm/hIfoLzVl5PaPynnrRWb/w0X0F5q06XqlyM2sVYx5gmbFre/t71NY2T+0h8VbSO5SWNJUOKSAMp7jDGspmMPaLRlXS6eWve1/FRO7WYdbZm1Y/eW/R7qHxHRXGojlm3ulid6aVbaW+OALvgCLq2Hm9WxHKWqjhj6xsK1e8dm15l4niG1LZkswGsxtrPeOmsvayBJA1VItlWjptLuTdPMo7LtjRDq9naK4+WF9IrUW7BaHOljGqVHB7w2hzVoZt87d8vaNYSLl02CcRsDEbJbj71Uu7UBkvJ7/D7q2QoDxySaAO8MTXdxRVMpRp5XZOWdF/ms7R5XdyKfKWJsO/5PhrG5XlNxmEywW6bTnTxAAcJNbGSMXkM1pjgbiNo1PziPJ+Os7u7m/6ReM00ZOgxSpqYYHT3wRXMKN4ll9zUG4bQfNshu8sZVuEA2hirA4qe/VOwwrVbzbww5mI44UKRRYkbWG0S3JWctbd7u5WFfOOLHiUdJqmaipfLsIsObhWe001lMkMVvJNjhghIALMcBxCs7fxXQmkupx1bXDswGPlaTidVaEyKNXkoo4eBV+Sq7L7Vs9zcBgeyQ4GQ/MB1crmoim2orezqcowTuSeEY48jQ7oZX2PLzdyLhNd6RjrEY6I7+uspvH78vfzPAK6UAAAFGAGgAcArmu8Xvy9/M8ArTfio24RW5nnaG67uou3H/KPuqT2X8hHytz1G+upLL3enK3PUb66ys9RDBRdr0hQgou06QqEGUkntH5Tz1e238vF9BeaqKT2j8p56vbb+Xi+gvNWjTdUuRn1XTHmTh8KrJTJlt8t1CPIY44cGnpJVjTJYkmjaN9Ib4u7V923njTethRauZJV3PaW1rfLIiXEDYg6R4VYc9CXW7thfOZbKdbGZtLW8uPVY/u3GrkNUkM9zlcxUjbhfWOA90cRq4gv4LhdqN+VToNYWmnRm9NNVWNTyHc6VWBv8wt4YeHqm6xyPmroq1Z7WGFLSxTq7WLSuPSdjrkfumq5yHXDUeA92oO2SKpVumNAaoJLMXH3myp0rpJ4uKhc3tbDM5BMri1zAj79j7KTiY8TcdBpcsith0286o+sPCagEX9Pzg4zXUCp6QYse8oouCG3tk6m1BYv05W6T+IdyolxbHDAAa2OgDlNCz3ryN2WxBd5PJMg1t81eId2ukqnLlTBbfcuY+9uJLiRcvtPvHdsHK+cfRHcHDWsyawjyy0WBcDI3lTP6TeIcFV+S5OmXx9bJg1048o8Cj0V8Jq2DVu09nL80up7OxHi+oal3P8AXB/IsZS8T/YOV65zvCcc7vfzPAK3ivWCz445zeH954BXOr6I8yfSfyz+jvCLP3fHytz1G+upLP3fHytz1E+usbPaQ0UXadIUIKLtekKhB7Ckk9o/Keer22/l4/oLzVRSe0flPPV7b/y8X0F5q0abqlyM+q6Y8yQsBTDMor1o8aiaE1pbluMqS3sbLLHIhSRQyngqukhaJ9uBjo+H5aOa3ao2t34qouRlLajTalGP8v0IY8ylXQ+PKPFU/bYXOLPge6CKia0LaxTOxHu1Q7cuBd9yPEJ7TbjXKO8CajbMIF6CNIeNvJHjqIWJ7tSpYkalqVblwIdyG+RGXur0hXYJFxal+Dhq5y3slkv3Y2pD0pTr+QUClpJRUdo9XW4OLrTHtM16cZLLWkeC7y4jvlNEpcRtw1Ux27Ci448NZrTFy3nn3IQWxlgGrDZ3pza7/M8ArZo+ArF5171uvp+CqdV0R5l/psUrs2vB3hdl7vTlbnqJ9dS2Xu+PlbnqJ9dY2eshooq16QoQUXa9IVCD2FLJ7RuU89WNtmUSQqkgYMgw0accKrpPaPynnrZWG4Vi+VWmY5tnMWXG+XrIYnA0rhj0mdcTgdNdwnKDqjmduM1SRR/qlr8/4KX6pa8T/BVzDuLZXudRZblmbxXcPUNPc3KqCIwrbOzgrHEnHjoyD+3eSXkht7DeKG4umDGOJVUklfouThXfmbnZ7Cvy1vt9pmv1W1+d8FL9VteJvgq5yrcOGfLmzHN80iyyETPbptAEFo2ZG8pmUa1OFNn3Ky6W/sbDKM5hv5bx2WTZA+7RF2y52WOPJTzE+z2Dy1vt9pT/AKpacTerS/U7Tib1a04/t7kDXPY03jhN0W6sQ7K7W3q2dnrMccaDy/8At80kuZfqWYxWNtlcvUPPhiGYhWDeUy7IwYU8xPs9g8tb7faUn6pacTerTxm9oOBvVq3v9z927aynuId44LiWKNnjhAXF2UYhRg516qpsryjLr21665zFLSTaK9U2GOA87SwqY37knRU+BzOzags0s1Oyr+BKM6sxwP6tSDPLMen6vy0rvdm3Sxlu7K/S7WDDrFUDUTxgnTU826eXW7KlxmqQuwDBXUKcD+1Xee/wXuKX5XDGWLapSVcOyhEM/seJ/V+WnjeGx4pPV+Wkm6kKZlFay3Jlt7iFpYZY8ASVK6DjtDDA0f8A0Tl340/1f8Ndx8xJVWXB0KbktFFpNzdVXAC/qOwA0CQni2flrO3Vwbm5lnI2TKxbDirX/wBE5d+NcfV/wVR7xZPa5U9utvI8nWhmbbw0YEAYYAVxfhfy5rlKR4Fulu6X7mW1mzT8S4Yis/5CPlbnqJ9dSWfu9OVueon11mZvQ2i7XpChKKtekKhBlNJ7R+U89bDfGTb3a3ZX0Lcj6kdY+T2j8p560288m1kWQr6MJ+ylSAr+2cnV5renjs3H1loX+3j9XvbbtxLN9lqW4UnV5jdnjtXHxihtyZNjeSBu5J9k1BJe7xy7W5CJ/wCzuD/mTVTf2+fq97LJuLrPsNRueS7W6aJ/38x+vLVXuY+xvHaNxbf2GoCezf8A36j/APsSf8w1sLnqczTefJluYoLm5uo5F61sBshItP1cNFYe1f8A3ir/APfE/wCZUe9bB94r5jwuPsrQFhmG4l/Z2M17HdW90tuu3IkTHaCjWdIw0VVZdks9/C06yJFEp2dp+E1bbqybGTZ8vpQD7L1XRv8A7blT96Oda7tpNuuNE37Cq9KSisjyuUoxrStKllHbLlWTXsMs8chuSuwEPDqwoLe5y+YRE/gLzmqRekvKKtd4327yM/ulHxmrHJStySWVRyrjxKI2XC/CTlnlPPKTpTdFbP0L1bgrf5Lp0G3dPhQHwV0S1lzBsns3sESR8Crh9WAJGjSOKuU3E+zdZQ3oJh8IArdZXFDmOTpHa3i2+YrI2KtKy4ricBsBuHHgFXSo440+Wa2qqxjvM9uMoy+WvzWpLCWWWE28HxL6e43ojgkeSCBY1Ri5BGIUDT51cl3vm276BBqSEH4WbxV0tlkyXJcxTMb+OW6uY9mGHrCzDQwwAbTp2uKuTZ9N1uYsfRRR8WPhrm419mSSjRyiqxVK7y23B/ftuTm2oSdJyzNVw3BFn7vTlbnqF9dS2fu9OVueon11lZuQ2iLdsGFD05H2dNQGV0ntG5Tz1dWm9N1b2kVq8EVwsI2UaQaQOKhmitZGLOmk68DhSFvY+gfWNSAg7z3Qvo7yKCKIohiaNR5LKxx8qpxvjcqS0VpbxvwOAcRQPZ7D0G9Y0uz2HoH1jUCpLY7zXlpbm3eKO5QuzjrBqZji3x17PvNcyT288VvDBJbMWUovS2hslW7mFQ9nsPQPrGl2ew9A+saCod/WNxtbYsrfb17WBxx5ddD2281xC88klvDcSXEnWuzrqOGGC9zRUPZ7D0G9Y0uzWHoH1jQVCLreq6ntZbaO3it1mGy7RjTs1X2mYy20ZiCq8ZOODcdEdmsPQb1jS7PYegfWNdJuLqnQiSUlRqpFLmryxtH1Ma7Qw2gNNPOdSt0oI27p007s9h6B9Y0uz2HoH1jXX3Z+I4+1b8IJdX89xLHKQFMXQUahpxoiPN5P+onfU+A0/s9h6DesaXZ7D0D6xpG7OLbUtu0StW5JJx2bBsmbtiSiEk+cxoCWWSaVpZOk2vDVo0VYdnsPQb1jSNvZcCH1jSd2c+p1XAmFqEOmOPEfaH+BQd1ueo211IzrgFUYKNAAqI1WztCpUqVCRUqVKgFSpUqAVKlSoBUqVKgFSpUqAVKlSoBUqVKgFSpUqAVKlSoD/9k="; diff --git a/cocos2d/core/sprites/CCAnimation.js b/cocos2d/core/sprites/CCAnimation.js index 41ac829eb9..1c653a0bea 100644 --- a/cocos2d/core/sprites/CCAnimation.js +++ b/cocos2d/core/sprites/CCAnimation.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -34,26 +34,44 @@ *

* @class * @extends cc.Class + * @param spriteFrame + * @param delayUnits + * @param userInfo + * @returns {AnimationFrame} */ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ _spriteFrame:null, _delayPerUnit:0, _userInfo:null, - ctor:function () { - this._delayPerUnit = 0; + ctor:function (spriteFrame, delayUnits, userInfo) { + this._spriteFrame = spriteFrame || null; + this._delayPerUnit = delayUnits || 0; + this._userInfo = userInfo || null; }, + /** + * Create a new animation frame and copy all contents into it + * @returns {AnimationFrame} + */ clone: function(){ var frame = new cc.AnimationFrame(); frame.initWithSpriteFrame(this._spriteFrame.clone(), this._delayPerUnit, this._userInfo); return frame; }, + /** + * Create a new animation frame and copy all contents into it + * @returns {AnimationFrame} + */ copyWithZone:function (pZone) { return cc.clone(this); }, + /** + * Create a new animation frame and copy all contents into it + * @returns {AnimationFrame} + */ copy:function (pZone) { var newFrame = new cc.AnimationFrame(); newFrame.initWithSpriteFrame(this._spriteFrame.clone(), this._delayPerUnit, this._userInfo); @@ -75,7 +93,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** - * cc.SpriteFrameName to be used + * Returns sprite frame to be used * @return {cc.SpriteFrame} */ getSpriteFrame:function () { @@ -83,7 +101,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** - * cc.SpriteFrameName to be used + * Sets sprite frame to be used * @param {cc.SpriteFrame} spriteFrame */ setSpriteFrame:function (spriteFrame) { @@ -91,7 +109,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** - * how many units of time the frame takes getter + * Returns how many units of time the frame takes getter * @return {Number} */ getDelayUnits:function () { @@ -99,7 +117,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** - * how many units of time the frame takes setter + * Sets how many units of time the frame takes setter * @param delayUnits */ setDelayUnits:function (delayUnits) { @@ -107,8 +125,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** - *

A cc.AnimationFrameDisplayedNotification notification will be broadcasted when the frame is displayed with this dictionary as UserInfo.
- * If UserInfo is nil, then no notification will be broadcasted.

+ * Returns the user custom information * @return {object} */ getUserInfo:function () { @@ -116,6 +133,7 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ }, /** + * Sets the user custom information * @param {object} userInfo */ setUserInfo:function (userInfo) { @@ -123,28 +141,56 @@ cc.AnimationFrame = cc.Class.extend(/** @lends cc.AnimationFrame# */{ } }); +/** + * Creates an animation frame. + * @deprecated since v3.0, please use the new construction instead + * @param {cc.SpriteFrame} spriteFrame + * @param {Number} delayUnits + * @param {object} userInfo + * @see cc.AnimationFrame + */ +cc.AnimationFrame.create = function(spriteFrame,delayUnits,userInfo){ + return new cc.AnimationFrame(spriteFrame,delayUnits,userInfo); +}; + /** *

* A cc.Animation object is used to perform animations on the cc.Sprite objects.
*
* The cc.Animation object contains cc.SpriteFrame objects, and a possible delay between the frames.
- * You can animate a cc.Animation object by using the cc.Animate action. Example:
+ * You can animate a cc.Animation object by using the cc.Animate action. *

* @class * @extends cc.Class + * @param {Array} frames + * @param {Number} delay + * @param {Number} [loops=1] * * @example - * //create an animation object - * var animation = cc.Animation.create(); + * // 1. Creates an empty animation + * var animation1 = new cc.Animation(); * - * //add a sprite frame to this animation - * animation.addFrameWithFile("grossini_dance_01.png"); + * // 2. Create an animation with sprite frames, delay and loops. + * var spriteFrames = []; + * var frame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); + * spriteFrames.push(frame); + * var animation1 = new cc.Animation(spriteFrames); + * var animation2 = new cc.Animation(spriteFrames, 0.2); + * var animation2 = new cc.Animation(spriteFrames, 0.2, 2); + * + * // 3. Create an animation with animation frames, delay and loops. + * var animationFrames = []; + * var frame = new cc.AnimationFrame(); + * animationFrames.push(frame); + * var animation1 = new cc.Animation(animationFrames); + * var animation2 = new cc.Animation(animationFrames, 0.2); + * var animation3 = new cc.Animation(animationFrames, 0.2, 2); * * //create an animate with this animation - * var action = cc.Animate.create(animation); + * var action = cc.animate(animation1); * * //run animate - * this._grossini.runAction(action); + * sprite.runAction(action); */ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ _frames:null, @@ -154,32 +200,6 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ _delayPerUnit:0, _totalDelayUnits:0, - /** - * Creates an animation. - * @constructor - * @param {Array} frames - * @param {Number} delay - * @param {Number} [loops=1] - * @example - * // 1. Creates an empty animation - * var animation1 = new cc.Animation(); - * - * // 2. Create an animation with sprite frames, delay and loops. - * var spriteFrames = []; - * var frame = cache.getSpriteFrame("grossini_dance_01.png"); - * spriteFrames.push(frame); - * var animation1 = new cc.Animation(spriteFrames); - * var animation2 = new cc.Animation(spriteFrames, 0.2); - * var animation2 = new cc.Animation(spriteFrames, 0.2, 2); - * - * // 3. Create an animation with animation frames, delay and loops. - * var animationFrames = []; - * var frame = new cc.AnimationFrame(); - * animationFrames.push(frame); - * var animation1 = new cc.Animation(animationFrames); - * var animation2 = new cc.Animation(animationFrames, 0.2); - * var animation3 = new cc.Animation(animationFrames, 0.2, 2); - */ ctor:function (frames, delay, loops) { this._frames = []; @@ -202,7 +222,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ // attributes /** - * return array of CCAnimationFrames + * Returns the array of animation frames * @return {Array} */ getFrames:function () { @@ -210,7 +230,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * array of CCAnimationFrames setter + * Sets array of animation frames * @param {Array} frames */ setFrames:function (frames) { @@ -218,7 +238,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * adds a frame to a cc.Animation The frame will be added with one "delay unit". + * Adds a frame to a cc.Animation, the frame will be added with one "delay unit". * @param {cc.SpriteFrame} frame */ addSpriteFrame:function (frame) { @@ -239,7 +259,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ var rect = cc.rect(0, 0, 0, 0); rect.width = texture.width; rect.height = texture.height; - var frame = cc.SpriteFrame.create(texture, rect); + var frame = new cc.SpriteFrame(texture, rect); this.addSpriteFrame(frame); }, @@ -249,12 +269,12 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ * @param {cc.Rect} rect */ addSpriteFrameWithTexture:function (texture, rect) { - var pFrame = cc.SpriteFrame.create(texture, rect); + var pFrame = new cc.SpriteFrame(texture, rect); this.addSpriteFrame(pFrame); }, /** - * Initializes a cc.Animation with cc.AnimationFrame + * Initializes a cc.Animation with cc.AnimationFrame, do not call this method yourself, please pass parameters to constructor to initialize. * @param {Array} arrayOfAnimationFrames * @param {Number} delayPerUnit * @param {Number} [loops=1] @@ -277,6 +297,10 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ return true; }, + /** + * Clone the current animation + * @return {cc.Animation} + */ clone: function(){ var animation = new cc.Animation(); animation.initWithAnimationFrames(this._copyFrames(), this._delayPerUnit, this._loops); @@ -285,7 +309,8 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * @param {cc.Animation} pZone + * Clone the current animation + * @return {cc.Animation} */ copyWithZone:function (pZone) { var pCopy = new cc.Animation(); @@ -301,12 +326,17 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ return copyFrames; }, + /** + * Clone the current animation + * @param pZone + * @returns {cc.Animation} + */ copy:function (pZone) { return this.copyWithZone(null); }, /** - * return how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ... + * Returns how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ... * @return {Number} */ getLoops:function () { @@ -314,7 +344,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * set how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ... + * Sets how many times the animation is going to loop. 0 means animation is not animated. 1, animation is executed one time, ... * @param {Number} value */ setLoops:function (value) { @@ -322,7 +352,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * whether or not it shall restore the original frame when the animation finishes + * Sets whether or not it shall restore the original frame when the animation finishes * @param {Boolean} restOrigFrame */ setRestoreOriginalFrame:function (restOrigFrame) { @@ -330,7 +360,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * return whether or not it shall restore the original frame when the animation finishes + * Returns whether or not it shall restore the original frame when the animation finishes * @return {Boolean} */ getRestoreOriginalFrame:function () { @@ -338,7 +368,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * return duration in seconds of the whole animation. It is the result of totalDelayUnits * delayPerUnit + * Returns duration in seconds of the whole animation. It is the result of totalDelayUnits * delayPerUnit * @return {Number} */ getDuration:function () { @@ -346,7 +376,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * return Delay in seconds of the "delay unit" + * Returns delay in seconds of the "delay unit" * @return {Number} */ getDelayPerUnit:function () { @@ -354,7 +384,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * set Delay in seconds of the "delay unit" + * Sets delay in seconds of the "delay unit" * @param {Number} delayPerUnit */ setDelayPerUnit:function (delayPerUnit) { @@ -362,7 +392,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * return total Delay units of the cc.Animation. + * Returns total delay units of the cc.Animation. * @return {Number} */ getTotalDelayUnits:function () { @@ -370,7 +400,7 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ }, /** - * Initializes a cc.Animation with frames and a delay between frames + * Initializes a cc.Animation with frames and a delay between frames, do not call this method yourself, please pass parameters to constructor to initialize. * @param {Array} frames * @param {Number} delay * @param {Number} [loops=1] @@ -395,45 +425,53 @@ cc.Animation = cc.Class.extend(/** @lends cc.Animation# */{ return true; }, /** - * Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. - * This is a hack, and should be removed once JSB fixes the retain/release bug + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created an engine object and haven't added it into the scene graph during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.Animation#release */ retain:function () { }, + /** + *

Currently JavaScript Bindings (JSB), in some cases, needs to use retain and release. This is a bug in JSB, + * and the ugly workaround is to use retain/release. So, these 2 methods were added to be compatible with JSB. + * This is a hack, and should be removed once JSB fixes the retain/release bug
+ * You will need to retain an object if you created an engine object and haven't added it into the scene graph during the same frame.
+ * Otherwise, JSB's native autorelease pool will consider this object a useless one and release it directly,
+ * when you want to use it later, a "Invalid Native Object" error will be raised.
+ * The retain function can increase a reference count for the native object to avoid it being released,
+ * you need to manually invoke release function when you think this object is no longer needed, otherwise, there will be memory learks.
+ * retain and release function call should be paired in developer's game code.

+ * @function + * @see cc.Animation#retain + */ release:function () { } }); /** * Creates an animation. + * @deprecated since v3.0, please use new construction instead + * @see cc.Animation * @param {Array} frames * @param {Number} delay * @param {Number} [loops=1] * @return {cc.Animation} - * @example - * 1. - * //Creates an empty animation - * var animation1 = cc.Animation.create(); - * - * 2. - * //Create an animation with sprite frames , delay and loops. - * var spriteFrames = []; - * var frame = cache.getSpriteFrame("grossini_dance_01.png"); - * spriteFrames.push(frame); - * var animation1 = cc.Animation.create(spriteFrames); - * var animation2 = cc.Animation.create(spriteFrames, 0.2); - * var animation2 = cc.Animation.create(spriteFrames, 0.2, 2); - * - * 3. - * //Create an animation with animation frames , delay and loops. - * var animationFrames = []; - * var frame = new cc.AnimationFrame(); - * animationFrames.push(frame); - * var animation1 = cc.Animation.create(animationFrames); - * var animation2 = cc.Animation.create(animationFrames, 0.2); - * var animation3 = cc.Animation.create(animationFrames, 0.2, 2); */ cc.Animation.create = function (frames, delay, loops) { return new cc.Animation(frames, delay, loops); }; + +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.Animation + * @type {Function} + */ +cc.Animation.createWithAnimationFrames = cc.Animation.create; \ No newline at end of file diff --git a/cocos2d/core/sprites/CCAnimationCache.js b/cocos2d/core/sprites/CCAnimationCache.js index e76e5e9875..d156393e26 100644 --- a/cocos2d/core/sprites/CCAnimationCache.js +++ b/cocos2d/core/sprites/CCAnimationCache.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,14 +25,15 @@ ****************************************************************************/ /** - * @namespace *

- * Singleton that manages the Animations.
+ * cc.animationCache is a singleton object that manages the Animations.
* It saves in a cache the animations. You should use this class if you want to save your animations in a cache.
*
* example
* cc.animationCache.addAnimation(animation,"animation1");
*

+ * @class + * @name cc.animationCache */ cc.animationCache = /** @lends cc.animationCache# */{ _animations: {}, @@ -47,8 +48,8 @@ cc.animationCache = /** @lends cc.animationCache# */{ }, /** - * Deletes a cc.Animation from the cache. - * @param {String} name + * Deletes a cc.Animation from the cache. + * @param {String} name */ removeAnimation:function (name) { if (!name) { @@ -74,14 +75,6 @@ cc.animationCache = /** @lends cc.animationCache# */{ return null; }, - /** - *

- * Adds an animation from an NSDictionary
- * Make sure that the frames were previously loaded in the cc.SpriteFrameCache. - *

- * @param {object} dictionary - * @param {String} plist - */ _addAnimationsWithDictionary:function (dictionary,plist) { var animations = dictionary["animations"]; if (!animations) { @@ -116,7 +109,7 @@ cc.animationCache = /** @lends cc.animationCache# */{ /** *

- * Adds an animation from a plist file.
+ * Adds an animations from a plist file.
* Make sure that the frames were previously loaded in the cc.SpriteFrameCache. *

* @param {String} plist @@ -163,10 +156,10 @@ cc.animationCache = /** @lends cc.animationCache# */{ if (frames.length === 0) { cc.log(cc._LogInfos.animationCache__parseVersion1_3, key); continue; - } else if (frames.length != frameNames.length) { + } else if (frames.length !== frameNames.length) { cc.log(cc._LogInfos.animationCache__parseVersion1_4, key); } - animation = cc.Animation.create(frames, delay, 1); + animation = new cc.Animation(frames, delay, 1); cc.animationCache.addAnimation(animation, key); } }, diff --git a/cocos2d/core/sprites/CCBakeSprite.js b/cocos2d/core/sprites/CCBakeSprite.js new file mode 100644 index 0000000000..305e84a467 --- /dev/null +++ b/cocos2d/core/sprites/CCBakeSprite.js @@ -0,0 +1,71 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of _t software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.BakeSprite is a type of sprite that will be cached. + * @class + * @extend cc.Sprite + */ +cc.BakeSprite = cc.Sprite.extend(/** @lends cc.BakeSprite# */{ + _cacheCanvas: null, + _cacheContext: null, + + ctor: function(){ + cc.Sprite.prototype.ctor.call(this); + var canvasElement = document.createElement("canvas"); + canvasElement.width = canvasElement.height = 10; + this._cacheCanvas = canvasElement; + this._cacheContext = new cc.CanvasContextWrapper(canvasElement.getContext("2d")); + + var texture = new cc.Texture2D(); + texture.initWithElement(canvasElement); + texture.handleLoadedTexture(); + this.setTexture(texture); + }, + + getCacheContext: function(){ + return this._cacheContext; + }, + + getCacheCanvas: function(){ + return this._cacheCanvas; + }, + + /** + * reset the cache canvas size + * @param {cc.Size|Number} sizeOrWidth size or width + * @param {Number} [height] + */ + resetCanvasSize: function(sizeOrWidth, height){ + if(height === undefined){ + height = sizeOrWidth.height; + sizeOrWidth = sizeOrWidth.width; + } + var locCanvas = this._cacheCanvas; + locCanvas.width = sizeOrWidth; + locCanvas.height = height; //TODO note baidu browser reset the context after set width or height + this.getTexture().handleLoadedTexture(); + this.setTextureRect(cc.rect(0,0, sizeOrWidth, height), false); + } +}); diff --git a/cocos2d/core/sprites/CCSprite.js b/cocos2d/core/sprites/CCSprite.js index 9b3ee418ea..b6662b3455 100644 --- a/cocos2d/core/sprites/CCSprite.js +++ b/cocos2d/core/sprites/CCSprite.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,199 +24,6 @@ THE SOFTWARE. ****************************************************************************/ -/** - * generate texture's cache for texture tint - * @function - * @param {HTMLImageElement} texture - * @return {Array} - */ - -cc.generateTextureCacheForColor = function (texture) { - if (texture.channelCache) { - return texture.channelCache; - } - - var textureCache = [ - cc.newElement("canvas"), - cc.newElement("canvas"), - cc.newElement("canvas"), - cc.newElement("canvas") - ]; - - function renderToCache() { - var ref = cc.generateTextureCacheForColor; - - var w = texture.width; - var h = texture.height; - - textureCache[0].width = w; - textureCache[0].height = h; - textureCache[1].width = w; - textureCache[1].height = h; - textureCache[2].width = w; - textureCache[2].height = h; - textureCache[3].width = w; - textureCache[3].height = h; - - ref.canvas.width = w; - ref.canvas.height = h; - - var ctx = ref.canvas.getContext("2d"); - ctx.drawImage(texture, 0, 0); - - ref.tempCanvas.width = w; - ref.tempCanvas.height = h; - - var pixels = ctx.getImageData(0, 0, w, h).data; - - for (var rgbI = 0; rgbI < 4; rgbI++) { - var cacheCtx = textureCache[rgbI].getContext('2d'); - cacheCtx.getImageData(0, 0, w, h).data; - ref.tempCtx.drawImage(texture, 0, 0); - - var to = ref.tempCtx.getImageData(0, 0, w, h); - var toData = to.data; - - for (var i = 0; i < pixels.length; i += 4) { - toData[i ] = (rgbI === 0) ? pixels[i ] : 0; - toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0; - toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0; - toData[i + 3] = pixels[i + 3]; - } - cacheCtx.putImageData(to, 0, 0); - } - texture.onload = null; - } - - try { - renderToCache(); - } catch (e) { - texture.onload = renderToCache; - } - - texture.channelCache = textureCache; - return textureCache; -}; - -cc.generateTextureCacheForColor.canvas = cc.newElement('canvas'); -cc.generateTextureCacheForColor.tempCanvas = cc.newElement('canvas'); -cc.generateTextureCacheForColor.tempCtx = cc.generateTextureCacheForColor.tempCanvas.getContext('2d'); - -/** - * generate tinted texture - * source-in: Where source and destination overlaps and both are opaque, the source is displayed. - * Everywhere else transparency is displayed. - * @function - * @param {HTMLImageElement} texture - * @param {cc.Color} color - * @param {cc.Rect} rect - * @return {HTMLCanvasElement} - */ -cc.generateTintImage2 = function (texture, color, rect) { - if (!rect) { - rect = cc.rect(0, 0, texture.width, texture.height); - rect = cc.rectPixelsToPoints(rect); - } - - var buff = cc.newElement("canvas"); - var ctx = buff.getContext("2d"); - - if (buff.width != rect.width) buff.width = rect.width; - if (buff.height != rect.height) buff.height = rect.height; - ctx.save(); - - ctx.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); - - ctx.globalCompositeOperation = "source-in"; - ctx.globalAlpha = color.a / 255.0; - ctx.fillStyle = "rgb(" + color.r + "," + color.g + "," + color.b + ")"; - ctx.fillRect(0, 0, rect.width, rect.height); - ctx.restore(); - - return buff; -}; - -/** - * generate tinted texture - * lighter: The source and destination colors are added to each other, resulting in brighter colors, - * moving towards color values of 1 (maximum brightness for that color). - * @function - * @param {HTMLImageElement} texture - * @param {Array} tintedImgCache - * @param {cc.Color} color - * @param {cc.Rect} rect - * @param {HTMLCanvasElement} [renderCanvas] - * @return {HTMLCanvasElement} - */ -cc.generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) { - if (!rect) - rect = cc.rect(0, 0, texture.width, texture.height); - - var r = color.r / 255; - var g = color.g / 255; - var b = color.b / 255; - - var w = Math.min(rect.width, tintedImgCache[0].width); - var h = Math.min(rect.height, tintedImgCache[0].height); - var buff = renderCanvas; - var ctx; - - // Create a new buffer if required - if (!buff) { - buff = cc.newElement("canvas"); - buff.width = w; - buff.height = h; - ctx = buff.getContext("2d"); - } else { - ctx = buff.getContext("2d"); - ctx.clearRect(0, 0, w, h); - } - - ctx.save(); - ctx.globalCompositeOperation = 'lighter'; - - // Make sure to keep the renderCanvas alpha in mind in case of overdraw - var a = ctx.globalAlpha; - if (r > 0) { - ctx.globalAlpha = r * a; - ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h); - } - if (g > 0) { - ctx.globalAlpha = g * a; - ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h); - } - if (b > 0) { - ctx.globalAlpha = b * a; - ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h); - } - - if (r + g + b < 1) { - ctx.globalAlpha = a; - ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h); - } - - ctx.restore(); - return buff; -}; - -cc.cutRotateImageToCanvas = function (texture, rect) { - if (!texture) - return null; - - if (!rect) - return texture; - - var nCanvas = cc.newElement("canvas"); - nCanvas.width = rect.width; - nCanvas.height = rect.height; - - var ctx = nCanvas.getContext("2d"); - ctx.translate(nCanvas.width / 2, nCanvas.height / 2); - ctx.rotate(-1.5707963267948966); - ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width); - return nCanvas; -}; - /** *

cc.Sprite is a 2d image ( http://en.wikipedia.org/wiki/Sprite_(computer_graphics) )
* @@ -240,11 +47,33 @@ cc.cutRotateImageToCanvas = function (texture, rect) { * * The default anchorPoint in cc.Sprite is (0.5, 0.5).

* @class - * @extends cc.NodeRGBA + * @extends cc.Node + * + * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png". + * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. + * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. + * @example + * + * 1.Create a sprite with image path and rect + * var sprite1 = new cc.Sprite("res/HelloHTML5World.png"); + * var sprite2 = new cc.Sprite("res/HelloHTML5World.png",cc.rect(0,0,480,320)); + * + * 2.Create a sprite with a sprite frame name. Must add "#" before frame name. + * var sprite = new cc.Sprite('#grossini_dance_01.png'); + * + * 3.Create a sprite with a sprite frame + * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); + * var sprite = new cc.Sprite(spriteFrame); + * + * 4.Create a sprite with an existing texture contained in a CCTexture2D object + * After creation, the rect will be the size of the texture, and the offset will be (0,0). + * var texture = cc.textureCache.addImage("HelloHTML5World.png"); + * var sprite1 = new cc.Sprite(texture); + * var sprite2 = new cc.Sprite(texture, cc.rect(0,0,480,320)); * * @property {Boolean} dirty - Indicates whether the sprite needs to be updated. - * @property {Boolean} flippedX - Indicates whether or not the spirte is flipped on x axis. - * @property {Boolean} flippedY - Indicates whether or not the spirte is flipped on y axis. + * @property {Boolean} flippedX - Indicates whether or not the sprite is flipped on x axis. + * @property {Boolean} flippedY - Indicates whether or not the sprite is flipped on y axis. * @property {Number} offsetX - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. * @property {Number} offsetY - <@readonly> The offset position on x axis of the sprite in texture. Calculated automatically by editors like Zwoptex. * @property {Number} atlasIndex - The index used on the TextureAtlas. @@ -253,13 +82,8 @@ cc.cutRotateImageToCanvas = function (texture, rect) { * @property {cc.TextureAtlas} textureAtlas - The weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode. * @property {cc.SpriteBatchNode} batchNode - The batch node object if this sprite is rendered by cc.SpriteBatchNode. * @property {cc.V3F_C4B_T2F_Quad} quad - <@readonly> The quad (tex coords, vertex coords and color) information. - * - * @example - * var aSprite = new cc.Sprite(); - * aSprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); */ -cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ - RGBAProtocol:true, +cc.Sprite = cc.Node.extend(/** @lends cc.Sprite# */{ dirty:false, atlasIndex:0, textureAtlas:null, @@ -280,7 +104,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ // Shared data // // texture - _rect:null, //Retangle of cc.Texture2D + _rect:null, //Rectangle of cc.Texture2D _rectRotated:false, //Whether the texture is rotated // Offset Position (used by Zwoptex) @@ -294,41 +118,48 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ _flippedY:false, //Whether the sprite is flipped vertically or not. _textureLoaded:false, - _loadedEventListeners: null, - _newTextureWhenChangeColor: null, //hack property for LabelBMFont _className:"Sprite", + ctor: function (fileName, rect, rotated) { + var self = this; + cc.Node.prototype.ctor.call(self); + self._shouldBeHidden = false; + self._offsetPosition = cc.p(0, 0); + self._unflippedOffsetPositionFromCenter = cc.p(0, 0); + self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; + self._rect = cc.rect(0, 0, 0, 0); + + self._softInit(fileName, rect, rotated); + }, + + /** + * Returns whether the texture have been loaded + * @returns {boolean} + */ textureLoaded:function(){ return this._textureLoaded; }, + /** + * Add a event listener for texture loaded event. + * @param {Function} callback + * @param {Object} target + * @deprecated since 3.1, please use addEventListener instead + */ addLoadedEventListener:function(callback, target){ - if(!this._loadedEventListeners) - this._loadedEventListeners = []; - this._loadedEventListeners.push({eventCallback:callback, eventTarget:target}); - }, - - _callLoadedEventCallbacks:function(){ - if(!this._loadedEventListeners) - return; - var locListeners = this._loadedEventListeners; - for(var i = 0, len = locListeners.length; i < len; i++){ - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; + this.addEventListener("load", callback, target); }, /** - * Whether or not the Sprite needs to be updated in the Atlas - * @return {Boolean} true if the sprite needs to be updated in the Atlas, false otherwise. + * Returns whether or not the Sprite needs to be updated in the Atlas + * @return {Boolean} True if the sprite needs to be updated in the Atlas, false otherwise. */ isDirty:function () { return this.dirty; }, /** - * Makes the Sprite to be updated in the Atlas. + * Makes the sprite to be updated in the Atlas. * @param {Boolean} bDirty */ setDirty:function (bDirty) { @@ -352,7 +183,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * Set the index used on the TextureAtlas. + * Sets the index used on the TextureAtlas. * @warning Don't modify this value unless you know what you are doing * @param {Number} atlasIndex */ @@ -361,15 +192,15 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * returns the rect of the cc.Sprite in points + * Returns the rect of the cc.Sprite in points * @return {cc.Rect} */ getTextureRect:function () { - return cc.rect(this._rect.x, this._rect.y, this._rect.width, this._rect.height); + return cc.rect(this._rect); }, /** - * Gets the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode + * Returns the weak reference of the cc.TextureAtlas when the sprite is rendered using via cc.SpriteBatchNode * @return {cc.TextureAtlas} */ getTextureAtlas:function () { @@ -385,11 +216,11 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * Gets the offset position of the sprite. Calculated automatically by editors like Zwoptex. + * Returns the offset position of the sprite. Calculated automatically by editors like Zwoptex. * @return {cc.Point} */ getOffsetPosition:function () { - return this._offsetPosition; + return cc.p(this._offsetPosition); }, _getOffsetX: function () { @@ -400,7 +231,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * conforms to cc.TextureProtocol protocol + * Returns the blend function * @return {cc.BlendFunc} */ getBlendFunc:function () { @@ -408,55 +239,52 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * Initializes a sprite with an SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite + * Initializes a sprite with a SpriteFrame. The texture and rect in SpriteFrame will be applied on this sprite.
+ * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself, * @param {cc.SpriteFrame} spriteFrame A CCSpriteFrame object. It should includes a valid texture and a rect * @return {Boolean} true if the sprite is initialized properly, false otherwise. - * @example - * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); - * var sprite = new cc.Sprite(); - * sprite.initWithSpriteFrame(spriteFrame); */ initWithSpriteFrame:function (spriteFrame) { - cc.assert(spriteFrame, cc._LogInfos.Sprite_initWithSpriteFrame); if(!spriteFrame.textureLoaded()){ //add event listener this._textureLoaded = false; - spriteFrame.addLoadedEventListener(this._spriteFrameLoadedCallback, this); + spriteFrame.addEventListener("load", this._renderCmd._spriteFrameLoadedCallback, this); } - var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect()); + + //TODO + var rotated = cc._renderType === cc._RENDER_TYPE_CANVAS ? false : spriteFrame._rotated; + var ret = this.initWithTexture(spriteFrame.getTexture(), spriteFrame.getRect(), rotated); this.setSpriteFrame(spriteFrame); return ret; }, - _spriteFrameLoadedCallback:null, - /** * Initializes a sprite with a sprite frame name.
* A cc.SpriteFrame will be fetched from the cc.SpriteFrameCache by name.
* If the cc.SpriteFrame doesn't exist it will raise an exception.
- * @param {String} spriteFrameName A key string that can fected a volid cc.SpriteFrame from cc.SpriteFrameCache + * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. + * @param {String} spriteFrameName A key string that can fected a valid cc.SpriteFrame from cc.SpriteFrameCache * @return {Boolean} true if the sprite is initialized properly, false otherwise. * @example * var sprite = new cc.Sprite(); * sprite.initWithSpriteFrameName("grossini_dance_01.png"); */ initWithSpriteFrameName:function (spriteFrameName) { - - cc.assert(cc._LogInfos.Sprite_initWithSpriteFrameName); - + cc.assert(spriteFrameName, cc._LogInfos.Sprite_initWithSpriteFrameName); var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName); + cc.assert(frame, spriteFrameName + cc._LogInfos.Sprite_initWithSpriteFrameName1); return this.initWithSpriteFrame(frame); }, /** - * tell the sprite to use batch node render. + * Tell the sprite to use batch node render. * @param {cc.SpriteBatchNode} batchNode */ useBatchNode:function (batchNode) { - this.textureAtlas = batchNode.textureAtlas; // weak ref + this.textureAtlas = batchNode.getTextureAtlas(); // weak ref this._batchNode = batchNode; }, @@ -471,35 +299,49 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @param {cc.Rect} rect */ setVertexRect:function (rect) { - this._rect.x = rect.x; - this._rect.y = rect.y; - this._rect.width = rect.width; - this._rect.height = rect.height; + var locRect = this._rect; + locRect.x = rect.x; + locRect.y = rect.y; + locRect.width = rect.width; + locRect.height = rect.height; }, + /** + * Sort all children of this sprite node. + * @override + */ sortAllChildren:function () { if (this._reorderChildDirty) { - var j, tempItem, locChildren = this._children, tempChild; - for (var i = 1; i < locChildren.length; i++) { - tempItem = locChildren[i]; + var _children = this._children; + + // insertion sort + var len = _children.length, i, j, tmp; + for(i=1; i= 0 && ( tempItem._localZOrder < tempChild._localZOrder || - ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { - locChildren[j + 1] = tempChild; - j = j - 1; - tempChild = locChildren[j]; + while(j >= 0){ + if(tmp._localZOrder < _children[j]._localZOrder){ + _children[j+1] = _children[j]; + }else if(tmp._localZOrder === _children[j]._localZOrder && tmp.arrivalOrder < _children[j].arrivalOrder){ + _children[j+1] = _children[j]; + }else{ + break; + } + j--; } - locChildren[j + 1] = tempItem; + _children[j+1] = tmp; } if (this._batchNode) { - this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren); + this._arrayMakeObjectsPerformSelector(_children, cc.Node._stateCallbackType.sortAllChildren); } + + //don't need to check children recursively, that's done in visit of each child this._reorderChildDirty = false; } + }, /** @@ -509,9 +351,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @override */ reorderChild:function (child, zOrder) { - cc.assert(child, cc._LogInfos.Sprite_reorderChild_2); - if(this._children.indexOf(child) === -1){ cc.log(cc._LogInfos.Sprite_reorderChild); return; @@ -528,7 +368,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * Removes a child from the sprite. (override cc.Node ) + * Removes a child from the sprite. * @param child * @param cleanup whether or not cleanup all running actions * @override @@ -540,7 +380,17 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, /** - * Removes all children from the container (override cc.Node ) + * Sets whether the sprite is visible or not. + * @param {Boolean} visible + * @override + */ + setVisible:function (visible) { + cc.Node.prototype.setVisible.call(this, visible); + this._renderCmd.setDirtyRecursively(true); + }, + + /** + * Removes all children from the container. * @param cleanup whether or not cleanup all running actions * @override */ @@ -559,42 +409,8 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ // cc.Node property overloads // - /** - * set Recursively is or isn't Dirty - * used only when parent is cc.SpriteBatchNode - * @param {Boolean} value - */ - setDirtyRecursively:function (value) { - this._recursiveDirty = value; - this.dirty = value; - // recursively set dirty - var locChildren = this._children, child, l = locChildren ? locChildren.length : 0; - for (var i = 0; i < l; i++) { - child = locChildren[i]; - (child instanceof cc.Sprite) && child.setDirtyRecursively(true); - } - }, - - /** - * Make the node dirty - * @param {Boolean} norecursive When true children will not be set dirty recursively, by default, they will be. - * @override - */ - setNodeDirty: function(norecursive) { - cc.Node.prototype.setNodeDirty.call(this); - // Lazy set dirty - if (!norecursive && this._batchNode && !this._recursiveDirty) { - if (this._hasChildren) - this.setDirtyRecursively(true); - else { - this._recursiveDirty = true; - this.dirty = true; - } - } - }, - /** - * IsRelativeAnchorPoint setter (override cc.Node ) + * Sets whether ignore anchor point for positioning * @param {Boolean} relative * @override */ @@ -611,7 +427,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @param {Boolean} flippedX true if the sprite should be flipped horizontally, false otherwise. */ setFlippedX:function (flippedX) { - if (this._flippedX != flippedX) { + if (this._flippedX !== flippedX) { this._flippedX = flippedX; this.setTextureRect(this._rect, this._rectRotated, this._contentSize); this.setNodeDirty(true); @@ -623,7 +439,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @param {Boolean} flippedY true if the sprite should be flipped vertically, false otherwise. */ setFlippedY:function (flippedY) { - if (this._flippedY != flippedY) { + if (this._flippedY !== flippedY) { this._flippedY = flippedY; this.setTextureRect(this._rect, this._rectRotated, this._contentSize); this.setNodeDirty(true); @@ -632,13 +448,13 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ /** *

- * Returns the flag which indicates whether the sprite is flipped horizontally or not.
+ * Returns the flag which indicates whether the sprite is flipped horizontally or not.
*
* It only flips the texture of the sprite, and not the texture of the sprite's children.
* Also, flipping the texture doesn't alter the anchorPoint.
* If you want to flip the anchorPoint too, and/or to flip the children too use:
- * sprite->setScaleX(sprite->getScaleX() * -1);

- * @return {Boolean} true if the sprite is flipped horizaontally, false otherwise. + * sprite.setScaleX(sprite.getScaleX() * -1);

+ * @return {Boolean} true if the sprite is flipped horizontally, false otherwise. */ isFlippedX:function () { return this._flippedX; @@ -651,8 +467,8 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * It only flips the texture of the sprite, and not the texture of the sprite's children.
* Also, flipping the texture doesn't alter the anchorPoint.
* If you want to flip the anchorPoint too, and/or to flip the children too use:
- * sprite->setScaleY(sprite->getScaleY() * -1);

- * @return {Boolean} true if the sprite is flipped vertically, flase otherwise. + * sprite.setScaleY(sprite.getScaleY() * -1);

+ * @return {Boolean} true if the sprite is flipped vertically, false otherwise. */ isFlippedY:function () { return this._flippedY; @@ -662,32 +478,34 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ // RGBA protocol // /** - * opacity: conforms to CCRGBAProtocol protocol + * Sets whether opacity modify color or not. * @function * @param {Boolean} modify */ - setOpacityModifyRGB:null, + setOpacityModifyRGB: function (modify) { + if (this._opacityModifyRGB !== modify) { + this._opacityModifyRGB = modify; + this._renderCmd._setColorDirty(); + } + }, /** - * return IsOpacityModifyRGB value + * Returns whether opacity modify color or not. * @return {Boolean} */ isOpacityModifyRGB:function () { return this._opacityModifyRGB; }, - updateDisplayedOpacity: null, - // Animation /** - * changes the display frame with animation name and index.
+ * Changes the display frame with animation name and index.
* The animation name will be get from the CCAnimationCache - * @param animationName - * @param frameIndex + * @param {String} animationName + * @param {Number} frameIndex */ setDisplayFrameWithAnimationName:function (animationName, frameIndex) { - cc.assert(animationName, cc._LogInfos.Sprite_setDisplayFrameWithAnimationName_3); var cache = cc.animationCache.getAnimation(animationName); @@ -716,7 +534,7 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ if (!this._reorderChildDirty) { this._reorderChildDirty = true; var pNode = this._parent; - while (pNode && pNode != this._batchNode) { + while (pNode && pNode !== this._batchNode) { pNode._setReorderChildDirtyRecursively(); pNode = pNode.parent; } @@ -724,45 +542,34 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ }, // CCTextureProtocol + /** + * Returns the texture of the sprite node + * @returns {cc.Texture2D} + */ getTexture:function () { return this._texture; }, - _quad:null, // vertex coords, texture coords and color info - _quadWebBuffer:null, - _quadDirty:false, - _colorized:false, - _isLighterMode:false, - _originalTexture:null, - _textureRect_Canvas:null, - _drawSize_Canvas:null, - - /** - * Constructor - * @function - * @param {String|cc.SpriteFrame|cc.SpriteBatchNode|HTMLImageElement|cc.Texture2D} fileName sprite construct parameter - * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. - */ - ctor: null, - - _softInit: function (fileName, rect) { + _softInit: function (fileName, rect, rotated) { if (fileName === undefined) cc.Sprite.prototype.init.call(this); - else if (typeof(fileName) === "string") { + else if (cc.isString(fileName)) { if (fileName[0] === "#") { // Init with a sprite frame name var frameName = fileName.substr(1, fileName.length - 1); var spriteFrame = cc.spriteFrameCache.getSpriteFrame(frameName); - this.initWithSpriteFrame(spriteFrame); + if (spriteFrame) + this.initWithSpriteFrame(spriteFrame); + else + cc.log("%s does not exist", fileName); } else { // Init with filename and rect cc.Sprite.prototype.init.call(this, fileName, rect); } - } - else if (typeof(fileName) === "object") { + } else if (typeof fileName === "object") { if (fileName instanceof cc.Texture2D) { // Init with texture and rect - this.initWithTexture(fileName, rect); + this.initWithTexture(fileName, rect, rotated); } else if (fileName instanceof cc.SpriteFrame) { // Init with a sprite frame this.initWithSpriteFrame(fileName); @@ -778,10 +585,10 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ /** * Returns the quad (tex coords, vertex coords and color) information. - * @return {cc.V3F_C4B_T2F_Quad} + * @return {cc.V3F_C4B_T2F_Quad|null} Returns a cc.V3F_C4B_T2F_Quad object when render mode is WebGL, returns null when render mode is Canvas. */ getQuad:function () { - return this._quad; + return this._renderCmd.getQuad(); }, /** @@ -790,149 +597,267 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @param {Number|cc.BlendFunc} src * @param {Number} dst */ - setBlendFunc: null, + setBlendFunc: function (src, dst) { + var locBlendFunc = this._blendFunc; + if (dst === undefined) { + locBlendFunc.src = src.src; + locBlendFunc.dst = src.dst; + } else { + locBlendFunc.src = src; + locBlendFunc.dst = dst; + } + this._renderCmd.updateBlendFunc(locBlendFunc); + }, /** - * Initializes an empty sprite with nothing init. + * Initializes an empty sprite with nothing init.
+ * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. * @function * @return {Boolean} */ - init:null, + init: function () { + var _t = this; + if (arguments.length > 0) + return _t.initWithFile(arguments[0], arguments[1]); + + cc.Node.prototype.init.call(_t); + _t.dirty = _t._recursiveDirty = false; + + _t._blendFunc.src = cc.BLEND_SRC; + _t._blendFunc.dst = cc.BLEND_DST; + + _t.texture = null; + _t._flippedX = _t._flippedY = false; + + // default transform anchor: center + _t.anchorX = 0.5; + _t.anchorY = 0.5; + + // zwoptex default values + _t._offsetPosition.x = 0; + _t._offsetPosition.y = 0; + _t._hasChildren = false; + + this._renderCmd._init(); + // updated in "useSelfRender" + // Atlas: TexCoords + _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); + return true; + }, /** *

- * Initializes a sprite with an image filename. + * Initializes a sprite with an image filename.
* - * This method will find pszFilename from local file system, load its content to CCTexture2D, - * then use CCTexture2D to create a sprite. - * After initialization, the rect used will be the size of the image. The offset will be (0,0). + * This method will find pszFilename from local file system, load its content to CCTexture2D,
+ * then use CCTexture2D to create a sprite.
+ * After initialization, the rect used will be the size of the image. The offset will be (0,0).
+ * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. *

* @param {String} filename The path to an image file in local file system * @param {cc.Rect} rect The rectangle assigned the content area from texture. * @return {Boolean} true if the sprite is initialized properly, false otherwise. - * @example - * var mySprite = new cc.Sprite(); - * mySprite.initWithFile("HelloHTML5World.png",cc.rect(0,0,480,320)); */ initWithFile:function (filename, rect) { - cc.assert(filename, cc._LogInfos.Sprite_initWithFile); - var texture = cc.textureCache.textureForKey(filename); - if (!texture) { - texture = cc.textureCache.addImage(filename); - return this.initWithTexture(texture, rect); + var tex = cc.textureCache.getTextureForKey(filename); + if (!tex) { + tex = cc.textureCache.addImage(filename); + return this.initWithTexture(tex, rect || cc.rect(0, 0, tex._contentSize.width, tex._contentSize.height)); } else { if (!rect) { - var size = texture.getContentSize(); + var size = tex.getContentSize(); rect = cc.rect(0, 0, size.width, size.height); } - return this.initWithTexture(texture, rect); + return this.initWithTexture(tex, rect); } }, /** * Initializes a sprite with a texture and a rect in points, optionally rotated.
- * After initialization, the rect used will be the size of the texture, and the offset will be (0,0). + * After initialization, the rect used will be the size of the texture, and the offset will be (0,0).
+ * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. * @function * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture A pointer to an existing CCTexture2D object. You can use a CCTexture2D object for many sprites. - * @param {cc.Rect} rect Only the contents inside rect of this texture will be applied for this sprite. + * @param {cc.Rect} [rect] Only the contents inside rect of this texture will be applied for this sprite. * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. + * @param {Boolean} [counterclockwise=true] Whether or not the texture rectangle rotation is counterclockwise (texture package is counterclockwise, spine is clockwise). * @return {Boolean} true if the sprite is initialized properly, false otherwise. - * @example - * var img =cc.textureCache.addImage("HelloHTML5World.png"); - * var mySprite = new cc.Sprite(); - * mySprite.initWithTexture(img,cc.rect(0,0,480,320)); */ - initWithTexture: null, + initWithTexture: function (texture, rect, rotated, counterclockwise) { + var _t = this; + cc.assert(arguments.length !== 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture); + + rotated = rotated || false; + texture = this._renderCmd._handleTextureForRotatedTexture(texture, rect, rotated, counterclockwise); + + if (!cc.Node.prototype.init.call(_t)) + return false; + + _t._batchNode = null; + _t._recursiveDirty = false; + _t.dirty = false; + _t._opacityModifyRGB = true; + + _t._blendFunc.src = cc.BLEND_SRC; + _t._blendFunc.dst = cc.BLEND_DST; + + _t._flippedX = _t._flippedY = false; + + // default transform anchor: center + _t.setAnchorPoint(0.5, 0.5); + + // zwoptex default values + _t._offsetPosition.x = 0; + _t._offsetPosition.y = 0; + _t._hasChildren = false; + + this._renderCmd._init(); + + var locTextureLoaded = texture.isLoaded(); + _t._textureLoaded = locTextureLoaded; + + if (!locTextureLoaded) { + _t._rectRotated = rotated; + if (rect) { + _t._rect.x = rect.x; + _t._rect.y = rect.y; + _t._rect.width = rect.width; + _t._rect.height = rect.height; + } + if(_t.texture) + _t.texture.removeEventListener("load", _t); + texture.addEventListener("load", _t._renderCmd._textureLoadedCallback, _t); + _t.texture = texture; + return true; + } + + if (!rect) + rect = cc.rect(0, 0, texture.width, texture.height); + + this._renderCmd._checkTextureBoundary(texture, rect, rotated); + + _t.texture = texture; + _t.setTextureRect(rect, rotated); - _textureLoadedCallback: null, + // by default use "Self Render". + // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" + _t.setBatchNode(null); + return true; + }, /** - * updates the texture rect of the CCSprite in points. + * Updates the texture rect of the CCSprite in points. * @function * @param {cc.Rect} rect a rect of texture - * @param {Boolean} rotated - * @param {cc.Size} untrimmedSize + * @param {Boolean} [rotated] Whether or not the texture is rotated + * @param {cc.Size} [untrimmedSize] The original pixels size of the texture */ - setTextureRect:null, + setTextureRect: function (rect, rotated, untrimmedSize, needConvert) { + var _t = this; + _t._rectRotated = rotated || false; + _t.setContentSize(untrimmedSize || rect); + + _t.setVertexRect(rect); + _t._renderCmd._setTextureCoords(rect, needConvert); + + var relativeOffsetX = _t._unflippedOffsetPositionFromCenter.x, relativeOffsetY = _t._unflippedOffsetPositionFromCenter.y; + if (_t._flippedX) + relativeOffsetX = -relativeOffsetX; + if (_t._flippedY) + relativeOffsetY = -relativeOffsetY; + var locRect = _t._rect; + _t._offsetPosition.x = relativeOffsetX + (_t._contentSize.width - locRect.width) / 2; + _t._offsetPosition.y = relativeOffsetY + (_t._contentSize.height - locRect.height) / 2; + + // rendering using batch node + if (_t._batchNode) { + // update dirty, don't update _recursiveDirty + _t.dirty = true; + } else { + // self rendering + // Atlas: Vertex + this._renderCmd._resetForBatchNode(); + } + }, // BatchNode methods /** - * updates the quad according the the rotation, position, scale values. + * Updates the quad according the the rotation, position, scale values. * @function */ - updateTransform: null, + updateTransform: function(){ + this._renderCmd.updateTransform(); + }, /** - * Add child to sprite (override cc.Node ) + * Add child to sprite (override cc.Node) * @function * @param {cc.Sprite} child * @param {Number} localZOrder child's zOrder - * @param {String} tag child's tag + * @param {String} [tag] child's tag * @override */ - addChild: null, + addChild: function (child, localZOrder, tag) { + cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2); - /** - * Update sprite's color - */ - updateColor:function () { - var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity; - var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity}; - // special opacity for premultiplied textures - if (this._opacityModifyRGB) { - color4.r *= locDisplayedOpacity / 255.0; - color4.g *= locDisplayedOpacity / 255.0; - color4.b *= locDisplayedOpacity / 255.0; - } - var locQuad = this._quad; - locQuad.bl.colors = color4; - locQuad.br.colors = color4; - locQuad.tl.colors = color4; - locQuad.tr.colors = color4; - - // renders using Sprite Manager - if (this._batchNode) { - if (this.atlasIndex != cc.Sprite.INDEX_NOT_INITIALIZED) { - this.textureAtlas.updateQuad(locQuad, this.atlasIndex) - } else { - // no need to set it recursively - // update dirty_, don't update recursiveDirty_ - this.dirty = true; - } + if (localZOrder == null) + localZOrder = child._localZOrder; + if (tag == null) + tag = child.tag; + + if(this._renderCmd._setBatchNodeForAddChild(child)){ + //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check + cc.Node.prototype.addChild.call(this, child, localZOrder, tag); + this._hasChildren = true; } - // self render - // do nothing - this._quadDirty = true; }, - /** - * Opacity setter - * @function - * @param {Number} opacity - */ - setOpacity:null, - - /** - * Color setter - * @function - * @param {cc.Color} color3 - */ - setColor: null, - - updateDisplayedColor: null, - // Frames /** - * Sets a new spriteFrame to the cc.Sprite. + * Sets a new sprite frame to the sprite. * @function * @param {cc.SpriteFrame|String} newFrame */ - setSpriteFrame: null, + setSpriteFrame: function (newFrame) { + var _t = this; + if(cc.isString(newFrame)){ + newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); + cc.assert(newFrame, cc._LogInfos.Sprite_setSpriteFrame) + } - /** - * Sets a new display frame to the cc.Sprite. + this.setNodeDirty(true); + + var frameOffset = newFrame.getOffset(); + _t._unflippedOffsetPositionFromCenter.x = frameOffset.x; + _t._unflippedOffsetPositionFromCenter.y = frameOffset.y; + + // update rect + var pNewTexture = newFrame.getTexture(); + var locTextureLoaded = newFrame.textureLoaded(); + if (!locTextureLoaded) { + _t._textureLoaded = false; + newFrame.addEventListener("load", function (sender) { + _t._textureLoaded = true; + var locNewTexture = sender.getTexture(); + if (locNewTexture !== _t._texture) + _t.texture = locNewTexture; + _t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); + _t.dispatchEvent("load"); + _t.setColor(_t.color); + }, _t); + }else{ + // update texture before updating texture rect + if (pNewTexture !== _t._texture) + _t.texture = pNewTexture; + _t.setTextureRect(newFrame.getRect(), newFrame.isRotated(), newFrame.getOriginalSize()); + } + this._renderCmd._updateForSetSpriteFrame(pNewTexture); + }, + + /** + * Sets a new display frame to the sprite. * @param {cc.SpriteFrame|String} newFrame * @deprecated */ @@ -947,14 +872,25 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @param {cc.SpriteFrame} frame * @return {Boolean} */ - isFrameDisplayed: null, + isFrameDisplayed: function(frame){ + return this._renderCmd.isFrameDisplayed(frame); + }, /** * Returns the current displayed frame. + * @deprecated since 3.4, please use getSpriteFrame instead * @return {cc.SpriteFrame} */ displayFrame: function () { - return cc.SpriteFrame.create(this._texture, + return this.getSpriteFrame(); + }, + + /** + * Returns the current displayed frame. + * @return {cc.SpriteFrame} + */ + getSpriteFrame: function () { + return new cc.SpriteFrame(this._texture, cc.rectPointsToPixels(this._rect), this._rectRotated, cc.pointPointsToPixels(this._unflippedOffsetPositionFromCenter), @@ -966,636 +902,141 @@ cc.Sprite = cc.NodeRGBA.extend(/** @lends cc.Sprite# */{ * @function * @param {cc.SpriteBatchNode|null} spriteBatchNode * @example - * var batch = cc.SpriteBatchNode.create("Images/grossini_dance_atlas.png", 15); - * var sprite = cc.Sprite.create(batch.texture, cc.rect(0, 0, 57, 57)); + * var batch = new cc.SpriteBatchNode("Images/grossini_dance_atlas.png", 15); + * var sprite = new cc.Sprite(batch.texture, cc.rect(0, 0, 57, 57)); * batch.addChild(sprite); * layer.addChild(batch); */ - setBatchNode:null, + setBatchNode:function (spriteBatchNode) { + var _t = this; + _t._batchNode = spriteBatchNode; // weak reference + + // self render + if (!_t._batchNode) { + _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED; + _t.textureAtlas = null; + _t._recursiveDirty = false; + _t.dirty = false; + + this._renderCmd._resetForBatchNode(); + } else { + // using batch + _t._transformToBatch = cc.affineTransformIdentity(); + _t.textureAtlas = _t._batchNode.getTextureAtlas(); // weak ref + } + }, // CCTextureProtocol /** - * Texture of sprite setter + * Sets the texture of sprite * @function * @param {cc.Texture2D|String} texture */ - setTexture: null, + setTexture: function (texture) { + if(!texture) + return this._renderCmd._setTexture(null); - // Texture protocol - _updateBlendFunc:function () { - if(this._batchNode){ - cc.log(cc._LogInfos.Sprite__updateBlendFunc); - return; - } + if(cc.isString(texture)){ + texture = cc.textureCache.addImage(texture); - // it's possible to have an untextured sprite - if (!this._texture || !this._texture.hasPremultipliedAlpha()) { - this._blendFunc.src = cc.SRC_ALPHA; - this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; - this.opacityModifyRGB = false; - } else { - this._blendFunc.src = cc.BLEND_SRC; - this._blendFunc.dst = cc.BLEND_DST; - this.opacityModifyRGB = true; + if(!texture._textureLoaded){ + texture.addEventListener("load", function(){ + this._clearRect(); + this._renderCmd._setTexture(texture); + this._changeRectWithTexture(texture.getContentSize()); + this.setColor(this._realColor); + this._textureLoaded = true; + }, this); + }else{ + this._clearRect(); + this._renderCmd._setTexture(texture); + this._changeRectWithTexture(texture.getContentSize()); + this.setColor(this._realColor); + this._textureLoaded = true; + } + }else{ + // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet + cc.assert(texture instanceof cc.Texture2D, cc._LogInfos.Sprite_setTexture_2); + this._clearRect(); + this._changeRectWithTexture(texture.getContentSize()); + this._renderCmd._setTexture(texture); } }, - _changeTextureColor: function () { - var locElement, locTexture = this._texture, locRect = this._textureRect_Canvas; //this.getTextureRect(); - if (locTexture && locRect.validRect && this._originalTexture) { - locElement = locTexture.getHtmlElementObj(); - if (!locElement) - return; - - var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); - if (cacheTextureForColor) { - this._colorized = true; - //generate color texture cache - if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor) - cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect, locElement); - else { - locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, locRect); - locTexture = new cc.Texture2D(); - locTexture.initWithElement(locElement); - locTexture.handleLoadedTexture(); - this.texture = locTexture; - } - } + _clearRect: function(){ + var texture = this._texture; + if(texture){ + var textureRect = texture._contentSize; + var spriteRect = this._rect; + if( + textureRect.width === spriteRect.width && + textureRect.height === spriteRect.height + ) + spriteRect.width = spriteRect.height = 0; } }, - _setTextureCoords:function (rect) { - rect = cc.rectPointsToPixels(rect); - - var tex = this._batchNode ? this.textureAtlas.texture : this._texture; - if (!tex) - return; - - var atlasWidth = tex.pixelsWidth; - var atlasHeight = tex.pixelsHeight; - - var left, right, top, bottom, tempSwap, locQuad = this._quad; - if (this._rectRotated) { - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (2 * rect.x + 1) / (2 * atlasWidth); - right = left + (rect.height * 2 - 2) / (2 * atlasWidth); - top = (2 * rect.y + 1) / (2 * atlasHeight); - bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight); - } else { - left = rect.x / atlasWidth; - right = (rect.x + rect.height) / atlasWidth; - top = rect.y / atlasHeight; - bottom = (rect.y + rect.width) / atlasHeight; - }// CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if (this._flippedX) { - tempSwap = top; - top = bottom; - bottom = tempSwap; - } - - if (this._flippedY) { - tempSwap = left; - left = right; - right = tempSwap; - } - - locQuad.bl.texCoords.u = left; - locQuad.bl.texCoords.v = top; - locQuad.br.texCoords.u = left; - locQuad.br.texCoords.v = bottom; - locQuad.tl.texCoords.u = right; - locQuad.tl.texCoords.v = top; - locQuad.tr.texCoords.u = right; - locQuad.tr.texCoords.v = bottom; - } else { - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (2 * rect.x + 1) / (2 * atlasWidth); - right = left + (rect.width * 2 - 2) / (2 * atlasWidth); - top = (2 * rect.y + 1) / (2 * atlasHeight); - bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight); - } else { - left = rect.x / atlasWidth; - right = (rect.x + rect.width) / atlasWidth; - top = rect.y / atlasHeight; - bottom = (rect.y + rect.height) / atlasHeight; - } // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL - - if (this._flippedX) { - tempSwap = left; - left = right; - right = tempSwap; - } - - if (this._flippedY) { - tempSwap = top; - top = bottom; - bottom = tempSwap; - } - - locQuad.bl.texCoords.u = left; - locQuad.bl.texCoords.v = bottom; - locQuad.br.texCoords.u = right; - locQuad.br.texCoords.v = bottom; - locQuad.tl.texCoords.u = left; - locQuad.tl.texCoords.v = top; - locQuad.tr.texCoords.u = right; - locQuad.tr.texCoords.v = top; - } - this._quadDirty = true; + _changeRectWithTexture: function(rect){ + if(!rect || (!rect.width && !rect.height)) return; + var textureRect = this.getTextureRect(); + if(textureRect.height || textureRect.width) return; + rect.x = rect.x || 0; + rect.y = rect.y || 0; + rect.width = rect.width || 0; + rect.height = rect.height || 0; + this.setTextureRect(rect); }, - /** - * draw sprite to canvas - * @function - */ - draw: null + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.Sprite.CanvasRenderCmd(this); + else + return new cc.Sprite.WebGLRenderCmd(this); + } }); /** * Create a sprite with image path or frame name or texture or spriteFrame. - * @constructs + * @deprecated since v3.0, please use new construction instead + * @see cc.Sprite * @param {String|cc.SpriteFrame|HTMLImageElement|cc.Texture2D} fileName The string which indicates a path to image file, e.g., "scene1/monster.png". * @param {cc.Rect} rect Only the contents inside rect of pszFileName's texture will be applied for this sprite. + * @param {Boolean} [rotated] Whether or not the texture rectangle is rotated. * @return {cc.Sprite} A valid sprite object - * @example - * - * 1.Create a sprite with image path and rect - * var sprite1 = cc.Sprite.create("res/HelloHTML5World.png"); - * var sprite2 = cc.Sprite.create("res/HelloHTML5World.png",cc.rect(0,0,480,320)); - * - * 2.Create a sprite with a sprite frame name. Must add "#" before frame name. - * var sprite = cc.Sprite.create('#grossini_dance_01.png'); - * - * 3.Create a sprite with a sprite frame - * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); - * var sprite = cc.Sprite.create(spriteFrame); - * - * 4.Create a sprite with an exsiting texture contained in a CCTexture2D object - * After creation, the rect will be the size of the texture, and the offset will be (0,0). - * var texture = cc.textureCache.addImage("HelloHTML5World.png"); - * var sprite1 = cc.Sprite.create(texture); - * var sprite2 = cc.Sprite.create(texture, cc.rect(0,0,480,320)); - * */ -cc.Sprite.create = function (fileName, rect) { - return new cc.Sprite(fileName, rect); +cc.Sprite.create = function (fileName, rect, rotated) { + return new cc.Sprite(fileName, rect, rotated); }; +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.Sprite + * @function + */ +cc.Sprite.createWithTexture = cc.Sprite.create; + +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.Sprite + * @function + */ +cc.Sprite.createWithSpriteFrameName = cc.Sprite.create; +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.Sprite + * @function + */ +cc.Sprite.createWithSpriteFrame = cc.Sprite.create; /** * cc.Sprite invalid index on the cc.SpriteBatchNode * @constant - * @type Number + * @type {Number} */ cc.Sprite.INDEX_NOT_INITIALIZED = -1; +cc.EventHelper.prototype.apply(cc.Sprite.prototype); -if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - - var _p = cc.Sprite.prototype; - - _p._spriteFrameLoadedCallback = function(spriteFrame){ - var _t = this; - _t.setNodeDirty(true); - _t.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); - var curColor = _t.color; - if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255) - _t._changeTextureColor(); - - _t._callLoadedEventCallbacks(); - }; - - _p.setOpacityModifyRGB = function (modify) { - if (this._opacityModifyRGB !== modify) { - this._opacityModifyRGB = modify; - this.setNodeDirty(true); - } - }; - - _p.updateDisplayedOpacity = function (parentOpacity) { - cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); - this._setNodeDirtyForCache(); - }; - - _p.ctor = function (fileName, rect) { - var self = this; - cc.NodeRGBA.prototype.ctor.call(self); - self._shouldBeHidden = false; - self._offsetPosition = cc.p(0, 0); - self._unflippedOffsetPositionFromCenter = cc.p(0, 0); - self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; - self._rect = cc.rect(0, 0, 0, 0); - - self._newTextureWhenChangeColor = false; - self._textureLoaded = true; - self._textureRect_Canvas = {x: 0, y: 0, width: 0, height:0, validRect: false}; - self._drawSize_Canvas = cc.size(0, 0); - - self._softInit(fileName, rect); - }; - - _p.setBlendFunc = function (src, dst) { - var locBlendFunc = this._blendFunc; - if (dst === undefined) { - locBlendFunc.src = src.src; - locBlendFunc.dst = src.dst; - } else { - locBlendFunc.src = src; - locBlendFunc.dst = dst; - } - this._isLighterMode = (locBlendFunc && - (( locBlendFunc.src == cc.SRC_ALPHA && locBlendFunc.dst == cc.ONE) || (locBlendFunc.src == cc.ONE && locBlendFunc.dst == cc.ONE))); - }; - - _p.init = function () { - var _t = this; - if (arguments.length > 0) - return _t.initWithFile(arguments[0], arguments[1]); - - cc.NodeRGBA.prototype.init.call(_t); - _t.dirty = _t._recursiveDirty = false; - _t._opacityModifyRGB = true; - - _t._blendFunc.src = cc.BLEND_SRC; - _t._blendFunc.dst = cc.BLEND_DST; - - // update texture (calls _updateBlendFunc) - _t.texture = null; - _t._textureLoaded = true; - _t._flippedX = _t._flippedY = false; - - // default transform anchor: center - _t.anchorX = 0.5; - _t.anchorY = 0.5; - - // zwoptex default values - _t._offsetPosition.x = 0; - _t._offsetPosition.y = 0; - _t._hasChildren = false; - - // updated in "useSelfRender" - // Atlas: TexCoords - _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); - return true; - }; - - _p.initWithTexture = function (texture, rect, rotated) { - var _t = this; - var argnum = arguments.length; - - cc.assert(argnum != 0, cc._LogInfos.CCSpriteBatchNode_initWithTexture); - - rotated = rotated || false; - - if (!cc.NodeRGBA.prototype.init.call(_t)) - return false; - - _t._batchNode = null; - - _t._recursiveDirty = false; - _t.dirty = false; - _t._opacityModifyRGB = true; - - _t._blendFunc.src = cc.BLEND_SRC; - _t._blendFunc.dst = cc.BLEND_DST; - - _t._flippedX = _t._flippedY = false; - - // default transform anchor: center - _t.anchorX = 0.5; - _t.anchorY = 0.5; - - // zwoptex default values - _t._offsetPosition.x = 0; - _t._offsetPosition.y = 0; - _t._hasChildren = false; - - var locTextureLoaded = texture.isLoaded(); - _t._textureLoaded = locTextureLoaded; - - if (!locTextureLoaded) { - _t._rectRotated = rotated || false; - if (rect) { - _t._rect.x = rect.x; - _t._rect.y = rect.y; - _t._rect.width = rect.width; - _t._rect.height = rect.height; - } - texture.addLoadedEventListener(_t._textureLoadedCallback, _t); - return true; - } - - if (!rect) { - rect = cc.rect(0, 0, texture.width, texture.height); - } - _t._originalTexture = texture; - - _t.texture = texture; - _t.setTextureRect(rect, rotated); - - // by default use "Self Render". - // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" - _t.batchNode = null; - return true; - }; - - _p._textureLoadedCallback = function (sender) { - var _t = this; - if(_t._textureLoaded) - return; - - _t._textureLoaded = true; - var locRect = _t._rect; - if (!locRect) { - locRect = cc.rect(0, 0, sender.width, sender.height); - } else if (cc._rectEqualToZero(locRect)) { - locRect.width = sender.width; - locRect.height = sender.height; - } - _t._originalTexture = sender; - - _t.texture = sender; - _t.setTextureRect(locRect, _t._rectRotated); - - // by default use "Self Render". - // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" - _t.batchNode = _t._batchNode; - _t._callLoadedEventCallbacks(); - }; - - _p.setTextureRect = function (rect, rotated, untrimmedSize) { - var _t = this; - _t._rectRotated = rotated || false; - _t.setContentSize(untrimmedSize || rect); - - _t.setVertexRect(rect); - - var locTextureRect = _t._textureRect_Canvas, scaleFactor = cc.contentScaleFactor(); - locTextureRect.x = 0 | (rect.x * scaleFactor); - locTextureRect.y = 0 | (rect.y * scaleFactor); - locTextureRect.width = 0 | (rect.width * scaleFactor); - locTextureRect.height = 0 | (rect.height * scaleFactor); - locTextureRect.validRect = !(locTextureRect.width === 0 || locTextureRect.height === 0 || locTextureRect.x < 0 || locTextureRect.y < 0); - - var relativeOffset = _t._unflippedOffsetPositionFromCenter; - if (_t._flippedX) - relativeOffset.x = -relativeOffset.x; - if (_t._flippedY) - relativeOffset.y = -relativeOffset.y; - _t._offsetPosition.x = relativeOffset.x + (_t._contentSize.width - _t._rect.width) / 2; - _t._offsetPosition.y = relativeOffset.y + (_t._contentSize.height - _t._rect.height) / 2; - - // rendering using batch node - if (_t._batchNode) { - // update dirty, don't update _recursiveDirty - _t.dirty = true; - } - }; - - _p.updateTransform = function () { - var _t = this; - //cc.assert(_t._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode"); - - // recaculate matrix only if it is dirty - if (_t.dirty) { - // If it is not visible, or one of its ancestors is not visible, then do nothing: - var locParent = _t._parent; - if (!_t._visible || ( locParent && locParent != _t._batchNode && locParent._shouldBeHidden)) { - _t._shouldBeHidden = true; - } else { - _t._shouldBeHidden = false; - - if (!locParent || locParent == _t._batchNode) { - _t._transformToBatch = _t.nodeToParentTransform(); - } else { - //cc.assert(_t._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); - _t._transformToBatch = cc.AffineTransformConcat(_t.nodeToParentTransform(), locParent._transformToBatch); - } - } - _t._recursiveDirty = false; - _t.dirty = false; - } - - // recursively iterate over children - if (_t._hasChildren) - _t._arrayMakeObjectsPerformSelector(_t._children, cc.Node.StateCallbackType.updateTransform); - }; - - _p.addChild = function (child, localZOrder, tag) { - - cc.assert(child, cc._LogInfos.CCSpriteBatchNode_addChild_2); - - if (localZOrder == null) - localZOrder = child._localZOrder; - if (tag == null) - tag = child.tag; - - //cc.Node already sets isReorderChildDirty_ so this needs to be after batchNode check - cc.NodeRGBA.prototype.addChild.call(this, child, localZOrder, tag); - this._hasChildren = true; - }; - - _p.setOpacity = function (opacity) { - cc.NodeRGBA.prototype.setOpacity.call(this, opacity); - this._setNodeDirtyForCache(); - }; - - _p.setColor = function (color3) { - var _t = this; - var curColor = _t.color; - if ((curColor.r === color3.r) && (curColor.g === color3.g) && (curColor.b === color3.b) && (curColor.a === color3.a)) - return; - - cc.NodeRGBA.prototype.setColor.call(_t, color3); - _t._changeTextureColor(); - _t._setNodeDirtyForCache(); - }; - - _p.updateDisplayedColor = function (parentColor) { - var _t = this; - var oldColor = _t.color; - cc.NodeRGBA.prototype.updateDisplayedColor.call(_t, parentColor); - var newColor = _t._displayedColor; - if ((oldColor.r === newColor.r) && (oldColor.g === newColor.g) && (oldColor.b === newColor.b)) - return; - _t._changeTextureColor(); - _t._setNodeDirtyForCache(); - }; - - _p.setSpriteFrame = function (newFrame) { - var _t = this; - if(typeof(newFrame) == "string"){ - newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); - - cc.assert(newFrame, cc._LogInfos.CCSpriteBatchNode_setSpriteFrame) - - } - - _t.setNodeDirty(true); - - var frameOffset = newFrame.getOffset(); - _t._unflippedOffsetPositionFromCenter.x = frameOffset.x; - _t._unflippedOffsetPositionFromCenter.y = frameOffset.y; - - // update rect - _t._rectRotated = newFrame.isRotated(); - - var pNewTexture = newFrame.getTexture(); - var locTextureLoaded = newFrame.textureLoaded(); - if (!locTextureLoaded) { - _t._textureLoaded = false; - newFrame.addLoadedEventListener(function (sender) { - _t._textureLoaded = true; - var locNewTexture = sender.getTexture(); - if (locNewTexture != _t._texture) - _t.texture = locNewTexture; - _t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); - _t._callLoadedEventCallbacks(); - }, _t); - } - // update texture before updating texture rect - if (pNewTexture != _t._texture) - _t.texture = pNewTexture; - - if (_t._rectRotated) - _t._originalTexture = pNewTexture; - - _t.setTextureRect(newFrame.getRect(), _t._rectRotated, newFrame.getOriginalSize()); - _t._colorized = false; - if (locTextureLoaded) { - var curColor = _t.color; - if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255) - _t._changeTextureColor(); - } - }; - - _p.isFrameDisplayed = function (frame) { - if (frame.getTexture() != this._texture) - return false; - return cc.rectEqualToRect(frame.getRect(), this._rect); - }; - - _p.setBatchNode = function (spriteBatchNode) { - var _t = this; - _t._batchNode = spriteBatchNode; // weak reference - - // self render - if (!_t._batchNode) { - _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED; - _t.textureAtlas = null; - _t._recursiveDirty = false; - _t.dirty = false; - } else { - // using batch - _t._transformToBatch = cc.AffineTransformIdentity(); - _t.textureAtlas = _t._batchNode.textureAtlas; // weak ref - } - }; - - - _p.setTexture = function (texture) { - var _t = this; - if(texture && (typeof(texture) === "string")){ - texture = cc.textureCache.addImage(texture); - _t.setTexture(texture); - - //TODO - var size = texture.getContentSize(); - _t.setTextureRect(cc.rect(0,0, size.width, size.height)); - return; - } - - // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet - - cc.assert(!texture || texture instanceof cc.Texture2D, cc._LogInfos.CCSpriteBatchNode_setTexture); - - if (_t._texture != texture) { - if (texture && texture.getHtmlElementObj() instanceof HTMLImageElement) { - _t._originalTexture = texture; - } - _t._texture = texture; - } - }; - - _p.draw = function (ctx) { - var _t = this; - if (!_t._textureLoaded) - return; - - var context = ctx || cc._renderContext; - if (_t._isLighterMode) - context.globalCompositeOperation = 'lighter'; - - var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); - - context.globalAlpha = _t._displayedOpacity / 255; - var locRect = _t._rect, locContentSize = _t._contentSize, locOffsetPosition = _t._offsetPosition, locDrawSizeCanvas = _t._drawSize_Canvas; - var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = _t._textureRect_Canvas; - locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX; - locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY; - - if (_t._flippedX || _t._flippedY) { - context.save(); - if (_t._flippedX) { - flipXOffset = -locOffsetPosition.x - locRect.width; - context.scale(-1, 1); - } - if (_t._flippedY) { - flipYOffset = locOffsetPosition.y; - context.scale(1, -1); - } - } - - flipXOffset *= locEGL_ScaleX; - flipYOffset *= locEGL_ScaleY; - - if (_t._texture && locTextureCoord.validRect) { - var image = _t._texture.getHtmlElementObj(); - if (_t._colorized) { - context.drawImage(image, - 0, 0, locTextureCoord.width, locTextureCoord.height, - flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height); - } else { - context.drawImage(image, - locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height, - flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height); - } - } else if (locContentSize.width !== 0) { - var curColor = _t.color; - context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"; - context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY); - } - - if (cc.SPRITE_DEBUG_DRAW === 1 || _t._showNode) { - // draw bounding box - context.strokeStyle = "rgba(0,255,0,1)"; - flipXOffset /= locEGL_ScaleX; - flipYOffset /= locEGL_ScaleY; - flipYOffset = -flipYOffset; - var vertices1 = [cc.p(flipXOffset, flipYOffset), - cc.p(flipXOffset + locRect.width, flipYOffset), - cc.p(flipXOffset + locRect.width, flipYOffset - locRect.height), - cc.p(flipXOffset, flipYOffset - locRect.height)]; - cc._drawingUtil.drawPoly(vertices1, 4, true); - } else if (cc.SPRITE_DEBUG_DRAW === 2) { - // draw texture box - context.strokeStyle = "rgba(0,255,0,1)"; - var drawRect = _t._rect; - flipYOffset = -flipYOffset; - var vertices2 = [cc.p(flipXOffset, flipYOffset), cc.p(flipXOffset + drawRect.width, flipYOffset), - cc.p(flipXOffset + drawRect.width, flipYOffset - drawRect.height), cc.p(flipXOffset, flipYOffset - drawRect.height)]; - cc._drawingUtil.drawPoly(vertices2, 4, true); - } - if (_t._flippedX || _t._flippedY) - context.restore(); - cc.g_NumberOfDraws++; - }; - - delete _p; -} else { - _tmp.WebGLSprite(); - delete _tmp.WebGLSprite; -} -_tmp.PrototypeSprite(); -delete _tmp.PrototypeSprite; - +cc.assert(cc.isFunction(cc._tmp.PrototypeSprite), cc._LogInfos.MissingFile, "SpritesPropertyDefine.js"); +cc._tmp.PrototypeSprite(); +delete cc._tmp.PrototypeSprite; \ No newline at end of file diff --git a/cocos2d/core/sprites/CCSpriteBatchNode.js b/cocos2d/core/sprites/CCSpriteBatchNode.js index 33a1c656a8..a67c4cac19 100644 --- a/cocos2d/core/sprites/CCSpriteBatchNode.js +++ b/cocos2d/core/sprites/CCSpriteBatchNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,18 +24,9 @@ THE SOFTWARE. ****************************************************************************/ -/** - * @constant - * @type Number - */ -cc.DEFAULT_SPRITE_BATCH_CAPACITY = 29; /** *

- * In Canvas render mode ,cc.SpriteBatchNodeCanvas is like a normal node: if it contains children.
- * If its _useCache is set to true, it can cache the result that all children of SpriteBatchNode to a canvas
- * (often known as "batch draw").
- *
* A cc.SpriteBatchNode can reference one and only one texture (one image file, one texture atlas).
* Only the cc.Sprites that are contained in that texture can be added to the cc.SpriteBatchNode.
* All cc.Sprites added to a cc.SpriteBatchNode are drawn in one WebGL draw call.
@@ -50,21 +41,43 @@ cc.DEFAULT_SPRITE_BATCH_CAPACITY = 29; * @class * @extends cc.Node * + * @param {String|cc.Texture2D} fileImage + * @param {Number} capacity + * @example + * + * // 1. create a SpriteBatchNode with image path + * var spriteBatchNode = new cc.SpriteBatchNode("res/animations/grossini.png", 50); + * + * // 2. create a SpriteBatchNode with texture + * var texture = cc.textureCache.addImage("res/animations/grossini.png"); + * var spriteBatchNode = new cc.SpriteBatchNode(texture,50); + * * @property {cc.TextureAtlas} textureAtlas - The texture atlas * @property {Array} descendants - <@readonly> Descendants of sprite batch node - * - * @example - * //create a SpriteBatchNode - * var parent2 = cc.SpriteBatchNode.create("res/animations/grossini.png", 50); */ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ - textureAtlas: null, - _blendFunc: null, // all descendants: chlidren, gran children, etc... _descendants: null, _className: "SpriteBatchNode", + ctor: function (fileImage, capacity) { + cc.Node.prototype.ctor.call(this); + this._descendants = []; + this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); + + var texture2D; + capacity = capacity || cc.SpriteBatchNode.DEFAULT_CAPACITY; + if (cc.isString(fileImage)) { + texture2D = cc.textureCache.getTextureForKey(fileImage); + if (!texture2D) + texture2D = cc.textureCache.addImage(fileImage); + }else if (fileImage instanceof cc.Texture2D) + texture2D = fileImage; + + texture2D && this.initWithTexture(texture2D, capacity); + }, + /** *

* This is the opposite of "addQuadFromSprite.
@@ -76,7 +89,6 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @return {cc.SpriteBatchNode} */ addSpriteWithoutQuad: function (child, z, aTag) { - cc.assert(child, cc._LogInfos.SpriteBatchNode_addSpriteWithoutQuad_2); if (!(child instanceof cc.Sprite)) { @@ -88,12 +100,12 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ child.atlasIndex = z; // XXX: optimize with a binary search - var i = 0, locDescendants = this._descendants; + var i = 0, len, locDescendants = this._descendants; if (locDescendants && locDescendants.length > 0) { - for (var index = 0; index < locDescendants.length; index++) { - var obj = locDescendants[index]; + for (i = 0, len = locDescendants.length; i < len; i++) { + var obj = locDescendants[i]; if (obj && (obj.atlasIndex >= z)) - ++i; + break; } } locDescendants.splice(i, 0, child); @@ -112,7 +124,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @return {cc.TextureAtlas} */ getTextureAtlas: function () { - return this.textureAtlas; + return this._renderCmd.getTextureAtlas(); }, /** @@ -120,9 +132,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @param {cc.TextureAtlas} textureAtlas */ setTextureAtlas: function (textureAtlas) { - if (textureAtlas != this.textureAtlas) { - this.textureAtlas = textureAtlas; - } + this._renderCmd.getTextureAtlas(textureAtlas); }, /** @@ -130,67 +140,59 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @return {Array} */ getDescendants: function () { - return this._descendants; + return this._descendants; }, /** *

- * initializes a cc.SpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children.
+ * Initializes a cc.SpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children.
* The capacity will be increased in 33% in runtime if it run out of space.
- * The file will be loaded using the TextureMgr. + * The file will be loaded using the TextureMgr.
+ * Please pass parameters to constructor to initialize the sprite batch node, do not call this function yourself. *

* @param {String} fileImage * @param {Number} capacity * @return {Boolean} */ initWithFile: function (fileImage, capacity) { - var texture2D = cc.textureCache.textureForKey(fileImage); + var texture2D = cc.textureCache.getTextureForKey(fileImage); if (!texture2D) texture2D = cc.textureCache.addImage(fileImage); return this.initWithTexture(texture2D, capacity); }, _setNodeDirtyForCache: function () { - this._cacheDirty = true; + if(this._renderCmd && this._renderCmd._setNodeDirtyForCache) + this._renderCmd._setNodeDirtyForCache(); }, /** *

* initializes a cc.SpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and a capacity of children.
* The capacity will be increased in 33% in runtime if it run out of space.
- * The file will be loaded using the TextureMgr. + * The file will be loaded using the TextureMgr.
+ * Please pass parameters to constructor to initialize the sprite batch node, do not call this function yourself. *

* @param {String} fileImage * @param {Number} capacity * @return {Boolean} */ init: function (fileImage, capacity) { - var texture2D = cc.textureCache.textureForKey(fileImage); + var texture2D = cc.textureCache.getTextureForKey(fileImage); if (!texture2D) texture2D = cc.textureCache.addImage(fileImage); return this.initWithTexture(texture2D, capacity); }, /** - * increase Atlas Capacity + * Increase Atlas Capacity */ increaseAtlasCapacity: function () { - // if we're going beyond the current TextureAtlas's capacity, - // all the previously initialized sprites will need to redo their texture coords - // this is likely computationally expensive - var locCapacity = this.textureAtlas.capacity; - var quantity = Math.floor((locCapacity + 1) * 4 / 3); - - cc.log(cc._LogInfos.SpriteBatchNode_increaseAtlasCapacity, locCapacity, quantity); - - if (!this.textureAtlas.resizeCapacity(quantity)) { - // serious problems - cc.log(cc._LogInfos.SpriteBatchNode_increaseAtlasCapacity_2); - } + this._renderCmd.increaseAtlasCapacity(); }, /** - * removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter. + * Removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter. * @warning Removing a child from a cc.SpriteBatchNode is very slow * @param {Number} index * @param {Boolean} doCleanup @@ -200,7 +202,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, /** - * rebuild index in order for child + * Rebuild index in order for child * @param {cc.Sprite} pobParent * @param {Number} index * @return {Number} @@ -210,57 +212,54 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ if (children && children.length > 0) { for (var i = 0; i < children.length; i++) { var obj = children[i]; - if (obj && (obj.zIndex < 0)) { + if (obj && (obj.zIndex < 0)) index = this.rebuildIndexInOrder(obj, index); - } } } // ignore self (batch node) - if (!pobParent == this) { + if (!pobParent === this) { pobParent.atlasIndex = index; index++; } if (children && children.length > 0) { for (i = 0; i < children.length; i++) { obj = children[i]; - if (obj && (obj.zIndex >= 0)) { + if (obj && (obj.zIndex >= 0)) index = this.rebuildIndexInOrder(obj, index); - } } } return index; }, /** - * get highest atlas index in child + * Returns highest atlas index in child * @param {cc.Sprite} sprite * @return {Number} */ highestAtlasIndexInChild: function (sprite) { var children = sprite.children; - if (!children || children.length == 0) + if (!children || children.length === 0) return sprite.atlasIndex; else return this.highestAtlasIndexInChild(children[children.length - 1]); }, /** - * get lowest atlas index in child + * Returns lowest atlas index in child * @param {cc.Sprite} sprite * @return {Number} */ lowestAtlasIndexInChild: function (sprite) { var children = sprite.children; - - if (!children || children.length == 0) + if (!children || children.length === 0) return sprite.atlasIndex; else return this.lowestAtlasIndexInChild(children[children.length - 1]); }, /** - * get atlas index for child + * Returns atlas index for child * @param {cc.Sprite} sprite * @param {Number} nZ * @return {Number} @@ -271,21 +270,21 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ var childIndex = brothers.indexOf(sprite); // ignore parent Z if parent is spriteSheet - var ignoreParent = selParent == this; + var ignoreParent = selParent === this; var previous = null; if (childIndex > 0 && childIndex < cc.UINT_MAX) previous = brothers[childIndex - 1]; // first child of the sprite sheet if (ignoreParent) { - if (childIndex == 0) + if (childIndex === 0) return 0; return this.highestAtlasIndexInChild(previous) + 1; } // parent is a cc.Sprite, so, it must be taken into account // first child of an cc.Sprite ? - if (childIndex == 0) { + if (childIndex === 0) { // less than parent and brothers if (nZ < 0) return selParent.atlasIndex; @@ -310,7 +309,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, /** - * set the source blending function for the texture + * Sets the source and destination blending function for the texture * @param {Number | cc.BlendFunc} src * @param {Number} dst */ @@ -322,40 +321,37 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, /** - * returns the blending function used for the texture + * Returns the blending function used for the texture * @return {cc.BlendFunc} */ getBlendFunc: function () { - return this._blendFunc; + return new cc.BlendFunc(this._blendFunc.src,this._blendFunc.dst); }, /** - * (override reorderChild of cc.Node) + * Reorder children (override reorderChild of cc.Node) * @override * @param {cc.Sprite} child * @param {Number} zOrder */ reorderChild: function (child, zOrder) { - cc.assert(child, cc._LogInfos.SpriteBatchNode_reorderChild_2); - if (this._children.indexOf(child) === -1) { cc.log(cc._LogInfos.SpriteBatchNode_reorderChild); return; } - if (zOrder === child.zIndex) return; //set the z-order and sort later cc.Node.prototype.reorderChild.call(this, child, zOrder); - this.setNodeDirty(); + //this.setNodeDirty(); }, /** - * remove child from cc.SpriteBatchNode (override removeChild of cc.Node) + * Removes a child from cc.SpriteBatchNode (override removeChild of cc.Node) * @param {cc.Sprite} child - * @param cleanup + * @param {Boolean} cleanup */ removeChild: function (child, cleanup) { // explicit null handling @@ -371,67 +367,6 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ cc.Node.prototype.removeChild.call(this, child, cleanup); }, - _mvpMatrix: null, - _textureForCanvas: null, - _useCache: false, - _originalTexture: null, - - /** - *

- * Constructor - * creates a cc.SpriteBatchNodeCanvas with a file image (.png, .jpg etc) with a default capacity of 29 children.
- * The capacity will be increased in 33% in runtime if it run out of space.
- * The file will be loaded using the TextureMgr.
- *

- * @function - * @constructor - * @param {String} fileImage - * @param {Number} capacity - * @example - * 1. - * //create a SpriteBatchNode with image path - * var spriteBatchNode = cc.SpriteBatchNode.create("res/animations/grossini.png", 50); - * 2. - * //create a SpriteBatchNode with texture - * var texture = cc.textureCache.addImage("res/animations/grossini.png"); - * var spriteBatchNode = cc.SpriteBatchNode.create(texture,50); - */ - ctor: null, - - _ctorForCanvas: function (fileImage, capacity) { - cc.Node.prototype.ctor.call(this); - - var texture2D; - capacity = capacity || cc.DEFAULT_SPRITE_BATCH_CAPACITY; - if (typeof(fileImage) == "string") { - texture2D = cc.textureCache.textureForKey(fileImage); - if (!texture2D) - texture2D = cc.textureCache.addImage(fileImage); - } - else if (fileImage instanceof cc.Texture2D) - texture2D = fileImage; - - texture2D && this.initWithTexture(texture2D, capacity); - }, - - _ctorForWebGL: function (fileImage, capacity) { - cc.Node.prototype.ctor.call(this); - this._mvpMatrix = new cc.kmMat4(); - - var texture2D; - capacity = capacity || cc.DEFAULT_SPRITE_BATCH_CAPACITY; - if (typeof(fileImage) == "string") { - texture2D = cc.textureCache.textureForKey(fileImage); - if (!texture2D) - texture2D = cc.textureCache.addImage(fileImage); - } - else if (fileImage instanceof cc.Texture2D) - texture2D = fileImage; - - texture2D && this.initWithTexture(texture2D, capacity); - }, - - /** *

* Updates a quad at a certain index into the texture atlas. The CCSprite won't be added into the children array.
@@ -442,70 +377,24 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @param {cc.Sprite} sprite * @param {Number} index */ - updateQuadFromSprite: null, - - _updateQuadFromSpriteForCanvas: function (sprite, index) { - + updateQuadFromSprite: function (sprite, index) { cc.assert(sprite, cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite_2); - if (!(sprite instanceof cc.Sprite)) { cc.log(cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite); return; } + this._renderCmd.checkAtlasCapacity(); // // update the quad directly. Don't add the sprite to the scene graph // sprite.batchNode = this; sprite.atlasIndex = index; - sprite.dirty = true; // UpdateTransform updates the textureAtlas quad sprite.updateTransform(); }, - _updateQuadFromSpriteForWebGL: function (sprite, index) { - - cc.assert(sprite, cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite); - - if (!(sprite instanceof cc.Sprite)) { - cc.log(cc._LogInfos.CCSpriteBatchNode_updateQuadFromSprite); - return; - } - - // make needed room - var locCapacity = this.textureAtlas.capacity; - while (index >= locCapacity || locCapacity == this.textureAtlas.totalQuads) { - this.increaseAtlasCapacity(); - } - - // - // update the quad directly. Don't add the sprite to the scene graph - // - sprite.batchNode = this; - sprite.atlasIndex = index; - - sprite.dirty = true; - // UpdateTransform updates the textureAtlas quad - sprite.updateTransform(); - }, - - _swap: function (oldIndex, newIndex) { - var locDescendants = this._descendants; - var locTextureAtlas = this.textureAtlas; - var quads = locTextureAtlas.quads; - var tempItem = locDescendants[oldIndex]; - var tempIteQuad = cc.V3F_C4B_T2F_QuadCopy(quads[oldIndex]); - - //update the index of other swapped item - locDescendants[newIndex].atlasIndex = oldIndex; - locDescendants[oldIndex] = locDescendants[newIndex]; - - locTextureAtlas.updateQuad(quads[newIndex], oldIndex); - locDescendants[newIndex] = tempItem; - locTextureAtlas.updateQuad(tempIteQuad, newIndex); - }, - /** *

* Inserts a quad at a certain index into the texture atlas. The cc.Sprite won't be added into the children array.
@@ -516,16 +405,13 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ * @param {cc.Sprite} sprite * @param {Number} index */ - insertQuadFromSprite: null, - - _insertQuadFromSpriteForCanvas: function (sprite, index) { - + insertQuadFromSprite: function (sprite, index) { cc.assert(sprite, cc._LogInfos.CCSpriteBatchNode_insertQuadFromSprite_2); - if (!(sprite instanceof cc.Sprite)) { cc.log(cc._LogInfos.CCSpriteBatchNode_insertQuadFromSprite); return; } + this._renderCmd.insertQuad(sprite, index); // // update the quad directly. Don't add the sprite to the scene graph @@ -537,150 +423,41 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ // XXX: so, it should be AFTER the insertQuad sprite.dirty = true; sprite.updateTransform(); - this._children.splice(index, 0, sprite); - }, - - _insertQuadFromSpriteForWebGL: function (sprite, index) { - - cc.assert(sprite, cc._LogInfos.Sprite_insertQuadFromSprite_2); - - if (!(sprite instanceof cc.Sprite)) { - cc.log(cc._LogInfos.Sprite_insertQuadFromSprite); - return; - } - - // make needed room - var locTextureAtlas = this.textureAtlas; - while (index >= locTextureAtlas.capacity || locTextureAtlas.capacity === locTextureAtlas.totalQuads) - this.increaseAtlasCapacity(); - - // - // update the quad directly. Don't add the sprite to the scene graph - // - sprite.batchNode = this; - sprite.atlasIndex = index; - locTextureAtlas.insertQuad(sprite.quad, index); - - // XXX: updateTransform will update the textureAtlas too, using updateQuad. - // XXX: so, it should be AFTER the insertQuad - sprite.dirty = true; - sprite.updateTransform(); - }, - - _updateAtlasIndex: function (sprite, curIndex) { - var count = 0; - var pArray = sprite.children; - if (pArray) - count = pArray.length; - - var oldIndex = 0; - if (count === 0) { - oldIndex = sprite.atlasIndex; - sprite.atlasIndex = curIndex; - sprite.arrivalOrder = 0; - if (oldIndex != curIndex) - this._swap(oldIndex, curIndex); - curIndex++; - } else { - var needNewIndex = true; - if (pArray[0].zIndex >= 0) { - //all children are in front of the parent - oldIndex = sprite.atlasIndex; - sprite.atlasIndex = curIndex; - sprite.arrivalOrder = 0; - if (oldIndex != curIndex) - this._swap(oldIndex, curIndex); - curIndex++; - needNewIndex = false; - } - for (var i = 0; i < pArray.length; i++) { - var child = pArray[i]; - if (needNewIndex && child.zIndex >= 0) { - oldIndex = sprite.atlasIndex; - sprite.atlasIndex = curIndex; - sprite.arrivalOrder = 0; - if (oldIndex != curIndex) { - this._swap(oldIndex, curIndex); - } - curIndex++; - needNewIndex = false; - } - curIndex = this._updateAtlasIndex(child, curIndex); - } - - if (needNewIndex) { - //all children have a zOrder < 0) - oldIndex = sprite.atlasIndex; - sprite.atlasIndex = curIndex; - sprite.arrivalOrder = 0; - if (oldIndex != curIndex) { - this._swap(oldIndex, curIndex); - } - curIndex++; - } - } - - return curIndex; - }, - - _updateBlendFunc: function () { - if (!this.textureAtlas.texture.hasPremultipliedAlpha()) { - this._blendFunc.src = cc.SRC_ALPHA; - this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; - } + this._renderCmd.cutting(sprite, index); }, /** *

- * initializes a CCSpriteBatchNode with a texture2d and capacity of children.
- * The capacity will be increased in 33% in runtime if it run out of space. + * Initializes a cc.SpriteBatchNode with a texture2d and capacity of children.
+ * The capacity will be increased in 33% in runtime if it run out of space.
+ * Please pass parameters to constructor to initialize the sprite batch node, do not call this function yourself. *

* @function * @param {cc.Texture2D} tex * @param {Number} [capacity] * @return {Boolean} */ - initWithTexture: null, - - _initWithTextureForCanvas: function (tex, capacity) { - this._children = []; - this._descendants = []; - - this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); - - this._originalTexture = tex; - this._textureForCanvas = tex; - return true; - }, - - _initWithTextureForWebGL: function (tex, capacity) { - this._children = []; - this._descendants = []; + initWithTexture: function (tex, capacity) { + this._children.length = 0; + this._descendants.length = 0; - this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); - capacity = capacity || cc.DEFAULT_SPRITE_BATCH_CAPACITY; - this.textureAtlas = new cc.TextureAtlas(); - this.textureAtlas.initWithTexture(tex, capacity); - this._updateBlendFunc(); - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + capacity = capacity || cc.SpriteBatchNode.DEFAULT_CAPACITY; + this._renderCmd.initWithTexture(tex, capacity); return true; }, /** - * add child helper - * @param {cc.Sprite} sprite - * @param {Number} index + * Insert a child + * @param {cc.Sprite} sprite The child sprite + * @param {Number} index The insert index */ insertChild: function (sprite, index) { + //TODO WebGL only ? sprite.batchNode = this; sprite.atlasIndex = index; sprite.dirty = true; - var locTextureAtlas = this.textureAtlas; - if (locTextureAtlas.totalQuads >= locTextureAtlas.capacity) - this.increaseAtlasCapacity(); - - locTextureAtlas.insertQuad(sprite.quad, index); + this._renderCmd.insertQuad(sprite, index); this._descendants.splice(index, 0, sprite); // update indices @@ -691,7 +468,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ } // add children recursively - var locChildren = sprite.children, child; + var locChildren = sprite.children, child, l; if (locChildren) { for (i = 0, l = locChildren.length || 0; i < l; i++) { child = locChildren[i]; @@ -704,40 +481,20 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, /** - * addChild helper, faster than insertChild + * Add child at the end, faster than insert child * @function * @param {cc.Sprite} sprite */ - appendChild: null, - - _appendChildForCanvas: function (sprite) { + appendChild: function (sprite) { this._reorderChildDirty = true; sprite.batchNode = this; sprite.dirty = true; this._descendants.push(sprite); var index = this._descendants.length - 1; - sprite.atlasIndex = index; - // add children recursively - var children = sprite.children; - for (var i = 0, l = children.length || 0; i < l; i++) - this.appendChild(children[i]); - }, - - _appendChildForWebGL: function (sprite) { - this._reorderChildDirty = true; - sprite.batchNode = this; - sprite.dirty = true; - - this._descendants.push(sprite); - var index = this._descendants.length - 1; sprite.atlasIndex = index; - - var locTextureAtlas = this.textureAtlas; - if (locTextureAtlas.totalQuads == locTextureAtlas.capacity) - this.increaseAtlasCapacity(); - locTextureAtlas.insertQuad(sprite.quad, index); + this._renderCmd.insertQuad(sprite, index); // add children recursively var children = sprite.children; @@ -746,49 +503,21 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, /** - * remove sprite from TextureAtlas + * Removes sprite from TextureAtlas * @function * @param {cc.Sprite} sprite */ - removeSpriteFromAtlas: null, - - _removeSpriteFromAtlasForCanvas: function (sprite) { - // Cleanup sprite. It might be reused (issue #569) - sprite.batchNode = null; - var locDescendants = this._descendants; - var index = locDescendants.indexOf(sprite); - if (index != -1) { - locDescendants.splice(index, 1) - - // update all sprites beyond this one - var len = locDescendants.length; - for (; index < len; ++index) { - var s = locDescendants[index]; - s.atlasIndex--; - } - } - - // remove children recursively - var children = sprite.children; - if (children) { - for (var i = 0, l = children.length || 0; i < l; i++) - children[i] && this.removeSpriteFromAtlas(children[i]); - } - }, - - _removeSpriteFromAtlasForWebGL: function (sprite) { - this.textureAtlas.removeQuadAtIndex(sprite.atlasIndex); // remove from TextureAtlas + removeSpriteFromAtlas: function (sprite) { + this._renderCmd.removeQuadAtIndex(sprite.atlasIndex); // Cleanup sprite. It might be reused (issue #569) sprite.batchNode = null; - var locDescendants = this._descendants; var index = locDescendants.indexOf(sprite); - if (index != -1) { + if (index !== -1) { locDescendants.splice(index, 1); // update all sprites beyond this one - var len = locDescendants.length; for (; index < len; ++index) { var s = locDescendants[index]; @@ -805,167 +534,51 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ }, // CCTextureProtocol /** - * Return texture of cc.SpriteBatchNode + * Returns texture of the sprite batch node * @function - * @return {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} + * @return {cc.Texture2D} */ - getTexture: null, - - _getTextureForCanvas: function () { - return this._textureForCanvas; - }, - - _getTextureForWebGL: function () { - return this.textureAtlas.texture; + getTexture: function () { + return this._renderCmd.getTexture(); }, /** - * Texture of cc.SpriteBatchNode setter + * Sets the texture of the sprite batch node. * @function * @param {cc.Texture2D} texture */ - setTexture: null, - - _setTextureForCanvas: function (texture) { - this._textureForCanvas = texture; - var locChildren = this._children; - for (var i = 0; i < locChildren.length; i++) - locChildren[i].texture = texture; - }, - - _setTextureForWebGL: function (texture) { - this.textureAtlas.texture = texture; - this._updateBlendFunc(); + setTexture: function(texture){ + this._renderCmd.setTexture(texture); }, /** - * Don't call visit on it's children ( override visit of cc.Node ) - * @function - * @override - * @param {CanvasRenderingContext2D} ctx - */ - visit: null, - - _visitForCanvas: function (ctx) { - var context = ctx || cc._renderContext; - // quick return if not visible - if (!this._visible) - return; - - context.save(); - this.transform(ctx); - var i, locChildren = this._children; - - if (locChildren) { - this.sortAllChildren(); - for (i = 0; i < locChildren.length; i++) { - if (locChildren[i]) - locChildren[i].visit(context); - } - } - - context.restore(); - }, - - _visitForWebGL: function (ctx) { - var gl = ctx || cc._renderContext; - - // CAREFUL: - // This visit is almost identical to CocosNode#visit - // with the exception that it doesn't call visit on it's children - // - // The alternative is to have a void CCSprite#visit, but - // although this is less mantainable, is faster - // - if (!this._visible) - return; - cc.kmGLPushMatrix(); - var locGrid = this.grid; - if (locGrid && locGrid.isActive()) { - locGrid.beforeDraw(); - this.transformAncestors(); - } - this.sortAllChildren(); - this.transform(gl); - this.draw(gl); - if (locGrid && locGrid.isActive()) - locGrid.afterDraw(this); - cc.kmGLPopMatrix(); - this.arrivalOrder = 0; - }, - - /** - * Add child to cc.SpriteBatchNode (override addChild of cc.Node) + * Add child to the sprite batch node (override addChild of cc.Node) * @function * @override * @param {cc.Sprite} child * @param {Number} [zOrder] * @param {Number} [tag] */ - addChild: null, - - _addChildForCanvas: function (child, zOrder, tag) { - + addChild: function (child, zOrder, tag) { cc.assert(child != null, cc._LogInfos.CCSpriteBatchNode_addChild_3); - if (!(child instanceof cc.Sprite)) { - cc.log(cc._LogInfos.CCSpriteBatchNode_addChild); + if(!this._renderCmd.isValidChild(child)) return; - } zOrder = (zOrder == null) ? child.zIndex : zOrder; tag = (tag == null) ? child.tag : tag; - cc.Node.prototype.addChild.call(this, child, zOrder, tag); this.appendChild(child); - this.setNodeDirty(); - }, - - _addChildForWebGL: function (child, zOrder, tag) { - - cc.assert(child != null, cc._LogInfos.Sprite_addChild_6); - - if (!(child instanceof cc.Sprite)) { - cc.log(cc._LogInfos.Sprite_addChild_4); - return; - } - if (child.texture != this.textureAtlas.texture) { // check cc.Sprite is using the same texture id - cc.log(cc._LogInfos.Sprite_addChild_5); - return; - } - - zOrder = (zOrder == null) ? child.zIndex : zOrder; - tag = (tag == null) ? child.tag : tag; - - cc.Node.prototype.addChild.call(this, child, zOrder, tag); - this.appendChild(child); - this.setNodeDirty(); + //this.setNodeDirty(); }, /** - *

Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter.
- * (override removeAllChildren of cc.Node)

+ * Removes all children from the container and do a cleanup all running actions depending on the cleanup parameter.
+ * (override removeAllChildren of cc.Node) * @function * @param {Boolean} cleanup */ - removeAllChildren: null, - - _removeAllChildrenForCanvas: function (cleanup) { - // Invalidate atlas index. issue #569 - // useSelfRender should be performed on all descendants. issue #1216 - var locDescendants = this._descendants; - if (locDescendants && locDescendants.length > 0) { - for (var i = 0, len = locDescendants.length; i < len; i++) { - if (locDescendants[i]) - locDescendants[i].batchNode = null; - } - } - - cc.Node.prototype.removeAllChildren.call(this, cleanup); - this._descendants.length = 0; - }, - - _removeAllChildrenForWebGL: function (cleanup) { + removeAllChildren: function (cleanup) { // Invalidate atlas index. issue #569 // useSelfRender should be performed on all descendants. issue #1216 var locDescendants = this._descendants; @@ -977,41 +590,13 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ } cc.Node.prototype.removeAllChildren.call(this, cleanup); this._descendants.length = 0; - this.textureAtlas.removeAllQuads(); + this._renderCmd.removeAllQuads(); }, - sortAllChildren: null, - - _sortAllChildrenForCanvas: function () { - if (this._reorderChildDirty) { - var i, j = 0, locChildren = this._children; - var length = locChildren.length, tempChild; - //insertion sort - for (i = 1; i < length; i++) { - var tempItem = locChildren[i]; - j = i - 1; - tempChild = locChildren[j]; - - //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller - while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder || - ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { - locChildren[j + 1] = tempChild; - j = j - 1; - tempChild = locChildren[j]; - } - locChildren[j + 1] = tempItem; - } - - //sorted now check all children - if (locChildren.length > 0) { - //first sort all children recursively based on zOrder - this._arrayMakeObjectsPerformSelector(locChildren, cc.Node.StateCallbackType.sortAllChildren); - } - this._reorderChildDirty = false; - } - }, - - _sortAllChildrenForWebGL: function () { + /** + * Sort all children nodes (override draw of cc.Node) + */ + sortAllChildren: function () { if (this._reorderChildDirty) { var childrenArr = this._children; var i, j = 0, length = childrenArr.length, tempChild; @@ -1023,7 +608,7 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder || - ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { + ( tempItem._localZOrder === tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { childrenArr[j + 1] = tempChild; j = j - 1; tempChild = childrenArr[j]; @@ -1034,72 +619,26 @@ cc.SpriteBatchNode = cc.Node.extend(/** @lends cc.SpriteBatchNode# */{ //sorted now check all children if (childrenArr.length > 0) { //first sort all children recursively based on zOrder - this._arrayMakeObjectsPerformSelector(childrenArr, cc.Node.StateCallbackType.sortAllChildren); - - var index = 0; - //fast dispatch, give every child a new atlasIndex based on their relative zOrder (keep parent -> child relations intact) - // and at the same time reorder descedants and the quads to the right index - for (i = 0; i < childrenArr.length; i++) - index = this._updateAtlasIndex(childrenArr[i], index); + this._arrayMakeObjectsPerformSelector(childrenArr, cc.Node._stateCallbackType.sortAllChildren); + this._renderCmd.updateChildrenAtlasIndex(childrenArr); } this._reorderChildDirty = false; } }, - /** - * draw cc.SpriteBatchNode (override draw of cc.Node) - * @function - */ - draw: null, - - _drawForWebGL: function () { - // Optimization: Fast Dispatch - if (this.textureAtlas.totalQuads === 0) - return; - //cc.nodeDrawSetup(this); - this._shaderProgram.use(); - this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.updateTransform); - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - - this.textureAtlas.drawQuads(); + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.SpriteBatchNode.CanvasRenderCmd(this); + else + return new cc.SpriteBatchNode.WebGLRenderCmd(this); } }); var _p = cc.SpriteBatchNode.prototype; -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _p.ctor = _p._ctorForWebGL; - _p.updateQuadFromSprite = _p._updateQuadFromSpriteForWebGL; - _p.insertQuadFromSprite = _p._insertQuadFromSpriteForWebGL; - _p.initWithTexture = _p._initWithTextureForWebGL; - _p.appendChild = _p._appendChildForWebGL; - _p.removeSpriteFromAtlas = _p._removeSpriteFromAtlasForWebGL; - _p.getTexture = _p._getTextureForWebGL; - _p.setTexture = _p._setTextureForWebGL; - _p.visit = _p._visitForWebGL; - _p.addChild = _p._addChildForWebGL; - _p.removeAllChildren = _p._removeAllChildrenForWebGL; - _p.sortAllChildren = _p._sortAllChildrenForWebGL; - _p.draw = _p._drawForWebGL; -} else { - _p.ctor = _p._ctorForCanvas; - _p.updateQuadFromSprite = _p._updateQuadFromSpriteForCanvas; - _p.insertQuadFromSprite = _p._insertQuadFromSpriteForCanvas; - _p.initWithTexture = _p._initWithTextureForCanvas; - _p.appendChild = _p._appendChildForCanvas; - _p.removeSpriteFromAtlas = _p._removeSpriteFromAtlasForCanvas; - _p.getTexture = _p._getTextureForCanvas; - _p.setTexture = _p._setTextureForCanvas; - _p.visit = _p._visitForCanvas; - _p.removeAllChildren = _p._removeAllChildrenForCanvas; - _p.addChild = _p._addChildForCanvas; - _p.sortAllChildren = _p._sortAllChildrenForCanvas; - _p.draw = cc.Node.prototype.draw; -} - // Override properties cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); +cc.defineGetterSetter(_p, "textureAtlas", _p.getTextureAtlas, _p.setTextureAtlas); // Extended properties /** @expose */ @@ -1107,24 +646,31 @@ _p.descendants; cc.defineGetterSetter(_p, "descendants", _p.getDescendants); +/** + * @constant + * @type Number + */ +cc.SpriteBatchNode.DEFAULT_CAPACITY = 29; + /** *

* creates a cc.SpriteBatchNodeCanvas with a file image (.png, .jpg etc) with a default capacity of 29 children.
* The capacity will be increased in 33% in runtime if it run out of space.
* The file will be loaded using the TextureMgr.
*

+ * @deprecated since v3.0, please use new construction instead + * @see cc.SpriteBatchNode * @param {String|cc.Texture2D} fileImage * @param {Number} capacity * @return {cc.SpriteBatchNode} - * @example - * 1. - * //create a SpriteBatchNode with image path - * var spriteBatchNode = cc.SpriteBatchNode.create("res/animations/grossini.png", 50); - * 2. - * //create a SpriteBatchNode with texture - * var texture = cc.textureCache.addImage("res/animations/grossini.png"); - * var spriteBatchNode = cc.SpriteBatchNode.create(texture,50); */ cc.SpriteBatchNode.create = function (fileImage, capacity) { return new cc.SpriteBatchNode(fileImage, capacity); }; + +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.SpriteBatchNode + * @function + */ +cc.SpriteBatchNode.createWithTexture = cc.SpriteBatchNode.create; \ No newline at end of file diff --git a/cocos2d/core/sprites/CCSpriteBatchNodeCanvasRenderCmd.js b/cocos2d/core/sprites/CCSpriteBatchNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..249486eae9 --- /dev/null +++ b/cocos2d/core/sprites/CCSpriteBatchNodeCanvasRenderCmd.js @@ -0,0 +1,101 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + //SpriteBatchNode's canvas render command + cc.SpriteBatchNode.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + + this._texture = null; + this._originalTexture = null; + }; + + var proto = cc.SpriteBatchNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.SpriteBatchNode.CanvasRenderCmd; + + proto.checkAtlasCapacity = function(){}; + + proto.isValidChild = function(child){ + if (!(child instanceof cc.Sprite)) { + cc.log(cc._LogInfos.Sprite_addChild_4); + return false; + } + return true; + }; + + proto.initWithTexture = function(texture, capacity){ + this._originalTexture = texture; + this._texture = texture; + }; + + proto.insertQuad = function(sprite, index){}; + + proto.increaseAtlasCapacity = function(){}; + + proto.removeQuadAtIndex = function(){}; + + proto.removeAllQuads = function(){}; + + proto.getTexture = function(){ + return this._texture; + }; + + proto.setTexture = function(texture){ + this._texture = texture; + var locChildren = this._node._children; + for (var i = 0; i < locChildren.length; i++) + locChildren[i].setTexture(texture); + }; + + proto.updateChildrenAtlasIndex = function(children){ + this._node._descendants.length = 0; + //update _descendants after sortAllChildren + for (var i = 0, len = children.length; i < len; i++) + this._updateAtlasIndex(children[i]); + }; + + proto._updateAtlasIndex = function (sprite) { + var locDescendants = this._node._descendants; + var pArray = sprite.children, i, len = pArray.length; + for (i = 0; i < len; i++) { + if (pArray[i]._localZOrder < 0) { + locDescendants.push(pArray[i]); + } else + break + } + locDescendants.push(sprite); + for (; i < len; i++) { + locDescendants.push(pArray[i]); + } + }; + + proto.getTextureAtlas = function(){}; + + proto.setTextureAtlas = function(textureAtlas){}; + + proto.cutting = function(sprite, index){ + var node = this._node; + node._children.splice(index, 0, sprite); + } +})(); \ No newline at end of file diff --git a/cocos2d/core/sprites/CCSpriteBatchNodeWebGLRenderCmd.js b/cocos2d/core/sprites/CCSpriteBatchNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..d61973d7e7 --- /dev/null +++ b/cocos2d/core/sprites/CCSpriteBatchNodeWebGLRenderCmd.js @@ -0,0 +1,243 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + //SpriteBatchNode's WebGL render command + cc.SpriteBatchNode.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + + this._textureAtlas = null; + }; + + var proto = cc.SpriteBatchNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.SpriteBatchNode.WebGLRenderCmd; + + proto.isValidChild = function(child){ + if (!(child instanceof cc.Sprite)) { + cc.log(cc._LogInfos.Sprite_addChild_4); + return false; + } + if (child.texture != this.getTexture()) { + cc.log(cc._LogInfos.Sprite_addChild_5); + return false; + } + return true; + }; + + proto.rendering = function () { + var node = this._node; + if (this._textureAtlas.totalQuads === 0) + return; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + node._arrayMakeObjectsPerformSelector(node._children, cc.Node._stateCallbackType.updateTransform); + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + + this._textureAtlas.drawQuads(); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + if (node._parent && node._parent._renderCmd) + this._curLevel = node._parent._renderCmd._curLevel + 1; + + var currentStack = cc.current_stack; + + //optimize performance for javascript + currentStack.stack.push(currentStack.top); + + if(!(this._dirtyFlag & cc.Node._dirtyFlags.transformDirty)) //batchNode's transform must update in visit + this.transform(parentCmd); + this.updateStatus(parentCmd); //because batchNode doesn't visit its children. + currentStack.top = this._stackMatrix; + + node.sortAllChildren(); + + cc.renderer.pushRenderCommand(this); + + this._dirtyFlag = 0; + //optimize performance for javascript + currentStack.top = currentStack.stack.pop(); + }; + + proto.checkAtlasCapacity = function(index){ + // make needed room + var locAtlas = this._textureAtlas; + while (index >= locAtlas.capacity || locAtlas.capacity === locAtlas.totalQuads) { + this.increaseAtlasCapacity(); + } + }; + + proto.increaseAtlasCapacity = function(){ + // if we're going beyond the current TextureAtlas's capacity, + // all the previously initialized sprites will need to redo their texture coords + // this is likely computationally expensive + var locCapacity = this._textureAtlas.capacity; + var quantity = Math.floor((locCapacity + 1) * 4 / 3); + + cc.log(cc._LogInfos.SpriteBatchNode_increaseAtlasCapacity, locCapacity, quantity); + + if (!this._textureAtlas.resizeCapacity(quantity)) { + // serious problems + cc.log(cc._LogInfos.SpriteBatchNode_increaseAtlasCapacity_2); + } + }; + + proto.initWithTexture = function(texture, capacity){ + this._textureAtlas = new cc.TextureAtlas(); + this._textureAtlas.initWithTexture(texture, capacity); + this._updateBlendFunc(); + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + }; + + proto.insertQuad = function(sprite, index){ + var locTextureAtlas = this._textureAtlas; + if (locTextureAtlas.totalQuads >= locTextureAtlas.capacity) + this.increaseAtlasCapacity(); + locTextureAtlas.insertQuad(sprite.quad, index); + }; + + proto.removeQuadAtIndex = function(index){ + this._textureAtlas.removeQuadAtIndex(index); // remove from TextureAtlas + }; + + proto.getTexture = function(){ + return this._textureAtlas.texture; + }; + + proto.setTexture = function(texture){ + this._textureAtlas.setTexture(texture); + if(texture) + this._updateBlendFunc(); + }; + + proto.removeAllQuads = function(){ + this._textureAtlas.removeAllQuads(); + }; + + proto._swap = function (oldIndex, newIndex) { + var locDescendants = this._node._descendants; + var locTextureAtlas = this._textureAtlas; + var quads = locTextureAtlas.quads; + var tempItem = locDescendants[oldIndex]; + var tempIteQuad = cc.V3F_C4B_T2F_QuadCopy(quads[oldIndex]); + + //update the index of other swapped item + locDescendants[newIndex].atlasIndex = oldIndex; + locDescendants[oldIndex] = locDescendants[newIndex]; + + locTextureAtlas.updateQuad(quads[newIndex], oldIndex); + locDescendants[newIndex] = tempItem; + locTextureAtlas.updateQuad(tempIteQuad, newIndex); + }; + + proto._updateAtlasIndex = function (sprite, curIndex) { + var count = 0; + var pArray = sprite.children; + if (pArray) + count = pArray.length; + + var oldIndex = 0; + if (count === 0) { + oldIndex = sprite.atlasIndex; + sprite.atlasIndex = curIndex; + sprite.arrivalOrder = 0; + if (oldIndex !== curIndex) + this._swap(oldIndex, curIndex); + curIndex++; + } else { + var needNewIndex = true; + if (pArray[0].zIndex >= 0) { + //all children are in front of the parent + oldIndex = sprite.atlasIndex; + sprite.atlasIndex = curIndex; + sprite.arrivalOrder = 0; + if (oldIndex !== curIndex) + this._swap(oldIndex, curIndex); + curIndex++; + needNewIndex = false; + } + for (var i = 0; i < pArray.length; i++) { + var child = pArray[i]; + if (needNewIndex && child.zIndex >= 0) { + oldIndex = sprite.atlasIndex; + sprite.atlasIndex = curIndex; + sprite.arrivalOrder = 0; + if (oldIndex !== curIndex) { + this._swap(oldIndex, curIndex); + } + curIndex++; + needNewIndex = false; + } + curIndex = this._updateAtlasIndex(child, curIndex); + } + + if (needNewIndex) { + //all children have a zOrder < 0) + oldIndex = sprite.atlasIndex; + sprite.atlasIndex = curIndex; + sprite.arrivalOrder = 0; + if (oldIndex !== curIndex) { + this._swap(oldIndex, curIndex); + } + curIndex++; + } + } + return curIndex; + }; + + proto.updateChildrenAtlasIndex = function(children){ + var index = 0; + //fast dispatch, give every child a new atlasIndex based on their relative zOrder (keep parent -> child relations intact) + // and at the same time reorder descedants and the quads to the right index + for (var i = 0; i < children.length; i++) + index = this._updateAtlasIndex(children[i], index); + }; + + proto._updateBlendFunc = function () { + if (!this._textureAtlas.texture.hasPremultipliedAlpha()) { + var blendFunc = this._node._blendFunc; + blendFunc.src = cc.SRC_ALPHA; + blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + } + }; + + proto.getTextureAtlas = function(){ + return this._textureAtlas; + }; + + proto.setTextureAtlas = function(textureAtlas){ + if (textureAtlas !== this._textureAtlas) { + this._textureAtlas = textureAtlas; + } + }; + + proto.cutting = function(){}; +})(); diff --git a/cocos2d/core/sprites/CCSpriteCanvasRenderCmd.js b/cocos2d/core/sprites/CCSpriteCanvasRenderCmd.js new file mode 100644 index 0000000000..dd08d36c00 --- /dev/null +++ b/cocos2d/core/sprites/CCSpriteCanvasRenderCmd.js @@ -0,0 +1,512 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function() { + cc.Sprite.CanvasRenderCmd = function (renderable) { + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + this._textureCoord = { + renderX: 0, //the x of texture coordinate for render, when texture tinted, its value doesn't equal x. + renderY: 0, //the y of texture coordinate for render, when texture tinted, its value doesn't equal y. + x: 0, //the x of texture coordinate for node. + y: 0, //the y of texture coordinate for node. + width: 0, + height: 0, + validRect: false + }; + this._blendFuncStr = "source-over"; + this._colorized = false; + + this._originalTexture = null; + }; + + var proto = cc.Sprite.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.Sprite.CanvasRenderCmd; + + proto._init = function () {}; + + proto.setDirtyRecursively = function (value) {}; + + proto._resetForBatchNode = function () {}; + + proto._setTexture = function (texture) { + var node = this._node; + if (node._texture !== texture) { + if (texture) { + if(texture.getHtmlElementObj() instanceof HTMLImageElement) + this._originalTexture = texture; + node._textureLoaded = texture._textureLoaded; + }else{ + node._textureLoaded = false; + } + node._texture = texture; + } + }; + + proto._setColorDirty = function () { + this.setDirtyFlag(cc.Node._dirtyFlags.colorDirty | cc.Node._dirtyFlags.opacityDirty); + }; + + proto.isFrameDisplayed = function (frame) { //TODO there maybe has a bug + var node = this._node; + if (frame.getTexture() !== node._texture) + return false; + return cc.rectEqualToRect(frame.getRect(), node._rect); + }; + + proto.updateBlendFunc = function (blendFunc) { + this._blendFuncStr = cc.Node.CanvasRenderCmd._getCompositeOperationByBlendFunc(blendFunc); + }; + + proto._setBatchNodeForAddChild = function (child) { + return true; + }; + + proto._handleTextureForRotatedTexture = function (texture, rect, rotated, counterclockwise) { + if (rotated && texture.isLoaded()) { + var tempElement = texture.getHtmlElementObj(); + tempElement = cc.Sprite.CanvasRenderCmd._cutRotateImageToCanvas(tempElement, rect, counterclockwise); + var tempTexture = new cc.Texture2D(); + tempTexture.initWithElement(tempElement); + tempTexture.handleLoadedTexture(); + texture = tempTexture; + rect.x = rect.y = 0; + this._node._rect = cc.rect(0, 0, rect.width, rect.height); + } + return texture; + }; + + proto._checkTextureBoundary = function (texture, rect, rotated) { + if (texture && texture.url) { + var _x = rect.x + rect.width, _y = rect.y + rect.height; + if (_x > texture.width) + cc.error(cc._LogInfos.RectWidth, texture.url); + if (_y > texture.height) + cc.error(cc._LogInfos.RectHeight, texture.url); + } + this._node._originalTexture = texture; + }; + + proto.rendering = function (ctx, scaleX, scaleY) { + var node = this._node; + var locTextureCoord = this._textureCoord, alpha = (this._displayedOpacity / 255); + if ((node._texture && ((locTextureCoord.width === 0 || locTextureCoord.height === 0) //set texture but the texture isn't loaded. + || !node._texture._textureLoaded)) || alpha === 0) + return; + + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + var locX = node._offsetPosition.x, locHeight = node._rect.height, locWidth = node._rect.width, + locY = -node._offsetPosition.y - locHeight, image; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + wrapper.setCompositeOperation(this._blendFuncStr); + wrapper.setGlobalAlpha(alpha); + + if(node._flippedX || node._flippedY) + wrapper.save(); + if (node._flippedX) { + locX = -locX - locWidth; + context.scale(-1, 1); + } + if (node._flippedY) { + locY = node._offsetPosition.y; + context.scale(1, -1); + } + + if (node._texture) { + image = node._texture._htmlElementObj; + if (node._texture._pattern !== "") { + wrapper.setFillStyle(context.createPattern(image, node._texture._pattern)); + context.fillRect(locX * scaleX, locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } else { + if (this._colorized) { + context.drawImage(image, + 0, 0, locTextureCoord.width,locTextureCoord.height, + locX * scaleX,locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } else { + context.drawImage(image, + locTextureCoord.renderX, locTextureCoord.renderY, locTextureCoord.width, locTextureCoord.height, + locX * scaleX, locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } + } + } else { + var contentSize = node._contentSize; + if (locTextureCoord.validRect) { + var curColor = this._displayedColor; + wrapper.setFillStyle("rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"); + context.fillRect(locX * scaleX, locY * scaleY, contentSize.width * scaleX, contentSize.height * scaleY); + } + } + if(node._flippedX || node._flippedY) + wrapper.restore(); + cc.g_NumberOfDraws++; + }; + + if(!cc.sys._supportCanvasNewBlendModes){ + proto._updateColor = function () { + var node = this._node, displayedColor = this._displayedColor; + + if (displayedColor.r === 255 && displayedColor.g === 255 && displayedColor.b === 255){ + if(this._colorized){ + this._colorized = false; + node.texture = this._originalTexture; + } + return; + } + + var locElement, locTexture = node._texture, locRect = this._textureCoord; + if (locTexture && locRect.validRect && this._originalTexture) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + + var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); + if (cacheTextureForColor) { + this._colorized = true; + //generate color texture cache + if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor) + cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, displayedColor, locRect, locElement); + else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, displayedColor, locRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.texture = locTexture; + } + } + } + }; + } else { + proto._updateColor = function () { + var node = this._node, displayedColor = this._displayedColor; + if (displayedColor.r === 255 && displayedColor.g === 255 && displayedColor.b === 255) { + if (this._colorized) { + this._colorized = false; + node.texture = this._originalTexture; + } + return; + } + + var locElement, locTexture = node._texture, locRect = this._textureCoord; + if (locTexture && locRect.validRect && this._originalTexture) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + + this._colorized = true; + if (locElement instanceof HTMLCanvasElement && !this._rectRotated && !this._newTextureWhenChangeColor + && this._originalTexture._htmlElementObj !== locElement) + cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(this._originalTexture._htmlElementObj, displayedColor, locRect, locElement); + else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(this._originalTexture._htmlElementObj, displayedColor, locRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.texture = locTexture; + } + } + }; + } + + proto.getQuad = function () { + //throw an error. it doesn't support this function. + return null; + }; + + proto._updateForSetSpriteFrame = function (pNewTexture, textureLoaded) { + var node = this._node; + if (node._rectRotated) + node._originalTexture = pNewTexture; //TODO + this._colorized = false; + this._textureCoord.renderX = this._textureCoord.x; + this._textureCoord.renderY = this._textureCoord.y; + if (textureLoaded) { + var curColor = node.getColor(); + if (curColor.r !== 255 || curColor.g !== 255 || curColor.b !== 255) + this._updateColor(); + } + }; + + proto.updateTransform = function () { //TODO need delete, because Canvas needn't + var _t = this, node = this._node; + + // re-calculate matrix only if it is dirty + if (node.dirty) { + // If it is not visible, or one of its ancestors is not visible, then do nothing: + var locParent = node._parent; + if (!node._visible || ( locParent && locParent !== node._batchNode && locParent._shouldBeHidden)) { + node._shouldBeHidden = true; + } else { + node._shouldBeHidden = false; + + if (!locParent || locParent === node._batchNode) { + node._transformToBatch = _t.getNodeToParentTransform(); + } else { + //cc.assert(_t._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); + node._transformToBatch = cc.affineTransformConcat(_t.getNodeToParentTransform(), locParent._transformToBatch); + } + } + node._recursiveDirty = false; + node.dirty = false; + } + + // recursively iterate over children + if (node._hasChildren) + node._arrayMakeObjectsPerformSelector(node._children, cc.Node._stateCallbackType.updateTransform); + }; + + proto._updateDisplayColor = function (parentColor) { + cc.Node.CanvasRenderCmd.prototype._updateDisplayColor.call(this, parentColor); + //this._updateColor(); + }; + + proto._spriteFrameLoadedCallback = function (spriteFrame) { + var node = this; + node.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); + + node._renderCmd._updateColor(); + node.dispatchEvent("load"); + }; + + proto._textureLoadedCallback = function (sender) { + var node = this; + if (node._textureLoaded) + return; + + node._textureLoaded = true; + var locRect = node._rect, locRenderCmd = this._renderCmd; + if (!locRect) { + locRect = cc.rect(0, 0, sender.width, sender.height); + } else if (cc._rectEqualToZero(locRect)) { + locRect.width = sender.width; + locRect.height = sender.height; + } + locRenderCmd._originalTexture = sender; + + node.texture = sender; + node.setTextureRect(locRect, node._rectRotated); + + //set the texture's color after the it loaded + var locColor = locRenderCmd._displayedColor; + if (locColor.r !== 255 || locColor.g !== 255 || locColor.b !== 255) + locRenderCmd._updateColor(); + + // by default use "Self Render". + // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" + node.setBatchNode(node._batchNode); + node.dispatchEvent("load"); + }; + + proto._setTextureCoords = function (rect, needConvert) { + if (needConvert === undefined) + needConvert = true; + var locTextureRect = this._textureCoord, + scaleFactor = needConvert ? cc.contentScaleFactor() : 1; + locTextureRect.renderX = locTextureRect.x = 0 | (rect.x * scaleFactor); + locTextureRect.renderY = locTextureRect.y = 0 | (rect.y * scaleFactor); + locTextureRect.width = 0 | (rect.width * scaleFactor); + locTextureRect.height = 0 | (rect.height * scaleFactor); + locTextureRect.validRect = !(locTextureRect.width === 0 || locTextureRect.height === 0 || locTextureRect.x < 0 || locTextureRect.y < 0); + + if(this._colorized){ + this._node._texture = this._originalTexture; + this._colorized = false; + } + }; + + //TODO need refactor these functions + //utils for tint + // Tint a texture using the "multiply" operation + cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply = function (image, color, rect, renderCanvas) { + renderCanvas = renderCanvas || cc.newElement("canvas"); + rect = rect || cc.rect(0, 0, image.width, image.height); + var context = renderCanvas.getContext("2d"); + if (renderCanvas.width !== rect.width || renderCanvas.height !== rect.height) { + renderCanvas.width = rect.width; + renderCanvas.height = rect.height; + } else { + context.globalCompositeOperation = "source-over"; + } + + context.fillStyle = "rgb(" + (0 | color.r) + "," + (0 | color.g) + "," + (0 | color.b) + ")"; + context.fillRect(0, 0, rect.width, rect.height); + context.globalCompositeOperation = "multiply"; + context.drawImage(image, + rect.x, + rect.y, + rect.width, + rect.height, + 0, + 0, + rect.width, + rect.height); + context.globalCompositeOperation = "destination-atop"; + context.drawImage(image, + rect.x, + rect.y, + rect.width, + rect.height, + 0, + 0, + rect.width, + rect.height); + return renderCanvas; + }; + + //Generate tinted texture with lighter. + cc.Sprite.CanvasRenderCmd._generateTintImage = function (texture, tintedImgCache, color, rect, renderCanvas) { + if (!rect) + rect = cc.rect(0, 0, texture.width, texture.height); + + var r = color.r / 255, g = color.g / 255, b = color.b / 255; + var w = Math.min(rect.width, tintedImgCache[0].width); + var h = Math.min(rect.height, tintedImgCache[0].height); + var buff = renderCanvas, ctx; + // Create a new buffer if required + if (!buff) { + buff = cc.newElement("canvas"); + buff.width = w; + buff.height = h; + ctx = buff.getContext("2d"); + } else { + ctx = buff.getContext("2d"); + ctx.clearRect(0, 0, w, h); + } + ctx.save(); + ctx.globalCompositeOperation = 'lighter'; + // Make sure to keep the renderCanvas alpha in mind in case of overdraw + var a = ctx.globalAlpha; + if (r > 0) { + ctx.globalAlpha = r * a; + ctx.drawImage(tintedImgCache[0], rect.x, rect.y, w, h, 0, 0, w, h); + } + if (g > 0) { + ctx.globalAlpha = g * a; + ctx.drawImage(tintedImgCache[1], rect.x, rect.y, w, h, 0, 0, w, h); + } + if (b > 0) { + ctx.globalAlpha = b * a; + ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h); + } + if (r + g + b < 1) { + ctx.globalAlpha = a; + ctx.drawImage(tintedImgCache[3], rect.x, rect.y, w, h, 0, 0, w, h); + } + ctx.restore(); + return buff; + }; + + cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor = function (texture) { + if (texture.channelCache) { + return texture.channelCache; + } + + var textureCache = [ + cc.newElement("canvas"), + cc.newElement("canvas"), + cc.newElement("canvas"), + cc.newElement("canvas") + ]; + + function renderToCache() { + var ref = cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor; + + var w = texture.width; + var h = texture.height; + + textureCache[0].width = w; + textureCache[0].height = h; + textureCache[1].width = w; + textureCache[1].height = h; + textureCache[2].width = w; + textureCache[2].height = h; + textureCache[3].width = w; + textureCache[3].height = h; + + ref.canvas.width = w; + ref.canvas.height = h; + + var ctx = ref.canvas.getContext("2d"); + ctx.drawImage(texture, 0, 0); + + ref.tempCanvas.width = w; + ref.tempCanvas.height = h; + + var pixels = ctx.getImageData(0, 0, w, h).data; + + for (var rgbI = 0; rgbI < 4; rgbI++) { + var cacheCtx = textureCache[rgbI].getContext('2d'); + cacheCtx.getImageData(0, 0, w, h).data; + ref.tempCtx.drawImage(texture, 0, 0); + + var to = ref.tempCtx.getImageData(0, 0, w, h); + var toData = to.data; + + for (var i = 0; i < pixels.length; i += 4) { + toData[i ] = (rgbI === 0) ? pixels[i ] : 0; + toData[i + 1] = (rgbI === 1) ? pixels[i + 1] : 0; + toData[i + 2] = (rgbI === 2) ? pixels[i + 2] : 0; + toData[i + 3] = pixels[i + 3]; + } + cacheCtx.putImageData(to, 0, 0); + } + texture.onload = null; + } + + try { + renderToCache(); + } catch (e) { + texture.onload = renderToCache; + } + + texture.channelCache = textureCache; + return textureCache; + }; + + cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor.canvas = cc.newElement('canvas'); + cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor.tempCanvas = cc.newElement('canvas'); + cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor.tempCtx = cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor.tempCanvas.getContext('2d'); + + cc.Sprite.CanvasRenderCmd._cutRotateImageToCanvas = function (texture, rect, counterclockwise) { + if (!texture) + return null; + + if (!rect) + return texture; + + counterclockwise = counterclockwise == null? true: counterclockwise; // texture package is counterclockwise, spine is clockwise + + var nCanvas = cc.newElement("canvas"); + nCanvas.width = rect.width; + nCanvas.height = rect.height; + var ctx = nCanvas.getContext("2d"); + ctx.translate(nCanvas.width / 2, nCanvas.height / 2); + if(counterclockwise) + ctx.rotate(-1.5707963267948966); + else + ctx.rotate(1.5707963267948966); + ctx.drawImage(texture, rect.x, rect.y, rect.height, rect.width, -rect.height / 2, -rect.width / 2, rect.height, rect.width); + return nCanvas; + }; +})(); diff --git a/cocos2d/core/sprites/CCSpriteFrame.js b/cocos2d/core/sprites/CCSpriteFrame.js index cfe6eeec10..b59154f894 100644 --- a/cocos2d/core/sprites/CCSpriteFrame.js +++ b/cocos2d/core/sprites/CCSpriteFrame.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -35,9 +35,21 @@ * @class * @extends cc.Class * + * @param {String|cc.Texture2D} filename + * @param {cc.Rect} rect If parameters' length equal 2, rect in points, else rect in pixels + * @param {Boolean} [rotated] Whether the frame is rotated in the texture + * @param {cc.Point} [offset] The offset of the frame in the texture + * @param {cc.Size} [originalSize] The size of the frame in the texture + * * @example - * var texture = cc.textureCache.addImage(s_dragon_animation); - * var frame0 = cc.SpriteFrame.create(texture, cc.rect(132 * 0, 132 * 0, 132, 132)); + * // 1. Create a cc.SpriteFrame with image path + * var frame1 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128)); + * var frame2 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128),false,0,cc.size(90,128)); + * + * // 2. Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. + * var texture = cc.textureCache.addImage("res/grossini_dance.png"); + * var frame1 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128)); + * var frame2 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128),false,0,cc.size(90,128)); */ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ _offset:null, @@ -50,29 +62,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ _texture:null, _textureFilename:"", _textureLoaded:false, - _eventListeners:null, - /** - *

- * Create a cc.SpriteFrame with a texture filename, rect, rotated, offset and originalSize in pixels.
- * The originalSize is the size in pixels of the frame before being trimmed. - *

- * @constructor - * @param {String|cc.Texture2D} filename - * @param {cc.Rect} rect if parameters' length equal 2, rect in points, else rect in pixels - * @param {Boolean} rotated - * @param {cc.Point} offset - * @param {cc.Size} originalSize - * @example - * // 1.Create a cc.SpriteFrame with image path - * var frame1 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128)); - * var frame2 = new cc.SpriteFrame("res/grossini_dance.png",cc.rect(0,0,90,128),false,0,cc.size(90,128)); - * - * // 2.Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. - * var texture = cc.textureCache.addImage("res/grossini_dance.png"); - * var frame1 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128)); - * var frame2 = new cc.SpriteFrame(texture, cc.rect(0,0,90,128),false,0,cc.size(90,128)); - */ ctor:function (filename, rect, rotated, offset, originalSize) { this._offset = cc.p(0, 0); this._offsetInPixels = cc.p(0, 0); @@ -84,38 +74,33 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ this._textureLoaded = false; if(filename !== undefined && rect !== undefined ){ - if(rotated === undefined || offset === undefined || originalSize === undefined){ + if(rotated === undefined || offset === undefined || originalSize === undefined) this.initWithTexture(filename, rect); - } - else{ + else this.initWithTexture(filename, rect, rotated, offset, originalSize) - } } }, - // attributes + /** + * Returns whether the texture have been loaded + * @returns {boolean} + */ textureLoaded:function(){ return this._textureLoaded; }, + /** + * Add a event listener for texture loaded event. + * @param {Function} callback + * @param {Object} target + * @deprecated since 3.1, please use addEventListener instead + */ addLoadedEventListener:function(callback, target){ - if (this._eventListeners == null){ - this._eventListeners = []; - } - this._eventListeners.push({eventCallback:callback, eventTarget:target}); - }, - - _callLoadedEventCallbacks:function(){ - var locListeners = this._eventListeners; - if (!locListeners) return; - for(var i = 0, len = locListeners.length; i < len; i++){ - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; + this.addEventListener("load", callback, target); }, /** + * Gets the rect of the frame in the texture * @return {cc.Rect} */ getRectInPixels:function () { @@ -124,6 +109,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** + * Sets the rect of the frame in the texture * @param {cc.Rect} rectInPixels */ setRectInPixels:function (rectInPixels) { @@ -138,9 +124,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - *

- * return is rotated of SpriteFrame.
- *

+ * Returns whether the sprite frame is rotated in the texture. * @return {Boolean} */ isRotated:function () { @@ -148,7 +132,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * set SpriteFrame is rotated + * Set whether the sprite frame is rotated in the texture. * @param {Boolean} bRotated */ setRotated:function (bRotated) { @@ -156,7 +140,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * get rect of the frame + * Returns the rect of the sprite frame in the texture * @return {cc.Rect} */ getRect:function () { @@ -165,7 +149,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * set rect of the frame + * Sets the rect of the sprite frame in the texture * @param {cc.Rect} rect */ setRect:function (rect) { @@ -180,15 +164,15 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * get offset of the frame + * Returns the offset of the sprite frame in the texture in pixel * @return {cc.Point} */ getOffsetInPixels:function () { - return this._offsetInPixels; + return cc.p(this._offsetInPixels); }, /** - * set offset of the frame + * Sets the offset of the sprite frame in the texture in pixel * @param {cc.Point} offsetInPixels */ setOffsetInPixels:function (offsetInPixels) { @@ -198,16 +182,15 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * get original size of the trimmed image - * @const + * Returns the original size of the trimmed image * @return {cc.Size} */ getOriginalSizeInPixels:function () { - return this._originalSizeInPixels; + return cc.size(this._originalSizeInPixels); }, /** - * set original size of the trimmed image + * Sets the original size of the trimmed image * @param {cc.Size} sizeInPixels */ setOriginalSizeInPixels:function (sizeInPixels) { @@ -216,16 +199,15 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * get original size of the trimmed image - * @const + * Returns the original size of the trimmed image * @return {cc.Size} */ getOriginalSize:function () { - return this._originalSize; + return cc.size(this._originalSize); }, /** - * set original size of the trimmed image + * Sets the original size of the trimmed image * @param {cc.Size} sizeInPixels */ setOriginalSize:function (sizeInPixels) { @@ -234,7 +216,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * get texture of the frame + * Returns the texture of the frame * @return {cc.Texture2D} */ getTexture:function () { @@ -250,20 +232,20 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * set texture of the frame, the texture is retained + * Sets the texture of the frame, the texture is retained automatically * @param {cc.Texture2D} texture */ setTexture:function (texture) { - if (this._texture != texture) { + if (this._texture !== texture) { var locLoaded = texture.isLoaded(); this._textureLoaded = locLoaded; this._texture = texture; if(!locLoaded){ - texture.addLoadedEventListener(function(sender){ + texture.addEventListener("load", function(sender){ this._textureLoaded = true; if(this._rotated && cc._renderType === cc._RENDER_TYPE_CANVAS){ var tempElement = sender.getHtmlElementObj(); - tempElement = cc.cutRotateImageToCanvas(tempElement, this.getRect()); + tempElement = cc.Sprite.CanvasRenderCmd._cutRotateImageToCanvas(tempElement, this.getRect()); var tempTexture = new cc.Texture2D(); tempTexture.initWithElement(tempElement); tempTexture.handleLoadedTexture(); @@ -283,23 +265,23 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ this._originalSize.width = w; this._originalSize.height = h; } - this._callLoadedEventCallbacks(); + //dispatch 'load' event of cc.SpriteFrame + this.dispatchEvent("load"); }, this); } } }, /** - * Offset getter - * @const + * Returns the offset of the frame in the texture * @return {cc.Point} */ getOffset:function () { - return this._offset; + return cc.p(this._offset); }, /** - * offset setter + * Sets the offset of the frame in the texture * @param {cc.Point} offsets */ setOffset:function (offsets) { @@ -307,6 +289,10 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ this._offset.y = offsets.y; }, + /** + * Clone the sprite frame + * @returns {SpriteFrame} + */ clone: function(){ var frame = new cc.SpriteFrame(); frame.initWithTexture(this._textureFilename, this._rectInPixels, this._rotated, this._offsetInPixels, this._originalSizeInPixels); @@ -315,7 +301,7 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ }, /** - * copy a new SpriteFrame + * Copy the sprite frame * @return {cc.SpriteFrame} */ copyWithZone:function () { @@ -325,12 +311,17 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ return copy; }, + /** + * Copy the sprite frame + * @returns {cc.SpriteFrame} + */ copy:function () { return this.copyWithZone(); }, /** - * Initializes SpriteFrame with Texture, rect, rotated, offset and originalSize in pixels. + * Initializes SpriteFrame with Texture, rect, rotated, offset and originalSize in pixels.
+ * Please pass parameters to the constructor to initialize the sprite, do not call this function yourself. * @param {String|cc.Texture2D} texture * @param {cc.Rect} rect if parameters' length equal 2, rect in points, else rect in pixels * @param {Boolean} [rotated=false] @@ -346,15 +337,35 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ originalSize = originalSize || rect; rotated = rotated || false; - if (typeof(texture) == "string"){ + if (cc.isString(texture)){ this._texture = null; this._textureFilename = texture; } else if (texture instanceof cc.Texture2D){ this.setTexture(texture); } + texture = this.getTexture(); + this._rectInPixels = rect; - this._rect = cc.rectPixelsToPoints(rect); + rect = this._rect = cc.rectPixelsToPoints(rect); + + if(texture && texture.url && texture.isLoaded()) { + var _x, _y; + if(rotated){ + _x = rect.x + rect.height; + _y = rect.y + rect.width; + }else{ + _x = rect.x + rect.width; + _y = rect.y + rect.height; + } + if(_x > texture.getPixelsWide()){ + cc.error(cc._LogInfos.RectWidth, texture.url); + } + if(_y > texture.getPixelsHigh()){ + cc.error(cc._LogInfos.RectHeight, texture.url); + } + } + this._offsetInPixels.x = offset.x; this._offsetInPixels.y = offset.y; cc._pointPixelsToPointsOut(offset, this._offset); @@ -366,33 +377,33 @@ cc.SpriteFrame = cc.Class.extend(/** @lends cc.SpriteFrame# */{ } }); +cc.EventHelper.prototype.apply(cc.SpriteFrame.prototype); + /** *

* Create a cc.SpriteFrame with a texture filename, rect, rotated, offset and originalSize in pixels.
* The originalSize is the size in pixels of the frame before being trimmed. *

+ * @deprecated since v3.0, please use new construction instead + * @see cc.SpriteFrame * @param {String|cc.Texture2D} filename * @param {cc.Rect} rect if parameters' length equal 2, rect in points, else rect in pixels * @param {Boolean} rotated * @param {cc.Point} offset * @param {cc.Size} originalSize * @return {cc.SpriteFrame} - * @example - * 1. - * //Create a cc.SpriteFrame with image path - * var frame1 = cc.SpriteFrame.create("res/grossini_dance.png",cc.rect(0,0,90,128)); - * var frame2 = cc.SpriteFrame.create("res/grossini_dance.png",cc.rect(0,0,90,128),false,0,cc.size(90,128)); - * - * 2. - * //Create a cc.SpriteFrame with a texture, rect, rotated, offset and originalSize in pixels. - * var texture = cc.textureCache.addImage("res/grossini_dance.png"); - * var frame1 = cc.SpriteFrame.create(texture, cc.rect(0,0,90,128)); - * var frame2 = cc.SpriteFrame.create(texture, cc.rect(0,0,90,128),false,0,cc.size(90,128)); */ cc.SpriteFrame.create = function (filename, rect, rotated, offset, originalSize) { return new cc.SpriteFrame(filename,rect,rotated,offset,originalSize); }; +/** + * @deprecated since v3.0, please use new construction instead + * @see cc.SpriteFrame + * @function + */ +cc.SpriteFrame.createWithTexture = cc.SpriteFrame.create; + cc.SpriteFrame._frameWithTextureForCanvas = function (texture, rect, rotated, offset, originalSize) { var spriteFrame = new cc.SpriteFrame(); spriteFrame._texture = texture; diff --git a/cocos2d/core/sprites/CCSpriteFrameCache.js b/cocos2d/core/sprites/CCSpriteFrameCache.js index fbdb307f8f..f6ebcf2c58 100644 --- a/cocos2d/core/sprites/CCSpriteFrameCache.js +++ b/cocos2d/core/sprites/CCSpriteFrameCache.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,13 +25,15 @@ ****************************************************************************/ /** - * @namespace

- * Singleton that handles the loading of the sprite frames. It saves in a cache the sprite frames.
+ *

+ * cc.spriteFrameCache is a singleton that handles the loading of the sprite frames. It saves in a cache the sprite frames.
*
* example
* // add SpriteFrames to spriteFrameCache With File
* cc.spriteFrameCache.addSpriteFrames(s_grossiniPlist);
*

+ * @class + * @name cc.spriteFrameCache */ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ _CCNS_REG1 : /^\s*\{\s*([\-]?\d+[.]?\d*)\s*,\s*([\-]?\d+[.]?\d*)\s*\}\s*$/, @@ -41,70 +43,24 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ _spriteFramesAliases: {}, _frameConfigCache : {}, - /** - * Returns a Core Graphics rectangle structure corresponding to the data in a given string.
- * The string is not localized, so items are always separated with a comma.
- * If the string is not well-formed, the function returns cc.rect(0, 0, 0, 0). - * @function - * @param {String} content content A string object whose contents are of the form "{{x,y},{w, h}}",
- * where x is the x coordinate, y is the y coordinate, w is the width, and h is the height.
- * These components can represent integer or float values. - * @return {cc.Rect} A Core Graphics structure that represents a rectangle. - * Constructor - * @example - * // example - * var rect = this._rectFromString("{{3,2},{4,5}}"); - */ _rectFromString : function (content) { var result = this._CCNS_REG2.exec(content); if(!result) return cc.rect(0, 0, 0, 0); return cc.rect(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]), parseFloat(result[4])); }, - /** - * Returns a Core Graphics point structure corresponding to the data in a given string. - * @function - * @param {String} content A string object whose contents are of the form "{x,y}", - * where x is the x coordinate and y is the y coordinate.
- * The x and y values can represent integer or float values.
- * The string is not localized, so items are always separated with a comma.
- * @return {cc.Point} A Core Graphics structure that represents a point.
- * If the string is not well-formed, the function returns cc.p(0,0). - * Constructor - * @example - * //example - * var point = this._pointFromString("{3.0,2.5}"); - */ _pointFromString : function (content) { var result = this._CCNS_REG1.exec(content); if(!result) return cc.p(0,0); return cc.p(parseFloat(result[1]), parseFloat(result[2])); }, - /** - * Returns a Core Graphics size structure corresponding to the data in a given string. - * @function - * @param {String} content A string object whose contents are of the form "{w, h}",
- * where w is the width and h is the height.
- * The w and h values can be integer or float values.
- * The string is not localized, so items are always separated with a comma.
- * @return {cc.Size} A Core Graphics structure that represents a size.
- * If the string is not well-formed, the function returns cc.size(0,0). - * @example - * // example - * var size = this._sizeFromString("{3.0,2.5}"); - */ + _sizeFromString : function (content) { var result = this._CCNS_REG1.exec(content); if(!result) return cc.size(0, 0); return cc.size(parseFloat(result[1]), parseFloat(result[2])); }, - /** - * Get the real data structure of frame used by engine. - * @param url - * @returns {*} - * @private - */ _getFrameConfig : function(url){ var dict = cc.loader.getRes(url); @@ -115,6 +71,17 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ this._frameConfigCache[url] = dict; return dict; } + this._frameConfigCache[url] = this._parseFrameConfig(dict); + return this._frameConfigCache[url]; + }, + + _getFrameConfigByJsonObject: function(url, jsonObject) { + cc.assert(jsonObject, cc._LogInfos.spriteFrameCache__getFrameConfig_2, url); + this._frameConfigCache[url] = this._parseFrameConfig(jsonObject); + return this._frameConfigCache[url]; + }, + + _parseFrameConfig: function(dict) { var tempFrames = dict["frames"], tempMeta = dict["metadata"] || dict["meta"]; var frames = {}, meta = {}; var format = 0; @@ -169,69 +136,56 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ } frames[key] = tempFrame; } - var cfg = this._frameConfigCache[url] = { - _inited : true, - frames : frames, - meta : meta - }; - return cfg; + return {_inited: true, frames: frames, meta: meta}; }, - /** - *

- * Adds multiple Sprite Frames from a plist or json file.
- * A texture will be loaded automatically. The texture name will composed by replacing the .plist or .json suffix with .png
- * If you want to use another texture, you should use the addSpriteFrames:texture method.
- *

- * @param {String} url file path - * @param {HTMLImageElement|cc.Texture2D|string} texture - * @example - * // add SpriteFrames to SpriteFrameCache With File - * cc.spriteFrameCache.addSpriteFrames(s_grossiniPlist); - * cc.spriteFrameCache.addSpriteFrames(s_grossiniJson); - */ - addSpriteFrames: function (url, texture) { - + // Adds multiple Sprite Frames from a json object. it uses for local web view app. + _addSpriteFramesByObject: function(url, jsonObject, texture) { cc.assert(url, cc._LogInfos.spriteFrameCache_addSpriteFrames_2); + if(!jsonObject || !jsonObject["frames"]) + return; - var self = this; - var frameConfig = self._frameConfigCache[url] || self._getFrameConfig(url); - //self._checkConflict(frameConfig); //TODO + var frameConfig = this._frameConfigCache[url] || this._getFrameConfigByJsonObject(url, jsonObject); + //this._checkConflict(frameConfig); //TODO + this._createSpriteFrames(url, frameConfig, texture); + }, + + _createSpriteFrames: function(url, frameConfig, texture) { var frames = frameConfig.frames, meta = frameConfig.meta; if(!texture){ var texturePath = cc.path.changeBasename(url, meta.image || ".png"); texture = cc.textureCache.addImage(texturePath); }else if(texture instanceof cc.Texture2D){ //do nothing - }else if(typeof texture == "string"){//string + }else if(cc.isString(texture)){//string texture = cc.textureCache.addImage(texture); }else{ cc.assert(0, cc._LogInfos.spriteFrameCache_addSpriteFrames_3); } //create sprite frames - var spAliases = self._spriteFramesAliases, spriteFrames = self._spriteFrames; + var spAliases = this._spriteFramesAliases, spriteFrames = this._spriteFrames; for (var key in frames) { var frame = frames[key]; var spriteFrame = spriteFrames[key]; if (!spriteFrame) { - spriteFrame = cc.SpriteFrame.create(texture, frame.rect, frame.rotated, frame.offset, frame.size); + spriteFrame = new cc.SpriteFrame(texture, frame.rect, frame.rotated, frame.offset, frame.size); var aliases = frame.aliases; if(aliases){//set aliases for(var i = 0, li = aliases.length; i < li; i++){ var alias = aliases[i]; - if (spAliases[alias]) { + if (spAliases[alias]) cc.log(cc._LogInfos.spriteFrameCache_addSpriteFrames, alias); - } spAliases[alias] = key; } } + if (cc._renderType === cc._RENDER_TYPE_CANVAS && spriteFrame.isRotated()) { //clip to canvas var locTexture = spriteFrame.getTexture(); if (locTexture.isLoaded()) { var tempElement = spriteFrame.getTexture().getHtmlElementObj(); - tempElement = cc.cutRotateImageToCanvas(tempElement, spriteFrame.getRectInPixels()); + tempElement = cc.Sprite.CanvasRenderCmd._cutRotateImageToCanvas(tempElement, spriteFrame.getRectInPixels()); var tempTexture = new cc.Texture2D(); tempTexture.initWithElement(tempElement); tempTexture.handleLoadedTexture(); @@ -246,6 +200,32 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ } }, + /** + *

+ * Adds multiple Sprite Frames from a plist or json file.
+ * A texture will be loaded automatically. The texture name will composed by replacing the .plist or .json suffix with .png
+ * If you want to use another texture, you should use the addSpriteFrames:texture method.
+ *

+ * @param {String} url file path + * @param {HTMLImageElement|cc.Texture2D|string} texture + * @example + * // add SpriteFrames to SpriteFrameCache With File + * cc.spriteFrameCache.addSpriteFrames(s_grossiniPlist); + * cc.spriteFrameCache.addSpriteFrames(s_grossiniJson); + */ + addSpriteFrames: function (url, texture) { + cc.assert(url, cc._LogInfos.spriteFrameCache_addSpriteFrames_2); + + //Is it a SpriteFrame plist? + var dict = this._frameConfigCache[url] || cc.loader.getRes(url); + if(!dict || !dict["frames"]) + return; + + var frameConfig = this._frameConfigCache[url] || this._getFrameConfig(url); + //this._checkConflict(frameConfig); //TODO + this._createSpriteFrames(url, frameConfig, texture); + }, + // Function to check if frames to add exists already, if so there may be name conflit that must be solved _checkConflict: function (dictionary) { var framesDict = dictionary["frames"]; @@ -309,7 +289,7 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ * Sprite Frames stored in this file will be removed.
* It is convinient to call this method when a specific texture needs to be removed.
*

- * @param {String} url plist filename + * @param {String} url Plist filename */ removeSpriteFramesFromFile: function (url) { var self = this, spriteFrames = self._spriteFrames, @@ -320,7 +300,7 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ if (spriteFrames[key]) { delete(spriteFrames[key]); for (var alias in aliases) {//remove alias - if(aliases[alias] == key) delete aliases[alias]; + if(aliases[alias] === key) delete aliases[alias]; } } } @@ -329,7 +309,7 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ /** *

* Removes all Sprite Frames associated with the specified textures.
- * It is convinient to call this method when a specific texture needs to be removed. + * It is convenient to call this method when a specific texture needs to be removed. *

* @param {HTMLImageElement|HTMLCanvasElement|cc.Texture2D} texture */ @@ -337,10 +317,10 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ var self = this, spriteFrames = self._spriteFrames, aliases = self._spriteFramesAliases; for (var key in spriteFrames) { var frame = spriteFrames[key]; - if (frame && (frame.getTexture() == texture)) { + if (frame && (frame.getTexture() === texture)) { delete(spriteFrames[key]); for (var alias in aliases) {//remove alias - if(aliases[alias] == key) delete aliases[alias]; + if(aliases[alias] === key) delete aliases[alias]; } } } @@ -368,7 +348,6 @@ cc.spriteFrameCache = /** @lends cc.spriteFrameCache# */{ if(!frame) delete self._spriteFramesAliases[name]; } } - if (!frame) cc.log(cc._LogInfos.spriteFrameCache_getSpriteFrame, name); return frame; }, diff --git a/cocos2d/core/sprites/CCSpriteWebGLRenderCmd.js b/cocos2d/core/sprites/CCSpriteWebGLRenderCmd.js new file mode 100644 index 0000000000..78a83f5736 --- /dev/null +++ b/cocos2d/core/sprites/CCSpriteWebGLRenderCmd.js @@ -0,0 +1,493 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//Sprite's WebGL render command +(function() { + cc.Sprite.WebGLRenderCmd = function (renderable) { + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + + this._quad = new cc.V3F_C4B_T2F_Quad(); + this._quadWebBuffer = cc._renderContext.createBuffer(); + this._quadDirty = true; + this._dirty = false; + this._recursiveDirty = false; + }; + + var proto = cc.Sprite.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.Sprite.WebGLRenderCmd; + + proto.updateBlendFunc = function (blendFunc) {}; + + proto.setDirtyFlag = function(dirtyFlag){ + cc.Node.WebGLRenderCmd.prototype.setDirtyFlag.call(this, dirtyFlag); + this._dirty = true; + }; + + proto.setDirtyRecursively = function (value) { + this._recursiveDirty = value; + this._dirty = value; + // recursively set dirty + var locChildren = this._node._children, child, l = locChildren ? locChildren.length : 0; + for (var i = 0; i < l; i++) { + child = locChildren[i]; + (child instanceof cc.Sprite) && child._renderCmd.setDirtyRecursively(value); + } + }; + + proto._setBatchNodeForAddChild = function (child) { + var node = this._node; + if (node._batchNode) { + if (!(child instanceof cc.Sprite)) { + cc.log(cc._LogInfos.Sprite_addChild); + return false; + } + if (child.texture._webTextureObj !== node.textureAtlas.texture._webTextureObj) + cc.log(cc._LogInfos.Sprite_addChild_2); + + //put it in descendants array of batch node + node._batchNode.appendChild(child); + if (!node._reorderChildDirty) + node._setReorderChildDirtyRecursively(); + } + return true; + }; + + proto._handleTextureForRotatedTexture = function (texture) { + return texture; + }; + + proto.isFrameDisplayed = function (frame) { + var node = this._node; + return (cc.rectEqualToRect(frame.getRect(), node._rect) && frame.getTexture().getName() === node._texture.getName() + && cc.pointEqualToPoint(frame.getOffset(), node._unflippedOffsetPositionFromCenter)); + }; + + proto._init = function () { + var tempColor = {r: 255, g: 255, b: 255, a: 255}, quad = this._quad; + quad.bl.colors = tempColor; + quad.br.colors = tempColor; + quad.tl.colors = tempColor; + quad.tr.colors = tempColor; + this._quadDirty = true; + }; + + proto._resetForBatchNode = function () { + var node = this._node; + var x1 = node._offsetPosition.x; + var y1 = node._offsetPosition.y; + var x2 = x1 + node._rect.width; + var y2 = y1 + node._rect.height; + var locQuad = this._quad; + locQuad.bl.vertices = {x: x1, y: y1, z: 0}; + locQuad.br.vertices = {x: x2, y: y1, z: 0}; + locQuad.tl.vertices = {x: x1, y: y2, z: 0}; + locQuad.tr.vertices = {x: x2, y: y2, z: 0}; + this._quadDirty = true; + }; + + proto.getQuad = function () { + return this._quad; + }; + + proto._updateForSetSpriteFrame = function () {}; + + proto._spriteFrameLoadedCallback = function (spriteFrame) { + this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); + this.dispatchEvent("load"); + }; + + proto._textureLoadedCallback = function (sender) { + var renderCmd = this._renderCmd; + if (this._textureLoaded) + return; + + this._textureLoaded = true; + var locRect = this._rect; + if (!locRect) { + locRect = cc.rect(0, 0, sender.width, sender.height); + } else if (cc._rectEqualToZero(locRect)) { + locRect.width = sender.width; + locRect.height = sender.height; + } + + this.texture = sender; + this.setTextureRect(locRect, this._rectRotated); + + // by default use "Self Render". + // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" + this.setBatchNode(this._batchNode); + renderCmd._quadDirty = true; + this.dispatchEvent("load"); + }; + + proto._setTextureCoords = function (rect, needConvert) { + if (needConvert === undefined) + needConvert = true; + if (needConvert) + rect = cc.rectPointsToPixels(rect); + var node = this._node; + + var tex = node._batchNode ? node.textureAtlas.texture : node._texture; + if (!tex) + return; + + var atlasWidth = tex.pixelsWidth; + var atlasHeight = tex.pixelsHeight; + + var left, right, top, bottom, tempSwap, locQuad = this._quad; + if (node._rectRotated) { + if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { + left = (2 * rect.x + 1) / (2 * atlasWidth); + right = left + (rect.height * 2 - 2) / (2 * atlasWidth); + top = (2 * rect.y + 1) / (2 * atlasHeight); + bottom = top + (rect.width * 2 - 2) / (2 * atlasHeight); + } else { + left = rect.x / atlasWidth; + right = (rect.x + rect.height) / atlasWidth; + top = rect.y / atlasHeight; + bottom = (rect.y + rect.width) / atlasHeight; + } + + if (node._flippedX) { + tempSwap = top; + top = bottom; + bottom = tempSwap; + } + + if (node._flippedY) { + tempSwap = left; + left = right; + right = tempSwap; + } + + locQuad.bl.texCoords.u = left; + locQuad.bl.texCoords.v = top; + locQuad.br.texCoords.u = left; + locQuad.br.texCoords.v = bottom; + locQuad.tl.texCoords.u = right; + locQuad.tl.texCoords.v = top; + locQuad.tr.texCoords.u = right; + locQuad.tr.texCoords.v = bottom; + } else { + if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { + left = (2 * rect.x + 1) / (2 * atlasWidth); + right = left + (rect.width * 2 - 2) / (2 * atlasWidth); + top = (2 * rect.y + 1) / (2 * atlasHeight); + bottom = top + (rect.height * 2 - 2) / (2 * atlasHeight); + } else { + left = rect.x / atlasWidth; + right = (rect.x + rect.width) / atlasWidth; + top = rect.y / atlasHeight; + bottom = (rect.y + rect.height) / atlasHeight; + } + + if (node._flippedX) { + tempSwap = left; + left = right; + right = tempSwap; + } + + if (node._flippedY) { + tempSwap = top; + top = bottom; + bottom = tempSwap; + } + + locQuad.bl.texCoords.u = left; + locQuad.bl.texCoords.v = bottom; + locQuad.br.texCoords.u = right; + locQuad.br.texCoords.v = bottom; + locQuad.tl.texCoords.u = left; + locQuad.tl.texCoords.v = top; + locQuad.tr.texCoords.u = right; + locQuad.tr.texCoords.v = top; + } + this._quadDirty = true; + }; + + proto.transform = function(parentCmd, recursive){ + cc.Node.WebGLRenderCmd.prototype.transform.call(this, parentCmd, recursive); + this._dirty = true; //use for batching + }; + + proto._setColorDirty = function () {}; + + proto._updateColor = function () { + var locDisplayedColor = this._displayedColor, locDisplayedOpacity = this._displayedOpacity, node = this._node; + var color4 = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: locDisplayedOpacity}; + // special opacity for premultiplied textures + if (node._opacityModifyRGB) { + color4.r *= locDisplayedOpacity / 255.0; + color4.g *= locDisplayedOpacity / 255.0; + color4.b *= locDisplayedOpacity / 255.0; + } + var locQuad = this._quad; + locQuad.bl.colors = color4; + locQuad.br.colors = color4; + locQuad.tl.colors = color4; + locQuad.tr.colors = color4; + + // renders using Sprite Manager + if (node._batchNode) { + if (node.atlasIndex !== cc.Sprite.INDEX_NOT_INITIALIZED) { + node.textureAtlas.updateQuad(locQuad, node.atlasIndex) + } else { + // no need to set it recursively + // update dirty_, don't update recursiveDirty_ + this._dirty = true; + } + } + // self render + // do nothing + this._quadDirty = true; + }; + + proto._updateBlendFunc = function () { + if (this._batchNode) { + cc.log(cc._LogInfos.Sprite__updateBlendFunc); + return; + } + + // it's possible to have an untextured sprite + var node = this._node; + if (!node._texture || !node._texture.hasPremultipliedAlpha()) { + node._blendFunc.src = cc.SRC_ALPHA; + node._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + node.opacityModifyRGB = false; + } else { + node._blendFunc.src = cc.BLEND_SRC; + node._blendFunc.dst = cc.BLEND_DST; + node.opacityModifyRGB = true; + } + }; + + proto._setTexture = function (texture) { + var node = this._node; + // If batchnode, then texture id should be the same + if (node._batchNode) { + if(node._batchNode.texture !== texture){ + cc.log(cc._LogInfos.Sprite_setTexture); + return; + } + }else{ + if(node._texture !== texture){ + node._textureLoaded = texture ? texture._textureLoaded : false; + node._texture = texture; + this._updateBlendFunc(); + } + } + + if (texture) + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + else + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_COLOR); + + }; + + proto.updateTransform = function () { //called only at batching. + var _t = this, node = this._node; + + // recalculate matrix only if it is dirty + if (this._dirty) { + var locQuad = _t._quad, locParent = node._parent; + // If it is not visible, or one of its ancestors is not visible, then do nothing: + if (!node._visible || ( locParent && locParent !== node._batchNode && locParent._shouldBeHidden)) { + locQuad.br.vertices = locQuad.tl.vertices = locQuad.tr.vertices = locQuad.bl.vertices = {x: 0, y: 0, z: 0}; + node._shouldBeHidden = true; + } else { + node._shouldBeHidden = false; + if(this._dirtyFlag !== 0){ //because changing color and opacity uses dirty flag at visit, but visit doesn't call at batching. + this.updateStatus(); + this._dirtyFlag = 0; + } + + if (!locParent || locParent === node._batchNode) { + node._transformToBatch = _t.getNodeToParentTransform(); + } else { + node._transformToBatch = cc.affineTransformConcat(_t.getNodeToParentTransform(), locParent._transformToBatch); + } + + // + // calculate the Quad based on the Affine Matrix + // + var locTransformToBatch = node._transformToBatch; + var rect = node._rect; + var x1 = node._offsetPosition.x; + var y1 = node._offsetPosition.y; + + var x2 = x1 + rect.width; + var y2 = y1 + rect.height; + var x = locTransformToBatch.tx; + var y = locTransformToBatch.ty; + + var cr = locTransformToBatch.a; + var sr = locTransformToBatch.b; + var cr2 = locTransformToBatch.d; + var sr2 = -locTransformToBatch.c; + var ax = x1 * cr - y1 * sr2 + x; + var ay = x1 * sr + y1 * cr2 + y; + + var bx = x2 * cr - y1 * sr2 + x; + var by = x2 * sr + y1 * cr2 + y; + + var cx = x2 * cr - y2 * sr2 + x; + var cy = x2 * sr + y2 * cr2 + y; + + var dx = x1 * cr - y2 * sr2 + x; + var dy = x1 * sr + y2 * cr2 + y; + + var locVertexZ = node._vertexZ; + if (!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { + ax = 0 | ax; + ay = 0 | ay; + bx = 0 | bx; + by = 0 | by; + cx = 0 | cx; + cy = 0 | cy; + dx = 0 | dx; + dy = 0 | dy; + } + locQuad.bl.vertices = {x: ax, y: ay, z: locVertexZ}; + locQuad.br.vertices = {x: bx, y: by, z: locVertexZ}; + locQuad.tl.vertices = {x: dx, y: dy, z: locVertexZ}; + locQuad.tr.vertices = {x: cx, y: cy, z: locVertexZ}; + } + node.textureAtlas.updateQuad(locQuad, node.atlasIndex); + node._recursiveDirty = false; + this._dirty = false; + } + + // recursively iterate over children + if (node._hasChildren) + node._arrayMakeObjectsPerformSelector(node._children, cc.Node._stateCallbackType.updateTransform); + + /*if (cc.SPRITE_DEBUG_DRAW) { //TODO + // draw bounding box + var vertices = [ + cc.p(_t._quad.bl.vertices.x, _t._quad.bl.vertices.y), + cc.p(_t._quad.br.vertices.x, _t._quad.br.vertices.y), + cc.p(_t._quad.tr.vertices.x, _t._quad.tr.vertices.y), + cc.p(_t._quad.tl.vertices.x, _t._quad.tl.vertices.y) + ]; + cc._drawingUtil.drawPoly(vertices, 4, true); + }*/ + }; + + proto._checkTextureBoundary = function (texture, rect, rotated) { + if (texture && texture.url) { + var _x, _y; + if (rotated) { + _x = rect.x + rect.height; + _y = rect.y + rect.width; + } else { + _x = rect.x + rect.width; + _y = rect.y + rect.height; + } + if (_x > texture.width) { + cc.error(cc._LogInfos.RectWidth, texture.url); + } + if (_y > texture.height) { + cc.error(cc._LogInfos.RectHeight, texture.url); + } + } + }; + + proto.rendering = function (ctx) { + var node = this._node, locTexture = node._texture; + if ((locTexture &&!locTexture._textureLoaded) || this._displayedOpacity === 0) + return; + + var gl = ctx || cc._renderContext ; + //cc.assert(!_t._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called"); + + if (locTexture) { + if (locTexture._textureLoaded) { + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + //optimize performance for javascript + cc.glBindTexture2DN(0, locTexture); // = cc.glBindTexture2D(locTexture); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); + + gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); + if (this._quadDirty) { + gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.DYNAMIC_DRAW); + this._quadDirty = false; + } + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0); //cc.VERTEX_ATTRIB_POSITION + gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12); //cc.VERTEX_ATTRIB_COLOR + gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16); //cc.VERTEX_ATTRIB_TEX_COORDS + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + } else { + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + cc.glBindTexture2D(null); + + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); + + gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); + if (this._quadDirty) { + gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.STATIC_DRAW); + this._quadDirty = false; + } + gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); + gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + cc.g_NumberOfDraws++; + + if (cc.SPRITE_DEBUG_DRAW === 0 && !node._showNode) + return; + + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + //cc.kmGLPushMatrixWitMat4(node._stackMatrix); + cc.current_stack.stack.push(cc.current_stack.top); + cc.current_stack.top = this._stackMatrix; + + if (cc.SPRITE_DEBUG_DRAW === 1 || node._showNode) { + // draw bounding box + var locQuad = this._quad; + var verticesG1 = [ + cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y), + cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y), + cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y), + cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y) + ]; + cc._drawingUtil.drawPoly(verticesG1, 4, true); + } else if (cc.SPRITE_DEBUG_DRAW === 2) { + // draw texture box + var drawRectG2 = node.getTextureRect(); + var offsetPixG2 = node.getOffsetPosition(); + var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y), + cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y + drawRectG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawRectG2.height)]; + cc._drawingUtil.drawPoly(verticesG2, 4, true); + } // CC_SPRITE_DEBUG_DRAW + cc.current_stack.top = cc.current_stack.stack.pop(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/core/sprites/SpritesPropertyDefine.js b/cocos2d/core/sprites/SpritesPropertyDefine.js index 44f00ba839..20e8cc938a 100644 --- a/cocos2d/core/sprites/SpritesPropertyDefine.js +++ b/cocos2d/core/sprites/SpritesPropertyDefine.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,7 +24,7 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.PrototypeSprite = function () { +cc._tmp.PrototypeSprite = function () { var _p = cc.Sprite.prototype; // Override properties diff --git a/cocos2d/core/sprites/SpritesWebGL.js b/cocos2d/core/sprites/SpritesWebGL.js deleted file mode 100644 index 57b12e09ef..0000000000 --- a/cocos2d/core/sprites/SpritesWebGL.js +++ /dev/null @@ -1,560 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of _t software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -_tmp.WebGLSprite = function () { - - - var _p = cc.Sprite.prototype; - - _p._spriteFrameLoadedCallback = function(spriteFrame){ - this.setNodeDirty(true); - this.setTextureRect(spriteFrame.getRect(), spriteFrame.isRotated(), spriteFrame.getOriginalSize()); - this._callLoadedEventCallbacks(); - }; - - _p.setOpacityModifyRGB = function (modify) { - if (this._opacityModifyRGB !== modify) { - this._opacityModifyRGB = modify; - this.updateColor(); - } - }; - - _p.updateDisplayedOpacity = function (parentOpacity) { - cc.NodeRGBA.prototype.updateDisplayedOpacity.call(this, parentOpacity); - this.updateColor(); - }; - - _p.ctor = function (fileName, rect) { - var self = this; - cc.NodeRGBA.prototype.ctor.call(self); - self._shouldBeHidden = false; - self._offsetPosition = cc.p(0, 0); - self._unflippedOffsetPositionFromCenter = cc.p(0, 0); - self._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; - self._rect = cc.rect(0,0,0,0); - - self._quad = new cc.V3F_C4B_T2F_Quad(); - self._quadWebBuffer = cc._renderContext.createBuffer(); - self._quadDirty = true; - - self._textureLoaded = true; - - self._softInit(fileName, rect); - }; - - _p.setBlendFunc = function (src, dst) { - var locBlendFunc = this._blendFunc; - if (dst === undefined) { - locBlendFunc.src = src.src; - locBlendFunc.dst = src.dst; - } else { - locBlendFunc.src = src; - locBlendFunc.dst = dst; - } - }; - - _p.init = function () { - var _t = this; - if (arguments.length > 0) - return _t.initWithFile(arguments[0], arguments[1]); - - cc.NodeRGBA.prototype.init.call(_t); - _t.dirty = _t._recursiveDirty = false; - _t._opacityModifyRGB = true; - - _t._blendFunc.src = cc.BLEND_SRC; - _t._blendFunc.dst = cc.BLEND_DST; - - // update texture (calls _updateBlendFunc) - _t.texture = null; - _t._textureLoaded = true; - _t._flippedX = _t._flippedY = false; - - // default transform anchor: center - _t.anchorX = 0.5; - _t.anchorY = 0.5; - - // zwoptex default values - _t._offsetPosition.x = 0; - _t._offsetPosition.y = 0; - - _t._hasChildren = false; - - // Atlas: Color - var tempColor = {r: 255, g: 255, b: 255, a: 255}; - _t._quad.bl.colors = tempColor; - _t._quad.br.colors = tempColor; - _t._quad.tl.colors = tempColor; - _t._quad.tr.colors = tempColor; - _t._quadDirty = true; - - // updated in "useSelfRender" - // Atlas: TexCoords - _t.setTextureRect(cc.rect(0, 0, 0, 0), false, cc.size(0, 0)); - return true; - }; - - _p.initWithTexture = function (texture, rect, rotated) { - var _t = this; - var argnum = arguments.length; - - cc.assert(argnum!=0, cc._LogInfos.Sprite_initWithTexture); - - rotated = rotated || false; - - if (!cc.NodeRGBA.prototype.init.call(_t)) - return false; - - _t._batchNode = null; - _t._recursiveDirty = false; - _t.dirty = false; - _t._opacityModifyRGB = true; - - _t._blendFunc.src = cc.BLEND_SRC; - _t._blendFunc.dst = cc.BLEND_DST; - - _t._flippedX = _t._flippedY = false; - - // default transform anchor: center - _t.anchorX = 0.5; - _t.anchorY = 0.5; - - // zwoptex default values - _t._offsetPosition.x = 0; - _t._offsetPosition.y = 0; - _t._hasChildren = false; - - // Atlas: Color - var tmpColor = cc.color(255, 255, 255, 255); - var locQuad = _t._quad; - locQuad.bl.colors = tmpColor; - locQuad.br.colors = tmpColor; - locQuad.tl.colors = tmpColor; - locQuad.tr.colors = tmpColor; - - var locTextureLoaded = texture.isLoaded(); - _t._textureLoaded = locTextureLoaded; - - if (!locTextureLoaded) { - _t._rectRotated = rotated || false; - if (rect) { - var locRect = _t._rect; - locRect.x = rect.x; - locRect.y = rect.y; - locRect.width = rect.width; - locRect.height = rect.height; - } - texture.addLoadedEventListener(_t._textureLoadedCallback, _t); - return true; - } - - if (!rect) { - rect = cc.rect(0, 0, texture.width, texture.height); - } - _t.texture = texture; - _t.setTextureRect(rect, rotated); - - // by default use "Self Render". - // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" - _t.batchNode = null; - _t._quadDirty = true; - return true; - }; - - _p._textureLoadedCallback = function (sender) { - var _t = this; - if(_t._textureLoaded) - return; - - _t._textureLoaded = true; - var locRect = _t._rect; - if (!locRect) { - locRect = cc.rect(0, 0, sender.width, sender.height); - } else if (cc._rectEqualToZero(locRect)) { - locRect.width = sender.width; - locRect.height = sender.height; - } - - _t.texture = sender; - _t.setTextureRect(locRect, _t._rectRotated); - - // by default use "Self Render". - // if the sprite is added to a batchnode, then it will automatically switch to "batchnode Render" - _t.batchNode = _t._batchNode; - _t._quadDirty = true; - _t._callLoadedEventCallbacks(); - }; - - _p.setTextureRect = function (rect, rotated, untrimmedSize) { - var _t = this; - _t._rectRotated = rotated || false; - _t.setContentSize(untrimmedSize || rect); - - _t.setVertexRect(rect); - _t._setTextureCoords(rect); - - var relativeOffset = _t._unflippedOffsetPositionFromCenter; - if (_t._flippedX) - relativeOffset.x = -relativeOffset.x; - if (_t._flippedY) - relativeOffset.y = -relativeOffset.y; - - var locRect = _t._rect; - _t._offsetPosition.x = relativeOffset.x + (_t._contentSize.width - locRect.width) / 2; - _t._offsetPosition.y = relativeOffset.y + (_t._contentSize.height - locRect.height) / 2; - - // rendering using batch node - if (_t._batchNode) { - // update dirty, don't update _recursiveDirty - _t.dirty = true; - } else { - // self rendering - // Atlas: Vertex - var x1 = 0 + _t._offsetPosition.x; - var y1 = 0 + _t._offsetPosition.y; - var x2 = x1 + locRect.width; - var y2 = y1 + locRect.height; - - // Don't update Z. - var locQuad = _t._quad; - locQuad.bl.vertices = {x:x1, y:y1, z:0}; - locQuad.br.vertices = {x:x2, y:y1, z:0}; - locQuad.tl.vertices = {x:x1, y:y2, z:0}; - locQuad.tr.vertices = {x:x2, y:y2, z:0}; - - _t._quadDirty = true; - } - }; - - _p.updateTransform = function () { - var _t = this; - //cc.assert(_t._batchNode, "updateTransform is only valid when cc.Sprite is being rendered using an cc.SpriteBatchNode"); - - // recaculate matrix only if it is dirty - if (_t.dirty) { - var locQuad = _t._quad, locParent = _t._parent; - // If it is not visible, or one of its ancestors is not visible, then do nothing: - if (!_t._visible || ( locParent && locParent != _t._batchNode && locParent._shouldBeHidden)) { - locQuad.br.vertices = {x: 0, y: 0, z: 0}; - locQuad.tl.vertices = {x: 0, y: 0, z: 0}; - locQuad.tr.vertices = {x: 0, y: 0, z: 0}; - locQuad.bl.vertices = {x: 0, y: 0, z: 0}; - _t._shouldBeHidden = true; - } else { - _t._shouldBeHidden = false; - - if (!locParent || locParent == _t._batchNode) { - _t._transformToBatch = _t.nodeToParentTransform(); - } else { - //cc.assert(_t._parent instanceof cc.Sprite, "Logic error in CCSprite. Parent must be a CCSprite"); - _t._transformToBatch = cc.AffineTransformConcat(_t.nodeToParentTransform(), locParent._transformToBatch); - } - - // - // calculate the Quad based on the Affine Matrix - // - var locTransformToBatch = _t._transformToBatch; - var rect = _t._rect; - var x1 = _t._offsetPosition.x; - var y1 = _t._offsetPosition.y; - - var x2 = x1 + rect.width; - var y2 = y1 + rect.height; - var x = locTransformToBatch.tx; - var y = locTransformToBatch.ty; - - var cr = locTransformToBatch.a; - var sr = locTransformToBatch.b; - var cr2 = locTransformToBatch.d; - var sr2 = -locTransformToBatch.c; - var ax = x1 * cr - y1 * sr2 + x; - var ay = x1 * sr + y1 * cr2 + y; - - var bx = x2 * cr - y1 * sr2 + x; - var by = x2 * sr + y1 * cr2 + y; - - var cx = x2 * cr - y2 * sr2 + x; - var cy = x2 * sr + y2 * cr2 + y; - - var dx = x1 * cr - y2 * sr2 + x; - var dy = x1 * sr + y2 * cr2 + y; - - var locVertexZ = _t._vertexZ; - if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { - ax = 0 | ax; - ay = 0 | ay; - bx = 0 | bx; - by = 0 | by; - cx = 0 | cx; - cy = 0 | cy; - dx = 0 | dx; - dy = 0 | dy; - } - locQuad.bl.vertices = {x: ax, y: ay, z: locVertexZ}; - locQuad.br.vertices = {x: bx, y: by, z: locVertexZ}; - locQuad.tl.vertices = {x: dx, y: dy, z: locVertexZ}; - locQuad.tr.vertices = {x: cx, y: cy, z: locVertexZ}; - } - _t.textureAtlas.updateQuad(locQuad, _t.atlasIndex); - _t._recursiveDirty = false; - _t.dirty = false; - } - - // recursively iterate over children - if (_t._hasChildren) - _t._arrayMakeObjectsPerformSelector(_t._children, cc.Node.StateCallbackType.updateTransform); - - if (cc.SPRITE_DEBUG_DRAW) { - // draw bounding box - var vertices = [ - cc.p(_t._quad.bl.vertices.x, _t._quad.bl.vertices.y), - cc.p(_t._quad.br.vertices.x, _t._quad.br.vertices.y), - cc.p(_t._quad.tr.vertices.x, _t._quad.tr.vertices.y), - cc.p(_t._quad.tl.vertices.x, _t._quad.tl.vertices.y) - ]; - cc._drawingUtil.drawPoly(vertices, 4, true); - } - }; - - _p.addChild = function (child, localZOrder, tag) { - var _t = this; - - cc.assert(child, cc._LogInfos.Sprite_addChild_3); - - if (localZOrder == null) - localZOrder = child._localZOrder; - if (tag == null) - tag = child.tag; - - if (_t._batchNode) { - if(!(child instanceof cc.Sprite)){ - cc.log(cc._LogInfos.Sprite_addChild); - return; - } - if(child.texture._webTextureObj !== _t.textureAtlas.texture._webTextureObj) - cc.log(cc._LogInfos.Sprite_addChild_2); - - //put it in descendants array of batch node - _t._batchNode.appendChild(child); - if (!_t._reorderChildDirty) - _t._setReorderChildDirtyRecursively(); - } - - //cc.Node already sets isReorderChildDirty_ so _t needs to be after batchNode check - cc.NodeRGBA.prototype.addChild.call(_t, child, localZOrder, tag); - _t._hasChildren = true; - }; - - _p.setOpacity = function (opacity) { - cc.NodeRGBA.prototype.setOpacity.call(this, opacity); - this.updateColor(); - }; - - _p.setColor = function (color3) { - cc.NodeRGBA.prototype.setColor.call(this, color3); - this.updateColor(); - }; - - _p.updateDisplayedColor = function (parentColor) { - cc.NodeRGBA.prototype.updateDisplayedColor.call(this, parentColor); - this.updateColor(); - }; - - _p.setSpriteFrame = function (newFrame) { - var _t = this; - if(typeof(newFrame) == "string"){ - newFrame = cc.spriteFrameCache.getSpriteFrame(newFrame); - - cc.assert(newFrame, cc._LogInfos.Sprite_setSpriteFrame); - } - - _t.setNodeDirty(true); - var frameOffset = newFrame.getOffset(); - _t._unflippedOffsetPositionFromCenter.x = frameOffset.x; - _t._unflippedOffsetPositionFromCenter.y = frameOffset.y; - - var pNewTexture = newFrame.getTexture(); - var locTextureLoaded = newFrame.textureLoaded(); - if (!locTextureLoaded) { - _t._textureLoaded = false; - newFrame.addLoadedEventListener(function (sender) { - _t._textureLoaded = true; - var locNewTexture = sender.getTexture(); - if (locNewTexture != _t._texture) - _t.texture = locNewTexture; - _t.setTextureRect(sender.getRect(), sender.isRotated(), sender.getOriginalSize()); - - _t._callLoadedEventCallbacks(); - }, _t); - } - // update texture before updating texture rect - if (pNewTexture != _t._texture) - _t.texture = pNewTexture; - - // update rect - _t._rectRotated = newFrame.isRotated(); - _t.setTextureRect(newFrame.getRect(), _t._rectRotated, newFrame.getOriginalSize()); - }; - - _p.isFrameDisplayed = function (frame) { - return (cc.rectEqualToRect(frame.getRect(), this._rect) && frame.getTexture().getName() == this._texture.getName() - && cc.pointEqualToPoint(frame.getOffset(), this._unflippedOffsetPositionFromCenter)); - }; - - _p.setBatchNode = function (spriteBatchNode) { - var _t = this; - _t._batchNode = spriteBatchNode; // weak reference - - // self render - if (!_t._batchNode) { - _t.atlasIndex = cc.Sprite.INDEX_NOT_INITIALIZED; - _t.textureAtlas = null; - _t._recursiveDirty = false; - _t.dirty = false; - - var x1 = _t._offsetPosition.x; - var y1 = _t._offsetPosition.y; - var x2 = x1 + _t._rect.width; - var y2 = y1 + _t._rect.height; - var locQuad = _t._quad; - locQuad.bl.vertices = {x:x1, y:y1, z:0}; - locQuad.br.vertices = {x:x2, y:y1, z:0}; - locQuad.tl.vertices = {x:x1, y:y2, z:0}; - locQuad.tr.vertices = {x:x2, y:y2, z:0}; - - _t._quadDirty = true; - } else { - // using batch - _t._transformToBatch = cc.AffineTransformIdentity(); - _t.textureAtlas = _t._batchNode.textureAtlas; // weak ref - } - }; - - _p.setTexture = function (texture) { - var _t = this; - if(texture && (typeof(texture) === "string")){ - texture = cc.textureCache.addImage(texture); - _t.setTexture(texture); - - //TODO - var size = texture.getContentSize(); - _t.setTextureRect(cc.rect(0,0, size.width, size.height)); - return; - } - // CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteSheet - - cc.assert(!texture || (texture instanceof cc.Texture2D), cc._LogInfos.Sprite_setTexture_2); - - // If batchnode, then texture id should be the same - if(_t._batchNode && _t._batchNode.texture != texture) { - cc.log(cc._LogInfos.Sprite_setTexture); - return; - } - - if (texture) - _t.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); - else - _t.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_COLOR); - - if (!_t._batchNode && _t._texture != texture) { - _t._texture = texture; - _t._updateBlendFunc(); - } - }; - - _p.draw = function () { - var _t = this; - if (!_t._textureLoaded) - return; - - var gl = cc._renderContext, locTexture = _t._texture; - //cc.assert(!_t._batchNode, "If cc.Sprite is being rendered by cc.SpriteBatchNode, cc.Sprite#draw SHOULD NOT be called"); - - if (locTexture) { - if (locTexture._isLoaded) { - _t._shaderProgram.use(); - _t._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); - - cc.glBlendFunc(_t._blendFunc.src, _t._blendFunc.dst); - //optimize performance for javascript - cc.glBindTexture2DN(0, locTexture); // = cc.glBindTexture2D(locTexture); - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); - - gl.bindBuffer(gl.ARRAY_BUFFER, _t._quadWebBuffer); - if (_t._quadDirty) { - gl.bufferData(gl.ARRAY_BUFFER, _t._quad.arrayBuffer, gl.DYNAMIC_DRAW); - _t._quadDirty = false; - } - gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0); //cc.VERTEX_ATTRIB_POSITION - gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12); //cc.VERTEX_ATTRIB_COLOR - gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16); //cc.VERTEX_ATTRIB_TEX_COORDS - - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - } - } else { - _t._shaderProgram.use(); - _t._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); - - cc.glBlendFunc(_t._blendFunc.src, _t._blendFunc.dst); - cc.glBindTexture2D(null); - - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR); - - gl.bindBuffer(gl.ARRAY_BUFFER, _t._quadWebBuffer); - if (_t._quadDirty) { - cc._renderContext.bufferData(cc._renderContext.ARRAY_BUFFER, _t._quad.arrayBuffer, cc._renderContext.STATIC_DRAW); - _t._quadDirty = false; - } - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); - gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); - } - cc.g_NumberOfDraws++; - if (cc.SPRITE_DEBUG_DRAW === 0 && !_t._showNode) - return; - - if (cc.SPRITE_DEBUG_DRAW === 1 || _t._showNode) { - // draw bounding box - var locQuad = _t._quad; - var verticesG1 = [ - cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y), - cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y), - cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y), - cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y) - ]; - cc._drawingUtil.drawPoly(verticesG1, 4, true); - } else if (cc.SPRITE_DEBUG_DRAW === 2) { - // draw texture box - var drawRectG2 = _t.getTextureRect(); - var offsetPixG2 = _t.getOffsetPosition(); - var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y), - cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y + drawRectG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawRectG2.height)]; - cc._drawingUtil.drawPoly(verticesG2, 4, true); - } // CC_SPRITE_DEBUG_DRAW - }; - - delete _p; -} \ No newline at end of file diff --git a/cocos2d/core/support/CCPointExtension.js b/cocos2d/core/support/CCPointExtension.js index 7a8fef6a4c..9771087379 100644 --- a/cocos2d/core/support/CCPointExtension.js +++ b/cocos2d/core/support/CCPointExtension.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -192,7 +192,7 @@ cc.pLength = function (v) { * Calculates the distance between two points * @param {cc.Point} v1 * @param {cc.Point} v2 - * @return {cc.pLength} + * @return {Number} */ cc.pDistance = function (v1, v2) { return cc.pLength(cc.pSub(v1, v2)); @@ -204,7 +204,8 @@ cc.pDistance = function (v1, v2) { * @return {cc.Point} */ cc.pNormalize = function (v) { - return cc.pMult(v, 1.0 / cc.pLength(v)); + var n = cc.pLength(v); + return n === 0 ? cc.p(v) : cc.pMult(v, 1.0 / n); }; /** @@ -356,6 +357,11 @@ cc.pRotateByAngle = function (v, pivot, angle) { /** * A general line-line intersection test + * indicating successful intersection of a line
+ * note that to truly test intersection for segments we have to make
+ * sure that s & t lie within [0..1] and for rays, make sure s & t > 0
+ * the hit point is p3 + t * (p4 - p3);
+ * the hit point also is p1 + s * (p2 - p1); * @param {cc.Point} A A is the startpoint for the first line P1 = (p1 - p2). * @param {cc.Point} B B is the endpoint for the first line P1 = (p1 - p2). * @param {cc.Point} C C is the startpoint for the second line P2 = (p3 - p4). @@ -363,14 +369,9 @@ cc.pRotateByAngle = function (v, pivot, angle) { * @param {cc.Point} retP retP.x is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)),
* retP.y is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)). * @return {Boolean} - * indicating successful intersection of a line
- * note that to truly test intersection for segments we have to make
- * sure that s & t lie within [0..1] and for rays, make sure s & t > 0
- * the hit point is p3 + t * (p4 - p3);
- * the hit point also is p1 + s * (p2 - p1); */ cc.pLineIntersect = function (A, B, C, D, retP) { - if ((A.x == B.x && A.y == B.y) || (C.x == D.x && C.y == D.y)) { + if ((A.x === B.x && A.y === B.y) || (C.x === D.x && C.y === D.y)) { return false; } var BAx = B.x - A.x; @@ -385,8 +386,8 @@ cc.pLineIntersect = function (A, B, C, D, retP) { retP.x = DCx * ACy - DCy * ACx; retP.y = BAx * ACy - BAy * ACx; - if (denom == 0) { - if (retP.x == 0 || retP.y == 0) { + if (denom === 0) { + if (retP.x === 0 || retP.y === 0) { // Lines incident return true; } @@ -446,7 +447,7 @@ cc.pIntersectPoint = function (A, B, C, D) { */ cc.pSameAs = function (A, B) { if ((A != null) && (B != null)) { - return (A.x == B.x && A.y == B.y); + return (A.x === B.x && A.y === B.y); } return false; }; @@ -456,48 +457,58 @@ cc.pSameAs = function (A, B) { // High Perfomance In Place Operationrs --------------------------------------- /** - * sets the position of the point to 0 - */ + * sets the position of the point to 0 + * @param {cc.Point} v + */ cc.pZeroIn = function(v) { v.x = 0; v.y = 0; }; /** - * copies the position of one point to another - */ + * copies the position of one point to another + * @param {cc.Point} v1 + * @param {cc.Point} v2 + */ cc.pIn = function(v1, v2) { v1.x = v2.x; v1.y = v2.y; }; /** - * multiplies the point with the given factor (inplace) - */ + * multiplies the point with the given factor (inplace) + * @param {cc.Point} point + * @param {Number} floatVar + */ cc.pMultIn = function(point, floatVar) { point.x *= floatVar; point.y *= floatVar; }; /** - * subtracts one point from another (inplace) - */ + * subtracts one point from another (inplace) + * @param {cc.Point} v1 + * @param {cc.Point} v2 + */ cc.pSubIn = function(v1, v2) { v1.x -= v2.x; v1.y -= v2.y; }; /** - * adds one point to another (inplace) - */ + * adds one point to another (inplace) + * @param {cc.Point} v1 + * @param {cc.point} v2 + */ cc.pAddIn = function(v1, v2) { v1.x += v2.x; v1.y += v2.y; }; /** - * normalizes the point (inplace) - */ + * normalizes the point (inplace) + * @param {cc.Point} v + */ cc.pNormalizeIn = function(v) { cc.pMultIn(v, 1.0 / Math.sqrt(v.x * v.x + v.y * v.y)); }; diff --git a/cocos2d/core/support/CCVertex.js b/cocos2d/core/support/CCVertex.js index a5b3f06026..44b92f0d22 100644 --- a/cocos2d/core/support/CCVertex.js +++ b/cocos2d/core/support/CCVertex.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2009 Valentin Milea http://www.cocos2d-x.org @@ -74,7 +76,7 @@ cc.vertexLineToPolygon = function (points, stroke, vertices, offset, nuPoints) { } // Validate vertexes - offset = (offset == 0) ? 0 : offset - 1; + offset = (offset === 0) ? 0 : offset - 1; for (i = offset; i < nuPointsMinus; i++) { idx = i * 2; var idx1 = idx + 2; @@ -115,7 +117,7 @@ cc.vertexLineIntersect = function (Ax, Ay, Bx, By, Cx, Cy, Dx, Dy) { var distAB, theCos, theSin, newX; // FAIL: Line undefined - if ((Ax == Bx && Ay == By) || (Cx == Dx && Cy == Dy)) + if ((Ax === Bx && Ay === By) || (Cx === Dx && Cy === Dy)) return {isSuccess:false, value:0}; // Translate system to make A the origin @@ -140,11 +142,29 @@ cc.vertexLineIntersect = function (Ax, Ay, Bx, By, Cx, Cy, Dx, Dy) { Dx = newX; // FAIL: Lines are parallel. - if (Cy == Dy) return {isSuccess:false, value:0}; + if (Cy === Dy) return {isSuccess:false, value:0}; // Discover the relative position of the intersection in the line AB var t = (Dx + (Cx - Dx) * Dy / (Dy - Cy)) / distAB; // Success. return {isSuccess:true, value:t}; +}; + +/** + * returns wheter or not polygon defined by vertex list is clockwise + * @param {Array} verts + * @return {Boolean} + */ +cc.vertexListIsClockwise = function(verts) { + for (var i = 0, len = verts.length; i < len; i++) { + var a = verts[i]; + var b = verts[(i + 1) % len]; + var c = verts[(i + 2) % len]; + + if (cc.pCross(cc.pSub(b, a), cc.pSub(c, b)) > 0) + return false; + } + + return true; }; \ No newline at end of file diff --git a/cocos2d/core/support/TransformUtils.js b/cocos2d/core/support/TransformUtils.js index 80cd797290..bb57c6f8c4 100644 --- a/cocos2d/core/support/TransformUtils.js +++ b/cocos2d/core/support/TransformUtils.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2009 Valentin Milea http://www.cocos2d-x.org diff --git a/cocos2d/core/textures/CCTexture2D.js b/cocos2d/core/textures/CCTexture2D.js index cd1401d309..dca144d060 100644 --- a/cocos2d/core/textures/CCTexture2D.js +++ b/cocos2d/core/textures/CCTexture2D.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -110,6 +110,7 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { * @extends cc.Class * * @property {WebGLTexture} name - <@readonly> WebGLTexture Object + * @property {Number} defaultPixelFormat - The default pixel format * @property {Number} pixelFormat - <@readonly> Pixel format of the texture * @property {Number} pixelsWidth - <@readonly> Width in pixels * @property {Number} pixelsHeight - <@readonly> Height in pixels @@ -119,29 +120,40 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { * @property {Number} maxS - Texture max S * @property {Number} maxT - Texture max T */ - - cc.Texture2D = cc.Class.extend({ + cc.Texture2D = cc.Class.extend(/** @lends cc.Texture2D# */{ _contentSize: null, - _isLoaded: false, + _textureLoaded: false, _htmlElementObj: null, - _loadedEventListeners: null, - url: null, + _pattern: null, ctor: function () { this._contentSize = cc.size(0, 0); - this._isLoaded = false; + this._textureLoaded = false; this._htmlElementObj = null; + this._pattern = ""; }, + /** + * get width in pixels + * @return {Number} + */ getPixelsWide: function () { return this._contentSize.width; }, + /** + * get height of in pixels + * @return {Number} + */ getPixelsHigh: function () { return this._contentSize.height; }, + /** + * get content size + * @returns {cc.Size} + */ getContentSize: function () { var locScaleFactor = cc.contentScaleFactor(); return cc.size(this._contentSize.width / locScaleFactor, this._contentSize.height / locScaleFactor); @@ -154,45 +166,67 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { return this._contentSize.height / cc.contentScaleFactor(); }, + /** + * get content size in pixels + * @returns {cc.Size} + */ getContentSizeInPixels: function () { return this._contentSize; }, + /** + * init with HTML element + * @param {HTMLImageElement|HTMLCanvasElement} element + */ initWithElement: function (element) { if (!element) return; this._htmlElementObj = element; + this._contentSize.width = element.width; + this._contentSize.height = element.height; + this._textureLoaded = true; }, /** * HTMLElement Object getter - * @return {HTMLElement} + * @return {HTMLImageElement|HTMLCanvasElement} */ getHtmlElementObj: function () { return this._htmlElementObj; }, + /** + * check whether texture is loaded + * @returns {boolean} + */ isLoaded: function () { - return this._isLoaded; + return this._textureLoaded; }, + /** + * handle loaded texture + */ handleLoadedTexture: function () { - var self = this - if (self._isLoaded) return; + var self = this; + if (self._textureLoaded) return; if (!self._htmlElementObj) { var img = cc.loader.getRes(self.url); if (!img) return; self.initWithElement(img); } - self._isLoaded = true; var locElement = self._htmlElementObj; self._contentSize.width = locElement.width; self._contentSize.height = locElement.height; - self._callLoadedEventCallbacks(); + //dispatch load event to listener. + self.dispatchEvent("load"); }, + /** + * description of cc.Texture2D + * @returns {string} + */ description: function () { return ""; }, @@ -213,7 +247,7 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { }, releaseTexture: function () { - //support only in WebGl rendering mode + cc.loader.release(this.url); }, getName: function () { @@ -280,23 +314,53 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { //support only in WebGl rendering mode }, + /** + * init with ETC file + * @warning does not support on HTML5 + */ initWithETCFile: function (file) { cc.log(cc._LogInfos.Texture2D_initWithETCFile); return false; }, + /** + * init with PVR file + * @warning does not support on HTML5 + */ initWithPVRFile: function (file) { cc.log(cc._LogInfos.Texture2D_initWithPVRFile); return false; }, + /** + * init with PVRTC data + * @warning does not support on HTML5 + */ initWithPVRTCData: function (data, level, bpp, hasAlpha, length, pixelFormat) { cc.log(cc._LogInfos.Texture2D_initWithPVRTCData); return false; }, - setTexParameters: function (texParams) { - //support only in WebGl rendering mode + setTexParameters: function (texParams, magFilter, wrapS, wrapT) { + if(magFilter !== undefined) + texParams = {minFilter: texParams, magFilter: magFilter, wrapS: wrapS, wrapT: wrapT}; + + if(texParams.wrapS === cc.REPEAT && texParams.wrapT === cc.REPEAT){ + this._pattern = "repeat"; + return; + } + + if(texParams.wrapS === cc.REPEAT ){ + this._pattern = "repeat-x"; + return; + } + + if(texParams.wrapT === cc.REPEAT){ + this._pattern = "repeat-y"; + return; + } + + this._pattern = ""; }, setAntiAliasTexParameters: function () { @@ -321,40 +385,71 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { return -1; }, + /** + * add listener for loaded event + * @param {Function} callback + * @param {cc.Node} target + * @deprecated since 3.1, please use addEventListener instead + */ addLoadedEventListener: function (callback, target) { - if (!this._loadedEventListeners) - this._loadedEventListeners = []; - this._loadedEventListeners.push({eventCallback: callback, eventTarget: target}); + this.addEventListener("load", callback, target); }, + /** + * remove listener from listeners by target + * @param {cc.Node} target + */ removeLoadedEventListener: function (target) { - if (!this._loadedEventListeners) - return; - var locListeners = this._loadedEventListeners; - for (var i = 0; i < locListeners.length; i++) { - var selCallback = locListeners[i]; - if (selCallback.eventTarget == target) { - locListeners.splice(i, 1); - } - } + this.removeEventListener("load", target); }, - _callLoadedEventCallbacks: function () { - if (!this._loadedEventListeners) + //hack for gray effect + _grayElementObj: null, + _backupElement: null, + _isGray: false, + _switchToGray: function(toGray){ + if(!this._textureLoaded || this._isGray === toGray) return; - var locListeners = this._loadedEventListeners; - for (var i = 0, len = locListeners.length; i < len; i++) { - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); + this._isGray = toGray; + if(this._isGray){ + this._backupElement = this._htmlElementObj; + if(!this._grayElementObj) + this._grayElementObj = cc.Texture2D._generateGrayTexture(this._htmlElementObj); + this._htmlElementObj = this._grayElementObj; + } else { + if(this._backupElement !== null) + this._htmlElementObj = this._backupElement; } - locListeners.length = 0; } }); + cc.Texture2D._generateGrayTexture = function(texture, rect, renderCanvas){ + if (texture === null) + return null; + renderCanvas = renderCanvas || cc.newElement("canvas"); + rect = rect || cc.rect(0, 0, texture.width, texture.height); + renderCanvas.width = rect.width; + renderCanvas.height = rect.height; + + var context = renderCanvas.getContext("2d"); + context.drawImage(texture, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); + var imgData = context.getImageData(0, 0, rect.width, rect.height); + var data = imgData.data; + for (var i = 0, len = data.length; i < len; i += 4) { + data[i] = data[i + 1] = data[i + 2] = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2]; + } + context.putImageData(imgData, 0, 0); + return renderCanvas; + }; + } else { - _tmp.WebGLTexture2D(); - delete _tmp.WebGLTexture2D; + cc.assert(cc.isFunction(cc._tmp.WebGLTexture2D), cc._LogInfos.MissingFile, "TexturesWebGL.js"); + cc._tmp.WebGLTexture2D(); + delete cc._tmp.WebGLTexture2D; } -_tmp.PrototypeTexture2D(); -delete _tmp.PrototypeTexture2D; \ No newline at end of file +cc.EventHelper.prototype.apply(cc.Texture2D.prototype); + +cc.assert(cc.isFunction(cc._tmp.PrototypeTexture2D), cc._LogInfos.MissingFile, "TexturesPropertyDefine.js"); +cc._tmp.PrototypeTexture2D(); +delete cc._tmp.PrototypeTexture2D; \ No newline at end of file diff --git a/cocos2d/core/textures/CCTextureAtlas.js b/cocos2d/core/textures/CCTextureAtlas.js index 1c22cf49dd..6de91ca14f 100644 --- a/cocos2d/core/textures/CCTextureAtlas.js +++ b/cocos2d/core/textures/CCTextureAtlas.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -42,7 +42,7 @@ * @property {Number} totalQuads - <@readonly> Quantity of quads that are going to be drawn. * @property {Array} quads - <@readonly> Quads that are going to be rendered */ -cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ +cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ //WebGL only dirty: false, texture: null, @@ -59,7 +59,7 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ /** *

Creates a TextureAtlas with an filename and with an initial capacity for Quads.
* The TextureAtlas capacity can be increased in runtime.

- * @constructor + * Constructor of cc.TextureAtlas * @param {String|cc.Texture2D} fileName * @param {Number} capacity * @example @@ -74,10 +74,9 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ ctor: function (fileName, capacity) { this._buffersVBO = []; - if (typeof(fileName) == "string") { + if (cc.isString(fileName)) { this.initWithFile(fileName, capacity); - } - else if (fileName instanceof cc.Texture2D) { + } else if (fileName instanceof cc.Texture2D) { this.initWithTexture(fileName, capacity); } }, @@ -142,8 +141,8 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * @param {Array} quads */ setQuads: function (quads) { - this._quads = quads; //TODO need re-binding + this._quads = quads; }, _copyQuadsToTextureAtlas: function (quads, index) { @@ -257,7 +256,6 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * textureAtlas.initWithTexture(texture, 3); */ initWithTexture: function (texture, capacity) { - cc.assert(texture, cc._LogInfos.TextureAtlas_initWithTexture); capacity = 0 | (capacity); @@ -294,9 +292,7 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * @param {Number} index */ updateQuad: function (quad, index) { - cc.assert(quad, cc._LogInfos.TextureAtlas_updateQuad); - cc.assert(index >= 0 && index < this._capacity, cc._LogInfos.TextureAtlas_updateQuad_2); this._totalQuads = Math.max(index + 1, this._totalQuads); @@ -311,7 +307,6 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * @param {Number} index */ insertQuad: function (quad, index) { - cc.assert(index < this._capacity, cc._LogInfos.TextureAtlas_insertQuad_2); this._totalQuads++; @@ -407,7 +402,6 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * @param {Number} index */ removeQuadAtIndex: function (index) { - cc.assert(index < this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadAtIndex); var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; @@ -422,8 +416,12 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ this.dirty = true; }, + /** + * Removes a given number of quads at a given index + * @param {Number} index + * @param {Number} amount + */ removeQuadsAtIndex: function (index, amount) { - cc.assert(index + amount <= this._totalQuads, cc._LogInfos.TextureAtlas_removeQuadsAtIndex); this._totalQuads -= amount; @@ -463,7 +461,7 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ * @return {Boolean} */ resizeCapacity: function (newCapacity) { - if (newCapacity == this._capacity) + if (newCapacity === this._capacity) return true; var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; @@ -473,7 +471,7 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ this._capacity = 0 | newCapacity; var i, capacity = this._capacity, locTotalQuads = this._totalQuads; - if (this._quads == null) { + if (this._quads === null) { this._quads = []; this._quadsArrayBuffer = new ArrayBuffer(quadSize * capacity); this._quadsReader = new Uint8Array(this._quadsArrayBuffer); @@ -508,7 +506,7 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ } } - if (this._indices == null) { + if (this._indices === null) { this._indices = new Uint16Array(capacity * 6); } else { if (capacity > oldCapacity) { @@ -551,12 +549,10 @@ cc.TextureAtlas = cc.Class.extend(/** @lends cc.TextureAtlas# */{ if (amount === 0) return; } else { - cc.assert((newIndex + amount) <= this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_2); - cc.assert(oldIndex < this._totalQuads, cc._LogInfos.TextureAtlas_moveQuadsFromIndex_3); - if (oldIndex == newIndex) + if (oldIndex === newIndex) return; } @@ -631,26 +627,27 @@ cc.defineGetterSetter(_p, "quads", _p.getQuads, _p.setQuads); /** *

Creates a TextureAtlas with an filename and with an initial capacity for Quads.
* The TextureAtlas capacity can be increased in runtime.

+ * @deprecated since v3.0, please use new cc.TextureAtlas(fileName, capacity) instead * @param {String|cc.Texture2D} fileName * @param {Number} capacity * @return {cc.TextureAtlas|Null} - * @example - * 1. - * //creates a TextureAtlas with filename - * var textureAtlas = cc.TextureAtlas.create("res/hello.png", 3); - * 2. - * //creates a TextureAtlas with texture - * var texture = cc.textureCache.addImage("hello.png"); - * var textureAtlas = cc.TextureAtlas.create(texture, 3); */ cc.TextureAtlas.create = function (fileName, capacity) { return new cc.TextureAtlas(fileName, capacity); }; +/** + * @deprecated since v3.0, please use new cc.TextureAtlas(texture) instead + * @function + */ +cc.TextureAtlas.createWithTexture = cc.TextureAtlas.create; + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _tmp.WebGLTextureAtlas(); - delete _tmp.WebGLTextureAtlas; + cc.assert(cc.isFunction(cc._tmp.WebGLTextureAtlas), cc._LogInfos.MissingFile, "TexturesWebGL.js"); + cc._tmp.WebGLTextureAtlas(); + delete cc._tmp.WebGLTextureAtlas; } -_tmp.PrototypeTextureAtlas(); -delete _tmp.PrototypeTextureAtlas; \ No newline at end of file +cc.assert(cc.isFunction(cc._tmp.PrototypeTextureAtlas), cc._LogInfos.MissingFile, "TexturesPropertyDefine.js"); +cc._tmp.PrototypeTextureAtlas(); +delete cc._tmp.PrototypeTextureAtlas; \ No newline at end of file diff --git a/cocos2d/core/textures/CCTextureCache.js b/cocos2d/core/textures/CCTextureCache.js index 67d0f964f7..8068eb485b 100644 --- a/cocos2d/core/textures/CCTextureCache.js +++ b/cocos2d/core/textures/CCTextureCache.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,7 +25,9 @@ ****************************************************************************/ /** - * @namespace The global cache for cc.Texture2D + * cc.textureCache is a singleton object, it's the global cache for cc.Texture2D + * @class + * @name cc.textureCache */ cc.textureCache = /** @lends cc.textureCache# */{ _textures: {}, @@ -88,11 +90,25 @@ cc.textureCache = /** @lends cc.textureCache# */{ * Returns an already created texture. Returns null if the texture doesn't exist. * @param {String} textureKeyName * @return {cc.Texture2D|Null} + * @deprecated * @example * //example * var key = cc.textureCache.textureForKey("hello.png"); */ textureForKey: function (textureKeyName) { + cc.log(cc._LogInfos.textureCache_textureForKey); + return this.getTextureForKey(textureKeyName); + }, + + /** + * Returns an already created texture. Returns null if the texture doesn't exist. + * @param {String} textureKeyName + * @return {cc.Texture2D|Null} + * @example + * //example + * var key = cc.textureCache.getTextureForKey("hello.png"); + */ + getTextureForKey: function(textureKeyName){ return this._textures[textureKeyName] || this._textures[cc.loader._aliases[textureKeyName]]; }, @@ -105,7 +121,7 @@ cc.textureCache = /** @lends cc.textureCache# */{ */ getKeyByTexture: function (texture) { for (var key in this._textures) { - if (this._textures[key] == texture) { + if (this._textures[key] === texture) { return key; } } @@ -134,7 +150,7 @@ cc.textureCache = /** @lends cc.textureCache# */{ } if (!this._textureColorsCache[key]) - this._textureColorsCache[key] = cc.generateTextureCacheForColor(texture); + this._textureColorsCache[key] = cc.Sprite.CanvasRenderCmd._generateTextureCacheForColor(texture); return this._textureColorsCache[key]; }, @@ -181,7 +197,7 @@ cc.textureCache = /** @lends cc.textureCache# */{ var locTextures = this._textures; for (var selKey in locTextures) { - if (locTextures[selKey] == texture) { + if (locTextures[selKey] === texture) { locTextures[selKey].releaseTexture(); delete(locTextures[selKey]); } @@ -231,7 +247,6 @@ cc.textureCache = /** @lends cc.textureCache# */{ * @return {cc.Texture2D} */ addUIImage: function (image, key) { - cc.assert(image, cc._LogInfos.textureCache_addUIImage_2); if (key) { @@ -242,7 +257,7 @@ cc.textureCache = /** @lends cc.textureCache# */{ // prevents overloading the autorelease pool var texture = new cc.Texture2D(); texture.initWithImage(image); - if ((key != null) && (texture != null)) + if (key != null) this._textures[key] = texture; else cc.log(cc._LogInfos.textureCache_addUIImage); @@ -274,7 +289,7 @@ cc.textureCache = /** @lends cc.textureCache# */{ for (var selCanvasKey in selCanvasColorsArr) { var selCanvas = selCanvasColorsArr[selCanvasKey]; count++; - cc.log("cocos2d: '%s' id= HTMLCanvasElement %s x %s", key, selCanvas.width, selCanvas.height); + cc.log(cc._LogInfos.textureCache_dumpCachedTextureInfo_2, key, selCanvas.width, selCanvas.height); totalBytes += selCanvas.width * selCanvas.height * 4; } @@ -327,35 +342,30 @@ if (cc._renderType === cc._RENDER_TYPE_CANVAS) { //remove judge var tex = locTexs[url] || locTexs[cc.loader._aliases[url]]; if (tex) { - if (cb) - cb.call(target); + cb && cb.call(target, tex); return tex; } - if (!cc.loader.getRes(url)) { - if (cc.loader._checkIsImageURL(url)) { - cc.loader.load(url, function (err) { - if (cb) - cb.call(target); - }); - } else { - cc.loader.cache[url] = cc.loader.loadImg(url, function (err, img) { - if (err) - return cb(err); - cc.textureCache.handleLoadedTexture(url); - cb(null, img); - }); - } - } - tex = locTexs[url] = new cc.Texture2D(); tex.url = url; + var loadFunc = cc.loader._checkIsImageURL(url) ? cc.loader.load : cc.loader.loadImg; + loadFunc.call(cc.loader, url, function (err, img) { + if (err) + return cb && cb.call(target, err); + cc.textureCache.handleLoadedTexture(url); + + var texResult = locTexs[url]; + cb && cb.call(target, texResult); + }); + return tex; }; + _p.addImageAsync = _p.addImage; _p = null; } else { - _tmp.WebGLTextureCache(); - delete _tmp.WebGLTextureCache; + cc.assert(cc.isFunction(cc._tmp.WebGLTextureCache), cc._LogInfos.MissingFile, "TexturesWebGL.js"); + cc._tmp.WebGLTextureCache(); + delete cc._tmp.WebGLTextureCache; } \ No newline at end of file diff --git a/cocos2d/core/textures/TexturesPropertyDefine.js b/cocos2d/core/textures/TexturesPropertyDefine.js index f6936370d1..fe1eef3801 100644 --- a/cocos2d/core/textures/TexturesPropertyDefine.js +++ b/cocos2d/core/textures/TexturesPropertyDefine.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,7 +24,7 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.PrototypeTexture2D = function () { +cc._tmp.PrototypeTexture2D = function () { var _c = cc.Texture2D; @@ -37,7 +37,6 @@ _tmp.PrototypeTexture2D = function () { * By default it is disabled.
*

* @param haveAlphaPremultiplied - * @constructor */ _c.PVRImagesHavePremultipliedAlpha = function (haveAlphaPremultiplied) { cc.PVRHaveAlphaPremultiplied_ = haveAlphaPremultiplied; @@ -203,7 +202,7 @@ _tmp.PrototypeTexture2D = function () { _c.defaultPixelFormat = _c.PIXEL_FORMAT_DEFAULT; }; -_tmp.PrototypeTextureAtlas = function () { +cc._tmp.PrototypeTextureAtlas = function () { var _p = cc.TextureAtlas.prototype; diff --git a/cocos2d/core/textures/TexturesWebGL.js b/cocos2d/core/textures/TexturesWebGL.js index 190b39eee9..c08cd2c49d 100644 --- a/cocos2d/core/textures/TexturesWebGL.js +++ b/cocos2d/core/textures/TexturesWebGL.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,7 +24,7 @@ THE SOFTWARE. ****************************************************************************/ -_tmp.WebGLTexture2D = function () { +cc._tmp.WebGLTexture2D = function () { /** *

@@ -38,6 +38,7 @@ _tmp.WebGLTexture2D = function () { * @extends cc.Class * * @property {WebGLTexture} name - <@readonly> WebGLTexture Object + * @property {Number} defaultPixelFormat - The default pixel format * @property {Number} pixelFormat - <@readonly> Pixel format of the texture * @property {Number} pixelsWidth - <@readonly> Width in pixels * @property {Number} pixelsHeight - <@readonly> Height in pixels @@ -63,19 +64,23 @@ _tmp.WebGLTexture2D = function () { shaderProgram: null, - _isLoaded: false, + _textureLoaded: false, _htmlElementObj: null, _webTextureObj: null, url: null, - _loadedEventListeners: null, - /*public:*/ + /** + * constructor of cc.Texture2D + */ ctor: function () { this._contentSize = cc.size(0, 0); this._pixelFormat = cc.Texture2D.defaultPixelFormat; }, + /** + * release texture + */ releaseTexture: function () { if (this._webTextureObj) cc._renderContext.deleteTexture(this._webTextureObj); @@ -129,24 +134,42 @@ _tmp.WebGLTexture2D = function () { return this._contentSize.height / cc.contentScaleFactor(); }, + /** + * get content size in pixels + * @return {cc.Size} + */ getContentSizeInPixels: function () { return this._contentSize; }, - /** texture max S */ + /** + * texture max S + * @return {Number} + */ getMaxS: function () { return this.maxS; }, + /** + * set texture max S + * @param {Number} maxS + */ setMaxS: function (maxS) { this.maxS = maxS; }, - /** texture max T */ + /** + * get texture max T + * @return {Number} + */ getMaxT: function () { return this.maxT; }, + /** + * set texture max T + * @param {Number} maxT + */ setMaxT: function (maxT) { this.maxT = maxT; }, @@ -175,10 +198,18 @@ _tmp.WebGLTexture2D = function () { return this._hasPremultipliedAlpha; }, + /** + * whether or not use mipmap + * @return {Boolean} + */ hasMipmaps: function () { return this._hasMipmaps; }, + /** + * description + * @return {string} + */ description: function () { var _t = this; return " * If the texture size is NPOT (non power of 2), then in can only use gl.CLAMP_TO_EDGE in gl.TEXTURE_WRAP_{S,T}. - * @param texParams + * @param {Object|Number} texParams texParams object or minFilter + * @param {Number} [magFilter] + * @param {Number} [wrapS] + * @param {Number} [wrapT] */ - setTexParameters: function (texParams) { + setTexParameters: function (texParams, magFilter, wrapS, wrapT) { var _t = this; var gl = cc._renderContext; - cc.assert((_t._pixelsWide == cc.NextPOT(_t._pixelsWide) && _t._pixelsHigh == cc.NextPOT(_t._pixelsHigh)) || - (texParams.wrapS == gl.CLAMP_TO_EDGE && texParams.wrapT == gl.CLAMP_TO_EDGE), + if(magFilter !== undefined) + texParams = {minFilter: texParams, magFilter: magFilter, wrapS: wrapS, wrapT: wrapT}; + + cc.assert((_t._pixelsWide === cc.NextPOT(_t._pixelsWide) && _t._pixelsHigh === cc.NextPOT(_t._pixelsHigh)) || + (texParams.wrapS === gl.CLAMP_TO_EDGE && texParams.wrapT === gl.CLAMP_TO_EDGE), "WebGLRenderingContext.CLAMP_TO_EDGE should be used in NPOT textures"); cc.glBindTexture2D(_t); @@ -521,9 +580,6 @@ _tmp.WebGLTexture2D = function () { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texParams.magFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, texParams.wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, texParams.wrapT); - - //TODO - //VolatileTexture::setTexParameters(_t, texParams); }, /** @@ -539,12 +595,7 @@ _tmp.WebGLTexture2D = function () { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); else gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - //TODO - /*#if CC_ENABLE_CACHE_TEXTURE_DATA - ccTexParams texParams = {m_bHasMipmaps?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR,GL_LINEAR,GL_NONE,GL_NONE}; - VolatileTexture::setTexParameters(this, &texParams); - #endif*/ + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); }, /** @@ -561,12 +612,6 @@ _tmp.WebGLTexture2D = function () { else gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - //TODO - /*#if CC_ENABLE_CACHE_TEXTURE_DATA - ccTexParams texParams = {m_bHasMipmaps?GL_NEAREST_MIPMAP_NEAREST:GL_NEAREST,GL_NEAREST,GL_NONE,GL_NONE}; - VolatileTexture::setTexParameters(this, &texParams); - #endif*/ }, /** @@ -575,7 +620,7 @@ _tmp.WebGLTexture2D = function () { */ generateMipmap: function () { var _t = this; - cc.assert(_t._pixelsWide == cc.NextPOT(_t._pixelsWide) && _t._pixelsHigh == cc.NextPOT(_t._pixelsHigh), "Mimpap texture only works in POT textures"); + cc.assert(_t._pixelsWide === cc.NextPOT(_t._pixelsWide) && _t._pixelsHigh === cc.NextPOT(_t._pixelsHigh), "Mimpap texture only works in POT textures"); cc.glBindTexture2D(_t); cc._renderContext.generateMipmap(cc._renderContext.TEXTURE_2D); @@ -627,7 +672,7 @@ _tmp.WebGLTexture2D = function () { // Repack the pixel data into the right format var length = width * height; - if (pixelFormat == tex2d.PIXEL_FORMAT_RGB565) { + if (pixelFormat === tex2d.PIXEL_FORMAT_RGB565) { if (hasAlpha) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB" tempData = new Uint16Array(width * height); @@ -651,7 +696,7 @@ _tmp.WebGLTexture2D = function () { (((inPixel8[i] & 0xFF) >> 3) << 0); // B } } - } else if (pixelFormat == tex2d.PIXEL_FORMAT_RGBA4444) { + } else if (pixelFormat === tex2d.PIXEL_FORMAT_RGBA4444) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" tempData = new Uint16Array(width * height); inPixel32 = uiImage.getData(); @@ -663,7 +708,7 @@ _tmp.WebGLTexture2D = function () { ((((inPixel32[i] >> 16) & 0xFF) >> 4) << 4) | // B ((((inPixel32[i] >> 24) & 0xFF) >> 4) << 0); // A } - } else if (pixelFormat == tex2d.PIXEL_FORMAT_RGB5A1) { + } else if (pixelFormat === tex2d.PIXEL_FORMAT_RGB5A1) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" tempData = new Uint16Array(width * height); inPixel32 = uiImage.getData(); @@ -675,7 +720,7 @@ _tmp.WebGLTexture2D = function () { ((((inPixel32[i] >> 16) & 0xFF) >> 3) << 1) | // B ((((inPixel32[i] >> 24) & 0xFF) >> 7) << 0); // A } - } else if (pixelFormat == tex2d.PIXEL_FORMAT_A8) { + } else if (pixelFormat === tex2d.PIXEL_FORMAT_A8) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "AAAAAAAA" tempData = new Uint8Array(width * height); inPixel32 = uiImage.getData(); @@ -685,7 +730,7 @@ _tmp.WebGLTexture2D = function () { } } - if (hasAlpha && pixelFormat == tex2d.PIXEL_FORMAT_RGB888) { + if (hasAlpha && pixelFormat === tex2d.PIXEL_FORMAT_RGB888) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB" inPixel32 = uiImage.getData(); tempData = new Uint8Array(width * height * 3); @@ -706,43 +751,28 @@ _tmp.WebGLTexture2D = function () { return true; }, + /** + * add listener for loaded event + * @param {Function} callback + * @param {cc.Node} target + * @deprecated since 3.1, please use addEventListener instead + */ addLoadedEventListener: function (callback, target) { - if (!this._loadedEventListeners) - this._loadedEventListeners = []; - this._loadedEventListeners.push({eventCallback: callback, eventTarget: target}); + this.addEventListener("load", callback, target); }, + /** + * remove listener from listeners by target + * @param {cc.Node} target + */ removeLoadedEventListener: function (target) { - if (!this._loadedEventListeners) - return; - var locListeners = this._loadedEventListeners; - for (var i = 0; i < locListeners.length; i++) { - var selCallback = locListeners[i]; - if (selCallback.eventTarget == target) { - locListeners.splice(i, 1); - } - } - }, - - _callLoadedEventCallbacks: function () { - if (!this._loadedEventListeners) - return; - var locListeners = this._loadedEventListeners; - for (var i = 0, len = locListeners.length; i < len; i++) { - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; + this.removeEventListener("load", target); } }); - }; - -_tmp.WebGLTextureAtlas = function () { - +cc._tmp.WebGLTextureAtlas = function () { var _p = cc.TextureAtlas.prototype; - _p._setupVBO = function () { var _t = this; var gl = cc._renderContext; @@ -767,7 +797,6 @@ _tmp.WebGLTextureAtlas = function () { //cc.checkGLErrorDebug(); }; - /** *

Draws n quads from an index (offset).
* n + start can't be greater than the capacity of the atlas

@@ -792,16 +821,15 @@ _tmp.WebGLTextureAtlas = function () { cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); gl.bindBuffer(gl.ARRAY_BUFFER, _t._quadsWebBuffer); - if (_t.dirty) + if (_t.dirty){ gl.bufferData(gl.ARRAY_BUFFER, _t._quadsArrayBuffer, gl.DYNAMIC_DRAW); + _t.dirty = false; + } gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords - if (_t.dirty) - _t.dirty = false; - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, _t._buffersVBO[1]); if (cc.TEXTURE_ATLAS_USE_TRIANGLE_STRIP) @@ -812,10 +840,9 @@ _tmp.WebGLTextureAtlas = function () { cc.g_NumberOfDraws++; //cc.checkGLErrorDebug(); }; +}; -} -_tmp.WebGLTextureCache = function () { - +cc._tmp.WebGLTextureCache = function () { var _p = cc.textureCache; _p.handleLoadedTexture = function (url) { @@ -847,8 +874,6 @@ _tmp.WebGLTextureCache = function () { * cc.textureCache.addImage("hello.png"); */ _p.addImage = function (url, cb, target) { - - cc.assert(url, cc._LogInfos.Texture2D_addImage_2); var locTexs = this._textures; @@ -858,30 +883,25 @@ _tmp.WebGLTextureCache = function () { } var tex = locTexs[url] || locTexs[cc.loader._aliases[url]]; if (tex) { - if (cb) - cb.call(target); + cb && cb.call(target, tex); return tex; } - if (!cc.loader.getRes(url)) { - if (cc.loader._checkIsImageURL(url)) { - cc.loader.load(url, function (err) { - cb && cb.call(target); - }); - } else { - cc.loader.cache[url] = cc.loader.loadImg(url, function (err, img) { - if (err) - return cb ? cb(err) : err; - cc.textureCache.handleLoadedTexture(url); - cb && cb(null, img); - }); - } - } - tex = locTexs[url] = new cc.Texture2D(); tex.url = url; + var loadFunc = cc.loader._checkIsImageURL(url) ? cc.loader.load : cc.loader.loadImg; + loadFunc.call(cc.loader, url, function (err, img) { + if (err) + return cb && cb.call(target, err); + cc.textureCache.handleLoadedTexture(url); + + var texResult = locTexs[url]; + cb && cb.call(target, texResult); + }); + return tex; }; - delete _p; -} \ No newline at end of file + _p.addImageAsync = _p.addImage; + _p = null; +}; diff --git a/cocos2d/core/utils/BinaryLoader.js b/cocos2d/core/utils/BinaryLoader.js index 8bb4959213..013c3dee6e 100644 --- a/cocos2d/core/utils/BinaryLoader.js +++ b/cocos2d/core/utils/BinaryLoader.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,6 +27,7 @@ /** * Load binary data by url. + * @function * @param {String} url * @param {Function} [cb] */ @@ -40,7 +41,7 @@ cc.loader.loadBinary = function (url, cb) { // IE-specific logic here xhr.setRequestHeader("Accept-Charset", "x-user-defined"); xhr.onreadystatechange = function () { - if (xhr.readyState == 4 && xhr.status == 200) { + if (xhr.readyState === 4 && xhr.status === 200) { var fileContents = cc._convertResponseBodyToText(xhr["responseBody"]); cb(null, self._str2Uint8Array(fileContents)); } else cb(errInfo); @@ -48,7 +49,7 @@ cc.loader.loadBinary = function (url, cb) { } else { if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=x-user-defined"); xhr.onload = function () { - xhr.readyState == 4 && xhr.status == 200 ? cb(null, self._str2Uint8Array(xhr.responseText)) : cb(errInfo); + xhr.readyState === 4 && xhr.status === 200 ? cb(null, self._str2Uint8Array(xhr.responseText)) : cb(errInfo); }; } xhr.send(null); @@ -65,6 +66,12 @@ cc.loader._str2Uint8Array = function (strData) { return arrData; }; +/** + * Load binary data by url synchronously + * @function + * @param {String} url + * @return {Uint8Array} + */ cc.loader.loadBinarySync = function (url) { var self = this; var req = this.getXMLHttpRequest(); @@ -74,7 +81,7 @@ cc.loader.loadBinarySync = function (url) { if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { req.setRequestHeader("Accept-Charset", "x-user-defined"); req.send(null); - if (req.status != 200) { + if (req.status !== 200) { cc.log(errInfo); return null; } @@ -87,7 +94,7 @@ cc.loader.loadBinarySync = function (url) { if (req.overrideMimeType) req.overrideMimeType('text\/plain; charset=x-user-defined'); req.send(null); - if (req.status != 200) { + if (req.status !== 200) { cc.log(errInfo); return null; } diff --git a/cocos2d/effects/CCGrabber.js b/cocos2d/effects/CCGrabber.js index 64831a9d6f..427ffb57e5 100644 --- a/cocos2d/effects/CCGrabber.js +++ b/cocos2d/effects/CCGrabber.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,7 +24,11 @@ THE SOFTWARE. ****************************************************************************/ -/** FBO class that grabs the the contents of the screen */ +/** + * FBO class that grabs the the contents of the screen + * @class + * @extends cc.Class + */ cc.Grabber = cc.Class.extend({ _FBO:null, _oldFBO:null, @@ -32,6 +36,9 @@ cc.Grabber = cc.Class.extend({ _gl:null, + /** + * constructor of cc.Grabber + */ ctor:function () { cc._checkWebGLRenderMode(); this._gl = cc._renderContext; @@ -41,6 +48,10 @@ cc.Grabber = cc.Class.extend({ this._FBO = this._gl.createFramebuffer(); }, + /** + * grab + * @param {cc.Texture2D} texture + */ grab:function (texture) { var locGL = this._gl; this._oldFBO = locGL.getParameter(locGL.FRAMEBUFFER_BINDING); @@ -51,11 +62,15 @@ cc.Grabber = cc.Class.extend({ // check if it worked (probably worth doing :) ) var status = locGL.checkFramebufferStatus(locGL.FRAMEBUFFER); - if (status != locGL.FRAMEBUFFER_COMPLETE) + if (status !== locGL.FRAMEBUFFER_COMPLETE) cc.log("Frame Grabber: could not attach texture to frmaebuffer"); locGL.bindFramebuffer(locGL.FRAMEBUFFER, this._oldFBO); }, + /** + * should be invoked before drawing + * @param {cc.Texture2D} texture + */ beforeRender:function (texture) { var locGL = this._gl; this._oldFBO = locGL.getParameter(locGL.FRAMEBUFFER_BINDING); @@ -76,12 +91,19 @@ cc.Grabber = cc.Class.extend({ // glColorMask(true, true, true, false); // #631 }, + /** + * should be invoked after drawing + * @param {cc.Texture2D} texture + */ afterRender:function (texture) { var locGL = this._gl; locGL.bindFramebuffer(locGL.FRAMEBUFFER, this._oldFBO); locGL.colorMask(true, true, true, true); // #631 }, + /** + * delete FBO + */ destroy:function(){ this._gl.deleteFramebuffer(this._FBO); } diff --git a/cocos2d/effects/CCGrid.js b/cocos2d/effects/CCGrid.js index 963b048f7c..3a0ec265c9 100644 --- a/cocos2d/effects/CCGrid.js +++ b/cocos2d/effects/CCGrid.js @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (c) 2010-2013 cocos2d-x.org - Copyright (c) 2009 On-Core Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2009 On-Core http://www.cocos2d-x.org @@ -45,7 +45,7 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ /** * create one cc.GridBase Object - * @constructor + * Constructor of cc.GridBase * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] @@ -138,7 +138,7 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ }, /** - * get wheter or not the texture is flipped + * get whether or not the texture is flipped * @return {Boolean} */ isTextureFlipped:function () { @@ -146,11 +146,11 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ }, /** - * set wheter or not the texture is flipped + * set whether or not the texture is flipped * @param {Boolean} flipped */ setTextureFlipped:function (flipped) { - if (this._isTextureFlipped != flipped) { + if (this._isTextureFlipped !== flipped) { this._isTextureFlipped = flipped; this.calculateVertexPoints(); } @@ -210,9 +210,7 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ // save projection this._directorProjection = cc.director.getProjection(); - // 2d projection - // [director setProjection:kCCDirectorProjection2D]; - this.set2DProjection(); + //this.set2DProjection(); //TODO why? this._grabber.beforeRender(this._texture); }, @@ -220,25 +218,38 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ this._grabber.afterRender(this._texture); // restore projection - cc.director.setProjection(this._directorProjection); + //cc.director.setProjection(this._directorProjection); - if (target.getCamera().isDirty()) { + if (target && target.getCamera().isDirty()) { var offset = target.getAnchorPointInPoints(); + //TODO hack + var stackMatrix = target._renderCmd._stackMatrix; // // XXX: Camera should be applied in the AnchorPoint // - cc.kmGLTranslatef(offset.x, offset.y, 0); - target.getCamera().locate(); - cc.kmGLTranslatef(-offset.x, -offset.y, 0); + //cc.kmGLTranslatef(offset.x, offset.y, 0); + var translation = cc.math.Matrix4.createByTranslation(offset.x, offset.y, 0); + stackMatrix.multiply(translation); + + //target.getCamera().locate(); + target._camera._locateForRenderer(stackMatrix); + + //cc.kmGLTranslatef(-offset.x, -offset.y, 0); + translation = cc.math.Matrix4.createByTranslation(-offset.x, -offset.y, 0, translation); + stackMatrix.multiply(translation); } cc.glBindTexture2D(this._texture); + this.beforeBlit(); + this.blit(target); + this.afterBlit(); + }, + + beforeBlit: function () { + }, - // restore projection for default FBO .fixed bug #543 #544 - //TODO: CCDirector::sharedDirector().setProjection(CCDirector::sharedDirector().getProjection()); - //TODO: CCDirector::sharedDirector().applyOrientation(); - this.blit(); + afterBlit: function () { }, blit:function () { @@ -261,8 +272,7 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); cc.kmGLLoadIdentity(); - var orthoMatrix = new cc.kmMat4(); - cc.kmMat4OrthographicProjection(orthoMatrix, 0, winSize.width, 0, winSize.height, -1, 1); + var orthoMatrix = cc.math.Matrix4.createOrthographicProjection(0, winSize.width, 0, winSize.height, -1, 1); cc.kmGLMultMatrix(orthoMatrix); cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); @@ -273,6 +283,7 @@ cc.GridBase = cc.Class.extend(/** @lends cc.GridBase# */{ /** * create one cc.GridBase Object + * @deprecated * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] @@ -297,9 +308,13 @@ cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{ _verticesBuffer:null, _indicesBuffer:null, + _needDepthTestForBlit: false, + _oldDepthTestValue: false, + _oldDepthWriteValue: false, + /** * create one Grid3D object - * @constructor + * Constructor of cc.Grid3D * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] @@ -320,11 +335,21 @@ cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{ }, /** - * returns the vertex at a given position + * returns the vertex at a given position
+ * It will be deprecated in future, please use getVertex instead. * @param {cc.Point} pos * @return {cc.Vertex3F} */ vertex:function (pos) { + return this.getVertex(pos); + }, + + /** + * returns the vertex at a given position + * @param {cc.Point} pos + * @return {cc.Vertex3F} + */ + getVertex: function(pos){ if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y)) cc.log("cc.Grid3D.vertex() : Numbers must be integers"); var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3); @@ -333,11 +358,21 @@ cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{ }, /** - * returns the original (non-transformed) vertex at a given position + * returns the original (non-transformed) vertex at a given position
+ * It will be deprecated in future, please use getOriginalVertex instead. * @param {cc.Point} pos * @return {cc.Vertex3F} */ originalVertex:function (pos) { + return this.getOriginalVertex(pos); + }, + + /** + * returns the original (non-transformed) vertex at a given position + * @param {cc.Point} pos + * @return {cc.Vertex3F} + */ + getOriginalVertex: function(pos) { if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y)) cc.log("cc.Grid3D.originalVertex() : Numbers must be integers"); var index = 0 | ((pos.x * (this._gridSize.height + 1) + pos.y) * 3); @@ -361,11 +396,34 @@ cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{ this._dirty = true; }, - blit:function () { + beforeBlit: function () { + if (this._needDepthTestForBlit) { + var gl = cc._renderContext; + this._oldDepthTestValue = gl.isEnabled(gl.DEPTH_TEST); + this._oldDepthWriteValue = gl.getParameter(gl.DEPTH_WRITEMASK); + //CHECK_GL_ERROR_DEBUG(); + gl.enable(gl.DEPTH_TEST); + gl.depthMask(true); + } + }, + + afterBlit: function () { + if (this._needDepthTestForBlit) { + var gl = cc._renderContext; + if (this._oldDepthTestValue) + gl.enable(gl.DEPTH_TEST); + else + gl.disable(gl.DEPTH_TEST); + gl.depthMask(this._oldDepthWriteValue); + } + }, + + blit:function (target) { var n = this._gridSize.width * this._gridSize.height; cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_TEX_COORDS); this._shaderProgram.use(); - this._shaderProgram.setUniformsForBuiltins(); + //this._shaderProgram.setUniformsForBuiltins(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix); var gl = cc._renderContext, locDirty = this._dirty; // @@ -476,11 +534,20 @@ cc.Grid3D = cc.GridBase.extend(/** @lends cc.Grid3D# */{ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indicesBuffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); this._dirty = true; + }, + + setNeedDepthTestForBlit: function(needDepthTest){ + this._needDepthTestForBlit = needDepthTest; + }, + + getNeedDepthTestForBlit: function(){ + return this._needDepthTestForBlit; } }); /** * create one Grid3D object + * @deprecated * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] @@ -508,7 +575,7 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ /** * create one TiledGrid3D object - * @constructor + * Constructor of cc.TiledGrid3D * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] @@ -529,11 +596,21 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ }, /** - * returns the tile at the given position + * returns the tile at the given position
+ * It will be deprecated in future, please use getTile instead. * @param {cc.Point} pos * @return {cc.Quad3} */ tile:function (pos) { + return this.getTile(pos); + }, + + /** + * returns the tile at the given position + * @param {cc.Point} pos + * @return {cc.Quad3} + */ + getTile: function(pos){ if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y)) cc.log("cc.TiledGrid3D.tile() : Numbers must be integers"); @@ -550,7 +627,7 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ * @param {cc.Point} pos * @return {cc.Quad3} */ - originalTile:function (pos) { + getOriginalTile:function (pos) { if(pos.x !== (0| pos.x) || pos.y !== (0| pos.y)) cc.log("cc.TiledGrid3D.originalTile() : Numbers must be integers"); @@ -562,6 +639,16 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ new cc.Vertex3F(locOriginalVertices[idx + 9], locOriginalVertices[idx + 10], locOriginalVertices[idx + 11])); }, + /** + * returns the original tile (untransformed) at the given position.
+ * It will be deprecated in future, please use getOriginalTile instead. + * @param {cc.Point} pos + * @return {cc.Quad3} + */ + originalTile: function(pos) { + return this.getOriginalTile(pos); + }, + /** * sets a new tile * @param {cc.Point} pos @@ -588,11 +675,12 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ this._dirty = true; }, - blit:function () { + blit: function (target) { var n = this._gridSize.width * this._gridSize.height; this._shaderProgram.use(); - this._shaderProgram.setUniformsForBuiltins(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(target._renderCmd._stackMatrix); + //this._shaderProgram.setUniformsForBuiltins(); // // Attributes @@ -718,6 +806,7 @@ cc.TiledGrid3D = cc.GridBase.extend(/** @lends cc.TiledGrid3D# */{ /** * create one TiledGrid3D object + * @deprecated since v3.0, please use new cc.TiledGrid3D(gridSize, texture, flipped) instead * @param {cc.Size} gridSize * @param {cc.Texture2D} [texture=] * @param {Boolean} [flipped=] diff --git a/cocos2d/kazmath/aabb.js b/cocos2d/kazmath/aabb.js index a5c8a116d2..8c5dc5b664 100644 --- a/cocos2d/kazmath/aabb.js +++ b/cocos2d/kazmath/aabb.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -25,42 +27,52 @@ */ /** - * A struture that represents an axis-aligned - * bounding box. + * A structure that represents an axis-aligned bounding box. + * cc.kmAABB => cc.math.AABB */ -cc.kmAABB = function (min, max) { +cc.math.AABB = function (min, max) { /** The max corner of the box */ - this.min = min || new cc.kmVec3(); + this.min = min || new cc.math.Vec3(); /** The min corner of the box */ - this.max = max || new cc.kmVec3(); + this.max = max || new cc.math.Vec3(); }; /** - * Returns KM_TRUE if point is in the specified AABB, returns - * KM_FALSE otherwise. + * Returns true if point is in the specified AABB, returns false otherwise. + * @param {cc.math.Vec3} point + * @returns {boolean} */ -cc.kmAABBContainsPoint = function (pPoint, pBox) { - if (pPoint.x >= pBox.min.x && pPoint.x <= pBox.max.x && +cc.math.AABB.prototype.containsPoint = function (point) { + return (point.x >= this.min.x && point.x <= this.max.x && + point.y >= this.min.y && point.y <= this.max.y && + point.z >= this.min.z && point.z <= this.max.z); +}; + +/** + * Returns true if point is in the specified AABB, returns + * false otherwise. + */ +cc.math.AABB.containsPoint = function (pPoint, pBox) { + return (pPoint.x >= pBox.min.x && pPoint.x <= pBox.max.x && pPoint.y >= pBox.min.y && pPoint.y <= pBox.max.y && - pPoint.z >= pBox.min.z && pPoint.z <= pBox.max.z) { - return cc.KM_TRUE; - } - return cc.KM_FALSE; + pPoint.z >= pBox.min.z && pPoint.z <= pBox.max.z); }; /** - * Assigns pIn to pOut, returns pOut. + * Assigns aabb to current AABB object + * @param {cc.math.AABB} aabb */ -cc.kmAABBAssign = function (pOut, pIn) { - cc.kmVec3Assign(pOut.min, pIn.min); - cc.kmVec3Assign(pOut.max, pIn.max); - return pOut; +cc.math.AABB.prototype.assignFrom = function(aabb){ + this.min.assignFrom(aabb.min); + this.max.assignFrom(aabb.max); }; /** - * Scales pIn by s, stores the resulting AABB in pOut. Returns pOut + * Assigns pIn to pOut, returns pOut. */ -cc.kmAABBScale = function (pOut, pIn, s) { - cc.log("cc.kmAABBScale hasn't been supported."); +cc.math.AABB.assign = function (pOut, pIn) { //cc.kmAABBAssign + pOut.min.assignFrom(pIn.min); + pOut.max.assignFrom(pIn.max); + return pOut; }; diff --git a/cocos2d/kazmath/gl/mat4stack.js b/cocos2d/kazmath/gl/mat4stack.js index 0532d759dc..ecd3aceba3 100644 --- a/cocos2d/kazmath/gl/mat4stack.js +++ b/cocos2d/kazmath/gl/mat4stack.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,33 +26,72 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.km_mat4_stack = function(capacity, item_count, top, stack){ - this.top = top ; - this.stack = stack ; -}; - -cc.km_mat4_stack.INITIAL_SIZE = 30; - -cc.km_mat4_stack_initialize = function(stack){ - stack.stack = []; //allocate the memory - stack.top = null; //Set the top to NULL -}; - -cc.km_mat4_stack_push = function(stack, item){ - stack.stack.push(stack.top); - stack.top = new cc.kmMat4(); - cc.kmMat4Assign(stack.top, item); -}; - -cc.km_mat4_stack_pop = function(stack, pOut){ - stack.top = stack.stack.pop(); -}; - -cc.km_mat4_stack_release = function(stack){ - stack.stack = null; - stack.top = null; - stack = null; -}; +(function(cc){ + /** + * The stack of cc.math.Matrix4 + * @param {cc.math.Matrix4} [top] + * @param {Array} [stack] + * @constructor + */ + cc.math.Matrix4Stack = function(top, stack) { + this.top = top; + this.stack = stack || []; + //this._matrixPool = []; // use pool in next version + }; + cc.km_mat4_stack = cc.math.Matrix4Stack; + var proto = cc.math.Matrix4Stack.prototype; + + proto.initialize = function() { //cc.km_mat4_stack_initialize + this.stack.length = 0; + this.top = null; + }; + + //for compatibility + cc.km_mat4_stack_push = function(stack, item){ + stack.stack.push(stack.top); + stack.top = new cc.math.Matrix4(item); + }; + + cc.km_mat4_stack_pop = function(stack, pOut){ + stack.top = stack.stack.pop(); + }; + + cc.km_mat4_stack_release = function(stack){ + stack.stack = null; + stack.top = null; + }; + + proto.push = function(item) { + item = item || this.top; + this.stack.push(this.top); + this.top = new cc.math.Matrix4(item); + //this.top = this._getFromPool(item); + }; + + proto.pop = function() { + //this._putInPool(this.top); + this.top = this.stack.pop(); + }; + + proto.release = function(){ + this.stack = null; + this.top = null; + this._matrixPool = null; + }; + + proto._getFromPool = function (item) { + var pool = this._matrixPool; + if (pool.length === 0) + return new cc.math.Matrix4(item); + var ret = pool.pop(); + ret.assignFrom(item); + return ret; + }; + + proto._putInPool = function(matrix){ + this._matrixPool.push(matrix); + }; +})(cc); diff --git a/cocos2d/kazmath/gl/matrix.js b/cocos2d/kazmath/gl/matrix.js index 6459b51bda..3975fa620c 100644 --- a/cocos2d/kazmath/gl/matrix.js +++ b/cocos2d/kazmath/gl/matrix.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,144 +26,142 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.KM_GL_MODELVIEW = 0x1700; +(function(cc) { + cc.KM_GL_MODELVIEW = 0x1700; + cc.KM_GL_PROJECTION = 0x1701; + cc.KM_GL_TEXTURE = 0x1702; -cc.KM_GL_PROJECTION = 0x1701; + cc.modelview_matrix_stack = new cc.math.Matrix4Stack(); + cc.projection_matrix_stack = new cc.math.Matrix4Stack(); + cc.texture_matrix_stack = new cc.math.Matrix4Stack(); -cc.KM_GL_TEXTURE = 0x1702; + cc.current_stack = null; + var initialized = false; -cc.modelview_matrix_stack = new cc.km_mat4_stack(); -cc.projection_matrix_stack = new cc.km_mat4_stack(); -cc.texture_matrix_stack = new cc.km_mat4_stack(); + cc.lazyInitialize = function () { + if (!initialized) { + var identity = new cc.math.Matrix4(); //Temporary identity matrix -cc.current_stack = null; + //Initialize all 3 stacks + cc.modelview_matrix_stack.initialize(); + cc.projection_matrix_stack.initialize(); + cc.texture_matrix_stack.initialize(); -cc.initialized = false; - -cc.lazyInitialize = function () { - if (!cc.initialized) { - var identity = new cc.kmMat4(); //Temporary identity matrix - - //Initialize all 3 stacks - cc.km_mat4_stack_initialize(cc.modelview_matrix_stack); - cc.km_mat4_stack_initialize(cc.projection_matrix_stack); - cc.km_mat4_stack_initialize(cc.texture_matrix_stack); - - cc.current_stack = cc.modelview_matrix_stack; - cc.initialized = true; - cc.kmMat4Identity(identity); - - //Make sure that each stack has the identity matrix - cc.km_mat4_stack_push(cc.modelview_matrix_stack, identity); - cc.km_mat4_stack_push(cc.projection_matrix_stack, identity); - cc.km_mat4_stack_push(cc.texture_matrix_stack, identity); - } -}; - -cc.lazyInitialize(); - -cc.kmGLFreeAll = function () { - //Clear the matrix stacks - cc.km_mat4_stack_release(cc.modelview_matrix_stack); - cc.km_mat4_stack_release(cc.projection_matrix_stack); - cc.km_mat4_stack_release(cc.texture_matrix_stack); - - //Delete the matrices - cc.initialized = false; //Set to uninitialized - cc.current_stack = null; //Set the current stack to point nowhere -}; - -cc.kmGLPushMatrix = function () { - cc.km_mat4_stack_push(cc.current_stack, cc.current_stack.top); -}; - -cc.kmGLPushMatrixWitMat4 = function (saveMat) { - cc.current_stack.stack.push(cc.current_stack.top); - cc.kmMat4Assign(saveMat, cc.current_stack.top); - cc.current_stack.top = saveMat; -}; - -cc.kmGLPopMatrix = function () { - //No need to lazy initialize, you shouldnt be popping first anyway! - //cc.km_mat4_stack_pop(cc.current_stack, null); - cc.current_stack.top = cc.current_stack.stack.pop(); -}; - -cc.kmGLMatrixMode = function (mode) { - //cc.lazyInitialize(); - switch (mode) { - case cc.KM_GL_MODELVIEW: cc.current_stack = cc.modelview_matrix_stack; - break; - case cc.KM_GL_PROJECTION: - cc.current_stack = cc.projection_matrix_stack; - break; - case cc.KM_GL_TEXTURE: - cc.current_stack = cc.texture_matrix_stack; - break; - default: - throw "Invalid matrix mode specified"; //TODO: Proper error handling - break; - } -}; - -cc.kmGLLoadIdentity = function () { - //cc.lazyInitialize(); - cc.kmMat4Identity(cc.current_stack.top); //Replace the top matrix with the identity matrix -}; - -cc.kmGLLoadMatrix = function (pIn) { - //cc.lazyInitialize(); - cc.kmMat4Assign(cc.current_stack.top, pIn); -}; - -cc.kmGLMultMatrix = function (pIn) { - //cc.lazyInitialize(); - cc.kmMat4Multiply(cc.current_stack.top, cc.current_stack.top, pIn); -}; - -cc.kmGLTranslatef = function (x, y, z) { - var translation = new cc.kmMat4(); - - //Create a rotation matrix using the axis and the angle - cc.kmMat4Translation(translation, x, y, z); - - //Multiply the rotation matrix by the current matrix - cc.kmMat4Multiply(cc.current_stack.top, cc.current_stack.top, translation); -}; - -cc.kmGLRotatef = function (angle, x, y, z) { - var axis = new cc.kmVec3(x, y, z); - var rotation = new cc.kmMat4(); - - //Create a rotation matrix using the axis and the angle - cc.kmMat4RotationAxisAngle(rotation, axis, cc.kmDegreesToRadians(angle)); - - //Multiply the rotation matrix by the current matrix - cc.kmMat4Multiply(cc.current_stack.top, cc.current_stack.top, rotation); -}; - -cc.kmGLScalef = function (x, y, z) { - var scaling = new cc.kmMat4(); - cc.kmMat4Scaling(scaling, x, y, z); - cc.kmMat4Multiply(cc.current_stack.top, cc.current_stack.top, scaling); -}; - -cc.kmGLGetMatrix = function (mode, pOut) { - //cc.lazyInitialize(); - - switch (mode) { - case cc.KM_GL_MODELVIEW: - cc.kmMat4Assign(pOut, cc.modelview_matrix_stack.top); - break; - case cc.KM_GL_PROJECTION: - cc.kmMat4Assign(pOut, cc.projection_matrix_stack.top); - break; - case cc.KM_GL_TEXTURE: - cc.kmMat4Assign(pOut, cc.texture_matrix_stack.top); - break; - default: - throw "Invalid matrix mode specified"; //TODO: Proper error handling - break; - } -}; + cc.initialized = true; + identity.identity(); + + //Make sure that each stack has the identity matrix + cc.modelview_matrix_stack.push(identity); + cc.projection_matrix_stack.push(identity); + cc.texture_matrix_stack.push(identity); + } + }; + + cc.lazyInitialize(); + + cc.kmGLFreeAll = function () { + //Clear the matrix stacks + cc.modelview_matrix_stack.release(); + cc.modelview_matrix_stack = null; + cc.projection_matrix_stack.release(); + cc.projection_matrix_stack = null; + cc.texture_matrix_stack.release(); + cc.texture_matrix_stack = null; + + //Delete the matrices + cc.initialized = false; //Set to uninitialized + cc.current_stack = null; //Set the current stack to point nowhere + }; + + cc.kmGLPushMatrix = function () { + cc.current_stack.push(cc.current_stack.top); + }; + + cc.kmGLPushMatrixWitMat4 = function (saveMat) { + cc.current_stack.stack.push(cc.current_stack.top); + saveMat.assignFrom(cc.current_stack.top); + cc.current_stack.top = saveMat; + }; + + cc.kmGLPopMatrix = function () { + //No need to lazy initialize, you shouldnt be popping first anyway! + //cc.km_mat4_stack_pop(cc.current_stack, null); + cc.current_stack.top = cc.current_stack.stack.pop(); + }; + + cc.kmGLMatrixMode = function (mode) { + //cc.lazyInitialize(); + switch (mode) { + case cc.KM_GL_MODELVIEW: + cc.current_stack = cc.modelview_matrix_stack; + break; + case cc.KM_GL_PROJECTION: + cc.current_stack = cc.projection_matrix_stack; + break; + case cc.KM_GL_TEXTURE: + cc.current_stack = cc.texture_matrix_stack; + break; + default: + throw "Invalid matrix mode specified"; //TODO: Proper error handling + break; + } + }; + + cc.kmGLLoadIdentity = function () { + //cc.lazyInitialize(); + cc.current_stack.top.identity(); //Replace the top matrix with the identity matrix + }; + + cc.kmGLLoadMatrix = function (pIn) { + //cc.lazyInitialize(); + cc.current_stack.top.assignFrom(pIn); + }; + + cc.kmGLMultMatrix = function (pIn) { + //cc.lazyInitialize(); + cc.current_stack.top.multiply(pIn); + }; + + var tempMatrix = new cc.math.Matrix4(); //an internal matrix + cc.kmGLTranslatef = function (x, y, z) { + //Create a rotation matrix using translation + var translation = cc.math.Matrix4.createByTranslation(x, y, z, tempMatrix); + + //Multiply the rotation matrix by the current matrix + cc.current_stack.top.multiply(translation); + }; + + var tempVector3 = new cc.math.Vec3(); + cc.kmGLRotatef = function (angle, x, y, z) { + tempVector3.fill(x, y, z); + //Create a rotation matrix using the axis and the angle + var rotation = cc.math.Matrix4.createByAxisAndAngle(tempVector3, cc.degreesToRadians(angle), tempMatrix); + + //Multiply the rotation matrix by the current matrix + cc.current_stack.top.multiply(rotation); + }; + + cc.kmGLScalef = function (x, y, z) { + var scaling = cc.math.Matrix4.createByScale(x, y, z, tempMatrix); + cc.current_stack.top.multiply(scaling); + }; + + cc.kmGLGetMatrix = function (mode, pOut) { + //cc.lazyInitialize(); + switch (mode) { + case cc.KM_GL_MODELVIEW: + pOut.assignFrom(cc.modelview_matrix_stack.top); + break; + case cc.KM_GL_PROJECTION: + pOut.assignFrom(cc.projection_matrix_stack.top); + break; + case cc.KM_GL_TEXTURE: + pOut.assignFrom(cc.texture_matrix_stack.top); + break; + default: + throw "Invalid matrix mode specified"; //TODO: Proper error handling + break; + } + }; +})(cc); diff --git a/cocos2d/kazmath/mat3.js b/cocos2d/kazmath/mat3.js index 7bcc8a1c77..05cdbe1417 100644 --- a/cocos2d/kazmath/mat3.js +++ b/cocos2d/kazmath/mat3.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -25,301 +27,315 @@ */ var Float32Array = Float32Array || Array; - -cc.kmMat3 = function () { - this.mat = new Float32Array([0, 0, 0, - 0, 0, 0, - 0, 0, 0]); -}; - -cc.kmMat3Fill = function (pOut, pMat) { - for (var i = 0; i < 9; i++) { - pOut.mat[i] = pMat; - } - return pOut; -}; - -cc.kmMat3Adjugate = function (pOut, pIn) { - pOut.mat[0] = pIn.mat[4] * pIn.mat[8] - pIn.mat[5] * pIn.mat[7]; - pOut.mat[1] = pIn.mat[2] * pIn.mat[7] - pIn.mat[1] * pIn.mat[8]; - pOut.mat[2] = pIn.mat[1] * pIn.mat[5] - pIn.mat[2] * pIn.mat[4]; - pOut.mat[3] = pIn.mat[5] * pIn.mat[6] - pIn.mat[3] * pIn.mat[8]; - pOut.mat[4] = pIn.mat[0] * pIn.mat[8] - pIn.mat[2] * pIn.mat[6]; - pOut.mat[5] = pIn.mat[2] * pIn.mat[3] - pIn.mat[0] * pIn.mat[5]; - pOut.mat[6] = pIn.mat[3] * pIn.mat[7] - pIn.mat[4] * pIn.mat[6]; - - // XXX: pIn.mat[9] is invalid! -// pOut.mat[7] = pIn.mat[1] * pIn.mat[6] - pIn.mat[9] * pIn.mat[7]; - pOut.mat[8] = pIn.mat[0] * pIn.mat[4] - pIn.mat[1] * pIn.mat[3]; - - return pOut; -}; - -cc.kmMat3Identity = function (pOut) { - pOut.mat[1] = pOut.mat[2] = pOut.mat[3] = - pOut.mat[5] = pOut.mat[6] = pOut.mat[7] = 0; - pOut.mat[0] = pOut.mat[4] = pOut.mat[8] = 1.0; - return pOut; -}; - -cc.kmMat3Inverse = function (pOut, pDeterminate, pM) { - var detInv; - var adjugate = new cc.kmMat3(); - - if (pDeterminate === 0.0) - return null; - - detInv = 1.0 / pDeterminate; - - cc.kmMat3Adjugate(adjugate, pM); - cc.kmMat3ScalarMultiply(pOut, adjugate, detInv); - - return pOut; -}; - -cc.kmMat3._identity = - new Float32Array([1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0]); - -cc.kmMat3IsIdentity = function (pIn) { - for (var i = 0; i < 9; i++) { - if (cc.kmMat3._identity[i] !== pIn.mat[i]) - return false; - } - return true; -}; - -cc.kmMat3Transpose = function (pOut, pIn) { - var z, x; - for (z = 0; z < 3; ++z) { - for (x = 0; x < 3; ++x) - pOut.mat[(z * 3) + x] = pIn.mat[(x * 3) + z]; - } - - return pOut; -}; - -cc.kmMat3Determinant = function (pIn) { - var output; - /* - calculating the determinant following the rule of sarus, - | 0 3 6 | 0 3 | - m = | 1 4 7 | 1 4 | - | 2 5 8 | 2 5 | - now sum up the products of the diagonals going to the right (i.e. 0,4,8) - and substract the products of the other diagonals (i.e. 2,4,6) - */ - - output = pIn.mat[0] * pIn.mat[4] * pIn.mat[8] + pIn.mat[1] * pIn.mat[5] * pIn.mat[6] + pIn.mat[2] * pIn.mat[3] * pIn.mat[7]; - output -= pIn.mat[2] * pIn.mat[4] * pIn.mat[6] + pIn.mat[0] * pIn.mat[5] * pIn.mat[7] + pIn.mat[1] * pIn.mat[3] * pIn.mat[8]; - - return output; -}; - -cc.kmMat3Multiply = function (pOut, pM1, pM2) { - var m1 = pM1.mat, m2 = pM2.mat; - - pOut.mat[0] = m1[0] * m2[0] + m1[3] * m2[1] + m1[6] * m2[2]; - pOut.mat[1] = m1[1] * m2[0] + m1[4] * m2[1] + m1[7] * m2[2]; - pOut.mat[2] = m1[2] * m2[0] + m1[5] * m2[1] + m1[8] * m2[2]; - - pOut.mat[3] = m1[0] * m2[3] + m1[3] * m2[4] + m1[6] * m2[5]; - pOut.mat[4] = m1[1] * m2[3] + m1[4] * m2[4] + m1[7] * m2[5]; - pOut.mat[5] = m1[2] * m2[3] + m1[5] * m2[4] + m1[8] * m2[5]; - - pOut.mat[6] = m1[0] * m2[6] + m1[3] * m2[7] + m1[6] * m2[8]; - pOut.mat[7] = m1[1] * m2[6] + m1[4] * m2[7] + m1[7] * m2[8]; - pOut.mat[8] = m1[2] * m2[6] + m1[5] * m2[7] + m1[8] * m2[8]; - - return pOut; -}; - -cc.kmMat3ScalarMultiply = function (pOut, pM, pFactor) { - for (var i = 0; i < 9; i++) { - pOut.mat[i] = pM.mat[i] * pFactor; - } - return pOut; -}; - -cc.kmMat3RotationAxisAngle = function (pOut, axis, radians) { - var rcos = Math.cos(radians); - var rsin = Math.sin(radians); - - pOut.mat[0] = rcos + axis.x * axis.x * (1 - rcos); - pOut.mat[1] = axis.z * rsin + axis.y * axis.x * (1 - rcos); - pOut.mat[2] = -axis.y * rsin + axis.z * axis.x * (1 - rcos); - - pOut.mat[3] = -axis.z * rsin + axis.x * axis.y * (1 - rcos); - pOut.mat[4] = rcos + axis.y * axis.y * (1 - rcos); - pOut.mat[5] = axis.x * rsin + axis.z * axis.y * (1 - rcos); - - pOut.mat[6] = axis.y * rsin + axis.x * axis.z * (1 - rcos); - pOut.mat[7] = -axis.x * rsin + axis.y * axis.z * (1 - rcos); - pOut.mat[8] = rcos + axis.z * axis.z * (1 - rcos); - - return pOut; -}; - -cc.kmMat3Assign = function (pOut, pIn) { - if(pOut == pIn) { - cc.log("cc.kmMat3Assign(): pOut equals pIn"); - return pOut; - } - - for (var i = 0; i < 9; i++) - pOut.mat[i] = pIn.mat[i]; - return pOut; -}; - -cc.kmMat3AreEqual = function (pMat1, pMat2) { - if (pMat1 == pMat2) - return true; - - for (var i = 0; i < 9; ++i) { - if (!(pMat1.mat[i] + cc.kmEpsilon > pMat2.mat[i] && - pMat1.mat[i] - cc.kmEpsilon < pMat2.mat[i])) { - return false; +(function(cc){ + cc.math.Matrix3 = function(mat3) { + if (mat3 && mat3.mat) { + this.mat = new Float32Array(mat3.mat); + } else { + this.mat = new Float32Array(9); + } + }; + cc.kmMat3 = cc.math.Matrix3; + var proto = cc.math.Matrix3.prototype; + + proto.fill = function(mat3) { //cc.kmMat3Fill + var mat = this.mat, matIn = mat3.mat; + mat[0] = matIn[0]; + mat[1] = matIn[1]; + mat[2] = matIn[2]; + mat[3] = matIn[3]; + mat[4] = matIn[4]; + mat[5] = matIn[5]; + mat[6] = matIn[6]; + mat[7] = matIn[7]; + mat[8] = matIn[8]; + return this; + }; + + proto.adjugate = function(){ //= cc.kmMat3Adjugate + var mat = this.mat; + var m0 = mat[0], m1 = mat[1], m2 = mat[2], m3 = mat[3], m4 = mat[4], + m5 = mat[5], m6 = mat[6], m7 = mat[7], m8 = mat[8]; + mat[0] = m4 * m8 - m5 * m7; + mat[1] = m2 * m7 - m1 * m8; + mat[2] = m1 * m5 - m2 * m4; + mat[3] = m5 * m6 - m3 * m8; + mat[4] = m0 * m8 - m2 * m6; + mat[5] = m2 * m3 - m0 * m5; + mat[6] = m3 * m7 - m4 * m6; + + // XXX: pIn.mat[9] is invalid! + //mat[7] = m1 * m6 - pIn.mat[9] * m7; + mat[8] = m0 * m4 - m1 * m3; + return this; + }; + + proto.identity = function() { //cc.kmMat3Identity + var mat = this.mat; + mat[1] = mat[2] = mat[3] = + mat[5] = mat[6] = mat[7] = 0; + mat[0] = mat[4] = mat[8] = 1.0; + return this; + }; + + var tmpMatrix = new cc.math.Matrix3(); // internal matrix + + proto.inverse = function(determinate){ //cc.kmMat3Inverse + if (determinate === 0.0) + return this; + tmpMatrix.assignFrom(this); + var detInv = 1.0 / determinate; + this.adjugate(); + this.multiplyScalar(detInv); + return this; + }; + + proto.isIdentity = function(){ //= cc.kmMat3IsIdentity + var mat = this.mat; + return (mat[0] === 1 && mat[1] === 0 && mat[2] === 0 + && mat[3] === 0 && mat[4] === 1 && mat[5] === 0 + && mat[6] === 0 && mat[7] === 0 && mat[8] === 1); + }; + + proto.transpose = function(){ // cc.kmMat3Transpose + var mat = this.mat; + var m1 = mat[1], m2 = mat[2], m3 = mat[3], m5 = mat[5], + m6 = mat[6], m7 = mat[7]; + // m0 = mat[0],m8 = mat[8], m4 = mat[4]; + //mat[0] = m0; + //mat[8] = m8; + //mat[4] = m4 + mat[1] = m3; + mat[2] = m6; + mat[3] = m1; + mat[5] = m7; + mat[6] = m2; + mat[7] = m5; + return this; + }; + + proto.determinant = function(){ + var mat = this.mat; + /* + calculating the determinant following the rule of sarus, + | 0 3 6 | 0 3 | + m = | 1 4 7 | 1 4 | + | 2 5 8 | 2 5 | + now sum up the products of the diagonals going to the right (i.e. 0,4,8) + and substract the products of the other diagonals (i.e. 2,4,6) + */ + var output = mat[0] * mat[4] * mat[8] + mat[1] * mat[5] * mat[6] + mat[2] * mat[3] * mat[7]; + output -= mat[2] * mat[4] * mat[6] + mat[0] * mat[5] * mat[7] + mat[1] * mat[3] * mat[8]; + return output; + }; + + proto.multiply = function(mat3){ + var m1 = this.mat, m2 = mat3.mat; + var a0 = m1[0], a1 = m1[1], a2 = m1[2], a3 = m1[3], a4 = m1[4], a5 = m1[5], + a6 = m1[6], a7 = m1[7], a8 = m1[8]; + var b0 = m2[0], b1 = m2[1], b2 = m2[2], b3 = m2[3], b4 = m2[4], b5 = m2[5], + b6 = m2[6], b7 = m2[7], b8 = m2[8]; + + m1[0] = a0 * b0 + a3 * b1 + a6 * b2; + m1[1] = a1 * b0 + a4 * b1 + a7 * b2; + m1[2] = a2 * b0 + a5 * b1 + a8 * b2; + + m1[3] = a2 * b0 + a5 * b1 + a8 * b2; + m1[4] = a1 * b3 + a4 * b4 + a7 * b5; + m1[5] = a2 * b3 + a5 * b4 + a8 * b5; + + m1[6] = a0 * b6 + a3 * b7 + a6 * b8; + m1[7] = a1 * b6 + a4 * b7 + a7 * b8; + m1[8] = a2 * b6 + a5 * b7 + a8 * b8; + return this; + }; + + proto.multiplyScalar = function(factor) { + var mat = this.mat; + mat[0] *= factor; + mat[1] *= factor; + mat[2] *= factor; + mat[3] *= factor; + mat[4] *= factor; + mat[5] *= factor; + mat[6] *= factor; + mat[7] *= factor; + mat[8] *= factor; + return this; + }; + + cc.math.Matrix3.rotationAxisAngle = function(axis, radians) { //cc.kmMat3RotationAxisAngle + var rcos = Math.cos(radians), rsin = Math.sin(radians); + var retMat = new cc.math.Matrix3(); + var mat = retMat.mat; + + mat[0] = rcos + axis.x * axis.x * (1 - rcos); + mat[1] = axis.z * rsin + axis.y * axis.x * (1 - rcos); + mat[2] = -axis.y * rsin + axis.z * axis.x * (1 - rcos); + + mat[3] = -axis.z * rsin + axis.x * axis.y * (1 - rcos); + mat[4] = rcos + axis.y * axis.y * (1 - rcos); + mat[5] = axis.x * rsin + axis.z * axis.y * (1 - rcos); + + mat[6] = axis.y * rsin + axis.x * axis.z * (1 - rcos); + mat[7] = -axis.x * rsin + axis.y * axis.z * (1 - rcos); + mat[8] = rcos + axis.z * axis.z * (1 - rcos); + + return retMat; + }; + + proto.assignFrom = function(matIn){ // cc.kmMat3Assign + if(this === matIn) { + cc.log("cc.math.Matrix3.assign(): current matrix equals matIn"); + return this; } + var mat = this.mat, m2 = matIn.mat; + mat[0] = m2[0]; + mat[1] = m2[1]; + mat[2] = m2[2]; + mat[3] = m2[3]; + mat[4] = m2[4]; + mat[5] = m2[5]; + mat[6] = m2[6]; + mat[7] = m2[7]; + mat[8] = m2[8]; + return this; + }; + + proto.equals = function(mat3) { + if (this === mat3) + return true; + var EPSILON = cc.math.EPSILON,m1 = this.mat, m2 = mat3.mat; + for (var i = 0; i < 9; ++i) { + if (!(m1[i] + EPSILON > m2[i] && m1[i] - EPSILON < m2[i])) + return false; + } + return true; + }; + + cc.math.Matrix3.createByRotationX = function(radians) { + var retMat = new cc.math.Matrix3(), mat = retMat.mat; + mat[0] = 1.0; + mat[1] = 0.0; + mat[2] = 0.0; + + mat[3] = 0.0; + mat[4] = Math.cos(radians); + mat[5] = Math.sin(radians); + + mat[6] = 0.0; + mat[7] = -Math.sin(radians); + mat[8] = Math.cos(radians); + return retMat; + }; + + cc.math.Matrix3.createByRotationY = function(radians) { + /* + | cos(A) 0 sin(A) | + M = | 0 1 0 | + | -sin(A) 0 cos(A) | + */ + var retMat = new cc.math.Matrix3(), mat = retMat.mat; + mat[0] = Math.cos(radians); + mat[1] = 0.0; + mat[2] = -Math.sin(radians); + + mat[3] = 0.0; + mat[4] = 1.0; + mat[5] = 0.0; + + mat[6] = Math.sin(radians); + mat[7] = 0.0; + mat[8] = Math.cos(radians); + return retMat; + }; + + cc.math.Matrix3.createByRotationZ = function(radians) { + /* + | cos(A) -sin(A) 0 | + M = | sin(A) cos(A) 0 | + | 0 0 1 | + */ + var retMat = new cc.math.Matrix3(), mat = retMat.mat; + mat[0] = Math.cos(radians); + mat[1] = -Math.sin(radians); + mat[2] = 0.0; + + mat[3] = Math.sin(radians); + mat[4] = Math.cos(radians); + mat[5] = 0.0; + + mat[6] = 0.0; + mat[7] = 0.0; + mat[8] = 1.0; + return retMat; + }; + + cc.math.Matrix3.createByRotation = function(radians) { + /* + | cos(A) -sin(A) 0 | + M = | sin(A) cos(A) 0 | + | 0 0 1 | + */ + var retMat = new cc.math.Matrix3(), mat = retMat.mat; + mat[0] = Math.cos(radians); + mat[1] = Math.sin(radians); + mat[2] = 0.0; + + mat[3] = -Math.sin(radians); + mat[4] = Math.cos(radians); + mat[5] = 0.0; + + mat[6] = 0.0; + mat[7] = 0.0; + mat[8] = 1.0; + return retMat; + }; + + cc.math.Matrix3.createByScale = function(x, y) { + var ret = new cc.math.Matrix3(); + ret.identity(); + ret.mat[0] = x; + ret.mat[4] = y; + return ret; + }; + + cc.math.Matrix3.createByTranslation = function(x, y){ + var ret = new cc.math.Matrix3(); + ret.identity(); + ret.mat[6] = x; + ret.mat[7] = y; + return ret; + }; + + cc.math.Matrix3.createByQuaternion = function(quaternion) { //cc.kmMat3RotationQuaternion + if(!quaternion) + return null; + + var ret = new cc.math.Matrix3(), mat = ret.mat; + // First row + mat[0] = 1.0 - 2.0 * (quaternion.y * quaternion.y + quaternion.z * quaternion.z); + mat[1] = 2.0 * (quaternion.x * quaternion.y - quaternion.w * quaternion.z); + mat[2] = 2.0 * (quaternion.x * quaternion.z + quaternion.w * quaternion.y); + + // Second row + mat[3] = 2.0 * (quaternion.x * quaternion.y + quaternion.w * quaternion.z); + mat[4] = 1.0 - 2.0 * (quaternion.x * quaternion.x + quaternion.z * quaternion.z); + mat[5] = 2.0 * (quaternion.y * quaternion.z - quaternion.w * quaternion.x); + + // Third row + mat[6] = 2.0 * (quaternion.x * quaternion.z - quaternion.w * quaternion.y); + mat[7] = 2.0 * (quaternion.y * quaternion.z + quaternion.w * quaternion.x); + mat[8] = 1.0 - 2.0 * (quaternion.x * quaternion.x + quaternion.y * quaternion.y); + return ret; + }; + + proto.rotationToAxisAngle = function() { //cc.kmMat3RotationToAxisAngle + return cc.math.Quaternion.rotationMatrix(this).toAxisAndAngle(); } +})(cc); + - return true; -}; - -cc.kmMat3RotationX = function (pOut, radians) { - /* - | 1 0 0 | - M = | 0 cos(A) -sin(A) | - | 0 sin(A) cos(A) | - - */ - - pOut.mat[0] = 1.0; - pOut.mat[1] = 0.0; - pOut.mat[2] = 0.0; - - pOut.mat[3] = 0.0; - pOut.mat[4] = Math.cos(radians); - pOut.mat[5] = Math.sin(radians); - - pOut.mat[6] = 0.0; - pOut.mat[7] = -Math.sin(radians); - pOut.mat[8] = Math.cos(radians); - - return pOut; -}; - -cc.kmMat3RotationY = function (pOut, radians) { - /* - | cos(A) 0 sin(A) | - M = | 0 1 0 | - | -sin(A) 0 cos(A) | - */ - - pOut.mat[0] = Math.cos(radians); - pOut.mat[1] = 0.0; - pOut.mat[2] = -Math.sin(radians); - - pOut.mat[3] = 0.0; - pOut.mat[4] = 1.0; - pOut.mat[5] = 0.0; - - pOut.mat[6] = Math.sin(radians); - pOut.mat[7] = 0.0; - pOut.mat[8] = Math.cos(radians); - - return pOut; -}; - -cc.kmMat3RotationZ = function (pOut, radians) { - /* - | cos(A) -sin(A) 0 | - M = | sin(A) cos(A) 0 | - | 0 0 1 | - */ - pOut.mat[0] = Math.cos(radians); - pOut.mat[1] = -Math.sin(radians); - pOut.mat[2] = 0.0; - - pOut.mat[3] = Math.sin(radians); - pOut.mat[4] = Math.cos(radians); - pOut.mat[5] = 0.0; - - pOut.mat[6] = 0.0; - pOut.mat[7] = 0.0; - pOut.mat[8] = 1.0; - - return pOut; -}; - -cc.kmMat3Rotation = function (pOut, radians) { - /* - | cos(A) -sin(A) 0 | - M = | sin(A) cos(A) 0 | - | 0 0 1 | - */ - pOut.mat[0] = Math.cos(radians); - pOut.mat[1] = Math.sin(radians); - pOut.mat[2] = 0.0; - - pOut.mat[3] = -Math.sin(radians); - pOut.mat[4] = Math.cos(radians); - pOut.mat[5] = 0.0; - - pOut.mat[6] = 0.0; - pOut.mat[7] = 0.0; - pOut.mat[8] = 1.0; - return pOut; -}; - -cc.kmMat3Scaling = function (pOut, x, y) { -// memset(pOut.mat, 0, sizeof(float) * 9); - cc.kmMat3Identity(pOut); - pOut.mat[0] = x; - pOut.mat[4] = y; - - return pOut; -}; - -cc.kmMat3Translation = function (pOut, x, y) { -// memset(pOut.mat, 0, sizeof(float) * 9); - cc.kmMat3Identity(pOut); - pOut.mat[6] = x; - pOut.mat[7] = y; -// pOut.mat[8] = 1.0; - - return pOut; -}; - -cc.kmMat3RotationQuaternion = function (pOut, pIn) { - if (!pIn || !pOut) - return null; - - // First row - pOut.mat[0] = 1.0 - 2.0 * (pIn.y * pIn.y + pIn.z * pIn.z); - pOut.mat[1] = 2.0 * (pIn.x * pIn.y - pIn.w * pIn.z); - pOut.mat[2] = 2.0 * (pIn.x * pIn.z + pIn.w * pIn.y); - - // Second row - pOut.mat[3] = 2.0 * (pIn.x * pIn.y + pIn.w * pIn.z); - pOut.mat[4] = 1.0 - 2.0 * (pIn.x * pIn.x + pIn.z * pIn.z); - pOut.mat[5] = 2.0 * (pIn.y * pIn.z - pIn.w * pIn.x); - - // Third row - pOut.mat[6] = 2.0 * (pIn.x * pIn.z - pIn.w * pIn.y); - pOut.mat[7] = 2.0 * (pIn.y * pIn.z + pIn.w * pIn.x); - pOut.mat[8] = 1.0 - 2.0 * (pIn.x * pIn.x + pIn.y * pIn.y); - - return pOut; -}; - -cc.kmMat3RotationToAxisAngle = function (pAxis, radians, pIn) { - /*Surely not this easy?*/ - var temp; - cc.kmQuaternionRotationMatrix(temp, pIn); - cc.kmQuaternionToAxisAngle(temp, pAxis, radians); - return pAxis; -}; diff --git a/cocos2d/kazmath/mat4.js b/cocos2d/kazmath/mat4.js index 8fa12a41de..b1af75efc3 100644 --- a/cocos2d/kazmath/mat4.js +++ b/cocos2d/kazmath/mat4.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,784 +26,986 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - *

- A 4x4 matrix
-
- mat =
- | 0 4 8 12 |
- | 1 5 9 13 |
- | 2 6 10 14 |
- | 3 7 11 15 | -

- */ -cc.kmMat4 = function () { - this.mat = new Float32Array([0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0]); -}; +(function(cc) { + /** + *

+ * A 4x4 matrix
+ *
+ * mat =
+ * | 0 4 8 12 |
+ * | 1 5 9 13 |
+ * | 2 6 10 14 |
+ * | 3 7 11 15 | + *

+ * @param {cc.math.Matrix4} [mat4] + */ + cc.math.Matrix4 = function (mat4) { + if(mat4 && mat4.mat){ + this.mat = new Float32Array(mat4.mat); + } else { + this.mat = new Float32Array(16); + } + }; + cc.kmMat4 = cc.math.Matrix4; + var proto = cc.math.Matrix4.prototype; -/** - * Fills a kmMat4 structure with the values from a 16 element array of floats - * @Params pOut - A pointer to the destination matrix - * @Params pMat - A 16 element array of floats - * @Return Returns pOut so that the call can be nested - */ -cc.kmMat4Fill = function (pOut, pMat) { - pOut.mat[0] = pOut.mat[1] = pOut.mat[2] =pOut.mat[3] = - pOut.mat[4] =pOut.mat[5] =pOut.mat[6] =pOut.mat[7] = - pOut.mat[8] =pOut.mat[9] =pOut.mat[10] =pOut.mat[11] = - pOut.mat[12] =pOut.mat[13] =pOut.mat[14] =pOut.mat[15] =pMat; -}; + /** + * Fills a cc.math.Matrix4 structure with the values from a 16 element array of floats + * @param {Array} scalarArr + */ + proto.fill = function(scalarArr){ //cc.kmMat4Fill + var mat = this.mat; + for(var i = 0; i < 16; i++){ + mat[i] = scalarArr[i]; + } + return this; + }; -/** - * Sets pOut to an identity matrix returns pOut - * @Params pOut - A pointer to the matrix to set to identity - * @Return Returns pOut so that the call can be nested - */ -cc.kmMat4Identity = function (pOut) { - pOut.mat[1] = pOut.mat[2] = pOut.mat[3] - = pOut.mat[4] = pOut.mat[6] = pOut.mat[7] - = pOut.mat[8] = pOut.mat[9] = pOut.mat[11] - = pOut.mat[12] = pOut.mat[13] = pOut.mat[14] = 0; - pOut.mat[0] = pOut.mat[5] = pOut.mat[10] = pOut.mat[15] = 1.0; - return pOut; -}; - -cc.kmMat4._get = function (pIn, row, col) { - return pIn.mat[row + 4 * col]; -}; - -cc.kmMat4._set = function (pIn, row, col, value) { - pIn.mat[row + 4 * col] = value; -}; - -cc.kmMat4._swap = function (pIn, r1, c1, r2, c2) { - var tmp = cc.kmMat4._get(pIn, r1, c1); - cc.kmMat4._set(pIn, r1, c1, cc.kmMat4._get(pIn, r2, c2)); - cc.kmMat4._set(pIn, r2, c2, tmp); -}; - -//Returns an upper and a lower triangular matrix which are L and R in the Gauss algorithm -cc.kmMat4._gaussj = function (a, b) { - var i, icol = 0, irow = 0, j, k, l, ll, n = 4, m = 4; - var big, dum, pivinv; - var indxc = [0, 0, 0, 0]; - var indxr = [0, 0, 0, 0]; - var ipiv = [0, 0, 0, 0]; - - /* for (j = 0; j < n; j++) { - ipiv[j] = 0; - }*/ - - for (i = 0; i < n; i++) { - big = 0.0; - for (j = 0; j < n; j++) { - if (ipiv[j] != 1) { - for (k = 0; k < n; k++) { - if (ipiv[k] == 0) { - if (Math.abs(cc.kmMat4._get(a, j, k)) >= big) { - big = Math.abs(cc.kmMat4._get(a, j, k)); - irow = j; - icol = k; + /** + * Sets pOut to an identity matrix returns pOut + * @Params pOut - A pointer to the matrix to set to identity + * @Return Returns pOut so that the call can be nested + */ + cc.kmMat4Identity = function (pOut) { + var mat = pOut.mat; + mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] + = mat[8] = mat[9] = mat[11] = mat[12] = mat[13] = mat[14] = 0; + mat[0] = mat[5] = mat[10] = mat[15] = 1.0; + return pOut; + }; + + /** + * Sets matrix to identity value. + * @returns {cc.math.Matrix4} + */ + proto.identity = function(){ + var mat = this.mat; + mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] + = mat[8] = mat[9] = mat[11] = mat[12] = mat[13] = mat[14] = 0; + mat[0] = mat[5] = mat[10] = mat[15] = 1.0; + return this; + }; + + proto.get = function(row, col){ + return this.mat[row + 4 * col]; + }; + + proto.set = function(row, col, value){ + this.mat[row + 4 * col] = value; + }; + + proto.swap = function(r1, c1, r2, c2) { +/* var tmp = this.get(r1, c1); + this.set(r1, c1, this.get(r2, c2)); + this.set(r2, c2, tmp);*/ + var mat = this.mat, tmp = mat[r1 + 4 * c1]; + mat[r1 + 4 * c1] = mat[r2 + 4 * c2]; + mat[r2 + 4 * c2] = tmp; + }; + + //Returns an upper and a lower triangular matrix which are L and R in the Gauss algorithm + cc.math.Matrix4._gaussj = function (a, b) { + var i, icol = 0, irow = 0, j, k, l, ll, n = 4, m = 4, selElement; + var big, dum, pivinv; + var indxc = [0, 0, 0, 0], indxr = [0, 0, 0, 0], ipiv = [0, 0, 0, 0]; + + /* for (j = 0; j < n; j++) { + ipiv[j] = 0; + }*/ + + for (i = 0; i < n; i++) { + big = 0.0; + for (j = 0; j < n; j++) { + if (ipiv[j] !== 1) { + for (k = 0; k < n; k++) { + if (ipiv[k] === 0) { + selElement = Math.abs(a.get(j, k)); + if (selElement >= big) { + big = selElement; + irow = j; + icol = k; + } } } } } - } - ++(ipiv[icol]); - if (irow != icol) { - for (l = 0; l < n; l++) - cc.kmMat4._swap(a, irow, l, icol, l); - for (l = 0; l < m; l++) - cc.kmMat4._swap(b, irow, l, icol, l); - } - indxr[i] = irow; - indxc[i] = icol; - if (cc.kmMat4._get(a, icol, icol) == 0.0) - return cc.KM_FALSE; - - pivinv = 1.0 / cc.kmMat4._get(a, icol, icol); - cc.kmMat4._set(a, icol, icol, 1.0); - for (l = 0; l < n; l++) - cc.kmMat4._set(a, icol, l, cc.kmMat4._get(a, icol, l) * pivinv); - - for (l = 0; l < m; l++) - cc.kmMat4._set(b, icol, l, cc.kmMat4._get(b, icol, l) * pivinv); - - for (ll = 0; ll < n; ll++) { - if (ll != icol) { - dum = cc.kmMat4._get(a, ll, icol); - cc.kmMat4._set(a, ll, icol, 0.0); + ++(ipiv[icol]); + if (irow !== icol) { for (l = 0; l < n; l++) - cc.kmMat4._set(a, ll, l, cc.kmMat4._get(a, ll, l) - cc.kmMat4._get(a, icol, l) * dum); - + a.swap(irow, l, icol, l); for (l = 0; l < m; l++) - cc.kmMat4._set(b, ll, l, cc.kmMat4._get(a, ll, l) - cc.kmMat4._get(b, icol, l) * dum); + b.swap(irow, l, icol, l); } - } - } -// This is the end of the main loop over columns of the reduction. It only remains to unscram- -// ble the solution in view of the column interchanges. We do this by interchanging pairs of -// columns in the reverse order that the permutation was built up. - for (l = n - 1; l >= 0; l--) { - if (indxr[l] != indxc[l]) { - for (k = 0; k < n; k++) - cc.kmMat4._swap(a, k, indxr[l], k, indxc[l]); - } - } - return cc.KM_TRUE; -}; - -cc.kmMat4._identity = - new Float32Array([1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0]); - -/** - * Calculates the inverse of pM and stores the result in - * pOut. - * @Return Returns NULL if there is no inverse, else pOut - */ -cc.kmMat4Inverse = function (pOut, pM) { - var inv = new cc.kmMat4(); - var tmp = new cc.kmMat4(); + indxr[i] = irow; + indxc[i] = icol; + if (a.get(icol, icol) === 0.0) + return false; - cc.kmMat4Assign(inv, pM); - cc.kmMat4Identity(tmp); - - if (cc.kmMat4._gaussj(inv, tmp) == cc.KM_FALSE) - return null; + pivinv = 1.0 / a.get(icol, icol); + a.set(icol, icol, 1.0); + for (l = 0; l < n; l++) + a.set(icol, l, a.get(icol, l) * pivinv); - cc.kmMat4Assign(pOut, inv); - return pOut; -}; + for (l = 0; l < m; l++) + b.set(icol, l, b.get(icol, l) * pivinv); -/** - * Returns KM_TRUE if pIn is an identity matrix - * KM_FALSE otherwise - */ -cc.kmMat4IsIdentity = function (pIn) { - for (var i = 0; i < 16; i++) { - if (cc.kmMat4._identity[i] != pIn.mat[i]) - return false; - } - return true; -}; + for (ll = 0; ll < n; ll++) { + if (ll !== icol) { + dum = a.get(ll, icol); + a.set(ll, icol, 0.0); + for (l = 0; l < n; l++) + a.set(ll, l, a.get(ll, l) - a.get(icol, l) * dum); -/** - * Sets pOut to the transpose of pIn, returns pOut - */ -cc.kmMat4Transpose = function (pOut, pIn) { - var x, z, outArr = pOut.mat,inArr = pIn.mat; - for (z = 0; z < 4; ++z) { - for (x = 0; x < 4; ++x) - outArr[(z * 4) + x] = inArr[(x * 4) + z]; - } - return pOut; -}; + for (l = 0; l < m; l++) + b.set(ll, l, a.get(ll, l) - b.get(icol, l) * dum); + } + } + } + // This is the end of the main loop over columns of the reduction. It only remains to unscram- + // ble the solution in view of the column interchanges. We do this by interchanging pairs of + // columns in the reverse order that the permutation was built up. + for (l = n - 1; l >= 0; l--) { + if (indxr[l] !== indxc[l]) { + for (k = 0; k < n; k++) + a.swap(k, indxr[l], k, indxc[l]); + } + } + return true; + }; -/** - * Multiplies pM1 with pM2, stores the result in pOut, returns pOut - */ -cc.kmMat4Multiply = function (pOut, pM1, pM2) { - // Cache the matrix values (makes for huge speed increases!) - var outArray = pOut.mat; - var a00 = pM1.mat[0], a01 = pM1.mat[1], a02 = pM1.mat[2], a03 = pM1.mat[3]; - var a10 = pM1.mat[4], a11 = pM1.mat[5], a12 = pM1.mat[6], a13 = pM1.mat[7]; - var a20 = pM1.mat[8], a21 = pM1.mat[9], a22 = pM1.mat[10], a23 = pM1.mat[11]; - var a30 = pM1.mat[12], a31 = pM1.mat[13], a32 = pM1.mat[14], a33 = pM1.mat[15]; - - var b00 = pM2.mat[0], b01 = pM2.mat[1], b02 = pM2.mat[2], b03 = pM2.mat[3]; - var b10 = pM2.mat[4], b11 = pM2.mat[5], b12 = pM2.mat[6], b13 = pM2.mat[7]; - var b20 = pM2.mat[8], b21 = pM2.mat[9], b22 = pM2.mat[10], b23 = pM2.mat[11]; - var b30 = pM2.mat[12], b31 = pM2.mat[13], b32 = pM2.mat[14], b33 = pM2.mat[15]; - - outArray[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; - outArray[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; - outArray[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; - outArray[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; - outArray[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; - outArray[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; - outArray[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; - outArray[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; - outArray[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; - outArray[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; - outArray[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; - outArray[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; - outArray[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; - outArray[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; - outArray[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; - outArray[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; - return pOut; -}; - -cc.getMat4MultiplyValue = function (pM1, pM2) { - var m1 = pM1.mat, m2 = pM2.mat; - var mat = new Float32Array(16); - - mat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; - mat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; - mat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; - mat[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; - - mat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; - mat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; - mat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; - mat[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; - - mat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; - mat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; - mat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; - mat[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; - - mat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; - mat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; - mat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; - mat[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; - - return mat; -}; - -cc.getMat4MultiplyWithMat4 = function (pM1, pM2, swapMat) { - var m1 = pM1.mat, m2 = pM2.mat; - var mat = swapMat.mat; - - mat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; - mat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; - mat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; - mat[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; - - mat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; - mat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; - mat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; - mat[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; - - mat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; - mat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; - mat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; - mat[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; - - mat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; - mat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; - mat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; - mat[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; - - return swapMat.mat; -}; + var identityMatrix = new cc.math.Matrix4().identity(); + /** + * Calculates the inverse of pM and stores the result in pOut. + * Please use matrix4's inverse function instead. + * @Return Returns NULL if there is no inverse, else pOut + */ + cc.kmMat4Inverse = function (pOut, pM) { + var inv = new cc.math.Matrix4(pM); + if (cc.math.Matrix4._gaussj(inv, identityMatrix) === false) + return null; + pOut.assignFrom(inv); + return pOut; + }; -/** - * Assigns the value of pIn to pOut - */ -cc.kmMat4Assign = function (pOut, pIn) { - if(pOut == pIn) { - cc.log("cc.kmMat4Assign(): pOut equals pIn"); + /** + * Calculates the inverse of current matrix. + * @returns {cc.math.Matrix4} Returns null if there is no inverse, else returns a new inverse matrix object + */ + proto.inverse = function(){ //cc.kmMat4Inverse + var inv = new cc.math.Matrix4(this); + if (cc.math.Matrix4._gaussj(inv, identityMatrix) === false) + return null; + return inv; + }; + + /** + * Returns true if current matrix is an identity matrix, false otherwise + */ + proto.isIdentity = function () { // cc.kmMat4IsIdentity + var mat = this.mat; + return (mat[0] === 1 && mat[1] === 0 && mat[2] === 0 && mat[3] === 0 + && mat[4] === 0 && mat[5] === 1 && mat[6] === 0 && mat[7] === 0 + && mat[8] === 0 && mat[9] === 0 && mat[10] === 1 && mat[11] === 0 + && mat[12] === 0 && mat[13] === 0 && mat[14] === 0 && mat[15] === 1); + }; + + /** + * transpose the current matrix + */ + proto.transpose = function() { // cc.kmMat4Transpose + var mat = this.mat; + var m1 = mat[1], m2 = mat[2], m3 = mat[3], + m4 = mat[4], m6 = mat[6], m7 = mat[7], + m8 = mat[8], m9 = mat[9], m11 = mat[11], + m12 = mat[12], m13 = mat[13], m14 = mat[14]; + mat[1] = m4; + mat[2] = m8; + mat[3] = m12; + + mat[4] = m1; + mat[6] = m9; + mat[7] = m13; + + mat[8] = m2; + mat[9] = m6; + mat[11] = m14; + + mat[12] = m3; + mat[13] = m7; + mat[14] = m11; + return this; + }; + + /** + * Multiplies pM1 with pM2, stores the result in pOut, returns pOut + */ + cc.kmMat4Multiply = function (pOut, pM1, pM2) { + // Cache the matrix values (makes for huge speed increases!) + var outArray = pOut.mat, mat1 = pM1.mat, mat2 = pM2.mat; + var a00 = mat1[0], a01 = mat1[1], a02 = mat1[2], a03 = mat1[3]; + var a10 = mat1[4], a11 = mat1[5], a12 = mat1[6], a13 = mat1[7]; + var a20 = mat1[8], a21 = mat1[9], a22 = mat1[10], a23 = mat1[11]; + var a30 = mat1[12], a31 = mat1[13], a32 = mat1[14], a33 = mat1[15]; + + var b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3]; + var b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7]; + var b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11]; + var b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; + + outArray[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + outArray[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + outArray[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + outArray[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + outArray[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + outArray[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + outArray[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + outArray[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + outArray[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + outArray[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + outArray[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + outArray[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + outArray[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + outArray[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + outArray[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + outArray[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; return pOut; - } + }; - var outArr = pOut.mat; - var inArr = pIn.mat; + /** + * current matrix multiplies with other matrix mat4 + * @param {cc.math.Matrix4} mat4 + * @returns {cc.math.Matrix4} + */ + proto.multiply = function(mat4){ + // Cache the matrix values (makes for huge speed increases!) + var mat = this.mat, mat2 = mat4.mat; + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; + var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; + var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + var b00 = mat2[0], b01 = mat2[1], b02 = mat2[2], b03 = mat2[3]; + var b10 = mat2[4], b11 = mat2[5], b12 = mat2[6], b13 = mat2[7]; + var b20 = mat2[8], b21 = mat2[9], b22 = mat2[10], b23 = mat2[11]; + var b30 = mat2[12], b31 = mat2[13], b32 = mat2[14], b33 = mat2[15]; + + mat[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + mat[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + mat[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + mat[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + mat[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + mat[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + mat[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + mat[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + mat[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + mat[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + mat[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + mat[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + mat[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + mat[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + mat[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + mat[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + return this; + }; + + cc.getMat4MultiplyValue = function (pM1, pM2) { + var m1 = pM1.mat, m2 = pM2.mat; + var mat = new Float32Array(16); + + mat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]; + mat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]; + mat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]; + mat[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]; + + mat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]; + mat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]; + mat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]; + mat[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]; + + mat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]; + mat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]; + mat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]; + mat[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]; + + mat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]; + mat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; + mat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; + mat[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; + + return mat; + }; + + /** + * Assigns the value of pIn to pOut + */ + cc.kmMat4Assign = function (pOut, pIn) { + if (pOut === pIn) { + cc.log("cc.kmMat4Assign(): pOut equals pIn"); + return pOut; + } - outArr[0] = inArr[0]; - outArr[1] = inArr[1]; - outArr[2] = inArr[2]; - outArr[3] = inArr[3]; + var outArr = pOut.mat; + var inArr = pIn.mat; - outArr[4] = inArr[4]; - outArr[5] = inArr[5]; - outArr[6] = inArr[6]; - outArr[7] = inArr[7]; + outArr[0] = inArr[0]; + outArr[1] = inArr[1]; + outArr[2] = inArr[2]; + outArr[3] = inArr[3]; - outArr[8] = inArr[8]; - outArr[9] = inArr[9]; - outArr[10] = inArr[10]; - outArr[11] = inArr[11]; + outArr[4] = inArr[4]; + outArr[5] = inArr[5]; + outArr[6] = inArr[6]; + outArr[7] = inArr[7]; - outArr[12] = inArr[12]; - outArr[13] = inArr[13]; - outArr[14] = inArr[14]; - outArr[15] = inArr[15]; - return pOut; -}; + outArr[8] = inArr[8]; + outArr[9] = inArr[9]; + outArr[10] = inArr[10]; + outArr[11] = inArr[11]; -/** - * Returns KM_TRUE if the 2 matrices are equal (approximately) - */ -cc.kmMat4AreEqual = function (pMat1, pMat2) { - if(pMat1 == pMat2){ - cc.log("cc.kmMat4AreEqual(): pMat1 and pMat2 are same object."); - return true; - } + outArr[12] = inArr[12]; + outArr[13] = inArr[13]; + outArr[14] = inArr[14]; + outArr[15] = inArr[15]; + return pOut; + }; - for (var i = 0; i < 16; i++) { - if (!(pMat1.mat[i] + cc.kmEpsilon > pMat2.mat[i] && - pMat1.mat[i] - cc.kmEpsilon < pMat2.mat[i])) { - return false; + /** + * Assigns the value of current matrix from mat4 + * @param {cc.math.Matrix4} mat4 + * @returns {cc.math.Matrix4} + */ + proto.assignFrom = function(mat4) { + if (this === mat4) { + cc.log("cc.mat.Matrix4.assignFrom(): mat4 equals current matrix"); + return this; } - } - return true; -}; - -/** - * Builds an X-axis rotation matrix and stores it in pOut, returns pOut - */ -cc.kmMat4RotationX = function (pOut, radians) { - /* - | 1 0 0 0 | - M = | 0 cos(A) -sin(A) 0 | - | 0 sin(A) cos(A) 0 | - | 0 0 0 1 | - + var outArr = this.mat, inArr = mat4.mat; + + outArr[0] = inArr[0]; + outArr[1] = inArr[1]; + outArr[2] = inArr[2]; + outArr[3] = inArr[3]; + + outArr[4] = inArr[4]; + outArr[5] = inArr[5]; + outArr[6] = inArr[6]; + outArr[7] = inArr[7]; + + outArr[8] = inArr[8]; + outArr[9] = inArr[9]; + outArr[10] = inArr[10]; + outArr[11] = inArr[11]; + + outArr[12] = inArr[12]; + outArr[13] = inArr[13]; + outArr[14] = inArr[14]; + outArr[15] = inArr[15]; + return this; + }; + + /** + * Returns true if current matrix equal mat4 (approximately) + * @param {cc.math.Matrix4} mat4 + * @returns {boolean} */ + proto.equals = function(mat4) { + if (this === mat4) { + cc.log("cc.kmMat4AreEqual(): pMat1 and pMat2 are same object."); + return true; + } + var matA = this.mat, matB = mat4.mat, EPSILON = cc.math.EPSILON; + for (var i = 0; i < 16; i++) { + if (!(matA[i] + EPSILON > matB[i] && matA[i] - EPSILON < matB[i])) + return false; + } + return true; + }; - pOut.mat[0] = 1.0; - pOut.mat[1] = 0.0; - pOut.mat[2] = 0.0; - pOut.mat[3] = 0.0; - - pOut.mat[4] = 0.0; - pOut.mat[5] = Math.cos(radians); - pOut.mat[6] = Math.sin(radians); - pOut.mat[7] = 0.0; - - pOut.mat[8] = 0.0; - pOut.mat[9] = -Math.sin(radians); - pOut.mat[10] = Math.cos(radians); - pOut.mat[11] = 0.0; - - pOut.mat[12] = 0.0; - pOut.mat[13] = 0.0; - pOut.mat[14] = 0.0; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** - * Builds a rotation matrix using the rotation around the Y-axis - * The result is stored in pOut, pOut is returned. - */ -cc.kmMat4RotationY = function (pOut, radians) { - /* - | cos(A) 0 sin(A) 0 | - M = | 0 1 0 0 | - | -sin(A) 0 cos(A) 0 | - | 0 0 0 1 | - */ - pOut.mat[0] = Math.cos(radians); - pOut.mat[1] = 0.0; - pOut.mat[2] = -Math.sin(radians); - pOut.mat[3] = 0.0; - - pOut.mat[4] = 0.0; - pOut.mat[5] = 1.0; - pOut.mat[6] = 0.0; - pOut.mat[7] = 0.0; - - pOut.mat[8] = Math.sin(radians); - pOut.mat[9] = 0.0; - pOut.mat[10] = Math.cos(radians); - pOut.mat[11] = 0.0; - - pOut.mat[12] = 0.0; - pOut.mat[13] = 0.0; - pOut.mat[14] = 0.0; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** - * Builds a rotation matrix around the Z-axis. The resulting - * matrix is stored in pOut. pOut is returned. - */ -cc.kmMat4RotationZ = function (pOut, radians) { - /* - | cos(A) -sin(A) 0 0 | - M = | sin(A) cos(A) 0 0 | - | 0 0 1 0 | - | 0 0 0 1 | - */ - pOut.mat[0] = Math.cos(radians); - pOut.mat[1] = Math.sin(radians); - pOut.mat[2] = 0.0; - pOut.mat[3] = 0.0; - - pOut.mat[4] = -Math.sin(radians); - pOut.mat[5] = Math.cos(radians); - pOut.mat[6] = 0.0; - pOut.mat[7] = 0.0; - - pOut.mat[8] = 0.0; - pOut.mat[9] = 0.0; - pOut.mat[10] = 1.0; - pOut.mat[11] = 0.0; - - pOut.mat[12] = 0.0; - pOut.mat[13] = 0.0; - pOut.mat[14] = 0.0; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** - * Builds a rotation matrix from pitch, yaw and roll. The resulting - * matrix is stored in pOut and pOut is returned - */ -cc.kmMat4RotationPitchYawRoll = function (pOut, pitch, yaw, roll) { - var cr = Math.cos(pitch); - var sr = Math.sin(pitch); - var cp = Math.cos(yaw); - var sp = Math.sin(yaw); - var cy = Math.cos(roll); - var sy = Math.sin(roll); - var srsp = sr * sp; - var crsp = cr * sp; - - pOut.mat[0] = cp * cy; - pOut.mat[4] = cp * sy; - pOut.mat[8] = -sp; - - pOut.mat[1] = srsp * cy - cr * sy; - pOut.mat[5] = srsp * sy + cr * cy; - pOut.mat[9] = sr * cp; - - pOut.mat[2] = crsp * cy + sr * sy; - pOut.mat[6] = crsp * sy - sr * cy; - pOut.mat[10] = cr * cp; - - pOut.mat[3] = pOut.mat[7] = pOut.mat[11] = 0.0; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** Converts a quaternion to a rotation matrix, - * the result is stored in pOut, returns pOut - */ -cc.kmMat4RotationQuaternion = function (pOut, pQ) { - pOut.mat[0] = 1.0 - 2.0 * (pQ.y * pQ.y + pQ.z * pQ.z ); - pOut.mat[1] = 2.0 * (pQ.x * pQ.y + pQ.z * pQ.w); - pOut.mat[2] = 2.0 * (pQ.x * pQ.z - pQ.y * pQ.w); - pOut.mat[3] = 0.0; - - // Second row - pOut.mat[4] = 2.0 * ( pQ.x * pQ.y - pQ.z * pQ.w ); - pOut.mat[5] = 1.0 - 2.0 * ( pQ.x * pQ.x + pQ.z * pQ.z ); - pOut.mat[6] = 2.0 * (pQ.z * pQ.y + pQ.x * pQ.w ); - pOut.mat[7] = 0.0; - - // Third row - pOut.mat[8] = 2.0 * ( pQ.x * pQ.z + pQ.y * pQ.w ); - pOut.mat[9] = 2.0 * ( pQ.y * pQ.z - pQ.x * pQ.w ); - pOut.mat[10] = 1.0 - 2.0 * ( pQ.x * pQ.x + pQ.y * pQ.y ); - pOut.mat[11] = 0.0; - - // Fourth row - pOut.mat[12] = 0; - pOut.mat[13] = 0; - pOut.mat[14] = 0; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** Build a 4x4 OpenGL transformation matrix using a 3x3 rotation matrix, - * and a 3d vector representing a translation. Assign the result to pOut, - * pOut is also returned. - */ -cc.kmMat4RotationTranslation = function (pOut, rotation, translation) { - pOut.mat[0] = rotation.mat[0]; - pOut.mat[1] = rotation.mat[1]; - pOut.mat[2] = rotation.mat[2]; - pOut.mat[3] = 0.0; - - pOut.mat[4] = rotation.mat[3]; - pOut.mat[5] = rotation.mat[4]; - pOut.mat[6] = rotation.mat[5]; - pOut.mat[7] = 0.0; - - pOut.mat[8] = rotation.mat[6]; - pOut.mat[9] = rotation.mat[7]; - pOut.mat[10] = rotation.mat[8]; - pOut.mat[11] = 0.0; - - pOut.mat[12] = translation.x; - pOut.mat[13] = translation.y; - pOut.mat[14] = translation.z; - pOut.mat[15] = 1.0; - - return pOut; -}; - -/** Builds a scaling matrix */ -cc.kmMat4Scaling = function (pOut, x, y, z) { - pOut.mat[0] = x; - pOut.mat[5] = y; - pOut.mat[10] = z; - pOut.mat[15] = 1.0; - pOut.mat[1] = pOut.mat[2] = pOut.mat[3] = - pOut.mat[4] = pOut.mat[6] = pOut.mat[7] = - pOut.mat[8] = pOut.mat[9] = pOut.mat[11] = - pOut.mat[12] = pOut.mat[13] = pOut.mat[14] = 0; - return pOut; -}; - -/** - * Builds a translation matrix. All other elements in the matrix - * will be set to zero except for the diagonal which is set to 1.0 - */ -cc.kmMat4Translation = function (pOut, x, y, z) { - //FIXME: Write a test for this - pOut.mat[0] = pOut.mat[5] = pOut.mat[10] = pOut.mat[15] = 1.0; - pOut.mat[1] = pOut.mat[2] = pOut.mat[3] = - pOut.mat[4] = pOut.mat[6] = pOut.mat[7] = - pOut.mat[8] = pOut.mat[9] = pOut.mat[11] = 0.0; - pOut.mat[12] = x; - pOut.mat[13] = y; - pOut.mat[14] = z; - return pOut; -}; - -/** - * Get the up vector from a matrix. pIn is the matrix you - * wish to extract the vector from. pOut is a pointer to the - * kmVec3 structure that should hold the resulting vector - */ -cc.kmMat4GetUpVec3 = function (pOut, pIn) { - pOut.x = pIn.mat[4]; - pOut.y = pIn.mat[5]; - pOut.z = pIn.mat[6]; - cc.kmVec3Normalize(pOut, pOut); - return pOut; -}; - -/** Extract the right vector from a 4x4 matrix. The result is - * stored in pOut. Returns pOut. - */ -cc.kmMat4GetRightVec3 = function (pOut, pIn) { - pOut.x = pIn.mat[0]; - pOut.y = pIn.mat[1]; - pOut.z = pIn.mat[2]; - cc.kmVec3Normalize(pOut, pOut); - return pOut; -}; - -/** - * Extract the forward vector from a 4x4 matrix. The result is - * stored in pOut. Returns pOut. - */ -cc.kmMat4GetForwardVec3 = function (pOut, pIn) { - pOut.x = pIn.mat[8]; - pOut.y = pIn.mat[9]; - pOut.z = pIn.mat[10]; - cc.kmVec3Normalize(pOut, pOut); - return pOut; -}; - -/** - * Creates a perspective projection matrix in the - * same way as gluPerspective - */ -cc.kmMat4PerspectiveProjection = function (pOut, fovY, aspect, zNear, zFar) { - var r = cc.kmDegreesToRadians(fovY / 2); - var deltaZ = zFar - zNear; - var s = Math.sin(r); - - if (deltaZ == 0 || s == 0 || aspect == 0) - return null; - - //cos(r) / sin(r) = cot(r) - var cotangent = Math.cos(r) / s; - - cc.kmMat4Identity(pOut); - pOut.mat[0] = cotangent / aspect; - pOut.mat[5] = cotangent; - pOut.mat[10] = -(zFar + zNear) / deltaZ; - pOut.mat[11] = -1; - pOut.mat[14] = -2 * zNear * zFar / deltaZ; - pOut.mat[15] = 0; - - return pOut; -}; - -/** Creates an orthographic projection matrix like glOrtho */ -cc.kmMat4OrthographicProjection = function (pOut, left, right, bottom, top, nearVal, farVal) { - cc.kmMat4Identity(pOut); - pOut.mat[0] = 2 / (right - left); - pOut.mat[5] = 2 / (top - bottom); - pOut.mat[10] = -2 / (farVal - nearVal); - pOut.mat[12] = -((right + left) / (right - left)); - pOut.mat[13] = -((top + bottom) / (top - bottom)); - pOut.mat[14] = -((farVal + nearVal) / (farVal - nearVal)); - return pOut; -}; - -/** - * Builds a translation matrix in the same way as gluLookAt() - * the resulting matrix is stored in pOut. pOut is returned. - */ -cc.kmMat4LookAt = function (pOut, pEye, pCenter, pUp) { - var f = new cc.kmVec3(), up = new cc.kmVec3(), s = new cc.kmVec3(), u = new cc.kmVec3(); - var translate = new cc.kmMat4(); - - cc.kmVec3Subtract(f, pCenter, pEye); - cc.kmVec3Normalize(f, f); - - cc.kmVec3Assign(up, pUp); - cc.kmVec3Normalize(up, up); - - cc.kmVec3Cross(s, f, up); - cc.kmVec3Normalize(s, s); - - cc.kmVec3Cross(u, s, f); - cc.kmVec3Normalize(s, s); - - cc.kmMat4Identity(pOut); + /** + * Builds an X-axis rotation matrix and stores it in matrix, returns matrix, if matrix is null, create a new matrix + * @param {Number} radians + * @param {cc.math.Matrix4} [matrix] + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByRotationX = function(radians, matrix) { //cc.kmMat4RotationX + /* + | 1 0 0 0 | + M = | 0 cos(A) -sin(A) 0 | + | 0 sin(A) cos(A) 0 | + | 0 0 0 1 | + */ + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat; + mat[0] = 1.0; + mat[3] = mat[2] = mat[1] = 0.0; + + mat[4] = 0.0; + mat[5] = Math.cos(radians); + mat[6] = Math.sin(radians); + mat[7] = 0.0; + + mat[8] = 0.0; + mat[9] = -Math.sin(radians); + mat[10] = Math.cos(radians); + mat[11] = 0.0; + + mat[14] = mat[13] = mat[12] = 0.0; + mat[15] = 1.0; + return matrix; + }; + + /** + * Builds a rotation matrix using the rotation around the Y-axis, The result is stored in matrix, matrix is returned. + * @param {Number} radians + * @param {cc.math.Matrix4} [matrix] + * @returns {*} + */ + cc.math.Matrix4.createByRotationY = function(radians, matrix) { // cc.kmMat4RotationY + /* + | cos(A) 0 sin(A) 0 | + M = | 0 1 0 0 | + | -sin(A) 0 cos(A) 0 | + | 0 0 0 1 | + */ + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat; + mat[0] = Math.cos(radians); + mat[1] = 0.0; + mat[2] = -Math.sin(radians); + mat[3] = 0.0; + + mat[7] = mat[6] = mat[4] = 0.0; + mat[5] = 1.0; + + mat[8] = Math.sin(radians); + mat[9] = 0.0; + mat[10] = Math.cos(radians); + mat[11] = 0.0; + + mat[14] = mat[13] = mat[12] = 0.0; + mat[15] = 1.0; + return matrix; + }; + + /** + * Builds a rotation matrix around the Z-axis. The resulting matrix is stored in matrix. matrix is returned. + * @param {Number} radians + * @param {cc.math.Matrix4} matrix + * @return {cc.math.Matrix4} + */ + cc.math.Matrix4.createByRotationZ = function(radians, matrix){ // cc.kmMat4RotationZ + /* + | cos(A) -sin(A) 0 0 | + M = | sin(A) cos(A) 0 0 | + | 0 0 1 0 | + | 0 0 0 1 | + */ + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat; + mat[0] = Math.cos(radians); + mat[1] = Math.sin(radians); + mat[3] = mat[2] = 0.0; + + mat[4] = -Math.sin(radians); + mat[5] = Math.cos(radians); + mat[7] = mat[6] = 0.0; + + mat[11] = mat[9] = mat[8] = 0.0; + mat[10] = 1.0; + + mat[14] = mat[13] = mat[12] = 0.0; + mat[15] = 1.0; + + return matrix; + }; + + /** + * Builds a rotation matrix from pitch, yaw and roll. The resulting matrix is stored in parameter matrix and returns. + * @param {Number} pitch + * @param {Number} yaw + * @param {Number} roll + * @param {cc.math.Matrix4} [matrix] if matrix is undefined, creates a new matrix. + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByPitchYawRoll = function(pitch, yaw, roll, matrix) { + matrix = matrix || new cc.math.Matrix4(); + var cr = Math.cos(pitch), sr = Math.sin(pitch); + var cp = Math.cos(yaw), sp = Math.sin(yaw); + var cy = Math.cos(roll), sy = Math.sin(roll); + var srsp = sr * sp, crsp = cr * sp; + var mat = matrix.mat; + + mat[0] = cp * cy; + mat[4] = cp * sy; + mat[8] = -sp; + + mat[1] = srsp * cy - cr * sy; + mat[5] = srsp * sy + cr * cy; + mat[9] = sr * cp; + + mat[2] = crsp * cy + sr * sy; + mat[6] = crsp * sy - sr * cy; + mat[10] = cr * cp; + + mat[3] = mat[7] = mat[11] = 0.0; + mat[15] = 1.0; + return matrix; + }; + + /** + * Builds a matrix by a quaternion. + * @param {cc.math.Quaternion} quaternion + * @param {cc.math.Matrix4} [matrix] if matrix is undefined, creates a new matrix. + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByQuaternion = function(quaternion, matrix) { + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat; + mat[0] = 1.0 - 2.0 * (quaternion.y * quaternion.y + quaternion.z * quaternion.z ); + mat[1] = 2.0 * (quaternion.x * quaternion.y + quaternion.z * quaternion.w); + mat[2] = 2.0 * (quaternion.x * quaternion.z - quaternion.y * quaternion.w); + mat[3] = 0.0; + + // Second row + mat[4] = 2.0 * ( quaternion.x * quaternion.y - quaternion.z * quaternion.w ); + mat[5] = 1.0 - 2.0 * ( quaternion.x * quaternion.x + quaternion.z * quaternion.z ); + mat[6] = 2.0 * (quaternion.z * quaternion.y + quaternion.x * quaternion.w ); + mat[7] = 0.0; + + // Third row + mat[8] = 2.0 * ( quaternion.x * quaternion.z + quaternion.y * quaternion.w ); + mat[9] = 2.0 * ( quaternion.y * quaternion.z - quaternion.x * quaternion.w ); + mat[10] = 1.0 - 2.0 * ( quaternion.x * quaternion.x + quaternion.y * quaternion.y ); + mat[11] = 0.0; + + // Fourth row + mat[14] = mat[13] = mat[12] = 0; + mat[15] = 1.0; + return matrix; + }; + + /** + * Build a 4x4 OpenGL transformation matrix using a 3x3 rotation matrix, and a 3d vector representing a translation. + * @param {cc.math.Matrix3} rotation + * @param {cc.math.Vec3} translation + * @param {cc.math.Matrix4} [matrix] if matrix is undefined, creates a new matrix. + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByRotationTranslation = function(rotation, translation, matrix) { + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat, rMat = rotation.mat; + mat[0] = rMat[0]; + mat[1] = rMat[1]; + mat[2] = rMat[2]; + mat[3] = 0.0; + + mat[4] = rMat[3]; + mat[5] = rMat[4]; + mat[6] = rMat[5]; + mat[7] = 0.0; + + mat[8] = rMat[6]; + mat[9] = rMat[7]; + mat[10] = rMat[8]; + mat[11] = 0.0; + + mat[12] = translation.x; + mat[13] = translation.y; + mat[14] = translation.z; + mat[15] = 1.0; + return matrix; + }; + + /** + * Builds a scaling matrix + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @param {cc.math.Matrix4} [matrix] if matrix is undefined, creates a new matrix. + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByScale = function(x, y, z, matrix) { //cc.kmMat4Scaling + matrix = matrix || new cc.math.Matrix4(); + var mat = matrix.mat; + mat[0] = x; + mat[5] = y; + mat[10] = z; + mat[15] = 1.0; + mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] = + mat[8] = mat[9] = mat[11] = mat[12] = mat[13] = mat[14] = 0; + return matrix; + }; + + /** + * Builds a translation matrix. All other elements in the matrix + * will be set to zero except for the diagonal which is set to 1.0 + */ + cc.kmMat4Translation = function (pOut, x, y, z) { + //FIXME: Write a test for this + pOut.mat[0] = pOut.mat[5] = pOut.mat[10] = pOut.mat[15] = 1.0; + pOut.mat[1] = pOut.mat[2] = pOut.mat[3] = + pOut.mat[4] = pOut.mat[6] = pOut.mat[7] = + pOut.mat[8] = pOut.mat[9] = pOut.mat[11] = 0.0; + pOut.mat[12] = x; + pOut.mat[13] = y; + pOut.mat[14] = z; + return pOut; + }; + + /** + * Builds a translation matrix. + * @param {Number} x + * @param {Number} y + * @param {Number} z + * @param {cc.math.Matrix4} [matrix] if matrix is undefined, creates a new matrix. + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByTranslation = function(x, y, z, matrix){ //cc.kmMat4Translation + matrix = matrix || new cc.math.Matrix4(); + matrix.identity(); + matrix.mat[12] = x; + matrix.mat[13] = y; + matrix.mat[14] = z; + return matrix; + }; + + /** + * Get the up vector from a matrix. + * @returns {cc.math.Vec3} + */ + proto.getUpVec3 = function() { + var mat = this.mat; + var ret = new cc.math.Vec3(mat[4],mat[5], mat[6]); + return ret.normalize(); + }; + + /** + * Extract the right vector from a 4x4 matrix. + * @returns {cc.math.Vec3} + */ + proto.getRightVec3 = function(){ + var mat = this.mat; + var ret = new cc.math.Vec3(mat[0],mat[1], mat[2]); + return ret.normalize(); + }; + + /** + * Extract the forward vector from a 4x4 matrix. + * @returns {cc.math.Vec3} + */ + proto.getForwardVec3 = function() { + var mat = this.mat; + var ret = new cc.math.Vec3(mat[8],mat[9], mat[10]); + return ret.normalize(); + }; + + /** + * Creates a perspective projection matrix in the + * same way as gluPerspective + */ + cc.kmMat4PerspectiveProjection = function (pOut, fovY, aspect, zNear, zFar) { + var r = cc.degreesToRadians(fovY / 2); + var deltaZ = zFar - zNear; + var s = Math.sin(r); + + if (deltaZ === 0 || s === 0 || aspect === 0) + return null; + + //cos(r) / sin(r) = cot(r) + var cotangent = Math.cos(r) / s; + pOut.identity(); + pOut.mat[0] = cotangent / aspect; + pOut.mat[5] = cotangent; + pOut.mat[10] = -(zFar + zNear) / deltaZ; + pOut.mat[11] = -1; + pOut.mat[14] = -2 * zNear * zFar / deltaZ; + pOut.mat[15] = 0; - pOut.mat[0] = s.x; - pOut.mat[4] = s.y; - pOut.mat[8] = s.z; + return pOut; + }; + + /** + * Creates a perspective projection matrix in the same way as gluPerspective + * @param {Number} fovY + * @param {Number} aspect + * @param {Number} zNear + * @param {Number} zFar + * @returns {cc.math.Matrix4|Null} + */ + cc.math.Matrix4.createPerspectiveProjection = function(fovY, aspect, zNear, zFar){ + var r = cc.degreesToRadians(fovY / 2), deltaZ = zFar - zNear; + var s = Math.sin(r); + + if (deltaZ === 0 || s === 0 || aspect === 0) + return null; + + //cos(r) / sin(r) = cot(r) + var cotangent = Math.cos(r) / s; + var matrix = new cc.math.Matrix4(), mat = matrix.mat; + matrix.identity(); + mat[0] = cotangent / aspect; + mat[5] = cotangent; + mat[10] = -(zFar + zNear) / deltaZ; + mat[11] = -1; + mat[14] = -2 * zNear * zFar / deltaZ; + mat[15] = 0; + return matrix; + }; + + /** Creates an orthographic projection matrix like glOrtho */ + cc.kmMat4OrthographicProjection = function (pOut, left, right, bottom, top, nearVal, farVal) { + pOut.identity(); + pOut.mat[0] = 2 / (right - left); + pOut.mat[5] = 2 / (top - bottom); + pOut.mat[10] = -2 / (farVal - nearVal); + pOut.mat[12] = -((right + left) / (right - left)); + pOut.mat[13] = -((top + bottom) / (top - bottom)); + pOut.mat[14] = -((farVal + nearVal) / (farVal - nearVal)); + return pOut; + }; + + /** + * Creates an orthographic projection matrix like glOrtho + * @param {Number} left + * @param {Number} right + * @param {Number} bottom + * @param {Number} top + * @param {Number} nearVal + * @param {Number} farVal + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createOrthographicProjection = function (left, right, bottom, top, nearVal, farVal) { + var matrix = new cc.math.Matrix4(), mat = matrix.mat; + matrix.identity(); + mat[0] = 2 / (right - left); + mat[5] = 2 / (top - bottom); + mat[10] = -2 / (farVal - nearVal); + mat[12] = -((right + left) / (right - left)); + mat[13] = -((top + bottom) / (top - bottom)); + mat[14] = -((farVal + nearVal) / (farVal - nearVal)); + return matrix; + }; + + /** + * Builds a translation matrix in the same way as gluLookAt() + * the resulting matrix is stored in pOut. pOut is returned. + */ + cc.kmMat4LookAt = function (pOut, pEye, pCenter, pUp) { + var f = new cc.math.Vec3(pCenter), up = new cc.math.Vec3(pUp); + f.subtract(pEye); + f.normalize(); + up.normalize(); - pOut.mat[1] = u.x; - pOut.mat[5] = u.y; - pOut.mat[9] = u.z; + var s = new cc.math.Vec3(f); + s.cross(up); + s.normalize(); - pOut.mat[2] = -f.x; - pOut.mat[6] = -f.y; - pOut.mat[10] = -f.z; + var u = new cc.math.Vec3(s); + u.cross(f); + s.normalize(); - cc.kmMat4Translation(translate, -pEye.x, -pEye.y, -pEye.z); - cc.kmMat4Multiply(pOut, pOut, translate); + pOut.identity(); - return pOut; -}; + pOut.mat[0] = s.x; + pOut.mat[4] = s.y; + pOut.mat[8] = s.z; -/** - * Build a rotation matrix from an axis and an angle. Result is stored in pOut. - * pOut is returned. - */ -cc.kmMat4RotationAxisAngle = function (pOut, axis, radians) { - var rcos = Math.cos(radians); - var rsin = Math.sin(radians); + pOut.mat[1] = u.x; + pOut.mat[5] = u.y; + pOut.mat[9] = u.z; - var normalizedAxis = new cc.kmVec3(); - cc.kmVec3Normalize(normalizedAxis, axis); + pOut.mat[2] = -f.x; + pOut.mat[6] = -f.y; + pOut.mat[10] = -f.z; - pOut.mat[0] = rcos + normalizedAxis.x * normalizedAxis.x * (1 - rcos); - pOut.mat[1] = normalizedAxis.z * rsin + normalizedAxis.y * normalizedAxis.x * (1 - rcos); - pOut.mat[2] = -normalizedAxis.y * rsin + normalizedAxis.z * normalizedAxis.x * (1 - rcos); - pOut.mat[3] = 0.0; + var translate = cc.math.Matrix4.createByTranslation(-pEye.x, -pEye.y, -pEye.z); + pOut.multiply(translate); + return pOut; + }; + + var tempMatrix = new cc.math.Matrix4(); // an internal matrix + proto.lookAt = function(eyeVec, centerVec, upVec) { + var f = new cc.math.Vec3(centerVec), up = new cc.math.Vec3(upVec), mat = this.mat; + f.subtract(eyeVec); + f.normalize(); + up.normalize(); + + var s = new cc.math.Vec3(f); + s.cross(up); + s.normalize(); + + var u = new cc.math.Vec3(s); + u.cross(f); + s.normalize(); + + this.identity(); + mat[0] = s.x; + mat[4] = s.y; + mat[8] = s.z; + + mat[1] = u.x; + mat[5] = u.y; + mat[9] = u.z; + + mat[2] = -f.x; + mat[6] = -f.y; + mat[10] = -f.z; + + tempMatrix = cc.math.Matrix4.createByTranslation(-eyeVec.x, -eyeVec.y, -eyeVec.z, tempMatrix); + this.multiply(tempMatrix); + return this; + }; + + /** + * Build a rotation matrix from an axis and an angle. Result is stored in pOut. + * pOut is returned. + */ + cc.kmMat4RotationAxisAngle = function (pOut, axis, radians) { + var rcos = Math.cos(radians), rsin = Math.sin(radians); - pOut.mat[4] = -normalizedAxis.z * rsin + normalizedAxis.x * normalizedAxis.y * (1 - rcos); - pOut.mat[5] = rcos + normalizedAxis.y * normalizedAxis.y * (1 - rcos); - pOut.mat[6] = normalizedAxis.x * rsin + normalizedAxis.z * normalizedAxis.y * (1 - rcos); - pOut.mat[7] = 0.0; + var normalizedAxis = new cc.math.Vec3(axis); + normalizedAxis.normalize(); - pOut.mat[8] = normalizedAxis.y * rsin + normalizedAxis.x * normalizedAxis.z * (1 - rcos); - pOut.mat[9] = -normalizedAxis.x * rsin + normalizedAxis.y * normalizedAxis.z * (1 - rcos); - pOut.mat[10] = rcos + normalizedAxis.z * normalizedAxis.z * (1 - rcos); - pOut.mat[11] = 0.0; + pOut.mat[0] = rcos + normalizedAxis.x * normalizedAxis.x * (1 - rcos); + pOut.mat[1] = normalizedAxis.z * rsin + normalizedAxis.y * normalizedAxis.x * (1 - rcos); + pOut.mat[2] = -normalizedAxis.y * rsin + normalizedAxis.z * normalizedAxis.x * (1 - rcos); + pOut.mat[3] = 0.0; - pOut.mat[12] = 0.0; - pOut.mat[13] = 0.0; - pOut.mat[14] = 0.0; - pOut.mat[15] = 1.0; + pOut.mat[4] = -normalizedAxis.z * rsin + normalizedAxis.x * normalizedAxis.y * (1 - rcos); + pOut.mat[5] = rcos + normalizedAxis.y * normalizedAxis.y * (1 - rcos); + pOut.mat[6] = normalizedAxis.x * rsin + normalizedAxis.z * normalizedAxis.y * (1 - rcos); + pOut.mat[7] = 0.0; - return pOut; -}; + pOut.mat[8] = normalizedAxis.y * rsin + normalizedAxis.x * normalizedAxis.z * (1 - rcos); + pOut.mat[9] = -normalizedAxis.x * rsin + normalizedAxis.y * normalizedAxis.z * (1 - rcos); + pOut.mat[10] = rcos + normalizedAxis.z * normalizedAxis.z * (1 - rcos); + pOut.mat[11] = 0.0; -/** - * Extract a 3x3 rotation matrix from the input 4x4 transformation. - * Stores the result in pOut, returns pOut - */ -cc.kmMat4ExtractRotation = function (pOut, pIn) { - pOut.mat[0] = pIn.mat[0]; - pOut.mat[1] = pIn.mat[1]; - pOut.mat[2] = pIn.mat[2]; - - pOut.mat[3] = pIn.mat[4]; - pOut.mat[4] = pIn.mat[5]; - pOut.mat[5] = pIn.mat[6]; - - pOut.mat[6] = pIn.mat[8]; - pOut.mat[7] = pIn.mat[9]; - pOut.mat[8] = pIn.mat[10]; - - return pOut; -}; - -cc.kmMat4ExtractPlane = function (pOut, pIn, plane) { - switch (plane) { - case cc.KM_PLANE_RIGHT: - pOut.a = pIn.mat[3] - pIn.mat[0]; - pOut.b = pIn.mat[7] - pIn.mat[4]; - pOut.c = pIn.mat[11] - pIn.mat[8]; - pOut.d = pIn.mat[15] - pIn.mat[12]; - break; - case cc.KM_PLANE_LEFT: - pOut.a = pIn.mat[3] + pIn.mat[0]; - pOut.b = pIn.mat[7] + pIn.mat[4]; - pOut.c = pIn.mat[11] + pIn.mat[8]; - pOut.d = pIn.mat[15] + pIn.mat[12]; - break; - case cc.KM_PLANE_BOTTOM: - pOut.a = pIn.mat[3] + pIn.mat[1]; - pOut.b = pIn.mat[7] + pIn.mat[5]; - pOut.c = pIn.mat[11] + pIn.mat[9]; - pOut.d = pIn.mat[15] + pIn.mat[13]; - break; - case cc.KM_PLANE_TOP: - pOut.a = pIn.mat[3] - pIn.mat[1]; - pOut.b = pIn.mat[7] - pIn.mat[5]; - pOut.c = pIn.mat[11] - pIn.mat[9]; - pOut.d = pIn.mat[15] - pIn.mat[13]; - break; - case cc.KM_PLANE_FAR: - pOut.a = pIn.mat[3] - pIn.mat[2]; - pOut.b = pIn.mat[7] - pIn.mat[6]; - pOut.c = pIn.mat[11] - pIn.mat[10]; - pOut.d = pIn.mat[15] - pIn.mat[14]; - break; - case cc.KM_PLANE_NEAR: - pOut.a = pIn.mat[3] + pIn.mat[2]; - pOut.b = pIn.mat[7] + pIn.mat[6]; - pOut.c = pIn.mat[11] + pIn.mat[10]; - pOut.d = pIn.mat[15] + pIn.mat[14]; - break; - default: - cc.log("cc.kmMat4ExtractPlane(): Invalid plane index"); - break; - } - - var t = Math.sqrt(pOut.a * pOut.a + - pOut.b * pOut.b + - pOut.c * pOut.c); - pOut.a /= t; - pOut.b /= t; - pOut.c /= t; - pOut.d /= t; - - return pOut; -}; + pOut.mat[12] = 0.0; + pOut.mat[13] = 0.0; + pOut.mat[14] = 0.0; + pOut.mat[15] = 1.0; -/** - * Take the rotation from a 4x4 transformation matrix, and return it as an axis and an angle (in radians) - * returns the output axis. - */ -cc.kmMat4RotationToAxisAngle = function (pAxis, radians, pIn) { - /*Surely not this easy?*/ - var temp = new cc.kmQuaternion(); - var rotation = new cc.kmMat3(); - cc.kmMat4ExtractRotation(rotation, pIn); - cc.kmQuaternionRotationMatrix(temp, rotation); - cc.kmQuaternionToAxisAngle(temp, pAxis, radians); - return pAxis; -}; + return pOut; + }; + + /** + * Build a rotation matrix from an axis and an angle. + * @param {cc.math.Vec3} axis + * @param {Number} radians + * @param {cc.math.Matrix4} [matrix] + * @returns {cc.math.Matrix4} + */ + cc.math.Matrix4.createByAxisAndAngle = function(axis, radians, matrix) { + matrix = matrix || new cc.math.Matrix4(); + var mat = this.mat, rcos = Math.cos(radians), rsin = Math.sin(radians) ; + + var normalizedAxis = new cc.math.Vec3(axis); + normalizedAxis.normalize(); + + mat[0] = rcos + normalizedAxis.x * normalizedAxis.x * (1 - rcos); + mat[1] = normalizedAxis.z * rsin + normalizedAxis.y * normalizedAxis.x * (1 - rcos); + mat[2] = -normalizedAxis.y * rsin + normalizedAxis.z * normalizedAxis.x * (1 - rcos); + mat[3] = 0.0; + + mat[4] = -normalizedAxis.z * rsin + normalizedAxis.x * normalizedAxis.y * (1 - rcos); + mat[5] = rcos + normalizedAxis.y * normalizedAxis.y * (1 - rcos); + mat[6] = normalizedAxis.x * rsin + normalizedAxis.z * normalizedAxis.y * (1 - rcos); + mat[7] = 0.0; + + mat[8] = normalizedAxis.y * rsin + normalizedAxis.x * normalizedAxis.z * (1 - rcos); + mat[9] = -normalizedAxis.x * rsin + normalizedAxis.y * normalizedAxis.z * (1 - rcos); + mat[10] = rcos + normalizedAxis.z * normalizedAxis.z * (1 - rcos); + mat[11] = 0.0; + + mat[12] = mat[13] = mat[14] = 0.0; + mat[15] = 1.0; + return matrix; + }; + + /** + * Extract a 3x3 rotation matrix from the input 4x4 transformation. + * @returns {cc.math.Matrix3} + */ + proto.extractRotation = function(){ + var matrix = new cc.math.Matrix3(), mat4 = this.mat, mat3 = matrix.mat; + mat3[0] = mat4[0]; + mat3[1] = mat4[1]; + mat3[2] = mat4[2]; + + mat3[3] = mat4[4]; + mat3[4] = mat4[5]; + mat3[5] = mat4[6]; + + mat3[6] = mat4[8]; + mat3[7] = mat4[9]; + mat3[8] = mat4[10]; + return matrix; + }; + + proto.extractPlane = function(planeType) { + var plane = new cc.math.Plane(), mat = this.mat; + switch (planeType) { + case cc.math.Plane.RIGHT: + plane.a = mat[3] - mat[0]; + plane.b = mat[7] - mat[4]; + plane.c = mat[11] - mat[8]; + plane.d = mat[15] - mat[12]; + break; + case cc.math.Plane.LEFT: + plane.a = mat[3] + mat[0]; + plane.b = mat[7] + mat[4]; + plane.c = mat[11] + mat[8]; + plane.d = mat[15] + mat[12]; + break; + case cc.math.Plane.BOTTOM: + plane.a = mat[3] + mat[1]; + plane.b = mat[7] + mat[5]; + plane.c = mat[11] + mat[9]; + plane.d = mat[15] + mat[13]; + break; + case cc.math.Plane.TOP: + plane.a = mat[3] - mat[1]; + plane.b = mat[7] - mat[5]; + plane.c = mat[11] - mat[9]; + plane.d = mat[15] - mat[13]; + break; + case cc.math.Plane.FAR: + plane.a = mat[3] - mat[2]; + plane.b = mat[7] - mat[6]; + plane.c = mat[11] - mat[10]; + plane.d = mat[15] - mat[14]; + break; + case cc.math.Plane.NEAR: + plane.a = mat[3] + mat[2]; + plane.b = mat[7] + mat[6]; + plane.c = mat[11] + mat[10]; + plane.d = mat[15] + mat[14]; + break; + default: + cc.log("cc.math.Matrix4.extractPlane: Invalid plane index"); + break; + } + var t = Math.sqrt(plane.a * plane.a + plane.b * plane.b + plane.c * plane.c); + plane.a /= t; + plane.b /= t; + plane.c /= t; + plane.d /= t; + return plane; + }; + + /** + * Take the rotation from a 4x4 transformation matrix, and return it as an axis and an angle (in radians) + * @returns {*|{axis: cc.math.Vec3, angle: number}} + */ + proto.toAxisAndAngle = function() { + /*Surely not this easy?*/ + var rotation = this.extractRotation(); + var temp = cc.math.Quaternion.rotationMatrix(rotation); + return temp.toAxisAndAngle(); + }; +})(cc); diff --git a/cocos2d/kazmath/plane.js b/cocos2d/kazmath/plane.js index 5470415f1a..94ab4e9b71 100644 --- a/cocos2d/kazmath/plane.js +++ b/cocos2d/kazmath/plane.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -27,156 +29,109 @@ /** * @ignore */ -cc.KM_PLANE_LEFT = 0; +(function(cc){ + cc.math.Plane = function (a, b, c, d) { + if (a && b === undefined) { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + } else { + this.a = a || 0; + this.b = b || 0; + this.c = c || 0; + this.d = d || 0; + } + }; + cc.kmPlane = cc.math.Plane; + var proto = cc.math.Plane.prototype; + + cc.math.Plane.LEFT = 0; + + cc.math.Plane.RIGHT = 1; + + cc.math.Plane.BOTTOM = 2; + + cc.math.Plane.TOP = 3; + + cc.math.Plane.NEAR = 4; + + cc.math.Plane.FAR = 5; + + cc.math.Plane.POINT_INFRONT_OF_PLANE = 0; + + cc.math.Plane.POINT_BEHIND_PLANE = 1; + + cc.math.Plane.POINT_ON_PLANE = 2; + + proto.dot = function(vec4){ //cc.kmPlaneDot + return (this.a * vec4.x + this.b * vec4.y + this.c * vec4.z + this.d * vec4.w); + }; + + proto.dotCoord = function(vec3) { //=cc.kmPlaneDotCoord + return (this.a * vec3.x + this.b * vec3.y + this.c * vec3.z + this.d); + }; + + proto.dotNormal = function(vec3) { //=cc.kmPlaneDotNormal + return (this.a * vec3.x + this.b * vec3.y + this.c * vec3.z); + }; + + cc.math.Plane.fromPointNormal = function(vec3, normal) { //cc.kmPlaneFromPointNormal + /* + Planea = Nx + Planeb = Ny + Planec = Nz + Planed = −N⋅P + */ + return new cc.math.Plane(normal.x, normal.y, normal.z, -normal.dot(vec3)); + }; + + cc.math.Plane.fromPoints = function(vec1, vec2, vec3) { //cc.kmPlaneFromPoints + /* + v = (B − A) × (C − A) + n = 1⁄|v| v + Outa = nx + Outb = ny + Outc = nz + Outd = −n⋅A + */ + var v1 = new cc.math.Vec3(vec2), v2 = new cc.math.Vec3(vec3), plane = new cc.math.Plane(); + v1.subtract(vec1); //Create the vectors for the 2 sides of the triangle + v2.subtract(vec1); + v1.cross(v2); // Use the cross product to get the normal + v1.normalize(); //Normalize it and assign to pOut.m_N + + plane.a = v1.x; + plane.b = v1.y; + plane.c = v1.z; + plane.d = v1.scale(-1.0).dot(vec1); + return plane; + }; + + proto.normalize = function(){ //cc.kmPlaneNormalize + var n = new cc.math.Vec3(this.a, this.b, this.c), l = 1.0 / n.length(); //Get 1/length + n.normalize(); //Normalize the vector and assign to pOut + this.a = n.x; + this.b = n.y; + this.c = n.z; + this.d = this.d * l; //Scale the D value and assign to pOut + return this; + }; + + proto.classifyPoint = function(vec3) { + // This function will determine if a point is on, in front of, or behind + // the plane. First we store the dot product of the plane and the point. + var distance = this.a * vec3.x + this.b * vec3.y + this.c * vec3.z + this.d; + + // Simply put if the dot product is greater than 0 then it is infront of it. + // If it is less than 0 then it is behind it. And if it is 0 then it is on it. + if(distance > 0.001) + return cc.math.Plane.POINT_INFRONT_OF_PLANE; + if(distance < -0.001) + return cc.math.Plane.POINT_BEHIND_PLANE; + return cc.math.Plane.POINT_ON_PLANE; + }; +})(cc); -cc.KM_PLANE_RIGHT = 1; - -cc.KM_PLANE_BOTTOM = 2; - -cc.KM_PLANE_TOP = 3; - -cc.KM_PLANE_NEAR = 4; - -cc.KM_PLANE_FAR = 5; - -cc.kmPlane = function (a, b, c, d) { - this.a = a || 0; - this.b = b || 0; - this.c = c || 0; - this.d = d || 0; -}; - -cc.POINT_INFRONT_OF_PLANE = 0; - -cc.POINT_BEHIND_PLANE = 1; - -cc.POINT_ON_PLANE = 2; - -cc.kmPlaneDot = function(pP, pV){ - //a*x + b*y + c*z + d*w - return (pP.a * pV.x + - pP.b * pV.y + - pP.c * pV.z + - pP.d * pV.w); -}; - -cc.kmPlaneDotCoord = function(pP, pV){ - return (pP.a * pV.x + - pP.b * pV.y + - pP.c * pV.z + pP.d); -}; - -cc.kmPlaneDotNormal = function(pP, pV){ - return (pP.a * pV.x + - pP.b * pV.y + - pP.c * pV.z); -}; - -cc.kmPlaneFromPointNormal = function(pOut, pPoint, pNormal){ - /* - Planea = Nx - Planeb = Ny - Planec = Nz - Planed = −N⋅P - */ - pOut.a = pNormal.x; - pOut.b = pNormal.y; - pOut.c = pNormal.z; - pOut.d = -cc.kmVec3Dot(pNormal, pPoint); - - return pOut; -}; - -/** - * Creates a plane from 3 points. The result is stored in pOut. - * pOut is returned. - */ -cc.kmPlaneFromPoints = function(pOut, p1, p2, p3){ - /* - v = (B − A) × (C − A) - n = 1⁄|v| v - Outa = nx - Outb = ny - Outc = nz - Outd = −n⋅A - */ - - var n = new cc.kmVec3(), v1 = new cc.kmVec3(), v2 = new cc.kmVec3(); - cc.kmVec3Subtract(v1, p2, p1); //Create the vectors for the 2 sides of the triangle - cc.kmVec3Subtract(v2, p3, p1); - cc.kmVec3Cross(n, v1, v2); //Use the cross product to get the normal - - cc.kmVec3Normalize(n, n); //Normalize it and assign to pOut.m_N - - pOut.a = n.x; - pOut.b = n.y; - pOut.c = n.z; - pOut.d = cc.kmVec3Dot(cc.kmVec3Scale(n, n, -1.0), p1); - - return pOut; -}; - -cc.kmPlaneIntersectLine = function(pOut, pP, pV1, pV2){ - throw "cc.kmPlaneIntersectLine() hasn't been implemented."; - /* - n = (Planea, Planeb, Planec) - d = V − U - Out = U − d⋅(Pd + n⋅U)⁄(d⋅n) [iff d⋅n ≠ 0] - */ - //var d = new cc.kmVec3(); - - //cc.kmVec3Subtract(d, pV2, pV1); //Get the direction vector - - //TODO: Continue here! - /*if (fabs(kmVec3Dot(&pP.m_N, &d)) > kmEpsilon) - { - //If we get here then the plane and line are parallel (i.e. no intersection) - pOut = nullptr; //Set to nullptr - - return pOut; - } */ - - //return null; -}; - -cc.kmPlaneNormalize = function(pOut, pP){ - var n = new cc.kmVec3(); - - n.x = pP.a; - n.y = pP.b; - n.z = pP.c; - - var l = 1.0 / cc.kmVec3Length(n); //Get 1/length - cc.kmVec3Normalize(n, n); //Normalize the vector and assign to pOut - - pOut.a = n.x; - pOut.b = n.y; - pOut.c = n.z; - - pOut.d = pP.d * l; //Scale the D value and assign to pOut - - return pOut; -}; - -cc.kmPlaneScale = function(pOut, pP, s){ - cc.log("cc.kmPlaneScale() has not been implemented."); -}; - -/** - * Returns POINT_INFRONT_OF_PLANE if pP is infront of pIn. Returns - * POINT_BEHIND_PLANE if it is behind. Returns POINT_ON_PLANE otherwise - */ -cc.kmPlaneClassifyPoint = function(pIn, pP){ - // This function will determine if a point is on, in front of, or behind - // the plane. First we store the dot product of the plane and the point. - var distance = pIn.a * pP.x + pIn.b * pP.y + pIn.c * pP.z + pIn.d; - - // Simply put if the dot product is greater than 0 then it is infront of it. - // If it is less than 0 then it is behind it. And if it is 0 then it is on it. - if(distance > 0.001) return cc.POINT_INFRONT_OF_PLANE; - if(distance < -0.001) return cc.POINT_BEHIND_PLANE; - - return cc.POINT_ON_PLANE; -}; diff --git a/cocos2d/kazmath/quaternion.js b/cocos2d/kazmath/quaternion.js index 54e1de8e17..ac926ebec2 100644 --- a/cocos2d/kazmath/quaternion.js +++ b/cocos2d/kazmath/quaternion.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,463 +26,425 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - * The Quaternion class - * @param {Number} x - * @param {Number} y - * @param {Number} z - * @param {Number} w - * @constructor - */ -cc.kmQuaternion = function (x, y, z, w) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w || 0; -}; - -///< Returns pOut, sets pOut to the conjugate of pIn -cc.kmQuaternionConjugate = function (pOut, pIn) { - pOut.x = -pIn.x; - pOut.y = -pIn.y; - pOut.z = -pIn.z; - pOut.w = pIn.w; - - return pOut; -}; - -///< Returns the dot product of the 2 quaternions -cc.kmQuaternionDot = function (q1, q2) { - // A dot B = B dot A = AtBt + AxBx + AyBy + AzBz - return (q1.w * q2.w + - q1.x * q2.x + - q1.y * q2.y + - q1.z * q2.z); -}; - -///< Returns the exponential of the quaternion -cc.kmQuaternionExp = function (pOut, pIn) { - //TODO not implement - //cc.assert(0); - return pOut; -}; - -///< Makes the passed quaternion an identity quaternion -cc.kmQuaternionIdentity = function (pOut) { - pOut.x = 0.0; - pOut.y = 0.0; - pOut.z = 0.0; - pOut.w = 1.0; - - return pOut; -}; - -///< Returns the inverse of the passed Quaternion -cc.kmQuaternionInverse = function (pOut, pIn) { - var l = cc.kmQuaternionLength(pIn); - var tmp = new cc.kmQuaternion(); - - if (Math.abs(l) > cc.kmEpsilon) { - pOut.x = 0.0; - pOut.y = 0.0; - pOut.z = 0.0; - pOut.w = 0.0; - return pOut; - } - - ///Get the conjugute and divide by the length - cc.kmQuaternionScale(pOut, - cc.kmQuaternionConjugate(tmp, pIn), 1.0 / l); - - return pOut; -}; - -///< Returns true if the quaternion is an identity quaternion -cc.kmQuaternionIsIdentity = function (pIn) { - return (pIn.x == 0.0 && pIn.y == 0.0 && pIn.z == 0.0 && - pIn.w == 1.0); -}; - -///< Returns the length of the quaternion -cc.kmQuaternionLength = function (pIn) { - return Math.sqrt(cc.kmQuaternionLengthSq(pIn)); -}; - -///< Returns the length of the quaternion squared (prevents a sqrt) -cc.kmQuaternionLengthSq = function (pIn) { - return pIn.x * pIn.x + pIn.y * pIn.y + - pIn.z * pIn.z + pIn.w * pIn.w; -}; - -///< Returns the natural logarithm -cc.kmQuaternionLn = function (pOut, pIn) { - /* - A unit quaternion, is defined by: - Q == (cos(theta), sin(theta) * v) where |v| = 1 - The natural logarithm of Q is, ln(Q) = (0, theta * v) +(function(cc) { + /** + * The Quaternion class + * @param {Number|cc.math.Quaternion} [x=0] + * @param {Number} [y=0] + * @param {Number} [z=0] + * @param {Number} [w=0] + * @constructor */ - //assert(0); - //TODO not implement - return pOut; -}; - -///< Multiplies 2 quaternions together -cc.kmQuaternionMultiply = function (pOut, q1, q2) { - pOut.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; - pOut.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y; - pOut.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z; - pOut.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x; - - return pOut; -}; - -///< Normalizes a quaternion -cc.kmQuaternionNormalize = function (pOut, pIn) { - var length = cc.kmQuaternionLength(pIn); - if(Math.abs(length) <= cc.kmEpsilon) - throw "cc.kmQuaternionNormalize(): pIn is an invalid value"; - cc.kmQuaternionScale(pOut, pIn, 1.0 / length); - - return pOut; -}; - -///< Rotates a quaternion around an axis -cc.kmQuaternionRotationAxis = function (pOut, pV, angle) { - var rad = angle * 0.5; - var scale = Math.sin(rad); - - pOut.w = Math.cos(rad); - pOut.x = pV.x * scale; - pOut.y = pV.y * scale; - pOut.z = pV.z * scale; - - return pOut; -}; - -///< Creates a quaternion from a rotation matrix -cc.kmQuaternionRotationMatrix = function (pOut, pIn) { - /* - Note: The OpenGL matrices are transposed from the description below - taken from the Matrix and Quaternion FAQ - - if ( mat[0] > mat[5] && mat[0] > mat[10] ) { // Column 0: - S = sqrt( 1.0 + mat[0] - mat[5] - mat[10] ) * 2; - X = 0.25 * S; - Y = (mat[4] + mat[1] ) / S; - Z = (mat[2] + mat[8] ) / S; - W = (mat[9] - mat[6] ) / S; - } else if ( mat[5] > mat[10] ) { // Column 1: - S = sqrt( 1.0 + mat[5] - mat[0] - mat[10] ) * 2; - X = (mat[4] + mat[1] ) / S; - Y = 0.25 * S; - Z = (mat[9] + mat[6] ) / S; - W = (mat[2] - mat[8] ) / S; - } else { // Column 2: - S = sqrt( 1.0 + mat[10] - mat[0] - mat[5] ) * 2; - X = (mat[2] + mat[8] ) / S; - Y = (mat[9] + mat[6] ) / S; - Z = 0.25 * S; - W = (mat[4] - mat[1] ) / S; - } - */ - var x, y, z, w; - var m4x4 = []; - var scale = 0.0; - var diagonal = 0.0; - - if (!pIn) { - return null; - } - - /* 0 3 6 - 1 4 7 - 2 5 8 - - 0 1 2 3 - 4 5 6 7 - 8 9 10 11 - 12 13 14 15*/ - - m4x4[0] = pIn.mat[0]; - m4x4[1] = pIn.mat[3]; - m4x4[2] = pIn.mat[6]; - m4x4[4] = pIn.mat[1]; - m4x4[5] = pIn.mat[4]; - m4x4[6] = pIn.mat[7]; - m4x4[8] = pIn.mat[2]; - m4x4[9] = pIn.mat[5]; - m4x4[10] = pIn.mat[8]; - m4x4[15] = 1; - var pMatrix = m4x4[0]; - - diagonal = pMatrix[0] + pMatrix[5] + pMatrix[10] + 1; - - if (diagonal > cc.kmEpsilon) { - // Calculate the scale of the diagonal - scale = Math.sqrt(diagonal) * 2; - - // Calculate the x, y, x and w of the quaternion through the respective equation - x = ( pMatrix[9] - pMatrix[6] ) / scale; - y = ( pMatrix[2] - pMatrix[8] ) / scale; - z = ( pMatrix[4] - pMatrix[1] ) / scale; - w = 0.25 * scale; - } else { - // If the first element of the diagonal is the greatest value - if (pMatrix[0] > pMatrix[5] && pMatrix[0] > pMatrix[10]) { - // Find the scale according to the first element, and double that value - scale = Math.sqrt(1.0 + pMatrix[0] - pMatrix[5] - pMatrix[10]) * 2.0; - - // Calculate the x, y, x and w of the quaternion through the respective equation - x = 0.25 * scale; - y = (pMatrix[4] + pMatrix[1] ) / scale; - z = (pMatrix[2] + pMatrix[8] ) / scale; - w = (pMatrix[9] - pMatrix[6] ) / scale; - } - // Else if the second element of the diagonal is the greatest value - else if (pMatrix[5] > pMatrix[10]) { - // Find the scale according to the second element, and double that value - scale = Math.sqrt(1.0 + pMatrix[5] - pMatrix[0] - pMatrix[10]) * 2.0; - - // Calculate the x, y, x and w of the quaternion through the respective equation - x = (pMatrix[4] + pMatrix[1] ) / scale; - y = 0.25 * scale; - z = (pMatrix[9] + pMatrix[6] ) / scale; - w = (pMatrix[2] - pMatrix[8] ) / scale; + cc.math.Quaternion = function (x, y, z, w) { + if (x && y === undefined) { + this.x = x.x; + this.y = x.y; + this.z = x.z; + this.w = x.w; } else { - // Else the third element of the diagonal is the greatest value - - // Find the scale according to the third element, and double that value - scale = Math.sqrt(1.0 + pMatrix[10] - pMatrix[0] - pMatrix[5]) * 2.0; - - // Calculate the x, y, x and w of the quaternion through the respective equation - x = (pMatrix[2] + pMatrix[8] ) / scale; - y = (pMatrix[9] + pMatrix[6] ) / scale; - z = 0.25 * scale; - w = (pMatrix[4] - pMatrix[1] ) / scale; + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = w || 0; } - } - - pOut.x = x; - pOut.y = y; - pOut.z = z; - pOut.w = w; - - return pOut; -}; - -///< Create a quaternion from yaw, pitch and roll -cc.kmQuaternionRotationYawPitchRoll = function (pOut, yaw, pitch, roll) { - var ex, ey, ez; // temp half euler angles - var cr, cp, cy, sr, sp, sy, cpcy, spsy; // temp vars in roll,pitch yaw - - ex = cc.kmDegreesToRadians(pitch) / 2.0; // convert to rads and half them - ey = cc.kmDegreesToRadians(yaw) / 2.0; - ez = cc.kmDegreesToRadians(roll) / 2.0; + }; + cc.kmQuaternion = cc.math.Quaternion; + var proto = cc.math.Quaternion.prototype; - cr = Math.cos(ex); - cp = Math.cos(ey); - cy = Math.cos(ez); - - sr = Math.sin(ex); - sp = Math.sin(ey); - sy = Math.sin(ez); - - cpcy = cp * cy; - spsy = sp * sy; - - pOut.w = cr * cpcy + sr * spsy; - - pOut.x = sr * cpcy - cr * spsy; - pOut.y = cr * sp * cy + sr * cp * sy; - pOut.z = cr * cp * sy - sr * sp * cy; - - cc.kmQuaternionNormalize(pOut, pOut); - - return pOut; -}; - -///< Interpolate between 2 quaternions -cc.kmQuaternionSlerp = function (pOut, q1, q2, t) { - /*float CosTheta = Q0.DotProd(Q1); - float Theta = acosf(CosTheta); - float SinTheta = sqrtf(1.0f-CosTheta*CosTheta); - - float Sin_T_Theta = sinf(T*Theta)/SinTheta; - float Sin_OneMinusT_Theta = sinf((1.0f-T)*Theta)/SinTheta; - - Quaternion Result = Q0*Sin_OneMinusT_Theta; - Result += (Q1*Sin_T_Theta); - - return Result;*/ - - if (q1.x == q2.x && - q1.y == q2.y && - q1.z == q2.z && - q1.w == q2.w) { - - pOut.x = q1.x; - pOut.y = q1.y; - pOut.z = q1.z; - pOut.w = q1.w; - - return pOut; - } - - var ct = cc.kmQuaternionDot(q1, q2); - var theta = Math.acos(ct); - var st = Math.sqrt(1.0 - cc.kmSQR(ct)); - - var stt = Math.sin(t * theta) / st; - var somt = Math.sin((1.0 - t) * theta) / st; - - var temp = new cc.kmQuaternion(), temp2 = new cc.kmQuaternion(); - cc.kmQuaternionScale(temp, q1, somt); - cc.kmQuaternionScale(temp2, q2, stt); - cc.kmQuaternionAdd(pOut, temp, temp2); - - return pOut; -}; - -///< Get the axis and angle of rotation from a quaternion -cc.kmQuaternionToAxisAngle = function (pIn, pAxis, pAngle) { - var tempAngle; // temp angle - var scale; // temp vars - - tempAngle = Math.acos(pIn.w); - scale = Math.sqrt(cc.kmSQR(pIn.x) + cc.kmSQR(pIn.y) + cc.kmSQR(pIn.z)); - - if (((scale > -cc.kmEpsilon) && scale < cc.kmEpsilon) - || (scale < 2 * cc.kmPI + cc.kmEpsilon && scale > 2 * cc.kmPI - cc.kmEpsilon)) { // angle is 0 or 360 so just simply set axis to 0,0,1 with angle 0 - pAngle = 0.0; - - pAxis.x = 0.0; - pAxis.y = 0.0; - pAxis.z = 1.0; - } else { - pAngle = tempAngle * 2.0; // angle in radians - - pAxis.x = pIn.x / scale; - pAxis.y = pIn.y / scale; - pAxis.z = pIn.z / scale; - cc.kmVec3Normalize(pAxis, pAxis); - } -}; - -///< Scale a quaternion -cc.kmQuaternionScale = function (pOut, pIn, s) { - pOut.x = pIn.x * s; - pOut.y = pIn.y * s; - pOut.z = pIn.z * s; - pOut.w = pIn.w * s; - - return pOut; -}; - -cc.kmQuaternionAssign = function (pOut, pIn) { - pOut.x = pIn.x; - pOut.y = pIn.y; - pOut.z = pIn.z; - pOut.w = pIn.w; - - return pOut; -}; + /** + * Sets the conjugate of quaternion to self + * @param {cc.math.Quaternion} quaternion + */ + proto.conjugate = function (quaternion) { //= cc.kmQuaternionConjugate + this.x = -quaternion.x; + this.y = -quaternion.y; + this.z = -quaternion.z; + this.w = quaternion.w; + return this; + }; + + /** + * Returns the dot product of the current quaternion and parameter quaternion + * @param quaternion + * @returns {number} + */ + proto.dot = function(quaternion) { // = cc.kmQuaternionDot + // A dot B = B dot A = AtBt + AxBx + AyBy + AzBz + return (this.w * quaternion.w + this.x * quaternion.x + this.y * quaternion.y + this.z * quaternion.z); + }; + + /** + * Returns the exponential of the quaternion, this function doesn't implemented. + * @returns {cc.math.Quaternion} + */ + proto.exponential = function(){ //=cc.kmQuaternionExp + return this; + }; -cc.kmQuaternionAdd = function (pOut, pQ1, pQ2) { - pOut.x = pQ1.x + pQ2.x; - pOut.y = pQ1.y + pQ2.y; - pOut.z = pQ1.z + pQ2.z; - pOut.w = pQ1.w + pQ2.w; - - return pOut; -}; - -/** Adapted from the OGRE engine! - - Gets the shortest arc quaternion to rotate this vector to the destination - vector. - @remarks - If you call this with a dest vector that is close to the inverse - of this vector, we will rotate 180 degrees around the 'fallbackAxis' - (if specified, or a generated axis if not) since in this case - ANY axis of rotation is valid. - */ -cc.kmQuaternionRotationBetweenVec3 = function (pOut, vec1, vec2, fallback) { - var v1 = new cc.kmVec3(), v2 = new cc.kmVec3(); - var a; + /** + * Makes the current quaternion an identity quaternion + */ + proto.identity = function(){ //=cc.kmQuaternionIdentity + this.x = 0.0; + this.y = 0.0; + this.z = 0.0; + this.w = 1.0; + return this; + }; + + /** + * Inverses the value of current Quaternion + */ + proto.inverse = function(){ //=cc.kmQuaternionInverse + var len = this.length(); + if (Math.abs(len) > cc.math.EPSILON) { + this.x = 0.0; + this.y = 0.0; + this.z = 0.0; + this.w = 0.0; + return this; + } - cc.kmVec3Assign(v1, vec1); - cc.kmVec3Assign(v2, vec2); + ///Get the conjugute and divide by the length + this.conjugate(this).scale(1.0 / len); + return this; + }; - cc.kmVec3Normalize(v1, v1); - cc.kmVec3Normalize(v2, v2); + /** + * Returns true if the quaternion is an identity quaternion + * @returns {boolean} + */ + proto.isIdentity = function(){ //=cc.kmQuaternionIsIdentity + return (this.x === 0.0 && this.y === 0.0 && this.z === 0.0 && this.w === 1.0); + }; - a = cc.kmVec3Dot(v1, v2); + /** + * Returns the length of the quaternion + * @returns {number} + */ + proto.length = function() { //=cc.kmQuaternionLength + return Math.sqrt(this.lengthSq()); + }; - if (a >= 1.0) { - cc.kmQuaternionIdentity(pOut); - return pOut; - } + /** + * Returns the length of the quaternion squared (prevents a sqrt) + * @returns {number} + */ + proto.lengthSq = function() { //=cc.kmQuaternionLengthSq + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + }; + + /** + * Uses current quaternion multiplies other quaternion. + * @param {cc.math.Quaternion} quaternion + * @returns {cc.math.Quaternion} + */ + proto.multiply = function(quaternion) { //cc.kmQuaternionMultiply + var x = this.x, y = this.y, z = this.z, w = this.w; + this.w = w * quaternion.w - x * quaternion.x - y * quaternion.y - z * quaternion.z; + this.x = w * quaternion.x + x * quaternion.w + y * quaternion.z - z * quaternion.y; + this.y = w * quaternion.y + y * quaternion.w + z * quaternion.x - x * quaternion.z; + this.z = w * quaternion.z + z * quaternion.w + x * quaternion.y - y * quaternion.x; + return this; + }; + + /** + * Normalizes a quaternion + * @returns {cc.math.Quaternion} + */ + proto.normalize = function(){ //=cc.kmQuaternionNormalize + var length = this.length(); + if (Math.abs(length) <= cc.math.EPSILON) + throw "current quaternion is an invalid value"; + this.scale(1.0 / length); + return this; + }; + + /** + * Rotates a quaternion around an axis and an angle + * @param {cc.math.Vec3} axis + * @param {Number} angle + */ + proto.rotationAxis = function(axis, angle){ //cc.kmQuaternionRotationAxis + var rad = angle * 0.5, scale = Math.sin(rad); + this.w = Math.cos(rad); + this.x = axis.x * scale; + this.y = axis.y * scale; + this.z = axis.z * scale; + return this; + }; + + /** + * Creates a quaternion from a rotation matrix + * @param mat3 + * @returns {*} + */ + cc.math.Quaternion.rotationMatrix = function (mat3) { //cc.kmQuaternionRotationMatrix + if (!mat3) + return null; + + var x, y, z, w; + var m4x4 = [], mat = mat3.mat, scale = 0.0; + + /* 0 3 6 + 1 4 7 + 2 5 8 + + 0 1 2 3 + 4 5 6 7 + 8 9 10 11 + 12 13 14 15*/ + m4x4[0] = mat[0]; + m4x4[1] = mat[3]; + m4x4[2] = mat[6]; + m4x4[4] = mat[1]; + m4x4[5] = mat[4]; + m4x4[6] = mat[7]; + m4x4[8] = mat[2]; + m4x4[9] = mat[5]; + m4x4[10] = mat[8]; + m4x4[15] = 1; + var pMatrix = m4x4[0]; + + var diagonal = pMatrix[0] + pMatrix[5] + pMatrix[10] + 1; + if (diagonal > cc.math.EPSILON) { + // Calculate the scale of the diagonal + scale = Math.sqrt(diagonal) * 2; - if (a < (1e-6 - 1.0)) { - if (Math.abs(cc.kmVec3LengthSq(fallback)) < cc.kmEpsilon) { - cc.kmQuaternionRotationAxis(pOut, fallback, cc.kmPI); + // Calculate the x, y, x and w of the quaternion through the respective equation + x = ( pMatrix[9] - pMatrix[6] ) / scale; + y = ( pMatrix[2] - pMatrix[8] ) / scale; + z = ( pMatrix[4] - pMatrix[1] ) / scale; + w = 0.25 * scale; } else { - var axis = new cc.kmVec3(); - var X = new cc.kmVec3(); - X.x = 1.0; - X.y = 0.0; - X.z = 0.0; - - cc.kmVec3Cross(axis, X, vec1); - - //If axis is zero - if (Math.abs(cc.kmVec3LengthSq(axis)) < cc.kmEpsilon) { - var Y = new cc.kmVec3(); - Y.x = 0.0; - Y.y = 1.0; - Y.z = 0.0; - - cc.kmVec3Cross(axis, Y, vec1); + // If the first element of the diagonal is the greatest value + if (pMatrix[0] > pMatrix[5] && pMatrix[0] > pMatrix[10]) { + // Find the scale according to the first element, and double that value + scale = Math.sqrt(1.0 + pMatrix[0] - pMatrix[5] - pMatrix[10]) * 2.0; + + // Calculate the x, y, x and w of the quaternion through the respective equation + x = 0.25 * scale; + y = (pMatrix[4] + pMatrix[1] ) / scale; + z = (pMatrix[2] + pMatrix[8] ) / scale; + w = (pMatrix[9] - pMatrix[6] ) / scale; + } + // Else if the second element of the diagonal is the greatest value + else if (pMatrix[5] > pMatrix[10]) { + // Find the scale according to the second element, and double that value + scale = Math.sqrt(1.0 + pMatrix[5] - pMatrix[0] - pMatrix[10]) * 2.0; + + // Calculate the x, y, x and w of the quaternion through the respective equation + x = (pMatrix[4] + pMatrix[1] ) / scale; + y = 0.25 * scale; + z = (pMatrix[9] + pMatrix[6] ) / scale; + w = (pMatrix[2] - pMatrix[8] ) / scale; + } else { + // Else the third element of the diagonal is the greatest value + + // Find the scale according to the third element, and double that value + scale = Math.sqrt(1.0 + pMatrix[10] - pMatrix[0] - pMatrix[5]) * 2.0; + + // Calculate the x, y, x and w of the quaternion through the respective equation + x = (pMatrix[2] + pMatrix[8] ) / scale; + y = (pMatrix[9] + pMatrix[6] ) / scale; + z = 0.25 * scale; + w = (pMatrix[4] - pMatrix[1] ) / scale; } - - cc.kmVec3Normalize(axis, axis); - cc.kmQuaternionRotationAxis(pOut, axis, cc.kmPI); } - } else { - var s = Math.sqrt((1 + a) * 2); - var invs = 1 / s; - - var c = new cc.kmVec3(); - cc.kmVec3Cross(c, v1, v2); - - pOut.x = c.x * invs; - pOut.y = c.y * invs; - pOut.z = c.z * invs; - pOut.w = s * 0.5; - - cc.kmQuaternionNormalize(pOut, pOut); - } - return pOut; -}; - -cc.kmQuaternionMultiplyVec3 = function (pOut, q, v) { - var uv = new cc.kmVec3(), uuv = new cc.kmVec3(), qvec = new cc.kmVec3(); - - qvec.x = q.x; - qvec.y = q.y; - qvec.z = q.z; + return new cc.math.Quaternion(x, y, z, w); + }; + + /** + * Create a quaternion from yaw, pitch and roll + * @param yaw + * @param pitch + * @param roll + * @returns {cc.math.Quaternion} + */ + cc.math.Quaternion.rotationYawPitchRoll = function (yaw, pitch, roll) { //cc.kmQuaternionRotationYawPitchRoll + var ex, ey, ez; // temp half euler angles + var cr, cp, cy, sr, sp, sy, cpcy, spsy; // temp vars in roll,pitch yaw + + ex = cc.degreesToRadians(pitch) / 2.0; // convert to rads and half them + ey = cc.degreesToRadians(yaw) / 2.0; + ez = cc.degreesToRadians(roll) / 2.0; + + cr = Math.cos(ex); + cp = Math.cos(ey); + cy = Math.cos(ez); + + sr = Math.sin(ex); + sp = Math.sin(ey); + sy = Math.sin(ez); + + cpcy = cp * cy; + spsy = sp * sy; + + var ret = new cc.math.Quaternion(); + ret.w = cr * cpcy + sr * spsy; + ret.x = sr * cpcy - cr * spsy; + ret.y = cr * sp * cy + sr * cp * sy; + ret.z = cr * cp * sy - sr * sp * cy; + ret.normalize(); + return ret; + }; + + /** + * Interpolate with other quaternions + * @param {cc.math.Quaternion} quaternion + * @param {Number} t + * @returns {cc.math.Quaternion} + */ + proto.slerp = function(quaternion, t) { //=cc.kmQuaternionSlerp + if (this.x === quaternion.x && this.y === quaternion.y && this.z === quaternion.z && this.w === quaternion.w) { + return this; + } + var ct = this.dot(quaternion), theta = Math.acos(ct), st = Math.sqrt(1.0 - cc.math.square(ct)); + var stt = Math.sin(t * theta) / st, somt = Math.sin((1.0 - t) * theta) / st; + var temp2 = new cc.math.Quaternion(quaternion); + this.scale(somt); + temp2.scale(stt); + this.add(temp2); + return this; + }; + + /** + * Get the axis and angle of rotation from a quaternion + * @returns {{axis: cc.math.Vec3, angle: number}} + */ + proto.toAxisAndAngle = function(){ //=cc.kmQuaternionToAxisAngle + var tempAngle; // temp angle + var scale; // temp vars + var retAngle, retAxis = new cc.math.Vec3(); + + tempAngle = Math.acos(this.w); + scale = Math.sqrt(cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z)); + + if (((scale > -cc.math.EPSILON) && scale < cc.math.EPSILON) + || (scale < 2 * Math.PI + cc.math.EPSILON && scale > 2 * Math.PI - cc.math.EPSILON)) { // angle is 0 or 360 so just simply set axis to 0,0,1 with angle 0 + retAngle = 0.0; + retAxis.x = 0.0; + retAxis.y = 0.0; + retAxis.z = 1.0; + } else { + retAngle = tempAngle * 2.0; // angle in radians + retAxis.x = this.x / scale; + retAxis.y = this.y / scale; + retAxis.z = this.z / scale; + retAxis.normalize(); + } + return {axis: retAxis, angle: retAngle}; + }; - cc.kmVec3Cross(uv, qvec, v); - cc.kmVec3Cross(uuv, qvec, uv); + /** + * Scale a quaternion + * @param {Number} scale + */ + proto.scale = function(scale) { //cc.kmQuaternionScale + this.x *= scale; + this.y *= scale; + this.z *= scale; + this.w *= scale; + return this; + }; + + /** + * Assign current quaternion value from a quaternion. + * @param {cc.math.Quaternion} quaternion + * @returns {cc.math.Quaternion} current quaternion + */ + proto.assignFrom = function(quaternion){ //=cc.kmQuaternionAssign + this.x = quaternion.x; + this.y = quaternion.y; + this.z = quaternion.z; + this.w = quaternion.w; + return this; + }; + + /** + * Adds other quaternion + * @param {cc.math.Quaternion} quaternion + * @returns {cc.math.Quaternion} + */ + proto.add = function(quaternion) { //cc.kmQuaternionAdd + this.x += quaternion.x; + this.y += quaternion.y; + this.z += quaternion.z; + this.w += quaternion.w; + return this; + }; + + /** + *

+ * Adapted from the OGRE engine!
+ * Gets the shortest arc quaternion to rotate this vector to the destination vector.
+ * @remarks
+ * If you call this with a destination vector that is close to the inverse
+ * of this vector, we will rotate 180 degrees around the 'fallbackAxis'
+ * (if specified, or a generated axis if not) since in this case ANY axis of rotation is valid. + *

+ * @param {cc.math.Vec3} vec1 + * @param {cc.math.Vec3} vec2 + * @param {cc.math.Vec3} fallback + * @returns {cc.math.Quaternion} + */ + cc.math.Quaternion.rotationBetweenVec3 = function(vec1, vec2, fallback) { //cc.kmQuaternionRotationBetweenVec3 + var v1 = new cc.math.Vec3(vec1), v2 = new cc.math.Vec3(vec2); + v1.normalize(); + v2.normalize(); + var a = v1.dot(v2), quaternion = new cc.math.Quaternion(); + + if (a >= 1.0) { + quaternion.identity(); + return quaternion; + } - cc.kmVec3Scale(uv, uv, (2.0 * q.w)); - cc.kmVec3Scale(uuv, uuv, 2.0); + if (a < (1e-6 - 1.0)) { + if (Math.abs(fallback.lengthSq()) < cc.math.EPSILON) { + quaternion.rotationAxis(fallback, Math.PI); + } else { + var axis = new cc.math.Vec3(1.0, 0.0, 0.0); + axis.cross(vec1); + + //If axis is zero + if (Math.abs(axis.lengthSq()) < cc.math.EPSILON) { + axis.fill(0.0, 1.0, 0.0); + axis.cross(vec1); + } + axis.normalize(); + quaternion.rotationAxis(axis, Math.PI); + } + } else { + var s = Math.sqrt((1 + a) * 2), invs = 1 / s; + v1.cross(v2); + quaternion.x = v1.x * invs; + quaternion.y = v1.y * invs; + quaternion.z = v1.z * invs; + quaternion.w = s * 0.5; + quaternion.normalize(); + } + return quaternion; + }; - cc.kmVec3Add(pOut, v, uv); - cc.kmVec3Add(pOut, pOut, uuv); + /** + * Current quaternion multiplies a vec3 + * @param {cc.math.Vec3} vec + * @returns {cc.math.Vec3} + */ + proto.multiplyVec3 = function(vec){ //=cc.kmQuaternionMultiplyVec3 + var x = this.x, y = this.y, z = this.z, retVec = new cc.math.Vec3(vec); + var uv = new cc.math.Vec3(x, y, z), uuv = new cc.math.Vec3(x, y, z); + uv.cross(vec); + uuv.cross(uv); + uv.scale((2.0 * q.w)); + uuv.scale(2.0); + + retVec.add(uv); + retVec.add(uuv); + return retVec; + }; +})(cc); - return pOut; -}; diff --git a/cocos2d/kazmath/ray2.js b/cocos2d/kazmath/ray2.js index d87f9c342e..5a29794e88 100644 --- a/cocos2d/kazmath/ray2.js +++ b/cocos2d/kazmath/ray2.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,138 +26,115 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.kmRay2 = function(start, dir){ - this.start = start || new cc.kmVec2(); - this.start = start || new cc.kmVec2(); -}; - -cc.kmRay2Fill = function(ray, px, py,vx,vy){ - ray.start.x = px; - ray.start.y = py; - ray.dir.x = vx; - ray.dir.y = vy; -}; - -cc.kmRay2IntersectLineSegment = function(ray, p1, p2, intersection){ - var x1 = ray.start.x; - var y1 = ray.start.y; - var x2 = ray.start.x + ray.dir.x; - var y2 = ray.start.y + ray.dir.y; - var x3 = p1.x; - var y3 = p1.y; - var x4 = p2.x; - var y4 = p2.y; - - var denom = (y4 -y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); - var ua, x, y; - //If denom is zero, the lines are parallel - if(denom > -cc.kmEpsilon && denom < cc.kmEpsilon) { - return cc.KM_FALSE; - } +(function(cc){ + cc.math.Ray2 = function (start, dir) { // = cc.kmRay2 + this.start = start || new cc.math.Vec2(); + this.dir = dir || new cc.math.Vec2(); + }; + + cc.math.Ray2.prototype.fill = function (px, py, vx, vy) { // = cc.kmRay2Fill + this.start.x = px; + this.start.y = py; + this.dir.x = vx; + this.dir.y = vy; + }; + + cc.math.Ray2.prototype.intersectLineSegment = function (p1, p2, intersection) { // = cc.kmRay2IntersectLineSegment + var x1 = this.start.x, y1 = this.start.y; + var x2 = this.start.x + this.dir.x, y2 = this.start.y + this.dir.y; + var x3 = p1.x, y3 = p1.y; + var x4 = p2.x, y4 = p2.y; + + var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + var ua, x, y; + //If denom is zero, the lines are parallel + if (denom > -cc.math.EPSILON && denom < cc.math.EPSILON) + return false; + + ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; + //var ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; + + x = x1 + ua * (x2 - x1); + y = y1 + ua * (y2 - y1); + + if (x < Math.min(p1.x, p2.x) - cc.math.EPSILON || + x > Math.max(p1.x, p2.x) + cc.math.EPSILON || + y < Math.min(p1.y, p2.y) - cc.math.EPSILON || + y > Math.max(p1.y, p2.y) + cc.math.EPSILON) { + //Outside of line + //printf("Outside of line, %f %f (%f %f)(%f, %f)\n", x, y, p1.x, p1.y, p2.x, p2.y); + return false; + } - ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; -// var ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; + if (x < Math.min(x1, x2) - cc.math.EPSILON || + x > Math.max(x1, x2) + cc.math.EPSILON || + y < Math.min(y1, y2) - cc.math.EPSILON || + y > Math.max(y1, y2) + cc.math.EPSILON) { + //printf("Outside of ray, %f %f (%f %f)(%f, %f)\n", x, y, x1, y1, x2, y2); + return false; + } - x = x1 + ua * (x2 - x1); - y = y1 + ua * (y2 - y1); + intersection.x = x; + intersection.y = y; + return true; + }; - if(x < cc.kmMin(p1.x, p2.x) - cc.kmEpsilon || - x > cc.kmMax(p1.x, p2.x) + cc.kmEpsilon || - y < cc.kmMin(p1.y, p2.y) - cc.kmEpsilon || - y > cc.kmMax(p1.y, p2.y) + cc.kmEpsilon) { - //Outside of line - //printf("Outside of line, %f %f (%f %f)(%f, %f)\n", x, y, p1.x, p1.y, p2.x, p2.y); - return cc.KM_FALSE; - } + function calculate_line_normal(p1, p2, normalOut){ + var tmp = new cc.math.Vec2(p2); + tmp.subtract(p1); - if(x < cc.kmMin(x1, x2) - cc.kmEpsilon || - x > cc.kmMax(x1, x2) + cc.kmEpsilon || - y < cc.kmMin(y1, y2) - cc.kmEpsilon || - y > cc.kmMax(y1, y2) + cc.kmEpsilon) { - //printf("Outside of ray, %f %f (%f %f)(%f, %f)\n", x, y, x1, y1, x2, y2); - return cc.KM_FALSE; + normalOut.x = -tmp.y; + normalOut.y = tmp.x; + normalOut.normalize(); + //TODO: should check that the normal is pointing out of the triangle } - intersection.x = x; - intersection.y = y; - - return cc.KM_TRUE; -}; - -cc.calculate_line_normal = function(p1, p2, normal_out){ - var tmp = new cc.kmVec2(); - cc.kmVec2Subtract(tmp, p2, p1); //Get direction vector - - normal_out.x = -tmp.y; - normal_out.y = tmp.x; - cc.kmVec2Normalize(normal_out, normal_out); - - //TODO: should check that the normal is pointing out of the triangle -}; - -cc.kmRay2IntersectTriangle = function(ray, p1, p2, p3, intersection, normal_out){ - var intersect = new cc.kmVec2(); - var final_intersect = new cc.kmVec2(); - var normal = new cc.kmVec2(); - var distance = 10000.0; - var intersected = cc.KM_FALSE; - - var tmp,this_distance; - - if(cc.kmRay2IntersectLineSegment(ray, p1, p2, intersect)) { - tmp = new cc.kmVec2(); - - intersected = cc.KM_TRUE; - this_distance = cc.kmVec2Length(cc.kmVec2Subtract(tmp, intersect, ray.start)); - if(this_distance < distance) { - final_intersect.x = intersect.x; - final_intersect.y = intersect.y; - distance = this_distance; - - cc.calculate_line_normal(p1, p2, normal); + cc.math.Ray2.prototype.intersectTriangle = function(p1, p2, p3, intersection, normal_out){ + var intersect = new cc.math.Vec2(), final_intersect = new cc.math.Vec2(); + var normal = new cc.math.Vec2(), distance = 10000.0, intersected = false; + var this_distance; + + if(this.intersectLineSegment(p1, p2, intersect)) { + intersected = true; + this_distance = intersect.subtract(this.start).length(); + if(this_distance < distance) { + final_intersect.x = intersect.x; + final_intersect.y = intersect.y; + distance = this_distance; + calculate_line_normal(p1, p2, normal); + } } - } - - if(cc.kmRay2IntersectLineSegment(ray, p2, p3, intersect)) { - tmp = new cc.kmVec2(); - intersected = cc.KM_TRUE; - this_distance = cc.kmVec2Length(cc.kmVec2Subtract(tmp, intersect, ray.start)); - if(this_distance < distance) { - final_intersect.x = intersect.x; - final_intersect.y = intersect.y; - distance = this_distance; - - cc.calculate_line_normal(p2, p3, normal); + if(this.intersectLineSegment(p2, p3, intersect)) { + intersected = true; + this_distance = intersect.subtract(this.start).length(); + if(this_distance < distance) { + final_intersect.x = intersect.x; + final_intersect.y = intersect.y; + distance = this_distance; + calculate_line_normal(p2, p3, normal); + } } - } - - if(cc.kmRay2IntersectLineSegment(ray, p3, p1, intersect)) { - tmp = new cc.kmVec2(); - intersected = cc.KM_TRUE; - this_distance = cc.kmVec2Length(cc.kmVec2Subtract(tmp, intersect, ray.start)); - if(this_distance < distance) { - final_intersect.x = intersect.x; - final_intersect.y = intersect.y; - distance = this_distance; - - cc.calculate_line_normal(p3, p1, normal); + if(this.intersectLineSegment(p3, p1, intersect)) { + intersected = true; + this_distance = intersect.subtract(this.start).length(); + if(this_distance < distance) { + final_intersect.x = intersect.x; + final_intersect.y = intersect.y; + distance = this_distance; + calculate_line_normal(p3, p1, normal); + } } - } - if(intersected) { - intersection.x = final_intersect.x; - intersection.y = final_intersect.y; - if(normal_out) { - normal_out.x = normal.x; - normal_out.y = normal.y; + if(intersected) { + intersection.x = final_intersect.x; + intersection.y = final_intersect.y; + if(normal_out) { + normal_out.x = normal.x; + normal_out.y = normal.y; + } } - } - - return intersected; -}; - -cc.kmRay2IntersectCircle = function(ray, centre, radius, intersection) { - cc.log("cc.kmRay2IntersectCircle() has not been implemented."); -}; \ No newline at end of file + return intersected; + }; +})(cc); diff --git a/cocos2d/kazmath/utility.js b/cocos2d/kazmath/utility.js index 173ae61f33..9cd3fb4c71 100644 --- a/cocos2d/kazmath/utility.js +++ b/cocos2d/kazmath/utility.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,51 +26,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + /** - * @ignore + *

The main namespace of Cocos2d-html5's math library,
+ * all math core classes, functions, properties and constants are defined in this namespace

+ * @namespace + * @name cc.math */ -cc.kmScalar = Number; - -cc.kmBool = Number; - -cc.kmEnum = Number; - -cc.KM_FALSE = 0; +cc.math = cc.math || {}; -cc.KM_TRUE = 1; +//cc.kmPIOver180 = 0.017453; please use cc.RAD -cc.kmPI = 3.141592; +//cc.kmPIUnder180 = 57.295779; please use cc.DEG -cc.kmPIOver180 = 0.017453; - -cc.kmPIUnder180 = 57.295779; - -cc.kmEpsilon = 1.0 / 64.0; +cc.math.EPSILON = 1.0 / 64.0; //cc.kmEpsilon /** * Returns the square of s (e.g. s*s) * @param {Number} s */ -cc.kmSQR = function(s){ +cc.math.square = function(s){ return s*s; }; -cc.kmDegreesToRadians = function(degrees){ - return degrees * cc.kmPIOver180; -}; - -cc.kmRadiansToDegrees = function(radians){ - return radians * cc.kmPIUnder180; -}; - -cc.kmMin = function(lhs,rhs){ - return (lhs < rhs)? lhs : rhs; -}; - -cc.kmMax = function(lhs,rhs){ - return (lhs > rhs)? lhs : rhs; -}; - -cc.kmAlmostEqual = function(lhs,rhs){ - return (lhs + cc.kmEpsilon > rhs && lhs - cc.kmEpsilon < rhs); +cc.math.almostEqual = function(lhs,rhs){ + return (lhs + cc.math.EPSILON > rhs && lhs - cc.math.EPSILON < rhs); }; diff --git a/cocos2d/kazmath/vec2.js b/cocos2d/kazmath/vec2.js index 613ad45559..a682bc4853 100644 --- a/cocos2d/kazmath/vec2.js +++ b/cocos2d/kazmath/vec2.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,82 +26,88 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.kmVec2 = function (x, y) { - this.x = x || 0; - this.y = y || 0; -}; +(function(cc){ + cc.math.Vec2 = function (x, y) { + if(y === undefined){ + this.x = x.x; + this.y = x.y; + }else{ + this.x = x || 0; + this.y = y || 0; + } + }; + + var proto = cc.math.Vec2.prototype; + proto.fill = function(x, y){ // = cc.kmVec2Fill + this.x = x; + this.y = y; + }; + + proto.length = function(){ // = cc.kmVec2Length + return Math.sqrt(cc.math.square(this.x) + cc.math.square(this.y)); + }; + + proto.lengthSq = function(){ // = cc.kmVec2LengthSq + return cc.math.square(this.x) + cc.math.square(this.y); + }; + + proto.normalize = function(){ // = cc.kmVec2Normalize + var l = 1.0 / this.length(); + this.x *= l; + this.y *= l; + return this; + }; + + cc.math.Vec2.add = function (pOut, pV1, pV2) { // = cc.kmVec2Add + pOut.x = pV1.x + pV2.x; + pOut.y = pV1.y + pV2.y; + return pOut + }; + + proto.add = function(vec){ // = cc.kmVec2Add + this.x += vec.x; + this.y += vec.y; + return this; + }; + + proto.dot = function (vec) { //cc.kmVec2Dot + return this.x * vec.x + this.y * vec.y; + }; + + cc.math.Vec2.subtract = function (pOut, pV1, pV2) { // = cc.kmVec2Subtract + pOut.x = pV1.x - pV2.x; + pOut.y = pV1.y - pV2.y; + return pOut; + }; + + proto.subtract = function(vec){ // = cc.kmVec2Subtract + this.x -= vec.x; + this.y -= vec.y; + return this; + }; + + proto.transform = function (mat3) { // = cc.kmVec2Transform + var x = this.x, y = this.y; + this.x = x * mat3.mat[0] + y * mat3.mat[3] + mat3.mat[6]; + this.y = x * mat3.mat[1] + y * mat3.mat[4] + mat3.mat[7]; + return this; + }; + + cc.math.Vec2.scale = function (pOut, pIn, s) { // = cc.kmVec2Scale + pOut.x = pIn.x * s; + pOut.y = pIn.y * s; + return pOut; + }; + + proto.scale = function(s) { // = cc.kmVec2Scale + this.x *= s; + this.y *= s; + return this; + }; + + proto.equals = function (vec) { // = cc.kmVec2AreEqual + return (this.x < vec.x + cc.math.EPSILON && this.x > vec.x - cc.math.EPSILON) && + (this.y < vec.y + cc.math.EPSILON && this.y > vec.y - cc.math.EPSILON); + }; +})(cc); -cc.kmVec2Fill = function (pOut, x, y) { - pOut.x = x; - pOut.y = y; - return pOut; -}; - -cc.kmVec2Length = function (pIn) { - return Math.sqrt(cc.kmSQR(pIn.x) + cc.kmSQR(pIn.y)); -}; - -cc.kmVec2LengthSq = function (pIn) { - return cc.kmSQR(pIn.x) + cc.kmSQR(pIn.y); -}; - -cc.kmVec2Normalize = function (pOut, pIn) { - var l = 1.0 / cc.kmVec2Length(pIn); - - var v = new cc.kmVec2(); - v.x = pIn.x * l; - v.y = pIn.y * l; - - pOut.x = v.x; - pOut.y = v.y; - - return pOut; -}; - -cc.kmVec2Add = function (pOut, pV1, pV2) { - pOut.x = pV1.x + pV2.x; - pOut.y = pV1.y + pV2.y; - - return pOut -}; - -cc.kmVec2Dot = function (pV1, pV2) { - return pV1.x * pV2.x + pV1.y * pV2.y; -}; - -cc.kmVec2Subtract = function (pOut, pV1, pV2) { - pOut.x = pV1.x - pV2.x; - pOut.y = pV1.y - pV2.y; - - return pOut; -}; - -cc.kmVec2Transform = function (pOut, pV, pM) { - var v= new cc.kmVec2(); - - v.x = pV.x * pM.mat[0] + pV.y * pM.mat[3] + pM.mat[6]; - v.y = pV.x * pM.mat[1] + pV.y * pM.mat[4] + pM.mat[7]; - - pOut.x = v.x; - pOut.y = v.y; - - return pOut; -}; - -cc.kmVec2TransformCoord = function (pOut, pV, pM) { - return null; -}; - -cc.kmVec2Scale = function (pOut, pIn, s) { - pOut.x = pIn.x * s; - pOut.y = pIn.y * s; - - return pOut; -}; - -cc.kmVec2AreEqual = function (p1, p2) { - return ( - (p1.x < p2.x + cc.kmEpsilon && p1.x > p2.x - cc.kmEpsilon) && - (p1.y < p2.y + cc.kmEpsilon && p1.y > p2.y - cc.kmEpsilon) - ); -}; diff --git a/cocos2d/kazmath/vec3.js b/cocos2d/kazmath/vec3.js index c31de7c191..282b34aaae 100644 --- a/cocos2d/kazmath/vec3.js +++ b/cocos2d/kazmath/vec3.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,173 +26,169 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.kmVec3 = function (x, y, z) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; -}; - -cc.kmVec3Fill = function(pOut, x, y , z){ - if(!pOut) - return new cc.kmVec3(x, y , z); - pOut.x = x; - pOut.y = y; - pOut.z = z; - return pOut; -}; - -cc.kmVec3Length = function(pIn){ - return Math.sqrt(cc.kmSQR(pIn.x) + cc.kmSQR(pIn.y) + cc.kmSQR(pIn.z)); -}; - -cc.kmVec3LengthSq = function(pIn){ - return cc.kmSQR(pIn.x) + cc.kmSQR(pIn.y) + cc.kmSQR(pIn.z) -} ; - -cc.kmVec3Normalize = function(pOut,pIn){ - var l = 1.0 / cc.kmVec3Length(pIn); - - pOut.x = pIn.x * l; - pOut.y = pIn.y * l; - pOut.z = pIn.z * l; - return pOut; -}; - -cc.kmVec3Cross = function(pOut, pV1,pV2){ - pOut.x = (pV1.y * pV2.z) - (pV1.z * pV2.y); - pOut.y = (pV1.z * pV2.x) - (pV1.x * pV2.z); - pOut.z = (pV1.x * pV2.y) - (pV1.y * pV2.x); - return pOut; -}; - -cc.kmVec3Dot = function(pV1, pV2){ - return ( pV1.x * pV2.x - + pV1.y * pV2.y - + pV1.z * pV2.z ); -} ; - -cc.kmVec3Add = function(pOut, pV1, pV2){ - pOut.x = pV1.x + pV2.x; - pOut.y = pV1.y + pV2.y; - pOut.z = pV1.z + pV2.z; - return pOut; -}; - -cc.kmVec3Subtract = function(pOut, pV1, pV2){ - pOut.x = pV1.x - pV2.x; - pOut.y = pV1.y - pV2.y; - pOut.z = pV1.z - pV2.z; - return pOut; -}; - -cc.kmVec3Transform = function(pOut, pV, pM){ - /* - a = (Vx, Vy, Vz, 1) - b = (a×M)T - Out = (bx, by, bz) - */ - pOut.x = pV.x * pM.mat[0] + pV.y * pM.mat[4] + pV.z * pM.mat[8] + pM.mat[12]; - pOut.y = pV.x * pM.mat[1] + pV.y * pM.mat[5] + pV.z * pM.mat[9] + pM.mat[13]; - pOut.z = pV.x * pM.mat[2] + pV.y * pM.mat[6] + pV.z * pM.mat[10] + pM.mat[14]; - return pOut; -}; - -cc.kmVec3TransformNormal = function(pOut, pV, pM){ - /* - a = (Vx, Vy, Vz, 0) - b = (a×M)T - Out = (bx, by, bz) - */ - //Omits the translation, only scaling + rotating - pOut.x = pV.x * pM.mat[0] + pV.y * pM.mat[4] + pV.z * pM.mat[8]; - pOut.y = pV.x * pM.mat[1] + pV.y * pM.mat[5] + pV.z * pM.mat[9]; - pOut.z = pV.x * pM.mat[2] + pV.y * pM.mat[6] + pV.z * pM.mat[10]; - return pOut; -}; - -cc.kmVec3TransformCoord = function(pOut,pV,pM){ - /* - a = (Vx, Vy, Vz, 1) - b = (a×M)T - Out = 1⁄bw(bx, by, bz) - */ - var v = new cc.kmVec4(); - var inV = new cc.kmVec4(); - cc.kmVec4Fill(inV, pV.x, pV.y, pV.z, 1.0); - - cc.kmVec4Transform(v, inV,pM); - - pOut.x = v.x / v.w; - pOut.y = v.y / v.w; - pOut.z = v.z / v.w; - - return pOut; -}; - -cc.kmVec3Scale = function(pOut, pIn, s){ - pOut.x = pIn.x * s; - pOut.y = pIn.y * s; - pOut.z = pIn.z * s; - - return pOut; -}; - -cc.kmVec3AreEqual = function(p1, p2){ - if ((p1.x < (p2.x + cc.kmEpsilon) && p1.x > (p2.x - cc.kmEpsilon)) && - (p1.y < (p2.y + cc.kmEpsilon) && p1.y > (p2.y - cc.kmEpsilon)) && - (p1.z < (p2.z + cc.kmEpsilon) && p1.z > (p2.z - cc.kmEpsilon))) { - return 1; - } - - return 0; -}; - -cc.kmVec3InverseTransform = function(pOut, pVect,pM){ - var v1 = new cc.kmVec3(pVect.x - pM.mat[12], pVect.y - pM.mat[13],pVect.z - pM.mat[14]); - - pOut.x = v1.x * pM.mat[0] + v1.y * pM.mat[1] + v1.z * pM.mat[2]; - pOut.y = v1.x * pM.mat[4] + v1.y * pM.mat[5] + v1.z * pM.mat[6]; - pOut.z = v1.x * pM.mat[8] + v1.y * pM.mat[9] + v1.z * pM.mat[10]; - - return pOut; -}; - -cc.kmVec3InverseTransformNormal = function(pOut, pVect, pM){ - pOut.x = pVect.x * pM.mat[0] + pVect.y * pM.mat[1] + pVect.z * pM.mat[2]; - pOut.y = pVect.x * pM.mat[4] + pVect.y * pM.mat[5] + pVect.z * pM.mat[6]; - pOut.z = pVect.x * pM.mat[8] + pVect.y * pM.mat[9] + pVect.z * pM.mat[10]; - - return pOut; -}; - -cc.kmVec3Assign = function(pOut,pIn){ - if (pOut == pIn) - return pOut; - - pOut.x = pIn.x; - pOut.y = pIn.y; - pOut.z = pIn.z; - return pOut; -}; - -cc.kmVec3Zero = function(pOut){ - pOut.x = 0.0; - pOut.y = 0.0; - pOut.z = 0.0; - - return pOut; -}; - -cc.kmVec3ToTypeArray = function(vecValue){ - if(!vecValue) - return null; - - var tyArr = new Float32Array(3); - tyArr[0] = vecValue.x; - tyArr[1] = vecValue.y; - tyArr[2] = vecValue.z; - return tyArr; -}; +(function(cc) { + cc.kmVec3 = cc.math.Vec3 = function (x, y, z) { + if(x && y === undefined){ + this.x = x.x; + this.y = x.y; + this.z = x.z; + } else { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + } + }; + + cc.math.vec3 = function(x, y, z){ + return new cc.math.Vec3(x, y, z); + }; + + var proto = cc.math.Vec3.prototype; + + proto.fill = function (x, y, z) { // =cc.kmVec3Fill + if (x && y === undefined) { + this.x = x.x; + this.y = x.y; + this.z = x.z; + } else { + this.x = x; + this.y = y; + this.z = z; + } + return this; + }; + + proto.length = function () { //=cc.kmVec3Length + return Math.sqrt(cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z)); + }; + + proto.lengthSq = function () { //=cc.kmVec3LengthSq + return cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z) + }; + + proto.normalize = function () { //= cc.kmVec3Normalize + var l = 1.0 / this.length(); + this.x *= l; + this.y *= l; + this.z *= l; + return this; + }; + + proto.cross = function (vec3) { //= cc.kmVec3Cross + var x = this.x, y = this.y, z = this.z; + this.x = (y * vec3.z) - (z * vec3.y); + this.y = (z * vec3.x) - (x * vec3.z); + this.z = (x * vec3.y) - (y * vec3.x); + return this; + }; + + proto.dot = function (vec) { //= cc.kmVec3Dot + return ( this.x * vec.x + this.y * vec.y + this.z * vec.z ); + }; + + proto.add = function(vec){ //= cc.kmVec3Add + this.x += vec.x; + this.y += vec.y; + this.z += vec.z; + return this; + }; + + proto.subtract = function (vec) { // = cc.kmVec3Subtract + this.x -= vec.x; + this.y -= vec.y; + this.z -= vec.z; + return this; + }; + + proto.transform = function (mat4) { // = cc.kmVec3Transform + var x = this.x, y = this.y, z = this.z, mat = mat4.mat; + this.x = x * mat[0] + y * mat[4] + z * mat[8] + mat[12]; + this.y = x * mat[1] + y * mat[5] + z * mat[9] + mat[13]; + this.z = x * mat[2] + y * mat[6] + z * mat[10] + mat[14]; + return this; + }; + + proto.transformNormal = function(mat4){ + /* + a = (Vx, Vy, Vz, 0) + b = (a×M)T + Out = (bx, by, bz) + */ + //Omits the translation, only scaling + rotating + var x = this.x, y = this.y, z = this.z, mat = mat4.mat; + this.x = x * mat[0] + y * mat[4] + z * mat[8]; + this.y = x * mat[1] + y * mat[5] + z * mat[9]; + this.z = x * mat[2] + y * mat[6] + z * mat[10]; + return this; + }; + + proto.transformCoord = function(mat4){ // = cc.kmVec3TransformCoord + /* + a = (Vx, Vy, Vz, 1) + b = (a×M)T + Out = 1⁄bw(bx, by, bz) + */ + var v = new cc.math.Vec4(this.x, this.y, this.z, 1.0); + v.transform(mat4); + this.x = v.x / v.w; + this.y = v.y / v.w; + this.z = v.z / v.w; + return this; + }; + + proto.scale = function(scale){ // = cc.kmVec3Scale + this.x *= scale; + this.y *= scale; + this.z *= scale; + return this; + }; + + proto.equals = function(vec){ // = cc.kmVec3AreEqual + var EPSILON = cc.math.EPSILON; + return (this.x < (vec.x + EPSILON) && this.x > (vec.x - EPSILON)) && + (this.y < (vec.y + EPSILON) && this.y > (vec.y - EPSILON)) && + (this.z < (vec.z + EPSILON) && this.z > (vec.z - EPSILON)); + }; + + proto.inverseTransform = function(mat4){ //= cc.kmVec3InverseTransform + var mat = mat4.mat; + var v1 = new cc.math.Vec3(this.x - mat[12], this.y - mat[13], this.z - mat[14]); + this.x = v1.x * mat[0] + v1.y * mat[1] + v1.z * mat[2]; + this.y = v1.x * mat[4] + v1.y * mat[5] + v1.z * mat[6]; + this.z = v1.x * mat[8] + v1.y * mat[9] + v1.z * mat[10]; + return this; + }; + + proto.inverseTransformNormal = function(mat4){ // = cc.kmVec3InverseTransformNormal + var x = this.x, y = this.y, z = this.z, mat = mat4.mat; + this.x = x * mat[0] + y * mat[1] + z * mat[2]; + this.y = x * mat[4] + y * mat[5] + z * mat[6]; + this.z = x * mat[8] + y * mat[9] + z * mat[10]; + return this; + }; + + proto.assignFrom = function(vec){ + if(!vec) + return this; + this.x = vec.x; + this.y = vec.y; + this.z = vec.z; + return this; + }; + + cc.math.Vec3.zero = function(vec){ // = cc.kmVec3Zero + vec.x = vec.y = vec.z = 0.0; + return vec; + }; + + proto.toTypeArray = function(){ //cc.kmVec3ToTypeArray + var tyArr = new Float32Array(3); + tyArr[0] = this.x; + tyArr[1] = this.y; + tyArr[2] = this.z; + return tyArr; + }; +})(cc); diff --git a/cocos2d/kazmath/vec4.js b/cocos2d/kazmath/vec4.js index 870e480632..fb2e376380 100644 --- a/cocos2d/kazmath/vec4.js +++ b/cocos2d/kazmath/vec4.js @@ -1,5 +1,7 @@ /** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008, Luke Benstead. All rights reserved. @@ -24,133 +26,133 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -cc.kmVec4 = function (x, y, z, w) { - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = w || 0; -}; - - -cc.kmVec4Fill = function(outVec, x, y ,z, w){ - outVec.x = x; - outVec.y = y; - outVec.z = z; - outVec.w = w; - return outVec; -}; - -cc.kmVec4Add = function(outVec, pV1, pV2){ - outVec.x = pV1.x + pV2.x; - outVec.y = pV1.y + pV2.y; - outVec.z = pV1.z + pV2.z; - outVec.w = pV1.w + pV2.w; - - return outVec; -}; - -cc.kmVec4Dot = function( vec1, vec2){ - return ( vec1.x * vec2.x - + vec1.y * vec2.y - + vec1.z * vec2.z - + vec1.w * vec2.w ); -}; - -cc.kmVec4Length = function(inVec){ - return Math.sqrt(cc.kmSQR(inVec.x) + cc.kmSQR(inVec.y) + cc.kmSQR(inVec.z) + cc.kmSQR(inVec.w)); -}; - -cc.kmVec4LengthSq = function(inVec){ - return cc.kmSQR(inVec.x) + cc.kmSQR(inVec.y) + cc.kmSQR(inVec.z) + cc.kmSQR(inVec.w); -}; - -cc.kmVec4Lerp = function(outVec, pV1, pV2, t){ - return outVec; -}; - -cc.kmVec4Normalize = function(outVec, inVec){ - var l = 1.0 / cc.kmVec4Length(inVec); - - outVec.x *= l; - outVec.y *= l; - outVec.z *= l; - outVec.w *= l; - - return outVec; -}; - -cc.kmVec4Scale = function(outVec, inVec, scale){ - cc.kmVec4Normalize(outVec, inVec); - - outVec.x *= scale; - outVec.y *= scale; - outVec.z *= scale; - outVec.w *= scale; - return outVec; -}; - -cc.kmVec4Subtract = function(outVec,vec1, vec2){ - outVec.x = vec1.x - vec2.x; - outVec.y = vec1.y - vec2.y; - outVec.z = vec1.z - vec2.z; - outVec.w = vec1.w - vec2.w; - - return outVec; -}; - -cc.kmVec4Transform = function(outVec, vec,mat4Obj){ - outVec.x = vec.x * mat4Obj.mat[0] + vec.y * mat4Obj.mat[4] + vec.z * mat4Obj.mat[8] + vec.w * mat4Obj.mat[12]; - outVec.y = vec.x * mat4Obj.mat[1] + vec.y * mat4Obj.mat[5] + vec.z * mat4Obj.mat[9] + vec.w * mat4Obj.mat[13]; - outVec.z = vec.x * mat4Obj.mat[2] + vec.y * mat4Obj.mat[6] + vec.z * mat4Obj.mat[10] + vec.w * mat4Obj.mat[14]; - outVec.w = vec.x * mat4Obj.mat[3] + vec.y * mat4Obj.mat[7] + vec.z * mat4Obj.mat[11] + vec.w * mat4Obj.mat[15]; - return outVec; -}; - -cc.kmVec4TransformArray = function(outVec,outStride,vecObj,stride,mat4Obj,count){ - var i = 0; - //Go through all of the vectors - while (i < count) { - var currIn = vecObj + (i * stride); //Get a pointer to the current input - var out = outVec + (i * outStride); //and the current output - cc.kmVec4Transform(out, currIn, mat4Obj); //Perform transform on it - ++i; - } - - return outVec; -}; - -cc.kmVec4AreEqual = function(vec1,vec2){ - return ( - (vec1.x < vec2.x + cc.kmEpsilon && vec1.x > vec2.x - cc.kmEpsilon) && - (vec1.y < vec2.y + cc.kmEpsilon && vec1.y > vec2.y - cc.kmEpsilon) && - (vec1.z < vec2.z + cc.kmEpsilon && vec1.z > vec2.z - cc.kmEpsilon) && - (vec1.w < vec2.w + cc.kmEpsilon && vec1.w > vec2.w - cc.kmEpsilon) - ); -}; - -cc.kmVec4Assign = function(destVec, srcVec){ - if(destVec == srcVec){ - cc.log("destVec and srcVec are same object"); - return destVec; - } - - destVec.x = srcVec.x; - destVec.y = srcVec.y; - destVec.z = srcVec.z; - destVec.w = srcVec.w; - - return destVec; -}; - -cc.kmVec4ToTypeArray = function(vecValue){ - if(!vecValue) - return null; - - var tyArr = new Float32Array(4); - tyArr[0] = vecValue.x; - tyArr[1] = vecValue.y; - tyArr[2] = vecValue.z; - tyArr[3] = vecValue.w; - return tyArr; -}; +(function(cc) { + cc.math.Vec4 = function (x, y, z, w) { + if (x && y === undefined) { + this.x = x.x; + this.y = x.y; + this.z = x.z; + this.w = x.w; + } else { + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; + this.w = w || 0; + } + }; + cc.kmVec4 = cc.math.Vec4; + var proto = cc.math.Vec4.prototype; + + proto.fill = function (x, y, z, w) { //=cc.kmVec4Fill + if (x && y === undefined) { + this.x = x.x; + this.y = x.y; + this.z = x.z; + this.w = x.w; + } else { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + }; + + proto.add = function(vec) { //cc.kmVec4Add + if(!vec) + return this; + this.x += vec.x; + this.y += vec.y; + this.z += vec.z; + this.w += vec.w; + return this; + }; + + proto.dot = function(vec){ //cc.kmVec4Dot + return ( this.x * vec.x + this.y * vec.y + this.z * vec.z + this.w * vec.w ); + }; + + proto.length = function(){ //=cc.kmVec4Length + return Math.sqrt(cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z) + cc.math.square(this.w)); + }; + + proto.lengthSq = function(){ //=cc.kmVec4LengthSq + return cc.math.square(this.x) + cc.math.square(this.y) + cc.math.square(this.z) + cc.math.square(this.w); + }; + + proto.lerp = function(vec, t){ //= cc.kmVec4Lerp + //not implemented + return this; + }; + + proto.normalize = function() { // cc.kmVec4Normalize + var l = 1.0 / this.length(); + this.x *= l; + this.y *= l; + this.z *= l; + this.w *= l; + return this; + }; + + proto.scale = function(scale){ //= cc.kmVec4Scale + /// Scales a vector to the required length. This performs a Normalize before multiplying by S. + this.normalize(); + this.x *= scale; + this.y *= scale; + this.z *= scale; + this.w *= scale; + return this; + }; + + proto.subtract = function(vec) { + this.x -= vec.x; + this.y -= vec.y; + this.z -= vec.z; + this.w -= vec.w; + }; + + proto.transform = function(mat4) { + var x = this.x, y = this.y, z = this.z, w = this.w, mat = mat4.mat; + this.x = x * mat[0] + y * mat[4] + z * mat[8] + w * mat[12]; + this.y = x * mat[1] + y * mat[5] + z * mat[9] + w * mat[13]; + this.z = x * mat[2] + y * mat[6] + z * mat[10] + w * mat[14]; + this.w = x * mat[3] + y * mat[7] + z * mat[11] + w * mat[15]; + return this; + }; + + cc.math.Vec4.transformArray = function(vecArray, mat4){ + var retArray = []; + for (var i = 0; i < vecArray.length; i++) { + var selVec = new cc.math.Vec4(vecArray[i]); + selVec.transform(mat4); + retArray.push(selVec); + } + return retArray; + }; + + proto.equals = function(vec){ //=cc.kmVec4AreEqual + var EPSILON = cc.math.EPSILON; + return (this.x < vec.x + EPSILON && this.x > vec.x - EPSILON) && + (this.y < vec.y + EPSILON && this.y > vec.y - EPSILON) && + (this.z < vec.z + EPSILON && this.z > vec.z - EPSILON) && + (this.w < vec.w + EPSILON && this.w > vec.w - EPSILON); + }; + + proto.assignFrom = function(vec) { //= cc.kmVec4Assign + this.x = vec.x; + this.y = vec.y; + this.z = vec.z; + this.w = vec.w; + return this; + }; + + proto.toTypeArray = function(){ //cc.kmVec4ToTypeArray + var tyArr = new Float32Array(4); + tyArr[0] = this.x; + tyArr[1] = this.y; + tyArr[2] = this.z; + tyArr[3] = this.w; + return tyArr; + }; +})(cc); + diff --git a/cocos2d/labels/CCLabelAtlas.js b/cocos2d/labels/CCLabelAtlas.js index f008aa480d..e922ddc2d6 100644 --- a/cocos2d/labels/CCLabelAtlas.js +++ b/cocos2d/labels/CCLabelAtlas.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -30,44 +30,59 @@ * @extends cc.AtlasNode * * @property {String} string - Content string of label + * + * @param {String} strText + * @param {String} charMapFile charMapFile or fntFile + * @param {Number} [itemWidth=0] + * @param {Number} [itemHeight=0] + * @param {Number} [startCharMap=""] + * @example + * //creates the cc.LabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas + * var myLabel = new cc.LabelAtlas('Text to display', 'CharMapfile.png', 12, 20, ' ') + * + * //creates the cc.LabelAtlas with a string, a fnt file + * var myLabel = new cc.LabelAtlas('Text to display', 'CharMapFile.plist‘); */ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ + //property String is Getter and Setter // string to render _string: null, // the first char in the charmap _mapStartChar: null, _textureLoaded: false, - _loadedEventListeners: null, _className: "LabelAtlas", /** *

- * Create a label atlas. - * It accepts two groups of parameters:
- * a) string, fntFile
- * b) label, textureFilename, width, height, startChar
+ * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
+ * Create a label atlas.
+ * It accepts two groups of parameters:
+ * a) string, fntFile
+ * b) label, textureFilename, width, height, startChar
*

* @param {String} strText * @param {String} charMapFile charMapFile or fntFile * @param {Number} [itemWidth=0] * @param {Number} [itemHeight=0] * @param {Number} [startCharMap=""] - * @example - * //creates the cc.LabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas - * var myLabel = new cc.LabelAtlas('Text to display', 'CharMapfile.png', 12, 20, ' ') - * - * //creates the cc.LabelAtlas with a string, a fnt file - * var myLabel = new cc.LabelAtlas('Text to display', 'CharMapFile.plist‘); */ ctor: function (strText, charMapFile, itemWidth, itemHeight, startCharMap) { cc.AtlasNode.prototype.ctor.call(this); + this._renderCmd.setCascade(); charMapFile && cc.LabelAtlas.prototype.initWithString.call(this, strText, charMapFile, itemWidth, itemHeight, startCharMap); }, + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + return new cc.LabelAtlas.WebGLRenderCmd(this); + else + return new cc.LabelAtlas.CanvasRenderCmd(this); + }, + /** - * return texture is loaded + * Return texture is loaded. * @returns {boolean} */ textureLoaded: function () { @@ -75,34 +90,22 @@ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ }, /** - * add texture loaded event listener + * Add texture loaded event listener. * @param {Function} callback - * @param {Object} target + * @param {cc.Node} target + * @deprecated since 3.1, please use addEventListener instead */ addLoadedEventListener: function (callback, target) { - if (!this._loadedEventListeners) - this._loadedEventListeners = []; - this._loadedEventListeners.push({eventCallback: callback, eventTarget: target}); + this.addEventListener("load", callback, target); }, - _callLoadedEventCallbacks: function () { - if (!this._loadedEventListeners) - return; - this._textureLoaded = true; - var locListeners = this._loadedEventListeners; - for (var i = 0, len = locListeners.length; i < len; i++) { - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; - }, /** *

- * initializes the cc.LabelAtlas with a string, a char map file(the atlas),
- * the width and height of each element and the starting char of the atlas
- * It accepts two groups of parameters:
- * a) string, fntFile
- * b) label, textureFilename, width, height, startChar
+ * initializes the cc.LabelAtlas with a string, a char map file(the atlas),
+ * the width and height of each element and the starting char of the atlas
+ * It accepts two groups of parameters:
+ * a) string, fntFile
+ * b) label, textureFilename, width, height, startChar
*

* @param {String} strText * @param {String|cc.Texture2D} charMapFile charMapFile or fntFile or texture file @@ -140,10 +143,12 @@ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ var locLoaded = texture.isLoaded(); this._textureLoaded = locLoaded; if (!locLoaded) { - texture.addLoadedEventListener(function (sender) { + this._string = label; + texture.addEventListener("load", function (sender) { this.initWithTexture(texture, width, height, label.length); - this.string = label; - this._callLoadedEventCallbacks(); + this.string = this._string; + this.setColor(this._renderCmd._displayedColor); + this.dispatchEvent("load"); }, this); } if (this.initWithTexture(texture, width, height, label.length)) { @@ -155,12 +160,14 @@ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ }, /** + * Set the color. * @param {cc.Color} color3 */ setColor: function (color3) { cc.AtlasNode.prototype.setColor.call(this, color3); - this.updateAtlasValues(); + this._renderCmd.updateAtlasValues(); }, + /** * return the text of this label * @return {String} @@ -169,136 +176,17 @@ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ return this._string; }, - /** - * draw the label - */ - draw: function (ctx) { - cc.AtlasNode.prototype.draw.call(this, ctx); - if (cc.LABELATLAS_DEBUG_DRAW) { - var s = this.size; - var vertices = [cc.p(0, 0), cc.p(s.width, 0), - cc.p(s.width, s.height), cc.p(0, s.height)]; - cc._drawingUtil.drawPoly(vertices, 4, true); - } + addChild: function(child, localZOrder, tag){ + this._renderCmd._addChild(child); + cc.Node.prototype.addChild.call(this, child, localZOrder, tag); }, /** - * @function * Atlas generation + * @function */ - updateAtlasValues: null, - - _updateAtlasValuesForCanvas: function () { - var locString = this._string; - var n = locString.length; - var texture = this.texture; - var locItemWidth = this._itemWidth , locItemHeight = this._itemHeight; //needn't multiply cc.contentScaleFactor(), because sprite's draw will do this - - for (var i = 0; i < n; i++) { - var a = locString.charCodeAt(i) - this._mapStartChar.charCodeAt(0); - var row = parseInt(a % this._itemsPerRow, 10); - var col = parseInt(a / this._itemsPerRow, 10); - - var rect = cc.rect(row * locItemWidth, col * locItemHeight, locItemWidth, locItemHeight); - var c = locString.charCodeAt(i); - var fontChar = this.getChildByTag(i); - if (!fontChar) { - fontChar = new cc.Sprite(); - if (c == 32) { - fontChar.init(); - fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.size(0, 0)); - } else - fontChar.initWithTexture(texture, rect); - - this.addChild(fontChar, 0, i); - } else { - if (c == 32) { - fontChar.init(); - fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.size(0, 0)); - } else { - // reusing fonts - fontChar.initWithTexture(texture, rect); - // restore to default in case they were modified - fontChar.visible = true; - fontChar.opacity = this._displayedOpacity; - } - } - fontChar.setPosition(i * locItemWidth + locItemWidth / 2, locItemHeight / 2); - } - }, - - _updateAtlasValuesForWebGL: function () { - var locString = this._string; - var n = locString.length; - var locTextureAtlas = this.textureAtlas; - - var texture = locTextureAtlas.texture; - var textureWide = texture.pixelsWidth; - var textureHigh = texture.pixelsHeight; - var itemWidthInPixels = this._itemWidth; - var itemHeightInPixels = this._itemHeight; - if (!this._ignoreContentScaleFactor) { - itemWidthInPixels = this._itemWidth * cc.contentScaleFactor(); - itemHeightInPixels = this._itemHeight * cc.contentScaleFactor(); - } - if (n > locTextureAtlas.getCapacity()) - cc.log("cc.LabelAtlas._updateAtlasValues(): Invalid String length"); - var quads = locTextureAtlas.quads; - var locDisplayedColor = this._displayedColor; - var curColor = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: this._displayedOpacity}; - var locItemWidth = this._itemWidth; - for (var i = 0; i < n; i++) { - var a = locString.charCodeAt(i) - this._mapStartChar.charCodeAt(0); - var row = a % this._itemsPerRow; - var col = 0 | (a / this._itemsPerRow); - - var left, right, top, bottom; - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - // Issue #938. Don't use texStepX & texStepY - left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide); - right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide); - top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh); - bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh); - } else { - left = row * itemWidthInPixels / textureWide; - right = left + itemWidthInPixels / textureWide; - top = col * itemHeightInPixels / textureHigh; - bottom = top + itemHeightInPixels / textureHigh; - } - var quad = quads[i]; - var locQuadTL = quad.tl, locQuadTR = quad.tr, locQuadBL = quad.bl, locQuadBR = quad.br; - locQuadTL.texCoords.u = left; - locQuadTL.texCoords.v = top; - locQuadTR.texCoords.u = right; - locQuadTR.texCoords.v = top; - locQuadBL.texCoords.u = left; - locQuadBL.texCoords.v = bottom; - locQuadBR.texCoords.u = right; - locQuadBR.texCoords.v = bottom; - - locQuadBL.vertices.x = (i * locItemWidth); - locQuadBL.vertices.y = 0; - locQuadBL.vertices.z = 0.0; - locQuadBR.vertices.x = (i * locItemWidth + locItemWidth); - locQuadBR.vertices.y = 0; - locQuadBR.vertices.z = 0.0; - locQuadTL.vertices.x = i * locItemWidth; - locQuadTL.vertices.y = this._itemHeight; - locQuadTL.vertices.z = 0.0; - locQuadTR.vertices.x = i * locItemWidth + locItemWidth; - locQuadTR.vertices.y = this._itemHeight; - locQuadTR.vertices.z = 0.0; - locQuadTL.colors = curColor; - locQuadTR.colors = curColor; - locQuadBL.colors = curColor; - locQuadBR.colors = curColor; - } - if (n > 0) { - locTextureAtlas.dirty = true; - var totalQuads = locTextureAtlas.totalQuads; - if (n > totalQuads) - locTextureAtlas.increaseTotalQuadsWith(n - totalQuads); - } + updateAtlasValues: function(){ + this._renderCmd.updateAtlasValues(); }, /** @@ -306,100 +194,45 @@ cc.LabelAtlas = cc.AtlasNode.extend(/** @lends cc.LabelAtlas# */{ * @function * @param {String} label */ - setString: null, - - _setStringForCanvas: function (label) { + setString: function(label){ label = String(label); var len = label.length; this._string = label; - this.width = len * this._itemWidth; - this.height = this._itemHeight; - if (this._children) { - var locChildren = this._children; - len = locChildren.length; - for (var i = 0; i < len; i++) { - var node = locChildren[i]; - if (node) - node.visible = false; - } - } + this.setContentSize(len * this._itemWidth, this._itemHeight); + this._renderCmd.setString(label); - this.updateAtlasValues(); + this._renderCmd.updateAtlasValues(); this.quadsToDraw = len; - }, - - _setStringForWebGL: function (label) { - label = String(label); - var len = label.length; - if (len > this.textureAtlas.totalQuads) - this.textureAtlas.resizeCapacity(len); - - this._string = label; - this.width = len * this._itemWidth; - this.height = this._itemHeight; - - this.updateAtlasValues(); - this.quadsToDraw = len; - }, - - setOpacity: null, - - _setOpacityForCanvas: function (opacity) { - if (this._displayedOpacity !== opacity) { - cc.AtlasNode.prototype.setOpacity.call(this, opacity); - var locChildren = this._children; - for (var i = 0, len = locChildren.length; i < len; i++) { - if (locChildren[i]) - locChildren[i].opacity = opacity; - } - } - }, - - _setOpacityForWebGL: function (opacity) { - if (this._opacity !== opacity) - cc.AtlasNode.prototype.setOpacity.call(this, opacity); } }); -var _p = cc.LabelAtlas.prototype; -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _p.updateAtlasValues = _p._updateAtlasValuesForWebGL; - _p.setString = _p._setStringForWebGL; - _p.setOpacity = _p._setOpacityForWebGL; -} else { - _p.updateAtlasValues = _p._updateAtlasValuesForCanvas; - _p.setString = _p._setStringForCanvas; - _p.setOpacity = _p._setOpacityForCanvas; -} +(function(){ + var proto = cc.LabelAtlas.prototype; + // Override properties + cc.defineGetterSetter(proto, "opacity", proto.getOpacity, proto.setOpacity); + cc.defineGetterSetter(proto, "color", proto.getColor, proto.setColor); -// Override properties -cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); - -// Extended properties -/** @expose */ -_p.string; -cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); + // Extended properties + /** @expose */ + proto.string; + cc.defineGetterSetter(proto, "string", proto.getString, proto.setString); +})(); /** *

- * Create a label atlas. - * It accepts two groups of parameters:
- * a) string, fntFile
- * b) label, textureFilename, width, height, startChar
+ * Please use new cc.LabelAtlas instead.
+ * Create a label atlas.
+ * It accepts two groups of parameters:
+ * a) string, fntFile
+ * b) label, textureFilename, width, height, startChar
*

+ * @deprecated since v3.0 please use new cc.LabelAtlas * @param {String} strText * @param {String} charMapFile charMapFile or fntFile * @param {Number} [itemWidth=0] * @param {Number} [itemHeight=0] * @param {Number} [startCharMap=""] - * @return {cc.LabelAtlas|Null} returns the LabelAtlas object on success - * @example - * //Example - * //creates the cc.LabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas - * var myLabel = cc.LabelAtlas.create('Text to display', 'CharMapfile.png', 12, 20, ' ') - * - * //creates the cc.LabelAtlas with a string, a fnt file - * var myLabel = cc.LabelAtlas.create('Text to display', 'CharMapFile.plist‘); + * @return {cc.LabelAtlas} returns the LabelAtlas object on success */ cc.LabelAtlas.create = function (strText, charMapFile, itemWidth, itemHeight, startCharMap) { return new cc.LabelAtlas(strText, charMapFile, itemWidth, itemHeight, startCharMap); diff --git a/cocos2d/labels/CCLabelAtlasCanvasRenderCmd.js b/cocos2d/labels/CCLabelAtlasCanvasRenderCmd.js new file mode 100644 index 0000000000..2be997851d --- /dev/null +++ b/cocos2d/labels/CCLabelAtlasCanvasRenderCmd.js @@ -0,0 +1,95 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.LabelAtlas.CanvasRenderCmd = function(renderableObject){ + cc.AtlasNode.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = false; + }; + + var proto = cc.LabelAtlas.CanvasRenderCmd.prototype = Object.create(cc.AtlasNode.CanvasRenderCmd.prototype); + proto.constructor = cc.LabelAtlas.CanvasRenderCmd; + + proto.setCascade = function(){ + var node = this._node; + node._cascadeOpacityEnabled = true; + node._cascadeColorEnabled = false; + }; + + proto.updateAtlasValues = function(){ + var node = this._node; + var locString = node._string || ""; + var n = locString.length; + var texture = this._texture; + var locItemWidth = node._itemWidth , locItemHeight = node._itemHeight; //needn't multiply cc.contentScaleFactor(), because sprite's draw will do this + + for (var i = 0; i < n; i++) { + var a = locString.charCodeAt(i) - node._mapStartChar.charCodeAt(0); + var row = parseInt(a % node._itemsPerRow, 10); + var col = parseInt(a / node._itemsPerRow, 10); + + var rect = cc.rect(row * locItemWidth, col * locItemHeight, locItemWidth, locItemHeight); + var c = locString.charCodeAt(i); + var fontChar = node.getChildByTag(i); + if (!fontChar) { + fontChar = new cc.Sprite(); + if (c === 32) { + fontChar.init(); + fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.size(0, 0)); + } else + fontChar.initWithTexture(texture, rect); + + cc.Node.prototype.addChild.call(node, fontChar, 0, i); + } else { + if (c === 32) { + fontChar.init(); + fontChar.setTextureRect(cc.rect(0, 0, 10, 10), false, cc.size(0, 0)); + } else { + // reusing fonts + fontChar.initWithTexture(texture, rect); + // restore to default in case they were modified + fontChar.visible = true; + } + } + fontChar.setPosition(i * locItemWidth + locItemWidth / 2, locItemHeight / 2); + } + }; + + proto.setString = function(label){ + var node = this._node; + if (node._children) { + var locChildren = node._children; + var len = locChildren.length; + for (var i = 0; i < len; i++) { + var child = locChildren[i]; + if (child && !child._lateChild) + child.visible = false; + } + } + }; + + proto._addChild = function(){ + child._lateChild = true; + }; +})(); \ No newline at end of file diff --git a/cocos2d/labels/CCLabelAtlasWebGLRenderCmd.js b/cocos2d/labels/CCLabelAtlasWebGLRenderCmd.js new file mode 100644 index 0000000000..ef548032e3 --- /dev/null +++ b/cocos2d/labels/CCLabelAtlasWebGLRenderCmd.js @@ -0,0 +1,132 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.LabelAtlas.WebGLRenderCmd = function(renderable){ + cc.AtlasNode.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + }; + + var proto = cc.LabelAtlas.WebGLRenderCmd.prototype = Object.create(cc.AtlasNode.WebGLRenderCmd.prototype); + proto.constructor = cc.LabelAtlas.WebGLRenderCmd; + + proto.setCascade = function(){ + var node = this._node; + node._cascadeOpacityEnabled = true; + node._cascadeColorEnabled = true; + }; + + proto.rendering = function(ctx){ + cc.AtlasNode.WebGLRenderCmd.prototype.rendering.call(this, ctx); + if (cc.LABELATLAS_DEBUG_DRAW) { + var s = this._node.getContentSize(); + var vertices = [cc.p(0, 0), cc.p(s.width, 0), + cc.p(s.width, s.height), cc.p(0, s.height)]; + cc._drawingUtil.drawPoly(vertices, 4, true); + } + }; + + proto.updateAtlasValues = function(){ + var node = this._node; + var locString = node._string; + var n = locString.length; + var locTextureAtlas = this._textureAtlas; + + var texture = locTextureAtlas.texture; + var textureWide = texture.pixelsWidth; + var textureHigh = texture.pixelsHeight; + var itemWidthInPixels = node._itemWidth; + var itemHeightInPixels = node._itemHeight; + if (!node._ignoreContentScaleFactor) { + itemWidthInPixels = node._itemWidth * cc.contentScaleFactor(); + itemHeightInPixels = node._itemHeight * cc.contentScaleFactor(); + } + if (n > locTextureAtlas.getCapacity()) + cc.log("cc.LabelAtlas._updateAtlasValues(): Invalid String length"); + var quads = locTextureAtlas.quads; + var locDisplayedColor = this._displayedColor; + var curColor = {r: locDisplayedColor.r, g: locDisplayedColor.g, b: locDisplayedColor.b, a: node._displayedOpacity}; + var locItemWidth = node._itemWidth; + for (var i = 0; i < n; i++) { + var a = locString.charCodeAt(i) - node._mapStartChar.charCodeAt(0); + var row = a % node._itemsPerRow; + var col = 0 | (a / node._itemsPerRow); + + var left, right, top, bottom; + if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { + // Issue #938. Don't use texStepX & texStepY + left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide); + right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide); + top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh); + bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh); + } else { + left = row * itemWidthInPixels / textureWide; + right = left + itemWidthInPixels / textureWide; + top = col * itemHeightInPixels / textureHigh; + bottom = top + itemHeightInPixels / textureHigh; + } + var quad = quads[i]; + var locQuadTL = quad.tl, locQuadTR = quad.tr, locQuadBL = quad.bl, locQuadBR = quad.br; + locQuadTL.texCoords.u = left; + locQuadTL.texCoords.v = top; + locQuadTR.texCoords.u = right; + locQuadTR.texCoords.v = top; + locQuadBL.texCoords.u = left; + locQuadBL.texCoords.v = bottom; + locQuadBR.texCoords.u = right; + locQuadBR.texCoords.v = bottom; + + locQuadBL.vertices.x = (i * locItemWidth); + locQuadBL.vertices.y = 0; + locQuadBL.vertices.z = 0.0; + locQuadBR.vertices.x = (i * locItemWidth + locItemWidth); + locQuadBR.vertices.y = 0; + locQuadBR.vertices.z = 0.0; + locQuadTL.vertices.x = i * locItemWidth; + locQuadTL.vertices.y = node._itemHeight; + locQuadTL.vertices.z = 0.0; + locQuadTR.vertices.x = i * locItemWidth + locItemWidth; + locQuadTR.vertices.y = node._itemHeight; + locQuadTR.vertices.z = 0.0; + locQuadTL.colors = curColor; + locQuadTR.colors = curColor; + locQuadBL.colors = curColor; + locQuadBR.colors = curColor; + } + if (n > 0) { + locTextureAtlas.dirty = true; + var totalQuads = locTextureAtlas.totalQuads; + if (n > totalQuads) + locTextureAtlas.increaseTotalQuadsWith(n - totalQuads); + } + }; + + proto.setString = function(label){ + var len = label.length; + if (len > this._textureAtlas.totalQuads) + this._textureAtlas.resizeCapacity(len); + }; + + proto._addChild = function(){}; +})(); \ No newline at end of file diff --git a/cocos2d/labels/CCLabelBMFont.js b/cocos2d/labels/CCLabelBMFont.js index 76f52cf287..83bdf818cf 100644 --- a/cocos2d/labels/CCLabelBMFont.js +++ b/cocos2d/labels/CCLabelBMFont.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -44,7 +44,7 @@ cc.LABEL_AUTOMATIC_WIDTH = -1; *
  • - scaled
  • *
  • - translated
  • *
  • - tinted
  • - *
  • - chage the opacity
  • + *
  • - change the opacity
  • *
  • - It can be used as part of a menu item.
  • *
  • - anchorPoint can be used to align the "label"
  • *
  • - Supports AngelCode text format
  • @@ -66,12 +66,29 @@ cc.LABEL_AUTOMATIC_WIDTH = -1; * @extends cc.SpriteBatchNode * * @property {String} string - Content string of label - * @property {enum} textAlign - Horizontal Alignment of label, cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT + * @property {Number} textAlign - Horizontal Alignment of label, cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT * @property {Number} boundingWidth - Width of the bounding box of label, the real content width is limited by boundingWidth + * + * @param {String} str + * @param {String} fntFile + * @param {Number} [width=-1] + * @param {Number} [alignment=cc.TEXT_ALIGNMENT_LEFT] + * @param {cc.Point} [imageOffset=cc.p(0,0)] + * + * @example + * // Example 01 + * var label1 = new cc.LabelBMFont("Test case", "test.fnt"); + * + * // Example 02 + * var label2 = new cc.LabelBMFont("test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT); + * + * // Example 03 + * var label3 = new cc.LabelBMFont("This is a \n test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT, cc.p(0,0)); */ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ - RGBAProtocol: true, - + //property string is Getter and Setter. + //property textAlign is Getter and Setter. + //property boundingWidth is Getter and Setter. _opacityModifyRGB: false, _string: "", @@ -93,18 +110,16 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ _reusedChar: null, - //texture RGBA - _displayedOpacity: 255, - _realOpacity: 255, - _displayedColor: null, - _realColor: null, - _cascadeColorEnabled: true, - _cascadeOpacityEnabled: true, - _textureLoaded: false, - _loadedEventListeners: null, _className: "LabelBMFont", + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + return new cc.LabelBMFont.WebGLRenderCmd(this); + else + return new cc.LabelBMFont.CanvasRenderCmd(this); + }, + _setString: function (newString, needUpdateLabel) { if (!needUpdateLabel) { this._string = newString; @@ -121,40 +136,29 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ } if (this._textureLoaded) { this.createFontChars(); - if (needUpdateLabel) this.updateLabel(); } }, /** - * creates a bitmap font atlas with an initial string and the FNT file - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
    + * creates a bitmap font atlas with an initial string and the FNT file. * @param {String} str * @param {String} fntFile * @param {Number} [width=-1] * @param {Number} [alignment=cc.TEXT_ALIGNMENT_LEFT] * @param {cc.Point} [imageOffset=cc.p(0,0)] - * @example - * // Example 01 - * var label1 = new cc.LabelBMFont("Test case", "test.fnt"); - * - * // Example 02 - * var label2 = new cc.LabelBMFont("test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT); - * - * // Example 03 - * var label3 = new cc.LabelBMFont("This is a \n test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT, cc.p(0,0)); */ ctor: function (str, fntFile, width, alignment, imageOffset) { - var self = this; - cc.SpriteBatchNode.prototype.ctor.call(self); - self._imageOffset = cc.p(0, 0); - self._displayedColor = cc.color(255, 255, 255, 255); - self._realColor = cc.color(255, 255, 255, 255); - self._reusedChar = []; - + cc.SpriteBatchNode.prototype.ctor.call(this); + this._imageOffset = cc.p(0, 0); + this._reusedChar = []; + this._cascadeColorEnabled = true; + this._cascadeOpacityEnabled = true; this.initWithString(str, fntFile, width, alignment, imageOffset); }, + /** * return texture is loaded * @returns {boolean} @@ -164,73 +168,18 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** - * add texture loaded event listener + * add texture loaded event listener.
    + * Will execute the callback in the loaded. * @param {Function} callback * @param {Object} target + * @deprecated since 3.1, please use addEventListener instead */ addLoadedEventListener: function (callback, target) { - if (!this._loadedEventListeners) - this._loadedEventListeners = []; - this._loadedEventListeners.push({eventCallback: callback, eventTarget: target}); - }, - - _callLoadedEventCallbacks: function () { - if (!this._loadedEventListeners) - return; - var locListeners = this._loadedEventListeners; - for (var i = 0, len = locListeners.length; i < len; i++) { - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; - }, - - /** - * @param {CanvasRenderingContext2D} ctx - */ - draw: function (ctx) { - cc.SpriteBatchNode.prototype.draw.call(this, ctx); - - //LabelBMFont - Debug draw - if (cc.LABELBMFONT_DEBUG_DRAW) { - var size = this.getContentSize(); - var pos = cc.p(0 | ( -this._anchorPointInPoints.x), 0 | ( -this._anchorPointInPoints.y)); - var vertices = [cc.p(pos.x, pos.y), cc.p(pos.x + size.width, pos.y), cc.p(pos.x + size.width, pos.y + size.height), cc.p(pos.x, pos.y + size.height)]; - cc._drawingUtil.setDrawColor(0, 255, 0, 255); - cc._drawingUtil.drawPoly(vertices, 4, true); - } - }, - - //TODO - /** - * tint this label - * @param {cc.Color} color - */ - setColor: function (color) { - var locDisplayed = this._displayedColor, locRealColor = this._realColor; - if ((locRealColor.r == color.r) && (locRealColor.g == color.g) && (locRealColor.b == color.b) && (locRealColor.a == color.a)) - return; - locDisplayed.r = locRealColor.r = color.r; - locDisplayed.g = locRealColor.g = color.g; - locDisplayed.b = locRealColor.b = color.b; - - if (this._textureLoaded) { - if (this._cascadeColorEnabled) { - var parentColor = cc.color.WHITE; - var locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeColor) - parentColor = locParent.getDisplayedColor(); - this.updateDisplayedColor(parentColor); - } - } - - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } + this.addEventListener("load", callback, target); }, /** - * conforms to cc.RGBAProtocol protocol + * Conforms to cc.RGBAProtocol protocol. * @return {Boolean} */ isOpacityModifyRGB: function () { @@ -238,6 +187,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set whether to support cc.RGBAProtocol protocol * @param {Boolean} opacityModifyRGB */ setOpacityModifyRGB: function (opacityModifyRGB) { @@ -246,130 +196,25 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ if (locChildren) { for (var i = 0; i < locChildren.length; i++) { var node = locChildren[i]; - if (node && node.RGBAProtocol) + if (node) node.opacityModifyRGB = this._opacityModifyRGB; } } }, - getOpacity: function () { - return this._realOpacity; - }, - - getDisplayedOpacity: function () { - return this._displayedOpacity; - }, - - /** - * Override synthesized setOpacity to recurse items - * @param {Number} opacity - */ - setOpacity: function (opacity) { - this._displayedOpacity = this._realOpacity = opacity; - if (this._cascadeOpacityEnabled) { - var parentOpacity = 255; - var locParent = this._parent; - if (locParent && locParent.RGBAProtocol && locParent.cascadeOpacity) - parentOpacity = locParent.getDisplayedOpacity(); - this.updateDisplayedOpacity(parentOpacity); - } - - this._displayedColor.a = this._realColor.a = opacity; - }, - - updateDisplayedOpacity: function (parentOpacity) { - this._displayedOpacity = this._realOpacity * parentOpacity / 255.0; - var locChildren = this._children; - for (var i = 0; i < locChildren.length; i++) { - var locChild = locChildren[i]; - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { - locChild.updateDisplayedOpacity(this._displayedOpacity); - } else { - cc.NodeRGBA.prototype.updateDisplayedOpacity.call(locChild, this._displayedOpacity); - locChild.setNodeDirty(); - } - } - this._changeTextureColor(); - }, - - isCascadeOpacityEnabled: function () { - return false; - }, - - setCascadeOpacityEnabled: function (cascadeOpacityEnabled) { - this._cascadeOpacityEnabled = cascadeOpacityEnabled; - }, - - getColor: function () { - var locRealColor = this._realColor; - return cc.color(locRealColor.r, locRealColor.g, locRealColor.b, locRealColor.a); - }, - - getDisplayedColor: function () { - return this._displayedColor; - }, - - updateDisplayedColor: function (parentColor) { - var locDispColor = this._displayedColor; - var locRealColor = this._realColor; - locDispColor.r = locRealColor.r * parentColor.r / 255.0; - locDispColor.g = locRealColor.g * parentColor.g / 255.0; - locDispColor.b = locRealColor.b * parentColor.b / 255.0; - - var locChildren = this._children; - for (var i = 0; i < locChildren.length; i++) { - var locChild = locChildren[i]; - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { - locChild.updateDisplayedColor(this._displayedColor); - } else { - cc.NodeRGBA.prototype.updateDisplayedColor.call(locChild, this._displayedColor); - locChild.setNodeDirty(); - } - } - this._changeTextureColor(); - }, - _changeTextureColor: function () { - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { - return; - } - var locElement, locTexture = this.texture; - if (locTexture && locTexture.width > 0) { - locElement = locTexture.getHtmlElementObj(); - if (!locElement) - return; - var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); - if (cacheTextureForColor) { - if (locElement instanceof HTMLCanvasElement && !this._rectRotated) - cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor, null, locElement); - else { - locElement = cc.generateTintImage(locElement, cacheTextureForColor, this._displayedColor); - locTexture = new cc.Texture2D(); - locTexture.initWithElement(locElement); - locTexture.handleLoadedTexture(); - this.texture = locTexture; - } - } - } - }, - - isCascadeColorEnabled: function () { - return false; - }, - - setCascadeColorEnabled: function (cascadeColorEnabled) { - this._cascadeColorEnabled = cascadeColorEnabled; + this._renderCmd._changeTextureColor(); }, /** - * init LabelBMFont + * Initialization of the node, please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. */ init: function () { return this.initWithString(null, null, null, null, null); }, /** - * init a bitmap font altas with an initial string and the FNT file + * init a bitmap font atlas with an initial string and the FNT file * @param {String} str * @param {String} fntFile * @param {Number} [width=-1] @@ -379,11 +224,11 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ */ initWithString: function (str, fntFile, width, alignment, imageOffset) { var self = this, theString = str || ""; + var cmd = this._renderCmd; if (self._config) cc.log("cc.LabelBMFont.initWithString(): re-init is no longer supported"); - var texture; if (fntFile) { var newConf = cc.loader.getRes(fntFile); @@ -398,13 +243,13 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ var locIsLoaded = texture.isLoaded(); self._textureLoaded = locIsLoaded; if (!locIsLoaded) { - texture.addLoadedEventListener(function (sender) { + texture.addEventListener("load", function (sender) { var self1 = this; self1._textureLoaded = true; //reset the LabelBMFont self1.initWithTexture(sender, self1._initialString.length); self1.setString(self1._initialString, true); - self1._callLoadedEventCallbacks(); + self1.dispatchEvent("load"); }, self); } } else { @@ -419,25 +264,16 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ self._imageOffset = imageOffset || cc.p(0, 0); self._width = (width == null) ? -1 : width; - self._displayedOpacity = self._realOpacity = 255; - self._displayedColor = cc.color(255, 255, 255, 255); + self._realOpacity = 255; self._realColor = cc.color(255, 255, 255, 255); - self._cascadeOpacityEnabled = true; - self._cascadeColorEnabled = true; self._contentSize.width = 0; self._contentSize.height = 0; self.setAnchorPoint(0.5, 0.5); - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - var locTexture = self.textureAtlas.texture; - self._opacityModifyRGB = locTexture.hasPremultipliedAlpha(); + this._renderCmd._initBatchTexture(); - var reusedChar = self._reusedChar = new cc.Sprite(); - reusedChar.initWithTexture(locTexture, cc.rect(0, 0, 0, 0), false); - reusedChar.batchNode = self; - } self.setString(theString, true); return true; } @@ -449,8 +285,8 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ */ createFontChars: function () { var self = this; - var locContextType = cc._renderType; - var locTexture = (locContextType === cc._RENDER_TYPE_CANVAS) ? self.texture : self.textureAtlas.texture; + var cmd = this._renderCmd; + var locTexture = cmd._texture || self.textureAtlas.texture; var nextFontPositionX = 0; @@ -469,7 +305,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ var i, locCfg = self._config, locKerningDict = locCfg.kerningDict, locCommonH = locCfg.commonHeight, locFontDict = locCfg.fontDefDictionary; for (i = 0; i < stringLen - 1; i++) { - if (locStr.charCodeAt(i) == 10) quantityOfLines++; + if (locStr.charCodeAt(i) === 10) quantityOfLines++; } var totalHeight = locCommonH * quantityOfLines; @@ -478,7 +314,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ var prev = -1; for (i = 0; i < stringLen; i++) { var key = locStr.charCodeAt(i); - if (key == 0) continue; + if (key === 0) continue; if (key === 10) { //new line @@ -500,34 +336,19 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ rect.y += self._imageOffset.y; var fontChar = self.getChildByTag(i); - //var hasSprite = true; - if (!fontChar) { + + if(!fontChar){ fontChar = new cc.Sprite(); - if ((key === 32) && (locContextType === cc._RENDER_TYPE_CANVAS)) rect = cc.rect(0, 0, 0, 0); fontChar.initWithTexture(locTexture, rect, false); fontChar._newTextureWhenChangeColor = true; - self.addChild(fontChar, 0, i); - } else { - if ((key === 32) && (locContextType === cc._RENDER_TYPE_CANVAS)) { - fontChar.setTextureRect(rect, false, cc.size(0, 0)); - } else { - // updating previous sprite - fontChar.setTextureRect(rect, false); - // restore to default in case they were modified - fontChar.visible = true; - } + this.addChild(fontChar, 0, i); + }else{ + this._renderCmd._updateCharTexture(fontChar, rect, key); } + // Apply label properties - fontChar.opacityModifyRGB = self._opacityModifyRGB; - // Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { - fontChar.updateDisplayedColor(self._displayedColor); - fontChar.updateDisplayedOpacity(self._displayedOpacity); - } else { - cc.NodeRGBA.prototype.updateDisplayedColor.call(fontChar, self._displayedColor); - cc.NodeRGBA.prototype.updateDisplayedOpacity.call(fontChar, self._displayedOpacity); - fontChar.setNodeDirty(); - } + fontChar.opacityModifyRGB = this._opacityModifyRGB; + this._renderCmd._updateCharColorAndOpacity(fontChar); var yOffset = locCfg.commonHeight - fontDef.yOffset; var fontPos = cc.p(nextFontPositionX + fontDef.xOffset + fontDef.rect.width * 0.5 + kerningAmount, @@ -542,13 +363,19 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ longestLine = nextFontPositionX; } - tmpSize.width = longestLine; + //If the last character processed has an xAdvance which is less that the width of the characters image, then we need + // to adjust the width of the string to take this into account, or the character will overlap the end of the bounding box + if(fontDef && fontDef.xAdvance < fontDef.rect.width) + tmpSize.width = longestLine - fontDef.xAdvance + fontDef.rect.width; + else + tmpSize.width = longestLine; tmpSize.height = totalHeight; self.setContentSize(cc.sizePixelsToPoints(tmpSize)); }, /** - * update String + * Update String.
    + * Only update this label display string. * @param {Boolean} fromUpdate */ updateString: function (fromUpdate) { @@ -568,7 +395,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** - * get the text of this label + * Gets the text of this label * @return {String} */ getString: function () { @@ -576,7 +403,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** - * set the text + * Set the text * @param {String} newString * @param {Boolean|null} needUpdateLabel */ @@ -584,7 +411,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ newString = String(newString); if (needUpdateLabel == null) needUpdateLabel = true; - if (newString == null || typeof(newString) != "string") + if (newString == null || !cc.isString(newString)) newString = newString + ""; this._initialString = newString; @@ -596,153 +423,148 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** - * @deprecated + * Set the text.
    + * Change this Label display string. + * @deprecated since v3.0 please use .setString * @param label */ setCString: function (label) { this.setString(label, true); }, - /** - * update Label - */ - updateLabel: function () { + // calc the text all with in a line + _getCharsWidth:function (startIndex, endIndex) { + if (endIndex <= 0) + { + return 0; + } + var curTextFirstSprite = this.getChildByTag(startIndex); + var curTextLastSprite = this.getChildByTag(startIndex + endIndex); + return this._getLetterPosXLeft(curTextLastSprite) - this._getLetterPosXLeft(curTextFirstSprite); + }, + + _checkWarp:function (strArr, i, maxWidth, initStringWrapNum) { var self = this; - self.string = self._initialString; + var text = strArr[i]; + var curLength = 0; + for (var strArrIndex = 0; strArrIndex < i; strArrIndex++) + { + curLength += strArr[strArrIndex].length; + } - // Step 1: Make multiline - if (self._width > 0) { - var stringLength = self._string.length; - var multiline_string = []; - var last_word = []; + curLength = curLength + i - initStringWrapNum; // add the wrap line num - var line = 1, i = 0, start_line = false, start_word = false, startOfLine = -1, startOfWord = -1, skip = 0; + var allWidth = self._getCharsWidth(curLength, strArr[i].length - 1); - var characterSprite; - for (var j = 0, lj = self._children.length; j < lj; j++) { - var justSkipped = 0; - while (!(characterSprite = self.getChildByTag(j + skip + justSkipped))) - justSkipped++; - skip += justSkipped; + if (allWidth > maxWidth && text.length > 1) { + var fuzzyLen = text.length * ( maxWidth / allWidth ) | 0; + var tmpText = text.substr(fuzzyLen); + var width = allWidth - this._getCharsWidth(curLength + fuzzyLen, tmpText.length - 1); + var sLine; + var pushNum = 0; - if (i >= stringLength) - break; + //Increased while cycle maximum ceiling. default 100 time + var checkWhile = 0; + + //Exceeded the size + while (width > maxWidth && checkWhile++ < 100) { + fuzzyLen *= maxWidth / width; + fuzzyLen = fuzzyLen | 0; + tmpText = text.substr(fuzzyLen); + width = allWidth - this._getCharsWidth(curLength + fuzzyLen, tmpText.length - 1); + } + + checkWhile = 0; - var character = self._string[i]; - if (!start_word) { - startOfWord = self._getLetterPosXLeft(characterSprite); - start_word = true; + //Find the truncation point + while (width < maxWidth && checkWhile++ < 100) { + if (tmpText) { + var exec = cc.LabelTTF._wordRex.exec(tmpText); + pushNum = exec ? exec[0].length : 1; + sLine = tmpText; } - if (!start_line) { - startOfLine = startOfWord; - start_line = true; + if (self._lineBreakWithoutSpaces) { + pushNum = 0; } + fuzzyLen = fuzzyLen + pushNum; + tmpText = text.substr(fuzzyLen); + width = allWidth - this._getCharsWidth(curLength + fuzzyLen, tmpText.length - 1); + } - // Newline. - if (character.charCodeAt(0) == 10) { - last_word.push('\n'); - multiline_string = multiline_string.concat(last_word); - last_word.length = 0; - start_word = false; - start_line = false; - startOfWord = -1; - startOfLine = -1; - //i+= justSkipped; - j--; - skip -= justSkipped; - line++; - - if (i >= stringLength) - break; - - character = self._string[i]; - if (!startOfWord) { - startOfWord = self._getLetterPosXLeft(characterSprite); - start_word = true; - } - if (!startOfLine) { - startOfLine = startOfWord; - start_line = true; + fuzzyLen -= pushNum; + if (fuzzyLen === 0) { + fuzzyLen = 1; + sLine = sLine.substr(1); + } + + var sText = text.substr(0, fuzzyLen), result; + + //symbol in the first + if (cc.LabelTTF.wrapInspection) { + if (cc.LabelTTF._symbolRex.test(sLine || tmpText)) { + result = cc.LabelTTF._lastWordRex.exec(sText); + pushNum = result ? result[0].length : 0; + if (self._lineBreakWithoutSpaces) { + pushNum = 0; } - i++; - continue; - } + fuzzyLen -= pushNum; - // Whitespace. - if (cc.isspace_unicode(character)) { - last_word.push(character); - multiline_string = multiline_string.concat(last_word); - last_word.length = 0; - start_word = false; - startOfWord = -1; - i++; - continue; + sLine = text.substr(fuzzyLen); + sText = text.substr(0, fuzzyLen); } + } - // Out of bounds. - if (self._getLetterPosXRight(characterSprite) - startOfLine > self._width) { - if (!self._lineBreakWithoutSpaces) { - last_word.push(character); - - var found = multiline_string.lastIndexOf(" "); - if (found != -1) - cc.utf8_trim_ws(multiline_string); - else - multiline_string = []; - - if (multiline_string.length > 0) - multiline_string.push('\n'); - - line++; - start_line = false; - startOfLine = -1; - i++; - } else { - cc.utf8_trim_ws(last_word); - - last_word.push('\n'); - multiline_string = multiline_string.concat(last_word); - last_word.length = 0; - start_word = false; - start_line = false; - startOfWord = -1; - startOfLine = -1; - line++; - - if (i >= stringLength) - break; - - if (!startOfWord) { - startOfWord = self._getLetterPosXLeft(characterSprite); - start_word = true; - } - if (!startOfLine) { - startOfLine = startOfWord; - start_line = true; - } - j--; + //To judge whether a English words are truncated + if (cc.LabelTTF._firsrEnglish.test(sLine)) { + result = cc.LabelTTF._lastEnglish.exec(sText); + if (result && sText !== result[0]) { + pushNum = result[0].length; + if (self._lineBreakWithoutSpaces) { + pushNum = 0; } - } else { - // Character is normal. - last_word.push(character); - i++; + fuzzyLen -= pushNum; + sLine = text.substr(fuzzyLen); + sText = text.substr(0, fuzzyLen); } } + strArr[i] = sLine || tmpText; + strArr.splice(i, 0, sText); + } + }, - multiline_string = multiline_string.concat(last_word); - var len = multiline_string.length; - var str_new = ""; - - for (i = 0; i < len; ++i) - str_new += multiline_string[i]; - - str_new = str_new + String.fromCharCode(0); - //this.updateString(true); - self._setString(str_new, false) + /** + * Update Label.
    + * Update this Label display string and more... + */ + updateLabel: function () { + var self = this; + self.string = self._initialString; + var i, j, characterSprite; + // process string + // Step 1: Make multiline + if (self._width > 0) { + var stringArr = self.string.split('\n'); + var wrapString = ""; + var newWrapNum = 0; + var oldArrLength = 0; + for (i = 0; i < stringArr.length; i++) { + oldArrLength = stringArr.length; + this._checkWarp(stringArr, i, self._width * this._scaleX, newWrapNum); + if (oldArrLength < stringArr.length) { + newWrapNum++; + } + if (i > 0) + { + wrapString += "\n"; + } + wrapString += stringArr[i]; + } + wrapString = wrapString + String.fromCharCode(0); + self._setString(wrapString, false); } // Step 2: Make alignment - if (self._alignment != cc.TEXT_ALIGNMENT_LEFT) { + if (self._alignment !== cc.TEXT_ALIGNMENT_LEFT) { i = 0; var lineNumber = 0; @@ -750,11 +572,11 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ var last_line = []; for (var ctr = 0; ctr < strlen; ctr++) { - if (self._string[ctr].charCodeAt(0) == 10 || self._string[ctr].charCodeAt(0) == 0) { + if (self._string[ctr].charCodeAt(0) === 10 || self._string[ctr].charCodeAt(0) === 0) { var lineWidth = 0; var line_length = last_line.length; // if last line is empty we must just increase lineNumber and work with next line - if (line_length == 0) { + if (line_length === 0) { lineNumber++; continue; } @@ -778,7 +600,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ break; } - if (shift != 0) { + if (shift !== 0) { for (j = 0; j < line_length; j++) { index = i + j + lineNumber; if (index < 0) continue; @@ -800,7 +622,7 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** - * Set text alignment + * Set text alignment. * @param {Number} alignment */ setAlignment: function (alignment) { @@ -813,6 +635,8 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set the bounding width.
    + * max with display width. The exceeding string will be wrapping. * @param {Number} width */ setBoundingWidth: function (width) { @@ -825,6 +649,8 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set the param to change English word warp according to whether the space.
    + * default is false. * @param {Boolean} breakWithoutSpace */ setLineBreakWithoutSpace: function (breakWithoutSpace) { @@ -833,8 +659,10 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set scale.
    + * Input a number, will be decrease or increase the font size.
    * @param {Number} scale - * @param {Number} [scaleY=null] + * @param {Number} [scaleY=null] default is scale */ setScale: function (scale, scaleY) { cc.Node.prototype.setScale.call(this, scale, scaleY); @@ -842,6 +670,9 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set scale of x.
    + * Input a number, will be decrease or increase the font size.
    + * Horizontal scale. * @param {Number} scaleX */ setScaleX: function (scaleX) { @@ -850,6 +681,9 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Set scale of x.
    + * Input a number, will be decrease or increase the font size.
    + * Longitudinal scale. * @param {Number} scaleY */ setScaleY: function (scaleY) { @@ -857,14 +691,14 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ this.updateLabel(); }, - //TODO /** - * set fnt file path + * set fnt file path.
    + * Change the fnt file path. * @param {String} fntFile */ setFntFile: function (fntFile) { var self = this; - if (fntFile != null && fntFile != self._fntFile) { + if (fntFile != null && fntFile !== self._fntFile) { var newConf = cc.loader.getRes(fntFile); if (!newConf) { @@ -879,17 +713,17 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ var locIsLoaded = texture.isLoaded(); self._textureLoaded = locIsLoaded; self.texture = texture; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - self._originalTexture = self.texture; + this._renderCmd._updateFntFileTexture(); if (!locIsLoaded) { - texture.addLoadedEventListener(function (sender) { + texture.addEventListener("load", function (sender) { var self1 = this; self1._textureLoaded = true; self1.texture = sender; self1.createFontChars(); self1._changeTextureColor(); self1.updateLabel(); - self1._callLoadedEventCallbacks(); + + self1.dispatchEvent("load"); }, self); } else { self.createFontChars(); @@ -898,14 +732,20 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ }, /** + * Return the fnt file path. * @return {String} */ getFntFile: function () { return this._fntFile; }, + setTexture: function(texture){ + this._renderCmd.setTexture(texture); + }, + /** - * set the AnchorPoint of the labelBMFont + * Set the AnchorPoint of the labelBMFont.
    + * In order to change the location of label. * @override * @param {cc.Point|Number} point The anchor point of labelBMFont or The anchor point.x of labelBMFont. * @param {Number} [y] The anchor point.y of labelBMFont. @@ -915,21 +755,17 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ this.updateLabel(); }, - _setAnchor: function (p) { - cc.Node.prototype._setAnchor.call(this, p); - this.updateLabel(); - }, _setAnchorX: function (x) { cc.Node.prototype._setAnchorX.call(this, x); this.updateLabel(); }, + _setAnchorY: function (y) { cc.Node.prototype._setAnchorY.call(this, y); this.updateLabel(); }, - _atlasNameFromFntFile: function (fntFile) { - }, + _atlasNameFromFntFile: function (fntFile) {}, _kerningAmountForFirst: function (first, second) { var ret = 0; @@ -948,109 +784,77 @@ cc.LabelBMFont = cc.SpriteBatchNode.extend(/** @lends cc.LabelBMFont# */{ _getLetterPosXRight: function (sp) { return sp.getPositionX() * this._scaleX + (sp._getWidth() * this._scaleX * sp._getAnchorX()); + }, + + //Checking whether the character is a whitespace + _isspace_unicode: function(ch){ + ch = ch.charCodeAt(0); + return ((ch >= 9 && ch <= 13) || ch === 32 || ch === 133 || ch === 160 || ch === 5760 + || (ch >= 8192 && ch <= 8202) || ch === 8232 || ch === 8233 || ch === 8239 + || ch === 8287 || ch === 12288) + }, + + _utf8_trim_ws: function(str){ + var len = str.length; + + if (len <= 0) + return; + + var last_index = len - 1; + + // Only start trimming if the last character is whitespace.. + if (this._isspace_unicode(str[last_index])) { + for (var i = last_index - 1; i >= 0; --i) { + if (this._isspace_unicode(str[i])) { + last_index = i; + } + else { + break; + } + } + this._utf8_trim_from(str, last_index); + } + }, + + //Trims str st str=[0, index) after the operation. + //Return value: the trimmed string. + _utf8_trim_from: function(str, index){ + var len = str.length; + if (index >= len || index < 0) + return; + str.splice(index, len); } }); -var _p = cc.LabelBMFont.prototype; - -// Extended properties -/** @expose */ -_p.opacityModifyRGB; -cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpacityModifyRGB); -/** @expose */ -_p.opacity; -cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); -/** @expose */ -_p.cascadeOpacity; -cc.defineGetterSetter(_p, "cascadeOpacity", _p.isCascadeOpacityEnabled, _p.setCascadeOpacityEnabled); -/** @expose */ -_p.color; -cc.defineGetterSetter(_p, "color", _p.getColor, _p.setColor); -/** @expose */ -_p.cascadeColor; -cc.defineGetterSetter(_p, "cascadeColor", _p.isCascadeColorEnabled, _p.setCascadeColorEnabled); -/** @expose */ -_p.string; -cc.defineGetterSetter(_p, "string", _p.getString, _p._setStringForSetter); -/** @expose */ -_p.boundingWidth; -cc.defineGetterSetter(_p, "boundingWidth", _p._getBoundingWidth, _p.setBoundingWidth); -/** @expose */ -_p.textAlign; -cc.defineGetterSetter(_p, "textAlign", _p._getAlignment, _p.setAlignment); +(function(){ + var p = cc.LabelBMFont.prototype; + cc.EventHelper.prototype.apply(p); + + /** @expose */ + p.string; + cc.defineGetterSetter(p, "string", p.getString, p._setStringForSetter); + /** @expose */ + p.boundingWidth; + cc.defineGetterSetter(p, "boundingWidth", p._getBoundingWidth, p.setBoundingWidth); + /** @expose */ + p.textAlign; + cc.defineGetterSetter(p, "textAlign", p._getAlignment, p.setAlignment); +})(); /** * creates a bitmap font atlas with an initial string and the FNT file + * @deprecated since v3.0 please use new cc.LabelBMFont * @param {String} str * @param {String} fntFile * @param {Number} [width=-1] * @param {Number} [alignment=cc.TEXT_ALIGNMENT_LEFT] * @param {cc.Point} [imageOffset=cc.p(0,0)] * @return {cc.LabelBMFont|Null} - * @example - * // Example 01 - * var label1 = cc.LabelBMFont.create("Test case", "test.fnt"); - * - * // Example 02 - * var label2 = cc.LabelBMFont.create("test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT); - * - * // Example 03 - * var label3 = cc.LabelBMFont.create("This is a \n test case", "test.fnt", 200, cc.TEXT_ALIGNMENT_LEFT, cc.p(0,0)); */ cc.LabelBMFont.create = function (str, fntFile, width, alignment, imageOffset) { return new cc.LabelBMFont(str, fntFile, width, alignment, imageOffset); }; -/** - * @param {String} ch - * @return {Boolean} weather the character is a whitespace character. - */ -cc.isspace_unicode = function (ch) { - ch = ch.charCodeAt(0); - return ((ch >= 9 && ch <= 13) || ch == 32 || ch == 133 || ch == 160 || ch == 5760 - || (ch >= 8192 && ch <= 8202) || ch == 8232 || ch == 8233 || ch == 8239 - || ch == 8287 || ch == 12288) -}; - -/** - * @param {Array} str - */ -cc.utf8_trim_ws = function (str) { - var len = str.length; - - if (len <= 0) - return; - - var last_index = len - 1; - - // Only start trimming if the last character is whitespace.. - if (cc.isspace_unicode(str[last_index])) { - for (var i = last_index - 1; i >= 0; --i) { - if (cc.isspace_unicode(str[i])) { - last_index = i; - } - else { - break; - } - } - cc.utf8_trim_from(str, last_index); - } -}; - -/** - * Trims str st str=[0, index) after the operation. - * Return value: the trimmed string. - * @param {Array} str he string to trim - * @param {Number} index the index to start trimming from. - */ -cc.utf8_trim_from = function (str, index) { - var len = str.length; - if (index >= len || index < 0) - return; - str.splice(index, len); -}; - - cc._fntLoader = { INFO_EXP: /info [^\n]*(\n|$)/gi, COMMON_EXP: /common [^\n]*(\n|$)/gi, @@ -1070,12 +874,19 @@ cc._fntLoader = { var key = tempStr.substring(0, index); var value = tempStr.substring(index + 1); if (value.match(this.INT_EXP)) value = parseInt(value); - else if (value[0] == '"') value = value.substring(1, value.length - 1); + else if (value[0] === '"') value = value.substring(1, value.length - 1); obj[key] = value; } } return obj; }, + + /** + * Parse Fnt string. + * @param fntStr + * @param url + * @returns {{}} + */ parseFnt: function (fntStr, url) { var self = this, fnt = {}; //padding @@ -1086,7 +897,7 @@ cc._fntLoader = { top: parseInt(paddingArr[1]), right: parseInt(paddingArr[2]), bottom: parseInt(paddingArr[3]) - } + }; //common var commonObj = self._parseStrToObj(fntStr.match(self.COMMON_EXP)[0]); @@ -1129,6 +940,13 @@ cc._fntLoader = { return fnt; }, + /** + * load the fnt + * @param realUrl + * @param url + * @param res + * @param cb + */ load: function (realUrl, url, res, cb) { var self = this; cc.loader.loadTxt(realUrl, function (err, txt) { diff --git a/cocos2d/labels/CCLabelBMFontCanvasRenderCmd.js b/cocos2d/labels/CCLabelBMFontCanvasRenderCmd.js new file mode 100644 index 0000000000..2fd0ac9792 --- /dev/null +++ b/cocos2d/labels/CCLabelBMFontCanvasRenderCmd.js @@ -0,0 +1,142 @@ +/**************************************************************************** + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + Use any of these editors to generate BMFonts: + http://glyphdesigner.71squared.com/ (Commercial, Mac OS X) + http://www.n4te.com/hiero/hiero.jnlp (Free, Java) + http://slick.cokeandcode.com/demos/hiero.jnlp (Free, Java) + http://www.angelcode.com/products/bmfont/ (Free, Windows only) + ****************************************************************************/ + +(function(){ + cc.LabelBMFont.CanvasRenderCmd = function(renderableObject){ + cc.SpriteBatchNode.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = cc.LabelBMFont.CanvasRenderCmd.prototype = Object.create(cc.SpriteBatchNode.CanvasRenderCmd.prototype); + proto.constructor = cc.LabelBMFont.CanvasRenderCmd; + + proto.rendering = function(){ + void 0; + }; + + proto._updateCharTexture = function(fontChar, rect, key){ + if (key === 32) { + fontChar.setTextureRect(rect, false, cc.size(0, 0)); + } else { + // updating previous sprite + fontChar.setTextureRect(rect, false); + // restore to default in case they were modified + fontChar.visible = true; + } + }; + + proto._updateCharColorAndOpacity = function(fontChar){ + // Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on + fontChar._displayedColor = this._displayedColor; + fontChar._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); + fontChar._displayedOpacity = this._displayedOpacity; + fontChar._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); + }; + + proto._updateFntFileTexture = function(){ + var node = this._node; + node._originalTexture = node.texture; + }; + + proto.setTexture = function (texture) { + var node = this._node; + var locChildren = node._children; + var locDisplayedColor = this._displayedColor; + for (var i = 0; i < locChildren.length; i++) { + var selChild = locChildren[i]; + var cm = selChild._renderCmd; + var childDColor = cm._displayedColor; + if (this._texture !== cm._texture && (childDColor.r !== locDisplayedColor.r || + childDColor.g !== locDisplayedColor.g || childDColor.b !== locDisplayedColor.b)) + continue; + selChild.texture = texture; + } + this._texture = texture; + }; + + if(cc.sys._supportCanvasNewBlendModes) + proto._changeTextureColor = function(){ + var node = this._node; + var locTexture = node.getTexture(); + if (locTexture && locTexture.getContentSize().width>0) { + var element = this._originalTexture.getHtmlElementObj(); + if(!element) + return; + var locElement = locTexture.getHtmlElementObj(); + var textureRect = cc.rect(0, 0, element.width, element.height); + if (locElement instanceof HTMLCanvasElement && !node._rectRotated){ + cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(element, this._displayedColor, textureRect, locElement); + node.setTexture(locTexture); + } else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(element, this._displayedColor, textureRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.setTexture(locTexture); + } + } + }; + else + proto._changeTextureColor = function () { + var node = this._node; + var locElement, locTexture = node.getTexture(); + if (locTexture && locTexture.getContentSize().width > 0) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); + if (cacheTextureForColor) { + if (locElement instanceof HTMLCanvasElement && !this._rectRotated) { + cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, this._displayedColor, null, locElement); + this.setTexture(locTexture); + } else { + locElement = cc.Sprite.CanvasRenderCmd._generateTintImage(locElement, cacheTextureForColor, this._displayedColor); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.setTexture(locTexture); + } + } + } + }; + + proto._updateChildrenDisplayedOpacity = function(locChild){ + cc.Node.prototype.updateDisplayedOpacity.call(locChild, this._displayedOpacity); + }; + + proto._updateChildrenDisplayedColor = function(locChild){ + cc.Node.prototype.updateDisplayedColor.call(locChild, this._displayedColor); + }; + + proto._initBatchTexture = function(){}; + +})(); \ No newline at end of file diff --git a/cocos2d/labels/CCLabelBMFontWebGLRenderCmd.js b/cocos2d/labels/CCLabelBMFontWebGLRenderCmd.js new file mode 100644 index 0000000000..8d0aee5e13 --- /dev/null +++ b/cocos2d/labels/CCLabelBMFontWebGLRenderCmd.js @@ -0,0 +1,87 @@ +/**************************************************************************** + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + Use any of these editors to generate BMFonts: + http://glyphdesigner.71squared.com/ (Commercial, Mac OS X) + http://www.n4te.com/hiero/hiero.jnlp (Free, Java) + http://slick.cokeandcode.com/demos/hiero.jnlp (Free, Java) + http://www.angelcode.com/products/bmfont/ (Free, Windows only) + ****************************************************************************/ + +(function(){ + cc.LabelBMFont.WebGLRenderCmd = function(renderableObject){ + cc.SpriteBatchNode.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = cc.LabelBMFont.WebGLRenderCmd.prototype = Object.create(cc.SpriteBatchNode.WebGLRenderCmd.prototype); + proto.constructor = cc.LabelBMFont.WebGLRenderCmd; + + proto._updateCharTexture = function(fontChar, rect, key){ + // updating previous sprite + fontChar.setTextureRect(rect, false); + // restore to default in case they were modified + fontChar.visible = true; + }; + + + proto._updateFntFileTexture = function(){}; + + proto._changeTextureColor = function(){}; + + proto._updateChildrenDisplayedOpacity = function(locChild){ + locChild.updateDisplayedOpacity(this._displayedOpacity); + }; + + proto._updateChildrenDisplayedColor = function(locChild){ + locChild.updateDisplayedColor(this._displayedColor); + }; + + proto._initBatchTexture = function(){ + var node = this._node; + var locTexture = node.textureAtlas.texture; + node._opacityModifyRGB = locTexture.hasPremultipliedAlpha(); + + var reusedChar = node._reusedChar = new cc.Sprite(); + reusedChar.initWithTexture(locTexture, cc.rect(0, 0, 0, 0), false); + reusedChar.batchNode = node; + }; + + proto.rendering = function(ctx){ + cc.SpriteBatchNode.WebGLRenderCmd.prototype.rendering.call(this, ctx); + + var node = this._node; + //LabelBMFont - Debug draw + if (cc.LABELBMFONT_DEBUG_DRAW) { + var size = node.getContentSize(); + var pos = cc.p(0 | ( -this._anchorPointInPoints.x), 0 | ( -this._anchorPointInPoints.y)); + var vertices = [cc.p(pos.x, pos.y), cc.p(pos.x + size.width, pos.y), cc.p(pos.x + size.width, pos.y + size.height), cc.p(pos.x, pos.y + size.height)]; + cc._drawingUtil.setDrawColor(0, 255, 0, 255); + cc._drawingUtil.drawPoly(vertices, 4, true); + } + }; + + proto._updateCharColorAndOpacity = function(){}; +})(); \ No newline at end of file diff --git a/cocos2d/menus/CCMenu.js b/cocos2d/menus/CCMenu.js index 90ad1289ef..53c34e6a1f 100644 --- a/cocos2d/menus/CCMenu.js +++ b/cocos2d/menus/CCMenu.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -46,38 +46,29 @@ cc.MENU_HANDLER_PRIORITY = -128; cc.DEFAULT_PADDING = 5; /** - *

    Features and Limitation:
    + *

    Features and Limitation:
    * - You can add MenuItem objects in runtime using addChild:
    * - But the only accepted children are MenuItem objects

    * @class - * @extends cc.LayerRGBA - * - * @property {Boolean} enabled - Indicates whether or not the menu is enabled + * @extends cc.Layer + * @param {...cc.MenuItem|null} menuItems} + * @example + * var layer = new cc.Menu(menuitem1, menuitem2, menuitem3); */ -cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ +cc.Menu = cc.Layer.extend(/** @lends cc.Menu# */{ enabled: false, - _color: null, - _opacity: 0, _selectedItem: null, _state: -1, _touchListener: null, _className: "Menu", /** - * Constructor of cc.Menu - * @constructor - * @function + * Constructor of cc.Menu override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. * @param {...cc.MenuItem|null} menuItems - * - * @example - * // Example - * //there is no limit on how many menu item you can pass in - * var myMenu1 = cc.Menu.create(menuitem1, menuitem2, menuitem3); - * var myMenu2 = cc.Menu.create([menuitem1, menuitem2, menuitem3]); */ ctor: function (menuItems) { - cc.LayerRGBA.prototype.ctor.call(this); + cc.Layer.prototype.ctor.call(this); this._color = cc.color.WHITE; this.enabled = false; this._opacity = 255; @@ -97,9 +88,9 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ cc.log("parameters should not be ending with null in Javascript"); var argc = arguments.length, items; - if (argc == 0) { + if (argc === 0) { items = []; - } else if (argc == 1) { + } else if (argc === 1) { if (menuItems instanceof Array) { items = menuItems; } @@ -114,7 +105,14 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ } this.initWithArray(items); }, - + /** + *

    + * Event callback that is invoked every time when CCMenu enters the 'stage'.
    + * If the CCMenu enters the 'stage' with a transition, this event is called when the transition starts.
    + * During onEnter you can't access a "sister/brother" node.
    + * If you override onEnter, you must call its parent's onEnter function with this._super(). + *

    + */ onEnter: function () { var locListener = this._touchListener; if (!locListener._isRegistered()) @@ -122,55 +120,6 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ cc.Node.prototype.onEnter.call(this); }, - /** - * @return {cc.Color} - */ - getColor: function () { - var locColor = this._color; - return cc.color(locColor.r, locColor.g, locColor.b, locColor.a); - }, - - /** - * @param {cc.Color} color - */ - setColor: function (color) { - var locColor = this._color; - locColor.r = color.r; - locColor.g = color.g; - locColor.b = color.b; - - var locChildren = this._children; - if (locChildren && locChildren.length > 0) { - for (var i = 0; i < locChildren.length; i++) { - locChildren[i].setColor(color); - } - } - - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } - }, - - /** - * @return {Number} - */ - getOpacity: function () { - return this._opacity; - }, - - /** - * @param {Number} opa - */ - setOpacity: function (opa) { - this._opacity = opa; - var locChildren = this._children; - if (locChildren && locChildren.length > 0) { - for (var i = 0; i < locChildren.length; i++) - locChildren[i].setOpacity(opa); - } - this._color.a = opa; - }, - /** * return whether or not the menu will receive events * @return {Boolean} @@ -206,11 +155,11 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ /** * initializes a cc.Menu with a Array of cc.MenuItem objects - * @param {Array} arrayOfItems + * @param {Array} arrayOfItems array Of cc.MenuItem Items * @return {Boolean} */ initWithArray: function (arrayOfItems) { - if (cc.LayerRGBA.prototype.init.call(this)) { + if (cc.Layer.prototype.init.call(this)) { this.enabled = true; // menu in the center of the screen @@ -238,9 +187,10 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ }, /** + * add a child for cc.Menu * @param {cc.Node} child - * @param {Number|Null} [zOrder=] - * @param {Number|Null} [tag=] + * @param {Number|Null} [zOrder=] zOrder for the child + * @param {Number|Null} [tag=] tag for the child */ addChild: function (child, zOrder, tag) { if (!(child instanceof cc.MenuItem)) @@ -365,7 +315,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ if (locChildren && locChildren.length > 0) { for (i = 0, len = locChildren.length; i < len; i++) { var child = locChildren[i]; - if (rowColumns == 0) { + if (rowColumns === 0) { rowColumns = rows[row]; w = winSize.width / (1 + rowColumns); x = w; @@ -390,6 +340,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ }, /** * align menu items in rows + * @param {Number} * @example * // Example * menu.alignItemsInRows(5,3)//this will align items to 2 rows, first row with 5 items, second row with 3 @@ -458,7 +409,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ if (locChildren && locChildren.length > 0) { for (i = 0, len = locChildren.length; i < len; i++) { child = locChildren[i]; - if (columnRows == 0) { + if (columnRows === 0) { columnRows = columns[column]; y = columnHeights[column]; } @@ -484,8 +435,9 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ }, /** - * @param {cc.Node} child - * @param {boolean} cleanup + * remove a child from cc.Menu + * @param {cc.Node} child the child you want to remove + * @param {boolean} cleanup whether to cleanup */ removeChild: function (child, cleanup) { if (child == null) @@ -495,14 +447,14 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ return; } - if (this._selectedItem == child) + if (this._selectedItem === child) this._selectedItem = null; cc.Node.prototype.removeChild.call(this, child, cleanup); }, _onTouchBegan: function (touch, event) { var target = event.getCurrentTarget(); - if (target._state != cc.MENU_STATE_WAITING || !target._visible || !target.enabled) + if (target._state !== cc.MENU_STATE_WAITING || !target._visible || !target.enabled) return false; for (var c = target.parent; c != null; c = c.parent) { @@ -514,6 +466,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ if (target._selectedItem) { target._state = cc.MENU_STATE_TRACKING_TOUCH; target._selectedItem.selected(); + target._selectedItem.setNodeDirty(); return true; } return false; @@ -527,6 +480,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ } if (target._selectedItem) { target._selectedItem.unselected(); + target._selectedItem.setNodeDirty(); target._selectedItem.activate(); } target._state = cc.MENU_STATE_WAITING; @@ -538,8 +492,10 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ cc.log("cc.Menu.onTouchCancelled(): invalid state"); return; } - if (this._selectedItem) + if (this._selectedItem) { target._selectedItem.unselected(); + target._selectedItem.setNodeDirty(); + } target._state = cc.MENU_STATE_WAITING; }, @@ -550,20 +506,29 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ return; } var currentItem = target._itemForTouch(touch); - if (currentItem != target._selectedItem) { - if (target._selectedItem) + if (currentItem !== target._selectedItem) { + if (target._selectedItem) { target._selectedItem.unselected(); + target._selectedItem.setNodeDirty(); + } target._selectedItem = currentItem; - if (target._selectedItem) + if (target._selectedItem) { target._selectedItem.selected(); + target._selectedItem.setNodeDirty(); + } } }, /** - * custom on exit + *

    + * callback that is called every time the cc.Menu leaves the 'stage'.
    + * If the cc.Menu leaves the 'stage' with a transition, this callback is called when the transition finishes.
    + * During onExit you can't access a sibling node.
    + * If you override onExit, you shall call its parent's onExit with this._super(). + *

    */ onExit: function () { - if (this._state == cc.MENU_STATE_TRACKING_TOUCH) { + if (this._state === cc.MENU_STATE_TRACKING_TOUCH) { if (this._selectedItem) { this._selectedItem.unselected(); this._selectedItem = null; @@ -572,10 +537,16 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ } cc.Node.prototype.onExit.call(this); }, - + /** + * only use for jsbinding + * @param value + */ setOpacityModifyRGB: function (value) { }, - + /** + * only use for jsbinding + * @returns {boolean} + */ isOpacityModifyRGB: function () { return false; }, @@ -584,7 +555,7 @@ cc.Menu = cc.LayerRGBA.extend(/** @lends cc.Menu# */{ var touchLocation = touch.getLocation(); var itemChildren = this._children, locItemChild; if (itemChildren && itemChildren.length > 0) { - for (var i = 0; i < itemChildren.length; i++) { + for (var i = itemChildren.length - 1; i >= 0; i--) { locItemChild = itemChildren[i]; if (locItemChild.isVisible() && locItemChild.isEnabled()) { var local = locItemChild.convertToNodeSpace(touchLocation); @@ -608,12 +579,10 @@ _p.enabled; /** * create a new menu + * @deprecated since v3.0, please use new cc.Menu(menuitem1, menuitem2, menuitem3) to create a new menu * @param {...cc.MenuItem|null} menuItems + * todo: need to use new * @return {cc.Menu} - * @example - * // Example - * //there is no limit on how many menu item you can pass in - * var myMenu = cc.Menu.create(menuitem1, menuitem2, menuitem3); */ cc.Menu.create = function (menuItems) { var argc = arguments.length; @@ -621,9 +590,9 @@ cc.Menu.create = function (menuItems) { cc.log("parameters should not be ending with null in Javascript"); var ret; - if (argc == 0) + if (argc === 0) ret = new cc.Menu(); - else if (argc == 1) + else if (argc === 1) ret = new cc.Menu(menuItems); else ret = new cc.Menu(Array.prototype.slice.call(arguments, 0)); diff --git a/cocos2d/menus/CCMenuItem.js b/cocos2d/menus/CCMenuItem.js index e366f25418..b083fca0bf 100644 --- a/cocos2d/menus/CCMenuItem.js +++ b/cocos2d/menus/CCMenuItem.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -31,11 +31,11 @@ cc._globalFontNameRelease = false; /** * Subclass cc.MenuItem (or any subclass) to create your custom cc.MenuItem objects. * @class - * @extends cc.NodeRGBA - * - * @property {Boolean} enabled - Indicate whether item is enabled + * @extends cc.Node + * @param {function|String} callback + * @param {cc.Node} target */ -cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ +cc.MenuItem = cc.Node.extend(/** @lends cc.MenuItem# */{ _enabled: false, _target: null, _callback: null, @@ -43,13 +43,12 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ _className: "MenuItem", /** - * Constructor - * @constructor + * Constructor of cc.MenuItem * @param {function|String} callback * @param {cc.Node} target */ ctor: function (callback, target) { - var nodeP = cc.NodeRGBA.prototype; + var nodeP = cc.Node.prototype; nodeP.ctor.call(this); this._target = null; this._callback = null; @@ -65,16 +64,22 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ }, /** - * MenuItem is selected + * return whether MenuItem is selected * @return {Boolean} */ isSelected: function () { return this._isSelected; }, - + /** + * only use for jsbinding + * @param value + */ setOpacityModifyRGB: function (value) { }, - + /** + * only use for jsbinding + * @returns {boolean} + */ isOpacityModifyRGB: function () { return false; }, @@ -83,7 +88,7 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ * set the target/selector of the menu item * @param {function|String} selector * @param {cc.Node} rec - * @deprecated + * @deprecated since v3.0 */ setTarget: function (selector, rec) { this._target = rec; @@ -91,7 +96,7 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ }, /** - * MenuItem is Enabled + * return whether MenuItem is Enabled * @return {Boolean} */ isEnabled: function () { @@ -107,6 +112,7 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ }, /** + * initializes a cc.MenuItem with callback * @param {function|String} callback * @param {cc.Node} target * @return {Boolean} @@ -133,14 +139,14 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ }, /** - * same as setIsSelected(true) + * set the cc.MenuItem selected same as setIsSelected(true) */ selected: function () { this._isSelected = true; }, /** - * same as setIsSelected(false) + * set the cc.MenuItem unselected same as setIsSelected(false) */ unselected: function () { this._isSelected = false; @@ -164,9 +170,9 @@ cc.MenuItem = cc.NodeRGBA.extend(/** @lends cc.MenuItem# */{ var locTarget = this._target, locCallback = this._callback; if (!locCallback) return; - if (locTarget && (typeof(locCallback) == "string")) { + if (locTarget && cc.isString(locCallback)) { locTarget[locCallback](this); - } else if (locTarget && (typeof(locCallback) == "function")) { + } else if (locTarget && cc.isFunction(locCallback)) { locCallback.call(locTarget, this); } else locCallback(this); @@ -184,6 +190,7 @@ cc.defineGetterSetter(_p, "enabled", _p.isEnabled, _p.setEnabled); /** * creates an empty menu item with target and callback
    * Not recommended to use the base class, should use more defined menu item classes + * @deprecated since v3.0, please use new cc.MenuItem(callback,target) instead * @param {function|String} callback callback * @param {cc.Node} target * @return {cc.MenuItem} @@ -200,19 +207,24 @@ cc.MenuItem.create = function (callback, target) { * - cc.LabelTTF
    * @class * @extends cc.MenuItem + * @param {cc.Node} label + * @param {function|String} selector + * @param {cc.Node} target + * @example + * var menuitemLabel = new cc.MenuItemLabel(label,selector,target); * * @property {String} string - Content string of label item * @property {cc.Node} label - Label of label item - * @property {cc.Color} disabledColor - Color of label when it's diabled + * @property {cc.Color} disabledColor - Color of label when it's disabled */ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ _disabledColor: null, _label: null, - _orginalScale: 0, + _originalScale: 0, _colorBackup: null, /** - * @constructor + * Constructor of cc.MenuItemLabel * @param {cc.Node} label * @param {function|String} selector * @param {cc.Node} target @@ -221,7 +233,6 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ cc.MenuItem.prototype.ctor.call(this, selector, target); this._disabledColor = null; this._label = null; - this._orginalScale = 0; this._colorBackup = null; if (label) { @@ -236,6 +247,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * return the disable color for this cc.MenuItemLabel * @return {cc.Color} */ getDisabledColor: function () { @@ -243,6 +255,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set the disable color for this cc.MenuItemLabel * @param {cc.Color} color */ setDisabledColor: function (color) { @@ -250,7 +263,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** - * return label of MenuItemLabel + * return label of cc.MenuItemLabel * @return {cc.Node} */ getLabel: function () { @@ -258,6 +271,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set a label for cc.MenuItemLabel * @param {cc.Node} label */ setLabel: function (label) { @@ -277,10 +291,11 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set enable value to cc.MenuItemLabel * @param {Boolean} enabled */ setEnabled: function (enabled) { - if (this._enabled != enabled) { + if (this._enabled !== enabled) { var locLabel = this._label; if (!enabled) { this._colorBackup = locLabel.color; @@ -293,6 +308,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set opacity for cc.MenuItemLabel * @param {Number} opacity from 0-255 */ setOpacity: function (opacity) { @@ -300,6 +316,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * return the opacity of cc.MenuItemLabel * @return {Number} */ getOpacity: function () { @@ -307,6 +324,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set the opacity for cc.MenuItemLabel * @param {cc.Color} color */ setColor: function (color) { @@ -314,6 +332,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * return the color of cc.MenuItemLabel * @return {cc.Color} */ getColor: function () { @@ -321,6 +340,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * initializes a cc.MenuItemLabel with a label * @param {cc.Node} label * @param {function|String} selector * @param {cc.Node} target @@ -340,6 +360,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ }, /** + * set the string for cc.MenuItemLabel * @param {String} label */ setString: function (label) { @@ -347,7 +368,10 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ this.width = this._label.width; this.height = this._label.height; }, - + /** + * return the string of cc.MenuItemLabel + * @returns {*|string|_p.string|ret.string|q.string|String} + */ getString: function () { return this._label.string; }, @@ -376,7 +400,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ else this._originalScale = this.scale; - var zoomAction = cc.ScaleTo.create(0.1, this._originalScale * 1.2); + var zoomAction = cc.scaleTo(0.1, this._originalScale * 1.2); zoomAction.setTag(cc.ZOOM_ACTION_TAG); this.runAction(zoomAction); } @@ -389,7 +413,7 @@ cc.MenuItemLabel = cc.MenuItem.extend(/** @lends cc.MenuItemLabel# */{ if (this._enabled) { cc.MenuItem.prototype.unselected.call(this); this.stopActionByTag(cc.ZOOM_ACTION_TAG); - var zoomAction = cc.ScaleTo.create(0.1, this._originalScale); + var zoomAction = cc.scaleTo(0.1, this._originalScale); zoomAction.setTag(cc.ZOOM_ACTION_TAG); this.runAction(zoomAction); } @@ -411,6 +435,7 @@ cc.defineGetterSetter(_p, "label", _p.getLabel, _p.setLabel); /** + * @deprecated since v3.0 ,please use new cc.MenuItemLabel(label,selector,target) instead * @param {cc.Node} label * @param {function|String|Null} [selector=] * @param {cc.Node|Null} [target=] @@ -424,10 +449,20 @@ cc.MenuItemLabel.create = function (label, selector, target) { * Helper class that creates a MenuItemLabel class with a LabelAtlas * @class * @extends cc.MenuItemLabel + * @param {String} value + * @param {String} charMapFile + * @param {Number} itemWidth + * @param {Number} itemHeight + * @param {String} startCharMap a single character + * @param {function|String|Null} callback + * @param {cc.Node|Null} target + * @example + * var menuItem = new cc.MenuItemAtlasFont(param1,param2...); */ cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# */{ /** + * the contructor of cc.MenuItemAtlasFont * @param {String} value * @param {String} charMapFile * @param {Number} itemWidth @@ -439,13 +474,14 @@ cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# ctor: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) { var label; if (value && value.length > 0) { - label = cc.LabelAtlas.create(value, charMapFile, itemWidth, itemHeight, startCharMap); + label = new cc.LabelAtlas(value, charMapFile, itemWidth, itemHeight, startCharMap); } cc.MenuItemLabel.prototype.ctor.call(this, label, callback, target); }, /** + * initializes a cc.MenuItemAtlasFont with string * @param {String} value * @param {String} charMapFile * @param {Number} itemWidth @@ -456,7 +492,7 @@ cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# * @return {Boolean} */ initWithString: function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) { - if (!value || value.length == 0) + if (!value || value.length === 0) throw "cc.MenuItemAtlasFont.initWithString(): value should be non-null and its length should be greater than 0"; var label = new cc.LabelAtlas(); @@ -470,6 +506,7 @@ cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# /** * create menu item from string with font + * @deprecated since v3.0 ,please use new cc.MenuItemAtlasFont() instead. * @param {String} value the text to display * @param {String} charMapFile the character map file * @param {Number} itemWidth @@ -478,12 +515,6 @@ cc.MenuItemAtlasFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemAtlasFont# * @param {function|String|Null} [callback=null] * @param {cc.Node|Null} [target=] * @return {cc.MenuItemAtlasFont} - * @example - * // Example - * var item = cc.MenuItemAtlasFont.create('text to display', 'font.fnt', 12, 32, ' ') - * - * //OR - * var item = cc.MenuItemAtlasFont.create('text to display', 'font.fnt', 12, 32, ' ', game.run, game) */ cc.MenuItemAtlasFont.create = function (value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target) { return new cc.MenuItemAtlasFont(value, charMapFile, itemWidth, itemHeight, startCharMap, callback, target); @@ -493,6 +524,11 @@ cc.MenuItemAtlasFont.create = function (value, charMapFile, itemWidth, itemHeigh * Helper class that creates a CCMenuItemLabel class with a Label * @class * @extends cc.MenuItemLabel + * @param {String} value text for the menu item + * @param {function|String} callback + * @param {cc.Node} target + * @example + * var menuItem = new cc.MenuItemFont(value, callback, target); * * @property {Number} fontSize - Font size of font item * @property {String} fontName - Font name of font item @@ -502,7 +538,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ _fontName: null, /** - * @constructor + * Constructor of cc.MenuItemFont * @param {String} value text for the menu item * @param {function|String} callback * @param {cc.Node} target @@ -512,7 +548,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ if (value && value.length > 0) { this._fontName = cc._globalFontName; this._fontSize = cc._globalFontSize; - label = cc.LabelTTF.create(value, this._fontName, this._fontSize); + label = new cc.LabelTTF(value, this._fontName, this._fontSize); } else { this._fontSize = 0; @@ -523,19 +559,20 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, /** + * initializes cc.MenuItemFont with string * @param {String} value text for the menu item * @param {function|String} callback * @param {cc.Node} target * @return {Boolean} */ initWithString: function (value, callback, target) { - if (!value || value.length == 0) + if (!value || value.length === 0) throw "Value should be non-null and its length should be greater than 0"; this._fontName = cc._globalFontName; this._fontSize = cc._globalFontSize; - var label = cc.LabelTTF.create(value, this._fontName, this._fontSize); + var label = new cc.LabelTTF(value, this._fontName, this._fontSize); if (this.initWithLabel(label, callback, target)) { // do something ? } @@ -543,6 +580,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, /** + * set the font size for cc.MenuItemFont * @param {Number} s */ setFontSize: function (s) { @@ -551,7 +589,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, /** - * + *return the font size of cc.MenuItemFont * @return {Number} */ getFontSize: function () { @@ -559,6 +597,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, /** + * set the font name for cc.MenuItemFont * @param {String} name */ setFontName: function (name) { @@ -567,6 +606,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, /** + * return the font name for cc.MenuItemFont * @return {String} */ getFontName: function () { @@ -574,7 +614,7 @@ cc.MenuItemFont = cc.MenuItemLabel.extend(/** @lends cc.MenuItemFont# */{ }, _recreateLabel: function () { - var label = cc.LabelTTF.create(this._label.string, this._fontName, this._fontSize); + var label = new cc.LabelTTF(this._label.string, this._fontName, this._fontSize); this.setLabel(label); } }); @@ -628,22 +668,11 @@ cc.MenuItemFont.fontName = function () { /** * create a menu item from string + * @deprecated since v3.0, please use new construction instead * @param {String} value the text to display * @param {String|function|Null} callback the callback to run, either in function name or pass in the actual function * @param {cc.Node|Null} target the target to run callback * @return {cc.MenuItemFont} - * @example - * // Example - * var item = cc.MenuItemFont.create("Game start", 'start', Game) - * //creates a menu item from string "Game start", and when clicked, it will run Game.start() - * - * var item = cc.MenuItemFont.create("Game start", game.start, Game)//same as above - * - * var item = cc.MenuItemFont.create("i do nothing")//create a text menu item that does nothing - * - * //you can set font size and name before or after - * cc.MenuItemFont.setFontName('my Fancy Font'); - * cc.MenuItemFont.setFontSize(62); */ cc.MenuItemFont.create = function (value, callback, target) { return new cc.MenuItemFont(value, callback, target); @@ -658,6 +687,19 @@ cc.MenuItemFont.create = function (value, callback, target) { * - disabled image
    * @class * @extends cc.MenuItem + * @param {Image|Null} normalSprite normal state image + * @param {Image|Null} selectedSprite selected state image + * @param {Image|cc.Node|Null} three disabled state image OR target node + * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node + * @param {String|function|Null} five callback function name in string or actual function + * + * @example + * var item = new cc.MenuItemSprite(normalImage)//create a menu item from a sprite with no functionality + * var item = new cc.MenuItemSprite(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked + * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image + * var item = new cc.MenuItemSprite(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback() + * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode) + * //same as above, but with disabled image, and passing in callback function * * @property {cc.Sprite} normalImage - Sprite in normal state * @property {cc.Sprite} selectedImage - Sprite in selected state @@ -669,21 +711,12 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ _disabledImage: null, /** - * @constructor + * Constructor of cc.MenuItemSprite * @param {Image|Null} normalSprite normal state image * @param {Image|Null} selectedSprite selected state image * @param {Image|cc.Node|Null} three disabled state image OR target node * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node * @param {String|function|Null} five callback function name in string or actual function - * - * @example - * // Example - * var item = new cc.MenuItemSprite(normalImage)//create a menu item from a sprite with no functionality - * var item = new cc.MenuItemSprite(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked - * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image - * var item = new cc.MenuItemSprite(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback() - * var item = new cc.MenuItemSprite(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode) - * //same as above, but with disabled image, and passing in callback function */ ctor: function (normalSprite, selectedSprite, three, four, five) { cc.MenuItem.prototype.ctor.call(this); @@ -692,29 +725,30 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ this._disabledImage = null; if (selectedSprite !== undefined) { - normalSprite = normalSprite; - selectedSprite = selectedSprite; + //normalSprite = normalSprite; + //selectedSprite = selectedSprite; var disabledImage, target, callback; //when you send 4 arguments, five is undefined if (five !== undefined) { disabledImage = three; callback = four; target = five; - } else if (four !== undefined && typeof four === "function") { + } else if (four !== undefined && cc.isFunction(four)) { disabledImage = three; callback = four; - } else if (four !== undefined && typeof three === "function") { + } else if (four !== undefined && cc.isFunction(three)) { target = four; callback = three; - disabledImage = selectedSprite; + disabledImage = null; } else if (three === undefined) { - disabledImage = selectedSprite; + disabledImage = null; } this.initWithNormalSprite(normalSprite, selectedSprite, disabledImage, callback, target); } }, /** + * return the normal status image(cc.Sprite) * @return {cc.Sprite} */ getNormalImage: function () { @@ -722,10 +756,11 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set the normal status image(cc.Sprite) * @param {cc.Sprite} normalImage */ setNormalImage: function (normalImage) { - if (this._normalImage == normalImage) { + if (this._normalImage === normalImage) { return; } if (normalImage) { @@ -743,7 +778,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ this._updateImagesVisibility(); if (normalImage.textureLoaded && !normalImage.textureLoaded()) { - normalImage.addLoadedEventListener(function (sender) { + normalImage.addEventListener("load", function (sender) { this.width = sender.width; this.height = sender.height; }, this); @@ -751,6 +786,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * return the selected status image(cc.Sprite) of cc.MenuItemSprite * @return {cc.Sprite} */ getSelectedImage: function () { @@ -758,10 +794,11 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set the selected status image(cc.Sprite) * @param {cc.Sprite} selectedImage */ setSelectedImage: function (selectedImage) { - if (this._selectedImage == selectedImage) + if (this._selectedImage === selectedImage) return; if (selectedImage) { @@ -779,6 +816,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * return the disabled status of cc.MenuItemSprite * @return {cc.Sprite} */ getDisabledImage: function () { @@ -786,10 +824,11 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set the disabled status image(cc.Sprite) * @param {cc.Sprite} disabledImage */ setDisabledImage: function (disabledImage) { - if (this._disabledImage == disabledImage) + if (this._disabledImage === disabledImage) return; if (disabledImage) { @@ -806,6 +845,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * initializes cc.MenuItemSprite with a cc.Sprite * @param {cc.Node} normalSprite * @param {cc.Node} selectedSprite * @param {cc.Node} disabledSprite @@ -824,7 +864,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ this.height = locNormalImage.height; if (locNormalImage.textureLoaded && !locNormalImage.textureLoaded()) { - locNormalImage.addLoadedEventListener(function (sender) { + locNormalImage.addEventListener("load", function (sender) { this.width = sender.width; this.height = sender.height; this.cascadeColor = true; @@ -838,6 +878,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set the color for cc.MenuItemSprite * @param {cc.Color} color */ setColor: function (color) { @@ -851,6 +892,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * return the color of cc.MenuItemSprite * @return {cc.Color} */ getColor: function () { @@ -858,6 +900,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set the opacity for cc.MenuItemSprite * @param {Number} opacity 0 - 255 */ setOpacity: function (opacity) { @@ -871,6 +914,7 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * return the opacity of cc.MenuItemSprite * @return {Number} opacity from 0 - 255 */ getOpacity: function () { @@ -911,10 +955,11 @@ cc.MenuItemSprite = cc.MenuItem.extend(/** @lends cc.MenuItemSprite# */{ }, /** + * set cc.MenuItemSprite enable to receive the touch event * @param {Boolean} bEnabled */ setEnabled: function (bEnabled) { - if (this._enabled != bEnabled) { + if (this._enabled !== bEnabled) { cc.MenuItem.prototype.setEnabled.call(this, bEnabled); this._updateImagesVisibility(); } @@ -962,24 +1007,13 @@ cc.defineGetterSetter(_p, "disabledImage", _p.getDisabledImage, _p.setDisabledIm /** * create a menu item from sprite + * @deprecated since v3.0 please use new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five) instead * @param {Image} normalSprite normal state image * @param {Image|Null} selectedSprite selected state image * @param {Image|cc.Node|Null} three disabled state image OR target node * @param {String|function|cc.Node|Null} four callback function name in string or actual function, OR target Node * @param {String|function|Null} five callback function name in string or actual function * @return {cc.MenuItemSprite} - * @example - * // Example - * var item = cc.MenuItemSprite.create(normalImage)//create a menu item from a sprite with no functionality - * - * var item = cc.MenuItemSprite.create(normalImage, selectedImage)//create a menu Item, nothing will happen when clicked - * - * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage)//same above, but with disabled state image - * - * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, 'callback', targetNode)//create a menu item, when clicked runs targetNode.callback() - * - * var item = cc.MenuItemSprite.create(normalImage, SelectedImage, disabledImage, targetNode.callback, targetNode) - * //same as above, but with disabled image, and passing in callback function */ cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, five) { return new cc.MenuItemSprite(normalSprite, selectedSprite, three, four, five || undefined); @@ -995,11 +1029,18 @@ cc.MenuItemSprite.create = function (normalSprite, selectedSprite, three, four, * For best results try that all images are of the same size
    * @class * @extends cc.MenuItemSprite + * @param {string|null} normalImage + * @param {string|null} selectedImage + * @param {string|null} disabledImage + * @param {function|string|null} callback + * @param {cc.Node|null} target + * @example + * var menuItem = new cc.MenuItemImage(normalImage, selectedImage, three, four, five); */ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ /** - * @constructor + * Constructor of cc.MenuItemImage * @param {string|null} normalImage * @param {string|null} selectedImage * @param {string|null} disabledImage @@ -1017,9 +1058,9 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ cc.MenuItemSprite.prototype.ctor.call(this); } else { - normalSprite = cc.Sprite.create(normalImage); + normalSprite = new cc.Sprite(normalImage); selectedImage && - (selectedSprite = cc.Sprite.create(selectedImage)); + (selectedSprite = new cc.Sprite(selectedImage)); if (four === undefined) { callback = three; } @@ -1028,7 +1069,7 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ target = four; } else if (five) { - disabledSprite = cc.Sprite.create(three); + disabledSprite = new cc.Sprite(three); callback = four; target = five; } @@ -1041,7 +1082,7 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ * @param {cc.SpriteFrame} frame */ setNormalSpriteFrame: function (frame) { - this.setNormalImage(cc.Sprite.create(frame)); + this.setNormalImage(new cc.Sprite(frame)); }, /** @@ -1049,7 +1090,7 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ * @param {cc.SpriteFrame} frame */ setSelectedSpriteFrame: function (frame) { - this.setSelectedImage(cc.Sprite.create(frame)); + this.setSelectedImage(new cc.Sprite(frame)); }, /** @@ -1057,10 +1098,11 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ * @param {cc.SpriteFrame} frame */ setDisabledSpriteFrame: function (frame) { - this.setDisabledImage(cc.Sprite.create(frame)); + this.setDisabledImage(new cc.Sprite(frame)); }, /** + * initializes a cc.MenuItemImage * @param {string|null} normalImage * @param {string|null} selectedImage * @param {string|null} disabledImage @@ -1074,13 +1116,13 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ var disabledSprite = null; if (normalImage) { - normalSprite = cc.Sprite.create(normalImage); + normalSprite = new cc.Sprite(normalImage); } if (selectedImage) { - selectedSprite = cc.Sprite.create(selectedImage); + selectedSprite = new cc.Sprite(selectedImage); } if (disabledImage) { - disabledSprite = cc.Sprite.create(disabledImage); + disabledSprite = new cc.Sprite(disabledImage); } return this.initWithNormalSprite(normalSprite, selectedSprite, disabledSprite, callback, target); } @@ -1088,19 +1130,13 @@ cc.MenuItemImage = cc.MenuItemSprite.extend(/** @lends cc.MenuItemImage# */{ /** * creates a new menu item image + * @deprecated since v3.0, please use new cc.MenuItemImage(normalImage, selectedImage, three, four, five) instead. * @param {String} normalImage file name for normal state * @param {String} selectedImage image for selected state * @param {String|cc.Node} three Disabled image OR callback function * @param {String|function|Null} [four] callback function, either name in string or pass the whole function OR the target * @param {cc.Node|String|function|Null} [five] cc.Node target to run callback when clicked * @return {cc.MenuItemImage} - * @example - * // Example - * //create a dom menu item with normal and selected state, when clicked it will run the run function from gameScene object - * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'run', gameScene) - * - * //same as above, but pass in the actual function and disabled image - * var item = cc.MenuItemImage.create('normal.png', 'selected.png', 'disabled.png', gameScene.run, gameScene) */ cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, five) { return new cc.MenuItemImage(normalImage, selectedImage, three, four, five); @@ -1115,6 +1151,17 @@ cc.MenuItemImage.create = function (normalImage, selectedImage, three, four, fiv * * @property {Array} subItems - Sub items * @property {Number} selectedIndex - Index of selected sub item + * + *@example + * // Example + * //create a toggle item with 2 menu items (which you can then toggle between them later) + * var toggler = new cc.MenuItemToggle( new cc.MenuItemFont("On"), new cc.MenuItemFont("Off"), this.callback, this) + * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems + * + * //if you pass only 1 variable, then it must be a cc.MenuItem + * var notYetToggler = new cc.MenuItemToggle(cc.MenuItemFont("On"));//it is useless right now, until you add more stuff to it + * notYetToggler.addSubItem(new cc.MenuItemFont("Off")); + * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else) */ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ subItems: null, @@ -1124,51 +1171,23 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ _color: null, /** - * @constructor - * @example - * // Example - * //create a toggle item with 2 menu items (which you can then toggle between them later) - * var toggler = new cc.MenuItemToggle( cc.MenuItemFont.create("On"), cc.MenuItemFont.create("Off"), this.callback, this) - * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems - * - * //if you pass only 1 variable, then it must be a cc.MenuItem - * var notYetToggler = new cc.MenuItemToggle(cc.MenuItemFont.create("On"));//it is useless right now, until you add more stuff to it - * notYetToggler.addSubItem(cc.MenuItemFont.create("Off")); - * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else) - */ + * Constructor of cc.MenuItemToggle + */ ctor: function (/*Multiple arguments follow*/) { - var argc = arguments.length, callback, target; - // passing callback. - if (typeof arguments[argc - 2] === 'function') { - callback = arguments[argc - 2]; - target = arguments[argc - 1]; - argc = argc - 2; - } else if (typeof arguments[argc - 1] === 'function') { - callback = arguments[argc - 1]; - argc = argc - 1; - } - cc.MenuItem.prototype.ctor.call(this, callback, target); + cc.MenuItem.prototype.ctor.call(this); this._selectedIndex = 0; this.subItems = []; this._opacity = 0; this._color = cc.color.WHITE; - if (argc > 0) { - var locSubItems = this.subItems; - locSubItems.length = 0; - for (var i = 0; i < argc; i++) { - if (arguments[i]) - locSubItems.push(arguments[i]); - } - this._selectedIndex = cc.UINT_MAX; - this.setSelectedIndex(0); - this.setCascadeColorEnabled(true); - this.setCascadeOpacityEnabled(true); - } + if(arguments.length > 0) + this.initWithItems(Array.prototype.slice.apply(arguments)); + }, /** + * return the opacity of cc.MenuItemToggle * @return {Number} */ getOpacity: function () { @@ -1176,6 +1195,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * set the opacity for cc.MenuItemToggle * @param {Number} opacity */ setOpacity: function (opacity) { @@ -1189,6 +1209,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * return the color of cc.MenuItemToggle * @return {cc.Color} */ getColor: function () { @@ -1197,6 +1218,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * set the color for cc.MenuItemToggle * @param {cc.Color} Color */ setColor: function (color) { @@ -1217,6 +1239,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * return the index of selected * @return {Number} */ getSelectedIndex: function () { @@ -1224,10 +1247,11 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * set the seleceted index for cc.MenuItemToggle * @param {Number} SelectedIndex */ setSelectedIndex: function (SelectedIndex) { - if (SelectedIndex != this._selectedIndex) { + if (SelectedIndex !== this._selectedIndex) { this._selectedIndex = SelectedIndex; var currItem = this.getChildByTag(cc.CURRENT_ITEM); if (currItem) @@ -1243,7 +1267,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** - * similar to get children + * similar to get children,return the sumItem array. * @return {Array} */ getSubItems: function () { @@ -1251,6 +1275,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * set the subitem for cc.MenuItemToggle * @param {cc.MenuItem} subItems */ setSubItems: function (subItems) { @@ -1258,6 +1283,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * initializes a cc.MenuItemToggle with items * @param {cc.MenuItem} args[0...last-2] the rest in the array are cc.MenuItems * @param {function|String} args[last-1] the second item in the args array is the callback * @param {cc.Node} args[last] the first item in the args array is a target @@ -1266,10 +1292,10 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ initWithItems: function (args) { var l = args.length; // passing callback. - if (typeof args[args.length - 2] === 'function') { + if (cc.isFunction(args[args.length - 2])) { this.initWithCallback(args[args.length - 2], args[args.length - 1]); l = l - 2; - } else if (typeof args[args.length - 1] === 'function') { + } else if (cc.isFunction(args[args.length - 1])) { this.initWithCallback(args[args.length - 1], null); l = l - 1; } else { @@ -1292,6 +1318,7 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * add the subitem for cc.MenuItemToggle * @param {cc.MenuItem} item */ addSubItem: function (item) { @@ -1327,10 +1354,11 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** + * set the enable status for cc.MenuItemToggle * @param {Boolean} enabled */ setEnabled: function (enabled) { - if (this._enabled != enabled) { + if (this._enabled !== enabled) { cc.MenuItem.prototype.setEnabled.call(this, enabled); var locItems = this.subItems; if (locItems && locItems.length > 0) { @@ -1341,13 +1369,29 @@ cc.MenuItemToggle = cc.MenuItem.extend(/** @lends cc.MenuItemToggle# */{ }, /** - * returns the selected item + * returns the selected item (deprecated in -x, please use getSelectedItem instead.) * @return {cc.MenuItem} */ selectedItem: function () { return this.subItems[this._selectedIndex]; }, + /** + * returns the selected item. + * @return {cc.MenuItem} + */ + getSelectedItem: function() { + return this.subItems[this._selectedIndex]; + }, + + /** + * *

    + * Event callback that is invoked every time when cc.MenuItemToggle enters the 'stage'.
    + * If the cc.MenuItemToggle enters the 'stage' with a transition, this event is called when the transition starts.
    + * During onEnter you can't access a "sister/brother" node.
    + * If you override onEnter, you must call its parent's onEnter function with this._super(). + *

    + */ onEnter: function () { cc.Node.prototype.onEnter.call(this); this.setSelectedIndex(this._selectedIndex); @@ -1365,18 +1409,9 @@ cc.defineGetterSetter(_p, "selectedIndex", _p.getSelectedIndex, _p.setSelectedIn /** * create a simple container class that "toggles" it's inner items
    * The inner items can be any MenuItem + * @deprecated since v3.0 please use new cc.MenuItemToggle(params) instead * @return {cc.MenuItemToggle} * @example - * // Example - * - * //create a toggle item with 2 menu items (which you can then toggle between them later) - * var toggler = cc.MenuItemToggle.create( cc.MenuItemFont.create("On"), cc.MenuItemFont.create("Off"), this.callback, this) - * //Note: the first param is the target, the second is the callback function, afterwards, you can pass in any number of menuitems - * - * //if you pass only 1 variable, then it must be a cc.MenuItem - * var notYetToggler = cc.MenuItemToggle.create(cc.MenuItemFont.create("On"));//it is useless right now, until you add more stuff to it - * notYetToggler.addSubItem(cc.MenuItemFont.create("Off")); - * //this is useful for constructing a toggler without a callback function (you wish to control the behavior from somewhere else) */ cc.MenuItemToggle.create = function (/*Multiple arguments follow*/) { if ((arguments.length > 0) && (arguments[arguments.length - 1] == null)) diff --git a/cocos2d/motion-streak/CCMotionStreak.js b/cocos2d/motion-streak/CCMotionStreak.js index 13254d9a79..85b43531dd 100644 --- a/cocos2d/motion-streak/CCMotionStreak.js +++ b/cocos2d/motion-streak/CCMotionStreak.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2008-2009 Jason Booth http://www.cocos2d-x.org @@ -34,13 +34,16 @@ * length is the how many pixels the texture is stretched across. The texture
    * is vertically aligned along the streak segment. * @class - * @extends cc.NodeRGBA + * @extends cc.Node * * @property {cc.Texture2D} texture - Texture used for the motion streak. * @property {Boolean} fastMode - Indicate whether use fast mode. * @property {Boolean} startingPositionInitialized - Indicate whether starting position initialized. + * @example + * //example + * new cc.MotionStreak(2, 3, 32, cc.color.GREEN, s_streak); */ -cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ +cc.MotionStreak = cc.Node.extend(/** @lends cc.MotionStreak# */{ texture:null, fastMode:false, startingPositionInitialized:false, @@ -55,7 +58,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ _nuPoints:0, _previousNuPoints:0, - /** Pointers */ + /* Pointers */ _pointVertexes:null, _pointState:null, @@ -70,8 +73,8 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ _className:"MotionStreak", /** - * creates and initializes a motion streak with fade in seconds, minimum segments, stroke's width, color, texture filename or texture - * @constructor + * creates and initializes a motion streak with fade in seconds, minimum segments, stroke's width, color, texture filename or texture
    + * Constructor of cc.MotionStreak * @param {Number} fade time to fade * @param {Number} minSeg minimum segment size * @param {Number} stroke stroke's width @@ -79,10 +82,9 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ * @param {string|cc.Texture2D} texture texture filename or texture */ ctor: function (fade, minSeg, stroke, color, texture) { - cc.NodeRGBA.prototype.ctor.call(this); + cc.Node.prototype.ctor.call(this); this._positionR = cc.p(0, 0); this._blendFunc = new cc.BlendFunc(cc.SRC_ALPHA, cc.ONE_MINUS_SRC_ALPHA); - this._vertexWebGLBuffer = cc._renderContext.createBuffer(); this.fastMode = false; this.startingPositionInitialized = false; @@ -115,6 +117,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Gets the texture. * @return {cc.Texture2D} */ getTexture:function () { @@ -122,14 +125,16 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Set the texture. * @param {cc.Texture2D} texture */ setTexture:function (texture) { - if (this.texture != texture) + if (this.texture !== texture) this.texture = texture; }, /** + * Gets the blend func. * @return {cc.BlendFunc} */ getBlendFunc:function () { @@ -137,6 +142,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Set the blend func. * @param {Number} src * @param {Number} dst */ @@ -149,32 +155,45 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ } }, + /** + * Gets opacity. + * @warning cc.MotionStreak.getOpacity has not been supported. + * @returns {number} + */ getOpacity:function () { cc.log("cc.MotionStreak.getOpacity has not been supported."); return 0; }, + /** + * Set opacity. + * @warning cc.MotionStreak.setOpacity has not been supported. + * @param opacity + */ setOpacity:function (opacity) { cc.log("cc.MotionStreak.setOpacity has not been supported."); }, + /** + * set opacity modify RGB. + * @warning cc.MotionStreak.setOpacityModifyRGB has not been supported. + * @param value + */ setOpacityModifyRGB:function (value) { }, + /** + * Checking OpacityModifyRGB. + * @returns {boolean} + */ isOpacityModifyRGB:function () { return false; }, - onExit:function(){ - cc.Node.prototype.onExit.call(this); - if(this._verticesBuffer) - cc._renderContext.deleteBuffer(this._verticesBuffer); - if(this._texCoordsBuffer) - cc._renderContext.deleteBuffer(this._texCoordsBuffer); - if(this._colorPointerBuffer) - cc._renderContext.deleteBuffer(this._colorPointerBuffer); - }, - + /** + * Checking fast mode. + * @returns {boolean} + */ isFastMode:function () { return this.fastMode; }, @@ -187,14 +206,38 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ this.fastMode = fastMode; }, + /** + * Checking starting position initialized. + * @returns {boolean} + */ isStartingPositionInitialized:function () { return this.startingPositionInitialized; }, + /** + * Set Starting Position Initialized. + * @param {Boolean} startingPositionInitialized + */ setStartingPositionInitialized:function (startingPositionInitialized) { this.startingPositionInitialized = startingPositionInitialized; }, + /** + * Get stroke. + * @returns {Number} stroke + */ + getStroke:function () { + return this._stroke; + }, + + /** + * Set stroke. + * @param {Number} stroke + */ + setStroke:function (stroke) { + this._stroke = stroke; + }, + /** * initializes a motion streak with fade in seconds, minimum segments, stroke's width, color and texture filename or texture * @param {Number} fade time to fade @@ -208,7 +251,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ if(!texture) throw "cc.MotionStreak.initWithFade(): Invalid filename or texture"; - if (typeof(texture) === "string") + if (cc.isString(texture)) texture = cc.textureCache.addImage(texture); cc.Node.prototype.setPosition.call(this, cc.p(0,0)); @@ -218,13 +261,14 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ this.startingPositionInitialized = false; this.fastMode = true; - this._minSeg = (minSeg == -1.0) ? (stroke / 5.0) : minSeg; + this._minSeg = (minSeg === -1.0) ? (stroke / 5.0) : minSeg; this._minSeg *= this._minSeg; this._stroke = stroke; this._fadeDelta = 1.0 / fade; var locMaxPoints = (0 | (fade * 60)) + 2; + this._maxPoints = locMaxPoints; this._nuPoints = 0; this._pointState = new Float32Array(locMaxPoints); this._pointVertexes = new Float32Array(locMaxPoints * 2); @@ -232,9 +276,6 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ this._vertices = new Float32Array(locMaxPoints * 4); this._texCoords = new Float32Array(locMaxPoints * 4); this._colorPointer = new Uint8Array(locMaxPoints * 8); - this._maxPoints = locMaxPoints; - - var gl = cc._renderContext; this._verticesBuffer = gl.createBuffer(); this._texCoordsBuffer = gl.createBuffer(); @@ -244,9 +285,6 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ this._blendFunc.src = gl.SRC_ALPHA; this._blendFunc.dst = gl.ONE_MINUS_SRC_ALPHA; - // shader program - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); - this.texture = texture; this.color = color; this.scheduleUpdate(); @@ -286,8 +324,10 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** - * @override - * @param {cc.Point} position + * Set the position.
    + * + * @param {cc.Point|Number} position + * @param {Number} [yValue=undefined] If not exists, the first parameter must be cc.Point. */ setPosition:function (position, yValue) { this.startingPositionInitialized = true; @@ -301,6 +341,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Gets the position.x * @return {Number} */ getPositionX:function () { @@ -308,6 +349,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Set the position.x * @param {Number} x */ setPositionX:function (x) { @@ -317,6 +359,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Gets the position.y * @return {Number} */ getPositionY:function () { @@ -324,6 +367,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** + * Set the position.y * @param {Number} y */ setPositionY:function (y) { @@ -333,49 +377,19 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ }, /** - * @override - * @param {WebGLRenderingContext} ctx - */ - draw:function (ctx) { - if (this._nuPoints <= 1) - return; - - if(this.texture && this.texture.isLoaded()){ - ctx = ctx || cc._renderContext; - cc.nodeDrawSetup(this); - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - - cc.glBindTexture2D(this.texture); - - //position - ctx.bindBuffer(ctx.ARRAY_BUFFER, this._verticesBuffer); - ctx.bufferData(ctx.ARRAY_BUFFER, this._vertices, ctx.DYNAMIC_DRAW); - ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, ctx.FLOAT, false, 0, 0); - - //texcoords - ctx.bindBuffer(ctx.ARRAY_BUFFER, this._texCoordsBuffer); - ctx.bufferData(ctx.ARRAY_BUFFER, this._texCoords, ctx.DYNAMIC_DRAW); - ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, ctx.FLOAT, false, 0, 0); - - //colors - ctx.bindBuffer(ctx.ARRAY_BUFFER, this._colorPointerBuffer); - ctx.bufferData(ctx.ARRAY_BUFFER, this._colorPointer, ctx.DYNAMIC_DRAW); - ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, ctx.UNSIGNED_BYTE, true, 0, 0); - - ctx.drawArrays(ctx.TRIANGLE_STRIP, 0, this._nuPoints * 2); - cc.g_NumberOfDraws ++; - } - }, - - /** - * @override + *

    schedules the "update" method.
    + * It will use the order number 0. This method will be called every frame.
    + * Scheduled methods with a lower order value will be called before the ones that have a higher order value.
    + * Only one "update" method could be scheduled per node.

    * @param {Number} delta */ update:function (delta) { if (!this.startingPositionInitialized) return; + //TODO update the color (need move to render cmd) + this._renderCmd._updateDisplayColor(); + delta *= this._fadeDelta; var newIdx, newIdx2, i, i2; @@ -434,7 +448,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ else if (locNuPoints > 0) { var a1 = cc.pDistanceSQ(cc.p(locPointVertexes[(locNuPoints - 1) * 2], locPointVertexes[(locNuPoints - 1) * 2 + 1]), this._positionR) < this._minSeg; - var a2 = (locNuPoints == 1) ? false : (cc.pDistanceSQ( + var a2 = (locNuPoints === 1) ? false : (cc.pDistanceSQ( cc.p(locPointVertexes[(locNuPoints - 2) * 2], locPointVertexes[(locNuPoints - 2) * 2 + 1]), this._positionR) < (this._minSeg * 2.0)); if (a1 || a2) appendNewPoint = false; @@ -448,7 +462,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ // Color assignment var offset = locNuPoints * 8; - var locDisplayedColor = this._displayedColor; + var locDisplayedColor = this.getDisplayedColor(); locColorPointer[offset] = locDisplayedColor.r; locColorPointer[offset + 1] = locDisplayedColor.g; locColorPointer[offset + 2] = locDisplayedColor.b; @@ -475,7 +489,7 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ cc.vertexLineToPolygon(locPointVertexes, this._stroke, this._vertices, 0, locNuPoints); // Updated Tex Coords only if they are different than previous step - if (locNuPoints && this._previousNuPoints != locNuPoints) { + if (locNuPoints && this._previousNuPoints !== locNuPoints) { var texDelta = 1.0 / locNuPoints; var locTexCoords = this._texCoords; for (i = 0; i < locNuPoints; i++) { @@ -490,17 +504,29 @@ cc.MotionStreak = cc.NodeRGBA.extend(/** @lends cc.MotionStreak# */{ } this._nuPoints = locNuPoints; + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + return new cc.MotionStreak.WebGLRenderCmd(this); + else + return null; //MotionStreak doesn't support Canvas mode } }); /** - * creates and initializes a motion streak with fade in seconds, minimum segments, stroke's width, color, texture filename or texture + * Please use new cc.MotionStreak instead.
    + * Creates and initializes a motion streak with fade in seconds, minimum segments, stroke's width, color, texture filename or texture + * @deprecated since v3.0 please use new cc.MotionStreak instead. * @param {Number} fade time to fade * @param {Number} minSeg minimum segment size * @param {Number} stroke stroke's width * @param {Number} color * @param {string|cc.Texture2D} texture texture filename or texture * @return {cc.MotionStreak} + * @example + * //example + * new cc.MotionStreak(2, 3, 32, cc.color.GREEN, s_streak); */ cc.MotionStreak.create = function (fade, minSeg, stroke, color, texture) { return new cc.MotionStreak(fade, minSeg, stroke, color, texture); diff --git a/cocos2d/motion-streak/CCMotionStreakWebGLRenderCmd.js b/cocos2d/motion-streak/CCMotionStreakWebGLRenderCmd.js new file mode 100644 index 0000000000..45ab07cafd --- /dev/null +++ b/cocos2d/motion-streak/CCMotionStreakWebGLRenderCmd.js @@ -0,0 +1,66 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +cc.MotionStreak.WebGLRenderCmd = function(renderableObject){ + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); +}; + +cc.MotionStreak.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); +cc.MotionStreak.WebGLRenderCmd.prototype.constructor = cc.Sprite.WebGLRenderCmd; + +cc.MotionStreak.WebGLRenderCmd.prototype.rendering = function(ctx){ + var node = this._node; + if (node._nuPoints <= 1) + return; + + if (node.texture && node.texture.isLoaded()) { + ctx = ctx || cc._renderContext; + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + + cc.glBindTexture2D(node.texture); + + //position + ctx.bindBuffer(ctx.ARRAY_BUFFER, node._verticesBuffer); + ctx.bufferData(ctx.ARRAY_BUFFER, node._vertices, ctx.DYNAMIC_DRAW); + ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, ctx.FLOAT, false, 0, 0); + + //texcoords + ctx.bindBuffer(ctx.ARRAY_BUFFER, node._texCoordsBuffer); + ctx.bufferData(ctx.ARRAY_BUFFER, node._texCoords, ctx.DYNAMIC_DRAW); + ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, ctx.FLOAT, false, 0, 0); + + //colors + ctx.bindBuffer(ctx.ARRAY_BUFFER, node._colorPointerBuffer); + ctx.bufferData(ctx.ARRAY_BUFFER, node._colorPointer, ctx.DYNAMIC_DRAW); + ctx.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, ctx.UNSIGNED_BYTE, true, 0, 0); + + ctx.drawArrays(ctx.TRIANGLE_STRIP, 0, node._nuPoints * 2); + cc.g_NumberOfDraws++; + } +}; \ No newline at end of file diff --git a/cocos2d/node-grid/CCNodeGrid.js b/cocos2d/node-grid/CCNodeGrid.js index b5cc41e2a5..781b8db4c8 100644 --- a/cocos2d/node-grid/CCNodeGrid.js +++ b/cocos2d/node-grid/CCNodeGrid.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2014 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -26,7 +26,8 @@ /** *

    NodeGrid class is a class serves as a decorator of cc.Node,
    - * Grid node can run grid actions over all its children

    + * Grid node can run grid actions over all its children (WebGL only) + *

    * @type {Class} * * @property {cc.GridBase} grid - Grid object that is used when applying effects @@ -36,54 +37,28 @@ cc.NodeGrid = cc.Node.extend({ grid: null, _target: null, + /** + * Gets the grid object. + * @returns {cc.GridBase} + */ getGrid: function () { return this.grid; }, + /** + * Set the grid object. + * @param {cc.GridBase} grid + */ setGrid: function (grid) { this.grid = grid; }, + /** + * Set the target + * @param {cc.Node} target + */ setTarget: function (target) { - //var self = this; - //self._target && self.removeChild(self._target); this._target = target; - //self.addChild(self._target); - }, - - addChild: function (child, zOrder, tag) { - cc.Node.prototype.addChild.call(this, child, zOrder, tag); - - if (child && !this._target) - this._target = child; - }, - - visit: function () { - var self = this; - // quick return if not visible - if (!self._visible) - return; - - var isWebGL = cc._renderType == cc._RENDER_TYPE_WEBGL; - var locGrid = self.grid; - if (isWebGL && locGrid && locGrid._active) - locGrid.beforeDraw(); - - self.transform(); - - var locChildren = this._children; - if (locChildren && locChildren.length > 0) { - var childLen = locChildren.length; - this.sortAllChildren(); - // draw children - for (i = 0; i < childLen; i++) { - var child = locChildren[i]; - child && child.visit(); - } - } - - if (isWebGL && locGrid && locGrid._active) - locGrid.afterDraw(self._target); }, _transformForWebGL: function () { @@ -91,8 +66,7 @@ cc.NodeGrid = cc.Node.extend({ var t4x4 = this._transform4x4, topMat4 = cc.current_stack.top; // Convert 3x3 into 4x4 matrix - //cc.CGAffineToGL(this.nodeToParentTransform(), this._transform4x4.mat); - var trans = this.nodeToParentTransform(); + var trans = this.getNodeToParentTransform(); var t4x4Mat = t4x4.mat; t4x4Mat[0] = trans.a; t4x4Mat[4] = trans.c; @@ -106,12 +80,13 @@ cc.NodeGrid = cc.Node.extend({ t4x4Mat[14] = this._vertexZ; //optimize performance for Javascript - cc.kmMat4Multiply(topMat4, topMat4, t4x4); // = cc.kmGLMultMatrix(this._transform4x4); + topMat4.multiply(t4x4) ; // = cc.kmGLMultMatrix(this._transform4x4); // XXX: Expensive calls. Camera should be integrated into the cached affine matrix - if (this._camera != null && !(this.grid && this.grid.isActive())) { - var apx = this._anchorPointInPoints.x, apy = this._anchorPointInPoints.y; - var translate = (apx !== 0.0 || apy !== 0.0); + if (this._camera !== null && !(this.grid && this.grid.isActive())) { + var app = this._renderCmd._anchorPointInPoints, + apx = app.x, apy = app.y, + translate = (apx !== 0.0 || apy !== 0.0); if (translate) { if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { apx = 0 | apx; @@ -124,14 +99,17 @@ cc.NodeGrid = cc.Node.extend({ this._camera.locate(); } } + }, + + _createRenderCmd: function(){ + if (cc._renderType === cc._RENDER_TYPE_WEBGL) + return new cc.NodeGrid.WebGLRenderCmd(this); + else + return new cc.Node.CanvasRenderCmd(this); // cc.NodeGrid doesn't support Canvas mode. } }); var _p = cc.NodeGrid.prototype; -if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - _p.transform = _p._transformForWebGL; - //The parent class method directly from canvas model -} // Extended property /** @expose */ _p.grid; @@ -141,9 +119,10 @@ cc.defineGetterSetter(_p, "target", null, _p.setTarget); /** - * Creates a NodeGrid + * Creates a NodeGrid.
    * Implementation cc.NodeGrid - * @return {cc.NodeGrid|null} + * @deprecated since v3.0 please new cc.NodeGrid instead. + * @return {cc.NodeGrid} */ cc.NodeGrid.create = function () { return new cc.NodeGrid(); diff --git a/cocos2d/node-grid/CCNodeGridWebGLRenderCmd.js b/cocos2d/node-grid/CCNodeGridWebGLRenderCmd.js new file mode 100644 index 0000000000..8c45377dfe --- /dev/null +++ b/cocos2d/node-grid/CCNodeGridWebGLRenderCmd.js @@ -0,0 +1,98 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.NodeGrid.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + this._gridBeginCommand = new cc.CustomRenderCmd(this, this.onGridBeginDraw); + this._gridEndCommand = new cc.CustomRenderCmd(this, this.onGridEndDraw); + }; + + var proto = cc.NodeGrid.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.NodeGrid.WebGLRenderCmd; + + proto.visit = function(parentCmd) { + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + parentCmd = parentCmd || this.getParentRenderCmd(); + if (node._parent && node._parent._renderCmd) + this._curLevel = node._parent._renderCmd._curLevel + 1; + + var currentStack = cc.current_stack; + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + currentStack.top = this._stackMatrix; + + /*var beforeProjectionType = cc.director.PROJECTION_DEFAULT; + if (locGrid && locGrid._active) { + //var backMatrix = new cc.kmMat4(); + //cc.kmMat4Assign(backMatrix, this._stackMatrix); + + beforeProjectionType = cc.director.getProjection(); + //locGrid.set2DProjection(); + + //reset this._stackMatrix to current_stack.top + //cc.kmMat4Assign(currentStack.top, backMatrix); + }*/ + cc.renderer.pushRenderCommand(this._gridBeginCommand); + + if (node._target) + node._target.visit(); + + var locChildren = node._children; + if (locChildren && locChildren.length > 0) { + var childLen = locChildren.length; + node.sortAllChildren(); + // draw children + for (var i = 0; i < childLen; i++) { + var child = locChildren[i]; + child && child.visit(); + } + } + + //if (locGrid && locGrid._active) { + //cc.director.setProjection(beforeProjectionType); + //} + cc.renderer.pushRenderCommand(this._gridEndCommand); + + this._dirtyFlag = 0; + currentStack.top = currentStack.stack.pop(); + }; + + proto.onGridBeginDraw = function(){ + var locGrid = this._node.grid; + if (locGrid && locGrid._active) + locGrid.beforeDraw(); + }; + + proto.onGridEndDraw = function(){ + var locGrid = this._node.grid; + if (locGrid && locGrid._active) + locGrid.afterDraw(this._node); + }; +})(); diff --git a/cocos2d/parallax/CCParallaxNode.js b/cocos2d/parallax/CCParallaxNode.js index e2b33b860b..ca41c526aa 100644 --- a/cocos2d/parallax/CCParallaxNode.js +++ b/cocos2d/parallax/CCParallaxNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,6 +25,8 @@ ****************************************************************************/ /** + * Parallax Object.
    + * Parallax required attributes are stored. * @class * @extends cc.Class */ @@ -33,14 +35,20 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ _offset:null, _child:null, + ctor: function(ratio, offset){ + this.initWithCCPoint(ratio, offset); + }, + /** - * @return {cc.Point} + * Gets the ratio. + * @return {cc.Point} Not point, this is ratio. */ getRatio:function () { return this._ratio; }, /** + * Set the ratio. * @param {cc.Point} value */ setRatio:function (value) { @@ -48,6 +56,7 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }, /** + * Gets the offset. * @return {cc.Point} */ getOffset:function () { @@ -55,6 +64,7 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }, /** + * Set the offset. * @param {cc.Point} value */ setOffset:function (value) { @@ -62,6 +72,7 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }, /** + * Gets the child. * @return {cc.Node} */ getChild:function () { @@ -69,6 +80,7 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }, /** + * Set the child. * @param {cc.Node} value */ setChild:function (value) { @@ -76,7 +88,8 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }, /** - * @param {cc.Point} ratio + * initializes cc.PointObject + * @param {cc.Point} ratio Not point, this is a ratio. * @param {cc.Point} offset * @return {Boolean} */ @@ -89,14 +102,14 @@ cc.PointObject = cc.Class.extend(/** @lends cc.PointObject# */{ }); /** + * Create a object to stored parallax data. * @param {cc.Point} ratio * @param {cc.Point} offset * @return {cc.PointObject} + * @deprecated since v3.0 please use new cc.PointObject() instead. */ cc.PointObject.create = function (ratio, offset) { - var ret = new cc.PointObject(); - ret.initWithCCPoint(ratio, offset); - return ret; + return new cc.PointObject(ratio, offset); }; /** @@ -107,13 +120,14 @@ cc.PointObject.create = function (ratio, offset) { * * @property {Array} parallaxArray - Parallax nodes array */ -cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ +cc.ParallaxNode = cc.Node.extend(/** @lends cc.ParallaxNode# */{ parallaxArray:null, _lastPosition:null, _className:"ParallaxNode", /** + * Gets the parallax array. * @return {Array} */ getParallaxArray:function () { @@ -121,6 +135,7 @@ cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ }, /** + * Set parallax array. * @param {Array} value */ setParallaxArray:function (value) { @@ -128,10 +143,10 @@ cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ }, /** - * Constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. */ ctor:function () { - cc.NodeRGBA.prototype.ctor.call(this); + cc.Node.prototype.ctor.call(this); this.parallaxArray = []; this._lastPosition = cc.p(-100, -100); }, @@ -149,18 +164,18 @@ cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ */ addChild:function (child, z, ratio, offset) { if (arguments.length === 3) { - cc.log("ParallaxNode: use addChild(child, z, ratio, offset) instead") + cc.log("ParallaxNode: use addChild(child, z, ratio, offset) instead"); return; } if(!child) throw "cc.ParallaxNode.addChild(): child should be non-null"; - var obj = cc.PointObject.create(ratio, offset); + var obj = new cc.PointObject(ratio, offset); obj.setChild(child); this.parallaxArray.push(obj); child.setPosition(this._position.x * ratio.x + offset.x, this._position.y * ratio.y + offset.y); - cc.NodeRGBA.prototype.addChild.call(this, child, z, child.tag); + cc.Node.prototype.addChild.call(this, child, z, child.tag); }, /** @@ -175,12 +190,12 @@ cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ var locParallaxArray = this.parallaxArray; for (var i = 0; i < locParallaxArray.length; i++) { var point = locParallaxArray[i]; - if (point.getChild() == child) { + if (point.getChild() === child) { locParallaxArray.splice(i, 1); break; } } - cc.NodeRGBA.prototype.removeChild.call(this, child, cleanup); + cc.Node.prototype.removeChild.call(this, child, cleanup); }, /** @@ -189,43 +204,48 @@ cc.ParallaxNode = cc.NodeRGBA.extend(/** @lends cc.ParallaxNode# */{ */ removeAllChildren:function (cleanup) { this.parallaxArray.length = 0; - cc.NodeRGBA.prototype.removeAllChildren.call(this, cleanup); + cc.Node.prototype.removeAllChildren.call(this, cleanup); }, - /** - * Visit - */ - visit:function () { + _updateParallaxPosition: function(){ var pos = this._absolutePosition(); if (!cc.pointEqualToPoint(pos, this._lastPosition)) { var locParallaxArray = this.parallaxArray; for (var i = 0, len = locParallaxArray.length; i < len; i++) { var point = locParallaxArray[i]; - var child = point.getChild(); - child.setPosition(-pos.x + pos.x * point.getRatio().x + point.getOffset().x, - -pos.y + pos.y * point.getRatio().y + point.getOffset().y); + var child = point.getChild(); + child.setPosition(-pos.x + pos.x * point.getRatio().x + point.getOffset().x, + -pos.y + pos.y * point.getRatio().y + point.getOffset().y); } this._lastPosition = pos; } - cc.NodeRGBA.prototype.visit.call(this); }, _absolutePosition:function () { var ret = this._position; var cn = this; - while (cn.parent != null) { + while (cn.parent !== null) { cn = cn.parent; ret = cc.pAdd(ret, cn.getPosition()); } return ret; + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ParallaxNode.CanvasRenderCmd(this); + else + return new cc.ParallaxNode.WebGLRenderCmd(this); } }); /** + * Create new parallax node. + * @deprecated since v3.0 please use new cc.ParallaxNode() instead. * @return {cc.ParallaxNode} * @example * //example - * var voidNode = cc.ParallaxNode.create(); + * var voidNode = new cc.ParallaxNode(); */ cc.ParallaxNode.create = function () { return new cc.ParallaxNode(); diff --git a/cocos2d/parallax/CCParallaxNodeRenderCmd.js b/cocos2d/parallax/CCParallaxNodeRenderCmd.js new file mode 100644 index 0000000000..690a7849f6 --- /dev/null +++ b/cocos2d/parallax/CCParallaxNodeRenderCmd.js @@ -0,0 +1,69 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +//TODO find a way to simple these code. + +(function(){ + cc.ParallaxNode.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = cc.ParallaxNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.ParallaxNode.CanvasRenderCmd; + + proto.updateStatus = function(){ + this._node._updateParallaxPosition(); + cc.Node.CanvasRenderCmd.prototype.updateStatus.call(this); + }; + + proto._syncStatus = function(parentCmd){ + this._node._updateParallaxPosition(); + cc.Node.CanvasRenderCmd.prototype._syncStatus.call(this, parentCmd); + } +})(); + +(function(){ + if(cc._renderType !== cc._RENDER_TYPE_WEBGL) + return; + + cc.ParallaxNode.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = cc.ParallaxNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.ParallaxNode.WebGLRenderCmd; + + proto.updateStatus = function(){ + this._node._updateParallaxPosition(); + cc.Node.WebGLRenderCmd.prototype.updateStatus.call(this); + }; + + proto._syncStatus = function(parentCmd){ + this._node._updateParallaxPosition(); + cc.Node.WebGLRenderCmd.prototype._syncStatus.call(this, parentCmd); + } +})(); + diff --git a/cocos2d/particle/CCPNGReader.js b/cocos2d/particle/CCPNGReader.js index 99fb63c2cb..20667a2cbc 100644 --- a/cocos2d/particle/CCPNGReader.js +++ b/cocos2d/particle/CCPNGReader.js @@ -1,7 +1,8 @@ /**************************************************************************** Copyright (c) 2011 Devon Govett - Copyright (c) 2010-2012 cocos2d-x.org - + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,6 +26,10 @@ THE SOFTWARE. ****************************************************************************/ +/** + * A png file reader + * @name cc.tiffReader + */ cc.PNGReader = cc.Class.extend({ ctor:function(data){ var chunkSize, colors, delayDen, delayNum, frame, i, index, key, section, ccshort, text, _i, _j, _ref; diff --git a/cocos2d/particle/CCParticleBatchNode.js b/cocos2d/particle/CCParticleBatchNode.js index 5f44b8f557..b92f11bc27 100644 --- a/cocos2d/particle/CCParticleBatchNode.js +++ b/cocos2d/particle/CCParticleBatchNode.js @@ -1,8 +1,8 @@ /** - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * Copyright (C) 2009 Matt Oswald - * Copyright (c) 2009-2010 Ricardo Quesada - * Copyright (c) 2011 Zynga Inc. * Copyright (c) 2011 Marco Tillemans * * http://www.cocos2d-x.org @@ -54,21 +54,31 @@ cc.PARTICLE_DEFAULT_CAPACITY = 500; *

    * @class * @extends cc.ParticleSystem + * @param {String|cc.Texture2D} fileImage + * @param {Number} capacity * * @property {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture - The used texture * @property {cc.TextureAtlas} textureAtlas - The texture atlas used for drawing the quads + * + * @example + * 1. + * //Create a cc.ParticleBatchNode with image path and capacity + * var particleBatchNode = new cc.ParticleBatchNode("res/grossini_dance.png",30); + * + * 2. + * //Create a cc.ParticleBatchNode with a texture and capacity + * var texture = cc.TextureCache.getInstance().addImage("res/grossini_dance.png"); + * var particleBatchNode = new cc.ParticleBatchNode(texture, 30); */ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ textureAtlas:null, - - TextureProtocol:true, //the blend function used for drawing the quads _blendFunc:null, _className:"ParticleBatchNode", /** * initializes the particle system with the name of a file on disk (for a list of supported formats look at the cc.Texture2D class), a capacity of particles - * @constructor + * Constructor of cc.ParticleBatchNode * @param {String|cc.Texture2D} fileImage * @param {Number} capacity * @example @@ -84,13 +94,20 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ ctor:function (fileImage, capacity) { cc.Node.prototype.ctor.call(this); this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST}; - if (typeof(fileImage) == "string") { + if (cc.isString(fileImage)) { this.init(fileImage, capacity); } else if (fileImage instanceof cc.Texture2D) { this.initWithTexture(fileImage, capacity); } }, + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ParticleBatchNode.CanvasRenderCmd(this); + else + return new cc.ParticleBatchNode.WebGLRenderCmd(this); + }, + /** * initializes the particle system with cc.Texture2D, a capacity of particles * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture @@ -104,8 +121,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ // no lazy alloc in this node this._children.length = 0; - if (cc._renderType === cc._RENDER_TYPE_WEBGL) - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + this._renderCmd._initWithTexture(); return true; }, @@ -127,7 +143,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ * @return {Boolean} */ init:function (fileImage, capacity) { - var tex = cc.TextureCache.getInstance().addImage(fileImage); + var tex = cc.textureCache.addImage(fileImage); return this.initWithTexture(tex, capacity); }, @@ -145,7 +161,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ zOrder = (zOrder == null) ? child.zIndex : zOrder; tag = (tag == null) ? child.tag : tag; - if(child.getTexture() != this.textureAtlas.texture) + if(child.getTexture() !== this.textureAtlas.texture) throw "cc.ParticleSystem.addChild() : the child is not using the same texture id"; // If this is the 1st children, then copy blending function @@ -153,7 +169,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ if (this._children.length === 0) this.setBlendFunc(childBlendFunc); else{ - if((childBlendFunc.src != this._blendFunc.src) || (childBlendFunc.dst != this._blendFunc.dst)){ + if((childBlendFunc.src !== this._blendFunc.src) || (childBlendFunc.dst !== this._blendFunc.dst)){ cc.log("cc.ParticleSystem.addChild() : Can't add a ParticleSystem that uses a different blending function"); return; } @@ -165,7 +181,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ //get new atlasIndex var atlasIndex = 0; - if (pos != 0) { + if (pos !== 0) { var p = this._children[pos - 1]; atlasIndex = p.getAtlasIndex() + p.getTotalParticles(); } else @@ -194,7 +210,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ } // make room for quads, not necessary for last child - if (pSystem.getAtlasIndex() + totalParticles != totalQuads) + if (pSystem.getAtlasIndex() + totalParticles !== totalQuads) locTextureAtlas.moveQuadsFromIndex(index, index + totalParticles); // increase totalParticles here for new particles, update method of particlesystem will fill the quads @@ -213,7 +229,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ if(!(child instanceof cc.ParticleSystem)) throw "cc.ParticleBatchNode.removeChild(): only supports cc.ParticleSystem as children"; - if(this._children.indexOf(child) == -1){ + if(this._children.indexOf(child) === -1){ cc.log("cc.ParticleBatchNode.removeChild(): doesn't contain the sprite. Can't remove it"); return; } @@ -248,14 +264,14 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ return; } - if (zOrder == child.zIndex) + if (zOrder === child.zIndex) return; // no reordering if only 1 child if (this._children.length > 1) { var getIndexes = this._getCurrentIndex(child, zOrder); - if (getIndexes.oldIndex != getIndexes.newIndex) { + if (getIndexes.oldIndex !== getIndexes.newIndex) { // reorder m_pChildren.array this._children.splice(getIndexes.oldIndex, 1) this._children.splice(getIndexes.newIndex, 0, child); @@ -271,7 +287,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ var locChildren = this._children; for (var i = 0; i < locChildren.length; i++) { var pNode = locChildren[i]; - if (pNode == child) { + if (pNode === child) { newAtlasIndex = child.getAtlasIndex(); break; } @@ -317,28 +333,9 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ this.textureAtlas._setDirty(true); }, - /** - * @override - * @param {CanvasContext} ctx - */ - draw:function (ctx) { - //cc.PROFILER_STOP("CCParticleBatchNode - draw"); - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - return; - - if (this.textureAtlas.totalQuads == 0) - return; - - cc.nodeDrawSetup(this); - cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst); - this.textureAtlas.drawQuads(); - - //cc.PROFILER_STOP("CCParticleBatchNode - draw"); - }, - /** * returns the used texture - * @return {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} + * @return {cc.Texture2D} */ getTexture:function () { return this.textureAtlas.texture; @@ -346,14 +343,14 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ /** * sets a new texture. it will be retained - * @param {cc.Texture2D|HTMLImageElement|HTMLCanvasElement} texture + * @param {cc.Texture2D} texture */ setTexture:function (texture) { this.textureAtlas.texture = texture; // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it var locBlendFunc = this._blendFunc; - if (texture && !texture.hasPremultipliedAlpha() && ( locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST )) { + if (texture && !texture.hasPremultipliedAlpha() && ( locBlendFunc.src === cc.BLEND_SRC && locBlendFunc.dst === cc.BLEND_DST )) { locBlendFunc.src = cc.SRC_ALPHA; locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; } @@ -361,7 +358,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ /** * set the blending function used for the texture - * @param {Number|cc.BlencFunc} src + * @param {Number|Object} src * @param {Number} dst */ setBlendFunc:function (src, dst) { @@ -372,7 +369,6 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ this._blendFunc.src = src; this._blendFunc.src = dst; } - }, /** @@ -380,38 +376,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ * @return {cc.BlendFunc} */ getBlendFunc:function () { - return {src:this._blendFunc.src, dst:this._blendFunc.dst}; - }, - - // override visit. - // Don't call visit on it's children - visit:function (ctx) { - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - return; - - // CAREFUL: - // This visit is almost identical to cc.Node#visit - // with the exception that it doesn't call visit on it's children - // - // The alternative is to have a void cc.Sprite#visit, but - // although this is less mantainable, is faster - // - if (!this._visible) - return; - - cc.kmGLPushMatrix(); - if (this.grid && this.grid.isActive()) { - this.grid.beforeDraw(); - this.transformAncestors(); - } - - this.transform(ctx); - this.draw(ctx); - - if (this.grid && this.grid.isActive()) - this.grid.afterDraw(this); - - cc.kmGLPopMatrix(); + return new cc.BlendFunc(this._blendFunc.src, this._blendFunc.dst); }, _updateAllAtlasIndexes:function () { @@ -464,7 +429,7 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ break; } // current index - if (child == pNode) { + if (child === pNode) { oldIndex = i; foundCurrentIdx = true; if (!foundNewIdx) @@ -479,19 +444,19 @@ cc.ParticleBatchNode = cc.Node.extend(/** @lends cc.ParticleBatchNode# */{ return {newIndex:newIndex, oldIndex:oldIndex}; }, - /** - *

    - * don't use lazy sorting, reordering the particle systems quads afterwards would be too complex
    - * XXX research whether lazy sorting + freeing current quads and calloc a new block with size of capacity would be faster
    - * XXX or possibly using vertexZ for reordering, that would be fastest
    - * this helper is almost equivalent to CCNode's addChild, but doesn't make use of the lazy sorting
    - *

    - * @param {cc.ParticleSystem} child - * @param {Number} z - * @param {Number} aTag - * @return {Number} - * @private - */ + // + //

    + // don't use lazy sorting, reordering the particle systems quads afterwards would be too complex
    + // XXX research whether lazy sorting + freeing current quads and calloc a new block with size of capacity would be faster
    + // XXX or possibly using vertexZ for reordering, that would be fastest
    + // this helper is almost equivalent to CCNode's addChild, but doesn't make use of the lazy sorting
    + //

    + // @param {cc.ParticleSystem} child + // @param {Number} z + // @param {Number} aTag + // @return {Number} + // @private + // _addChildHelper:function (child, z, aTag) { if(!child) throw "cc.ParticleBatchNode._addChildHelper(): child should be non-null"; @@ -552,18 +517,10 @@ cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); /** * initializes the particle system with the name of a file on disk (for a list of supported formats look at the cc.Texture2D class), a capacity of particles + * @deprecated since v3.0 please use new cc.ParticleBatchNode(filename, capacity) instead. * @param {String|cc.Texture2D} fileImage * @param {Number} capacity * @return {cc.ParticleBatchNode} - * @example - * 1. - * //Create a cc.ParticleBatchNode with image path and capacity - * var particleBatchNode = cc.ParticleBatchNode.create("res/grossini_dance.png",30); - * - * 2. - * //Create a cc.ParticleBatchNode with a texture and capacity - * var texture = cc.TextureCache.getInstance().addImage("res/grossini_dance.png"); - * var particleBatchNode = cc.ParticleBatchNode.create(texture, 30); */ cc.ParticleBatchNode.create = function (fileImage, capacity) { return new cc.ParticleBatchNode(fileImage, capacity); diff --git a/cocos2d/particle/CCParticleBatchNodeCanvasRenderCmd.js b/cocos2d/particle/CCParticleBatchNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..36da185ecb --- /dev/null +++ b/cocos2d/particle/CCParticleBatchNodeCanvasRenderCmd.js @@ -0,0 +1,38 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + /** + * cc.ParticleBatchNode's rendering objects of Canvas + */ + cc.ParticleBatchNode.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = cc.ParticleBatchNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.ParticleBatchNode.CanvasRenderCmd; + + proto._initWithTexture = function(){}; +})(); diff --git a/cocos2d/particle/CCParticleBatchNodeWebGLRenderCmd.js b/cocos2d/particle/CCParticleBatchNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..16da24b496 --- /dev/null +++ b/cocos2d/particle/CCParticleBatchNodeWebGLRenderCmd.js @@ -0,0 +1,74 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + /** + * cc.ParticleBatchNode's rendering objects of WebGL + */ + cc.ParticleBatchNode.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + }; + + var proto = cc.ParticleBatchNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.ParticleBatchNode.WebGLRenderCmd; + + proto.rendering = function (ctx) { + var _t = this._node; + if (_t.textureAtlas.totalQuads === 0) + return; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + cc.glBlendFuncForParticle(_t._blendFunc.src, _t._blendFunc.dst); + _t.textureAtlas.drawQuads(); + }; + + proto._initWithTexture = function(){ + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + // CAREFUL: + // This visit is almost identical to cc.Node#visit + // with the exception that it doesn't call visit on it's children + // + // The alternative is to have a void cc.Sprite#visit, but + // although this is less mantainable, is faster + // + if (!node._visible) + return; + + var currentStack = cc.current_stack; + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + currentStack.top = this._stackMatrix; + //this.draw(ctx); + cc.renderer.pushRenderCommand(this); + + this._dirtyFlag = 0; + cc.kmGLPopMatrix(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/particle/CCParticleExamples.js b/cocos2d/particle/CCParticleExamples.js index 06d5cf793c..1202482f85 100644 --- a/cocos2d/particle/CCParticleExamples.js +++ b/cocos2d/particle/CCParticleExamples.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -30,15 +30,16 @@ * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleFire.create(); + * var emitter = new cc.ParticleFire(); */ cc.ParticleFire = cc.ParticleSystem.extend(/** @lends cc.ParticleFire# */{ /** - * initialize a fire particle system - * @return {Boolean} + *

    The cc.ParticleFire's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleFire()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 300 : 150); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 300 : 150); }, /** @@ -49,10 +50,10 @@ cc.ParticleFire = cc.ParticleSystem.extend(/** @lends cc.ParticleFire# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity @@ -83,7 +84,7 @@ cc.ParticleFire = cc.ParticleSystem.extend(/** @lends cc.ParticleFire# */{ // size, in pixels this.setStartSize(54.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per frame this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -104,17 +105,11 @@ cc.ParticleFire = cc.ParticleSystem.extend(/** @lends cc.ParticleFire# */{ /** * Create a fire particle system + * @deprecated since v3.0 please use new cc.ParticleFire() instead * @return {cc.ParticleFire} - * - * @example - * var emitter = cc.ParticleFire.create(); */ cc.ParticleFire.create = function () { - var ret = new cc.ParticleFire(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleFire(); }; /** @@ -123,15 +118,16 @@ cc.ParticleFire.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleFireworks.create(); + * var emitter = new cc.ParticleFireworks(); */ cc.ParticleFireworks = cc.ParticleSystem.extend(/** @lends cc.ParticleFireworks# */{ /** - * initialize a fireworks particle system - * @return {Boolean} + *

    The cc.ParticleFireworks's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleFireworks()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 1500 : 150); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 1500 : 150); }, /** @@ -142,10 +138,10 @@ cc.ParticleFireworks = cc.ParticleSystem.extend(/** @lends cc.ParticleFireworks# initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, -90)); @@ -182,7 +178,7 @@ cc.ParticleFireworks = cc.ParticleSystem.extend(/** @lends cc.ParticleFireworks# // size, in pixels this.setStartSize(8.0); this.setStartSizeVar(2.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // additive this.setBlendAdditive(false); @@ -194,17 +190,11 @@ cc.ParticleFireworks = cc.ParticleSystem.extend(/** @lends cc.ParticleFireworks# /** * Create a fireworks particle system + * @deprecated since v3.0 please use new cc.ParticleFireworks() instead. * @return {cc.ParticleFireworks} - * - * @example - * var emitter = cc.ParticleFireworks.create(); */ cc.ParticleFireworks.create = function () { - var ret = new cc.ParticleFireworks(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleFireworks(); }; /** @@ -213,15 +203,16 @@ cc.ParticleFireworks.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleSun.create(); + * var emitter = new cc.ParticleSun(); */ cc.ParticleSun = cc.ParticleSystem.extend(/** @lends cc.ParticleSun# */{ /** - * initialize a sun particle system - * @return {Boolean} + *

    The cc.ParticleSun's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleSun()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 350 : 150); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 350 : 150); }, /** @@ -235,10 +226,10 @@ cc.ParticleSun = cc.ParticleSystem.extend(/** @lends cc.ParticleSun# */{ this.setBlendAdditive(true); // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -267,7 +258,7 @@ cc.ParticleSun = cc.ParticleSystem.extend(/** @lends cc.ParticleSun# */{ // size, in pixels this.setStartSize(30.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per seconds this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -286,17 +277,11 @@ cc.ParticleSun = cc.ParticleSystem.extend(/** @lends cc.ParticleSun# */{ /** * Create a sun particle system + * @deprecated since v3.0 please use new cc.ParticleSun() instead. * @return {cc.ParticleSun} - * - * @example - * var emitter = cc.ParticleSun.create(); */ cc.ParticleSun.create = function () { - var ret = new cc.ParticleSun(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleSun(); }; //! @brief A particle system @@ -306,16 +291,16 @@ cc.ParticleSun.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleGalaxy.create(); + * var emitter = new cc.ParticleGalaxy(); */ cc.ParticleGalaxy = cc.ParticleSystem.extend(/** @lends cc.ParticleGalaxy# */{ /** - * initialize a galaxy particle system - * @return {Boolean} + *

    The cc.ParticleGalaxy's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleGalaxy()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - //return this.initWithTotalParticles(200); - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 200 : 100); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 200 : 100); }, /** @@ -326,10 +311,10 @@ cc.ParticleGalaxy = cc.ParticleSystem.extend(/** @lends cc.ParticleGalaxy# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -362,7 +347,7 @@ cc.ParticleGalaxy = cc.ParticleSystem.extend(/** @lends cc.ParticleGalaxy# */{ // size, in pixels this.setStartSize(37.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -382,17 +367,11 @@ cc.ParticleGalaxy = cc.ParticleSystem.extend(/** @lends cc.ParticleGalaxy# */{ }); /** * Create a galaxy particle system + * @deprecated since v3.0 please use new cc.OarticleGalaxy() instead. * @return {cc.ParticleGalaxy} - * - * @example - * var emitter = cc.ParticleGalaxy.create(); */ cc.ParticleGalaxy.create = function () { - var ret = new cc.ParticleGalaxy(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleGalaxy(); }; /** @@ -401,15 +380,16 @@ cc.ParticleGalaxy.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleFlower.create(); + * var emitter = new cc.ParticleFlower(); */ cc.ParticleFlower = cc.ParticleSystem.extend(/** @lends cc.ParticleFlower# */{ /** - * initialize a flower particle system - * @return {Boolean} + *

    The cc.ParticleFlower's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleFlower()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 250 : 100); + ctor : function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 250 : 100); }, /** @@ -420,10 +400,10 @@ cc.ParticleFlower = cc.ParticleSystem.extend(/** @lends cc.ParticleFlower# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -456,7 +436,7 @@ cc.ParticleFlower = cc.ParticleSystem.extend(/** @lends cc.ParticleFlower# */{ // size, in pixels this.setStartSize(30.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -477,17 +457,11 @@ cc.ParticleFlower = cc.ParticleSystem.extend(/** @lends cc.ParticleFlower# */{ /** * Create a flower particle system + * @deprecated since v3.0 please use new cc.ParticleFlower() instead. * @return {cc.ParticleFlower} - * - * @example - * var emitter = cc.ParticleFlower.create(); */ cc.ParticleFlower.create = function () { - var ret = new cc.ParticleFlower(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleFlower(); }; //! @brief A meteor particle system @@ -497,15 +471,16 @@ cc.ParticleFlower.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleMeteor.create(); + * var emitter = new cc.ParticleMeteor(); */ cc.ParticleMeteor = cc.ParticleSystem.extend(/** @lends cc.ParticleMeteor# */{ /** - * initialize a meteor particle system - * @return {Boolean} + *

    The cc.ParticleMeteor's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleMeteor()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 150 : 100); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 150 : 100); }, /** @@ -516,10 +491,10 @@ cc.ParticleMeteor = cc.ParticleSystem.extend(/** @lends cc.ParticleMeteor# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(-200, 200)); @@ -552,7 +527,7 @@ cc.ParticleMeteor = cc.ParticleSystem.extend(/** @lends cc.ParticleMeteor# */{ // size, in pixels this.setStartSize(60.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -573,17 +548,11 @@ cc.ParticleMeteor = cc.ParticleSystem.extend(/** @lends cc.ParticleMeteor# */{ /** * Create a meteor particle system + * @deprecated since v3.0 please use new cc.ParticleMeteor() instead. * @return {cc.ParticleMeteor} - * - * @example - * var emitter = cc.ParticleMeteor.create(); */ cc.ParticleMeteor.create = function () { - var ret = new cc.ParticleMeteor(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleMeteor(); }; /** @@ -592,15 +561,17 @@ cc.ParticleMeteor.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleSpiral.create(); + * var emitter = new cc.ParticleSpiral(); */ cc.ParticleSpiral = cc.ParticleSystem.extend(/** @lends cc.ParticleSpiral# */{ + /** - * initialize a spiral particle system - * @return {Boolean} + *

    The cc.ParticleSpiral's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleSpiral()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 500 : 100); + ctor:function() { + cc.ParticleSystem.prototype.ctor.call(this,(cc._renderType === cc._RENDER_TYPE_WEBGL) ? 500 : 100); }, /** @@ -611,10 +582,10 @@ cc.ParticleSpiral = cc.ParticleSystem.extend(/** @lends cc.ParticleSpiral# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -647,7 +618,7 @@ cc.ParticleSpiral = cc.ParticleSystem.extend(/** @lends cc.ParticleSpiral# */{ // size, in pixels this.setStartSize(20.0); this.setStartSizeVar(0.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -668,17 +639,11 @@ cc.ParticleSpiral = cc.ParticleSystem.extend(/** @lends cc.ParticleSpiral# */{ /** * Create a spiral particle system + * @deprecated since v3.0 please use new cc.ParticleSpiral() instead. * @return {cc.ParticleSpiral} - * - * @example - * var emitter = cc.ParticleSpiral.create(); */ cc.ParticleSpiral.create = function () { - var ret = new cc.ParticleSpiral(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleSpiral(); }; /** @@ -687,16 +652,16 @@ cc.ParticleSpiral.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleExplosion.create(); + * var emitter = new cc.ParticleExplosion(); */ cc.ParticleExplosion = cc.ParticleSystem.extend(/** @lends cc.ParticleExplosion# */{ /** - * initialize an explosion particle system - * @return {Boolean} + *

    The cc.ParticleExplosion's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleExplosion()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - //return this.initWithTotalParticles(700); - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 700 : 300); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 700 : 300); }, /** @@ -709,7 +674,7 @@ cc.ParticleExplosion = cc.ParticleSystem.extend(/** @lends cc.ParticleExplosion# // duration this.setDuration(0.1); - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -742,7 +707,7 @@ cc.ParticleExplosion = cc.ParticleSystem.extend(/** @lends cc.ParticleExplosion# // size, in pixels this.setStartSize(15.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(this.getTotalParticles() / this.getDuration()); @@ -763,17 +728,11 @@ cc.ParticleExplosion = cc.ParticleSystem.extend(/** @lends cc.ParticleExplosion# /** * Create an explosion particle system + * @deprecated since v3.0 please use new cc.ParticleExplosion() instead. * @return {cc.ParticleExplosion} - * - * @example - * var emitter = cc.ParticleExplosion.create(); */ cc.ParticleExplosion.create = function () { - var ret = new cc.ParticleExplosion(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleExplosion(); }; /** @@ -782,16 +741,17 @@ cc.ParticleExplosion.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleSmoke.create(); + * var emitter = new cc.ParticleSmoke(); */ cc.ParticleSmoke = cc.ParticleSystem.extend(/** @lends cc.ParticleSmoke# */{ + /** - * initialize a smoke particle system - * @return {Boolean} + *

    The cc.ParticleSmoke's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleSmoke()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - //return this.initWithTotalParticles(200); - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 200 : 100); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 200 : 100); }, /** @@ -802,10 +762,10 @@ cc.ParticleSmoke = cc.ParticleSystem.extend(/** @lends cc.ParticleSmoke# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // Emitter mode: Gravity Mode - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, 0)); @@ -834,7 +794,7 @@ cc.ParticleSmoke = cc.ParticleSystem.extend(/** @lends cc.ParticleSmoke# */{ // size, in pixels this.setStartSize(60.0); this.setStartSizeVar(10.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per frame this.setEmissionRate(this.getTotalParticles() / this.getLife()); @@ -855,17 +815,11 @@ cc.ParticleSmoke = cc.ParticleSystem.extend(/** @lends cc.ParticleSmoke# */{ /** * Create a smoke particle system + * @deprecated since v3.0 please use new cc.ParticleSmoke() instead. * @return {cc.ParticleSmoke} - * - * @example - * var emitter = cc.ParticleFireworks.create(); */ cc.ParticleSmoke.create = function () { - var ret = new cc.ParticleSmoke(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleSmoke(); }; /** @@ -874,15 +828,17 @@ cc.ParticleSmoke.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleSnow.create(); + * var emitter = new cc.ParticleSnow(); */ cc.ParticleSnow = cc.ParticleSystem.extend(/** @lends cc.ParticleSnow# */{ + /** - * initialize a snow particle system - * @return {Boolean} + *

    The cc.ParticleSnow's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleSnow()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 700 : 250); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 700 : 250); }, /** @@ -893,10 +849,10 @@ cc.ParticleSnow = cc.ParticleSystem.extend(/** @lends cc.ParticleSnow# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); // set gravity mode. - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(0, -1)); @@ -929,7 +885,7 @@ cc.ParticleSnow = cc.ParticleSystem.extend(/** @lends cc.ParticleSnow# */{ // size, in pixels this.setStartSize(10.0); this.setStartSizeVar(5.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(10); @@ -950,17 +906,11 @@ cc.ParticleSnow = cc.ParticleSystem.extend(/** @lends cc.ParticleSnow# */{ /** * Create a snow particle system + * @deprecated since v3.0 please use new cc.ParticleSnow() instead. * @return {cc.ParticleSnow} - * - * @example - * var emitter = cc.ParticleSnow.create(); */ cc.ParticleSnow.create = function () { - var ret = new cc.ParticleSnow(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleSnow(); }; //! @brief A rain particle system @@ -970,15 +920,17 @@ cc.ParticleSnow.create = function () { * @extends cc.ParticleSystem * * @example - * var emitter = cc.ParticleRain.create(); + * var emitter = new cc.ParticleRain(); */ cc.ParticleRain = cc.ParticleSystem.extend(/** @lends cc.ParticleRain# */{ + /** - * initialize a rain particle system - * @return {Boolean} + *

    The cc.ParticleRain's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.ParticleRain()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    */ - init:function () { - return this.initWithTotalParticles((cc._renderType === cc._RENDER_TYPE_WEBGL) ? 1000 : 300); + ctor:function () { + cc.ParticleSystem.prototype.ctor.call(this, (cc._renderType === cc._RENDER_TYPE_WEBGL) ? 1000 : 300); }, /** @@ -989,9 +941,9 @@ cc.ParticleRain = cc.ParticleSystem.extend(/** @lends cc.ParticleRain# */{ initWithTotalParticles:function (numberOfParticles) { if (cc.ParticleSystem.prototype.initWithTotalParticles.call(this, numberOfParticles)) { // duration - this.setDuration(cc.PARTICLE_DURATION_INFINITY); + this.setDuration(cc.ParticleSystem.DURATION_INFINITY); - this.setEmitterMode(cc.PARTICLE_MODE_GRAVITY); + this.setEmitterMode(cc.ParticleSystem.MODE_GRAVITY); // Gravity Mode: gravity this.setGravity(cc.p(10, -10)); @@ -1025,7 +977,7 @@ cc.ParticleRain = cc.ParticleSystem.extend(/** @lends cc.ParticleRain# */{ // size, in pixels this.setStartSize(4.0); this.setStartSizeVar(2.0); - this.setEndSize(cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE); + this.setEndSize(cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE); // emits per second this.setEmissionRate(20); @@ -1046,15 +998,9 @@ cc.ParticleRain = cc.ParticleSystem.extend(/** @lends cc.ParticleRain# */{ /** * Create a rain particle system + * @deprecated since v3.0 please use cc.ParticleRain() instead. * @return {cc.ParticleRain} - * - * @example - * var emitter = cc.ParticleRain.create(); */ cc.ParticleRain.create = function () { - var ret = new cc.ParticleRain(); - if (ret.init()) { - return ret; - } - return null; + return new cc.ParticleRain(); }; diff --git a/cocos2d/particle/CCParticleSystem.js b/cocos2d/particle/CCParticleSystem.js index 8607313689..7136f5335e 100644 --- a/cocos2d/particle/CCParticleSystem.js +++ b/cocos2d/particle/CCParticleSystem.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -41,91 +41,10 @@ // cocos2d uses a another approach, but the results are almost identical. // -/** - * Shape Mode of Particle Draw - * @constant - * @type Number - */ -cc.PARTICLE_SHAPE_MODE = 0; -/** - * Texture Mode of Particle Draw - * @constant - * @type Number - */ -cc.PARTICLE_TEXTURE_MODE = 1; - -/** - * Star Shape for ShapeMode of Particle - * @constant - * @type Number - */ -cc.PARTICLE_STAR_SHAPE = 0; -/** - * Ball Shape for ShapeMode of Particle - * @constant - * @type Number - */ -cc.PARTICLE_BALL_SHAPE = 1; - -/** - * The Particle emitter lives forever - * @constant - * @type Number - */ -cc.PARTICLE_DURATION_INFINITY = -1; - -/** - * The starting size of the particle is equal to the ending size - * @constant - * @type Number - */ -cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE = -1; - -/** - * The starting radius of the particle is equal to the ending radius - * @constant - * @type Number - */ -cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS = -1; - -/** - * Gravity mode (A mode) - * @constant - * @type Number - */ -cc.PARTICLE_MODE_GRAVITY = 0; - -/** - * Radius mode (B mode) - * @constant - * @type Number - */ -cc.PARTICLE_MODE_RADIUS = 1; // tCCPositionType // possible types of particle positions -/** - * Living particles are attached to the world and are unaffected by emitter repositioning. - * @constant - * @type Number - */ -cc.PARTICLE_TYPE_FREE = 0; - -/** - * Living particles are attached to the world but will follow the emitter repositioning.
    - * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. - * @constant - * @type Number - */ -cc.PARTICLE_TYPE_RELATIVE = 1; - -/** - * Living particles are attached to the emitter and are translated along with it. - * @constant - * @type Number - */ -cc.PARTICLE_TYPE_GROUPED = 2; /** * Structure that contains the values of each particle @@ -244,7 +163,7 @@ cc.Particle.TemporaryPoints = [ * @property {Boolean} opacityModifyRGB - Indicate whether the alpha value modify color. * @property {cc.SpriteBatchNode} batchNode - Weak reference to the sprite batch node. * @property {Boolean} active - <@readonly> Indicate whether the particle system is activated. - * @property {Number} shapeType - ShapeType of ParticleSystem : cc.PARTICLE_BALL_SHAPE | cc.PARTICLE_STAR_SHAPE. + * @property {Number} shapeType - ShapeType of ParticleSystem : cc.ParticleSystem.BALL_SHAPE | cc.ParticleSystem.STAR_SHAPE. * @property {Number} atlasIndex - Index of system in batch node array. * @property {Number} particleCount - Current quantity of particles that are being simulated. * @property {Number} duration - How many seconds the emitter wil run. -1 means 'forever' @@ -281,8 +200,8 @@ cc.Particle.TemporaryPoints = [ * @property {cc.Color} endColor - Ending color of each particle. * @property {cc.Color} endColorVar - Variation of the end color. * @property {Number} emissionRate - Emission rate of the particles. - * @property {Number} emitterMode - Emitter modes: CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration; CCPARTICLE_MODE_RADIUS: uses radius movement + rotation. - * @property {Number} positionType - Particles movement type: cc.PARTICLE_TYPE_FREE | cc.PARTICLE_TYPE_GROUPED. + * @property {Number} emitterMode - Emitter modes: CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration; CCParticleSystem.MODE_RADIUS: uses radius movement + rotation. + * @property {Number} positionType - Particles movement type: cc.ParticleSystem.TYPE_FREE | cc.ParticleSystem.TYPE_GROUPED. * @property {Number} totalParticles - Maximum particles of the system. * @property {Boolean} autoRemoveOnFinish - Indicate whether the node will be auto-removed when it has no particles left. * @property {cc.Texture2D} texture - Texture of Particle System. @@ -292,11 +211,11 @@ cc.Particle.TemporaryPoints = [ * emitter.startSpin = 0; */ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ + _className:"ParticleSystem", //***********variables************* _plistFile: "", //! time elapsed since the start of the system (in seconds) _elapsed: 0, - _dontTint: false, // Different modes @@ -304,7 +223,6 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ modeA: null, //! Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) modeB: null, - _className:"ParticleSystem", //private POINTZERO for ParticleSystem _pointZeroForParticle: cc.p(0, 0), @@ -327,11 +245,6 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ _transformSystemDirty: false, _allocatedParticles: 0, - //drawMode - drawMode: cc.PARTICLE_SHAPE_MODE, - - //shape type - shapeType: cc.PARTICLE_BALL_SHAPE, _isActive: false, particleCount: 0, duration: 0, @@ -358,34 +271,23 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ _texture: null, _blendFunc: null, _opacityModifyRGB: false, - positionType: cc.PARTICLE_TYPE_FREE, + positionType: null, autoRemoveOnFinish: false, emitterMode: 0, - // quads to be rendered - _quads:null, - // indices - _indices:null, - - //_VAOname:0, - //0: vertex 1: indices - _buffersVBO:null, - _pointRect:null, - _textureLoaded: null, - _quadsArrayBuffer:null, /** *

    return the string found by key in dict.
    * This plist files can be create manually or with Particle Designer:
    * http://particledesigner.71squared.com/
    *

    - * @constructor + * Constructor of cc.ParticleSystem * @param {String|Number} plistFile */ ctor:function (plistFile) { cc.Node.prototype.ctor.call(this); - this.emitterMode = cc.PARTICLE_MODE_GRAVITY; + this.emitterMode = cc.ParticleSystem.MODE_GRAVITY; this.modeA = new cc.ParticleSystem.ModeA(); this.modeB = new cc.ParticleSystem.ModeB(); this._blendFunc = {src:cc.BLEND_SRC, dst:cc.BLEND_DST}; @@ -410,8 +312,6 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ this._transformSystemDirty = false; this._allocatedParticles = 0; - this.drawMode = cc.PARTICLE_SHAPE_MODE; - this.shapeType = cc.PARTICLE_BALL_SHAPE; this._isActive = false; this.particleCount = 0; this.duration = 0; @@ -432,44 +332,36 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ this._totalParticles = 0; this._texture = null; this._opacityModifyRGB = false; - this.positionType = cc.PARTICLE_TYPE_FREE; + this.positionType = cc.ParticleSystem.TYPE_FREE; this.autoRemoveOnFinish = false; - this._buffersVBO = [0, 0]; - this._quads = []; - this._indices = []; - this._pointRect = cc.rect(0, 0, 0, 0); this._textureLoaded = true; - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - this._quadsArrayBuffer = null; - } - - if (!plistFile || typeof(plistFile) === "number") { + if (!plistFile || cc.isNumber(plistFile)) { var ton = plistFile || 100; - this.setDrawMode(cc.PARTICLE_TEXTURE_MODE); + this.setDrawMode(cc.ParticleSystem.TEXTURE_MODE); this.initWithTotalParticles(ton); - }else{ + } else if (cc.isString(plistFile)) { this.initWithFile(plistFile); + } else if (cc.isObject(plistFile)) { + this.initWithDictionary(plistFile, ""); } }, + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ParticleSystem.CanvasRenderCmd(this); + else + return new cc.ParticleSystem.WebGLRenderCmd(this); + }, + /** - * initializes the indices for the vertices + * This is a hack function for performance, it's only available on Canvas mode.
    + * It's very expensive to change color on Canvas mode, so if set it to true, particle system will ignore the changing color operation. + * @param {boolean} ignore */ - initIndices:function () { - var locIndices = this._indices; - for (var i = 0, len = this._totalParticles; i < len; ++i) { - var i6 = i * 6; - var i4 = i * 4; - locIndices[i6 + 0] = i4 + 0; - locIndices[i6 + 1] = i4 + 1; - locIndices[i6 + 2] = i4 + 2; - - locIndices[i6 + 5] = i4 + 1; - locIndices[i6 + 4] = i4 + 2; - locIndices[i6 + 3] = i4 + 3; - } + ignoreColor: function(ignore){ + this._dontTint = ignore; }, /** @@ -479,73 +371,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.Rect} pointRect */ initTexCoordsWithRect:function (pointRect) { - var scaleFactor = cc.contentScaleFactor(); - // convert to pixels coords - var rect = cc.rect( - pointRect.x * scaleFactor, - pointRect.y * scaleFactor, - pointRect.width * scaleFactor, - pointRect.height * scaleFactor); - - var wide = pointRect.width; - var high = pointRect.height; - - if (this._texture) { - wide = this._texture.pixelsWidth; - high = this._texture.pixelsHeight; - } - - if(cc._renderType === cc._RENDER_TYPE_CANVAS) - return; - - var left, bottom, right, top; - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (rect.x * 2 + 1) / (wide * 2); - bottom = (rect.y * 2 + 1) / (high * 2); - right = left + (rect.width * 2 - 2) / (wide * 2); - top = bottom + (rect.height * 2 - 2) / (high * 2); - } else { - left = rect.x / wide; - bottom = rect.y / high; - right = left + rect.width / wide; - top = bottom + rect.height / high; - } - - // Important. Texture in cocos2d are inverted, so the Y component should be inverted - var temp = top; - top = bottom; - bottom = temp; - - var quads; - var start = 0, end = 0; - if (this._batchNode) { - quads = this._batchNode.textureAtlas.quads; - start = this.atlasIndex; - end = this.atlasIndex + this._totalParticles; - } else { - quads = this._quads; - start = 0; - end = this._totalParticles; - } - - for (var i = start; i < end; i++) { - if (!quads[i]) - quads[i] = cc.V3F_C4B_T2F_QuadZero(); - - // bottom-left vertex: - var selQuad = quads[i]; - selQuad.bl.texCoords.u = left; - selQuad.bl.texCoords.v = bottom; - // bottom-right vertex: - selQuad.br.texCoords.u = right; - selQuad.br.texCoords.v = bottom; - // top-left vertex: - selQuad.tl.texCoords.u = left; - selQuad.tl.texCoords.v = top; - // top-right vertex: - selQuad.tr.texCoords.u = right; - selQuad.tr.texCoords.v = top; - } + this._renderCmd.initTexCoordsWithRect(pointRect); }, /** @@ -561,38 +387,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.ParticleBatchNode} batchNode */ setBatchNode:function (batchNode) { - if (this._batchNode != batchNode) { - var oldBatch = this._batchNode; - - this._batchNode = batchNode; //weak reference - - if (batchNode) { - var locParticles = this._particles; - for (var i = 0; i < this._totalParticles; i++) - locParticles[i].atlasIndex = i; - } - - // NEW: is self render ? - if (!batchNode) { - this._allocMemory(); - this.initIndices(); - this.setTexture(oldBatch.getTexture()); - //if (cc.TEXTURE_ATLAS_USE_VAO) - // this._setupVBOandVAO(); - //else - this._setupVBO(); - } else if (!oldBatch) { - // OLD: was it self render cleanup ? - // copy current state to batch - this._batchNode.textureAtlas._copyQuadsToTextureAtlas(this._quads, this.atlasIndex); - - //delete buffer - cc._renderContext.deleteBuffer(this._buffersVBO[1]); //where is re-bindBuffer code? - - //if (cc.TEXTURE_ATLAS_USE_VAO) - // glDeleteVertexArrays(1, this._VAOname); - } - } + this._renderCmd.setBatchNode(batchNode); }, /** @@ -612,35 +407,35 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ }, /** - * Return DrawMode of ParticleSystem + * Return DrawMode of ParticleSystem (Canvas Mode only) * @return {Number} */ getDrawMode:function () { - return this.drawMode; + return this._renderCmd.getDrawMode(); }, /** - * DrawMode of ParticleSystem setter + * DrawMode of ParticleSystem setter (Canvas Mode only) * @param {Number} drawMode */ setDrawMode:function (drawMode) { - this.drawMode = drawMode; + this._renderCmd.setDrawMode(drawMode); }, /** - * Return ShapeType of ParticleSystem + * Return ShapeType of ParticleSystem (Canvas Mode only) * @return {Number} */ getShapeType:function () { - return this.shapeType; + return this._renderCmd.getShapeType(); }, /** - * ShapeType of ParticleSystem setter + * ShapeType of ParticleSystem setter (Canvas Mode only) * @param {Number} shapeType */ setShapeType:function (shapeType) { - this.shapeType = shapeType; + this._renderCmd.setShapeType(shapeType); }, /** @@ -688,7 +483,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Point | Object} */ getSourcePosition:function () { - return {x:this._sourcePosition.x, y:this._sourcePosition.y}; + return {x: this._sourcePosition.x, y: this._sourcePosition.y}; }, /** @@ -785,7 +580,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Point} */ getGravity:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getGravity() : Particle Mode should be Gravity"); var locGravity = this.modeA.gravity; return cc.p(locGravity.x, locGravity.y); @@ -796,7 +591,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.Point} gravity */ setGravity:function (gravity) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setGravity() : Particle Mode should be Gravity"); this.modeA.gravity = gravity; }, @@ -806,7 +601,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getSpeed:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getSpeed() : Particle Mode should be Gravity"); return this.modeA.speed; }, @@ -816,7 +611,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} speed */ setSpeed:function (speed) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setSpeed() : Particle Mode should be Gravity"); this.modeA.speed = speed; }, @@ -826,7 +621,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getSpeedVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getSpeedVar() : Particle Mode should be Gravity"); return this.modeA.speedVar; }, @@ -836,7 +631,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} speedVar */ setSpeedVar:function (speedVar) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setSpeedVar() : Particle Mode should be Gravity"); this.modeA.speedVar = speedVar; }, @@ -846,7 +641,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getTangentialAccel:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getTangentialAccel() : Particle Mode should be Gravity"); return this.modeA.tangentialAccel; }, @@ -856,7 +651,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} tangentialAccel */ setTangentialAccel:function (tangentialAccel) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setTangentialAccel() : Particle Mode should be Gravity"); this.modeA.tangentialAccel = tangentialAccel; }, @@ -866,7 +661,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getTangentialAccelVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getTangentialAccelVar() : Particle Mode should be Gravity"); return this.modeA.tangentialAccelVar; }, @@ -876,7 +671,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} tangentialAccelVar */ setTangentialAccelVar:function (tangentialAccelVar) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setTangentialAccelVar() : Particle Mode should be Gravity"); this.modeA.tangentialAccelVar = tangentialAccelVar; }, @@ -886,7 +681,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getRadialAccel:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getRadialAccel() : Particle Mode should be Gravity"); return this.modeA.radialAccel; }, @@ -896,7 +691,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} radialAccel */ setRadialAccel:function (radialAccel) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setRadialAccel() : Particle Mode should be Gravity"); this.modeA.radialAccel = radialAccel; }, @@ -906,7 +701,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getRadialAccelVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getRadialAccelVar() : Particle Mode should be Gravity"); return this.modeA.radialAccelVar; }, @@ -916,7 +711,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} radialAccelVar */ setRadialAccelVar:function (radialAccelVar) { - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setRadialAccelVar() : Particle Mode should be Gravity"); this.modeA.radialAccelVar = radialAccelVar; }, @@ -926,7 +721,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @returns {boolean} */ getRotationIsDir: function(){ - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.getRotationIsDir() : Particle Mode should be Gravity"); return this.modeA.rotationIsDir; }, @@ -936,7 +731,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {boolean} t */ setRotationIsDir: function(t){ - if(this.emitterMode !== cc.PARTICLE_MODE_GRAVITY) + if(this.emitterMode !== cc.ParticleSystem.MODE_GRAVITY) cc.log("cc.ParticleBatchNode.setRotationIsDir() : Particle Mode should be Gravity"); this.modeA.rotationIsDir = t; }, @@ -947,7 +742,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getStartRadius:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getStartRadius() : Particle Mode should be Radius"); return this.modeB.startRadius; }, @@ -957,7 +752,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} startRadius */ setStartRadius:function (startRadius) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setStartRadius() : Particle Mode should be Radius"); this.modeB.startRadius = startRadius; }, @@ -967,7 +762,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getStartRadiusVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getStartRadiusVar() : Particle Mode should be Radius"); return this.modeB.startRadiusVar; }, @@ -977,7 +772,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} startRadiusVar */ setStartRadiusVar:function (startRadiusVar) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setStartRadiusVar() : Particle Mode should be Radius"); this.modeB.startRadiusVar = startRadiusVar; }, @@ -987,7 +782,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getEndRadius:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getEndRadius() : Particle Mode should be Radius"); return this.modeB.endRadius; }, @@ -997,7 +792,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} endRadius */ setEndRadius:function (endRadius) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setEndRadius() : Particle Mode should be Radius"); this.modeB.endRadius = endRadius; }, @@ -1007,7 +802,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getEndRadiusVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getEndRadiusVar() : Particle Mode should be Radius"); return this.modeB.endRadiusVar; }, @@ -1017,7 +812,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param endRadiusVar */ setEndRadiusVar:function (endRadiusVar) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setEndRadiusVar() : Particle Mode should be Radius"); this.modeB.endRadiusVar = endRadiusVar; }, @@ -1027,7 +822,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getRotatePerSecond:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getRotatePerSecond() : Particle Mode should be Radius"); return this.modeB.rotatePerSecond; }, @@ -1037,7 +832,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} degrees */ setRotatePerSecond:function (degrees) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setRotatePerSecond() : Particle Mode should be Radius"); this.modeB.rotatePerSecond = degrees; }, @@ -1047,7 +842,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {Number} */ getRotatePerSecondVar:function () { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.getRotatePerSecondVar() : Particle Mode should be Radius"); return this.modeB.rotatePerSecondVar; }, @@ -1057,7 +852,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param degrees */ setRotatePerSecondVar:function (degrees) { - if(this.emitterMode !== cc.PARTICLE_MODE_RADIUS) + if(this.emitterMode !== cc.ParticleSystem.MODE_RADIUS) cc.log("cc.ParticleBatchNode.setRotatePerSecondVar() : Particle Mode should be Radius"); this.modeB.rotatePerSecondVar = degrees; }, @@ -1153,7 +948,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Color} */ getStartColor:function () { - return this._startColor; + return cc.color(this._startColor.r, this._startColor.g, this._startColor.b, this._startColor.a); }, /** @@ -1169,7 +964,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Color} */ getStartColorVar:function () { - return this._startColorVar; + return cc.color(this._startColorVar.r, this._startColorVar.g, this._startColorVar.b, this._startColorVar.a); }, /** @@ -1185,7 +980,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Color} */ getEndColor:function () { - return this._endColor; + return cc.color(this._endColor.r, this._endColor.g, this._endColor.b, this._endColor.a); }, /** @@ -1201,7 +996,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @return {cc.Color} */ getEndColorVar:function () { - return this._endColorVar; + return cc.color(this._endColorVar.r, this._endColorVar.g, this._endColorVar.b, this._endColorVar.a); }, /** @@ -1305,53 +1100,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {Number} tp totalParticles */ setTotalParticles:function (tp) { - //cc.assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads"); - if (cc._renderType === cc._RENDER_TYPE_CANVAS){ - this._totalParticles = (tp < 200) ? tp : 200; - return; - } - - // If we are setting the total numer of particles to a number higher - // than what is allocated, we need to allocate new arrays - if (tp > this._allocatedParticles) { - var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; - // Allocate new memory - this._indices = new Uint16Array(tp * 6); - var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize); - //TODO need fix - // Assign pointers - var locParticles = this._particles; - locParticles.length = 0; - var locQuads = this._quads; - locQuads.length = 0; - for (var j = 0; j < tp; j++) { - locParticles[j] = new cc.Particle(); - locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize); - } - this._allocatedParticles = tp; - this._totalParticles = tp; - - // Init particles - if (this._batchNode) { - for (var i = 0; i < tp; i++) - locParticles[i].atlasIndex = i; - } - - this._quadsArrayBuffer = locQuadsArrayBuffer; - - this.initIndices(); - //if (cc.TEXTURE_ATLAS_USE_VAO) - // this._setupVBOandVAO(); - //else - this._setupVBO(); - - //set the texture coord - if(this._texture){ - this.initTexCoordsWithRect(cc.rect(0, 0, this._texture.width, this._texture.height)); - } - } else - this._totalParticles = tp; - this.resetSystem(); + this._renderCmd.setTotalParticles(tp); }, /** @@ -1367,11 +1116,14 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.Texture2D } texture */ setTexture:function (texture) { + if(!texture) + return; + if(texture.isLoaded()){ this.setTextureWithRect(texture, cc.rect(0, 0, texture.width, texture.height)); } else { this._textureLoaded = false; - texture.addLoadedEventListener(function(sender){ + texture.addEventListener("load", function(sender){ this._textureLoaded = true; this.setTextureWithRect(sender, cc.rect(0, 0, sender.width, sender.height)); }, this); @@ -1394,12 +1146,12 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ */ setBlendFunc:function (src, dst) { if (dst === undefined) { - if (this._blendFunc != src) { + if (this._blendFunc !== src) { this._blendFunc = src; this._updateBlendFunc(); } } else { - if (this._blendFunc.src != src || this._blendFunc.dst != dst) { + if (this._blendFunc.src !== src || this._blendFunc.dst !== dst) { this._blendFunc = {src:src, dst:dst}; this._updateBlendFunc(); } @@ -1432,7 +1184,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * dest blend function = GL_ONE; */ isBlendAdditive:function () { - return (( this._blendFunc.src == cc.SRC_ALPHA && this._blendFunc.dst == cc.ONE) || (this._blendFunc.src == cc.ONE && this._blendFunc.dst == cc.ONE)); + return (( this._blendFunc.src === cc.SRC_ALPHA && this._blendFunc.dst === cc.ONE) || (this._blendFunc.src === cc.ONE && this._blendFunc.dst === cc.ONE)); }, /** @@ -1447,18 +1199,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ locBlendFunc.src = cc.SRC_ALPHA; locBlendFunc.dst = cc.ONE; } else { - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - if (this._texture && !this._texture.hasPremultipliedAlpha()) { - locBlendFunc.src = cc.SRC_ALPHA; - locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; - } else { - locBlendFunc.src = cc.BLEND_SRC; - locBlendFunc.dst = cc.BLEND_DST; - } - } else { - locBlendFunc.src = cc.BLEND_SRC; - locBlendFunc.dst = cc.BLEND_DST; - } + this._renderCmd._setBlendAdditive(); } }, @@ -1508,8 +1249,8 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ /** *

    Switch between different kind of emitter modes:
    - * - CCPARTICLE_MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration
    - * - CCPARTICLE_MODE_RADIUS: uses radius movement + rotation
    + * - CCParticleSystem.MODE_GRAVITY: uses gravity, speed, radial and tangential acceleration
    + * - CCParticleSystem.MODE_RADIUS: uses radius movement + rotation
    *

    * @param {Number} emitterMode */ @@ -1625,7 +1366,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ this.emitterMode = parseInt(locValueForKey("emitterType", dictionary)); // Mode A: Gravity + tangential accel + radial accel - if (this.emitterMode == cc.PARTICLE_MODE_GRAVITY) { + if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { var locModeA = this.modeA; // gravity locModeA.gravity.x = parseFloat(locValueForKey("gravityx", dictionary)); @@ -1652,7 +1393,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ // rotation is dir var locRotationIsDir = locValueForKey("rotationIsDir", dictionary).toLowerCase(); locModeA.rotationIsDir = (locRotationIsDir != null && (locRotationIsDir === "true" || locRotationIsDir === "1")); - } else if (this.emitterMode == cc.PARTICLE_MODE_RADIUS) { + } else if (this.emitterMode === cc.ParticleSystem.MODE_RADIUS) { // or Mode B: radius movement var locModeB = this.modeB; locModeB.startRadius = parseFloat(locValueForKey("maxRadius", dictionary)); @@ -1682,14 +1423,14 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ // Try to get the texture from the cache var textureName = locValueForKey("textureFileName", dictionary); var imgPath = cc.path.changeBasename(this._plistFile, textureName); - var tex = cc.textureCache.textureForKey(imgPath); + var tex = cc.textureCache.getTextureForKey(imgPath); if (tex) { this.setTexture(tex); } else { var textureData = locValueForKey("textureImageData", dictionary); - if (textureData && textureData.length == 0) { + if (!textureData || textureData.length === 0) { tex = cc.textureCache.addImage(imgPath); if (!tex) return false; @@ -1719,7 +1460,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ cc.textureCache.cacheImage(imgPath, canvasObj); - var addTexture = cc.textureCache.textureForKey(imgPath); + var addTexture = cc.textureCache.getTextureForKey(imgPath); if(!addTexture) cc.log("cc.ParticleSystem.initWithDictionary() : error loading the texture"); this.setTexture(addTexture); @@ -1763,10 +1504,10 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ this._blendFunc.dst = cc.BLEND_DST; // default movement type; - this.positionType = cc.PARTICLE_TYPE_FREE; + this.positionType = cc.ParticleSystem.TYPE_FREE; // by default be in mode A: - this.emitterMode = cc.PARTICLE_MODE_GRAVITY; + this.emitterMode = cc.ParticleSystem.MODE_GRAVITY; // default: modulate // XXX: not used @@ -1778,24 +1519,15 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ // udpate after action in run! this.scheduleUpdateWithPriority(1); - - if(cc._renderType === cc._RENDER_TYPE_WEBGL){ - // allocating data space - if (!this._allocMemory()) - return false; - - this.initIndices(); - //if (cc.TEXTURE_ATLAS_USE_VAO) - // this._setupVBOandVAO(); - //else - this._setupVBO(); - - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); - } - + this._renderCmd._initWithTotalParticles(numberOfParticles); return true; }, + /** + * Unschedules the "update" method. + * @function + * @see scheduleUpdate(); + */ destroyParticleSystem:function () { this.unscheduleUpdate(); }, @@ -1807,17 +1539,8 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ addParticle: function () { if (this.isFull()) return false; - var particle, particles = this._particles; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - if (this.particleCount < particles.length) { - particle = particles[this.particleCount]; - } else { - particle = new cc.Particle(); - particles.push(particle); - } - } else { - particle = particles[this.particleCount]; - } + + var particle = this._renderCmd.addParticle(); this.initParticle(particle); ++this.particleCount; return true; @@ -1842,33 +1565,18 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ var start, end; var locStartColor = this._startColor, locStartColorVar = this._startColorVar; var locEndColor = this._endColor, locEndColorVar = this._endColorVar; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - start = cc.color( - cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), - cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), - cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), - cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) - ); - end = cc.color( - cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), - cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), - cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), - cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) - ); - } else { - start = { - r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), - g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), - b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), - a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) - }; - end = { - r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), - g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), - b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), - a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) - }; - } + start = { + r: cc.clampf(locStartColor.r + locStartColorVar.r * locRandomMinus11(), 0, 255), + g: cc.clampf(locStartColor.g + locStartColorVar.g * locRandomMinus11(), 0, 255), + b: cc.clampf(locStartColor.b + locStartColorVar.b * locRandomMinus11(), 0, 255), + a: cc.clampf(locStartColor.a + locStartColorVar.a * locRandomMinus11(), 0, 255) + }; + end = { + r: cc.clampf(locEndColor.r + locEndColorVar.r * locRandomMinus11(), 0, 255), + g: cc.clampf(locEndColor.g + locEndColorVar.g * locRandomMinus11(), 0, 255), + b: cc.clampf(locEndColor.b + locEndColorVar.b * locRandomMinus11(), 0, 255), + a: cc.clampf(locEndColor.a + locEndColorVar.a * locRandomMinus11(), 0, 255) + }; particle.color = start; var locParticleDeltaColor = particle.deltaColor, locParticleTimeToLive = particle.timeToLive; @@ -1882,7 +1590,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ startS = Math.max(0, startS); // No negative value particle.size = startS; - if (this.endSize === cc.PARTICLE_START_SIZE_EQUAL_TO_END_SIZE) { + if (this.endSize === cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE) { particle.deltaSize = 0; } else { var endS = this.endSize + this.endSizeVar * locRandomMinus11(); @@ -1897,9 +1605,9 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ particle.deltaRotation = (endA - startA) / locParticleTimeToLive; // position - if (this.positionType == cc.PARTICLE_TYPE_FREE) + if (this.positionType === cc.ParticleSystem.TYPE_FREE) particle.startPos = this.convertToWorldSpace(this._pointZeroForParticle); - else if (this.positionType == cc.PARTICLE_TYPE_RELATIVE){ + else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE){ particle.startPos.x = this._position.x; particle.startPos.y = this._position.y; } @@ -1908,7 +1616,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ var a = cc.degreesToRadians(this.angle + this.angleVar * locRandomMinus11()); // Mode Gravity: A - if (this.emitterMode === cc.PARTICLE_MODE_GRAVITY) { + if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { var locModeA = this.modeA, locParticleModeA = particle.modeA; var s = locModeA.speed + locModeA.speedVar * locRandomMinus11(); @@ -1925,7 +1633,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ // rotation is dir if(locModeA.rotationIsDir) - particle.rotation = -cc.radiansToDegress(cc.pToAngle(locParticleModeA.dir)); + particle.rotation = -cc.radiansToDegrees(cc.pToAngle(locParticleModeA.dir)); } else { // Mode Radius: B var locModeB = this.modeB, locParitlceModeB = particle.modeB; @@ -1935,7 +1643,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ var endRadius = locModeB.endRadius + locModeB.endRadiusVar * locRandomMinus11(); locParitlceModeB.radius = startRadius; - locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.PARTICLE_START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; + locParitlceModeB.deltaRadius = (locModeB.endRadius === cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS) ? 0 : (endRadius - startRadius) / locParticleTimeToLive; locParitlceModeB.angle = a; locParitlceModeB.degreesPerSecond = cc.degreesToRadians(locModeB.rotatePerSecond + locModeB.rotatePerSecondVar * locRandomMinus11()); @@ -1976,128 +1684,14 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.Point} newPosition */ updateQuadWithParticle:function (particle, newPosition) { - var quad = null; - if (this._batchNode) { - var batchQuads = this._batchNode.textureAtlas.quads; - quad = batchQuads[this.atlasIndex + particle.atlasIndex]; - this._batchNode.textureAtlas.dirty = true; - } else - quad = this._quads[this._particleIdx]; - - var r, g, b, a; - if (this._opacityModifyRGB) { - r = 0 | (particle.color.r * particle.color.a/255); - g = 0 | (particle.color.g * particle.color.a/255); - b = 0 | (particle.color.b * particle.color.a/255); - } else { - r = 0 | (particle.color.r ); - g = 0 | (particle.color.g ); - b = 0 | (particle.color.b ); - } - a = 0 | (particle.color.a ); - - var locColors = quad.bl.colors; - locColors.r = r; - locColors.g = g; - locColors.b = b; - locColors.a = a; - - locColors = quad.br.colors; - locColors.r = r; - locColors.g = g; - locColors.b = b; - locColors.a = a; - - locColors = quad.tl.colors; - locColors.r = r; - locColors.g = g; - locColors.b = b; - locColors.a = a; - - locColors = quad.tr.colors; - locColors.r = r; - locColors.g = g; - locColors.b = b; - locColors.a = a; - - // vertices - var size_2 = particle.size / 2; - if (particle.rotation) { - var x1 = -size_2; - var y1 = -size_2; - - var x2 = size_2; - var y2 = size_2; - var x = newPosition.x; - var y = newPosition.y; - - var rad = -cc.degreesToRadians(particle.rotation); - var cr = Math.cos(rad); - var sr = Math.sin(rad); - var ax = x1 * cr - y1 * sr + x; - var ay = x1 * sr + y1 * cr + y; - var bx = x2 * cr - y1 * sr + x; - var by = x2 * sr + y1 * cr + y; - var cx = x2 * cr - y2 * sr + x; - var cy = x2 * sr + y2 * cr + y; - var dx = x1 * cr - y2 * sr + x; - var dy = x1 * sr + y2 * cr + y; - - // bottom-left - quad.bl.vertices.x = ax; - quad.bl.vertices.y = ay; - - // bottom-right vertex: - quad.br.vertices.x = bx; - quad.br.vertices.y = by; - - // top-left vertex: - quad.tl.vertices.x = dx; - quad.tl.vertices.y = dy; - - // top-right vertex: - quad.tr.vertices.x = cx; - quad.tr.vertices.y = cy; - } else { - // bottom-left vertex: - quad.bl.vertices.x = newPosition.x - size_2; - quad.bl.vertices.y = newPosition.y - size_2; - - // bottom-right vertex: - quad.br.vertices.x = newPosition.x + size_2; - quad.br.vertices.y = newPosition.y - size_2; - - // top-left vertex: - quad.tl.vertices.x = newPosition.x - size_2; - quad.tl.vertices.y = newPosition.y + size_2; - - // top-right vertex: - quad.tr.vertices.x = newPosition.x + size_2; - quad.tr.vertices.y = newPosition.y + size_2; - } + this._renderCmd.updateQuadWithParticle(particle, newPosition); }, /** * should be overridden by subclasses */ postStep:function () { - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - var gl = cc._renderContext; - - gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); - gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); - - // Option 2: Data - // glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * particleCount, quads_, GL_DYNAMIC_DRAW); - - // Option 3: Orphaning + glMapBuffer - // glBufferData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*m_uTotalParticles, NULL, GL_STREAM_DRAW); - // void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); - // memcpy(buf, m_pQuads, sizeof(m_pQuads[0])*m_uTotalParticles); - // glUnmapBuffer(GL_ARRAY_BUFFER); - - //cc.checkGLErrorDebug(); - } + this._renderCmd.postStep(); }, /** @@ -2118,21 +1712,20 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ } this._elapsed += dt; - if (this.duration != -1 && this.duration < this._elapsed) + if (this.duration !== -1 && this.duration < this._elapsed) this.stopSystem(); } this._particleIdx = 0; var currentPosition = cc.Particle.TemporaryPoints[0]; - if (this.positionType == cc.PARTICLE_TYPE_FREE) { + if (this.positionType === cc.ParticleSystem.TYPE_FREE) { cc.pIn(currentPosition, this.convertToWorldSpace(this._pointZeroForParticle)); - } else if (this.positionType == cc.PARTICLE_TYPE_RELATIVE) { + } else if (this.positionType === cc.ParticleSystem.TYPE_RELATIVE) { currentPosition.x = this._position.x; currentPosition.y = this._position.y; } if (this._visible) { - // Used to reduce memory allocation / creation within the loop var tpa = cc.Particle.TemporaryPoints[1], tpb = cc.Particle.TemporaryPoints[2], @@ -2153,7 +1746,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ if (selParticle.timeToLive > 0) { // Mode A: gravity, direction, tangential accel & radial accel - if (this.emitterMode == cc.PARTICLE_MODE_GRAVITY) { + if (this.emitterMode === cc.ParticleSystem.MODE_GRAVITY) { var tmp = tpc, radial = tpa, tangential = tpb; @@ -2185,7 +1778,6 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ cc.pIn(tmp, selParticle.modeA.dir); cc.pMultIn(tmp, dt); cc.pAddIn(selParticle.pos, tmp); - } else { // Mode B: radius movement var selModeB = selParticle.modeB; @@ -2198,13 +1790,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ } // color - if (!this._dontTint) { - selParticle.color.r += (selParticle.deltaColor.r * dt); - selParticle.color.g += (selParticle.deltaColor.g * dt); - selParticle.color.b += (selParticle.deltaColor.b * dt); - selParticle.color.a += (selParticle.deltaColor.a * dt); - selParticle.isChangeColor = true; - } + this._renderCmd._updateDeltaColor(selParticle, dt); // size selParticle.size += (selParticle.deltaSize * dt); @@ -2217,15 +1803,13 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ // update values in quad // var newPos = tpa; - if (this.positionType == cc.PARTICLE_TYPE_FREE || this.positionType == cc.PARTICLE_TYPE_RELATIVE) { - + if (this.positionType === cc.ParticleSystem.TYPE_FREE || this.positionType === cc.ParticleSystem.TYPE_RELATIVE) { var diff = tpb; cc.pIn(diff, currentPosition); cc.pSubIn(diff, selParticle.startPos); cc.pIn(newPos, selParticle.pos); cc.pSubIn(newPos, diff); - } else { cc.pIn(newPos, selParticle.pos); } @@ -2236,16 +1820,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ newPos.x += this._position.x; newPos.y += this._position.y; } - - if (cc._renderType == cc._RENDER_TYPE_WEBGL) { - // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point) - // the implementation of updateQuadWithParticle must use - // the x and y values directly - this.updateQuadWithParticle(selParticle, newPos); - } else { - cc.pIn(selParticle.drawPos, newPos); - } - //updateParticleImp(self, updateParticleSel, p, newPos); + this._renderCmd.updateParticlePosition(selParticle, newPos); // update particle counter ++this._particleIdx; @@ -2260,13 +1835,12 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ if (this._batchNode) { //disable the switched particle this._batchNode.disableParticle(this.atlasIndex + currentIndex); - //switch indexes locParticles[this.particleCount - 1].atlasIndex = currentIndex; } --this.particleCount; - if (this.particleCount == 0 && this.autoRemoveOnFinish) { + if (this.particleCount === 0 && this.autoRemoveOnFinish) { this.unscheduleUpdate(); this._parent.removeChild(this, true); return; @@ -2280,17 +1854,20 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ this.postStep(); }, + /** + * update emitter's status (dt = 0) + */ updateWithNoTime:function () { this.update(0); }, - /** - * return the string found by key in dict. - * @param {string} key - * @param {object} dict - * @return {String} "" if not found; return the string if found. - * @private - */ + // + // return the string found by key in dict. + // @param {string} key + // @param {object} dict + // @return {String} "" if not found; return the string if found. + // @private + // _valueForKey:function (key, dict) { if (dict) { var pString = dict[key]; @@ -2309,7 +1886,7 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ if (locTexture && locTexture instanceof cc.Texture2D) { this._opacityModifyRGB = false; var locBlendFunc = this._blendFunc; - if (locBlendFunc.src == cc.BLEND_SRC && locBlendFunc.dst == cc.BLEND_DST) { + if (locBlendFunc.src === cc.BLEND_SRC && locBlendFunc.dst === cc.BLEND_DST) { if (locTexture.hasPremultipliedAlpha()) { this._opacityModifyRGB = true; } else { @@ -2320,112 +1897,103 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ } }, + /** + * to copy object with deep copy. + * returns a clone of action. + * + * @return {cc.ParticleSystem} + */ clone:function () { var retParticle = new cc.ParticleSystem(); // self, not super - if (retParticle.initWithTotalParticles(this._totalParticles)) { + if (retParticle.initWithTotalParticles(this.getTotalParticles())) { // angle - retParticle.angle = this.angle; - retParticle.angleVar = this.angleVar; + retParticle.setAngle(this.getAngle()); + retParticle.setAngleVar(this.getAngleVar()); // duration - retParticle.duration = this.duration; + retParticle.setDuration(this.getDuration()); // blend function - retParticle._blendFunc.src = this._blendFunc.src; - retParticle._blendFunc.dst = this._blendFunc.dst; + var blend = this.getBlendFunc(); + retParticle.setBlendFunc(blend.src,blend.dst); // color - var particleStartColor = retParticle._startColor, locStartColor = this._startColor; - particleStartColor.r = locStartColor.r; - particleStartColor.g = locStartColor.g; - particleStartColor.b = locStartColor.b; - particleStartColor.a = locStartColor.a; - - var particleStartColorVar = retParticle._startColorVar, locStartColorVar = this._startColorVar; - particleStartColorVar.r = locStartColorVar.r; - particleStartColorVar.g = locStartColorVar.g; - particleStartColorVar.b = locStartColorVar.b; - particleStartColorVar.a = locStartColorVar.a; - - var particleEndColor = retParticle._endColor, locEndColor = this._endColor; - particleEndColor.r = locEndColor.r; - particleEndColor.g = locEndColor.g; - particleEndColor.b = locEndColor.b; - particleEndColor.a = locEndColor.a; - - var particleEndColorVar = retParticle._endColorVar, locEndColorVar = this._endColorVar; - particleEndColorVar.r = locEndColorVar.r; - particleEndColorVar.g = locEndColorVar.g; - particleEndColorVar.b = locEndColorVar.b; - particleEndColorVar.a = locEndColorVar.a; + retParticle.setStartColor(this.getStartColor()); - // particle size - retParticle.startSize = this.startSize; - retParticle.startSizeVar = this.startSizeVar; - retParticle.endSize = this.endSize; - retParticle.endSizeVar = this.endSizeVar; + retParticle.setStartColorVar(this.getStartColorVar()); + + retParticle.setEndColor(this.getEndColor()); + + retParticle.setEndColorVar(this.getEndColorVar()); + + // this size + retParticle.setStartSize(this.getStartSize()); + retParticle.setStartSizeVar(this.getStartSizeVar()); + retParticle.setEndSize(this.getEndSize()); + retParticle.setEndSizeVar(this.getEndSizeVar()); // position - retParticle.x = this._position.x; - retParticle.y = this._position.y; - retParticle._posVar.x = this._posVar.x; - retParticle._posVar.y = this._posVar.y; + retParticle.setPosition(cc.p(this.x, this.y)); + retParticle.setPosVar(cc.p(this.getPosVar().x,this.getPosVar().y)); + + retParticle.setPositionType(this.getPositionType()); // Spinning - retParticle.startSpin = this.startSpin; - retParticle.startSpinVar = this.startSpinVar; - retParticle.endSpin = this.endSpin; - retParticle.endSpinVar = this.endSpinVar; + retParticle.setStartSpin(this.getStartSpin()||0); + retParticle.setStartSpinVar(this.getStartSpinVar()||0); + retParticle.setEndSpin(this.getEndSpin()||0); + retParticle.setEndSpinVar(this.getEndSpinVar()||0); - retParticle.emitterMode = this.emitterMode; + retParticle.setEmitterMode(this.getEmitterMode()); // Mode A: Gravity + tangential accel + radial accel - if (this.emitterMode == cc.PARTICLE_MODE_GRAVITY) { - var particleModeA = retParticle.modeA, locModeA = this.modeA; + if (this.getEmitterMode() === cc.ParticleSystem.MODE_GRAVITY) { // gravity - particleModeA.gravity.x = locModeA.gravity.x; - particleModeA.gravity.y = locModeA.gravity.y; + var gra = this.getGravity(); + retParticle.setGravity(cc.p(gra.x,gra.y)); // speed - particleModeA.speed = locModeA.speed; - particleModeA.speedVar = locModeA.speedVar; + retParticle.setSpeed(this.getSpeed()); + retParticle.setSpeedVar(this.getSpeedVar()); // radial acceleration - particleModeA.radialAccel = locModeA.radialAccel; - - particleModeA.radialAccelVar = locModeA.radialAccelVar; + retParticle.setRadialAccel(this.getRadialAccel()); + retParticle.setRadialAccelVar(this.getRadialAccelVar()); // tangential acceleration - particleModeA.tangentialAccel = locModeA.tangentialAccel; + retParticle.setTangentialAccel(this.getTangentialAccel()); + retParticle.setTangentialAccelVar(this.getTangentialAccelVar()); - particleModeA.tangentialAccelVar = locModeA.tangentialAccelVar; - } else if (this.emitterMode == cc.PARTICLE_MODE_RADIUS) { - var particleModeB = retParticle.modeB, locModeB = this.modeB; + } else if (this.getEmitterMode() === cc.ParticleSystem.MODE_RADIUS) { // or Mode B: radius movement - particleModeB.startRadius = locModeB.startRadius; - particleModeB.startRadiusVar = locModeB.startRadiusVar; - particleModeB.endRadius = locModeB.endRadius; - particleModeB.endRadiusVar = locModeB.endRadiusVar; - particleModeB.rotatePerSecond = locModeB.rotatePerSecond; - particleModeB.rotatePerSecondVar = locModeB.rotatePerSecondVar; + retParticle.setStartRadius(this.getStartRadius()); + retParticle.setStartRadiusVar(this.getStartRadiusVar()); + retParticle.setEndRadius(this.getEndRadius()); + retParticle.setEndRadiusVar(this.getEndRadiusVar()); + + retParticle.setRotatePerSecond(this.getRotatePerSecond()); + retParticle.setRotatePerSecondVar(this.getRotatePerSecondVar()); } // life span - retParticle.life = this.life; - retParticle.lifeVar = this.lifeVar; + retParticle.setLife(this.getLife()); + retParticle.setLifeVar(this.getLifeVar()); // emission Rate - retParticle.emissionRate = this.emissionRate; + retParticle.setEmissionRate(this.getEmissionRate()); //don't get the internal texture if a batchNode is used - if (!this._batchNode) { + if (!this.getBatchNode()) { // Set a compatible default for the alpha transfer - retParticle._opacityModifyRGB = this._opacityModifyRGB; - + retParticle.setOpacityModifyRGB(this.isOpacityModifyRGB()); // texture - retParticle._texture = this._texture; + var texture = this.getTexture(); + if(texture){ + var size = texture.getContentSize(); + retParticle.setTextureWithRect(texture, cc.rect(0, 0, size.width, size.height)); + } } } return retParticle; @@ -2437,15 +2005,18 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ *

    * @param {cc.SpriteFrame} spriteFrame */ - setDisplayFrame:function (spriteFrame) { + setDisplayFrame: function (spriteFrame) { + if (!spriteFrame) + return; + var locOffset = spriteFrame.getOffsetInPixels(); - if(locOffset.x != 0 || locOffset.y != 0) + if (locOffset.x !== 0 || locOffset.y !== 0) cc.log("cc.ParticleSystem.setDisplayFrame(): QuadParticle only supports SpriteFrames with no offsets"); // update texture before updating texture rect - if (cc._renderType === cc._RENDER_TYPE_WEBGL) - if (!this._texture || spriteFrame.getTexture()._webTextureObj != this._texture._webTextureObj) - this.setTexture(spriteFrame.getTexture()); + var texture = spriteFrame.getTexture(), locTexture = this._texture; + if (locTexture !== texture) + this.setTexture(texture); }, /** @@ -2453,238 +2024,21 @@ cc.ParticleSystem = cc.Node.extend(/** @lends cc.ParticleSystem# */{ * @param {cc.Texture2D} texture * @param {cc.Rect} rect */ - setTextureWithRect:function (texture, rect) { + setTextureWithRect: function (texture, rect) { var locTexture = this._texture; - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - // Only update the texture if is different from the current one - if ((!locTexture || texture._webTextureObj != locTexture._webTextureObj) && (locTexture != texture)) { - this._texture = texture; - this._updateBlendFunc(); - } - } else { - if ((!locTexture || texture != locTexture) && (locTexture != texture)) { - this._texture = texture; - this._updateBlendFunc(); - } + if (locTexture !== texture) { + this._texture = texture; + this._updateBlendFunc(); } - - this._pointRect = rect; this.initTexCoordsWithRect(rect); }, /** - * draw particle - * @param {CanvasRenderingContext2D} ctx CanvasContext - * @override - */ - draw:function (ctx) { - if(!this._textureLoaded || this._batchNode) // draw should not be called when added to a particleBatchNode - return; - - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - this._drawForCanvas(ctx); - else - this._drawForWebGL(ctx); - - cc.g_NumberOfDraws++; - }, - - _drawForCanvas:function (ctx) { - var context = ctx || cc._renderContext; - context.save(); - if (this.isBlendAdditive()) - context.globalCompositeOperation = 'lighter'; - else - context.globalCompositeOperation = 'source-over'; - - for (var i = 0; i < this.particleCount; i++) { - var particle = this._particles[i]; - var lpx = (0 | (particle.size * 0.5)); - - if (this.drawMode == cc.PARTICLE_TEXTURE_MODE) { - - var element = this._texture.getHtmlElementObj(); - - // Delay drawing until the texture is fully loaded by the browser - if (!element.width || !element.height) - continue; - - context.save(); - context.globalAlpha = particle.color.a / 255; - context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y)); - - var size = Math.floor(particle.size / 4) * 4; - var w = this._pointRect.width; - var h = this._pointRect.height; - - context.scale( - Math.max((1 / w) * size, 0.000001), - Math.max((1 / h) * size, 0.000001) - ); - - - if (particle.rotation) - context.rotate(cc.degreesToRadians(particle.rotation)); - - context.translate(-(0 | (w / 2)), -(0 | (h / 2))); - if (particle.isChangeColor) { - - var cacheTextureForColor = cc.textureCache.getTextureColors(element); - if (cacheTextureForColor) { - // Create another cache for the tinted version - // This speeds up things by a fair bit - if (!cacheTextureForColor.tintCache) { - cacheTextureForColor.tintCache = cc.newElement('canvas'); - cacheTextureForColor.tintCache.width = element.width; - cacheTextureForColor.tintCache.height = element.height; - } - cc.generateTintImage(element, cacheTextureForColor, particle.color, this._pointRect, cacheTextureForColor.tintCache); - element = cacheTextureForColor.tintCache; - } - } - - context.drawImage(element, 0, 0); - context.restore(); - - } else { - context.save(); - context.globalAlpha = particle.color.a / 255; - - context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y)); - - if (this.shapeType == cc.PARTICLE_STAR_SHAPE) { - if (particle.rotation) - context.rotate(cc.degreesToRadians(particle.rotation)); - cc._drawingUtil.drawStar(context, lpx, particle.color); - } else - cc._drawingUtil.drawColorBall(context, lpx, particle.color); - context.restore(); - } - } - context.restore(); - }, - - _drawForWebGL:function (ctx) { - if(!this._texture) - return; - - var gl = ctx || cc._renderContext; - - this._shaderProgram.use(); - this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); - - cc.glBindTexture2D(this._texture); - cc.glBlendFuncForParticle(this._blendFunc.src, this._blendFunc.dst); - - //cc.assert(this._particleIdx == this.particleCount, "Abnormal error in particle quad"); - - // - // Using VBO without VAO - // - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors - gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); - gl.drawElements(gl.TRIANGLES, this._particleIdx * 6, gl.UNSIGNED_SHORT, 0); - }, - - /** - * listen the event that coming to foreground on Android + * listen the event that coming to foreground on Android (An empty function for native) * @param {cc.Class} obj */ listenBackToForeground:function (obj) { - if (cc.TEXTURE_ATLAS_USE_VAO) - this._setupVBOandVAO(); - else - this._setupVBO(); - }, - - _setupVBOandVAO:function () { - //Not support on WebGL - /*if (cc._renderType == cc._RENDER_TYPE_CANVAS) { - return; - }*/ - - //NOT SUPPORTED - /*glGenVertexArrays(1, this._VAOname); - glBindVertexArray(this._VAOname); - - var kQuadSize = sizeof(m_pQuads[0].bl); - - glGenBuffers(2, this._buffersVBO[0]); - - glBindBuffer(GL_ARRAY_BUFFER, this._buffersVBO[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(this._quads[0]) * this._totalParticles, this._quads, GL_DYNAMIC_DRAW); - - // vertices - glEnableVertexAttribArray(kCCVertexAttrib_Position); - glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, vertices)); - - // colors - glEnableVertexAttribArray(kCCVertexAttrib_Color); - glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, offsetof(ccV3F_C4B_T2F, colors)); - - // tex coords - glEnableVertexAttribArray(kCCVertexAttrib_TexCoords); - glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, offsetof(ccV3F_C4B_T2F, texCoords)); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_pIndices[0]) * m_uTotalParticles * 6, m_pIndices, GL_STATIC_DRAW); - - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - CHECK_GL_ERROR_DEBUG();*/ - }, - - _setupVBO:function () { - if (cc._renderType == cc._RENDER_TYPE_CANVAS) - return; - - var gl = cc._renderContext; - - //gl.deleteBuffer(this._buffersVBO[0]); - this._buffersVBO[0] = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); - gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); - - this._buffersVBO[1] = gl.createBuffer(); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); - - //cc.checkGLErrorDebug(); - }, - - _allocMemory:function () { - if (cc._renderType === cc._RENDER_TYPE_CANVAS) - return true; - - //cc.assert((!this._quads && !this._indices), "Memory already allocated"); - if(this._batchNode){ - cc.log("cc.ParticleSystem._allocMemory(): Memory should not be allocated when not using batchNode"); - return false; - } - - var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; - var totalParticles = this._totalParticles; - var locQuads = this._quads; - locQuads.length = 0; - this._indices = new Uint16Array(totalParticles * 6); - var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles); - - for (var i = 0; i < totalParticles; i++) - locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize); - if (!locQuads || !this._indices) { - cc.log("cocos2d: Particle system: not enough memory"); - return false; - } - this._quadsArrayBuffer = locQuadsArrayBuffer; - return true; + //do nothing } }); @@ -2698,6 +2052,12 @@ cc.defineGetterSetter(_p, "opacityModifyRGB", _p.isOpacityModifyRGB, _p.setOpaci _p.batchNode; cc.defineGetterSetter(_p, "batchNode", _p.getBatchNode, _p.setBatchNode); /** @expose */ +_p.drawMode; +cc.defineGetterSetter(_p, "drawMode", _p.getDrawMode, _p.setDrawMode); +/** @expose */ +_p.shapeType; +cc.defineGetterSetter(_p, "shapeType", _p.getShapeType, _p.setShapeType); +/** @expose */ _p.active; cc.defineGetterSetter(_p, "active", _p.isActive); /** @expose */ @@ -2773,6 +2133,7 @@ cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); * This plist files can be create manually or with Particle Designer:
    * http://particledesigner.71squared.com/
    *

    + * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. * @param {String|Number} plistFile * @return {cc.ParticleSystem} */ @@ -2780,6 +2141,18 @@ cc.ParticleSystem.create = function (plistFile) { return new cc.ParticleSystem(plistFile); }; +/** + *

    return the string found by key in dict.
    + * This plist files can be create manually or with Particle Designer:
    + * http://particledesigner.71squared.com/
    + *

    + * @deprecated since v3.0 please use new cc.ParticleSysytem(plistFile) instead. + * @function + * @param {String|Number} plistFile + * @return {cc.ParticleSystem} + */ +cc.ParticleSystem.createWithTotalParticles = cc.ParticleSystem.create; + // Different modes /** * Mode A:Gravity + Tangential Accel + Radial Accel @@ -2817,12 +2190,12 @@ cc.ParticleSystem.ModeA = function (gravity, speed, speedVar, tangentialAccel, t * Mode B: circular movement (gravity, radial accel and tangential accel don't are not used in this mode) * @Class * @Construct - * @param {Number} startRadius The starting radius of the particles. - * @param {Number} startRadiusVar The starting radius variance of the particles. - * @param {Number} endRadius The ending radius of the particles. - * @param {Number} endRadiusVar The ending radius variance of the particles. - * @param {Number} rotatePerSecond Number of degress to rotate a particle around the source pos per second. - * @param {Number} rotatePerSecondVar Variance in degrees for rotatePerSecond. + * @param {Number} [startRadius=0] The starting radius of the particles. + * @param {Number} [startRadiusVar=0] The starting radius variance of the particles. + * @param {Number} [endRadius=0] The ending radius of the particles. + * @param {Number} [endRadiusVar=0] The ending radius variance of the particles. + * @param {Number} [rotatePerSecond=0] Number of degrees to rotate a particle around the source pos per second. + * @param {Number} [rotatePerSecondVar=0] Variance in degrees for rotatePerSecond. */ cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endRadiusVar, rotatePerSecond, rotatePerSecondVar) { /** The starting radius of the particles. Only available in 'Radius' mode. */ @@ -2838,3 +2211,88 @@ cc.ParticleSystem.ModeB = function (startRadius, startRadiusVar, endRadius, endR /** Variance in degrees for rotatePerSecond. Only available in 'Radius' mode. */ this.rotatePerSecondVar = rotatePerSecondVar || 0; }; + +/** + * Shape Mode of Particle Draw + * @constant + * @type Number + */ +cc.ParticleSystem.SHAPE_MODE = 0; + +/** + * Texture Mode of Particle Draw + * @constant + * @type Number + */ +cc.ParticleSystem.TEXTURE_MODE = 1; + +/** + * Star Shape for ShapeMode of Particle + * @constant + * @type Number + */ +cc.ParticleSystem.STAR_SHAPE = 0; + +/** + * Ball Shape for ShapeMode of Particle + * @constant + * @type Number + */ +cc.ParticleSystem.BALL_SHAPE = 1; + +/** + * The Particle emitter lives forever + * @constant + * @type Number + */ +cc.ParticleSystem.DURATION_INFINITY = -1; + +/** + * The starting size of the particle is equal to the ending size + * @constant + * @type Number + */ +cc.ParticleSystem.START_SIZE_EQUAL_TO_END_SIZE = -1; + +/** + * The starting radius of the particle is equal to the ending radius + * @constant + * @type Number + */ +cc.ParticleSystem.START_RADIUS_EQUAL_TO_END_RADIUS = -1; + +/** + * Gravity mode (A mode) + * @constant + * @type Number + */ +cc.ParticleSystem.MODE_GRAVITY = 0; + +/** + * Radius mode (B mode) + * @constant + * @type Number + */ +cc.ParticleSystem.MODE_RADIUS = 1; + +/** + * Living particles are attached to the world and are unaffected by emitter repositioning. + * @constant + * @type Number + */ +cc.ParticleSystem.TYPE_FREE = 0; + +/** + * Living particles are attached to the world but will follow the emitter repositioning.
    + * Use case: Attach an emitter to an sprite, and you want that the emitter follows the sprite. + * @constant + * @type Number + */ +cc.ParticleSystem.TYPE_RELATIVE = 1; + +/** + * Living particles are attached to the emitter and are translated along with it. + * @constant + * @type Number + */ +cc.ParticleSystem.TYPE_GROUPED = 2; diff --git a/cocos2d/particle/CCParticleSystemCanvasRenderCmd.js b/cocos2d/particle/CCParticleSystemCanvasRenderCmd.js new file mode 100644 index 0000000000..7537bb94d5 --- /dev/null +++ b/cocos2d/particle/CCParticleSystemCanvasRenderCmd.js @@ -0,0 +1,217 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * ParticleSystem's canvas render command + */ +(function(){ + cc.ParticleSystem.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + + this._drawMode = cc.ParticleSystem.TEXTURE_MODE; + this._shapeType = cc.ParticleSystem.BALL_SHAPE; + + this._pointRect = cc.rect(0, 0, 0, 0); + }; + var proto = cc.ParticleSystem.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.ParticleSystem.CanvasRenderCmd; + + proto.getDrawMode = function(){ + return this._drawMode; + }; + + proto.setDrawMode = function(drawMode){ + this._drawMode = drawMode; + }; + + proto.getShapeType = function(){ + return this._shapeType; + }; + + proto.setShapeType = function(shapeType){ + this._shapeType = shapeType; + }; + + proto.setBatchNode = function(batchNode){ + if (this._batchNode !== batchNode) { + this._node._batchNode = batchNode; + } + }; + + proto.updateQuadWithParticle = function (particle, newPosition) { + //do nothing + }; + + proto.updateParticlePosition = function(particle, position){ + cc.pIn(particle.drawPos, position); + }; + + proto.rendering = function (ctx, scaleX, scaleY) { + //TODO: need refactor rendering for performance + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(), + node = this._node, pointRect = this._pointRect; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + wrapper.save(); + if (node.isBlendAdditive()) + context.globalCompositeOperation = 'lighter'; + else + context.globalCompositeOperation = 'source-over'; + + var i, particle, lpx, alpha; + var particleCount = this._node.particleCount, particles = this._node._particles; + if (node.drawMode !== cc.ParticleSystem.SHAPE_MODE && node._texture) { + // Delay drawing until the texture is fully loaded by the browser + if (!node._texture._textureLoaded) { + wrapper.restore(); + return; + } + var element = node._texture.getHtmlElementObj(); + if (!element.width || !element.height) { + wrapper.restore(); + return; + } + + var drawElement = element; + for (i = 0; i < particleCount; i++) { + particle = particles[i]; + lpx = (0 | (particle.size * 0.5)); + + alpha = particle.color.a / 255; + if (alpha === 0) continue; + context.globalAlpha = alpha; + + context.save(); + context.translate((0 | particle.drawPos.x), -(0 | particle.drawPos.y)); + + var size = Math.floor(particle.size / 4) * 4; + var w = pointRect.width; + var h = pointRect.height; + + context.scale(Math.max((1 / w) * size, 0.000001), Math.max((1 / h) * size, 0.000001)); + if (particle.rotation) + context.rotate(cc.degreesToRadians(particle.rotation)); + + drawElement = particle.isChangeColor ? this._changeTextureColor(element, particle.color, this._pointRect) : element; + context.drawImage(drawElement, -(0 | (w / 2)), -(0 | (h / 2))); + context.restore(); + } + } else { + var drawTool = cc._drawingUtil; + for (i = 0; i < particleCount; i++) { + particle = particles[i]; + lpx = (0 | (particle.size * 0.5)); + alpha = particle.color.a / 255; + if (alpha === 0) continue; + context.globalAlpha = alpha; + + context.save(); + context.translate(0 | particle.drawPos.x, -(0 | particle.drawPos.y)); + if (node.shapeType === cc.ParticleSystem.STAR_SHAPE) { + if (particle.rotation) + context.rotate(cc.degreesToRadians(particle.rotation)); + drawTool.drawStar(wrapper, lpx, particle.color); + } else + drawTool.drawColorBall(wrapper, lpx, particle.color); + context.restore(); + } + } + wrapper.restore(); + cc.g_NumberOfDraws++; + }; + + if(!cc.sys._supportCanvasNewBlendModes){ + proto._changeTextureColor = function(element, color, rect){ + var cacheTextureForColor = cc.textureCache.getTextureColors(element); + if (cacheTextureForColor) { + // Create another cache for the tinted version + // This speeds up things by a fair bit + if (!cacheTextureForColor.tintCache) { + cacheTextureForColor.tintCache = document.createElement('canvas'); + cacheTextureForColor.tintCache.width = element.width; + cacheTextureForColor.tintCache.height = element.height; + } + cc.Sprite.CanvasRenderCmd._generateTintImage(element, cacheTextureForColor, color, rect, cacheTextureForColor.tintCache); + return cacheTextureForColor.tintCache; + } + return null + } + }else{ + proto._changeTextureColor = function(element, color, rect){ + if (!element.tintCache) { + element.tintCache = document.createElement('canvas'); + element.tintCache.width = element.width; + element.tintCache.height = element.height; + } + return cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(element, color, rect, element.tintCache); + } + } + + proto.initTexCoordsWithRect = function(pointRect){ + this._pointRect = pointRect; + }; + + proto.setTotalParticles = function(tp){ + //cc.assert(tp <= this._allocatedParticles, "Particle: resizing particle array only supported for quads"); + this._node._totalParticles = (tp < 200) ? tp : 200; + }; + + proto.addParticle = function(){ + var node = this._node, + particles = node._particles, + particle; + if (node.particleCount < particles.length) { + particle = particles[node.particleCount]; + } else { + particle = new cc.Particle(); + particles.push(particle); + } + return particle; + }; + + proto._setupVBO = function(){}; + proto._allocMemory = function(){ + return true; + }; + + proto.postStep = function(){}; + + proto._setBlendAdditive = function(){ + var locBlendFunc = this._node._blendFunc; + locBlendFunc.src = cc.BLEND_SRC; + locBlendFunc.dst = cc.BLEND_DST; + }; + + proto._initWithTotalParticles = function(totalParticles){}; + proto._updateDeltaColor = function(selParticle, dt){ + if (!this._node._dontTint) { + selParticle.color.r += selParticle.deltaColor.r * dt; + selParticle.color.g += selParticle.deltaColor.g * dt; + selParticle.color.b += selParticle.deltaColor.b * dt; + selParticle.color.a += selParticle.deltaColor.a * dt; + selParticle.isChangeColor = true; + } + }; +})(); diff --git a/cocos2d/particle/CCParticleSystemWebGLRenderCmd.js b/cocos2d/particle/CCParticleSystemWebGLRenderCmd.js new file mode 100644 index 0000000000..eb1ce063b0 --- /dev/null +++ b/cocos2d/particle/CCParticleSystemWebGLRenderCmd.js @@ -0,0 +1,401 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + /** + * ParticleSystem's WebGL render command + */ + cc.ParticleSystem.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = true; + + this._buffersVBO = [0, 0]; + this._quads = []; + this._indices = []; + this._quadsArrayBuffer = null; + }; + var proto = cc.ParticleSystem.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.ParticleSystem.WebGLRenderCmd; + + proto.getDrawMode = function(){}; + proto.setDrawMode = function(drawMode){}; + proto.getShapeType = function(){}; + proto.setShapeType = function(shapeType){}; + + proto.setBatchNode = function(batchNode){ + var node = this._node; + if (node._batchNode !== batchNode) { + var oldBatch = node._batchNode; + node._batchNode = batchNode; //weak reference + + if (batchNode) { + var locParticles = node._particles; + for (var i = 0; i < node._totalParticles; i++) + locParticles[i].atlasIndex = i; + } + + // NEW: is self render ? + if (!batchNode) { + this._allocMemory(); + this.initIndices(node._totalParticles); + node.setTexture(oldBatch.getTexture()); + this._setupVBO(); + + } else if (!oldBatch) { + // OLD: was it self render cleanup ? + // copy current state to batch + node._batchNode.textureAtlas._copyQuadsToTextureAtlas(this._quads, node.atlasIndex); + + //delete buffer + cc._renderContext.deleteBuffer(this._buffersVBO[1]); //where is re-bindBuffer code? + } + } + }; + + proto.initIndices = function (totalParticles) { + var locIndices = this._indices; + for (var i = 0, len = totalParticles; i < len; ++i) { + var i6 = i * 6; + var i4 = i * 4; + locIndices[i6 + 0] = i4 + 0; + locIndices[i6 + 1] = i4 + 1; + locIndices[i6 + 2] = i4 + 2; + + locIndices[i6 + 5] = i4 + 1; + locIndices[i6 + 4] = i4 + 2; + locIndices[i6 + 3] = i4 + 3; + } + }; + + proto.isDifferentTexture = function(texture1, texture2){ + return (texture1 === texture2); + }; + + proto.updateParticlePosition = function(particle, position){ + // IMPORTANT: newPos may not be used as a reference here! (as it is just the temporary tpa point) + // the implementation of updateQuadWithParticle must use + // the x and y values directly + this.updateQuadWithParticle(particle, position); + }; + + proto.updateQuadWithParticle = function (particle, newPosition) { + var quad = null, node = this._node; + if (node._batchNode) { + var batchQuads = node._batchNode.textureAtlas.quads; + quad = batchQuads[node.atlasIndex + particle.atlasIndex]; + node._batchNode.textureAtlas.dirty = true; + } else + quad = this._quads[node._particleIdx]; + + var r, g, b, a; + if (node._opacityModifyRGB) { + r = 0 | (particle.color.r * particle.color.a/255); + g = 0 | (particle.color.g * particle.color.a/255); + b = 0 | (particle.color.b * particle.color.a/255); + } else { + r = 0 | (particle.color.r ); + g = 0 | (particle.color.g ); + b = 0 | (particle.color.b ); + } + a = 0 | (particle.color.a ); + + var blColors = quad.bl.colors, brColors = quad.br.colors, tlColors = quad.tl.colors, trColors = quad.tr.colors; + blColors.r = brColors.r = tlColors.r = trColors.r = r; + blColors.g = brColors.g = tlColors.g = trColors.g = g; + blColors.b = brColors.b = tlColors.b = trColors.b = b; + blColors.a = brColors.a = tlColors.a = trColors.a = a; + + // vertices + var size_2 = particle.size / 2; + if (particle.rotation) { + var x1 = -size_2, y1 = -size_2; + + var x2 = size_2, y2 = size_2; + var x = newPosition.x, y = newPosition.y; + + var rad = -cc.degreesToRadians(particle.rotation); + var cr = Math.cos(rad), sr = Math.sin(rad); + var ax = x1 * cr - y1 * sr + x; + var ay = x1 * sr + y1 * cr + y; + var bx = x2 * cr - y1 * sr + x; + var by = x2 * sr + y1 * cr + y; + var cx = x2 * cr - y2 * sr + x; + var cy = x2 * sr + y2 * cr + y; + var dx = x1 * cr - y2 * sr + x; + var dy = x1 * sr + y2 * cr + y; + + // bottom-left + quad.bl.vertices.x = ax; + quad.bl.vertices.y = ay; + + // bottom-right vertex: + quad.br.vertices.x = bx; + quad.br.vertices.y = by; + + // top-left vertex: + quad.tl.vertices.x = dx; + quad.tl.vertices.y = dy; + + // top-right vertex: + quad.tr.vertices.x = cx; + quad.tr.vertices.y = cy; + } else { + // bottom-left vertex: + quad.bl.vertices.x = newPosition.x - size_2; + quad.bl.vertices.y = newPosition.y - size_2; + + // bottom-right vertex: + quad.br.vertices.x = newPosition.x + size_2; + quad.br.vertices.y = newPosition.y - size_2; + + // top-left vertex: + quad.tl.vertices.x = newPosition.x - size_2; + quad.tl.vertices.y = newPosition.y + size_2; + + // top-right vertex: + quad.tr.vertices.x = newPosition.x + size_2; + quad.tr.vertices.y = newPosition.y + size_2; + } + }; + + proto.rendering = function (ctx) { + var node = this._node; + if (!node._texture) + return; + + var gl = ctx || cc._renderContext; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); //; + + cc.glBindTexture2D(node._texture); + cc.glBlendFuncForParticle(node._blendFunc.src, node._blendFunc.dst); + + // + // Using VBO without VAO + // + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); + + gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); + gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 3, gl.FLOAT, false, 24, 0); // vertices + gl.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, gl.UNSIGNED_BYTE, true, 24, 12); // colors + gl.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, gl.FLOAT, false, 24, 16); // tex coords + + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); + gl.drawElements(gl.TRIANGLES, node._particleIdx * 6, gl.UNSIGNED_SHORT, 0); + }; + + proto.initTexCoordsWithRect = function(pointRect){ + var node = this._node; + var texture = node.texture; + var scaleFactor = cc.contentScaleFactor(); + // convert to pixels coords + var rect = cc.rect( + pointRect.x * scaleFactor, + pointRect.y * scaleFactor, + pointRect.width * scaleFactor, + pointRect.height * scaleFactor); + + var wide = pointRect.width; + var high = pointRect.height; + + if (texture) { + wide = texture.pixelsWidth; + high = texture.pixelsHeight; + } + + var left, bottom, right, top; + if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { + left = (rect.x * 2 + 1) / (wide * 2); + bottom = (rect.y * 2 + 1) / (high * 2); + right = left + (rect.width * 2 - 2) / (wide * 2); + top = bottom + (rect.height * 2 - 2) / (high * 2); + } else { + left = rect.x / wide; + bottom = rect.y / high; + right = left + rect.width / wide; + top = bottom + rect.height / high; + } + + // Important. Texture in cocos2d are inverted, so the Y component should be inverted + var temp = top; + top = bottom; + bottom = temp; + + var quads; + var start = 0, end = 0; + if (node._batchNode) { + quads = node._batchNode.textureAtlas.quads; + start = node.atlasIndex; + end = node.atlasIndex + node._totalParticles; + } else { + quads = this._quads; + start = 0; + end = node._totalParticles; + } + + for (var i = start; i < end; i++) { + if (!quads[i]) + quads[i] = cc.V3F_C4B_T2F_QuadZero(); + + // bottom-left vertex: + var selQuad = quads[i]; + selQuad.bl.texCoords.u = left; + selQuad.bl.texCoords.v = bottom; + // bottom-right vertex: + selQuad.br.texCoords.u = right; + selQuad.br.texCoords.v = bottom; + // top-left vertex: + selQuad.tl.texCoords.u = left; + selQuad.tl.texCoords.v = top; + // top-right vertex: + selQuad.tr.texCoords.u = right; + selQuad.tr.texCoords.v = top; + } + }; + + proto.setTotalParticles = function(tp){ + var node = this._node; + // If we are setting the total numer of particles to a number higher + // than what is allocated, we need to allocate new arrays + if (tp > node._allocatedParticles) { + var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; + // Allocate new memory + this._indices = new Uint16Array(tp * 6); + var locQuadsArrayBuffer = new ArrayBuffer(tp * quadSize); + //TODO need fix + // Assign pointers + var locParticles = node._particles; + locParticles.length = 0; + var locQuads = this._quads; + locQuads.length = 0; + for (var j = 0; j < tp; j++) { + locParticles[j] = new cc.Particle(); + locQuads[j] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, j * quadSize); + } + node._allocatedParticles = tp; + node._totalParticles = tp; + + // Init particles + if (node._batchNode) { + for (var i = 0; i < tp; i++) + locParticles[i].atlasIndex = i; + } + + this._quadsArrayBuffer = locQuadsArrayBuffer; + this.initIndices(tp); + this._setupVBO(); + + //set the texture coord + if(node._texture){ + this.initTexCoordsWithRect(cc.rect(0, 0, node._texture.width, node._texture.height)); + } + } else + node._totalParticles = tp; + node.resetSystem(); + }; + + proto.addParticle = function(){ + var node = this._node, + particles = node._particles; + return particles[node.particleCount]; + }; + + proto._setupVBO = function(){ + var node = this; + var gl = cc._renderContext; + + //gl.deleteBuffer(this._buffersVBO[0]); + this._buffersVBO[0] = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); + gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); + + this._buffersVBO[1] = gl.createBuffer(); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._buffersVBO[1]); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this._indices, gl.STATIC_DRAW); + + //cc.checkGLErrorDebug(); + }; + + proto._allocMemory = function(){ + var node = this._node; + //cc.assert((!this._quads && !this._indices), "Memory already allocated"); + if(node._batchNode){ + cc.log("cc.ParticleSystem._allocMemory(): Memory should not be allocated when not using batchNode"); + return false; + } + + var quadSize = cc.V3F_C4B_T2F_Quad.BYTES_PER_ELEMENT; + var totalParticles = node._totalParticles; + var locQuads = this._quads; + locQuads.length = 0; + this._indices = new Uint16Array(totalParticles * 6); + var locQuadsArrayBuffer = new ArrayBuffer(quadSize * totalParticles); + + for (var i = 0; i < totalParticles; i++) + locQuads[i] = new cc.V3F_C4B_T2F_Quad(null, null, null, null, locQuadsArrayBuffer, i * quadSize); + if (!locQuads || !this._indices) { + cc.log("cocos2d: Particle system: not enough memory"); + return false; + } + this._quadsArrayBuffer = locQuadsArrayBuffer; + return true; + }; + + proto.postStep = function(){ + var gl = cc._renderContext; + gl.bindBuffer(gl.ARRAY_BUFFER, this._buffersVBO[0]); + gl.bufferData(gl.ARRAY_BUFFER, this._quadsArrayBuffer, gl.DYNAMIC_DRAW); + }; + + proto._setBlendAdditive = function(){ + var locBlendFunc = this._node._blendFunc; + if (this._texture && !this._texture.hasPremultipliedAlpha()) { + locBlendFunc.src = cc.SRC_ALPHA; + locBlendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + } else { + locBlendFunc.src = cc.BLEND_SRC; + locBlendFunc.dst = cc.BLEND_DST; + } + }; + + proto._initWithTotalParticles = function(totalParticles){ + // allocating data space + if (!this._allocMemory()) + return false; + + this.initIndices(totalParticles); + this._setupVBO(); + + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + }; + + proto._updateDeltaColor = function (selParticle, dt) { + selParticle.color.r += selParticle.deltaColor.r * dt; + selParticle.color.g += selParticle.deltaColor.g * dt; + selParticle.color.b += selParticle.deltaColor.b * dt; + selParticle.color.a += selParticle.deltaColor.a * dt; + selParticle.isChangeColor = true; + }; +})(); \ No newline at end of file diff --git a/cocos2d/particle/CCTIFFReader.js b/cocos2d/particle/CCTIFFReader.js index 8eb693f8d6..da832b4717 100644 --- a/cocos2d/particle/CCTIFFReader.js +++ b/cocos2d/particle/CCTIFFReader.js @@ -2,7 +2,10 @@ Copyright (c) 2011 Gordon P. Hemsley http://gphemsley.org/ - Copyright (c) 2010-2013 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + http://www.cocos2d-x.org Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,9 +27,10 @@ THE SOFTWARE. ****************************************************************************/ - /** - * @namespace A tiff file reader, it can parse byte array to draw into a canvas + * cc.tiffReader is a singleton object, it's a tiff file reader, it can parse byte array to draw into a canvas + * @class + * @name cc.tiffReader */ cc.tiffReader = /** @lends cc.tiffReader# */{ _littleEndian: false, @@ -224,7 +228,7 @@ cc.tiffReader = /** @lends cc.tiffReader# */{ }, /** - * + * @function * @param {Array} tiffData * @param {HTMLCanvasElement} canvas * @returns {*} diff --git a/cocos2d/physics/CCPhysicsDebugNode.js b/cocos2d/physics/CCPhysicsDebugNode.js index 93c8c9d203..17bfe544a4 100644 --- a/cocos2d/physics/CCPhysicsDebugNode.js +++ b/cocos2d/physics/CCPhysicsDebugNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2012 Scott Lembcke and Howling Moon Software http://www.cocos2d-x.org @@ -34,7 +34,12 @@ as the private API may change with little or no warning. */ -// Helper. Converts an array of numbers into an array of vectors(x,y) +/** + * Converts an array of numbers into an array of vectors(x,y) + * @function + * @param {Array} verts + * @return {Array} + */ cc.__convertVerts = function (verts) { var ret = []; for (var i = 0; i < verts.length / 2; i++) { @@ -43,6 +48,12 @@ cc.__convertVerts = function (verts) { return ret; }; +/** + * color for body + * @function + * @param {cp.Body} body + * @return {cc.color} + */ cc.ColorForBody = function (body) { if (body.isRogue() || body.isSleeping()) { return cc.color(128, 128, 128, 128); @@ -53,6 +64,11 @@ cc.ColorForBody = function (body) { } }; +/** + * draw shape + * @param {cp.Shape} shape + * @param renderer + */ cc.DrawShape = function (shape, renderer) { var body = shape.body; var color = cc.ColorForBody(body); @@ -74,6 +90,11 @@ cc.DrawShape = function (shape, renderer) { } }; +/** + * draw constraint + * @param {cp.Constraint} constraint + * @param renderer + */ cc.DrawConstraint = function (constraint, renderer) { var body_a = constraint.a; var body_b = constraint.b; @@ -111,8 +132,13 @@ cc.DrawConstraint = function (constraint, renderer) { } }; +/** + * @constant + * @type {cc.color} + */ cc.CONSTRAINT_COLOR = cc.color(0, 255, 0, 128); + /** *

    A Node that draws the components of a physics engine.
    * Supported physics engines:
    @@ -125,50 +151,62 @@ cc.CONSTRAINT_COLOR = cc.color(0, 255, 0, 128); * @property {cp.Space} space Physic world space */ cc.PhysicsDebugNode = cc.DrawNode.extend({ - space:null, - - _spaceObj:null, + _space:null, _className:"PhysicsDebugNode", + /** + * constructor of cc.PhysicsDebugNode + * @param {cp.Space} space + */ + ctor: function (space) { + cc.DrawNode.prototype.ctor.call(this); + this._space = space; + }, + + /** + * get space + * @returns {cp.Space} + */ getSpace:function () { - return this.space; + return this._space; }, + /** + * set space + * @param {cp.Space} space + */ setSpace:function (space) { - this.space = space; + this._space = space; }, + /** + * draw + * @param {object} context + */ draw:function (context) { - if (!this.space) + if (!this._space) return; - this.space.eachShape(cc.DrawShape.bind(this)); - this.space.eachConstraint(cc.DrawConstraint.bind(this)); + this._space.eachShape(cc.DrawShape.bind(this)); + this._space.eachConstraint(cc.DrawConstraint.bind(this)); cc.DrawNode.prototype.draw.call(this); this.clear(); - } -}); + }, -/** Create a debug node for an Objective-Chipmunk space. */ -cc.PhysicsDebugNode.debugNodeForChipmunkSpace = function (space) { - var node = new cc.PhysicsDebugNode(); - if (node.init()) { - node._spaceObj = space; - node.space = space.space; - return node; + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.PhysicsDebugNode.CanvasRenderCmd(this); + else + return new cc.PhysicsDebugNode.WebGLRenderCmd(this); } - return null; -}; +}); -/** Create a debug node for a regular Chipmunk space. */ -cc.PhysicsDebugNode.debugNodeForCPSpace = function (space) { - var node = new cc.PhysicsDebugNode(); - if (node.init()) { - node.space = space; - return node; - } - return null; +/** + * Create a debug node for a regular Chipmunk space. + * @deprecated since v3.0, please use new cc.PhysicsDebugNode(space) + * @param {cp.Space} space + * @return {cc.PhysicsDebugNode} + */ +cc.PhysicsDebugNode.create = function (space) { + return new cc.PhysicsDebugNode(space); }; - -cc.PhysicsDebugNode.create = cc.PhysicsDebugNode.debugNodeForCPSpace; - diff --git a/cocos2d/physics/CCPhysicsDebugNodeCanvasRenderCmd.js b/cocos2d/physics/CCPhysicsDebugNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..be1f6f14ba --- /dev/null +++ b/cocos2d/physics/CCPhysicsDebugNodeCanvasRenderCmd.js @@ -0,0 +1,52 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.PhysicsDebugNode's rendering objects of Canvas + */ +(function(){ + cc.PhysicsDebugNode.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._buffer = renderableObject._buffer; + this._needDraw = true; + }; + + var proto = cc.PhysicsDebugNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.PhysicsDebugNode.CanvasRenderCmd; + + proto.rendering = function(ctx, scaleX, scaleY){ + var node = this._node; + if (!node._space) + return; + node._space.eachShape(cc.DrawShape.bind(node)); + node._space.eachConstraint(cc.DrawConstraint.bind(node)); + cc.DrawNode.CanvasRenderCmd.prototype.rendering.call(this, ctx, scaleX, scaleY); + node.clear(); + }; + + proto._drawDot = cc.DrawNode.CanvasRenderCmd.prototype._drawDot; + proto._drawSegment = cc.DrawNode.CanvasRenderCmd.prototype._drawSegment; + proto._drawPoly = cc.DrawNode.CanvasRenderCmd.prototype._drawPoly; + +})(); diff --git a/extensions/pluginx/samples/HelloSocial/main.js b/cocos2d/physics/CCPhysicsDebugNodeWebGLRenderCmd.js similarity index 50% rename from extensions/pluginx/samples/HelloSocial/main.js rename to cocos2d/physics/CCPhysicsDebugNodeWebGLRenderCmd.js index 183e53c1c5..38ddf9f630 100644 --- a/extensions/pluginx/samples/HelloSocial/main.js +++ b/cocos2d/physics/CCPhysicsDebugNodeWebGLRenderCmd.js @@ -1,11 +1,8 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -24,36 +21,33 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ -var cocos2dApp = cc.Application.extend({ - config:document['ccConfig'], - ctor:function (scene) { - this._super(); - this.startScene = scene; - cc.COCOS2D_DEBUG = this.config['COCOS2D_DEBUG']; - cc.initDebugSetting(); - cc.setup(this.config['tag']); - cc.AppController.shareAppController().didFinishLaunchingWithOptions(); - }, - applicationDidFinishLaunching:function () { - // initialize director - var director = cc.director; - var designSize = cc.size(800, 450); - - cc.view.setDesignResolutionSize(designSize.width, designSize.height, cc.ResolutionPolicy.SHOW_ALL); - - // turn on display FPS - director.setDisplayStats(this.config['showFPS']); - - // set FPS. the default value is 1.0/60 if you don't call this - director.setAnimationInterval(1.0 / this.config['frameRate']); - - //load resources - cc.LoaderScene.preload(g_ressources, function () { - director.runScene(new this.startScene()); - }, this); - - return true; - } -}); - -var myApp = new cocos2dApp(MyScene); \ No newline at end of file + +/** + * cc.PhysicsDebugNode's rendering objects of WebGL + */ +(function(){ + cc.PhysicsDebugNode.WebGLRenderCmd = function (renderableObject) { + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + cc.PhysicsDebugNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + cc.PhysicsDebugNode.WebGLRenderCmd.prototype.constructor = cc.PhysicsDebugNode.WebGLRenderCmd; + + cc.PhysicsDebugNode.WebGLRenderCmd.prototype.rendering = function (ctx) { + var node = this._node; + if (!node._space) + return; + + node._space.eachShape(cc.DrawShape.bind(node)); + node._space.eachConstraint(cc.DrawConstraint.bind(node)); + + //cc.DrawNode.prototype.draw.call(node); + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + node._render(); + + node.clear(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/physics/CCPhysicsSprite.js b/cocos2d/physics/CCPhysicsSprite.js index 455ac7c322..2fa248da8f 100644 --- a/cocos2d/physics/CCPhysicsSprite.js +++ b/cocos2d/physics/CCPhysicsSprite.js @@ -1,4 +1,8 @@ -/** Copyright (c) 2012 Scott Lembcke and Howling Moon Software +/** + * Copyright (c) 2012 Scott Lembcke and Howling Moon Software + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,13 +43,13 @@ _rotation:1, /** * Create a PhysicsSprite with filename and rect - * @constructor + * Constructor of cc.PhysicsSprite for Box2d * @param {String|cc.Texture2D|cc.SpriteFrame} fileName * @param {cc.Rect} rect * @example * * 1.Create a sprite with image path and rect - * var physicsSprite1 = cc.PhysicsSprite.create("res/HelloHTML5World.png"); + * var physicsSprite1 = new cc.PhysicsSprite("res/HelloHTML5World.png"); * var physicsSprite2 = new cc.PhysicsSprite("res/HelloHTML5World.png",cc.rect(0,0,480,320)); * * 2.Create a sprite with a sprite frame name. Must add "#" before fame name. @@ -55,7 +59,7 @@ * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); * var physicsSprite = new cc.PhysicsSprite(spriteFrame); * - * 4.Creates a sprite with an exsiting texture contained in a CCTexture2D object + * 4.Creates a sprite with an existing texture contained in a CCTexture2D object * After creation, the rect will be the size of the texture, and the offset will be (0,0). * var texture = cc.textureCache.addImage("HelloHTML5World.png"); * var physicsSprite1 = new cc.PhysicsSprite(texture); @@ -67,7 +71,7 @@ if (fileName === undefined) { cc.PhysicsSprite.prototype.init.call(this); - }else if (typeof(fileName) === "string") { + }else if (cc.isString(fileName)) { if (fileName[0] === "#") { //init with a sprite frame name var frameName = fileName.substr(1, fileName.length - 1); @@ -77,7 +81,7 @@ //init with filename and rect this.init(fileName, rect); } - }else if (typeof(fileName) === "object") { + }else if (cc.isObject(fileName)) { if (fileName instanceof cc.Texture2D) { //init with texture and rect this.initWithTexture(fileName, rect); @@ -86,33 +90,80 @@ this.initWithSpriteFrame(fileName); } } + //this._transformCmd = new cc.PhysicsSpriteTransformCmdCanvas(this); + //cc.rendererCanvas.pushRenderCommand(this._transformCmd); }, + + //visit: function(){ + // cc.Sprite.prototype.visit.call(this); + // cc.rendererCanvas.pushRenderCommand(this._transformCmd); + //}, + + /** + * set body + * @param {Box2D.Dynamics.b2Body} body + */ setBody:function (body) { this._body = body; }, + + /** + * get body + * @return {Box2D.Dynamics.b2Body} + */ getBody:function () { return this._body; }, + + /** + * set PTM ratio + * @param {Number} r + */ setPTMRatio:function (r) { this._PTMRatio = r; }, + + /** + * get PTM ration + * @return {Number} + */ getPTMRatio:function () { return this._PTMRatio; }, + + /** + * get position + * @return {cc.Point} + */ getPosition:function () { var pos = this._body.GetPosition(); var locPTMRatio =this._PTMRatio; return cc.p(pos.x * locPTMRatio, pos.y * locPTMRatio); }, + + /** + * set position + * @param {cc.Point} p + */ setPosition:function (p) { var angle = this._body.GetAngle(); var locPTMRatio =this._PTMRatio; this._body.setTransform(Box2D.b2Vec2(p.x / locPTMRatio, p.y / locPTMRatio), angle); this.setNodeDirty(); }, + + /** + * get rotation + * @return {Number} + */ getRotation:function () { - return (this._ignoreBodyRotation ? cc.radiansToDegress(this._rotationRadians) : cc.radiansToDegress(this._body.GetAngle())); + return (this._ignoreBodyRotation ? cc.radiansToDegrees(this._rotationRadians) : cc.radiansToDegrees(this._body.GetAngle())); }, + + /** + * set rotation + * @param {Number} r + */ setRotation:function (r) { if (this._ignoreBodyRotation) { this._rotation = r; @@ -132,6 +183,9 @@ _syncRotation:function () { this._rotationRadians = this._body.GetAngle(); }, + /** + * visit + */ visit:function () { if (this._body && this._PTMRatio) { this._syncPosition(); @@ -143,10 +197,16 @@ } this._super(); }, + + /** + * set whether to ingore body's rotation + * @param {Boolean} b + */ setIgnoreBodyRotation: function(b) { this._ignoreBodyRotation = b; } }; + var chipmunkAPI = { _ignoreBodyRotation:false, _body:null, //physics body @@ -154,16 +214,16 @@ /** * Create a PhysicsSprite with filename and rect - * @constructor + * Constructor of cc.PhysicsSprite for chipmunk * @param {String|cc.Texture2D|cc.SpriteFrame} fileName * @param {cc.Rect} rect * @example * * 1.Create a sprite with image path and rect - * var physicsSprite1 = cc.PhysicsSprite.create("res/HelloHTML5World.png"); + * var physicsSprite1 = new cc.PhysicsSprite("res/HelloHTML5World.png"); * var physicsSprite2 = new cc.PhysicsSprite("res/HelloHTML5World.png",cc.rect(0,0,480,320)); * - * 2.Create a sprite with a sprite frame name. Must add "#" before fame name. + * 2.Create a sprite with a sprite frame name. Must add "#" before frame name. * var physicsSprite = new cc.PhysicsSprite('#grossini_dance_01.png'); * * 3.Create a sprite with a sprite frame @@ -182,7 +242,7 @@ if (fileName === undefined) { cc.PhysicsSprite.prototype.init.call(this); - }else if (typeof(fileName) === "string") { + }else if (cc.isString(fileName)) { if (fileName[0] === "#") { //init with a sprite frame name var frameName = fileName.substr(1, fileName.length - 1); @@ -192,7 +252,7 @@ //init with filename and rect this.init(fileName, rect); } - }else if (typeof(fileName) === "object") { + }else if (cc.isObject(fileName)) { if (fileName instanceof cc.Texture2D) { //init with texture and rect this.initWithTexture(fileName, rect); @@ -201,26 +261,61 @@ this.initWithSpriteFrame(fileName); } } + + cc.renderer.pushRenderCommand(this._renderCmd); + }, + + visit: function(){ + cc.renderer.pushRenderCommand(this._renderCmd); + cc.Sprite.prototype.visit.call(this); }, + + /** + * set body + * @param {cp.Body} body + */ setBody:function (body) { this._body = body; }, + + /** + * get body + * @returns {cp.Body} + */ getBody:function () { return this._body; }, + + /** + * get position + * @return {cc.Point} + */ getPosition:function () { var locBody = this._body; return {x:locBody.p.x, y:locBody.p.y}; }, + /** + * get position x + * @return {Number} + */ getPositionX:function () { return this._body.p.x; }, + /** + * get position y + * @return {Number} + */ getPositionY:function () { return this._body.p.y; }, + /** + * set position + * @param {cc.Point|Number}newPosOrxValue + * @param {Number}yValue + */ setPosition:function (newPosOrxValue, yValue) { if (yValue === undefined) { this._body.p.x = newPosOrxValue.x; @@ -231,10 +326,20 @@ } //this._syncPosition(); }, + + /** + * set position x + * @param {Number} xValue + */ setPositionX:function (xValue) { this._body.p.x = xValue; //this._syncPosition(); }, + + /** + * set position y + * @param {Number} yValue + */ setPositionY:function (yValue) { this._body.p.y = yValue; //this._syncPosition(); @@ -242,13 +347,23 @@ _syncPosition:function () { var locPosition = this._position, locBody = this._body; - if (locPosition.x != locBody.p.x || locPosition.y != locBody.p.y) { + if (locPosition.x !== locBody.p.x || locPosition.y !== locBody.p.y) { cc.Sprite.prototype.setPosition.call(this, locBody.p.x, locBody.p.y); } }, + + /** + * get rotation + * @return {Number} + */ getRotation:function () { - return this._ignoreBodyRotation ? cc.radiansToDegress(this._rotationRadiansX) : -cc.radiansToDegress(this._body.a); + return this._ignoreBodyRotation ? this._rotationX : -cc.radiansToDegrees(this._body.a); }, + + /** + * set rotation + * @param {Number} r + */ setRotation:function (r) { if (this._ignoreBodyRotation) { cc.Sprite.prototype.setRotation.call(this, r); @@ -258,94 +373,41 @@ } }, _syncRotation:function () { - if (this._rotationRadiansX != -this._body.a) { - cc.Sprite.prototype.setRotation.call(this, -cc.radiansToDegress(this._body.a)); + if (this._rotationX !== -cc.radiansToDegrees(this._body.a)) { + cc.Sprite.prototype.setRotation.call(this, -cc.radiansToDegrees(this._body.a)); } }, - nodeToParentTransform:function () { - if(cc._renderType === cc._RENDER_TYPE_CANVAS) - return this._nodeToParentTransformForCanvas(); - - var locBody = this._body, locAnchorPIP = this._anchorPointInPoints, locScaleX = this._scaleX, locScaleY = this._scaleY; - var x = locBody.p.x; - var y = locBody.p.y; - if (this._ignoreAnchorPointForPosition) { - x += locAnchorPIP.x; - y += locAnchorPIP.y; - } - - // Make matrix - var radians = locBody.a; - var c = Math.cos(radians); - var s = Math.sin(radians); - - // Although scale is not used by physics engines, it is calculated just in case - // the sprite is animated (scaled up/down) using actions. - // For more info see: http://www.cocos2d-iphone.org/forum/topic/68990 - if (!cc._rectEqualToZero(locAnchorPIP)) { - x += c * -locAnchorPIP.x * locScaleX + -s * -locAnchorPIP.y * locScaleY; - y += s * -locAnchorPIP.x * locScaleX + c * -locAnchorPIP.y * locScaleY; - } - - // Rot, Translate Matrix - this._transform = cc.AffineTransformMake(c * locScaleX, s * locScaleX, - -s * locScaleY, c * locScaleY, - x, y); - - return this._transform; - }, - - _nodeToParentTransformForCanvas: function () { - if (this.dirty) { - var t = this._transform;// quick reference - // base position - var locBody = this._body, locScaleX = this._scaleX, locScaleY = this._scaleY, locAnchorPIP = this._anchorPointInPoints; - t.tx = locBody.p.x; - t.ty = locBody.p.y; - - // rotation Cos and Sin - var radians = -locBody.a; - var Cos = 1, Sin = 0; - if (radians) { - Cos = Math.cos(radians); - Sin = Math.sin(radians); - } - - // base abcd - t.a = t.d = Cos; - t.b = -Sin; - t.c = Sin; - - // scale - if (locScaleX !== 1 || locScaleY !== 1) { - t.a *= locScaleX; - t.c *= locScaleX; - t.b *= locScaleY; - t.d *= locScaleY; - } - - // adjust anchorPoint - t.tx += Cos * -locAnchorPIP.x * locScaleX + -Sin * locAnchorPIP.y * locScaleY; - t.ty -= Sin * -locAnchorPIP.x * locScaleX + Cos * locAnchorPIP.y * locScaleY; - - // if ignore anchorPoint - if (this._ignoreAnchorPointForPosition) { - t.tx += locAnchorPIP.x; - t.ty += locAnchorPIP.y; - } - this._transformDirty = false; - } - return this._transform; + /** + * get the affine transform matrix of node to parent coordinate frame + * @return {cc.AffineTransform} + */ + getNodeToParentTransform:function () { + return this._renderCmd.getNodeToParentTransform(); }, + /** + * whether dirty + * @return {Boolean} + */ isDirty:function(){ return !this._body.isSleeping(); }, setDirty: function(){ }, + /** + * set whether to ignore rotation of body + * @param {Boolean} b + */ setIgnoreBodyRotation: function(b) { this._ignoreBodyRotation = b; + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.PhysicsSprite.CanvasRenderCmd(this); + else + return new cc.PhysicsSprite.WebGLRenderCmd(this); } }; cc.PhysicsSprite = cc.Sprite.extend(chipmunkAPI); @@ -362,31 +424,24 @@ /** * Create a PhysicsSprite with filename and rect - * @constructor + * @deprecated since v3.0, please use new cc.PhysicsSprite(fileName, rect) instead * @param {String|cc.Texture2D|cc.SpriteFrame} fileName * @param {cc.Rect} rect * @return {cc.PhysicsSprite} - * @example - * - * 1.Create a sprite with image path and rect - * var physicsSprite1 = cc.PhysicsSprite.create("res/HelloHTML5World.png"); - * var physicsSprite2 = cc.PhysicsSprite.create("res/HelloHTML5World.png",cc.rect(0,0,480,320)); - * - * 2.Create a sprite with a sprite frame name. Must add "#" before fame name. - * var physicsSprite = cc.PhysicsSprite.create('#grossini_dance_01.png'); - * - * 3.Create a sprite with a sprite frame - * var spriteFrame = cc.spriteFrameCache.getSpriteFrame("grossini_dance_01.png"); - * var physicsSprite = cc.PhysicsSprite.create(spriteFrame); - * - * 4.Creates a sprite with an exsiting texture contained in a CCTexture2D object - * After creation, the rect will be the size of the texture, and the offset will be (0,0). - * var texture = cc.textureCache.addImage("HelloHTML5World.png"); - * var physicsSprite1 = cc.PhysicsSprite.create(texture); - * var physicsSprite2 = cc.PhysicsSprite.create(texture, cc.rect(0,0,480,320)); - * */ cc.PhysicsSprite.create = function (fileName, rect) { return new cc.PhysicsSprite(fileName, rect); }; + + /** + * @deprecated since v3.0, please use new cc.PhysicsSprite(spriteFrameName) instead + * @type {Function} + */ + cc.PhysicsSprite.createWithSpriteFrameName = cc.PhysicsSprite.create; + + /** + * @deprecated since v3.0, please use new cc.PhysicsSprite(spriteFrame) instead + * @type {Function} + */ + cc.PhysicsSprite.createWithSpriteFrame = cc.PhysicsSprite.create; })(); diff --git a/cocos2d/physics/CCPhysicsSpriteCanvasRenderCmd.js b/cocos2d/physics/CCPhysicsSpriteCanvasRenderCmd.js new file mode 100644 index 0000000000..ae95d94df9 --- /dev/null +++ b/cocos2d/physics/CCPhysicsSpriteCanvasRenderCmd.js @@ -0,0 +1,93 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.PhysicsSprite's rendering objects of Canvas + */ +(function(){ + cc.PhysicsSprite.CanvasRenderCmd = function(renderableObject){ + cc.Sprite.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = cc.PhysicsSprite.CanvasRenderCmd.prototype = Object.create(cc.Sprite.CanvasRenderCmd.prototype); + proto.constructor = cc.PhysicsSprite.CanvasRenderCmd; + + proto.rendering = function(ctx, scaleX, scaleY){ + // This is a special class + // Sprite can not obtain sign + // So here must to calculate of each frame + var node = this._node; + node._syncPosition(); + if(!node._ignoreBodyRotation) + node._syncRotation(); + this.transform(this.getParentRenderCmd()); + + cc.Sprite.CanvasRenderCmd.prototype.rendering.call(this, ctx, scaleX, scaleY); + }; + + proto.getNodeToParentTransform = function(){ + var node = this._node; + + var t = this._transform;// quick reference + // base position + var locBody = node._body, locScaleX = node._scaleX, locScaleY = node._scaleY, locAnchorPIP = this._anchorPointInPoints; + t.tx = locBody.p.x; + t.ty = locBody.p.y; + + // rotation Cos and Sin + var radians = -locBody.a; + var Cos = 1, Sin = 0; + if (radians && !node._ignoreBodyRotation) { + Cos = Math.cos(radians); + Sin = Math.sin(radians); + } + + // base abcd + t.a = t.d = Cos; + t.b = -Sin; + t.c = Sin; + + // scale + if (locScaleX !== 1 || locScaleY !== 1) { + t.a *= locScaleX; + t.c *= locScaleX; + t.b *= locScaleY; + t.d *= locScaleY; + } + + // adjust anchorPoint + t.tx += Cos * -locAnchorPIP.x * locScaleX + -Sin * locAnchorPIP.y * locScaleY; + t.ty -= Sin * -locAnchorPIP.x * locScaleX + Cos * locAnchorPIP.y * locScaleY; + + // if ignore anchorPoint + if (this._ignoreAnchorPointForPosition) { + t.tx += locAnchorPIP.x; + t.ty += locAnchorPIP.y; + } + + return this._transform; + }; + +})(); \ No newline at end of file diff --git a/cocos2d/physics/CCPhysicsSpriteWebGLRenderCmd.js b/cocos2d/physics/CCPhysicsSpriteWebGLRenderCmd.js new file mode 100644 index 0000000000..332c8e5d6f --- /dev/null +++ b/cocos2d/physics/CCPhysicsSpriteWebGLRenderCmd.js @@ -0,0 +1,87 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.PhysicsSprite's rendering objects of WebGL + */ +(function(){ + cc.PhysicsSprite.WebGLRenderCmd = function(renderableObject){ + cc.Sprite.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = cc.PhysicsSprite.WebGLRenderCmd.prototype = Object.create(cc.Sprite.WebGLRenderCmd.prototype); + proto.constructor = cc.PhysicsSprite.WebGLRenderCmd; + + proto.rendering = function(ctx){ + // This is a special class + // Sprite can not obtain sign + // So here must to calculate of each frame + var node = this._node; + node._syncPosition(); + if(!node._ignoreBodyRotation) + node._syncRotation(); + this.transform(this.getParentRenderCmd()); + + cc.Sprite.WebGLRenderCmd.prototype.rendering.call(this, ctx); + }; + + proto.getNodeToParentTransform = function(){ + var node = this._node; + var locBody = node._body, locAnchorPIP = this._anchorPointInPoints, locScaleX = node._scaleX, locScaleY = node._scaleY; + var x = locBody.p.x; + var y = locBody.p.y; + + if (this._ignoreAnchorPointForPosition) { + x += locAnchorPIP.x; + y += locAnchorPIP.y; + } + + // Make matrix + var radians = locBody.a, c = 1, s=0; + if (radians && !node._ignoreBodyRotation) { + c = Math.cos(radians); + s = Math.sin(radians); + } + + // Although scale is not used by physics engines, it is calculated just in case + // the sprite is animated (scaled up/down) using actions. + // For more info see: http://www.cocos2d-iphone.org/forum/topic/68990 + if (!cc._rectEqualToZero(locAnchorPIP)) { + x += c * -locAnchorPIP.x * locScaleX + -s * -locAnchorPIP.y * locScaleY; + y += s * -locAnchorPIP.x * locScaleX + c * -locAnchorPIP.y * locScaleY; + } + + // Rot, Translate Matrix + this._transform = cc.affineTransformMake(c * locScaleX, s * locScaleX, + -s * locScaleY, c * locScaleY, x, y); + + return this._transform; + }; + + proto.updateTransform = function(){ + this._dirty = this._node.isDirty(); + cc.Sprite.WebGLRenderCmd.prototype.updateTransform.call(this); + }; +})(); \ No newline at end of file diff --git a/cocos2d/progress-timer/CCActionProgressTimer.js b/cocos2d/progress-timer/CCActionProgressTimer.js index 6245b0024a..026af89750 100644 --- a/cocos2d/progress-timer/CCActionProgressTimer.js +++ b/cocos2d/progress-timer/CCActionProgressTimer.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (C) 2010 Lam Pham http://www.cocos2d-x.org @@ -27,6 +29,10 @@ * Progress to percentage * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} percent + * @example + * var to = new cc.ProgressTo(2, 100); */ cc.ProgressTo = cc.ActionInterval.extend(/** @lends cc.ProgressTo# */{ _to:0, @@ -34,11 +40,9 @@ cc.ProgressTo = cc.ActionInterval.extend(/** @lends cc.ProgressTo# */{ /** * Creates a ProgressTo action with a duration and a percent - * @constructor - * @param {Number} duration duration in seconds - * @param {Number} percent - * @example - * var to = new cc.ProgressTo(2, 100); + * Constructor of cc.ProgressTo + * @param {Number} duration duration in seconds + * @param {Number} percent */ ctor: function(duration, percent){ cc.ActionInterval.prototype.ctor.call(this); @@ -60,32 +64,35 @@ cc.ProgressTo = cc.ActionInterval.extend(/** @lends cc.ProgressTo# */{ } return false; }, - + /** + * return a new cc.ProgressTo, all the configuration is the same as the original + * @returns {cc.ProgressTo} + */ clone:function(){ var action = new cc.ProgressTo(); action.initWithDuration(this._duration, this._to); return action; }, - + /** + * reverse hasn't been supported + * @returns {null} + */ reverse: function(){ cc.log("cc.ProgressTo.reverse(): reverse hasn't been supported."); return null; }, /** + * start with a target * @param {cc.Node} target */ startWithTarget:function (target) { cc.ActionInterval.prototype.startWithTarget.call(this, target); this._from = target.percentage; - - // XXX: Is this correct ? - // Adding it to support CCRepeat - if (this._from == 100) - this._from = 0; }, /** + * custom update * @param {Number} time time in seconds */ update:function (time) { @@ -94,22 +101,39 @@ cc.ProgressTo = cc.ActionInterval.extend(/** @lends cc.ProgressTo# */{ } }); -/** Creates and initializes with a duration and a percent +/** + * Creates and initializes with a duration and a percent + * @function * @param {Number} duration duration in seconds * @param {Number} percent * @return {cc.ProgressTo} * @example * // example - * var to = cc.ProgressTo.create(2, 100); + * var to = cc.progressTo(2, 100); */ -cc.ProgressTo.create = function (duration, percent) { +cc.progressTo = function (duration, percent) { return new cc.ProgressTo(duration, percent); }; +/** + * Please use cc.progressTo instead + * Creates and initializes with a duration and a percent + * @static + * @deprecated since v3.0,please use cc.progressTo instead. + * @param {Number} duration duration in seconds + * @param {Number} percent + * @return {cc.ProgressTo} + */ +cc.ProgressTo.create = cc.progressTo; /** * Progress from a percentage to another percentage * @class * @extends cc.ActionInterval + * @param {Number} duration duration in seconds + * @param {Number} fromPercentage + * @param {Number} toPercentage + * @example + * var fromTo = new cc.ProgressFromTo(2, 100.0, 0.0); */ cc.ProgressFromTo = cc.ActionInterval.extend(/** @lends cc.ProgressFromTo# */{ _to:0, @@ -117,12 +141,10 @@ cc.ProgressFromTo = cc.ActionInterval.extend(/** @lends cc.ProgressFromTo# */{ /** * Creates and initializes the action with a duration, a "from" percentage and a "to" percentage - * @constructor - * @param {Number} duration duration in seconds - * @param {Number} fromPercentage - * @param {Number} toPercentage - * @example - * var fromTo = new cc.ProgressFromTo(2, 100.0, 0.0); + * Constructor of cc.ProgressFromTo + * @param {Number} duration duration in seconds + * @param {Number} fromPercentage + * @param {Number} toPercentage */ ctor:function(duration, fromPercentage, toPercentage){ cc.ActionInterval.prototype.ctor.call(this); @@ -146,7 +168,10 @@ cc.ProgressFromTo = cc.ActionInterval.extend(/** @lends cc.ProgressFromTo# */{ } return false; }, - + /** + * return a new cc.ProgressTo, all the configuration is the same as the original + * @returns {cc.ProgressFromTo} + */ clone:function(){ var action = new cc.ProgressFromTo(); action.initWithDuration(this._duration, this._from, this._to); @@ -157,10 +182,11 @@ cc.ProgressFromTo = cc.ActionInterval.extend(/** @lends cc.ProgressFromTo# */{ * @return {cc.ActionInterval} */ reverse:function () { - return cc.ProgressFromTo.create(this._duration, this._to, this._from); + return cc.progressFromTo(this._duration, this._to, this._from); }, /** + * start with a target * @param {cc.Node} target */ startWithTarget:function (target) { @@ -177,14 +203,25 @@ cc.ProgressFromTo = cc.ActionInterval.extend(/** @lends cc.ProgressFromTo# */{ }); /** Creates and initializes the action with a duration, a "from" percentage and a "to" percentage + * @function * @param {Number} duration duration in seconds * @param {Number} fromPercentage * @param {Number} toPercentage * @return {cc.ProgressFromTo} * @example * // example - * var fromTO = cc.ProgressFromTo.create(2, 100.0, 0.0); + * var fromTo = cc.progressFromTo(2, 100.0, 0.0); */ -cc.ProgressFromTo.create = function (duration, fromPercentage, toPercentage) { +cc.progressFromTo = function (duration, fromPercentage, toPercentage) { return new cc.ProgressFromTo(duration, fromPercentage, toPercentage); }; +/** + * Creates and initializes the action with a duration, a "from" percentage and a "to" percentage + * @static + * @deprecated since v3.0,please use cc.ProgressFromTo(duration, fromPercentage, toPercentage) instead. + * @param {Number} duration duration in seconds + * @param {Number} fromPercentage + * @param {Number} toPercentage + * @return {cc.ProgressFromTo} + */ +cc.ProgressFromTo.create = cc.progressFromTo; diff --git a/cocos2d/progress-timer/CCProgressTimer.js b/cocos2d/progress-timer/CCProgressTimer.js index ee35370fea..3ad05586f0 100644 --- a/cocos2d/progress-timer/CCProgressTimer.js +++ b/cocos2d/progress-timer/CCProgressTimer.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2011 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2010 Lam Pham http://www.cocos2d-x.org @@ -23,38 +25,12 @@ THE SOFTWARE. ****************************************************************************/ - -/** - * Radial Counter-Clockwise - * @type Number - * @constant - */ -cc.PROGRESS_TIMER_TYPE_RADIAL = 0; -/** - * Bar - * @type Number - * @constant - */ -cc.PROGRESS_TIMER_TYPE_BAR = 1; - -/** - * @constant - * @type Number - */ -cc.PROGRESS_TEXTURE_COORDS_COUNT = 4; - -/** - * @constant - * @type Number - */ -cc.PROGRESS_TEXTURE_COORDS = 0x4b; - /** * cc.Progresstimer is a subclass of cc.Node.
    * It renders the inner sprite according to the percentage.
    * The progress can be Radial, Horizontal or vertical. * @class - * @extends cc.NodeRGBA + * @extends cc.Node * * @property {cc.Point} midPoint

    - Midpoint is used to modify the progress start position.
    * If you're using radials type then the midpoint changes the center point
    @@ -65,12 +41,13 @@ cc.PROGRESS_TEXTURE_COORDS = 0x4b; * you want a bottom to top then set the midpoint all the way to cc.p(x,0)
    * you want a top to bottom then set the midpoint all the way to cc.p(x,1)

    * @property {cc.Point} barChangeRate - This allows the bar type to move the component at a specific rate. - * @property {enum} type - Type of the progress timer: cc.PROGRESS_TIMER_TYPE_RADIAL|cc.PROGRESS_TIMER_TYPE_BAR. + * @property {enum} type - Type of the progress timer: cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR. * @property {Number} percentage - Percentage to change progress, from 0 to 100. * @property {cc.Sprite} sprite - The sprite to show the progress percentage. * @property {Boolean} reverseDir - Indicate whether the direction is reversed. + * */ -cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ +cc.ProgressTimer = cc.Node.extend(/** @lends cc.ProgressTimer# */{ _type:null, _percentage:0.0, _sprite:null, @@ -80,6 +57,24 @@ cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ _reverseDirection:false, _className:"ProgressTimer", + /** + * constructor of cc.cc.ProgressTimer + * @function + * @param {cc.Sprite} sprite + */ + ctor: function(sprite){ + cc.Node.prototype.ctor.call(this); + + this._type = cc.ProgressTimer.TYPE_RADIAL; + this._percentage = 0.0; + this._midPoint = cc.p(0, 0); + this._barChangeRate = cc.p(0, 0); + this._reverseDirection = false; + this._sprite = null; + + sprite && this.initWithSprite(sprite); + }, + /** * Midpoint is used to modify the progress start position. * If you're using radials type then the midpoint changes the center point @@ -123,7 +118,7 @@ cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ /** * Change the percentage to change progress - * @return {cc.PROGRESS_TIMER_TYPE_RADIAL|cc.PROGRESS_TIMER_TYPE_BAR} + * @return {cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR} */ getType:function () { return this._type; @@ -150,101 +145,49 @@ cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ * @param {Number} percentage */ setPercentage:function (percentage) { - if (this._percentage != percentage) { + if (this._percentage !== percentage) { this._percentage = cc.clampf(percentage, 0, 100); - this._updateProgress(); + this._renderCmd._updateProgress(); } }, - + /** + * only use for jsbinding + * @param bValue + */ setOpacityModifyRGB:function (bValue) { }, - + /** + * only use for jsbinding + * @returns {boolean} + */ isOpacityModifyRGB:function () { return false; }, - + /** + * return if reverse direction + * @returns {boolean} + */ isReverseDirection:function () { return this._reverseDirection; }, - _boundaryTexCoord:function (index) { - if (index < cc.PROGRESS_TEXTURE_COORDS_COUNT) { - var locProTextCoords = cc.PROGRESS_TEXTURE_COORDS; - if (this._reverseDirection) - return cc.p((locProTextCoords >> (7 - (index << 1))) & 1, (locProTextCoords >> (7 - ((index << 1) + 1))) & 1); - else - return cc.p((locProTextCoords >> ((index << 1) + 1)) & 1, (locProTextCoords >> (index << 1)) & 1); - } - return cc.p(0,0); - }, - - _origin:null, - _startAngle:270, - _endAngle:270, - _radius:0, - _counterClockWise:false, - _barRect:null, - - _vertexDataCount:0, - _vertexData:null, - _vertexArrayBuffer:null, - _vertexWebGLBuffer:null, - _vertexDataDirty:false, - - ctor: null, - - _ctorForCanvas: function () { - cc.NodeRGBA.prototype.ctor.call(this); - - this._type = cc.PROGRESS_TIMER_TYPE_RADIAL; - this._percentage = 0.0; - this._midPoint = cc.p(0, 0); - this._barChangeRate = cc.p(0, 0); - this._reverseDirection = false; - - this._sprite = null; - - this._origin = cc.p(0,0); - this._startAngle = 270; - this._endAngle = 270; - this._radius = 0; - this._counterClockWise = false; - this._barRect = cc.rect(0, 0, 0, 0); - }, - - _ctorForWebGL: function () { - cc.NodeRGBA.prototype.ctor.call(this); - this._type = cc.PROGRESS_TIMER_TYPE_RADIAL; - this._percentage = 0.0; - this._midPoint = cc.p(0, 0); - this._barChangeRate = cc.p(0, 0); - this._reverseDirection = false; - - this._sprite = null; - - this._vertexWebGLBuffer = cc._renderContext.createBuffer(); - this._vertexDataCount = 0; - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataDirty = false; - }, - /** * set color of sprite * @param {cc.Color} color */ setColor:function (color) { this._sprite.color = color; - this._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); }, /** - * Opacity + * set opacity of sprite * @param {Number} opacity */ setOpacity:function (opacity) { this._sprite.opacity = opacity; - this._updateColor(); + //this._renderCmd._updateColor(); + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.opacityDirty); }, /** @@ -264,77 +207,42 @@ cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ }, /** + * set reverse cc.ProgressTimer * @function * @param {Boolean} reverse */ - setReverseProgress:null, - - _setReverseProgressForCanvas:function (reverse) { - if (this._reverseDirection !== reverse) - this._reverseDirection = reverse; - }, - - _setReverseProgressForWebGL:function (reverse) { - if (this._reverseDirection !== reverse) { + setReverseProgress: function(reverse){ + if (this._reverseDirection !== reverse){ this._reverseDirection = reverse; - - // release all previous information - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; + this._renderCmd.releaseData(); } }, /** + * set sprite for cc.ProgressTimer * @function * @param {cc.Sprite} sprite */ - setSprite:null, - - _setSpriteForCanvas:function (sprite) { - if (this._sprite != sprite) { - this._sprite = sprite; - this.width = this._sprite.width; - this.height = this._sprite.height; - } - }, - - _setSpriteForWebGL:function (sprite) { - if (sprite && this._sprite != sprite) { + setSprite: function(sprite){ + if (this._sprite !== sprite) { this._sprite = sprite; - this.width = sprite.width; - this.height = sprite.height; - - // Everytime we set a new sprite, we free the current vertex data - if (this._vertexData) { - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; - } + if(sprite) + this.setContentSize(sprite.width,sprite.height); + else + this.setContentSize(0,0); + this._renderCmd.releaseData(); } }, /** * set Progress type of cc.ProgressTimer * @function - * @param {cc.PROGRESS_TIMER_TYPE_RADIAL|cc.PROGRESS_TIMER_TYPE_BAR} type + * @param {cc.ProgressTimer.TYPE_RADIAL|cc.ProgressTimer.TYPE_BAR} type */ - setType:null, - - _setTypeForCanvas:function (type) { - if (type !== this._type) - this._type = type; - }, - - _setTypeForWebGL:function (type) { - if (type !== this._type) { - // release all previous information - if (this._vertexData) { - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; - } + setType: function(type){ + if (type !== this._type){ this._type = type; + this._renderCmd.releaseData(); } }, @@ -343,594 +251,43 @@ cc.ProgressTimer = cc.NodeRGBA.extend(/** @lends cc.ProgressTimer# */{ * @function * @param {Boolean} reverse */ - setReverseDirection: null, - - _setReverseDirectionForCanvas: function (reverse) { - if (this._reverseDirection !== reverse) + setReverseDirection: function(reverse){ + if (this._reverseDirection !== reverse){ this._reverseDirection = reverse; - }, - - _setReverseDirectionForWebGL: function (reverse) { - if (this._reverseDirection !== reverse) { - this._reverseDirection = reverse; - //release all previous information - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; + this._renderCmd.releaseData(); } }, - /** - * @param {cc.Point} alpha - * @return {cc.Vertex2F | Object} the vertex position from the texture coordinate - * @private - */ - _textureCoordFromAlphaPoint:function (alpha) { - var locSprite = this._sprite; - if (!locSprite) { - return {u:0, v:0}; //new cc.Tex2F(0, 0); - } - var quad = locSprite.quad; - var min = cc.p(quad.bl.texCoords.u, quad.bl.texCoords.v); - var max = cc.p(quad.tr.texCoords.u, quad.tr.texCoords.v); - - // Fix bug #1303 so that progress timer handles sprite frame texture rotation - if (locSprite.textureRectRotated) { - var temp = alpha.x; - alpha.x = alpha.y; - alpha.y = temp; - } - return {u: min.x * (1 - alpha.x) + max.x * alpha.x, v: min.y * (1 - alpha.y) + max.y * alpha.y}; - }, - - _vertexFromAlphaPoint:function (alpha) { - if (!this._sprite) { - return {x: 0, y: 0}; - } - var quad = this._sprite.quad; - var min = cc.p(quad.bl.vertices.x, quad.bl.vertices.y); - var max = cc.p(quad.tr.vertices.x, quad.tr.vertices.y); - return {x: min.x * (1 - alpha.x) + max.x * alpha.x, y: min.y * (1 - alpha.y) + max.y * alpha.y}; - }, - /** * Initializes a progress timer with the sprite as the shape the timer goes through * @function * @param {cc.Sprite} sprite * @return {Boolean} */ - initWithSprite:null, - - _initWithSpriteForCanvas:function (sprite) { + initWithSprite: function(sprite){ this.percentage = 0; - this.anchorX = 0.5; - this.anchorY = 0.5; + this.setAnchorPoint(0.5,0.5); - this._type = cc.PROGRESS_TIMER_TYPE_RADIAL; - this._reverseDirection = false; - this.midPoint = cc.p(0.5, 0.5); - this.barChangeRate = cc.p(1, 1); - this.sprite = sprite; - - return true; - }, - - _initWithSpriteForWebGL:function (sprite) { - this.percentage = 0; - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; - this.anchorX = 0.5; - this.anchorY = 0.5; - - this._type = cc.PROGRESS_TIMER_TYPE_RADIAL; + this._type = cc.ProgressTimer.TYPE_RADIAL; this._reverseDirection = false; this.midPoint = cc.p(0.5, 0.5); this.barChangeRate = cc.p(1, 1); - this.sprite = sprite; - - //shader program - this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + this.setSprite(sprite); + this._renderCmd.initCmd(); return true; }, - /** - * Stuff gets drawn here - * @function - * @param {CanvasRenderingContext2D} ctx - */ - draw:null, - - _drawForCanvas:function (ctx) { - var context = ctx || cc._renderContext; - - var locSprite = this._sprite; - if (locSprite._isLighterMode) - context.globalCompositeOperation = 'lighter'; - - var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); - - context.globalAlpha = locSprite._displayedOpacity / 255; - var locRect = locSprite._rect, locContentSize = locSprite._contentSize, locOffsetPosition = locSprite._offsetPosition, locDrawSizeCanvas = locSprite._drawSize_Canvas; - var flipXOffset = 0 | (locOffsetPosition.x), flipYOffset = -locOffsetPosition.y - locRect.height, locTextureCoord = locSprite._textureRect_Canvas; - locDrawSizeCanvas.width = locRect.width * locEGL_ScaleX; - locDrawSizeCanvas.height = locRect.height * locEGL_ScaleY; - - context.save(); - if (locSprite._flippedX) { - flipXOffset = -locOffsetPosition.x - locRect.width; - context.scale(-1, 1); - } - if (locSprite._flippedY) { - flipYOffset = locOffsetPosition.y; - context.scale(1, -1); - } - - flipXOffset *= locEGL_ScaleX; - flipYOffset *= locEGL_ScaleY; - - //clip - if (this._type == cc.PROGRESS_TIMER_TYPE_BAR) { - var locBarRect = this._barRect; - context.beginPath(); - context.rect(locBarRect.x * locEGL_ScaleX, locBarRect.y * locEGL_ScaleY, locBarRect.width * locEGL_ScaleX, locBarRect.height * locEGL_ScaleY); - context.clip(); - context.closePath(); - } else if (this._type == cc.PROGRESS_TIMER_TYPE_RADIAL) { - var locOriginX = this._origin.x * locEGL_ScaleX; - var locOriginY = this._origin.y * locEGL_ScaleY; - context.beginPath(); - context.arc(locOriginX, locOriginY, this._radius * locEGL_ScaleY, (Math.PI / 180) * this._startAngle, (Math.PI / 180) * this._endAngle, this._counterClockWise); - context.lineTo(locOriginX, locOriginY); - context.clip(); - context.closePath(); - } - - //draw sprite - if (locSprite._texture && locTextureCoord.validRect) { - var image = locSprite._texture.getHtmlElementObj(); - if (this._colorized) { - context.drawImage(image, - 0, 0, locTextureCoord.width, locTextureCoord.height, - flipXOffset, flipYOffset, locDrawSizeCanvas.width, locDrawSizeCanvas.height); - } else { - context.drawImage(image, - locTextureCoord.x, locTextureCoord.y, locTextureCoord.width, locTextureCoord.height, - flipXOffset, flipYOffset, locDrawSizeCanvas.width , locDrawSizeCanvas.height); - } - } else if (locContentSize.width !== 0) { - var curColor = this.color; - context.fillStyle = "rgba(" + curColor.r + "," + curColor.g + "," + curColor.b + ",1)"; - context.fillRect(flipXOffset, flipYOffset, locContentSize.width * locEGL_ScaleX, locContentSize.height * locEGL_ScaleY); - } - - context.restore(); - cc.incrementGLDraws(1); - }, - - _drawForWebGL:function (ctx) { - var context = ctx || cc._renderContext; - if (!this._vertexData || !this._sprite) - return; - - cc.nodeDrawSetup(this); - - var blendFunc = this._sprite.getBlendFunc(); - cc.glBlendFunc(blendFunc.src, blendFunc.dst); - cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); - - cc.glBindTexture2D(this._sprite.texture); - - context.bindBuffer(context.ARRAY_BUFFER, this._vertexWebGLBuffer); - if(this._vertexDataDirty){ - context.bufferData(context.ARRAY_BUFFER, this._vertexArrayBuffer, context.DYNAMIC_DRAW); - this._vertexDataDirty = false; - } - var locVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; - context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, locVertexDataLen, 0); - context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, locVertexDataLen, 8); - context.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, context.FLOAT, false, locVertexDataLen, 12); - - if (this._type === cc.PROGRESS_TIMER_TYPE_RADIAL) - context.drawArrays(context.TRIANGLE_FAN, 0, this._vertexDataCount); - else if (this._type == cc.PROGRESS_TIMER_TYPE_BAR) { - if (!this._reverseDirection) - context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount); - else { - context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount / 2); - context.drawArrays(context.TRIANGLE_STRIP, 4, this._vertexDataCount / 2); - // 2 draw calls - cc.g_NumberOfDraws++; - } - } - cc.g_NumberOfDraws++; - }, - - /** - *

    - * Update does the work of mapping the texture onto the triangles
    - * It now doesn't occur the cost of free/alloc data every update cycle.
    - * It also only changes the percentage point but no other points if they have not been modified.
    - *
    - * It now deals with flipped texture. If you run into this problem, just use the
    - * sprite property and enable the methods flipX, flipY.
    - *

    - * @private - */ - _updateRadial:function () { - if (!this._sprite) - return; - - var i, locMidPoint = this._midPoint; - var alpha = this._percentage / 100; - var angle = 2 * (cc.PI) * ( this._reverseDirection ? alpha : 1.0 - alpha); - - // We find the vector to do a hit detection based on the percentage - // We know the first vector is the one @ 12 o'clock (top,mid) so we rotate - // from that by the progress angle around the m_tMidpoint pivot - var topMid = cc.p(locMidPoint.x, 1); - var percentagePt = cc.pRotateByAngle(topMid, locMidPoint, angle); - - var index = 0; - var hit; - - if (alpha == 0) { - // More efficient since we don't always need to check intersection - // If the alpha is zero then the hit point is top mid and the index is 0. - hit = topMid; - index = 0; - } else if (alpha == 1) { - // More efficient since we don't always need to check intersection - // If the alpha is one then the hit point is top mid and the index is 4. - hit = topMid; - index = 4; - } else { - // We run a for loop checking the edges of the texture to find the - // intersection point - // We loop through five points since the top is split in half - - var min_t = cc.FLT_MAX; - var locProTextCoordsCount = cc.PROGRESS_TEXTURE_COORDS_COUNT; - for (i = 0; i <= locProTextCoordsCount; ++i) { - var pIndex = (i + (locProTextCoordsCount - 1)) % locProTextCoordsCount; - - var edgePtA = this._boundaryTexCoord(i % locProTextCoordsCount); - var edgePtB = this._boundaryTexCoord(pIndex); - - // Remember that the top edge is split in half for the 12 o'clock position - // Let's deal with that here by finding the correct endpoints - if (i == 0) - edgePtB = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); - else if (i == 4) - edgePtA = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); - - // retPoint are returned by ccpLineIntersect - var retPoint = cc.p(0, 0); - if (cc.pLineIntersect(edgePtA, edgePtB, locMidPoint, percentagePt, retPoint)) { - // Since our hit test is on rays we have to deal with the top edge - // being in split in half so we have to test as a segment - if ((i == 0 || i == 4)) { - // s represents the point between edgePtA--edgePtB - if (!(0 <= retPoint.x && retPoint.x <= 1)) - continue; - } - // As long as our t isn't negative we are at least finding a - // correct hitpoint from m_tMidpoint to percentagePt. - if (retPoint.y >= 0) { - // Because the percentage line and all the texture edges are - // rays we should only account for the shortest intersection - if (retPoint.y < min_t) { - min_t = retPoint.y; - index = i; - } - } - } - } - - // Now that we have the minimum magnitude we can use that to find our intersection - hit = cc.pAdd(locMidPoint, cc.pMult(cc.pSub(percentagePt, locMidPoint), min_t)); - } - - // The size of the vertex data is the index from the hitpoint - // the 3 is for the m_tMidpoint, 12 o'clock point and hitpoint position. - var sameIndexCount = true; - if (this._vertexDataCount != index + 3) { - sameIndexCount = false; - this._vertexData = null; - this._vertexArrayBuffer = null; - this._vertexDataCount = 0; - } - - if (!this._vertexData) { - this._vertexDataCount = index + 3; - var locCount = this._vertexDataCount, vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; - this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); - var locData = []; - for (i = 0; i < locCount; i++) - locData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); - - this._vertexData = locData; - if(!this._vertexData){ - cc.log( "cc.ProgressTimer._updateRadial() : Not enough memory"); - return; - } - } - this._updateColor(); - - var locVertexData = this._vertexData; - if (!sameIndexCount) { - // First we populate the array with the m_tMidpoint, then all - // vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint - locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(locMidPoint); - locVertexData[0].vertices = this._vertexFromAlphaPoint(locMidPoint); - - locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(topMid); - locVertexData[1].vertices = this._vertexFromAlphaPoint(topMid); - - for (i = 0; i < index; i++) { - var alphaPoint = this._boundaryTexCoord(i); - locVertexData[i + 2].texCoords = this._textureCoordFromAlphaPoint(alphaPoint); - locVertexData[i + 2].vertices = this._vertexFromAlphaPoint(alphaPoint); - } - } - - // hitpoint will go last - locVertexData[this._vertexDataCount - 1].texCoords = this._textureCoordFromAlphaPoint(hit); - locVertexData[this._vertexDataCount - 1].vertices = this._vertexFromAlphaPoint(hit); - }, - - /** - *

    - * Update does the work of mapping the texture onto the triangles for the bar
    - * It now doesn't occur the cost of free/alloc data every update cycle.
    - * It also only changes the percentage point but no other points if they have not been modified.
    - *
    - * It now deals with flipped texture. If you run into this problem, just use the
    - * sprite property and enable the methods flipX, flipY.
    - *

    - * @private - */ - _updateBar:function () { - if (!this._sprite) - return; - - var i; - var alpha = this._percentage / 100.0; - var locBarChangeRate = this._barChangeRate; - var alphaOffset = cc.pMult(cc.p((1.0 - locBarChangeRate.x) + alpha * locBarChangeRate.x, - (1.0 - locBarChangeRate.y) + alpha * locBarChangeRate.y), 0.5); - var min = cc.pSub(this._midPoint, alphaOffset); - var max = cc.pAdd(this._midPoint, alphaOffset); - - if (min.x < 0) { - max.x += -min.x; - min.x = 0; - } - - if (max.x > 1) { - min.x -= max.x - 1; - max.x = 1; - } - - if (min.y < 0) { - max.y += -min.y; - min.y = 0; - } - - if (max.y > 1) { - min.y -= max.y - 1; - max.y = 1; - } - - var locVertexData; - if (!this._reverseDirection) { - if (!this._vertexData) { - this._vertexDataCount = 4; - var vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, locCount = 4; - this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); - this._vertexData = []; - for (i = 0; i < locCount; i++) - this._vertexData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); - } - - locVertexData = this._vertexData; - // TOPLEFT - locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); - locVertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); - - // BOTLEFT - locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); - locVertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); - - // TOPRIGHT - locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); - locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); - - // BOTRIGHT - locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); - locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); - } else { - if (!this._vertexData) { - this._vertexDataCount = 8; - var rVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, rLocCount = 8; - this._vertexArrayBuffer = new ArrayBuffer(rLocCount * rVertexDataLen); - var rTempData = []; - for (i = 0; i < rLocCount; i++) - rTempData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * rVertexDataLen); - // TOPLEFT 1 - rTempData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 1)); - rTempData[0].vertices = this._vertexFromAlphaPoint(cc.p(0, 1)); - - // BOTLEFT 1 - rTempData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 0)); - rTempData[1].vertices = this._vertexFromAlphaPoint(cc.p(0, 0)); - - // TOPRIGHT 2 - rTempData[6].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 1)); - rTempData[6].vertices = this._vertexFromAlphaPoint(cc.p(1, 1)); - - // BOTRIGHT 2 - rTempData[7].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 0)); - rTempData[7].vertices = this._vertexFromAlphaPoint(cc.p(1, 0)); - - this._vertexData = rTempData; - } - - locVertexData = this._vertexData; - // TOPRIGHT 1 - locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); - locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); - - // BOTRIGHT 1 - locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); - locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); - - // TOPLEFT 2 - locVertexData[4].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); - locVertexData[4].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); - - // BOTLEFT 2 - locVertexData[5].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); - locVertexData[5].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); - } - this._updateColor(); - }, - - _updateColor:function () { - if (!this._sprite || !this._vertexData) - return; - - var sc = this._sprite.quad.tl.colors; - var locVertexData = this._vertexData; - for (var i = 0, len = this._vertexDataCount; i < len; ++i) - locVertexData[i].colors = sc; - this._vertexDataDirty = true; - }, - - _updateProgress:null, - - _updateProgressForCanvas:function () { - var locSprite = this._sprite; - var sw = locSprite.width, sh = locSprite.height; - var locMidPoint = this._midPoint; - - if (this._type == cc.PROGRESS_TIMER_TYPE_RADIAL) { - this._radius = Math.round(Math.sqrt(sw * sw + sh * sh)); - var locStartAngle, locEndAngle, locCounterClockWise = false, locOrigin = this._origin; - locOrigin.x = sw * locMidPoint.x; - locOrigin.y = -sh * locMidPoint.y; - - if (this._reverseDirection) { - locEndAngle = 270; - locStartAngle = 270 - 3.6 * this._percentage; - } else { - locStartAngle = -90; - locEndAngle = -90 + 3.6 * this._percentage; - } - - if (locSprite._flippedX) { - locOrigin.x -= sw * (this._midPoint.x * 2); - locStartAngle= -locStartAngle; - locEndAngle= -locEndAngle; - locStartAngle -= 180; - locEndAngle -= 180; - locCounterClockWise = !locCounterClockWise; - } - if (locSprite._flippedY) { - locOrigin.y+=sh*(this._midPoint.y*2); - locCounterClockWise = !locCounterClockWise; - locStartAngle= -locStartAngle; - locEndAngle= -locEndAngle; - } - - this._startAngle = locStartAngle; - this._endAngle = locEndAngle; - this._counterClockWise = locCounterClockWise; - } else { - var locBarChangeRate = this._barChangeRate; - var percentageF = this._percentage / 100; - var locBarRect = this._barRect; - - var drawedSize = cc.size((sw * (1 - locBarChangeRate.x)), (sh * (1 - locBarChangeRate.y))); - var drawingSize = cc.size((sw - drawedSize.width) * percentageF, (sh - drawedSize.height) * percentageF); - var currentDrawSize = cc.size(drawedSize.width + drawingSize.width, drawedSize.height + drawingSize.height); - - var startPoint = cc.p(sw * locMidPoint.x, sh * locMidPoint.y); - - var needToLeft = startPoint.x - currentDrawSize.width / 2; - if (locMidPoint.x > 0.5) { - if (currentDrawSize.width / 2 >= sw - startPoint.x) { - needToLeft = sw - currentDrawSize.width; - } - } - - var needToTop = startPoint.y - currentDrawSize.height / 2; - if (locMidPoint.y > 0.5) { - if (currentDrawSize.height / 2 >= sh - startPoint.y) { - needToTop = sh - currentDrawSize.height; - } - } - - //left pos - locBarRect.x = 0; - var flipXNeed = 1; - if (locSprite._flippedX) { - locBarRect.x -= currentDrawSize.width; - flipXNeed = -1; - } - - if (needToLeft > 0) - locBarRect.x += needToLeft * flipXNeed; - - //right pos - locBarRect.y = 0; - var flipYNeed = 1; - if (locSprite._flippedY) { - locBarRect.y += currentDrawSize.height; - flipYNeed = -1; - } - - if (needToTop > 0) - locBarRect.y -= needToTop * flipYNeed; - - //clip width and clip height - locBarRect.width = currentDrawSize.width; - locBarRect.height = -currentDrawSize.height; - } - }, - - _updateProgressForWebGL:function () { - var locType = this._type; - if(locType === cc.PROGRESS_TIMER_TYPE_RADIAL) - this._updateRadial(); - else if(locType === cc.PROGRESS_TIMER_TYPE_BAR) - this._updateBar(); - this._vertexDataDirty = true; + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ProgressTimer.CanvasRenderCmd(this); + else + return new cc.ProgressTimer.WebGLRenderCmd(this); } }); +// Extended properties var _p = cc.ProgressTimer.prototype; -if(cc._renderType == cc._RENDER_TYPE_WEBGL){ - _p.ctor = _p._ctorForWebGL; - _p.setReverseProgress = _p._setReverseProgressForWebGL; - _p.setSprite = _p._setSpriteForWebGL; - _p.setType = _p._setTypeForWebGL; - _p.setReverseDirection = _p._setReverseDirectionForWebGL; - _p.initWithSprite = _p._initWithSpriteForWebGL; - _p.draw = _p._drawForWebGL; - _p._updateProgress = _p._updateProgressForWebGL; -} else { - _p.ctor = _p._ctorForCanvas; - _p.setReverseProgress = _p._setReverseProgressForCanvas; - _p.setSprite = _p._setSpriteForCanvas; - _p.setType = _p._setTypeForCanvas; - _p.setReverseDirection = _p._setReverseDirectionForCanvas; - _p.initWithSprite = _p._initWithSpriteForCanvas; - _p.draw = _p._drawForCanvas; - _p._updateProgress = cc.ProgressTimer.prototype._updateProgressForCanvas; -} -// Extended properties /** @expose */ _p.midPoint; cc.defineGetterSetter(_p, "midPoint", _p.getMidpoint, _p.setMidpoint); @@ -953,17 +310,36 @@ cc.defineGetterSetter(_p, "reverseDir", _p.isReverseDirection, _p.setReverseDire /** * create a progress timer object with image file name that renders the inner sprite according to the percentage + * @deprecated since v3.0,please use new cc.ProgressTimer(sprite) instead. * @param {cc.Sprite} sprite * @return {cc.ProgressTimer} - * @example - * // Example - * var progress = cc.ProgressTimer.create('progress.png') */ cc.ProgressTimer.create = function (sprite) { - var progressTimer = new cc.ProgressTimer(); - if (progressTimer.initWithSprite(sprite)) - return progressTimer; - return null; + return new cc.ProgressTimer(sprite); }; +/** + * @constant + * @type Number + */ +cc.ProgressTimer.TEXTURE_COORDS_COUNT = 4; + +/** + * @constant + * @type Number + */ +cc.ProgressTimer.TEXTURE_COORDS = 0x4b; +/** + * Radial Counter-Clockwise + * @type Number + * @constant + */ +cc.ProgressTimer.TYPE_RADIAL = 0; + +/** + * Bar + * @type Number + * @constant + */ +cc.ProgressTimer.TYPE_BAR = 1; diff --git a/cocos2d/progress-timer/CCProgressTimerCanvasRenderCmd.js b/cocos2d/progress-timer/CCProgressTimerCanvasRenderCmd.js new file mode 100644 index 0000000000..fbb87b8ced --- /dev/null +++ b/cocos2d/progress-timer/CCProgressTimerCanvasRenderCmd.js @@ -0,0 +1,270 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.ProgressTimer's rendering objects of Canvas + */ +(function(){ + cc.ProgressTimer.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + + this._PI180 = Math.PI / 180; + this._barRect = cc.rect(0, 0, 0, 0); + this._origin = cc.p(0, 0); + this._radius = 0; + this._startAngle = 270; + this._endAngle = 270; + this._counterClockWise = false; + }; + + var proto = cc.ProgressTimer.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.ProgressTimer.CanvasRenderCmd; + + proto.rendering = function (ctx, scaleX, scaleY) { + var wrapper = ctx || cc._renderContext,context = wrapper.getContext(), node = this._node, locSprite = node._sprite; + var locTextureCoord = locSprite._renderCmd._textureCoord, alpha = locSprite._renderCmd._displayedOpacity / 255; + + if (locTextureCoord.width === 0 || locTextureCoord.height === 0) + return; + if (!locSprite._texture || !locTextureCoord.validRect || alpha === 0) + return; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + wrapper.setCompositeOperation(locSprite._blendFuncStr); + wrapper.setGlobalAlpha(alpha); + + var locRect = locSprite._rect, locOffsetPosition = locSprite._offsetPosition; + var locX = locOffsetPosition.x, + locY = -locOffsetPosition.y - locRect.height, + locWidth = locRect.width, + locHeight = locRect.height; + + wrapper.save(); + if (locSprite._flippedX) { + locX = -locX - locWidth; + context.scale(-1, 1); + } + if (locSprite._flippedY) { + locY = locOffsetPosition.y; + context.scale(1, -1); + } + + //clip + if (node._type === cc.ProgressTimer.TYPE_BAR) { + var locBarRect = this._barRect; + context.beginPath(); + context.rect(locBarRect.x * scaleX, locBarRect.y * scaleY, locBarRect.width * scaleX, locBarRect.height * scaleY); + context.clip(); + context.closePath(); + } else if (node._type === cc.ProgressTimer.TYPE_RADIAL) { + var locOriginX = this._origin.x * scaleX; + var locOriginY = this._origin.y * scaleY; + context.beginPath(); + context.arc(locOriginX, locOriginY, this._radius * scaleY, this._PI180 * this._startAngle, this._PI180 * this._endAngle, this._counterClockWise); + context.lineTo(locOriginX, locOriginY); + context.clip(); + context.closePath(); + } + + //draw sprite + var image = locSprite._texture.getHtmlElementObj(); + if (locSprite._colorized) { + context.drawImage(image, + 0, 0, locTextureCoord.width, locTextureCoord.height, + locX * scaleX, locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } else { + context.drawImage(image, + locTextureCoord.renderX, locTextureCoord.renderY, locTextureCoord.width, locTextureCoord.height, + locX * scaleX, locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } + wrapper.restore(); + cc.g_NumberOfDraws++; + }; + + proto.releaseData = function(){}; + + proto.initCmd = function(){}; + + proto._updateProgress = function(){ + var node = this._node; + var locSprite = node._sprite; + var sw = locSprite.width, sh = locSprite.height; + var locMidPoint = node._midPoint; + + if (node._type === cc.ProgressTimer.TYPE_RADIAL) { + this._radius = Math.round(Math.sqrt(sw * sw + sh * sh)); + var locStartAngle, locEndAngle, locCounterClockWise = false, locOrigin = this._origin; + locOrigin.x = sw * locMidPoint.x; + locOrigin.y = -sh * locMidPoint.y; + + if (node._reverseDirection) { + locEndAngle = 270; + locStartAngle = 270 - 3.6 * node._percentage; + } else { + locStartAngle = -90; + locEndAngle = -90 + 3.6 * node._percentage; + } + + if (locSprite._flippedX) { + locOrigin.x -= sw * (node._midPoint.x * 2); + locStartAngle = -locStartAngle; + locEndAngle = -locEndAngle; + locStartAngle -= 180; + locEndAngle -= 180; + locCounterClockWise = !locCounterClockWise; + } + if (locSprite._flippedY) { + locOrigin.y += sh * (node._midPoint.y * 2); + locCounterClockWise = !locCounterClockWise; + locStartAngle = -locStartAngle; + locEndAngle = -locEndAngle; + } + + this._startAngle = locStartAngle; + this._endAngle = locEndAngle; + this._counterClockWise = locCounterClockWise; + } else { + var locBarChangeRate = node._barChangeRate; + var percentageF = node._percentage / 100; + var locBarRect = this._barRect; + + var drewSize = cc.size((sw * (1 - locBarChangeRate.x)), (sh * (1 - locBarChangeRate.y))); + var drawingSize = cc.size((sw - drewSize.width) * percentageF, (sh - drewSize.height) * percentageF); + var currentDrawSize = cc.size(drewSize.width + drawingSize.width, drewSize.height + drawingSize.height); + + var startPoint = cc.p(sw * locMidPoint.x, sh * locMidPoint.y); + + var needToLeft = startPoint.x - currentDrawSize.width / 2; + if ((locMidPoint.x > 0.5) && (currentDrawSize.width / 2 >= sw - startPoint.x)) + needToLeft = sw - currentDrawSize.width; + + var needToTop = startPoint.y - currentDrawSize.height / 2; + if ((locMidPoint.y > 0.5) && (currentDrawSize.height / 2 >= sh - startPoint.y)) + needToTop = sh - currentDrawSize.height; + + //left pos + locBarRect.x = 0; + var flipXNeed = 1; + if (locSprite._flippedX) { + locBarRect.x -= currentDrawSize.width; + flipXNeed = -1; + } + + if (needToLeft > 0) + locBarRect.x += needToLeft * flipXNeed; + + //right pos + locBarRect.y = 0; + var flipYNeed = 1; + if (locSprite._flippedY) { + locBarRect.y += currentDrawSize.height; + flipYNeed = -1; + } + + if (needToTop > 0) + locBarRect.y -= needToTop * flipYNeed; + + //clip width and clip height + locBarRect.width = currentDrawSize.width; + locBarRect.height = -currentDrawSize.height; + } + }; + + proto._updateColor = function(){}; + + proto._syncStatus = function (parentCmd) { + var node = this._node; + if(!node._sprite) + return; + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + + this._dirtyFlag = locFlag; + + var spriteCmd = node._sprite._renderCmd; + var spriteFlag = spriteCmd._dirtyFlag; + + var colorDirty = spriteFlag & flags.colorDirty, + opacityDirty = spriteFlag & flags.opacityDirty; + + if (colorDirty){ + spriteCmd._syncDisplayColor(); + } + + if (opacityDirty){ + spriteCmd._syncDisplayOpacity(); + } + +/* if(colorDirty || opacityDirty){ + spriteCmd._updateColor(); + this._updateColor(); + }*/ + + if (locFlag & flags.transformDirty) { + //update the transform + this.transform(parentCmd); + } + }; + + proto.updateStatus = function () { + var node = this._node; + if(!node._sprite) + return; + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var spriteCmd = node._sprite._renderCmd; + var spriteFlag = spriteCmd._dirtyFlag; + + var colorDirty = spriteFlag & flags.colorDirty, + opacityDirty = spriteFlag & flags.opacityDirty; + + if(colorDirty){ + spriteCmd._updateDisplayColor(); + } + + if(opacityDirty){ + spriteCmd._updateDisplayOpacity(); + } + +/* if(colorDirty || opacityDirty){ + spriteCmd._updateColor(); + this._updateColor(); + }*/ + + if(locFlag & flags.transformDirty){ + //update the transform + this.transform(this.getParentRenderCmd(), true); + } + this._dirtyFlag = 0; + }; +})(); \ No newline at end of file diff --git a/cocos2d/progress-timer/CCProgressTimerWebGLRenderCmd.js b/cocos2d/progress-timer/CCProgressTimerWebGLRenderCmd.js new file mode 100644 index 0000000000..c8b147ae8b --- /dev/null +++ b/cocos2d/progress-timer/CCProgressTimerWebGLRenderCmd.js @@ -0,0 +1,486 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * cc.ProgressTimer's rendering objects of WebGL + */ +(function(){ + cc.ProgressTimer.WebGLRenderCmd = function(renderableObject){ + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + + this._vertexWebGLBuffer = cc._renderContext.createBuffer(); + this._vertexDataCount = 0; + this._vertexData = null; + this._vertexArrayBuffer = null; + this._vertexDataDirty = false; + }; + + var proto = cc.ProgressTimer.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.ProgressTimer.WebGLRenderCmd; + + proto.rendering = function (ctx) { + var node = this._node; + var context = ctx || cc._renderContext; + if (!this._vertexData || !node._sprite) + return; + + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + + var blendFunc = node._sprite._blendFunc; + cc.glBlendFunc(blendFunc.src, blendFunc.dst); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); + + cc.glBindTexture2D(node._sprite.texture); + + context.bindBuffer(context.ARRAY_BUFFER, this._vertexWebGLBuffer); + if (this._vertexDataDirty) { + context.bufferData(context.ARRAY_BUFFER, this._vertexArrayBuffer, context.DYNAMIC_DRAW); + this._vertexDataDirty = false; + } + var locVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; + context.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, context.FLOAT, false, locVertexDataLen, 0); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_COLOR, 4, context.UNSIGNED_BYTE, true, locVertexDataLen, 8); + context.vertexAttribPointer(cc.VERTEX_ATTRIB_TEX_COORDS, 2, context.FLOAT, false, locVertexDataLen, 12); + + if (node._type === cc.ProgressTimer.TYPE_RADIAL) + context.drawArrays(context.TRIANGLE_FAN, 0, this._vertexDataCount); + else if (node._type === cc.ProgressTimer.TYPE_BAR) { + if (!node._reverseDirection) + context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount); + else { + context.drawArrays(context.TRIANGLE_STRIP, 0, this._vertexDataCount / 2); + context.drawArrays(context.TRIANGLE_STRIP, 4, this._vertexDataCount / 2); + // 2 draw calls + cc.g_NumberOfDraws++; + } + } + cc.g_NumberOfDraws++; + }; + + proto._syncStatus = function (parentCmd) { + var node = this._node; + if(!node._sprite) + return; + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var parentNode = parentCmd ? parentCmd._node : null; + + if(parentNode && parentNode._cascadeColorEnabled && (parentCmd._dirtyFlag & flags.colorDirty)) + locFlag |= flags.colorDirty; + if(parentNode && parentNode._cascadeOpacityEnabled && (parentCmd._dirtyFlag & flags.opacityDirty)) + locFlag |= flags.opacityDirty; + if(parentCmd && (parentCmd._dirtyFlag & flags.transformDirty)) + locFlag |= flags.transformDirty; + this._dirtyFlag = locFlag; + + var spriteCmd = node._sprite._renderCmd; + var spriteFlag = spriteCmd._dirtyFlag; + + var colorDirty = spriteFlag & flags.colorDirty, + opacityDirty = spriteFlag & flags.opacityDirty; + + if (colorDirty){ + spriteCmd._syncDisplayColor(); + } + + if (opacityDirty){ + spriteCmd._syncDisplayOpacity(); + } + + if(colorDirty || opacityDirty){ + spriteCmd._updateColor(); + this._updateColor(); + } + + //if (locFlag & flags.transformDirty) { + //update the transform + this.transform(parentCmd); + //} + + spriteCmd._dirtyFlag = 0; + }; + + proto.updateStatus = function () { + var node = this._node; + if(!node._sprite) + return; + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var spriteCmd = node._sprite._renderCmd; + var spriteFlag = spriteCmd._dirtyFlag; + + var colorDirty = spriteFlag & flags.colorDirty, + opacityDirty = spriteFlag & flags.opacityDirty; + + if(colorDirty){ + spriteCmd._updateDisplayColor(); + this._dirtyFlag = this._dirtyFlag & flags.colorDirty ^ this._dirtyFlag; + } + + if(opacityDirty){ + spriteCmd._updateDisplayOpacity(); + this._dirtyFlag = this._dirtyFlag & flags.opacityDirty ^ this._dirtyFlag; + } + + if(colorDirty || opacityDirty){ + spriteCmd._updateColor(); + this._updateColor(); + } + + if(locFlag & flags.transformDirty){ + //update the transform + this.transform(this.getParentRenderCmd(), true); + } + }; + + proto.releaseData = function(){ + if (this._vertexData) { + //release all previous information + this._vertexData = null; + this._vertexArrayBuffer = null; + this._vertexDataCount = 0; + } + }; + + proto.initCmd = function(){ + this._vertexData = null; + this._vertexArrayBuffer = null; + this._vertexDataCount = 0; + + //shader program + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + }; + + proto._updateProgress = function(){ + var node = this._node; + var locType = node._type; + if(locType === cc.ProgressTimer.TYPE_RADIAL) + this._updateRadial(); + else if(locType === cc.ProgressTimer.TYPE_BAR) + this._updateBar(); + this._vertexDataDirty = true; + }; + + /** + *

    + * Update does the work of mapping the texture onto the triangles for the bar
    + * It now doesn't occur the cost of free/alloc data every update cycle.
    + * It also only changes the percentage point but no other points if they have not been modified.
    + *
    + * It now deals with flipped texture. If you run into this problem, just use the
    + * sprite property and enable the methods flipX, flipY.
    + *

    + * @private + */ + proto._updateBar = function(){ + var node = this._node; + if (!node._sprite) + return; + + var i, alpha = node._percentage / 100.0; + var locBarChangeRate = node._barChangeRate; + var alphaOffset = cc.pMult(cc.p((1.0 - locBarChangeRate.x) + alpha * locBarChangeRate.x, + (1.0 - locBarChangeRate.y) + alpha * locBarChangeRate.y), 0.5); + var min = cc.pSub(node._midPoint, alphaOffset), max = cc.pAdd(node._midPoint, alphaOffset); + + if (min.x < 0) { + max.x += -min.x; + min.x = 0; + } + + if (max.x > 1) { + min.x -= max.x - 1; + max.x = 1; + } + + if (min.y < 0) { + max.y += -min.y; + min.y = 0; + } + + if (max.y > 1) { + min.y -= max.y - 1; + max.y = 1; + } + + var locVertexData; + if (!this._reverseDirection) { + if (!this._vertexData) { + this._vertexDataCount = 4; + var vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, locCount = 4; + this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); + this._vertexData = []; + for (i = 0; i < locCount; i++) + this._vertexData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); + } + + locVertexData = this._vertexData; + // TOPLEFT + locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); + locVertexData[0].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); + + // BOTLEFT + locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); + locVertexData[1].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); + + // TOPRIGHT + locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); + locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); + + // BOTRIGHT + locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); + locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); + } else { + if (!this._vertexData) { + this._vertexDataCount = 8; + var rVertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT, rLocCount = 8; + this._vertexArrayBuffer = new ArrayBuffer(rLocCount * rVertexDataLen); + var rTempData = []; + for (i = 0; i < rLocCount; i++) + rTempData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * rVertexDataLen); + // TOPLEFT 1 + rTempData[0].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 1)); + rTempData[0].vertices = this._vertexFromAlphaPoint(cc.p(0, 1)); + + // BOTLEFT 1 + rTempData[1].texCoords = this._textureCoordFromAlphaPoint(cc.p(0, 0)); + rTempData[1].vertices = this._vertexFromAlphaPoint(cc.p(0, 0)); + + // TOPRIGHT 2 + rTempData[6].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 1)); + rTempData[6].vertices = this._vertexFromAlphaPoint(cc.p(1, 1)); + + // BOTRIGHT 2 + rTempData[7].texCoords = this._textureCoordFromAlphaPoint(cc.p(1, 0)); + rTempData[7].vertices = this._vertexFromAlphaPoint(cc.p(1, 0)); + + this._vertexData = rTempData; + } + + locVertexData = this._vertexData; + // TOPRIGHT 1 + locVertexData[2].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, max.y)); + locVertexData[2].vertices = this._vertexFromAlphaPoint(cc.p(min.x, max.y)); + + // BOTRIGHT 1 + locVertexData[3].texCoords = this._textureCoordFromAlphaPoint(cc.p(min.x, min.y)); + locVertexData[3].vertices = this._vertexFromAlphaPoint(cc.p(min.x, min.y)); + + // TOPLEFT 2 + locVertexData[4].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, max.y)); + locVertexData[4].vertices = this._vertexFromAlphaPoint(cc.p(max.x, max.y)); + + // BOTLEFT 2 + locVertexData[5].texCoords = this._textureCoordFromAlphaPoint(cc.p(max.x, min.y)); + locVertexData[5].vertices = this._vertexFromAlphaPoint(cc.p(max.x, min.y)); + } + this._updateColor(); + }; + + /** + *

    + * Update does the work of mapping the texture onto the triangles
    + * It now doesn't occur the cost of free/alloc data every update cycle.
    + * It also only changes the percentage point but no other points if they have not been modified.
    + *
    + * It now deals with flipped texture. If you run into this problem, just use the
    + * sprite property and enable the methods flipX, flipY.
    + *

    + * @private + */ + proto._updateRadial = function () { + var node = this._node; + if (!node._sprite) + return; + + var i, locMidPoint = node._midPoint; + var alpha = node._percentage / 100; + var angle = 2 * (cc.PI) * ( node._reverseDirection ? alpha : 1.0 - alpha); + + // We find the vector to do a hit detection based on the percentage + // We know the first vector is the one @ 12 o'clock (top,mid) so we rotate + // from that by the progress angle around the m_tMidpoint pivot + var topMid = cc.p(locMidPoint.x, 1); + var percentagePt = cc.pRotateByAngle(topMid, locMidPoint, angle); + + var index = 0; + var hit; + + if (alpha === 0) { + // More efficient since we don't always need to check intersection + // If the alpha is zero then the hit point is top mid and the index is 0. + hit = topMid; + index = 0; + } else if (alpha === 1) { + // More efficient since we don't always need to check intersection + // If the alpha is one then the hit point is top mid and the index is 4. + hit = topMid; + index = 4; + } else { + // We run a for loop checking the edges of the texture to find the + // intersection point + // We loop through five points since the top is split in half + + var min_t = cc.FLT_MAX; + var locProTextCoordsCount = cc.ProgressTimer.TEXTURE_COORDS_COUNT; + for (i = 0; i <= locProTextCoordsCount; ++i) { + var pIndex = (i + (locProTextCoordsCount - 1)) % locProTextCoordsCount; + + var edgePtA = this._boundaryTexCoord(i % locProTextCoordsCount); + var edgePtB = this._boundaryTexCoord(pIndex); + + // Remember that the top edge is split in half for the 12 o'clock position + // Let's deal with that here by finding the correct endpoints + if (i === 0) + edgePtB = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); + else if (i === 4) + edgePtA = cc.pLerp(edgePtA, edgePtB, 1 - locMidPoint.x); + + // retPoint are returned by ccpLineIntersect + var retPoint = cc.p(0, 0); + if (cc.pLineIntersect(edgePtA, edgePtB, locMidPoint, percentagePt, retPoint)) { + // Since our hit test is on rays we have to deal with the top edge + // being in split in half so we have to test as a segment + if ((i === 0 || i === 4)) { + // s represents the point between edgePtA--edgePtB + if (!(0 <= retPoint.x && retPoint.x <= 1)) + continue; + } + // As long as our t isn't negative we are at least finding a + // correct hitpoint from m_tMidpoint to percentagePt. + if (retPoint.y >= 0) { + // Because the percentage line and all the texture edges are + // rays we should only account for the shortest intersection + if (retPoint.y < min_t) { + min_t = retPoint.y; + index = i; + } + } + } + } + + // Now that we have the minimum magnitude we can use that to find our intersection + hit = cc.pAdd(locMidPoint, cc.pMult(cc.pSub(percentagePt, locMidPoint), min_t)); + } + + // The size of the vertex data is the index from the hitpoint + // the 3 is for the m_tMidpoint, 12 o'clock point and hitpoint position. + var sameIndexCount = true; + if (this._vertexDataCount !== index + 3) { + sameIndexCount = false; + this._vertexData = null; + this._vertexArrayBuffer = null; + this._vertexDataCount = 0; + } + + if (!this._vertexData) { + this._vertexDataCount = index + 3; + var locCount = this._vertexDataCount, vertexDataLen = cc.V2F_C4B_T2F.BYTES_PER_ELEMENT; + this._vertexArrayBuffer = new ArrayBuffer(locCount * vertexDataLen); + var locData = []; + for (i = 0; i < locCount; i++) + locData[i] = new cc.V2F_C4B_T2F(null, null, null, this._vertexArrayBuffer, i * vertexDataLen); + + this._vertexData = locData; + if(!this._vertexData){ + cc.log( "cc.ProgressTimer._updateRadial() : Not enough memory"); + return; + } + } + this._updateColor(); + + var locVertexData = this._vertexData; + if (!sameIndexCount) { + // First we populate the array with the m_tMidpoint, then all + // vertices/texcoords/colors of the 12 'o clock start and edges and the hitpoint + locVertexData[0].texCoords = this._textureCoordFromAlphaPoint(locMidPoint); + locVertexData[0].vertices = this._vertexFromAlphaPoint(locMidPoint); + + locVertexData[1].texCoords = this._textureCoordFromAlphaPoint(topMid); + locVertexData[1].vertices = this._vertexFromAlphaPoint(topMid); + + for (i = 0; i < index; i++) { + var alphaPoint = this._boundaryTexCoord(i); + locVertexData[i + 2].texCoords = this._textureCoordFromAlphaPoint(alphaPoint); + locVertexData[i + 2].vertices = this._vertexFromAlphaPoint(alphaPoint); + } + } + + // hitpoint will go last + locVertexData[this._vertexDataCount - 1].texCoords = this._textureCoordFromAlphaPoint(hit); + locVertexData[this._vertexDataCount - 1].vertices = this._vertexFromAlphaPoint(hit); + }; + + proto._boundaryTexCoord = function (index) { + if (index < cc.ProgressTimer.TEXTURE_COORDS_COUNT) { + var locProTextCoords = cc.ProgressTimer.TEXTURE_COORDS; + if (this._node._reverseDirection) + return cc.p((locProTextCoords >> (7 - (index << 1))) & 1, (locProTextCoords >> (7 - ((index << 1) + 1))) & 1); + else + return cc.p((locProTextCoords >> ((index << 1) + 1)) & 1, (locProTextCoords >> (index << 1)) & 1); + } + return cc.p(0,0); + }; + + proto._textureCoordFromAlphaPoint = function (alpha) { + var locSprite = this._node._sprite; + if (!locSprite) { + return {u:0, v:0}; //new cc.Tex2F(0, 0); + } + var quad = locSprite.quad; + var min = cc.p(quad.bl.texCoords.u, quad.bl.texCoords.v); + var max = cc.p(quad.tr.texCoords.u, quad.tr.texCoords.v); + + // Fix bug #1303 so that progress timer handles sprite frame texture rotation + if (locSprite.textureRectRotated) { + var temp = alpha.x; + alpha.x = alpha.y; + alpha.y = temp; + } + return {u: min.x * (1 - alpha.x) + max.x * alpha.x, v: min.y * (1 - alpha.y) + max.y * alpha.y}; + }; + + proto._vertexFromAlphaPoint = function (alpha) { + var locSprite = this._node._sprite; + if (!locSprite) { + return {x: 0, y: 0}; + } + var quad = locSprite.quad; + var min = cc.p(quad.bl.vertices.x, quad.bl.vertices.y); + var max = cc.p(quad.tr.vertices.x, quad.tr.vertices.y); + return {x: min.x * (1 - alpha.x) + max.x * alpha.x, y: min.y * (1 - alpha.y) + max.y * alpha.y}; + }; + + proto._updateColor = function(){ + var node = this._node; + if (!node._sprite || !this._vertexData) + return; + + var sc = node._sprite.quad.tl.colors; + var locVertexData = this._vertexData; + for (var i = 0, len = this._vertexDataCount; i < len; ++i) + locVertexData[i].colors = sc; + this._vertexDataDirty = true; + }; +})(); \ No newline at end of file diff --git a/cocos2d/render-texture/CCRenderTexture.js b/cocos2d/render-texture/CCRenderTexture.js index e41a78ee9b..3a8f14da69 100644 --- a/cocos2d/render-texture/CCRenderTexture.js +++ b/cocos2d/render-texture/CCRenderTexture.js @@ -1,8 +1,8 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2009 Jason Booth Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2009 Jason Booth http://www.cocos2d-x.org @@ -42,7 +42,7 @@ cc.IMAGE_FORMAT_PNG = 1; * @constant * @type Number */ -cc.IMAGE_FORMAT_RAWDATA = 2; +cc.IMAGE_FORMAT_RAWDATA = 9; /** * @param {Number} x @@ -70,84 +70,37 @@ cc.NextPOT = function (x) { * @extends cc.Node * * @property {cc.Sprite} sprite - The sprite. + * @property {cc.Sprite} clearFlags - Code for "auto" update. * @property {Number} clearDepthVal - Clear depth value. + * @property {Boolean} autoDraw - Indicate auto draw mode activate or not. * @property {Number} clearStencilVal - Clear stencil value. * @property {cc.Color} clearColorVal - Clear color value, valid only when "autoDraw" is true. - * @property {Boolean} autoDraw - Indicate auto draw mode activate or not. */ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ sprite:null, - /** - *

    Code for "auto" update
    - * Valid flags: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT.
    - * They can be OR'ed. Valid when "autoDraw is YES.

    - * @public - */ + // + //

    Code for "auto" update
    + // Valid flags: GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT.
    + // They can be OR'ed. Valid when "autoDraw is YES.

    + // @public + // clearFlags:0, clearDepthVal:0, autoDraw:false, - /** - * the off-screen canvas for rendering and storing the texture - * @type HTMLCanvasElement - */ - _cacheCanvas:null, - /** - * stores a reference to the canvas context object - * @type CanvasRenderingContext2D - */ - _cacheContext:null, - - _fBO:0, - _depthRenderBuffer:0, - _oldFBO:0, _texture:null, - _textureCopy:null, - _uITextureImage:null, - _pixelFormat:cc.Texture2D.PIXEL_FORMAT_RGBA8888, - _clearColor:null, clearStencilVal:0, + _clearColor:null, - _clearColorStr:null, _className:"RenderTexture", - ctor: null, - - /** - * creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid - * @constructor - * @param {Number} width - * @param {Number} height - * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format - * @param {Number} depthStencilFormat - * @example - * // Example - * var rt = new cc.RenderTexture(width, height, format, depthStencilFormat) - */ - _ctorForCanvas: function (width, height, format, depthStencilFormat) { - cc.Node.prototype.ctor.call(this); - this._clearColor = cc.color(255, 255, 255, 255); - this._clearColorStr = "rgba(255,255,255,1)"; - - this._cacheCanvas = cc.newElement('canvas'); - this._cacheContext = this._cacheCanvas.getContext('2d'); - this.anchorX = 0; - this.anchorY = 0; - - if(width !== undefined && height !== undefined){ - format = format || cc.Texture2D.PIXEL_FORMAT_RGBA8888; - depthStencilFormat = depthStencilFormat || 0; - this.initWithWidthAndHeight(width, height, format, depthStencilFormat); - } - }, - /** * creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid - * @constructor + * Constructor of cc.RenderTexture for Canvas * @param {Number} width * @param {Number} height * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format @@ -155,43 +108,40 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ * @example * // Example * var rt = new cc.RenderTexture(width, height, format, depthStencilFormat) + * @function */ - _ctorForWebGL: function (width, height, format, depthStencilFormat) { + ctor: function(width, height, format, depthStencilFormat){ cc.Node.prototype.ctor.call(this); - this._clearColor = cc.color(0, 0, 0, 0); + this._cascadeColorEnabled = true; + this._cascadeOpacityEnabled = true; + this._clearColor = new cc.Color(0,0,0,255); - if(width !== undefined && height !== undefined){ + if(width !== undefined && height !== undefined) { format = format || cc.Texture2D.PIXEL_FORMAT_RGBA8888; depthStencilFormat = depthStencilFormat || 0; this.initWithWidthAndHeight(width, height, format, depthStencilFormat); } + this.setAnchorPoint(0,0); }, - cleanup:null, - - _cleanupForCanvas:function () { - cc.Node.prototype.onExit.call(this); - this._cacheContext = null; - this._cacheCanvas = null; + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.RenderTexture.CanvasRenderCmd(this); + else + return new cc.RenderTexture.WebGLRenderCmd(this); }, - _cleanupForWebGL: function () { + /** + * Clear RenderTexture. + * @function + */ + cleanup: function(){ cc.Node.prototype.onExit.call(this); - - //this.sprite = null; - this._textureCopy = null; - - var gl = cc._renderContext; - gl.deleteFramebuffer(this._fBO); - if (this._depthRenderBuffer) - gl.deleteRenderbuffer(this._depthRenderBuffer); - this._uITextureImage = null; - //if (this._texture) - // this._texture.releaseTexture(); + this._renderCmd.cleanup(); }, /** - * The sprite + * Gets the sprite * @return {cc.Sprite} */ getSprite:function () { @@ -199,6 +149,7 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ }, /** + * Set the sprite * @param {cc.Sprite} sprite */ setSprite:function (sprite) { @@ -206,296 +157,66 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ }, /** + * Used for grab part of screen to a texture. + * @param {cc.Point} rtBegin + * @param {cc.Rect} fullRect + * @param {cc.Rect} fullViewport + */ + setVirtualViewport: function(rtBegin, fullRect, fullViewport){ + this._renderCmd.setVirtualViewport(rtBegin, fullRect, fullViewport); + }, + + /** + * Initializes the instance of cc.RenderTexture * @function * @param {Number} width * @param {Number} height - * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format - * @param {Number} depthStencilFormat + * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} [format] + * @param {Number} [depthStencilFormat] * @return {Boolean} */ - initWithWidthAndHeight: null, - - _initWithWidthAndHeightForCanvas: function (width, height, format, depthStencilFormat) { - var locCacheCanvas = this._cacheCanvas, locScaleFactor = cc.contentScaleFactor(); - locCacheCanvas.width = 0 | (width * locScaleFactor); - locCacheCanvas.height = 0 | (height * locScaleFactor); - this._cacheContext.translate(0, locCacheCanvas.height); - var texture = new cc.Texture2D(); - texture.initWithElement(locCacheCanvas); - texture.handleLoadedTexture(); - this.sprite = cc.Sprite.create(texture); - return true; - }, - - _initWithWidthAndHeightForWebGL: function (width, height, format, depthStencilFormat) { - if(format == cc.Texture2D.PIXEL_FORMAT_A8) - cc.log( "cc.RenderTexture._initWithWidthAndHeightForWebGL() : only RGB and RGBA formats are valid for a render texture;"); - - var gl = cc._renderContext, locScaleFactor = cc.contentScaleFactor(); - - width = 0 | (width * locScaleFactor); - height = 0 | (height * locScaleFactor); - - this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING); - - // textures must be power of two squared - var powW , powH; - - if (cc.configuration.supportsNPOT()) { - powW = width; - powH = height; - } else { - powW = cc.NextPOT(width); - powH = cc.NextPOT(height); - } - - //void *data = malloc(powW * powH * 4); - var dataLen = powW * powH * 4; - var data = new Uint8Array(dataLen); - //memset(data, 0, (int)(powW * powH * 4)); - for (var i = 0; i < powW * powH * 4; i++) - data[i] = 0; - - this._pixelFormat = format; - - this._texture = new cc.Texture2D(); - if (!this._texture) - return false; - - var locTexture = this._texture; - locTexture.initWithData(data, this._pixelFormat, powW, powH, cc.size(width, height)); - //free( data ); - - var oldRBO = gl.getParameter(gl.RENDERBUFFER_BINDING); - - if (cc.configuration.checkForGLExtension("GL_QCOM")) { - this._textureCopy = new cc.Texture2D(); - if (!this._textureCopy) { - return false; - } - this._textureCopy.initWithData(data, this._pixelFormat, powW, powH, cc.size(width, height)); - } - - // generate FBO - this._fBO = gl.createFramebuffer(); - gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO); - - // associate texture with FBO - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, locTexture._webTextureObj, 0); - - if (depthStencilFormat != 0) { - //create and attach depth buffer - this._depthRenderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this._depthRenderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, depthStencilFormat, powW, powH); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer); - - // if depth format is the one with stencil part, bind same render buffer as stencil attachment - //if (depthStencilFormat == gl.DEPTH24_STENCIL8) - // gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer); - } - - // check if it worked (probably worth doing :) ) - if(gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) - cc.log("Could not attach texture to the framebuffer"); - - locTexture.setAliasTexParameters(); - - this.sprite = cc.Sprite.create(locTexture); - var locSprite = this.sprite; - locSprite.scaleY = -1; - locSprite.setBlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - - gl.bindRenderbuffer(gl.RENDERBUFFER, oldRBO); - gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO); - - // Disabled by default. - this.autoDraw = false; - - // add sprite for backward compatibility - this.addChild(locSprite); - return true; + initWithWidthAndHeight: function(width, height, format, depthStencilFormat){ + return this._renderCmd.initWithWidthAndHeight(width, height, format, depthStencilFormat); }, /** * starts grabbing * @function */ - begin: null, - - _beginForCanvas: function () { - cc._renderContext = this._cacheContext; - cc.view._setScaleXYForRenderTexture(); - - /*// Save the current matrix - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLPushMatrix(); - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLPushMatrix();*/ + begin: function(){ + cc.renderer._turnToCacheMode(this.__instanceId); + this._renderCmd.begin(); }, - - _beginForWebGL: function () { - // Save the current matrix - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLPushMatrix(); - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLPushMatrix(); - - var director = cc.director; - director.setProjection(director.getProjection()); - - var texSize = this._texture.getContentSizeInPixels(); - - // Calculate the adjustment ratios based on the old and new projections - var size = cc.director.getWinSizeInPixels(); - var widthRatio = size.width / texSize.width; - var heightRatio = size.height / texSize.height; - - var gl = cc._renderContext; - - // Adjust the orthographic projection and viewport - gl.viewport(0, 0, texSize.width, texSize.height); - - var orthoMatrix = new cc.kmMat4(); - cc.kmMat4OrthographicProjection(orthoMatrix, -1.0 / widthRatio, 1.0 / widthRatio, - -1.0 / heightRatio, 1.0 / heightRatio, -1, 1); - cc.kmGLMultMatrix(orthoMatrix); - - this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING); - gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO);//Will direct drawing to the frame buffer created above - - /* Certain Qualcomm Andreno gpu's will retain data in memory after a frame buffer switch which corrupts the render to the texture. - * The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture. - * Create a temporary texture to overcome this. At the end of CCRenderTexture::begin(), switch the attached texture to the second one, call glClear, - * and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers. - */ - if (cc.configuration.checkForGLExtension("GL_QCOM")) { - // -- bind a temporary texture so we can clear the render buffer without losing our texture - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._textureCopy._webTextureObj, 0); - //cc.checkGLErrorDebug(); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._texture._webTextureObj, 0); - } - }, - /** * starts rendering to the texture while clearing the texture first.
    * This is more efficient then calling -clear first and then -begin - * @param {Number} r red 0-1 - * @param {Number} g green 0-1 - * @param {Number} b blue 0-1 - * @param {Number} a alpha 0-1 0 is transparent + * @param {Number} r red 0-255 + * @param {Number} g green 0-255 + * @param {Number} b blue 0-255 + * @param {Number} a alpha 0-255 0 is transparent * @param {Number} [depthValue=] * @param {Number} [stencilValue=] */ beginWithClear:function (r, g, b, a, depthValue, stencilValue) { + //todo: only for WebGL? var gl = cc._renderContext; depthValue = depthValue || gl.COLOR_BUFFER_BIT; stencilValue = stencilValue || (gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - this._beginWithClear(r, g, b, a, depthValue, stencilValue, (gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)); - }, - - _beginWithClear: null, - - _beginWithClearForCanvas: function (r, g, b, a, depthValue, stencilValue, flags) { - this.begin(); - - r = r || 0; - g = g || 0; - b = b || 0; - a = isNaN(a) ? 1 : a; - - //var context = cc._renderContext; - var context = this._cacheContext; - var locCanvas = this._cacheCanvas; - context.save(); - context.fillStyle = "rgba(" + (0 | r) + "," + (0 | g) + "," + (0 | b) + "," + a / 255 + ")"; - context.clearRect(0, 0, locCanvas.width, -locCanvas.height); - context.fillRect(0, 0, locCanvas.width, -locCanvas.height); - context.restore(); + this._beginWithClear(r , g , b , a , depthValue, stencilValue, (gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)); }, - _beginWithClearForWebGL: function (r, g, b, a, depthValue, stencilValue, flags) { + _beginWithClear: function(r, g, b, a, depthValue, stencilValue, flags){ this.begin(); - - var gl = cc._renderContext; - - // save clear color - var clearColor = [0.0, 0.0, 0.0, 0.0]; - var depthClearValue = 0.0; - var stencilClearValue = 0; - - if (flags & gl.COLOR_BUFFER_BIT) { - clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); - gl.clearColor(r, g, b, a); - } - - if (flags & gl.DEPTH_BUFFER_BIT) { - depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); - gl.clearDepth(depthValue); - } - - if (flags & gl.STENCIL_BUFFER_BIT) { - stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); - gl.clearStencil(stencilValue); - } - - gl.clear(flags); - - // restore - if (flags & gl.COLOR_BUFFER_BIT) - gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - - if (flags & gl.DEPTH_BUFFER_BIT) - gl.clearDepth(depthClearValue); - - if (flags & gl.STENCIL_BUFFER_BIT) - gl.clearStencil(stencilClearValue); + this._renderCmd._beginWithClear(r, g, b, a, depthValue, stencilValue, flags); }, /** * ends grabbing * @function */ - end: null, - - _endForCanvas: function () { - cc._renderContext = cc._mainRenderContextBackup; - cc.view._resetScale(); - - //TODO - /*//restore viewport - director.setViewport(); - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLPopMatrix(); - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLPopMatrix();*/ - }, - - _endForWebGL: function () { - var gl = cc._renderContext; - var director = cc.director; - gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO); - - //restore viewport - director.setViewport(); - cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); - cc.kmGLPopMatrix(); - cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); - cc.kmGLPopMatrix(); - - /* var size = director.getWinSizeInPixels(); - - // restore viewport - gl.viewport(0, 0, size.width * cc.contentScaleFactor(), size.height * cc.contentScaleFactor()); - - // special viewport for 3d projection + retina display - if (director.getProjection() == cc.Director.PROJECTION_3D && cc.contentScaleFactor() != 1) { - gl.viewport((-size.width / 2), (-size.height / 2), (size.width * cc.contentScaleFactor()), (size.height * cc.contentScaleFactor())); - } - - director.setProjection(director.getProjection());*/ + end: function(){ + this._renderCmd.end(); }, /** @@ -510,14 +231,16 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ this.end(); }, - clearRect:null, - - _clearRectForCanvas:function(x, y, width, height){ - this._cacheContext.clearRect(x, y, width, -height); - }, - - _clearRectForWebGL:function(x, y, width, height){ - //TODO need to implement + /** + * clears the texture with rect. + * @function + * @param {number} x + * @param {number} y + * @param {number} width + * @param {number} height + */ + clearRect: function(x, y, width, height){ + this._renderCmd.clearRect(x, y, width, height); }, /** @@ -525,25 +248,8 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ * @function * @param {Number} depthValue */ - clearDepth:null, - - _clearDepthForCanvas:function (depthValue) { - cc.log("clearDepth isn't supported on Cocos2d-Html5"); - }, - - _clearDepthForWebGL:function (depthValue) { - this.begin(); - - var gl = cc._renderContext; - //! save old depth value - var depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); - - gl.clearDepth(depthValue); - gl.clear(gl.DEPTH_BUFFER_BIT); - - // restore clear color - gl.clearDepth(depthClearValue); - this.end(); + clearDepth: function(depthValue){ + this._renderCmd.clearDepth(depthValue); }, /** @@ -551,195 +257,8 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ * @function * @param {Number} stencilValue */ - clearStencil:null, - - _clearStencilForCanvas:function (stencilValue) { - cc.log("clearDepth isn't supported on Cocos2d-Html5"); - }, - - _clearStencilForWebGL:function (stencilValue) { - var gl = cc._renderContext; - // save old stencil value - var stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); - - gl.clearStencil(stencilValue); - gl.clear(gl.STENCIL_BUFFER_BIT); - - // restore clear color - gl.clearStencil(stencilClearValue); - }, - - visit:null, - - _visitForCanvas:function (ctx) { - // override visit. - // Don't call visit on its children - if (!this._visible) - return; - - ctx = ctx || cc._renderContext; - ctx.save(); - - this.draw(ctx); // update children of RenderTexture before - this.transform(ctx); - this.sprite.visit(); // draw the RenderTexture - - ctx.restore(); - - this.arrivalOrder = 0; - }, - - _visitForWebGL:function (ctx) { - // override visit. - // Don't call visit on its children - if (!this._visible) - return; - - cc.kmGLPushMatrix(); - - var locGrid = this.grid; - if (locGrid && locGrid.isActive()) { - locGrid.beforeDraw(); - this.transformAncestors(); - } - - this.transform(ctx); - this.sprite.visit(); - this.draw(ctx); - - if (locGrid && locGrid.isActive()) - locGrid.afterDraw(this); - - cc.kmGLPopMatrix(); - - this.arrivalOrder = 0; - }, - - draw:null, - - _drawForCanvas: function (ctx) { - ctx = ctx || cc._renderContext; - if (this.autoDraw) { - this.begin(); - - if (this.clearFlags) { - var locCanvas = this._cacheCanvas; - ctx.save(); - ctx.fillStyle = this._clearColorStr; - ctx.clearRect(0, 0, locCanvas.width, -locCanvas.height); - ctx.fillRect(0, 0, locCanvas.width, -locCanvas.height); - ctx.restore(); - } - - //! make sure all children are drawn - this.sortAllChildren(); - var locChildren = this._children; - var childrenLen = locChildren.length; - var selfSprite = this.sprite; - for (var i = 0; i < childrenLen; i++) { - var getChild = locChildren[i]; - if (getChild != selfSprite) - getChild.visit(); - } - - this.end(); - } - }, - - _drawForWebGL: function (ctx) { - var gl = cc._renderContext; - if (this.autoDraw) { - this.begin(); - - var locClearFlags = this.clearFlags; - if (locClearFlags) { - var oldClearColor = [0.0, 0.0, 0.0, 0.0]; - var oldDepthClearValue = 0.0; - var oldStencilClearValue = 0; - - // backup and set - if (locClearFlags & gl.COLOR_BUFFER_BIT) { - oldClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); - gl.clearColor(this._clearColor.r/255, this._clearColor.g/255, this._clearColor.b/255, this._clearColor.a/255); - } - - if (locClearFlags & gl.DEPTH_BUFFER_BIT) { - oldDepthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); - gl.clearDepth(this.clearDepthVal); - } - - if (locClearFlags & gl.STENCIL_BUFFER_BIT) { - oldStencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); - gl.clearStencil(this.clearStencilVal); - } - - // clear - gl.clear(locClearFlags); - - // restore - if (locClearFlags & gl.COLOR_BUFFER_BIT) - gl.clearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[3]); - - if (locClearFlags & gl.DEPTH_BUFFER_BIT) - gl.clearDepth(oldDepthClearValue); - - if (locClearFlags & gl.STENCIL_BUFFER_BIT) - gl.clearStencil(oldStencilClearValue); - } - - //! make sure all children are drawn - this.sortAllChildren(); - var locChildren = this._children; - for (var i = 0; i < locChildren.length; i++) { - var getChild = locChildren[i]; - if (getChild != this.sprite) - getChild.visit(); - } - - this.end(); - } - }, - - /** - * creates a new CCImage from with the texture's data. Caller is responsible for releasing it by calling delete. - * @return {*} - */ - newCCImage:function(flipImage){ - cc.log("saveToFile isn't supported on cocos2d-html5"); - return null; - }, - - _memcpy:function (destArr, destIndex, srcArr, srcIndex, size) { - for (var i = 0; i < size; i++) { - destArr[destIndex + i] = srcArr[srcIndex + i]; - } - }, - - /** - * saves the texture into a file using JPEG format. The file will be saved in the Documents folder. - * Returns YES if the operation is successful. - * (doesn't support in HTML5) - * @param {Number} filePath - * @param {Number} format - */ - saveToFile:function (filePath, format) { - cc.log("saveToFile isn't supported on Cocos2d-Html5"); - }, - - /** - * Listen "come to background" message, and save render texture. It only has effect on Android. - * @param {cc.Class} obj - */ - listenToBackground:function (obj) { - cc.log("listenToBackground isn't supported on Cocos2d-Html5"); - }, - - /** - * Listen "come to foreground" message and restore the frame buffer object. It only has effect on Android. - * @param {cc.Class} obj - */ - listenToForeground:function (obj) { - cc.log("listenToForeground isn't supported on Cocos2d-Html5"); + clearStencil: function(stencilValue) { + this._renderCmd.clearStencil(stencilValue); }, /** @@ -750,6 +269,10 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ return this.clearFlags; }, + /** + * Set the clearFlags + * @param {Number} clearFlags + */ setClearFlags:function (clearFlags) { this.clearFlags = clearFlags; }, @@ -768,24 +291,13 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ * @function * @param {cc.Color} clearColor The clear color */ - setClearColor:null, - - _setClearColorForCanvas:function (clearColor) { - var locClearColor = this._clearColor; - locClearColor.r = clearColor.r; - locClearColor.g = clearColor.g; - locClearColor.b = clearColor.b; - locClearColor.a = clearColor.a; - - this._clearColorStr = "rgba(" + (0 | clearColor.r) + "," + (0 | clearColor.g) + "," + (0 | clearColor.b) + "," + clearColor.a / 255 + ")"; - }, - - _setClearColorForWebGL:function (clearColor) { + setClearColor: function(clearColor){ var locClearColor = this._clearColor; locClearColor.r = clearColor.r; locClearColor.g = clearColor.g; locClearColor.b = clearColor.b; locClearColor.a = clearColor.a; + this._renderCmd.updateClearColor(clearColor); }, /** @@ -796,6 +308,10 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ return this.clearDepthVal; }, + /** + * Set value for clearDepth. Valid only when autoDraw is true. + * @param {Number} clearDepth + */ setClearDepth:function (clearDepth) { this.clearDepthVal = clearDepth; }, @@ -808,6 +324,10 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ return this.clearStencilVal; }, + /** + * Set value for clear Stencil. Valid only when autoDraw is true + * @return {Number} + */ setClearStencil:function (clearStencil) { this.clearStencilVal = clearStencil; }, @@ -821,41 +341,50 @@ cc.RenderTexture = cc.Node.extend(/** @lends cc.RenderTexture# */{ return this.autoDraw; }, + /** + * When enabled, it will render its children into the texture automatically. Disabled by default for compatiblity reasons.
    + * Will be enabled in the future. + * @return {Boolean} + */ setAutoDraw:function (autoDraw) { this.autoDraw = autoDraw; - } -}); + }, -var _p = cc.RenderTexture.prototype; + //---- some stub functions for jsb + /** + * saves the texture into a file using JPEG format. The file will be saved in the Documents folder. + * Returns YES if the operation is successful. + * (doesn't support in HTML5) + * @param {Number} filePath + * @param {Number} format + */ + saveToFile:function (filePath, format) { + cc.log("saveToFile isn't supported on Cocos2d-Html5"); + }, -if(cc._renderType == cc._RENDER_TYPE_WEBGL){ - _p.ctor = _p._ctorForWebGL; - _p.cleanup = _p._cleanupForWebGL; - _p.initWithWidthAndHeight = _p._initWithWidthAndHeightForWebGL; - _p.begin = _p._beginForWebGL; - _p._beginWithClear = _p._beginWithClearForWebGL; - _p.end = _p._endForWebGL; - _p.clearRect = _p._clearRectForWebGL; - _p.clearDepth = _p._clearDepthForWebGL; - _p.clearStencil = _p._clearStencilForWebGL; - _p.visit = _p._visitForWebGL; - _p.draw = _p._drawForWebGL; - _p.setClearColor = _p._setClearColorForWebGL; -} else { - _p.ctor = _p._ctorForCanvas; - _p.cleanup = _p._cleanupForCanvas; - _p.initWithWidthAndHeight = _p._initWithWidthAndHeightForCanvas; - _p.begin = _p._beginForCanvas; - _p._beginWithClear = _p._beginWithClearForCanvas; - _p.end = _p._endForCanvas; - _p.clearRect = _p._clearRectForCanvas; - _p.clearDepth = _p._clearDepthForCanvas; - _p.clearStencil = _p._clearStencilForCanvas; - _p.visit = _p._visitForCanvas; - _p.draw = _p._drawForCanvas; - _p.setClearColor = _p._setClearColorForCanvas; -} + /** + * creates a new CCImage from with the texture's data. Caller is responsible for releasing it by calling delete. + * @return {*} + */ + newCCImage:function(flipImage){ + cc.log("saveToFile isn't supported on cocos2d-html5"); + return null; + }, + + /** + * Listen "come to background" message, and save render texture. It only has effect on Android. + * @param {cc.Class} obj + */ + listenToBackground:function (obj) { }, + /** + * Listen "come to foreground" message and restore the frame buffer object. It only has effect on Android. + * @param {cc.Class} obj + */ + listenToForeground:function (obj) { } +}); + +var _p = cc.RenderTexture.prototype; // Extended /** @expose */ _p.clearColorVal; @@ -864,14 +393,12 @@ cc.defineGetterSetter(_p, "clearColorVal", _p.getClearColor, _p.setClearColor); /** * creates a RenderTexture object with width and height in Points and a pixel format, only RGB and RGBA formats are valid + * @deprecated since v3.0 please use new cc.RenderTexture() instead. * @param {Number} width * @param {Number} height * @param {cc.IMAGE_FORMAT_JPEG|cc.IMAGE_FORMAT_PNG|cc.IMAGE_FORMAT_RAWDATA} format * @param {Number} depthStencilFormat * @return {cc.RenderTexture} - * @example - * // Example - * var rt = cc.RenderTexture.create() */ cc.RenderTexture.create = function (width, height, format, depthStencilFormat) { return new cc.RenderTexture(width, height, format, depthStencilFormat); diff --git a/cocos2d/render-texture/CCRenderTextureCanvasRenderCmd.js b/cocos2d/render-texture/CCRenderTextureCanvasRenderCmd.js new file mode 100644 index 0000000000..6df19091a0 --- /dev/null +++ b/cocos2d/render-texture/CCRenderTextureCanvasRenderCmd.js @@ -0,0 +1,107 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.RenderTexture.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + this._clearColorStr = "rgba(255,255,255,1)"; + + this._cacheCanvas = cc.newElement('canvas'); + this._cacheContext = new cc.CanvasContextWrapper(this._cacheCanvas.getContext('2d')); + }; + + var proto = cc.RenderTexture.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.RenderTexture.CanvasRenderCmd; + + proto.cleanup = function(){ + this._cacheContext = null; + this._cacheCanvas = null; + }; + + proto.clearStencil = function (stencilValue) { }; + + proto.setVirtualViewport = function(rtBegin, fullRect, fullViewport) {}; + + proto.updateClearColor = function(clearColor){ + this._clearColorStr = "rgba(" + (0 | clearColor.r) + "," + (0 | clearColor.g) + "," + (0 | clearColor.b) + "," + clearColor.a / 255 + ")"; + }; + + proto.initWithWidthAndHeight = function(width, height, format, depthStencilFormat){ + var node = this._node; + var locCacheCanvas = this._cacheCanvas, locScaleFactor = cc.contentScaleFactor(); + locCacheCanvas.width = 0 | (width * locScaleFactor); + locCacheCanvas.height = 0 | (height * locScaleFactor); + + var texture = new cc.Texture2D(); + texture.initWithElement(locCacheCanvas); + texture.handleLoadedTexture(); + + var locSprite = node.sprite = new cc.Sprite(texture); + locSprite.setBlendFunc(cc.ONE, cc.ONE_MINUS_SRC_ALPHA); + // Disabled by default. + node.autoDraw = false; + // add sprite for backward compatibility + node.addChild(locSprite); + return true; + }; + + proto.begin = function(){}; + + proto._beginWithClear = function(r, g, b, a, depthValue, stencilValue, flags){ + r = r || 0; + g = g || 0; + b = b || 0; + a = isNaN(a) ? 255 : a; + + var context = this._cacheContext.getContext(); + var locCanvas = this._cacheCanvas; + context.setTransform(1,0,0,1,0,0); + this._cacheContext.setFillStyle("rgba(" + (0 | r) + "," + (0 | g) + "," + (0 | b) + "," + a / 255 + ")"); + context.clearRect(0, 0, locCanvas.width, locCanvas.height); + context.fillRect(0, 0, locCanvas.width, locCanvas.height); + }; + + proto.end = function(){ + var node = this._node; + + var scale = cc.contentScaleFactor(); + cc.renderer._renderingToCacheCanvas(this._cacheContext, node.__instanceId, scale, scale); + }; + + proto.clearRect = function(x, y, width, height){ + this._cacheContext.clearRect(x, y, width, -height); + }; + + proto.clearDepth = function(depthValue){ + cc.log("clearDepth isn't supported on Cocos2d-Html5"); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + this._syncStatus(parentCmd); + node.sprite.visit(this); + this._dirtyFlag = 0; + }; +})(); \ No newline at end of file diff --git a/cocos2d/render-texture/CCRenderTextureWebGLRenderCmd.js b/cocos2d/render-texture/CCRenderTextureWebGLRenderCmd.js new file mode 100644 index 0000000000..50bed35f16 --- /dev/null +++ b/cocos2d/render-texture/CCRenderTextureWebGLRenderCmd.js @@ -0,0 +1,387 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.RenderTexture.WebGLRenderCmd = function(renderableObject){ + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + + this._fBO = null; + this._oldFBO = null; + this._textureCopy = null; + this._depthRenderBuffer = null; + + this._rtTextureRect = new cc.Rect(); + this._fullRect = new cc.Rect(); + this._fullViewport = new cc.Rect(); + }; + + var proto = cc.RenderTexture.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = cc.RenderTexture.WebGLRenderCmd; + + proto.setVirtualViewport = function(rtBegin, fullRect, fullViewport) { + this._rtTextureRect.x = rtBegin.x; + this._rtTextureRect.y = rtBegin.y; + + this._fullRect = fullRect; + this._fullViewport = fullViewport; + }; + + proto.rendering = function (ctx) { + var gl = ctx || cc._renderContext; + var node = this._node; + if (node.autoDraw) { + node.begin(); + + var locClearFlags = node.clearFlags; + if (locClearFlags) { + var oldClearColor = [0.0, 0.0, 0.0, 0.0]; + var oldDepthClearValue = 0.0; + var oldStencilClearValue = 0; + + // backup and set + if (locClearFlags & gl.COLOR_BUFFER_BIT) { + oldClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); + gl.clearColor(node._clearColor.r / 255, node._clearColor.g / 255, node._clearColor.b / 255, node._clearColor.a / 255); + } + + if (locClearFlags & gl.DEPTH_BUFFER_BIT) { + oldDepthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); + gl.clearDepth(node.clearDepthVal); + } + + if (locClearFlags & gl.STENCIL_BUFFER_BIT) { + oldStencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); + gl.clearStencil(node.clearStencilVal); + } + + // clear + gl.clear(locClearFlags); + + // restore + if (locClearFlags & gl.COLOR_BUFFER_BIT) + gl.clearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[3]); + + if (locClearFlags & gl.DEPTH_BUFFER_BIT) + gl.clearDepth(oldDepthClearValue); + + if (locClearFlags & gl.STENCIL_BUFFER_BIT) + gl.clearStencil(oldStencilClearValue); + } + + //! make sure all children are drawn + node.sortAllChildren(); + var locChildren = node._children; + for (var i = 0; i < locChildren.length; i++) { + var getChild = locChildren[i]; + if (getChild !== node.sprite){ + getChild._renderCmd.visit(node.sprite._renderCmd); //TODO it's very Strange + } + } + node.end(); + } + }; + + proto.clearStencil = function(stencilValue) { + var gl = cc._renderContext; + // save old stencil value + var stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); + + gl.clearStencil(stencilValue); + gl.clear(gl.STENCIL_BUFFER_BIT); + + // restore clear color + gl.clearStencil(stencilClearValue); + }; + + proto.cleanup = function(){ + var node = this._node; + //node.sprite = null; + this._textureCopy = null; + + var gl = cc._renderContext; + gl.deleteFramebuffer(this._fBO); + if (this._depthRenderBuffer) + gl.deleteRenderbuffer(this._depthRenderBuffer); + }; + + proto.updateClearColor = function(clearColor){ }; + + proto.initWithWidthAndHeight = function(width, height, format, depthStencilFormat){ + var node = this._node; + if(format === cc.Texture2D.PIXEL_FORMAT_A8) + cc.log( "cc.RenderTexture._initWithWidthAndHeightForWebGL() : only RGB and RGBA formats are valid for a render texture;"); + + var gl = cc._renderContext, locScaleFactor = cc.contentScaleFactor(); + this._fullRect = new cc.Rect(0,0, width, height); + this._fullViewport = new cc.Rect(0,0, width, height); + + width = 0 | (width * locScaleFactor); + height = 0 | (height * locScaleFactor); + + this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING); + + // textures must be power of two squared + var powW , powH; + + if (cc.configuration.supportsNPOT()) { + powW = width; + powH = height; + } else { + powW = cc.NextPOT(width); + powH = cc.NextPOT(height); + } + + //void *data = malloc(powW * powH * 4); + var dataLen = powW * powH * 4; + var data = new Uint8Array(dataLen); + //memset(data, 0, (int)(powW * powH * 4)); + for (var i = 0; i < powW * powH * 4; i++) + data[i] = 0; + + this._pixelFormat = format; + + var locTexture = node._texture = new cc.Texture2D(); + if (!node._texture) + return false; + + locTexture.initWithData(data, node._pixelFormat, powW, powH, cc.size(width, height)); + //free( data ); + + var oldRBO = gl.getParameter(gl.RENDERBUFFER_BINDING); + + if (cc.configuration.checkForGLExtension("GL_QCOM")) { + this._textureCopy = new cc.Texture2D(); + if (!this._textureCopy) + return false; + this._textureCopy.initWithData(data, node._pixelFormat, powW, powH, cc.size(width, height)); + } + + // generate FBO + this._fBO = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO); + + // associate texture with FBO + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, locTexture._webTextureObj, 0); + + if (depthStencilFormat !== 0) { + //create and attach depth buffer + this._depthRenderBuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, this._depthRenderBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, depthStencilFormat, powW, powH); + if(depthStencilFormat === gl.DEPTH_STENCIL) + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer); + else if(depthStencilFormat === gl.STENCIL_INDEX || depthStencilFormat === gl.STENCIL_INDEX8) + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer); + else if(depthStencilFormat === gl.DEPTH_COMPONENT16) + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this._depthRenderBuffer); + } + + // check if it worked (probably worth doing :) ) + if(gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) + cc.log("Could not attach texture to the framebuffer"); + + locTexture.setAliasTexParameters(); + + var locSprite = node.sprite = new cc.Sprite(locTexture); + locSprite.scaleY = -1; + locSprite.setBlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + + gl.bindRenderbuffer(gl.RENDERBUFFER, oldRBO); + gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO); + + // Disabled by default. + node.autoDraw = false; + + // add sprite for backward compatibility + node.addChild(locSprite); + return true; + }; + + proto.begin = function(){ + var node = this._node; + // Save the current matrix + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLPushMatrix(); + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLPushMatrix(); + + var gl = cc._renderContext; + + var director = cc.director; + director.setProjection(director.getProjection()); + + var texSize = node._texture.getContentSizeInPixels(); + + // Calculate the adjustment ratios based on the old and new projections + var size = cc.director.getWinSizeInPixels(); + var widthRatio = size.width / texSize.width; + var heightRatio = size.height / texSize.height; + + var orthoMatrix = cc.math.Matrix4.createOrthographicProjection(-1.0 / widthRatio, 1.0 / widthRatio, + -1.0 / heightRatio, 1.0 / heightRatio, -1, 1); + cc.kmGLMultMatrix(orthoMatrix); + + //calculate viewport + var viewport = new cc.Rect(0, 0, 0, 0); + viewport.width = this._fullViewport.width; + viewport.height = this._fullViewport.height; + var viewPortRectWidthRatio = viewport.width / this._fullRect.width; + var viewPortRectHeightRatio = viewport.height / this._fullRect.height; + viewport.x = (this._fullRect.x - this._rtTextureRect.x) * viewPortRectWidthRatio; + viewport.y = (this._fullRect.y - this._rtTextureRect.y) * viewPortRectHeightRatio; + gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); + + this._oldFBO = gl.getParameter(gl.FRAMEBUFFER_BINDING); + gl.bindFramebuffer(gl.FRAMEBUFFER, this._fBO);//Will direct drawing to the frame buffer created above + + /* Certain Qualcomm Andreno gpu's will retain data in memory after a frame buffer switch which corrupts the render to the texture. + * The solution is to clear the frame buffer before rendering to the texture. However, calling glClear has the unintended result of clearing the current texture. + * Create a temporary texture to overcome this. At the end of CCRenderTexture::begin(), switch the attached texture to the second one, call glClear, + * and then switch back to the original texture. This solution is unnecessary for other devices as they don't have the same issue with switching frame buffers. + */ + if (cc.configuration.checkForGLExtension("GL_QCOM")) { + // -- bind a temporary texture so we can clear the render buffer without losing our texture + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this._textureCopy._webTextureObj, 0); + //cc.checkGLErrorDebug(); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, node._texture._webTextureObj, 0); + } + }; + + proto._beginWithClear = function(r, g, b, a, depthValue, stencilValue, flags){ + r = r / 255; + g = g / 255; + b = b / 255; + a = a / 255; + + var gl = cc._renderContext; + + // save clear color + var clearColor = [0.0, 0.0, 0.0, 0.0]; + var depthClearValue = 0.0; + var stencilClearValue = 0; + + if (flags & gl.COLOR_BUFFER_BIT) { + clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE); + gl.clearColor(r, g, b, a); + } + + if (flags & gl.DEPTH_BUFFER_BIT) { + depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); + gl.clearDepth(depthValue); + } + + if (flags & gl.STENCIL_BUFFER_BIT) { + stencilClearValue = gl.getParameter(gl.STENCIL_CLEAR_VALUE); + gl.clearStencil(stencilValue); + } + + gl.clear(flags); + + // restore + if (flags & gl.COLOR_BUFFER_BIT) + gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + + if (flags & gl.DEPTH_BUFFER_BIT) + gl.clearDepth(depthClearValue); + + if (flags & gl.STENCIL_BUFFER_BIT) + gl.clearStencil(stencilClearValue); + }; + + proto.end = function(){ + var node = this._node; + cc.renderer._renderingToBuffer(node.__instanceId); + + var gl = cc._renderContext; + var director = cc.director; + gl.bindFramebuffer(gl.FRAMEBUFFER, this._oldFBO); + + //restore viewport + director.setViewport(); + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLPopMatrix(); + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLPopMatrix(); + + /* var size = director.getWinSizeInPixels(); + + // restore viewport + gl.viewport(0, 0, size.width * cc.contentScaleFactor(), size.height * cc.contentScaleFactor()); + + // special viewport for 3d projection + retina display + if (director.getProjection() == cc.Director.PROJECTION_3D && cc.contentScaleFactor() != 1) { + gl.viewport((-size.width / 2), (-size.height / 2), (size.width * cc.contentScaleFactor()), (size.height * cc.contentScaleFactor())); + } + + director.setProjection(director.getProjection());*/ + }; + + proto.clearRect = function(x, y, width, height){ + //TODO need to implement + }; + + proto.clearDepth = function(depthValue){ + var node = this._node; + node.begin(); + + var gl = cc._renderContext; + //! save old depth value + var depthClearValue = gl.getParameter(gl.DEPTH_CLEAR_VALUE); + + gl.clearDepth(depthValue); + gl.clear(gl.DEPTH_BUFFER_BIT); + + // restore clear color + gl.clearDepth(depthClearValue); + node.end(); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + if (!node._visible) + return; + cc.kmGLPushMatrix(); + + //TODO using GridNode + /* var locGrid = this.grid; + if (locGrid && locGrid.isActive()) { + locGrid.beforeDraw(); + this.transformAncestors(); + }*/ + + this._syncStatus(parentCmd); + //this.toRenderer(); + cc.renderer.pushRenderCommand(this); + node.sprite.visit(this); + + //TODO GridNode + /* if (locGrid && locGrid.isActive()) + locGrid.afterDraw(this);*/ + + this._dirtyFlag = 0; + cc.kmGLPopMatrix(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/shaders/CCGLProgram.js b/cocos2d/shaders/CCGLProgram.js index 991efd0722..4e63c3c435 100644 --- a/cocos2d/shaders/CCGLProgram.js +++ b/cocos2d/shaders/CCGLProgram.js @@ -1,9 +1,9 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright 2011 Jeff Lamarche Copyright 2012 Goffredo Marocchi - Copyright (c) 2011 Zynga Inc. http://www.cocos2d-x.org @@ -33,11 +33,11 @@ cc.HashUniformEntry = function (value, location, hh) { }; /** - * Class that implements a glProgram + * Class that implements a WebGL program * @class * @extends cc.Class */ -cc.GLProgram = cc.Class.extend({ +cc.GLProgram = cc.Class.extend(/** @lends cc.GLProgram# */{ _glContext: null, _programObj: null, _vertShader: null, @@ -83,8 +83,8 @@ cc.GLProgram = cc.Class.extend({ if (!source || !shader) return false; - //var preStr = (type == this._glContext.VERTEX_SHADER) ? "precision highp float;\n" : "precision mediump float;\n"; - source = "precision highp float; \n" + var preStr = cc.GLProgram._isHighpSupported() ? "precision highp float;\n" : "precision mediump float;\n"; + source = preStr + "uniform mat4 CC_PMatrix; \n" + "uniform mat4 CC_MVMatrix; \n" + "uniform mat4 CC_MVPMatrix; \n" @@ -92,6 +92,7 @@ cc.GLProgram = cc.Class.extend({ + "uniform vec4 CC_SinTime; \n" + "uniform vec4 CC_CosTime; \n" + "uniform vec4 CC_Random01; \n" + + "uniform sampler2D CC_Texture0; \n" + "//CC INCLUDES END \n" + source; this._glContext.shaderSource(shader, source); @@ -100,12 +101,12 @@ cc.GLProgram = cc.Class.extend({ if (!status) { cc.log("cocos2d: ERROR: Failed to compile shader:\n" + this._glContext.getShaderSource(shader)); - if (type == this._glContext.VERTEX_SHADER) + if (type === this._glContext.VERTEX_SHADER) cc.log("cocos2d: \n" + this.vertexShaderLog()); else cc.log("cocos2d: \n" + this.fragmentShaderLog()); } - return ( status == 1 ); + return ( status === true ); }, /** @@ -122,6 +123,9 @@ cc.GLProgram = cc.Class.extend({ vShaderFileName && fShaderFileName && this.init(vShaderFileName, fShaderFileName); }, + /** + * destroy program + */ destroyProgram: function () { this._vertShader = null; this._fragShader = null; @@ -294,10 +298,18 @@ cc.GLProgram = cc.Class.extend({ return this._glContext.getUniformLocation(this._programObj, name); }, + /** + * get uniform MVP matrix + * @returns {WebGLUniformLocation} + */ getUniformMVPMatrix: function () { return this._uniforms[cc.UNIFORM_MVPMATRIX]; }, + /** + * get uniform sampler + * @returns {WebGLUniformLocation} + */ getUniformSampler: function () { return this._uniforms[cc.UNIFORM_SAMPLER]; }, @@ -531,9 +543,9 @@ cc.GLProgram = cc.Class.extend({ * will update the builtin uniforms if they are different than the previous call for this same shader program. */ setUniformsForBuiltins: function () { - var matrixP = new cc.kmMat4(); - var matrixMV = new cc.kmMat4(); - var matrixMVP = new cc.kmMat4(); + var matrixP = new cc.math.Matrix4(); + var matrixMV = new cc.math.Matrix4(); + var matrixMVP = new cc.math.Matrix4(); cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP); cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, matrixMV); @@ -556,7 +568,40 @@ cc.GLProgram = cc.Class.extend({ this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME], time / 8.0, time / 4.0, time / 2.0, Math.cos(time)); } - if (this._uniforms[cc.UNIFORM_RANDOM01] != -1) + if (this._uniforms[cc.UNIFORM_RANDOM01] !== -1) + this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01], Math.random(), Math.random(), Math.random(), Math.random()); + }, + + _setUniformsForBuiltinsForRenderer: function (node) { + if(!node || !node._renderCmd) + return; + + var matrixP = new cc.math.Matrix4(); + //var matrixMV = new cc.kmMat4(); + var matrixMVP = new cc.math.Matrix4(); + + cc.kmGLGetMatrix(cc.KM_GL_PROJECTION, matrixP); + //cc.kmGLGetMatrix(cc.KM_GL_MODELVIEW, node._stackMatrix); + + cc.kmMat4Multiply(matrixMVP, matrixP, node._renderCmd._stackMatrix); + + this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], matrixP.mat, 1); + this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], node._renderCmd._stackMatrix.mat, 1); + this.setUniformLocationWithMatrix4fv(this._uniforms[cc.UNIFORM_MVPMATRIX], matrixMVP.mat, 1); + + if (this._usesTime) { + var director = cc.director; + // This doesn't give the most accurate global time value. + // Cocos2D doesn't store a high precision time value, so this will have to do. + // Getting Mach time per frame per shader using time could be extremely expensive. + var time = director.getTotalFrames() * director.getAnimationInterval(); + + this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_TIME], time / 10.0, time, time * 2, time * 4); + this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_SINTIME], time / 8.0, time / 4.0, time / 2.0, Math.sin(time)); + this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_COSTIME], time / 8.0, time / 4.0, time / 2.0, Math.cos(time)); + } + + if (this._uniforms[cc.UNIFORM_RANDOM01] !== -1) this.setUniformLocationWith4f(this._uniforms[cc.UNIFORM_RANDOM01], Math.random(), Math.random(), Math.random(), Math.random()); }, @@ -578,6 +623,12 @@ cc.GLProgram = cc.Class.extend({ this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], false, cc.projection_matrix_stack.top.mat); }, + _setUniformForMVPMatrixWithMat4: function(modelViewMatrix){ + if(!modelViewMatrix) + throw "modelView matrix is undefined."; + this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_MVMATRIX], false, modelViewMatrix.mat); + this._glContext.uniformMatrix4fv(this._uniforms[cc.UNIFORM_PMATRIX], false, cc.projection_matrix_stack.top.mat); + }, /** * returns the vertexShader error log @@ -671,6 +722,7 @@ cc.GLProgram = cc.Class.extend({ /** * Create a cc.GLProgram object + * @deprecated since v3.0, please use new cc.GLProgram(vShaderFileName, fShaderFileName) instead * @param {String} vShaderFileName * @param {String} fShaderFileName * @returns {cc.GLProgram} @@ -678,3 +730,38 @@ cc.GLProgram = cc.Class.extend({ cc.GLProgram.create = function (vShaderFileName, fShaderFileName) { return new cc.GLProgram(vShaderFileName, fShaderFileName); }; + +cc.GLProgram._highpSupported = null; + +cc.GLProgram._isHighpSupported = function(){ + if(cc.GLProgram._highpSupported == null){ + var ctx = cc._renderContext; + var highp = ctx.getShaderPrecisionFormat(ctx.FRAGMENT_SHADER, ctx.HIGH_FLOAT); + cc.GLProgram._highpSupported = highp.precision !== 0; + } + return cc.GLProgram._highpSupported; +}; + +/** + *

    + * Sets the shader program for this node + * + * Since v2.0, each rendering node must set its shader program. + * It should be set in initialize phase. + *

    + * @function + * @param {cc.Node} node + * @param {cc.GLProgram} program The shader program which fetches from CCShaderCache. + * @example + * cc.setGLProgram(node, cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); + */ +cc.setProgram = function (node, program) { + node.shaderProgram = program; + + var children = node.children; + if (!children) + return; + + for (var i = 0; i < children.length; i++) + cc.setProgram(children[i], program); +}; diff --git a/cocos2d/shaders/CCGLStateCache.js b/cocos2d/shaders/CCGLStateCache.js index c8d890ae32..f048ce03e3 100644 --- a/cocos2d/shaders/CCGLStateCache.js +++ b/cocos2d/shaders/CCGLStateCache.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -46,6 +46,7 @@ if (cc.ENABLE_GL_STATE_CACHE) { /** * Invalidates the GL state cache.
    * If CC_ENABLE_GL_STATE_CACHE it will reset the GL state cache. + * @function */ cc.glInvalidateStateCache = function () { cc.kmGLFreeAll(); @@ -67,6 +68,7 @@ cc.glInvalidateStateCache = function () { /** * Uses the GL program in case program is different than the current one.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will the glUseProgram() directly. + * @function * @param {WebGLProgram} program */ cc.glUseProgram = function (program) { @@ -85,6 +87,7 @@ if(!cc.ENABLE_GL_STATE_CACHE){ /** * Deletes the GL program. If it is the one that is being used, it invalidates it.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will the glDeleteProgram() directly. + * @function * @param {WebGLProgram} program */ cc.glDeleteProgram = function (program) { @@ -98,6 +101,7 @@ cc.glDeleteProgram = function (program) { /** * Uses a blending function in case it not already used.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will the glBlendFunc() directly. + * @function * @param {Number} sfactor * @param {Number} dfactor */ @@ -109,6 +113,11 @@ cc.glBlendFunc = function (sfactor, dfactor) { } }; +/** + * @function + * @param {Number} sfactor + * @param {Number} dfactor + */ cc.setBlending = function (sfactor, dfactor) { var ctx = cc._renderContext; if ((sfactor === ctx.ONE) && (dfactor === ctx.ZERO)) { @@ -121,6 +130,11 @@ cc.setBlending = function (sfactor, dfactor) { } }; +/** + * @function + * @param {Number} sfactor + * @param {Number} dfactor + */ cc.glBlendFuncForParticle = function(sfactor, dfactor) { if ((sfactor !== cc._blendingSource) || (dfactor !== cc._blendingDest)) { cc._blendingSource = sfactor; @@ -143,6 +157,7 @@ if(!cc.ENABLE_GL_STATE_CACHE){ /** * Resets the blending mode back to the cached state in case you used glBlendFuncSeparate() or glBlendEquation().
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will just set the default blending mode using GL_FUNC_ADD. + * @function */ cc.glBlendResetToCache = function () { var ctx = cc._renderContext; @@ -155,6 +170,7 @@ cc.glBlendResetToCache = function () { /** * sets the projection matrix as dirty + * @function */ cc.setProjectionMatrixDirty = function () { cc._currentProjectionMatrix = -1; @@ -170,6 +186,7 @@ cc.setProjectionMatrixDirty = function () { *
    * These flags can be ORed. The flags that are not present, will be disabled. *

    + * @function * @param {cc.VERTEX_ATTRIB_FLAG_POSITION | cc.VERTEX_ATTRIB_FLAG_COLOR | cc.VERTEX_ATTRIB_FLAG_TEX_OORDS} flags */ cc.glEnableVertexAttribs = function (flags) { @@ -208,6 +225,7 @@ cc.glEnableVertexAttribs = function (flags) { /** * If the texture is not already bound, it binds it.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glBindTexture() directly. + * @function * @param {cc.Texture2D} textureId */ cc.glBindTexture2D = function (textureId) { @@ -217,11 +235,12 @@ cc.glBindTexture2D = function (textureId) { /** * If the texture is not already bound to a given unit, it binds it.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glBindTexture() directly. + * @function * @param {Number} textureUnit * @param {cc.Texture2D} textureId */ cc.glBindTexture2DN = function (textureUnit, textureId) { - if (cc._currentBoundTexture[textureUnit] == textureId) + if (cc._currentBoundTexture[textureUnit] === textureId) return; cc._currentBoundTexture[textureUnit] = textureId; @@ -246,6 +265,7 @@ if (!cc.ENABLE_GL_STATE_CACHE){ /** * It will delete a given texture. If the texture was bound, it will invalidate the cached.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glDeleteTextures() directly. + * @function * @param {WebGLTexture} textureId */ cc.glDeleteTexture = function (textureId) { @@ -255,12 +275,13 @@ cc.glDeleteTexture = function (textureId) { /** * It will delete a given texture. If the texture was bound, it will invalidate the cached for the given texture unit.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glDeleteTextures() directly. + * @function * @param {Number} textureUnit * @param {WebGLTexture} textureId */ cc.glDeleteTextureN = function (textureUnit, textureId) { if (cc.ENABLE_GL_STATE_CACHE) { - if (textureId == cc._currentBoundTexture[ textureUnit ]) + if (textureId === cc._currentBoundTexture[ textureUnit ]) cc._currentBoundTexture[ textureUnit ] = -1; } cc._renderContext.deleteTexture(textureId); @@ -269,14 +290,15 @@ cc.glDeleteTextureN = function (textureUnit, textureId) { /** * If the vertex array is not already bound, it binds it.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glBindVertexArray() directly. - * @param vaoId + * @function + * @param {Number} vaoId */ cc.glBindVAO = function (vaoId) { if (!cc.TEXTURE_ATLAS_USE_VAO) return; if (cc.ENABLE_GL_STATE_CACHE) { - if (cc._uVAO != vaoId) { + if (cc._uVAO !== vaoId) { cc._uVAO = vaoId; //TODO need fixed //glBindVertexArray(vaoId); @@ -289,6 +311,7 @@ cc.glBindVAO = function (vaoId) { /** * It will enable / disable the server side GL states.
    * If CC_ENABLE_GL_STATE_CACHE is disabled, it will call glEnable() directly. + * @function * @param {Number} flags */ cc.glEnable = function (flags) { diff --git a/cocos2d/shaders/CCShaderCache.js b/cocos2d/shaders/CCShaderCache.js index 8b56228447..f78780ddb6 100644 --- a/cocos2d/shaders/CCShaderCache.js +++ b/cocos2d/shaders/CCShaderCache.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,7 +25,9 @@ ****************************************************************************/ /** - * @namespace Singleton object that stores manages GL shaders + * cc.shaderCache is a singleton object that stores manages GL shaders + * @class + * @name cc.shaderCache */ cc.shaderCache = /** @lends cc.shaderCache# */{ @@ -271,7 +273,10 @@ cc.shaderCache = /** @lends cc.shaderCache# */{ this._loadDefaultShader(program, this.TYPE_POSITION_UCOLOR); }, - /** returns a GL program for a given key */ + /** + * returns a GL program for a given key + * @param {String} key + */ programForKey: function (key) { return this._programs[key]; }, @@ -279,13 +284,17 @@ cc.shaderCache = /** @lends cc.shaderCache# */{ /** * returns a GL program for a shader name * @param {String} shaderName - * @return cc.GLProgram + * @return {cc.GLProgram} */ getProgram: function (shaderName) { return this._programs[shaderName]; }, - /** adds a CCGLProgram to the cache for a given name */ + /** + * adds a CCGLProgram to the cache for a given name + * @param {cc.GLProgram} program + * @param {String} key + */ addProgram: function (program, key) { this._programs[key] = program; } diff --git a/cocos2d/shaders/CCShaders.js b/cocos2d/shaders/CCShaders.js index 1304248d1a..437ce589aa 100644 --- a/cocos2d/shaders/CCShaders.js +++ b/cocos2d/shaders/CCShaders.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -125,7 +125,6 @@ cc.SHADER_POSITION_COLOR_LENGTH_TEXTURE_VERT = cc.SHADER_POSITION_TEXTURE_FRAG = "precision lowp float; \n" + "varying vec2 v_texCoord; \n" - + "uniform sampler2D CC_Texture0; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D(CC_Texture0, v_texCoord); \n" @@ -155,7 +154,6 @@ cc.SHADER_POSITION_TEXTURE_UCOLOR_FRAG = "precision lowp float; \n" + "uniform vec4 u_color; \n" + "varying vec2 v_texCoord; \n" - + "uniform sampler2D CC_Texture0; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D(CC_Texture0, v_texCoord) * u_color; \n" @@ -185,7 +183,6 @@ cc.SHADER_POSITION_TEXTURE_A8COLOR_FRAG = "precision lowp float; \n" + "varying vec4 v_fragmentColor; \n" + "varying vec2 v_texCoord; \n" - + "uniform sampler2D CC_Texture0; \n" + "void main() \n" + "{ \n" + " gl_FragColor = vec4( v_fragmentColor.rgb, \n" // RGB from uniform @@ -220,7 +217,6 @@ cc.SHADER_POSITION_TEXTURE_COLOR_FRAG = "precision lowp float;\n" + "varying vec4 v_fragmentColor; \n" + "varying vec2 v_texCoord; \n" - + "uniform sampler2D CC_Texture0; \n" + "void main() \n" + "{ \n" + " gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord); \n" @@ -253,13 +249,12 @@ cc.SHADER_POSITION_TEXTURE_COLOR_ALPHATEST_FRAG = "precision lowp float; \n" + "varying vec4 v_fragmentColor; \n" + "varying vec2 v_texCoord; \n" - + "uniform sampler2D CC_Texture0; \n" + "uniform float CC_alpha_value; \n" + "void main() \n" + "{ \n" + " vec4 texColor = texture2D(CC_Texture0, v_texCoord); \n" - + " // mimic: glAlphaFunc(GL_GREATER) \n" - + " //pass if ( incoming_pixel >= CC_alpha_value ) => fail if incoming_pixel < CC_alpha_value \n" + // mimic: glAlphaFunc(GL_GREATER) + //pass if ( incoming_pixel >= CC_alpha_value ) => fail if incoming_pixel < CC_alpha_value + " if ( texColor.a <= CC_alpha_value ) \n" + " discard; \n" + " gl_FragColor = texColor * v_fragmentColor; \n" diff --git a/cocos2d/shape-nodes/CCDrawNode.js b/cocos2d/shape-nodes/CCDrawNode.js index 57abf6a9ea..1d222cb9e7 100644 --- a/cocos2d/shape-nodes/CCDrawNode.js +++ b/cocos2d/shape-nodes/CCDrawNode.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2012 Scott Lembcke and Howling Moon Software http://www.cocos2d-x.org @@ -88,30 +88,42 @@ cc.__t = function (v) { * @name cc.DrawNode * @extends cc.Node */ -cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ +cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ //TODO need refactor _buffer: null, _blendFunc: null, _lineWidth: 1, _drawColor: null, _className:"DrawNodeCanvas", - /* - * @constructor - */ + /** + *

    The cc.DrawNodeCanvas's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.DrawNodeCanvas()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    + */ ctor: function () { cc.Node.prototype.ctor.call(this); - this._buffer = []; - this._drawColor = cc.color(255, 255, 255, 255); - this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); + var locCmd = this._renderCmd; + locCmd._buffer = this._buffer = []; + locCmd._drawColor = this._drawColor = cc.color(255, 255, 255, 255); + locCmd._blendFunc = this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); this.init(); }, // ----common function start ---- + /** + * Gets the blend func + * @returns {Object} + */ getBlendFunc: function () { return this._blendFunc; }, + /** + * Set the blend func + * @param blendFunc + * @param dst + */ setBlendFunc: function (blendFunc, dst) { if (dst === undefined) { this._blendFunc.src = blendFunc.src; @@ -164,12 +176,12 @@ cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ * draws a rectangle given the origin and destination point measured in points. * @param {cc.Point} origin * @param {cc.Point} destination - * @param {cc.Color} fillColor + * @param {cc.Color} fillColor * @param {Number} lineWidth * @param {cc.Color} lineColor */ drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { - lineWidth = lineWidth || this._lineWidth; + lineWidth = (lineWidth == null) ? this._lineWidth : lineWidth; lineColor = lineColor || this.getDrawColor(); if(lineColor.a == null) lineColor.a = 255; @@ -334,7 +346,7 @@ cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ for (var i = 0; i < segments + 1; i++) { var dt = i / segments; // border - if (dt == 1) { + if (dt === 1) { p = config.length - 1; lt = 1; } else { @@ -362,7 +374,7 @@ cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ }, /** - * draw a dot at a position, with a given radius and color + * draw a dot at a position, with a given radius and color * @param {cc.Point} pos * @param {Number} radius * @param {cc.Color} color @@ -424,7 +436,7 @@ cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ * @param {cc.Color} color */ drawPoly_: function (verts, fillColor, lineWidth, color) { - lineWidth = lineWidth || this._lineWidth; + lineWidth = (lineWidth == null ) ? this._lineWidth : lineWidth; color = color || this.getDrawColor(); if (color.a == null) color.a = 255; @@ -457,106 +469,19 @@ cc.DrawNodeCanvas = cc.Node.extend(/** @lends cc.DrawNode# */{ return this.drawPoly_(vertsCopy, fillColor, lineWidth, color); }, - draw: function (ctx) { - var context = ctx || cc._renderContext, _t = this; - if ((_t._blendFunc && (_t._blendFunc.src == cc.SRC_ALPHA) && (_t._blendFunc.dst == cc.ONE))) - context.globalCompositeOperation = 'lighter'; - - for (var i = 0; i < _t._buffer.length; i++) { - var element = _t._buffer[i]; - switch (element.type) { - case cc.DrawNode.TYPE_DOT: - _t._drawDot(context, element); - break; - case cc.DrawNode.TYPE_SEGMENT: - _t._drawSegment(context, element); - break; - case cc.DrawNode.TYPE_POLY: - _t._drawPoly(context, element); - break; - } - } - }, - - _drawDot: function (ctx, element) { - var locColor = element.fillColor, locPos = element.verts[0], locRadius = element.lineWidth; - var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); - - ctx.fillStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; - ctx.beginPath(); - ctx.arc(locPos.x * locScaleX, -locPos.y * locScaleY, locRadius * locScaleX, 0, Math.PI * 2, false); - ctx.closePath(); - ctx.fill(); - }, - - _drawSegment: function (ctx, element) { - var locColor = element.lineColor; - var locFrom = element.verts[0]; - var locTo = element.verts[1]; - var locLineWidth = element.lineWidth; - var locLineCap = element.lineCap; - var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); - - ctx.strokeStyle = "rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"; - ctx.lineWidth = locLineWidth * locScaleX; - ctx.beginPath(); - ctx.lineCap = locLineCap; - ctx.moveTo(locFrom.x * locScaleX, -locFrom.y * locScaleY); - ctx.lineTo(locTo.x * locScaleX, -locTo.y * locScaleY); - ctx.stroke(); - }, - - _drawPoly: function (ctx, element) { - var locVertices = element.verts; - var locLineCap = element.lineCap; - var locFillColor = element.fillColor; - var locLineWidth = element.lineWidth; - var locLineColor = element.lineColor; - var locIsClosePolygon = element.isClosePolygon; - var locIsFill = element.isFill; - var locIsStroke = element.isStroke; - if (locVertices == null) - return; - - var firstPoint = locVertices[0]; - var locScaleX = cc.view.getScaleX(), locScaleY = cc.view.getScaleY(); - - ctx.lineCap = locLineCap; - - if (locFillColor) { - ctx.fillStyle = "rgba(" + (0 | locFillColor.r) + "," + (0 | locFillColor.g) + "," - + (0 | locFillColor.b) + "," + locFillColor.a / 255 + ")"; - } - - if (locLineWidth) { - ctx.lineWidth = locLineWidth * locScaleX; - } - if (locLineColor) { - ctx.strokeStyle = "rgba(" + (0 | locLineColor.r) + "," + (0 | locLineColor.g) + "," - + (0 | locLineColor.b) + "," + locLineColor.a / 255 + ")"; - } - ctx.beginPath(); - ctx.moveTo(firstPoint.x * locScaleX, -firstPoint.y * locScaleY); - for (var i = 1, len = locVertices.length; i < len; i++) - ctx.lineTo(locVertices[i].x * locScaleX, -locVertices[i].y * locScaleY); - - if (locIsClosePolygon) - ctx.closePath(); - - if (locIsFill) - ctx.fill(); - if (locIsStroke) - ctx.stroke(); - }, - /** * Clear the geometry in the node's buffer. */ clear: function () { this._buffer.length = 0; + }, + + _createRenderCmd: function(){ + return new cc.DrawNode.CanvasRenderCmd(this); } }); +//Just only a note cc.DrawNodeWebGL = cc.Node.extend({ _bufferCapacity:0, _buffer:null, @@ -608,26 +533,14 @@ cc.DrawNodeWebGL = cc.Node.extend({ return false; }, - /** - * line width setter - * @param {Number} width - */ setLineWidth: function (width) { this._lineWidth = width; }, - /** - * line width getter - * @returns {Number} - */ getLineWidth: function () { return this._lineWidth; }, - /** - * draw color setter - * @param {cc.Color} color - */ setDrawColor: function (color) { var locDrawColor = this._drawColor; locDrawColor.r = color.r; @@ -636,24 +549,12 @@ cc.DrawNodeWebGL = cc.Node.extend({ locDrawColor.a = color.a; }, - /** - * draw color getter - * @returns {cc.Color} - */ getDrawColor: function () { return cc.color(this._drawColor.r, this._drawColor.g, this._drawColor.b, this._drawColor.a); }, - /** - * draws a rectangle given the origin and destination point measured in points. - * @param {cc.Point} origin - * @param {cc.Point} destination - * @param {cc.Color} fillColor - * @param {Number} lineWidth - * @param {cc.Color} lineColor - */ drawRect: function (origin, destination, fillColor, lineWidth, lineColor) { - lineWidth = lineWidth || this._lineWidth; + lineWidth = (lineWidth == null) ? this._lineWidth : lineWidth; lineColor = lineColor || this.getDrawColor(); if (lineColor.a == null) lineColor.a = 255; @@ -664,17 +565,6 @@ cc.DrawNodeWebGL = cc.Node.extend({ this.drawPoly(vertices, fillColor, lineWidth, lineColor); }, - /** - * draws a circle given the center, radius and number of segments. - * @override - * @param {cc.Point} center center of circle - * @param {Number} radius - * @param {Number} angle angle in radians - * @param {Number} segments - * @param {Boolean} drawLineToCenter - * @param {Number} lineWidth - * @param {cc.Color} color - */ drawCircle: function (center, radius, angle, segments, drawLineToCenter, lineWidth, color) { lineWidth = lineWidth || this._lineWidth; color = color || this.getDrawColor(); @@ -695,16 +585,6 @@ cc.DrawNodeWebGL = cc.Node.extend({ this.drawSegment(vertices[i], vertices[i + 1], lineWidth, color); }, - /** - * draws a quad bezier path - * @override - * @param {cc.Point} origin - * @param {cc.Point} control - * @param {cc.Point} destination - * @param {Number} segments - * @param {Number} lineWidth - * @param {cc.Color} color - */ drawQuadBezier: function (origin, control, destination, segments, lineWidth, color) { lineWidth = lineWidth || this._lineWidth; color = color || this.getDrawColor(); @@ -721,17 +601,6 @@ cc.DrawNodeWebGL = cc.Node.extend({ this._drawSegments(vertices, lineWidth, color, false); }, - /** - * draws a cubic bezier path - * @override - * @param {cc.Point} origin - * @param {cc.Point} control1 - * @param {cc.Point} control2 - * @param {cc.Point} destination - * @param {Number} segments - * @param {Number} lineWidth - * @param {cc.Color} color - */ drawCubicBezier: function (origin, control1, control2, destination, segments, lineWidth, color) { lineWidth = lineWidth || this._lineWidth; color = color || this.getDrawColor(); @@ -748,27 +617,10 @@ cc.DrawNodeWebGL = cc.Node.extend({ this._drawSegments(vertices, lineWidth, color, false); }, - /** - * draw a CatmullRom curve - * @override - * @param {Array} points - * @param {Number} segments - * @param {Number} lineWidth - * @param {cc.Color} color - */ drawCatmullRom: function (points, segments, lineWidth, color) { this.drawCardinalSpline(points, 0.5, segments, lineWidth, color); }, - /** - * draw a cardinal spline path - * @override - * @param {Array} config - * @param {Number} tension - * @param {Number} segments - * @param {Number} lineWidth - * @param {cc.Color} color - */ drawCardinalSpline: function (config, tension, segments, lineWidth, color) { lineWidth = lineWidth || this._lineWidth; color = color || this.getDrawColor(); @@ -780,7 +632,7 @@ cc.DrawNodeWebGL = cc.Node.extend({ var dt = i / segments; // border - if (dt == 1) { + if (dt === 1) { p = config.length - 1; lt = 1; } else { @@ -852,13 +704,6 @@ cc.DrawNodeWebGL = cc.Node.extend({ } }, - draw:function () { - cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); - this._shaderProgram.use(); - this._shaderProgram.setUniformsForBuiltins(); - this._render(); - }, - drawDot:function (pos, radius, color) { color = color || this.getDrawColor(); if (color.a == null) @@ -868,13 +713,16 @@ cc.DrawNodeWebGL = cc.Node.extend({ var b = {vertices: {x: pos.x - radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: -1.0, v: 1.0}}; var c = {vertices: {x: pos.x + radius, y: pos.y + radius}, colors: c4bColor, texCoords: {u: 1.0, v: 1.0}}; var d = {vertices: {x: pos.x + radius, y: pos.y - radius}, colors: c4bColor, texCoords: {u: 1.0, v: -1.0}}; + + this._ensureCapacity(2*3); + this._buffer.push(new cc.V2F_C4B_T2F_Triangle(a, b, c, this._trianglesArrayBuffer, this._buffer.length * cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT)); this._buffer.push(new cc.V2F_C4B_T2F_Triangle(a, c, d, this._trianglesArrayBuffer, this._buffer.length * cc.V2F_C4B_T2F_Triangle.BYTES_PER_ELEMENT)); this._dirty = true; }, drawDots: function(points, radius,color) { - if(!points || points.length == 0) + if(!points || points.length === 0) return; color = color || this.getDrawColor(); if (color.a == null) @@ -941,7 +789,7 @@ cc.DrawNodeWebGL = cc.Node.extend({ fillColor.a = 255; if (borderColor.a == null) borderColor.a = 255; - borderWidth = borderWidth || this._lineWidth; + borderWidth = (borderWidth == null)? this._lineWidth : borderWidth; borderWidth *= 0.5; var c4bFillColor = {r: 0 | fillColor.r, g: 0 | fillColor.g, b: 0 | fillColor.b, a: 0 | fillColor.a}; var c4bBorderColor = {r: 0 | borderColor.r, g: 0 | borderColor.g, b: 0 | borderColor.b, a: 0 | borderColor.a}; @@ -1004,7 +852,7 @@ cc.DrawNodeWebGL = cc.Node.extend({ }, _drawSegments: function(verts, borderWidth, borderColor, closePoly){ - borderWidth = borderWidth || this._lineWidth; + borderWidth = (borderWidth == null) ? this._lineWidth : borderWidth; borderColor = borderColor || this._drawColor; if(borderColor.a == null) borderColor.a = 255; @@ -1056,13 +904,18 @@ cc.DrawNodeWebGL = cc.Node.extend({ clear:function () { this._buffer.length = 0; this._dirty = true; + }, + + _createRenderCmd: function () { + return new cc.DrawNode.WebGLRenderCmd(this); } }); -cc.DrawNode = cc._renderType == cc._RENDER_TYPE_WEBGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; +cc.DrawNode = cc._renderType === cc._RENDER_TYPE_WEBGL ? cc.DrawNodeWebGL : cc.DrawNodeCanvas; /** * Creates a DrawNode + * @deprecated since v3.0 please use new cc.DrawNode() instead. * @return {cc.DrawNode} */ cc.DrawNode.create = function () { diff --git a/cocos2d/shape-nodes/CCDrawNodeCanvasRenderCmd.js b/cocos2d/shape-nodes/CCDrawNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..8631e70a71 --- /dev/null +++ b/cocos2d/shape-nodes/CCDrawNodeCanvasRenderCmd.js @@ -0,0 +1,129 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + + cc.DrawNode.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + this._buffer = null; + this._drawColor = null; + this._blendFunc = null; + }; + + cc.DrawNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + cc.DrawNode.CanvasRenderCmd.prototype.constructor = cc.DrawNode.CanvasRenderCmd; + + cc.DrawNode.CanvasRenderCmd.prototype.rendering = function (ctx, scaleX, scaleY) { + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(), node = this._node; + var alpha = node._displayedOpacity / 255; + if (alpha === 0) + return; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + + //context.save(); + wrapper.setGlobalAlpha(alpha); + if ((this._blendFunc && (this._blendFunc.src === cc.SRC_ALPHA) && (this._blendFunc.dst === cc.ONE))) + wrapper.setCompositeOperation('lighter'); //todo: need refactor + var locBuffer = this._buffer; + for (var i = 0, len = locBuffer.length; i < len; i++) { + var element = locBuffer[i]; + switch (element.type) { + case cc.DrawNode.TYPE_DOT: + this._drawDot(wrapper, element, scaleX, scaleY); + break; + case cc.DrawNode.TYPE_SEGMENT: + this._drawSegment(wrapper, element, scaleX, scaleY); + break; + case cc.DrawNode.TYPE_POLY: + this._drawPoly(wrapper, element, scaleX, scaleY); + break; + } + } + //context.restore(); //todo It can be reserve + }; + + cc.DrawNode.CanvasRenderCmd.prototype._drawDot = function (wrapper, element, scaleX, scaleY) { + var locColor = element.fillColor, locPos = element.verts[0], locRadius = element.lineWidth; + + var ctx = wrapper.getContext(); + wrapper.setFillStyle("rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"); + + ctx.beginPath(); + ctx.arc(locPos.x * scaleX, -locPos.y * scaleY, locRadius * scaleX, 0, Math.PI * 2, false); + ctx.closePath(); + ctx.fill(); + }; + + cc.DrawNode.CanvasRenderCmd.prototype._drawSegment = function (wrapper, element, scaleX, scaleY) { + var locColor = element.lineColor; + var locFrom = element.verts[0], locTo = element.verts[1]; + var locLineWidth = element.lineWidth, locLineCap = element.lineCap; + + var ctx = wrapper.getContext(); + wrapper.setStrokeStyle("rgba(" + (0 | locColor.r) + "," + (0 | locColor.g) + "," + (0 | locColor.b) + "," + locColor.a / 255 + ")"); + + ctx.lineWidth = locLineWidth * scaleX; + ctx.beginPath(); + ctx.lineCap = locLineCap; + ctx.moveTo(locFrom.x * scaleX, -locFrom.y * scaleY); + ctx.lineTo(locTo.x * scaleX, -locTo.y * scaleY); + ctx.stroke(); + }; + + cc.DrawNode.CanvasRenderCmd.prototype._drawPoly = function (wrapper, element, scaleX, scaleY) { + var locVertices = element.verts, locLineCap = element.lineCap; + if (locVertices == null) + return; + + var locFillColor = element.fillColor, locLineWidth = element.lineWidth; + var locLineColor = element.lineColor, locIsClosePolygon = element.isClosePolygon; + var locIsFill = element.isFill, locIsStroke = element.isStroke; + + var ctx = wrapper.getContext(); + var firstPoint = locVertices[0]; + ctx.lineCap = locLineCap; + if (locFillColor) + wrapper.setFillStyle("rgba(" + (0 | locFillColor.r) + "," + (0 | locFillColor.g) + "," + + (0 | locFillColor.b) + "," + locFillColor.a / 255 + ")"); + if (locLineWidth) + ctx.lineWidth = locLineWidth * scaleX; + if (locLineColor) + wrapper.setStrokeStyle("rgba(" + (0 | locLineColor.r) + "," + (0 | locLineColor.g) + "," + + (0 | locLineColor.b) + "," + locLineColor.a / 255 + ")"); + + ctx.beginPath(); + ctx.moveTo(firstPoint.x * scaleX, -firstPoint.y * scaleY); + for (var i = 1, len = locVertices.length; i < len; i++) + ctx.lineTo(locVertices[i].x * scaleX, -locVertices[i].y * scaleY); + + if (locIsClosePolygon) + ctx.closePath(); + if (locIsFill) + ctx.fill(); + if (locIsStroke) + ctx.stroke(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/shape-nodes/CCDrawNodeWebGLRenderCmd.js b/cocos2d/shape-nodes/CCDrawNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..2c393c6cdb --- /dev/null +++ b/cocos2d/shape-nodes/CCDrawNodeWebGLRenderCmd.js @@ -0,0 +1,41 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.DrawNode.WebGLRenderCmd = function (renderableObject) { + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + cc.DrawNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + cc.DrawNode.WebGLRenderCmd.prototype.constructor = cc.DrawNode.WebGLRenderCmd; + + cc.DrawNode.WebGLRenderCmd.prototype.rendering = function (ctx) { + var node = this._node; + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); + node._render(); + }; +})(); \ No newline at end of file diff --git a/cocos2d/text-input/CCIMEDispatcher.js b/cocos2d/text-input/CCIMEDispatcher.js index 07727f5e36..4b713086e5 100644 --- a/cocos2d/text-input/CCIMEDispatcher.js +++ b/cocos2d/text-input/CCIMEDispatcher.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -43,7 +43,7 @@ cc.IMEKeyboardNotificationInfo = function (begin, end, duration) { */ cc.IMEDelegate = cc.Class.extend(/** @lends cc.IMEDelegate# */{ /** - * Constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. */ ctor:function () { cc.imeDispatcher.addDelegate(this); @@ -132,7 +132,8 @@ cc.IMEDelegate = cc.Class.extend(/** @lends cc.IMEDelegate# */{ }); /** - * @namespace Input Method Edit Message Dispatcher. + * cc.imeDispatcher is a singleton object which manage input message dispatching. + * @class * @name cc.imeDispatcher */ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ @@ -141,7 +142,7 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ _currentInputString:"", _lastClickPosition:null, /** - * Constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. */ ctor:function () { this.impl = new cc.IMEDispatcher.Impl(); @@ -177,7 +178,7 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ if (e.keyCode === cc.KEY.tab) { e.stopPropagation(); e.preventDefault(); - } else if (e.keyCode == cc.KEY.enter) { + } else if (e.keyCode === cc.KEY.enter) { selfPointer.dispatchInsertText("\n", 1); e.stopPropagation(); e.preventDefault(); @@ -186,7 +187,7 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ if (/msie/i.test(navigator.userAgent)) { cc._addEventListener(this._domInputControl, "keyup", function (e) { - if (e.keyCode == cc.KEY.backspace) { + if (e.keyCode === cc.KEY.backspace) { selfPointer._processDomInputString(selfPointer._domInputControl.value); } }, false); @@ -352,7 +353,7 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ return false; // if delegate is not in delegate list, return - if (this.impl._delegateList.indexOf(delegate) == -1) + if (this.impl._delegateList.indexOf(delegate) === -1) return false; if (this.impl._delegateWithIme) { @@ -386,7 +387,9 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ delegate.didAttachWithIME(); //prompt this._currentInputString = delegate.string || ""; - var userInput = prompt("please enter your word:", this._currentInputString); + + var tipMessage = delegate.getTipMessage ? delegate.getTipMessage() : "please enter your word:"; + var userInput = prompt(tipMessage, this._currentInputString); if(userInput != null) this._processDomInputString(userInput); this.dispatchInsertText("\n", 1); @@ -422,7 +425,7 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ return false; // if delegate is not the current delegate attached with ime, return - if (this.impl._delegateWithIme != delegate) + if (this.impl._delegateWithIme !== delegate) return false; if (!delegate.canDetachWithIME()) @@ -446,11 +449,11 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ return; // if delegate is not in delegate list, return - if (this.impl._delegateList.indexOf(delegate) == -1) + if (this.impl._delegateList.indexOf(delegate) === -1) return; if (this.impl._delegateWithIme) { - if (delegate == this.impl._delegateWithIme) { + if (delegate === this.impl._delegateWithIme) { this.impl._delegateWithIme = null; } } @@ -468,13 +471,13 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ */ processKeycode:function (keyCode) { if (keyCode < 32) { - if (keyCode == cc.KEY.backspace) { + if (keyCode === cc.KEY.backspace) { this.dispatchDeleteBackward(); - } else if (keyCode == cc.KEY.enter) { + } else if (keyCode === cc.KEY.enter) { this.dispatchInsertText("\n", 1); - } else if (keyCode == cc.KEY.tab) { + } else if (keyCode === cc.KEY.tab) { //tab input - } else if (keyCode == cc.KEY.escape) { + } else if (keyCode === cc.KEY.escape) { //ESC input } } else if (keyCode < 255) { @@ -486,6 +489,8 @@ cc.IMEDispatcher = cc.Class.extend(/** @lends cc.imeDispatcher# */{ }); /** + * Create the cc.IMEDispatcher.Imp Object.
    + * This is the inner class... * @class * @extends cc.Class * @name cc.IMEDispatcher.Impl @@ -494,7 +499,7 @@ cc.IMEDispatcher.Impl = cc.Class.extend(/** @lends cc.IMEDispatcher.Impl# */{ _delegateWithIme:null, _delegateList:null, /** - * Constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. */ ctor:function () { this._delegateList = []; @@ -506,7 +511,7 @@ cc.IMEDispatcher.Impl = cc.Class.extend(/** @lends cc.IMEDispatcher.Impl# */{ */ findDelegate:function (delegate) { for (var i = 0; i < this._delegateList.length; i++) { - if (this._delegateList[i] == delegate) + if (this._delegateList[i] === delegate) return i; } return null; @@ -515,4 +520,9 @@ cc.IMEDispatcher.Impl = cc.Class.extend(/** @lends cc.IMEDispatcher.Impl# */{ // Initialize imeDispatcher singleton cc.imeDispatcher = new cc.IMEDispatcher(); -cc.imeDispatcher.init(); \ No newline at end of file + +document.body ? + cc.imeDispatcher.init() : + cc._addEventListener(window, 'load', function () { + cc.imeDispatcher.init(); + }, false); \ No newline at end of file diff --git a/cocos2d/text-input/CCTextFieldTTF.js b/cocos2d/text-input/CCTextFieldTTF.js index 04fd28cb02..b5c9fb1283 100644 --- a/cocos2d/text-input/CCTextFieldTTF.js +++ b/cocos2d/text-input/CCTextFieldTTF.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -89,11 +89,25 @@ cc.TextFieldDelegate = cc.Class.extend(/** @lends cc.TextFieldDelegate# */{ * @property {Number} charCount - <@readonly> Characators count * @property {String} placeHolder - Place holder for the field * @property {cc.Color} colorSpaceHolder + * + * @param {String} placeholder + * @param {cc.Size} dimensions + * @param {Number} alignment + * @param {String} fontName + * @param {Number} fontSize + * + * @example + * //example + * // When five parameters + * var textField = new cc.TextFieldTTF("", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32); + * // When three parameters + * var textField = new cc.TextFieldTTF("", "Arial", 32); */ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ delegate:null, colorSpaceHolder:null, + _colorText: null, _lens:null, _inputText:"", _placeHolder:"", @@ -101,22 +115,17 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ _className:"TextFieldTTF", /** - * creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size - * @constructor + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
    + * creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size. * @param {String} placeholder * @param {cc.Size} dimensions * @param {Number} alignment * @param {String} fontName * @param {Number} fontSize - * @example - * //example - * // When five parameters - * var textField = cc.TextFieldTTF.create("", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32); - * // When three parameters - * var textField = cc.TextFieldTTF.create("", "Arial", 32); */ ctor:function (placeholder, dimensions, alignment, fontName, fontSize) { this.colorSpaceHolder = cc.color(127, 127, 127); + this._colorText = cc.color(255,255,255, 255); cc.imeDispatcher.addDelegate(this); cc.LabelTTF.prototype.ctor.call(this); @@ -132,6 +141,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Gets the delegate. * @return {cc.Node} */ getDelegate:function () { @@ -139,6 +149,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Set the delegate. * @param {cc.Node} value */ setDelegate:function (value) { @@ -146,6 +157,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Gets the char count. * @return {Number} */ getCharCount:function () { @@ -153,18 +165,39 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Returns the color of space holder. * @return {cc.Color} */ getColorSpaceHolder:function () { - return this.colorSpaceHolder; + return cc.color(this.colorSpaceHolder); }, /** + * Sets the color of space holder. * @param {cc.Color} value */ setColorSpaceHolder:function (value) { - this.colorSpaceHolder = value; + this.colorSpaceHolder.r = value.r; + this.colorSpaceHolder.g = value.g; + this.colorSpaceHolder.b = value.b; + this.colorSpaceHolder.a = cc.isUndefined(value.a) ? 255 : value.a; + if(!this._inputText.length) + this.setColor(this.colorSpaceHolder); }, + + /** + * Sets the color of cc.TextFieldTTF's text. + * @param {cc.Color} textColor + */ + setTextColor:function(textColor){ + this._colorText.r = textColor.r; + this._colorText.g = textColor.g; + this._colorText.b = textColor.b; + this._colorText.a = cc.isUndefined(textColor.a) ? 255 : textColor.a; + if(this._inputText.length) + this.setColor(this._colorText); + }, + /** * Initializes the cc.TextFieldTTF with a font name, alignment, dimension and font size * @param {String} placeholder @@ -184,15 +217,13 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ initWithPlaceHolder:function (placeholder, dimensions, alignment, fontName, fontSize) { switch (arguments.length) { case 5: - if (placeholder) { + if (placeholder) this.setPlaceHolder(placeholder); - } return this.initWithString(this._placeHolder,fontName, fontSize, dimensions, alignment); break; case 3: - if (placeholder) { + if (placeholder) this.setPlaceHolder(placeholder); - } return this.initWithString(this._placeHolder, arguments[1], arguments[2]); break; default: @@ -210,14 +241,20 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ this._inputText = text || ""; // if there is no input text, display placeholder instead - if (!this._inputText.length) + if (!this._inputText.length){ cc.LabelTTF.prototype.setString.call(this, this._placeHolder); - else + this.setColor(this.colorSpaceHolder); + } else { cc.LabelTTF.prototype.setString.call(this,this._inputText); + this.setColor(this._colorText); + } + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + this._renderCmd._updateTexture(); this._charCount = this._inputText.length; }, /** + * Gets the string * @return {String} */ getString:function () { @@ -225,16 +262,21 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Set the place holder.
    + * display this string if string equal "". * @param {String} text */ setPlaceHolder:function (text) { this._placeHolder = text || ""; if (!this._inputText.length) { cc.LabelTTF.prototype.setString.call(this,this._placeHolder); + this.setColor(this.colorSpaceHolder); } }, /** + * Gets the place holder.
    + * default display string. * @return {String} */ getPlaceHolder:function () { @@ -242,7 +284,8 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** - * @param {CanvasContext} ctx + * Render function using the canvas 2d context or WebGL context, internal usage only, please do not call this function. + * @param {CanvasRenderingContext2D | WebGLRenderingContext} ctx The render context */ draw:function (ctx) { //console.log("size",this._contentSize); @@ -250,20 +293,13 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ if (this.delegate && this.delegate.onDraw(this)) return; - if (this._inputText && this._inputText.length > 0) { - cc.LabelTTF.prototype.draw.call(this, context); - return; - } - - // draw placeholder - var color = this.color; - this.color = this.colorSpaceHolder; - if(cc._renderType === cc._RENDER_TYPE_CANVAS) - this._updateTexture(); cc.LabelTTF.prototype.draw.call(this, context); - this.color = color; }, + /** + * Recursive method that visit its children and draw them. + * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx + */ visit: function(ctx){ this._super(ctx); }, @@ -288,6 +324,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Return whether to allow attach with IME. * @return {Boolean} */ canAttachWithIME:function () { @@ -301,6 +338,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** + * Return whether to allow detach with IME. * @return {Boolean} */ canDetachWithIME:function () { @@ -314,11 +352,11 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ }, /** - * Delete backward + * Delete backward */ deleteBackward:function () { var strLen = this._inputText.length; - if (strLen == 0) + if (strLen === 0) return; // get the delete byte number @@ -334,6 +372,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ this._inputText = ""; this._charCount = 0; cc.LabelTTF.prototype.setString.call(this,this._placeHolder); + this.setColor(this.colorSpaceHolder); return; } @@ -348,7 +387,28 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ cc.imeDispatcher.removeDelegate(this); }, + _tipMessage: "please enter your word:", + /** + * Sets the input tip message to show on mobile browser. (mobile Web only) + * @param {string} tipMessage + */ + setTipMessage: function (tipMessage) { + if (tipMessage == null) + return; + this._tipMessage = tipMessage; + }, + /** + * Gets the input tip message to show on mobile browser. (mobile Web only) + * @returns {string} + */ + getTipMessage: function () { + return this._tipMessage; + }, + + /** + * Append the text.
    + * Input the character. * @param {String} text * @param {Number} len */ @@ -372,7 +432,7 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ this.string = sText; } - if (pos == -1) + if (pos === -1) return; // '\n' has inserted, let delegate process first @@ -382,7 +442,9 @@ cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{ // if delegate hasn't process, detach with ime as default this.detachWithIME(); }, + /** + * Gets the input text. * @return {String} */ getContentText:function () { @@ -412,21 +474,16 @@ cc.defineGetterSetter(_p, "charCount", _p.getCharCount); _p.placeHolder; cc.defineGetterSetter(_p, "placeHolder", _p.getPlaceHolder, _p.setPlaceHolder); - /** - * creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size + * Please use new TextFieldTTF instead.
    + * Creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size. + * @deprecated since v3.0 Please use new TextFieldTTF instead. * @param {String} placeholder * @param {cc.Size} dimensions * @param {Number} alignment * @param {String} fontName * @param {Number} fontSize * @return {cc.TextFieldTTF|Null} - * @example - * //example - * // When five parameters - * var textField = cc.TextFieldTTF.create("", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32); - * // When three parameters - * var textField = cc.TextFieldTTF.create("", "Arial", 32); */ cc.TextFieldTTF.create = function (placeholder, dimensions, alignment, fontName, fontSize) { return new cc.TextFieldTTF(placeholder, dimensions, alignment, fontName, fontSize); diff --git a/cocos2d/tilemap/CCTGAlib.js b/cocos2d/tilemap/CCTGAlib.js index 1f729e20df..60a8672ca4 100644 --- a/cocos2d/tilemap/CCTGAlib.js +++ b/cocos2d/tilemap/CCTGAlib.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2013 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -80,7 +82,7 @@ cc.ImageTGA = function (status, type, pixelDepth, width, height, imageData, flip }; /** - * load the image header field from stream. We only keep those that matter! + * load the image header field from stream. We only keep those that matter! * @param {Array} buffer * @param {Number} bufSize * @param {cc.ImageTGA} psInfo @@ -116,7 +118,7 @@ cc.tgaLoadHeader = function (buffer, bufSize, psInfo) { }; /** - * loads the image pixels. You shouldn't call this function directly + * loads the image pixels. You shouldn't call this function directly. * @param {Array} buffer * @param {Number} bufSize * @param {cc.ImageTGA} psInfo @@ -190,6 +192,13 @@ cc.tgaDestroy = function (psInfo) { psInfo = null; }; +/** + * Load RLE image data + * @param buffer + * @param bufSize + * @param psInfo + * @returns {boolean} + */ cc.tgaLoadRLEImageData = function (buffer, bufSize, psInfo) { var mode, total, i, index = 0 , skip = 0, flag = 0; var aux = [], runlength = 0; @@ -203,10 +212,10 @@ cc.tgaLoadRLEImageData = function (buffer, bufSize, psInfo) { for (i = 0; i < total; i++) { // if we have a run length pending, run it - if (runlength != 0) { + if (runlength !== 0) { // we do, update the run length count runlength--; - skip = (flag != 0); + skip = (flag !== 0); } else { // otherwise, read in the run length token if (step + 1 > bufSize) @@ -248,6 +257,10 @@ cc.tgaLoadRLEImageData = function (buffer, bufSize, psInfo) { return true; }; +/** + * ImageTGA Flip + * @param {cc.ImageTGA} psInfo + */ cc.tgaFlipImage = function (psInfo) { // mode equal the number of components for each pixel var mode = psInfo.pixelDepth / 8; @@ -273,20 +286,39 @@ cc.__setDataToArray = function (sourceData, destArray, startIndex) { destArray[startIndex + i] = sourceData[i]; }; - +/** + * Binary Stream Reader + * + * @class + * @param binaryData + */ cc.BinaryStreamReader = cc.Class.extend({ _binaryData:null, _offset:0, + /** + *

    The cc.BinaryStreamReader's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.BinaryStreamReader()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    + * @param binaryData + */ ctor:function (binaryData) { this._binaryData = binaryData; }, + /** + * Set the binaryData. + * @param binaryData + */ setBinaryData:function (binaryData) { this._binaryData = binaryData; this._offset = 0; }, + /** + * Gets the binaryData. + * @returns {Object} + */ getBinaryData:function () { return this._binaryData; }, @@ -320,7 +352,7 @@ cc.BinaryStreamReader = cc.Class.extend({ this._offset += size; - return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity + return exponent === (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand : Math.pow(2, exponent - bias) * (1 + significand) : 0); }, @@ -338,7 +370,7 @@ cc.BinaryStreamReader = cc.Class.extend({ }, _shl:function (a, b) { - for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1){}; + for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) === 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1){}; return a; }, diff --git a/cocos2d/tilemap/CCTMXLayer.js b/cocos2d/tilemap/CCTMXLayer.js index 9463cf4009..9491fb6b70 100644 --- a/cocos2d/tilemap/CCTMXLayer.js +++ b/cocos2d/tilemap/CCTMXLayer.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -72,28 +72,17 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ //Only used when vertexZ is used _vertexZvalue: null, _useAutomaticVertexZ: null, - _alphaFuncValue: null, //used for optimization _reusedTile: null, _atlasIndexArray: null, //used for retina display _contentScaleFactor: null, - _cacheCanvas:null, - _cacheContext:null, - _cacheTexture:null, - // Sub caches for avoid Chrome big image draw issue - _subCacheCanvas:null, - _subCacheContext:null, - _subCacheCount:0, - _subCacheWidth:0, - // Maximum pixel number by cache, a little more than 3072*3072, real limit is 4096*4096 - _maxCachePixel:10000000, _className:"TMXLayer", /** - * Creates a cc.TMXLayer with an tile set info, a layer info and a map info - * @constructor + * Creates a cc.TMXLayer with an tile set info, a layer info and a map info
    + * Constructor of cc.TMXLayer * @param {cc.TMXTilesetInfo} tilesetInfo * @param {cc.TMXLayerInfo} layerInfo * @param {cc.TMXMapInfo} mapInfo @@ -105,26 +94,17 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ this._layerSize = cc.size(0, 0); this._mapTileSize = cc.size(0, 0); - if(cc._renderType === cc._RENDER_TYPE_CANVAS){ - var locCanvas = cc._canvas; - var tmpCanvas = cc.newElement('canvas'); - tmpCanvas.width = locCanvas.width; - tmpCanvas.height = locCanvas.height; - this._cacheCanvas = tmpCanvas; - this._cacheContext = this._cacheCanvas.getContext('2d'); - var tempTexture = new cc.Texture2D(); - tempTexture.initWithElement(tmpCanvas); - tempTexture.handleLoadedTexture(); - this._cacheTexture = tempTexture; - this.width = locCanvas.width; - this.height = locCanvas.height; - // This class uses cache, so its default cachedParent should be himself - this._cachedParent = this; - } if(mapInfo !== undefined) this.initWithTilesetInfo(tilesetInfo, layerInfo, mapInfo); }, + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.TMXLayer.CanvasRenderCmd(this); + else + return new cc.TMXLayer.WebGLRenderCmd(this); + }, + /** * Sets the untransformed size of the TMXLayer. * @override @@ -132,142 +112,21 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ * @param {Number} [height] The untransformed size's height of the TMXLayer. */ setContentSize:function (size, height) { - var locContentSize = this._contentSize; cc.Node.prototype.setContentSize.call(this, size, height); - - if(cc._renderType === cc._RENDER_TYPE_CANVAS){ - var locCanvas = this._cacheCanvas; - var scaleFactor = cc.contentScaleFactor(); - locCanvas.width = 0 | (locContentSize.width * 1.5 * scaleFactor); - locCanvas.height = 0 | (locContentSize.height * 1.5 * scaleFactor); - - this._cacheContext.translate(0, locCanvas.height); - var locTexContentSize = this._cacheTexture._contentSize; - locTexContentSize.width = locCanvas.width; - locTexContentSize.height = locCanvas.height; - - // Init sub caches if needed - var totalPixel = locCanvas.width * locCanvas.height; - if(totalPixel > this._maxCachePixel) { - if(!this._subCacheCanvas) this._subCacheCanvas = []; - if(!this._subCacheContext) this._subCacheContext = []; - - this._subCacheCount = Math.ceil( totalPixel / this._maxCachePixel ); - var locSubCacheCanvas = this._subCacheCanvas, i; - for(i = 0; i < this._subCacheCount; i++) { - if(!locSubCacheCanvas[i]) { - locSubCacheCanvas[i] = document.createElement('canvas'); - this._subCacheContext[i] = locSubCacheCanvas[i].getContext('2d'); - } - var tmpCanvas = locSubCacheCanvas[i]; - tmpCanvas.width = this._subCacheWidth = Math.round( locCanvas.width / this._subCacheCount ); - tmpCanvas.height = locCanvas.height; - } - // Clear wasted cache to release memory - for(i = this._subCacheCount; i < locSubCacheCanvas.length; i++) { - tmpCanvas.width = 0; - tmpCanvas.height = 0; - } - } - // Otherwise use count as a flag to disable sub caches - else this._subCacheCount = 0; - } + this._renderCmd._updateCacheContext(size, height); }, - /** * Return texture of cc.SpriteBatchNode + * @function * @return {cc.Texture2D} */ - getTexture: null, - - _getTextureForCanvas:function () { - return this._cacheTexture; - }, - - /** - * don't call visit on it's children ( override visit of cc.Node ) - * @override - * @param {CanvasRenderingContext2D} ctx - */ - visit: null, - - _visitForCanvas: function (ctx) { - var context = ctx || cc._renderContext; - // quick return if not visible - if (!this._visible) - return; - - context.save(); - this.transform(ctx); - var i, locChildren = this._children; - - if (this._cacheDirty) { - // - var eglViewer = cc.view; - eglViewer._setScaleXYForRenderTexture(); - //add dirty region - var locCacheContext = this._cacheContext, locCacheCanvas = this._cacheCanvas; - locCacheContext.clearRect(0, 0, locCacheCanvas.width, -locCacheCanvas.height); - locCacheContext.save(); - locCacheContext.translate(this._anchorPointInPoints.x, -(this._anchorPointInPoints.y)); - if (locChildren) { - this.sortAllChildren(); - for (i = 0; i < locChildren.length; i++) { - if (locChildren[i]) - locChildren[i].visit(locCacheContext); - } - } - locCacheContext.restore(); - // Update sub caches if needed - if(this._subCacheCount > 0) { - var subCacheW = this._subCacheWidth, subCacheH = locCacheCanvas.height; - for(i = 0; i < this._subCacheCount; i++) { - this._subCacheContext[i].drawImage(locCacheCanvas, i * subCacheW, 0, subCacheW, subCacheH, 0, 0, subCacheW, subCacheH); - } - } - - //reset Scale - eglViewer._resetScale(); - this._cacheDirty = false; - } - // draw RenderTexture - this.draw(ctx); - context.restore(); - }, - - /** - * draw cc.SpriteBatchNode (override draw of cc.Node) - * @param {CanvasRenderingContext2D} ctx - */ - draw:null, - - _drawForCanvas:function (ctx) { - var context = ctx || cc._renderContext; - //context.globalAlpha = this._opacity / 255; - var posX = 0 | ( -this._anchorPointInPoints.x), posY = 0 | ( -this._anchorPointInPoints.y); - var eglViewer = cc.view; - var locCacheCanvas = this._cacheCanvas; - //direct draw image by canvas drawImage - if (locCacheCanvas) { - var locSubCacheCount = this._subCacheCount, locCanvasHeight = locCacheCanvas.height * eglViewer._scaleY; - if(locSubCacheCount > 0) { - var locSubCacheCanvasArr = this._subCacheCanvas; - for(var i = 0; i < locSubCacheCount; i++){ - var selSubCanvas = locSubCacheCanvasArr[i]; - context.drawImage(locSubCacheCanvasArr[i], 0, 0, selSubCanvas.width, selSubCanvas.height, - posX + i * this._subCacheWidth, -(posY + locCanvasHeight), selSubCanvas.width * eglViewer._scaleX, locCanvasHeight); - } - } else{ - //context.drawImage(locCacheCanvas, 0, 0, locCacheCanvas.width, locCacheCanvas.height, - // posX, -(posY + locCacheCanvas.height ), locCacheCanvas.width, locCacheCanvas.height ); - context.drawImage(locCacheCanvas, 0, 0, locCacheCanvas.width, locCacheCanvas.height, - posX, -(posY + locCanvasHeight), locCacheCanvas.width * eglViewer._scaleX, locCanvasHeight); - } - } + getTexture: function(){ + return this._renderCmd.getTexture(); }, /** + * Gets layer size. * @return {cc.Size} */ getLayerSize:function () { @@ -275,6 +134,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Set layer size * @param {cc.Size} Var */ setLayerSize:function (Var) { @@ -304,6 +164,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Set the map tile size. * @param {cc.Size} Var */ setMapTileSize:function (Var) { @@ -333,6 +194,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Pointer to the map of tiles * @param {Array} Var */ setTiles:function (Var) { @@ -348,6 +210,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Tile set information for the layer * @param {cc.TMXTilesetInfo} Var */ setTileset:function (Var) { @@ -363,6 +226,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Layer orientation, which is the same as the map orientation * @param {Number} Var */ setLayerOrientation:function (Var) { @@ -378,6 +242,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * properties from the layer. They can be added using Tiled * @param {Array} Var */ setProperties:function (Var) { @@ -452,12 +317,15 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ * You can remove either by calling:
    * - layer.removeChild(sprite, cleanup);
    * - or layer.removeTileAt(ccp(x,y));

    - * @param {cc.Point} pos + * @param {cc.Point|Number} pos or x + * @param {Number} [y] * @return {cc.Sprite} */ - getTileAt: function (pos) { + getTileAt: function (pos, y) { if(!pos) throw "cc.TMXLayer.getTileAt(): pos should be non-null"; + if(y !== undefined) + pos = cc.p(pos, y); if(pos.x >= this._layerSize.width || pos.y >= this._layerSize.height || pos.x < 0 || pos.y < 0) throw "cc.TMXLayer.getTileAt(): invalid position"; if(!this.tiles || !this._atlasIndexArray){ @@ -465,8 +333,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ return null; } - var tile = null; - var gid = this.getTileGIDAt(pos); + var tile = null, gid = this.getTileGIDAt(pos); // if GID == 0, then no tile is present if (gid === 0) @@ -498,12 +365,15 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ * Returns the tile gid at a given tile coordinate.
    * if it returns 0, it means that the tile is empty.
    * This method requires the the tile map has not been previously released (eg. don't call layer.releaseMap())
    - * @param {cc.Point} pos + * @param {cc.Point|Number} pos or x + * @param {Number} [y] * @return {Number} */ - getTileGIDAt:function (pos) { - if(!pos) + getTileGIDAt:function (pos, y) { + if(pos == null) throw "cc.TMXLayer.getTileGIDAt(): pos should be non-null"; + if(y !== undefined) + pos = cc.p(pos, y); if(pos.x >= this._layerSize.width || pos.y >= this._layerSize.height || pos.x < 0 || pos.y < 0) throw "cc.TMXLayer.getTileGIDAt(): invalid position"; if(!this.tiles || !this._atlasIndexArray){ @@ -522,12 +392,15 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ /** * lipped tiles can be changed dynamically - * @param {cc.Point} pos + * @param {cc.Point|Number} pos or x + * @param {Number} [y] * @return {Number} */ - getTileFlagsAt:function (pos) { + getTileFlagsAt:function (pos, y) { if(!pos) throw "cc.TMXLayer.getTileFlagsAt(): pos should be non-null"; + if(y !== undefined) + pos = cc.p(pos, y); if(pos.x >= this._layerSize.width || pos.y >= this._layerSize.height || pos.x < 0 || pos.y < 0) throw "cc.TMXLayer.getTileFlagsAt(): invalid position"; if(!this.tiles || !this._atlasIndexArray){ @@ -549,30 +422,37 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ * The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor . Tileset Mgr +1.
    * If a tile is already placed at that position, then it will be removed.

    * @param {Number} gid - * @param {cc.Point} pos - * @param {Number} flags + * @param {cc.Point|Number} posOrX position or x + * @param {Number} flagsOrY flags or y + * @param {Number} [flags] */ - setTileGID:function (gid, pos, flags) { - if(!pos) + setTileGID: function(gid, posOrX, flagsOrY, flags) { + if(!posOrX) throw "cc.TMXLayer.setTileGID(): pos should be non-null"; + var pos; + if (flags !== undefined) { + pos = cc.p(posOrX, flagsOrY); + } else { + pos = posOrX; + flags = flagsOrY; + } if(pos.x >= this._layerSize.width || pos.y >= this._layerSize.height || pos.x < 0 || pos.y < 0) throw "cc.TMXLayer.setTileGID(): invalid position"; if(!this.tiles || !this._atlasIndexArray){ cc.log("cc.TMXLayer.setTileGID(): TMXLayer: the tiles map has been released"); - return null; + return; } if(gid !== 0 && gid < this.tileset.firstGid){ cc.log( "cc.TMXLayer.setTileGID(): invalid gid:" + gid); - return null; + return; } flags = flags || 0; this._setNodeDirtyForCache(); - var currentFlags = this.getTileFlagsAt(pos); var currentGID = this.getTileGIDAt(pos); - if (currentGID != gid || currentFlags != flags) { + if (currentGID !== gid || currentFlags !== flags) { var gidAndFlags = (gid | flags) >>> 0; // setting gid=0 is equal to remove the tile if (gid === 0) @@ -599,16 +479,19 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ /** * Removes a tile at given tile coordinate - * @param {cc.Point} pos + * @param {cc.Point|Number} pos position or x + * @param {Number} [y] */ - removeTileAt:function (pos) { + removeTileAt:function (pos, y) { if(!pos) throw "cc.TMXLayer.removeTileAt(): pos should be non-null"; + if(y !== undefined) + pos = cc.p(pos, y); if(pos.x >= this._layerSize.width || pos.y >= this._layerSize.height || pos.x < 0 || pos.y < 0) throw "cc.TMXLayer.removeTileAt(): invalid position"; if(!this.tiles || !this._atlasIndexArray){ cc.log("cc.TMXLayer.removeTileAt(): TMXLayer: the tiles map has been released"); - return null; + return; } var gid = this.getTileGIDAt(pos); @@ -650,10 +533,13 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ /** * Returns the position in pixels of a given tile coordinate - * @param {cc.Point} pos + * @param {cc.Point|Number} pos position or x + * @param {Number} [y] * @return {cc.Point} */ - getPositionAt:function (pos) { + getPositionAt:function (pos, y) { + if (y !== undefined) + pos = cc.p(pos, y); var ret = cc.p(0,0); switch (this.layerOrientation) { case cc.TMX_ORIENTATION_ORTHO: @@ -685,18 +571,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ */ setupTiles:function () { // Optimization: quick hack that sets the image size on the tileset - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - this.tileset.imageSize = this._originalTexture.getContentSizeInPixels(); - } else { - this.tileset.imageSize = this.textureAtlas.texture.getContentSizeInPixels(); - - // By default all the tiles are aliased - // pros: - // - easier to render - // cons: - // - difficult to scale / rotate / etc. - this.textureAtlas.texture.setAliasTexParameters(); - } + this._renderCmd.initImageSize(); // Parse cocos2d properties this._parseInternalProperties(); @@ -757,9 +632,11 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ this.tiles[zz] = 0; this._atlasIndexArray.splice(atlasIndex, 1); cc.SpriteBatchNode.prototype.removeChild.call(this, sprite, cleanup); + cc.renderer.childrenOrderDirty = true; }, /** + * Gets the layer name * @return {String} */ getLayerName:function () { @@ -767,6 +644,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, /** + * Set the layer name * @param {String} layerName */ setLayerName:function (layerName) { @@ -784,7 +662,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ }, _positionForHexAt:function (pos) { - var diffY = (pos.x % 2 == 1) ? (-this._mapTileSize.height / 2) : 0; + var diffY = (pos.x % 2 === 1) ? (-this._mapTileSize.height / 2) : 0; return cc.p(pos.x * this._mapTileSize.width * 3 / 4, (this._layerSize.height - pos.y - 1) * this._mapTileSize.height + diffY); }, @@ -812,7 +690,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ rect = cc.rectPixelsToPoints(rect); var z = 0 | (pos.x + pos.y * this._layerSize.width); - var tile = this._reusedTileWithRect(rect); + var tile = this._renderCmd._reusedTileWithRect(rect); this._setupTileSprite(tile, pos, gid); // optimization: @@ -833,7 +711,7 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ rect = cc.rectPixelsToPoints(rect); var z = 0 | (pos.x + pos.y * this._layerSize.width); - var tile = this._reusedTileWithRect(rect); + var tile = this._renderCmd._reusedTileWithRect(rect); this._setupTileSprite(tile, pos, gid); // get atlas index @@ -867,12 +745,11 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ rect.width / locScaleFactor, rect.height / locScaleFactor); var z = pos.x + pos.y * this._layerSize.width; - var tile = this._reusedTileWithRect(rect); + var tile = this._renderCmd._reusedTileWithRect(rect); this._setupTileSprite(tile, pos, gid); // get atlas index - var indexForZ = this._atlasIndexForExistantZ(z); - tile.atlasIndex = indexForZ; + tile.atlasIndex = this._atlasIndexForExistantZ(z); tile.dirty = true; tile.updateTransform(); this.tiles[z] = gid; @@ -885,14 +762,14 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ // if cc_vertex=automatic, then tiles will be rendered using vertexz var vertexz = this.getProperty("cc_vertexz"); if (vertexz) { - if (vertexz == "automatic") { + if (vertexz === "automatic") { this._useAutomaticVertexZ = true; var alphaFuncVal = this.getProperty("cc_alpha_func"); var alphaFuncValue = 0; if (alphaFuncVal) alphaFuncValue = parseFloat(alphaFuncVal); - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { //todo: need move to WebGL render cmd this.shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLORALPHATEST); var alphaValueLocation = cc._renderContext.getUniformLocation(this.shaderProgram.getProgram(), cc.UNIFORM_ALPHA_TEST_VALUE_S); // NOTE: alpha test shader is hard-coded to use the equivalent of a glAlphaFunc(GL_GREATER) comparison @@ -932,11 +809,11 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ var flag = (gid & (cc.TMX_TILE_HORIZONTAL_FLAG | cc.TMX_TILE_VERTICAL_FLAG) >>> 0) >>> 0; // handle the 4 diagonally flipped states. - if (flag == cc.TMX_TILE_HORIZONTAL_FLAG) + if (flag === cc.TMX_TILE_HORIZONTAL_FLAG) sprite.rotation = 90; - else if (flag == cc.TMX_TILE_VERTICAL_FLAG) + else if (flag === cc.TMX_TILE_VERTICAL_FLAG) sprite.rotation = 270; - else if (flag == (cc.TMX_TILE_VERTICAL_FLAG | cc.TMX_TILE_HORIZONTAL_FLAG) >>> 0) { + else if (flag === (cc.TMX_TILE_VERTICAL_FLAG | cc.TMX_TILE_HORIZONTAL_FLAG) >>> 0) { sprite.rotation = 90; sprite.setFlippedX(true); } else { @@ -954,32 +831,6 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ } }, - _reusedTileWithRect:function (rect) { - if(cc._renderType === cc._RENDER_TYPE_WEBGL){ - if (!this._reusedTile) { - this._reusedTile = new cc.Sprite(); - this._reusedTile.initWithTexture(this.texture, rect, false); - this._reusedTile.batchNode = this; - } else { - // XXX HACK: Needed because if "batch node" is nil, - // then the Sprite'squad will be reset - this._reusedTile.batchNode = null; - - // Re-init the sprite - this._reusedTile.setTextureRect(rect, false); - - // restore the batch node - this._reusedTile.batchNode = this; - } - } else { - this._reusedTile = new cc.Sprite(); - this._reusedTile.initWithTexture(this._textureForCanvas, rect, false); - this._reusedTile.batchNode = this; - this._reusedTile.parent = this; - } - return this._reusedTile; - }, - _vertexZForPos:function (pos) { var ret = 0; var maxVal = 0; @@ -1010,11 +861,11 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ var locAtlasIndexArray = this._atlasIndexArray; for (var i = 0, len = locAtlasIndexArray.length; i < len; i++) { item = locAtlasIndexArray[i]; - if (item == z) + if (item === z) break; } } - if(typeof item != "number") + if(!cc.isNumber(item)) cc.log("cc.TMXLayer._atlasIndexForExistantZ(): TMX atlas index not found. Shall not happen"); return i; }, @@ -1032,16 +883,6 @@ cc.TMXLayer = cc.SpriteBatchNode.extend(/** @lends cc.TMXLayer# */{ var _p = cc.TMXLayer.prototype; -if(cc._renderType == cc._RENDER_TYPE_WEBGL){ - _p.draw = cc.SpriteBatchNode.prototype.draw; - _p.visit = cc.SpriteBatchNode.prototype.visit; - _p.getTexture = cc.SpriteBatchNode.prototype.getTexture; -}else{ - _p.draw = _p._drawForCanvas; - _p.visit = _p._visitForCanvas; - _p.getTexture = _p._getTextureForCanvas; -} - /** @expose */ cc.defineGetterSetter(_p, "texture", _p.getTexture, _p.setTexture); @@ -1062,6 +903,7 @@ cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); /** * Creates a cc.TMXLayer with an tile set info, a layer info and a map info + * @deprecated since v3.0 please use new cc.TMXLayer(tilesetInfo, layerInfo, mapInfo) instead. * @param {cc.TMXTilesetInfo} tilesetInfo * @param {cc.TMXLayerInfo} layerInfo * @param {cc.TMXMapInfo} mapInfo diff --git a/cocos2d/tilemap/CCTMXLayerCanvasRenderCmd.js b/cocos2d/tilemap/CCTMXLayerCanvasRenderCmd.js new file mode 100644 index 0000000000..6589bb2643 --- /dev/null +++ b/cocos2d/tilemap/CCTMXLayerCanvasRenderCmd.js @@ -0,0 +1,220 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.TMXLayer.CanvasRenderCmd = function(renderable){ + cc.SpriteBatchNode.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + this._realWorldTransform = {a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0}; + + var locCanvas = cc._canvas; + var tmpCanvas = cc.newElement('canvas'); + tmpCanvas.width = locCanvas.width; + tmpCanvas.height = locCanvas.height; + this._cacheCanvas = tmpCanvas; + this._cacheContext = new cc.CanvasContextWrapper(this._cacheCanvas.getContext('2d')); + var tempTexture = new cc.Texture2D(); + tempTexture.initWithElement(tmpCanvas); + tempTexture.handleLoadedTexture(); + this._cacheTexture = tempTexture; + // This class uses cache, so its default cachedParent should be himself + this._cacheDirty = false; + }; + + var proto = cc.TMXLayer.CanvasRenderCmd.prototype = Object.create(cc.SpriteBatchNode.CanvasRenderCmd.prototype); + proto.constructor = cc.TMXLayer.CanvasRenderCmd; + + //set the cache dirty flag for canvas + proto._setNodeDirtyForCache = function () { + this._cacheDirty = true; + }; + + proto._renderingChildToCache = function () { + if (this._cacheDirty) { + var wrapper = this._cacheContext, + context = wrapper.getContext(), locCanvas = this._cacheCanvas; + + //wrapper.save(); + context.setTransform(1, 0, 0, 1, 0, 0); + context.clearRect(0, 0, locCanvas.width, locCanvas.height); + //reset the cache context + + var locChildren = this._node._children; + for (var i = 0, len = locChildren.length; i < len; i++) { + if (locChildren[i]){ + var selCmd = locChildren[i]._renderCmd; + if(selCmd){ + selCmd.rendering(wrapper, 1, 1); + selCmd._cacheDirty = false; + } + } + } + + //wrapper.restore(); + this._cacheDirty = false; + } + }; + + proto.rendering = function (ctx, scaleX, scaleY) { + var alpha = this._displayedOpacity / 255; + if (alpha <= 0) + return; + + var node = this._node; + this._renderingChildToCache(); + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + wrapper.setGlobalAlpha(alpha); + + var locCacheCanvas = this._cacheCanvas; + //direct draw image by canvas drawImage + if (locCacheCanvas && locCacheCanvas.width !== 0 && locCacheCanvas.height !== 0) { + wrapper.setTransform(this._realWorldTransform, scaleX, scaleY); + var locCanvasHeight = locCacheCanvas.height * scaleY; + if (node.layerOrientation === cc.TMX_ORIENTATION_HEX) { + var halfTileSize = node._mapTileSize.height * 0.5 * scaleY; + context.drawImage(locCacheCanvas, 0, 0, locCacheCanvas.width, locCacheCanvas.height, + 0, -locCanvasHeight + halfTileSize, locCacheCanvas.width * scaleX, locCanvasHeight); + } else { + context.drawImage(locCacheCanvas, 0, 0, locCacheCanvas.width, locCacheCanvas.height, + 0, -locCanvasHeight, locCacheCanvas.width * scaleX, locCanvasHeight); + } + } + cc.g_NumberOfDraws++; + }; + + proto._updateCacheContext = function(size, height){ + var node = this._node, + locContentSize = node._contentSize, + locCanvas = this._cacheCanvas, + scaleFactor = cc.contentScaleFactor(); + locCanvas.width = 0 | (locContentSize.width * 1.5 * scaleFactor); + locCanvas.height = 0 | (locContentSize.height * 1.5 * scaleFactor); + + //todo: need change the wrapper's height + if(node.layerOrientation === cc.TMX_ORIENTATION_HEX) + this._cacheContext.setOffset(0, -node._mapTileSize.height * 0.5); //translate for hexagonal + else + this._cacheContext.setOffset(0, 0); + var locTexContentSize = this._cacheTexture._contentSize; + locTexContentSize.width = locCanvas.width; + locTexContentSize.height = locCanvas.height; + }; + + proto.getTexture = function(){ + return this._cacheTexture; + }; + + proto.visit = function(parentCmd){ + var node = this._node; + //TODO: it will implement dynamic compute child cutting automation. + var i, len, locChildren = node._children; + // quick return if not visible + if (!node._visible || !locChildren || locChildren.length === 0) + return; + + parentCmd = parentCmd || this.getParentRenderCmd(); + if (parentCmd) + this._curLevel = parentCmd._curLevel + 1; + + this._syncStatus(parentCmd); + if (this._cacheDirty) { + var wrapper = this._cacheContext, locCanvas = this._cacheCanvas, context = wrapper.getContext(), + instanceID = node.__instanceId, renderer = cc.renderer; + //begin cache + renderer._turnToCacheMode(instanceID); + + node.sortAllChildren(); + for (i = 0, len = locChildren.length; i < len; i++) { + if (locChildren[i]){ + var selCmd = locChildren[i]._renderCmd; + if(selCmd){ + selCmd.visit(this); + selCmd._cacheDirty = false; + } + } + } + + //wrapper.save(); + context.setTransform(1, 0, 0, 1, 0, 0); + context.clearRect(0, 0, locCanvas.width, locCanvas.height); + //set the wrapper's offset + + //draw to cache canvas + renderer._renderingToCacheCanvas(wrapper, instanceID); + //wrapper.restore(); //todo: it can be reserve. + this._cacheDirty = false + } + cc.renderer.pushRenderCommand(this); + this._dirtyFlag = 0; + }; + + proto.transform = function (parentCmd, recursive) { + // transform for canvas + var t = this.getNodeToParentTransform(), + worldT = this._realWorldTransform; //get the world transform + + if (parentCmd) { + var pt = parentCmd._worldTransform; + // cc.AffineTransformConcat is incorrect at get world transform + worldT.a = t.a * pt.a + t.b * pt.c; //a + worldT.b = t.a * pt.b + t.b * pt.d; //b + worldT.c = t.c * pt.a + t.d * pt.c; //c + worldT.d = t.c * pt.b + t.d * pt.d; //d + + worldT.tx = pt.a * t.tx + pt.c * t.ty + pt.tx; + worldT.ty = pt.d * t.ty + pt.ty + pt.b * t.tx; + } else { + worldT.a = t.a; + worldT.b = t.b; + worldT.c = t.c; + worldT.d = t.d; + worldT.tx = t.tx; + worldT.ty = t.ty; + } + if (recursive) { + var locChildren = this._node._children; + if (!locChildren || locChildren.length === 0) + return; + var i, len; + for (i = 0, len = locChildren.length; i < len; i++) { + locChildren[i]._renderCmd.transform(this, recursive); + } + } + }; + + proto.initImageSize = function(){ + var node = this._node; + node.tileset.imageSize = this._originalTexture.getContentSizeInPixels(); + }; + + proto._reusedTileWithRect = function(rect){ + var node = this._node; + node._reusedTile = new cc.Sprite(); + node._reusedTile.initWithTexture(node._renderCmd._texture, rect, false); + node._reusedTile.batchNode = node; + node._reusedTile.parent = node; + node._reusedTile._renderCmd._cachedParent = node._renderCmd; + return node._reusedTile; + }; +})(); \ No newline at end of file diff --git a/cocos2d/tilemap/CCTMXLayerWebGLRenderCmd.js b/cocos2d/tilemap/CCTMXLayerWebGLRenderCmd.js new file mode 100644 index 0000000000..8c1906f640 --- /dev/null +++ b/cocos2d/tilemap/CCTMXLayerWebGLRenderCmd.js @@ -0,0 +1,67 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.TMXLayer.WebGLRenderCmd = function(renderableObject){ + cc.SpriteBatchNode.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = cc.TMXLayer.WebGLRenderCmd.prototype = Object.create(cc.SpriteBatchNode.WebGLRenderCmd.prototype); + proto.constructor = cc.TMXLayer.WebGLRenderCmd; + + proto._updateCacheContext = function(){}; + + proto.initImageSize = function(){ + var node = this._node; + node.tileset.imageSize = this._textureAtlas.texture.getContentSizeInPixels(); + + // By default all the tiles are aliased + // pros: + // - easier to render + // cons: + // - difficult to scale / rotate / etc. + this._textureAtlas.texture.setAliasTexParameters(); + }; + + proto._reusedTileWithRect = function(rect){ + var node = this._node; + if (!node._reusedTile) { + node._reusedTile = new cc.Sprite(); + node._reusedTile.initWithTexture(node.texture, rect, false); + node._reusedTile.batchNode = node; + } else { + // XXX HACK: Needed because if "batch node" is nil, + // then the Sprite'squad will be reset + node._reusedTile.batchNode = null; + + // Re-init the sprite + node._reusedTile.setTextureRect(rect, false); + + // restore the batch node + node._reusedTile.batchNode = node; + } + return node._reusedTile; + }; +})(); diff --git a/cocos2d/tilemap/CCTMXObjectGroup.js b/cocos2d/tilemap/CCTMXObjectGroup.js index 47233e51e1..560c690afe 100644 --- a/cocos2d/tilemap/CCTMXObjectGroup.js +++ b/cocos2d/tilemap/CCTMXObjectGroup.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -39,6 +39,11 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ _positionOffset: null, _objects: null, + /** + *

    The cc.TMXObjectGroup's constructor.
    + * This function will automatically be invoked when you create a node using new construction: "var node = new cc.TMXObjectGroup()".
    + * Override it to extend its behavior, remember to call "this._super()" in the extended "ctor" function.

    + */ ctor:function () { this.groupName = ""; this._positionOffset = cc.p(0,0); @@ -51,10 +56,11 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ * @return {cc.Point} */ getPositionOffset:function () { - return this._positionOffset; + return cc.p(this._positionOffset); }, /** + * Offset position of child objects * @param {cc.Point} offset */ setPositionOffset:function (offset) { @@ -71,6 +77,7 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ }, /** + * List of properties stored in a dictionary * @param {object} Var */ setProperties:function (Var) { @@ -78,6 +85,7 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ }, /** + * Gets the Group name. * @return {String} */ getGroupName:function () { @@ -85,6 +93,7 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ }, /** + * Set the Group name * @param {String} groupName */ setGroupName:function (groupName) { @@ -103,15 +112,26 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ /** *

    Return the dictionary for the specific object name.
    * It will return the 1st object found on the array for the given name.

    + * @deprecated since v3.4 please use .getObject * @param {String} objectName * @return {object|Null} */ objectNamed:function (objectName) { + this.getObject(objectName); + }, + + /** + *

    Return the dictionary for the specific object name.
    + * It will return the 1st object found on the array for the given name.

    + * @param {String} objectName + * @return {object|Null} + */ + getObject: function(objectName){ if (this._objects && this._objects.length > 0) { var locObjects = this._objects; for (var i = 0, len = locObjects.length; i < len; i++) { var name = locObjects[i]["name"]; - if (name && name == objectName) + if (name && name === objectName) return locObjects[i]; } } @@ -120,6 +140,7 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ }, /** + * Gets the objects. * @return {Array} */ getObjects:function () { @@ -127,6 +148,7 @@ cc.TMXObjectGroup = cc.Class.extend(/** @lends cc.TMXObjectGroup# */{ }, /** + * Set the objects. * @param {object} objects */ setObjects:function (objects) { diff --git a/cocos2d/tilemap/CCTMXTiledMap.js b/cocos2d/tilemap/CCTMXTiledMap.js index b76ce052c9..97165dd3b2 100644 --- a/cocos2d/tilemap/CCTMXTiledMap.js +++ b/cocos2d/tilemap/CCTMXTiledMap.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -97,6 +97,9 @@ cc.TMX_ORIENTATION_ISO = 2; * object.getProperty(name_of_the_property);

    * @class * @extends cc.Node + * @param {String} tmxFile tmxFile fileName or content string + * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. + * * @property {Array} properties - Properties from the map. They can be added using tilemap editors * @property {Number} mapOrientation - Map orientation @@ -105,8 +108,20 @@ cc.TMX_ORIENTATION_ISO = 2; * @property {Number} mapHeight - Height of the map * @property {Number} tileWidth - Width of a tile * @property {Number} tileHeight - Height of a tile + * + * @example + * //example + * 1. + * //create a TMXTiledMap with file name + * var tmxTiledMap = new cc.TMXTiledMap("res/orthogonal-test1.tmx"); + * 2. + * //create a TMXTiledMap with content string and resource path + * var resources = "res/TileMaps"; + * var filePath = "res/TileMaps/orthogonal-test1.tmx"; + * var xmlStr = cc.loader.getRes(filePath); + * var tmxTiledMap = new cc.TMXTiledMap(xmlStr, resources); */ -cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ +cc.TMXTiledMap = cc.Node.extend(/** @lends cc.TMXTiledMap# */{ properties: null, mapOrientation: null, objectGroups: null, @@ -119,22 +134,10 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ _className: "TMXTiledMap", /** - * Creates a TMX Tiled Map with a TMX file or content string. - * Implementation cc.TMXTiledMap - * @constructor + * Creates a TMX Tiled Map with a TMX file or content string.
    + * Constructor of cc.TMXTiledMap * @param {String} tmxFile tmxFile fileName or content string * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. - * @example - * //example - * 1. - * //create a TMXTiledMap with file name - * var tmxTiledMap = new cc.TMXTiledMap("res/orthogonal-test1.tmx"); - * 2. - * //create a TMXTiledMap with content string and resource path - * var resources = "res/TileMaps"; - * var filePath = "res/TileMaps/orthogonal-test1.tmx"; - * var xmlStr = cc.loader.getRes(filePath); - * var tmxTiledMap = new cc.TMXTiledMap(xmlStr, resources); */ ctor:function(tmxFile,resourcePath){ cc.Node.prototype.ctor.call(this); @@ -149,6 +152,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Gets the map size. * @return {cc.Size} */ getMapSize:function () { @@ -156,6 +160,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Set the map size. * @param {cc.Size} Var */ setMapSize:function (Var) { @@ -177,6 +182,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Gets the tile size. * @return {cc.Size} */ getTileSize:function () { @@ -184,6 +190,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Set the tile size * @param {cc.Size} Var */ setTileSize:function (Var) { @@ -213,6 +220,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * map orientation * @param {Number} Var */ setMapOrientation:function (Var) { @@ -228,6 +236,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * object groups * @param {Array} Var */ setObjectGroups:function (Var) { @@ -235,7 +244,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** - * properties + * Gets the properties * @return {object} */ getProperties:function () { @@ -243,6 +252,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Set the properties * @param {object} Var */ setProperties:function (Var) { @@ -250,19 +260,20 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ }, /** + * Initializes the instance of cc.TMXTiledMap with tmxFile * @param {String} tmxFile - * @return {Boolean} + * @return {Boolean} Whether the initialization was successful. * @example * //example * var map = new cc.TMXTiledMap() * map.initWithTMXFile("hello.tmx"); */ initWithTMXFile:function (tmxFile) { - if(!tmxFile || tmxFile.length == 0) + if(!tmxFile || tmxFile.length === 0) throw "cc.TMXTiledMap.initWithTMXFile(): tmxFile should be non-null or non-empty string."; this.width = 0; this.height = 0; - var mapInfo = cc.TMXMapInfo.create(tmxFile); + var mapInfo = new cc.TMXMapInfo(tmxFile); if (!mapInfo) return false; @@ -273,11 +284,17 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ return true; }, + /** + * Initializes the instance of cc.TMXTiledMap with tmxString + * @param {String} tmxString + * @param {String} resourcePath + * @return {Boolean} Whether the initialization was successful. + */ initWithXML:function(tmxString, resourcePath){ this.width = 0; this.height = 0; - var mapInfo = cc.TMXMapInfo.create(tmxString, resourcePath); + var mapInfo = new cc.TMXMapInfo(tmxString, resourcePath); var locTilesets = mapInfo.getTilesets(); if(!locTilesets || locTilesets.length === 0) cc.log("cc.TMXTiledMap.initWithXML(): Map not found. Please check the filename."); @@ -311,6 +328,10 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ } }, + /** + * Return All layers array. + * @returns {Array} + */ allLayers: function () { var retArr = [], locChildren = this._children; for(var i = 0, len = locChildren.length;i< len;i++){ @@ -332,7 +353,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ var locChildren = this._children; for (var i = 0; i < locChildren.length; i++) { var layer = locChildren[i]; - if (layer && layer.layerName == layerName) + if (layer && layer.layerName === layerName) return layer; } // layer not found @@ -350,7 +371,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ if (this.objectGroups) { for (var i = 0; i < this.objectGroups.length; i++) { var objectGroup = this.objectGroups[i]; - if (objectGroup && objectGroup.groupName == groupName) { + if (objectGroup && objectGroup.groupName === groupName) { return objectGroup; } } @@ -372,14 +393,25 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ * Return properties dictionary for tile GID * @param {Number} GID * @return {object} + * @deprecated */ propertiesForGID:function (GID) { + cc.log("propertiesForGID is deprecated. Please use getPropertiesForGID instead."); + return this.getPropertiesForGID[GID]; + }, + + /** + * Return properties dictionary for tile GID + * @param {Number} GID + * @return {object} + */ + getPropertiesForGID: function(GID) { return this._tileProperties[GID]; }, _parseLayer:function (layerInfo, mapInfo) { var tileset = this._tilesetForLayer(layerInfo, mapInfo); - var layer = cc.TMXLayer.create(tileset, layerInfo, mapInfo); + var layer = new cc.TMXLayer(tileset, layerInfo, mapInfo); // tell the layerinfo to release the ownership of the tiles map. layerInfo.ownTiles = false; layer.setupTiles(); @@ -397,7 +429,7 @@ cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ for (var x = 0; x < size.width; x++) { var pos = x + size.width * y; var gid = layerInfo._tiles[pos]; - if (gid != 0) { + if (gid !== 0) { // Optimization: quick return // if the layer is invalid (more than 1 tileset per layer) an cc.assert will be thrown later if (((gid & cc.TMX_TILE_FLIPPED_MASK)>>>0) >= tileset.firstGid) { @@ -437,20 +469,10 @@ cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); /** * Creates a TMX Tiled Map with a TMX file or content string. * Implementation cc.TMXTiledMap + * @deprecated since v3.0 please use new cc.TMXTiledMap(tmxFile,resourcePath) instead. * @param {String} tmxFile tmxFile fileName or content string * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. * @return {cc.TMXTiledMap|undefined} - * @example - * //example - * 1. - * //create a TMXTiledMap with file name - * var tmxTiledMap = cc.TMXTiledMap.create("res/orthogonal-test1.tmx"); - * 2. - * //create a TMXTiledMap with content string and resource path - * var resources = "res/TileMaps"; - * var filePath = "res/TileMaps/orthogonal-test1.tmx"; - * var xmlStr = cc.loader.getRes(filePath); - * var tmxTiledMap = cc.TMXTiledMap.create(xmlStr, resources); */ cc.TMXTiledMap.create = function (tmxFile,resourcePath) { return new cc.TMXTiledMap(tmxFile,resourcePath); diff --git a/cocos2d/tilemap/CCTMXXMLParser.js b/cocos2d/tilemap/CCTMXXMLParser.js index 984d63c562..63b295d0e7 100644 --- a/cocos2d/tilemap/CCTMXXMLParser.js +++ b/cocos2d/tilemap/CCTMXXMLParser.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,27 +24,6 @@ THE SOFTWARE. ****************************************************************************/ -/** - * @constant - * @type Number - */ -cc.TMX_LAYER_ATTRIB_NONE = 1 << 0; -/** - * @constant - * @type Number - */ -cc.TMX_LAYER_ATTRIB_BASE64 = 1 << 1; -/** - * @constant - * @type Number - */ -cc.TMX_LAYER_ATTRIB_GZIP = 1 << 2; -/** - * @constant - * @type Number - */ -cc.TMX_LAYER_ATTRIB_ZLIB = 1 << 3; - /** * @constant * @type Number @@ -154,6 +133,7 @@ cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{ }, /** + * Gets the Properties. * @return {Array} */ getProperties:function () { @@ -161,6 +141,7 @@ cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{ }, /** + * Set the Properties. * @param {object} value */ setProperties:function (value) { @@ -180,38 +161,33 @@ cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{ * This information is obtained from the TMX file.

    * @class * @extends cc.Class + * + * @property {string} name - Tileset name + * @property {number} firstGid - First grid + * @property {number} spacing - Spacing + * @property {number} margin - Margin + * @property {string} sourceImage - Filename containing the tiles (should be sprite sheet / texture atlas) + * @property {cc.Size|null} imageSize - Size in pixels of the image */ cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{ - /** - * Tileset name - */ + //Tileset name name:"", - /** - * First grid - */ + //First grid firstGid:0, _tileSize:null, - /** - * Spacing - */ + //Spacing spacing:0, - /** - * Margin - */ + //Margin margin:0, - /** - * Filename containing the tiles (should be sprite sheet / texture atlas) - */ + //Filename containing the tiles (should be sprite sheet / texture atlas) sourceImage:"", - /** - * Size in pixels of the image - */ + //Size in pixels of the image imageSize:null, ctor:function () { @@ -220,6 +196,7 @@ cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{ }, /** + * Return rect * @param {Number} gid * @return {cc.Rect} */ @@ -263,6 +240,19 @@ cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{ * @property {Number} mapHeight - Height of the map * @property {Number} tileWidth - Width of a tile * @property {Number} tileHeight - Height of a tile + * + * @param {String} tmxFile fileName or content string + * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. + * @example + * 1. + * //create a TMXMapInfo with file name + * var tmxMapInfo = new cc.TMXMapInfo("res/orthogonal-test1.tmx"); + * 2. + * //create a TMXMapInfo with content string and resource path + * var resources = "res/TileMaps"; + * var filePath = "res/TileMaps/orthogonal-test1.tmx"; + * var xmlStr = cc.loader.getRes(filePath); + * var tmxMapInfo = new cc.TMXMapInfo(xmlStr, resources); */ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ properties:null, @@ -285,20 +275,10 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ _currentFirstGID:0, /** - * Creates a TMX Format with a tmx file or content string - * @constructor + * Creates a TMX Format with a tmx file or content string
    + * Constructor of cc.TMXMapInfo * @param {String} tmxFile fileName or content string * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. - * @example - * 1. - * //create a TMXMapInfo with file name - * var tmxMapInfo = cc.TMXMapInfo.create("res/orthogonal-test1.tmx"); - * 2. - * //create a TMXMapInfo with content string and resource path - * var resources = "res/TileMaps"; - * var filePath = "res/TileMaps/orthogonal-test1.tmx"; - * var xmlStr = cc.loader.getRes(filePath); - * var tmxMapInfo = cc.TMXMapInfo.create(xmlStr, resources); */ ctor:function (tmxFile, resourcePath) { cc.SAXParser.prototype.ctor.apply(this); @@ -319,6 +299,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ } }, /** + * Gets Map orientation. * @return {Number} */ getOrientation:function () { @@ -326,6 +307,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Set the Map orientation. * @param {Number} value */ setOrientation:function (value) { @@ -341,6 +323,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Map width & height * @param {cc.Size} value */ setMapSize:function (value) { @@ -370,6 +353,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Tiles width & height * @param {cc.Size} value */ setTileSize:function (value) { @@ -399,6 +383,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Layers * @param {cc.TMXLayerInfo} value */ setLayers:function (value) { @@ -414,6 +399,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * tilesets * @param {cc.TMXTilesetInfo} value */ setTilesets:function (value) { @@ -429,6 +415,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * ObjectGroups * @param {cc.TMXObjectGroup} value */ setObjectGroups:function (value) { @@ -444,6 +431,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * parent element * @param {Object} value */ setParentElement:function (value) { @@ -459,6 +447,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * parent GID * @param {Number} value */ setParentGID:function (value) { @@ -474,6 +463,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Layer attribute * @param {Object} value */ setLayerAttribs:function (value) { @@ -489,6 +479,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Is reading storing characters stream * @param {Boolean} value */ setStoringCharacters:function (value) { @@ -504,6 +495,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Properties * @param {object} value */ setProperties:function (value) { @@ -550,15 +542,15 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ var version = map.getAttribute('version'); var orientationStr = map.getAttribute('orientation'); - if (map.nodeName == "map") { - if (version != "1.0" && version !== null) + if (map.nodeName === "map") { + if (version !== "1.0" && version !== null) cc.log("cocos2d: TMXFormat: Unsupported TMX version:" + version); - if (orientationStr == "orthogonal") + if (orientationStr === "orthogonal") this.orientation = cc.TMX_ORIENTATION_ORTHO; - else if (orientationStr == "isometric") + else if (orientationStr === "isometric") this.orientation = cc.TMX_ORIENTATION_ISO; - else if (orientationStr == "hexagonal") + else if (orientationStr === "hexagonal") this.orientation = cc.TMX_ORIENTATION_HEX; else if (orientationStr !== null) cc.log("cocos2d: TMXFomat: Unsupported orientation:" + orientationStr); @@ -630,24 +622,23 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ tileset.sourceImage = this._resources + (this._resources ? "/" : "") + imagename; } this.setTilesets(tileset); - } - } - // PARSE - var tiles = map.querySelectorAll('tile'); - if (tiles) { - for (i = 0; i < tiles.length; i++) { - var info = this._tilesets[0]; - var t = tiles[i]; - this.parentGID = parseInt(info.firstGid) + parseInt(t.getAttribute('id') || 0); - var tp = t.querySelectorAll("properties > property"); - if (tp) { - var dict = {}; - for (j = 0; j < tp.length; j++) { - var name = tp[j].getAttribute('name'); - dict[name] = tp[j].getAttribute('value'); + // PARSE + var tiles = selTileset.getElementsByTagName('tile'); + if (tiles) { + for (var tIdx = 0; tIdx < tiles.length; tIdx++) { + var t = tiles[tIdx]; + this.parentGID = parseInt(tileset.firstGid) + parseInt(t.getAttribute('id') || 0); + var tp = t.querySelectorAll("properties > property"); + if (tp) { + var dict = {}; + for (j = 0; j < tp.length; j++) { + var name = tp[j].getAttribute('name'); + dict[name] = tp[j].getAttribute('value'); + } + this._tileProperties[this.parentGID] = dict; + } } - this._tileProperties[this.parentGID] = dict; } } } @@ -702,7 +693,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ case null: case '': // Uncompressed - if (encoding == "base64") + if (encoding === "base64") layer._tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4); else if (encoding === "csv") { layer._tiles = []; @@ -718,7 +709,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ } break; default: - if(this.layerAttrs == cc.TMX_LAYER_ATTRIB_NONE) + if(this.layerAttrs === cc.TMXLayerInfo.ATTRIB_NONE) cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported"); break; } @@ -757,6 +748,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ } var objects = selGroup.querySelectorAll('object'); + var getContentScaleFactor = cc.director.getContentScaleFactor(); if (objects) { for (j = 0; j < objects.length; j++) { var selObj = objects[j]; @@ -770,14 +762,15 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ // Assign all the attributes as key/name pairs in the properties dictionary objectProp["type"] = selObj.getAttribute('type') || ""; - objectProp["x"] = parseInt(selObj.getAttribute('x') || 0) + objectGroup.getPositionOffset().x; - var y = parseInt(selObj.getAttribute('y') || 0) + objectGroup.getPositionOffset().y; - objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0; objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0; + objectProp["x"] = (((selObj.getAttribute('x') || 0) | 0) + objectGroup.getPositionOffset().x) / getContentScaleFactor; + var y = ((selObj.getAttribute('y') || 0) | 0) + objectGroup.getPositionOffset().y / getContentScaleFactor; // Correct y position. (Tiled uses Flipped, cocos2d uses Standard) - objectProp["y"] = parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"]; + objectProp["y"] = (parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"]) / cc.director.getContentScaleFactor(); + + objectProp["rotation"] = parseInt(selObj.getAttribute('rotation')) || 0; var docObjProps = selObj.querySelectorAll("properties > property"); if (docObjProps) { @@ -835,6 +828,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Gets the tile properties. * @return {object} */ getTileProperties:function () { @@ -842,6 +836,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Set the tile properties. * @param {object} tileProperties */ setTileProperties:function (tileProperties) { @@ -849,6 +844,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Gets the currentString * @return {String} */ getCurrentString:function () { @@ -856,6 +852,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Set the currentString * @param {String} currentString */ setCurrentString:function (currentString) { @@ -863,6 +860,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Gets the tmxFileName * @return {String} */ getTMXFileName:function () { @@ -870,6 +868,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ }, /** + * Set the tmxFileName * @param {String} fileName */ setTMXFileName:function (fileName) { @@ -891,7 +890,7 @@ cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ // tmp vars this.currentString = ""; this.storingCharacters = false; - this.layerAttrs = cc.TMX_LAYER_ATTRIB_NONE; + this.layerAttrs = cc.TMXLayerInfo.ATTRIB_NONE; this.parentElement = cc.TMX_PROPERTY_NONE; this._currentFirstGID = 0; } @@ -916,19 +915,10 @@ cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); /** * Creates a TMX Format with a tmx file or content string + * @deprecated since v3.0 please use new cc.TMXMapInfo(tmxFile, resourcePath) instead. * @param {String} tmxFile fileName or content string * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. * @return {cc.TMXMapInfo} - * @example - * 1. - * //create a TMXMapInfo with file name - * var tmxMapInfo = cc.TMXMapInfo.create("res/orthogonal-test1.tmx"); - * 2. - * //create a TMXMapInfo with content string and resource path - * var resources = "res/TileMaps"; - * var filePath = "res/TileMaps/orthogonal-test1.tmx"; - * var xmlStr = cc.loader.getRes(filePath); - * var tmxMapInfo = cc.TMXMapInfo.create(xmlStr, resources); */ cc.TMXMapInfo.create = function (tmxFile, resourcePath) { return new cc.TMXMapInfo(tmxFile, resourcePath); @@ -936,3 +926,25 @@ cc.TMXMapInfo.create = function (tmxFile, resourcePath) { cc.loader.register(["tmx", "tsx"], cc._txtLoader); + + +/** + * @constant + * @type Number + */ +cc.TMXLayerInfo.ATTRIB_NONE = 1 << 0; +/** + * @constant + * @type Number + */ +cc.TMXLayerInfo.ATTRIB_BASE64 = 1 << 1; +/** + * @constant + * @type Number + */ +cc.TMXLayerInfo.ATTRIB_GZIP = 1 << 2; +/** + * @constant + * @type Number + */ +cc.TMXLayerInfo.ATTRIB_ZLIB = 1 << 3; diff --git a/cocos2d/tilemap/CCTileMapAtlas.js b/cocos2d/tilemap/CCTileMapAtlas.js deleted file mode 100644 index 62b4689de2..0000000000 --- a/cocos2d/tilemap/CCTileMapAtlas.js +++ /dev/null @@ -1,305 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -/** - *

    cc.TileMapAtlas is a subclass of cc.AtlasNode.

    - * - *

    It knows how to render a map based of tiles.
    - * The tiles must be in a .PNG format while the map must be a .TGA file.

    - * - *

    For more information regarding the format, please see this post:
    - * http://www.cocos2d-iphone.org/archives/27

    - * - *

    All features from cc.AtlasNode are valid in cc.TileMapAtlas

    - * - *

    IMPORTANT:
    - * This class is deprecated. It is maintained for compatibility reasons only.
    - * You SHOULD not use this class.
    - * Instead, use the newer TMX file format: cc.TMXTiledMap

    - * @class - * @extends cc.AtlasNode - * - * @property {cc.ImageTGA} tgaInfo - TGA Info - */ -cc.TileMapAtlas = cc.AtlasNode.extend(/** @lends cc.TileMapAtlas# */{ - tgaInfo:null, - - indices:null, - //numbers of tiles to render - _itemsToRender:0, - //x,y to altas dictionary - _posToAtlasIndex:null, - _className:"TileMapAtlas", - - /** - *

    Creates a cc.TileMap with a tile file (atlas) with a map file and the width and height of each tile in points.
    - * The tile file will be loaded using the TextureMgr.

    - * @constructor - * @param {String} tile - * @param {String} mapFile - * @param {Number} tileWidth - * @param {Number} tileHeight - * @example - * //example - * var tmpAtlas = new cc.TileMapAtlas("hello.png", "hello.tga", 16, 16); - */ - ctor:function(tile, mapFile, tileWidth, tileHeight){ - cc.AtlasNode.prototype.ctor.call(this); - if(tileHeight !== undefined) - this.initWithTileFile(tile, mapFile, tileWidth, tileHeight); - }, - - /** - * @return {cc.ImageTGA} - */ - getTGAInfo:function () { - return this.tgaInfo; - }, - - /** - * @param {cc.ImageTGA} Var - */ - setTGAInfo:function (Var) { - this.tgaInfo = Var; - }, - - /** - * Initializes a cc.TileMap with a tile file (atlas) with a map file and the width and height of each tile in points.
    - * The file will be loaded using the TextureMgr. - * @param {String} tile - * @param {String} mapFile - * @param {Number} tileWidth - * @param {Number} tileHeight - * @return {Boolean} - * @example - * //example - * var tmpAtlas = new cc.TileMapAtlas(); - * tmpAtlas.initWithTileFile("hello.png", "hello.tga", 16, 16); - */ - initWithTileFile:function (tile, mapFile, tileWidth, tileHeight) { - this._calculateItemsToRender(); - if (cc.AtlasNode.prototype.initWithTileFile.call(this, tile, tileWidth, tileHeight, this._itemsToRender)) { - this._color = cc.color.WHITE; - this._posToAtlasIndex = {}; - this._updateAtlasValues(); - this.width = this.tgaInfo.width * this._itemWidth; - this.height = this.tgaInfo.height * this._itemHeight; - return true; - } - return false; - }, - - /** - *

    Returns a tile from position x,y.
    - * For the moment only channel R is used.

    - * @param {cc.Point} position - * @return {cc.Color} - */ - getTileAt:function (position) { - if(!this.tgaInfo){ - cc.log("cc.TileMapAtlas.getTileAt(): tgaInfo must not be null"); - return null; - } - if(position.x >= this.tgaInfo.width || position.y >= this.tgaInfo.height) - throw "cc.TileMapAtlas.getTileAt(): Invalid position"; - - var colorPos = 0|(position.x * 3 + position.y * this.tgaInfo.width * 3); - var locTGAImageData = this.tgaInfo.imageData; - return cc.color(locTGAImageData[colorPos], locTGAImageData[colorPos + 1], locTGAImageData[colorPos + 2]); - }, - - /** - * Sets a tile at position x,y. - * For the moment only channel R is used - * @param {cc.Color} tile - * @param {cc.Point} position - */ - setTile:function (tile, position) { - if(!this.tgaInfo){ - cc.log("cc.TileMapAtlas.setTile(): tgaInfo must not be null"); - return; - } - if(!this._posToAtlasIndex){ - cc.log("cc.TileMapAtlas.setTile(): posToAtlasIndex must not be null"); - return; - } - if(position.x >= this.tgaInfo.width || position.y >= this.tgaInfo.height) - throw "cc.TileMapAtlas.setTile(): Invalid position"; - if(!tile || tile.r == 0) - throw "cc.TileMapAtlas.setTile(): tile should be non-null and tile.r should be non-nil"; - - var colorPos = 0 | (position.x * 3 + position.y * this.tgaInfo.width * 3); - if (this.tgaInfo.imageData[colorPos] == 0) - cc.log("cocos2d: Value.r must be non 0."); - else { - this.tgaInfo.imageData[colorPos] = tile.r; - this.tgaInfo.imageData[colorPos + 1] = tile.g; - this.tgaInfo.imageData[colorPos + 2] = tile.b; - - var num = this._posToAtlasIndex[position.x + "_" + position.y]; - this._updateAtlasValueAt(position, tile, num); - } - }, - - /** - * Dealloc the map from memory - */ - releaseMap:function () { - if (this.tgaInfo) { - cc.tgaDestroy(this.tgaInfo); - } - this.tgaInfo = null; - }, - - _calculateItemsToRender:function () { - if(!this.tgaInfo){ - cc.log("cc.TileMapAtlas._calculateItemsToRender(): tgaInfo must not be null"); - return; - } - - this._itemsToRender = 0; - var locWidth = this.tgaInfo.width, locHeight = this.tgaInfo.height, locImageData = this.tgaInfo.imageData; - for (var x = 0; x < locWidth; x++) { - for (var y = 0; y < locHeight; y++) { - if (locImageData[x * 3 + y * locWidth * 3]) - ++this._itemsToRender; - } - } - }, - - /** - * @param {cc.Point|cc.GridSize} pos - * @param {cc.Color} value - * @param {Number} index - * @private - */ - _updateAtlasValueAt:function (pos, value, index) { - var locTextureAtlas = this.textureAtlas; - if(index < 0 && index >= locTextureAtlas.getCapacity()) - throw "cc.TileMapAtlas._updateAtlasValueAt(): Invalid index"; - var quad = locTextureAtlas.quads[index]; - - var x = pos.x; - var y = pos.y; - var row = (value.r % this._itemsPerRow); - var col = (value.r / this._itemsPerRow); - - var tex = locTextureAtlas.texture, textureWide = tex.pixelsWidth, textureHigh = tex.pixelsHeight; - - var locItemWidth = this._itemWidth; - var locItemHeight = this._itemHeight; - var itemWidthInPixels = locItemWidth * cc.contentScaleFactor(); - var itemHeightInPixels = locItemHeight * cc.contentScaleFactor(); - - var left, right, top, bottom; - if (cc.FIX_ARTIFACTS_BY_STRECHING_TEXEL) { - left = (2 * row * itemWidthInPixels + 1) / (2 * textureWide); - right = left + (itemWidthInPixels * 2 - 2) / (2 * textureWide); - top = (2 * col * itemHeightInPixels + 1) / (2 * textureHigh); - bottom = top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh); - } else { - left = (row * itemWidthInPixels) / textureWide; - right = left + itemWidthInPixels / textureWide; - top = (col * itemHeightInPixels) / textureHigh; - bottom = top + itemHeightInPixels / textureHigh; - } - - quad.tl.texCoords.u = left; - quad.tl.texCoords.v = top; - quad.tr.texCoords.u = right; - quad.tr.texCoords.v = top; - quad.bl.texCoords.u = left; - quad.bl.texCoords.v = bottom; - quad.br.texCoords.u = right; - quad.br.texCoords.v = bottom; - - quad.bl.vertices.x = (x * locItemWidth); - quad.bl.vertices.y = (y * locItemHeight); - quad.bl.vertices.z = 0.0; - quad.br.vertices.x = (x * locItemWidth + locItemWidth); - quad.br.vertices.y = (y * locItemHeight); - quad.br.vertices.z = 0.0; - quad.tl.vertices.x = (x * locItemWidth); - quad.tl.vertices.y = (y * locItemHeight + locItemHeight); - quad.tl.vertices.z = 0.0; - quad.tr.vertices.x = (x * locItemWidth + locItemWidth); - quad.tr.vertices.y = (y * locItemHeight + locItemHeight); - quad.tr.vertices.z = 0.0; - - var locColor = this._displayedColor; - var color = {r: locColor.r, g: locColor.g, b: locColor.b, a: this._displayedOpacity}; - quad.tr.colors = color; - quad.tl.colors = color; - quad.br.colors = color; - quad.bl.colors = color; - - locTextureAtlas.dirty = true; - var totalQuads = locTextureAtlas.totalQuads; - if (index + 1 > totalQuads) - locTextureAtlas.increaseTotalQuadsWith(index + 1 - totalQuads); - }, - - _updateAtlasValues:function () { - if(!this.tgaInfo){ - cc.log("cc.TileMapAtlas._updateAtlasValues(): tgaInfo must not be null"); - return; - } - - var total = 0; - var locTGAInfo = this.tgaInfo; - var locTGAInfoWidth = locTGAInfo.width, locTGAInfoHeight = locTGAInfo.height, locItemsToRender = this._itemsToRender; - for (var x = 0; x < locTGAInfoWidth; x++) { - for (var y = 0; y < locTGAInfoHeight; y++) { - if (total < locItemsToRender) { - var colorPos = x * 3 + y * locTGAInfoWidth * 3; - var value = cc.color(locTGAInfo.imageData[colorPos], locTGAInfo.imageData[colorPos + 1], locTGAInfo.imageData[colorPos + 2]); - if (value.r != 0) { - this._updateAtlasValueAt(cc.p(x, y), value, total); - this._posToAtlasIndex[x + "_" + y] = total; - total++; - } - } - } - } - } -}); - -/** - *

    Creates a cc.TileMap with a tile file (atlas) with a map file and the width and height of each tile in points.
    - * The tile file will be loaded using the TextureMgr.

    - * @param {String} tile - * @param {String} mapFile - * @param {Number} tileWidth - * @param {Number} tileHeight - * @return {Boolean|Null} - * @example - * //example - * var tmpAtlas = new cc.TileMapAtlas(); - * tmpAtlas.initWithTileFile("hello.png", "hello.tga", 16, 16); - */ -cc.TileMapAtlas.create = function (tile, mapFile, tileWidth, tileHeight) { - return new cc.TileMapAtlas(tile, mapFile, tileWidth, tileHeight); -}; diff --git a/cocos2d/transitions/CCTransition.js b/cocos2d/transitions/CCTransition.js index 09bdec9035..f5ccb82cfe 100644 --- a/cocos2d/transitions/CCTransition.js +++ b/cocos2d/transitions/CCTransition.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -30,19 +30,6 @@ */ cc.SCENE_FADE = 4208917214; -/** - * cc.TransitionEaseScene can ease the actions of the scene protocol. - * @class - * @extends cc.Class - */ -cc.TransitionEaseScene = cc.Class.extend(/** @lends cc.TransitionEaseScene# */{ - /** - * returns the Ease action that will be performed on a linear action. - */ - easeActionWithAction:function () { - } -}); - /** * horizontal orientation Type where the Left is nearer * @constant @@ -71,6 +58,10 @@ cc.TRANSITION_ORIENTATION_DOWN_OVER = 1; /** * @class * @extends cc.Scene + * @param {Number} t time in seconds + * @param {cc.Scene} scene the scene to transit with + * @example + * var trans = new TransitionScene(time,scene); */ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ _inScene:null, @@ -82,11 +73,11 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ /** * creates a base transition with duration and incoming scene - * @constructor + * Constructor of cc.TransitionScene * @param {Number} t time in seconds * @param {cc.Scene} scene the scene to transit with */ - ctor:function(t, scene){ + ctor:function (t, scene) { cc.Scene.prototype.ctor.call(this); if(t !== undefined && scene !== undefined) this.initWithDuration(t, scene); @@ -115,7 +106,7 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ /** * stuff gets drawn here */ - draw:function () { + visit:function () { if (this._isInSceneOnTop) { this._outScene.visit(); this._inScene.visit(); @@ -123,10 +114,16 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ this._inScene.visit(); this._outScene.visit(); } + cc.Node.prototype.visit.call(this); }, /** - * custom onEnter + *

    + * Event callback that is invoked every time when cc.TransitionScene enters the 'stage'.
    + * If the TransitionScene enters the 'stage' with a transition, this event is called when the transition starts.
    + * During onEnter you can't access a "sister/brother" node.
    + * If you override onEnter, you must call its parent's onEnter function with this._super(). + *

    */ onEnter:function () { cc.Node.prototype.onEnter.call(this); @@ -142,7 +139,12 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ }, /** - * custom onExit + *

    + * callback that is called every time the cc.TransitionScene leaves the 'stage'.
    + * If the cc.TransitionScene leaves the 'stage' with a transition, this callback is called when the transition finishes.
    + * During onExit you can't access a sibling node.
    + * If you override onExit, you shall call its parent's onExit with this._super(). + *

    */ onExit:function () { cc.Node.prototype.onExit.call(this); @@ -189,11 +191,11 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ this._inScene = scene; this._outScene = cc.director.getRunningScene(); if (!this._outScene) { - this._outScene = cc.Scene.create(); + this._outScene = new cc.Scene(); this._outScene.init(); } - if(this._inScene == this._outScene) + if(this._inScene === this._outScene) throw "cc.TransitionScene.initWithDuration(): Incoming scene must be different from the outgoing scene"; this._sceneOrder(); @@ -242,6 +244,7 @@ cc.TransitionScene = cc.Scene.extend(/** @lends cc.TransitionScene# */{ }); /** * creates a base transition with duration and incoming scene + * @deprecated since v3.0, please use new cc.TransitionScene(t,scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene the scene to transit with * @return {cc.TransitionScene|Null} @@ -256,10 +259,25 @@ cc.TransitionScene.create = function (t, scene) { * useful for when you want to make a transition happen between 2 orientations * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} orientation + * @example + * var trans = new cc.TransitionSceneOriented(time,scene,orientation); */ cc.TransitionSceneOriented = cc.TransitionScene.extend(/** @lends cc.TransitionSceneOriented# */{ _orientation:0, + /** + * Constructor of TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} orientation + */ + ctor:function (t, scene, orientation) { + cc.TransitionScene.prototype.ctor.call(this); + orientation != undefined && this.initWithDuration(t, scene, orientation); + }, /** * initialize the transition * @param {Number} t time in seconds @@ -277,27 +295,37 @@ cc.TransitionSceneOriented = cc.TransitionScene.extend(/** @lends cc.TransitionS /** * creates a base transition with duration and incoming scene + * @deprecated since v3.0 ,please use new cc.TransitionSceneOriented(t, scene, orientation) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} orientation * @return {cc.TransitionSceneOriented} - * @example - * // Example - * var goHorizontal = cc.TransitionSceneOriented.create(0.5, thisScene, cc.TRANSITION_ORIENTATION_LEFT_OVER) */ cc.TransitionSceneOriented.create = function (t, scene, orientation) { - var tempScene = new cc.TransitionSceneOriented(); - tempScene.initWithDuration(t, scene, orientation); - - return tempScene; + return new cc.TransitionSceneOriented(t, scene, orientation); }; /** * Rotate and zoom out the outgoing scene, and then rotate and zoom in the incoming * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionRotoZoom(t, scene); */ cc.TransitionRotoZoom = cc.TransitionScene.extend(/** @lends cc.TransitionRotoZoom# */{ + + /** + * Constructor of TransitionRotoZoom + * @function + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * Custom On Enter callback * @override @@ -315,42 +343,49 @@ cc.TransitionRotoZoom = cc.TransitionScene.extend(/** @lends cc.TransitionRotoZo anchorX: 0.5, anchorY: 0.5 }); - - var rotoZoom = cc.Sequence.create( - cc.Spawn.create(cc.ScaleBy.create(this._duration / 2, 0.001), - cc.RotateBy.create(this._duration / 2, 360 * 2)), - cc.DelayTime.create(this._duration / 2)); + + var rotoZoom = cc.sequence( + cc.spawn(cc.scaleBy(this._duration / 2, 0.001), + cc.rotateBy(this._duration / 2, 360 * 2)), + cc.delayTime(this._duration / 2)); this._outScene.runAction(rotoZoom); this._inScene.runAction( - cc.Sequence.create(rotoZoom.reverse(), - cc.CallFunc.create(this.finish, this))); + cc.sequence(rotoZoom.reverse(), + cc.callFunc(this.finish, this))); } }); /** * Creates a Transtion rotation and zoom + * @deprecated since v3.0,please use new cc.TransitionRotoZoom(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene the scene to work with * @return {cc.TransitionRotoZoom} - * @example - * // Example - * var RotoZoomTrans = cc.TransitionRotoZoom.create(2, nextScene); */ cc.TransitionRotoZoom.create = function (t, scene) { - var tempScene = new cc.TransitionRotoZoom(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionRotoZoom(t, scene); }; /** * Zoom out and jump the outgoing scene, and then jump and zoom in the incoming * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionJumpZoom(t, scene); */ cc.TransitionJumpZoom = cc.TransitionScene.extend(/** @lends cc.TransitionJumpZoom# */{ + /** + * Constructor of TransitionJumpZoom + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * Custom on enter */ @@ -368,40 +403,49 @@ cc.TransitionJumpZoom = cc.TransitionScene.extend(/** @lends cc.TransitionJumpZo this._outScene.anchorX = 0.5; this._outScene.anchorY = 0.5; - var jump = cc.JumpBy.create(this._duration / 4, cc.p(-winSize.width, 0), winSize.width / 4, 2); - var scaleIn = cc.ScaleTo.create(this._duration / 4, 1.0); - var scaleOut = cc.ScaleTo.create(this._duration / 4, 0.5); + var jump = cc.jumpBy(this._duration / 4, cc.p(-winSize.width, 0), winSize.width / 4, 2); + var scaleIn = cc.scaleTo(this._duration / 4, 1.0); + var scaleOut = cc.scaleTo(this._duration / 4, 0.5); - var jumpZoomOut = cc.Sequence.create(scaleOut, jump); - var jumpZoomIn = cc.Sequence.create(jump, scaleIn); + var jumpZoomOut = cc.sequence(scaleOut, jump); + var jumpZoomIn = cc.sequence(jump, scaleIn); - var delay = cc.DelayTime.create(this._duration / 2); + var delay = cc.delayTime(this._duration / 2); this._outScene.runAction(jumpZoomOut); - this._inScene.runAction(cc.Sequence.create(delay, jumpZoomIn, cc.CallFunc.create(this.finish, this))); + this._inScene.runAction(cc.sequence(delay, jumpZoomIn, cc.callFunc(this.finish, this))); } }); /** * creates a scene transition that zooms then jump across the screen, the same for the incoming scene + * @deprecated since v3.0,please use new cc.TransitionJumpZoom(t, scene); * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionJumpZoom} */ cc.TransitionJumpZoom.create = function (t, scene) { - var tempScene = new cc.TransitionJumpZoom(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionJumpZoom(t, scene); }; /** * Move in from to the left the incoming scene. * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionMoveInL(time,scene); */ cc.TransitionMoveInL = cc.TransitionScene.extend(/** @lends cc.TransitionMoveInL# */{ - + /** + * Constructor of TransitionMoveInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * Custom on enter */ @@ -411,7 +455,7 @@ cc.TransitionMoveInL = cc.TransitionScene.extend(/** @lends cc.TransitionMoveInL var action = this.action(); this._inScene.runAction( - cc.Sequence.create(this.easeActionWithAction(action), cc.CallFunc.create(this.finish, this)) + cc.sequence(this.easeActionWithAction(action), cc.callFunc(this.finish, this)) ); }, @@ -426,7 +470,7 @@ cc.TransitionMoveInL = cc.TransitionScene.extend(/** @lends cc.TransitionMoveInL * returns the action that will be performed */ action:function () { - return cc.MoveTo.create(this._duration, cc.p(0, 0)); + return cc.moveTo(this._duration, cc.p(0, 0)); }, /** @@ -435,35 +479,42 @@ cc.TransitionMoveInL = cc.TransitionScene.extend(/** @lends cc.TransitionMoveInL * @return {cc.EaseOut} */ easeActionWithAction:function (action) { - return cc.EaseOut.create(action, 2.0); + return new cc.EaseOut(action, 2.0); } }); /** * creates an action that Move in from to the left the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionMoveInL(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionMoveInL} - * @example - * // Example - * var MoveInLeft = cc.TransitionMoveInL.create(1, nextScene) */ cc.TransitionMoveInL.create = function (t, scene) { - var tempScene = new cc.TransitionMoveInL(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionMoveInL(t, scene); }; /** * Move in from to the right the incoming scene. * @class * @extends cc.TransitionMoveInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionMoveInR(time,scene); */ cc.TransitionMoveInR = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveInR# */{ /** - * Init + * Constructor of TransitionMoveInR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionMoveInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + /** + * Init function */ initScenes:function () { this._inScene.setPosition(cc.director.getWinSize().width, 0); @@ -472,30 +523,36 @@ cc.TransitionMoveInR = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveI /** * create a scene transition that Move in from to the right the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionMoveInR(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionMoveInR} - * @example - * // Example - * var MoveInRight = cc.TransitionMoveInR.create(1, nextScene) */ cc.TransitionMoveInR.create = function (t, scene) { - var tempScene = new cc.TransitionMoveInR(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionMoveInR(t, scene); }; /** * Move in from to the top the incoming scene. * @class * @extends cc.TransitionMoveInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionMoveInT(time,scene); */ cc.TransitionMoveInT = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveInT# */{ - /** - * init + * Constructor of TransitionMoveInT + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionMoveInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + /** + * init function */ initScenes:function () { this._inScene.setPosition(0, cc.director.getWinSize().height); @@ -504,30 +561,37 @@ cc.TransitionMoveInT = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveI /** * Move in from to the top the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionMoveInT(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionMoveInT} - * @example - * // Example - * var MoveInTop = cc.TransitionMoveInT.create(1, nextScene) */ cc.TransitionMoveInT.create = function (t, scene) { - var tempScene = new cc.TransitionMoveInT(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionMoveInT(t, scene); }; /** * Move in from to the bottom the incoming scene. * @class * @extends cc.TransitionMoveInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionMoveInB(time,scene); */ cc.TransitionMoveInB = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveInB# */{ + /** + * Constructor of TransitionMoveInB + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionMoveInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** - * init + * init function */ initScenes:function () { this._inScene.setPosition(0, -cc.director.getWinSize().height); @@ -536,19 +600,13 @@ cc.TransitionMoveInB = cc.TransitionMoveInL.extend(/** @lends cc.TransitionMoveI /** * create a scene transition that Move in from to the bottom the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionMoveInB(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionMoveInB} - * @example - * // Example - * var MoveinB = cc.TransitionMoveInB.create(1, nextScene) */ cc.TransitionMoveInB.create = function (t, scene) { - var tempScene = new cc.TransitionMoveInB(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionMoveInB(t, scene); }; /** @@ -565,8 +623,21 @@ cc.ADJUST_FACTOR = 0.5; * a transition that a new scene is slided from left * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = cc.TransitionSlideInL(time,scene); */ cc.TransitionSlideInL = cc.TransitionScene.extend(/** @lends cc.TransitionSlideInL# */{ + /** + * Constructor of TransitionSlideInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, _sceneOrder:function () { this._isInSceneOnTop = false; }, @@ -582,7 +653,7 @@ cc.TransitionSlideInL = cc.TransitionScene.extend(/** @lends cc.TransitionSlideI var outA = this.action(); var inAction = this.easeActionWithAction(inA); - var outAction = cc.Sequence.create(this.easeActionWithAction(outA), cc.CallFunc.create(this.finish, this)); + var outAction = cc.sequence(this.easeActionWithAction(outA), cc.callFunc(this.finish, this)); this._inScene.runAction(inAction); this._outScene.runAction(outAction); }, @@ -598,7 +669,7 @@ cc.TransitionSlideInL = cc.TransitionScene.extend(/** @lends cc.TransitionSlideI * @return {cc.MoveBy} */ action:function () { - return cc.MoveBy.create(this._duration, cc.p(cc.director.getWinSize().width - cc.ADJUST_FACTOR, 0)); + return cc.moveBy(this._duration, cc.p(cc.director.getWinSize().width - cc.ADJUST_FACTOR, 0)); }, /** @@ -606,33 +677,40 @@ cc.TransitionSlideInL = cc.TransitionScene.extend(/** @lends cc.TransitionSlideI * @return {*} */ easeActionWithAction:function (action) { - return cc.EaseOut.create(action, 2.0); + return new cc.EaseInOut(action, 2.0); } }); /** * create a transition that a new scene is slided from left + * @deprecated since v3.0,please use new cc.TransitionSlideInL(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSlideInL} - * @example - * // Example - * var myTransition = cc.TransitionSlideInL.create(1.5, nextScene) */ cc.TransitionSlideInL.create = function (t, scene) { - var tempScene = new cc.TransitionSlideInL(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSlideInL(t, scene); }; /** * Slide in the incoming scene from the right border. * @class * @extends cc.TransitionSlideInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionSlideInR(time,scene); */ cc.TransitionSlideInR = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSlideInR# */{ + /** + * Constructor of TransitionSlideInR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionSlideInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, _sceneOrder:function () { this._isInSceneOnTop = true; }, @@ -647,33 +725,40 @@ cc.TransitionSlideInR = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSli * @return {cc.MoveBy} */ action:function () { - return cc.MoveBy.create(this._duration, cc.p(-(cc.director.getWinSize().width - cc.ADJUST_FACTOR), 0)); + return cc.moveBy(this._duration, cc.p(-(cc.director.getWinSize().width - cc.ADJUST_FACTOR), 0)); } }); /** * create Slide in the incoming scene from the right border. + * @deprecated since v3.0,please use new cc.TransitionSlideInR(t, scene) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSlideInR} - * @example - * // Example - * var myTransition = cc.TransitionSlideInR.create(1.5, nextScene) */ cc.TransitionSlideInR.create = function (t, scene) { - var tempScene = new cc.TransitionSlideInR(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSlideInR(t, scene); }; /** * Slide in the incoming scene from the bottom border. * @class * @extends cc.TransitionSlideInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionSlideInB(time,scene); */ cc.TransitionSlideInB = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSlideInB# */{ + /** + * Constructor of TransitionSlideInB + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionSlideInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, _sceneOrder:function () { this._isInSceneOnTop = false; }, @@ -682,7 +767,7 @@ cc.TransitionSlideInB = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSli * initializes the scenes */ initScenes:function () { - this._inScene.setPosition(0, cc.director.getWinSize().height - cc.ADJUST_FACTOR); + this._inScene.setPosition(0, -(cc.director.getWinSize().height - cc.ADJUST_FACTOR)); }, /** @@ -690,33 +775,40 @@ cc.TransitionSlideInB = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSli * @return {cc.MoveBy} */ action:function () { - return cc.MoveBy.create(this._duration, cc.p(0, -(cc.director.getWinSize().height - cc.ADJUST_FACTOR))); + return cc.moveBy(this._duration, cc.p(0, cc.director.getWinSize().height - cc.ADJUST_FACTOR)); } }); /** * create a Slide in the incoming scene from the bottom border. + * @deprecated since v3.0,please use new cc.TransitionSlideInB(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSlideInB} - * @example - * // Example - * var myTransition = cc.TransitionSlideInB.create(1.5, nextScene) */ cc.TransitionSlideInB.create = function (t, scene) { - var tempScene = new cc.TransitionSlideInB(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSlideInB(t, scene); }; /** * Slide in the incoming scene from the top border. * @class * @extends cc.TransitionSlideInL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionSlideInT(time,scene); */ cc.TransitionSlideInT = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSlideInT# */{ + /** + * Constructor of TransitionSlideInT + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionSlideInL.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, _sceneOrder:function () { this._isInSceneOnTop = true; }, @@ -725,7 +817,7 @@ cc.TransitionSlideInT = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSli * initializes the scenes */ initScenes:function () { - this._inScene.setPosition(0, -(cc.director.getWinSize().height - cc.ADJUST_FACTOR)); + this._inScene.setPosition(0, cc.director.getWinSize().height - cc.ADJUST_FACTOR); }, /** @@ -733,34 +825,40 @@ cc.TransitionSlideInT = cc.TransitionSlideInL.extend(/** @lends cc.TransitionSli * @return {cc.MoveBy} */ action:function () { - return cc.MoveBy.create(this._duration, cc.p(0, cc.director.getWinSize().height - cc.ADJUST_FACTOR)); + return cc.moveBy(this._duration, cc.p(0, -(cc.director.getWinSize().height - cc.ADJUST_FACTOR))); } }); /** * create a Slide in the incoming scene from the top border. + * @deprecated since v3.0,please use new cc.TransitionSlideInT(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSlideInT} - * @example - * // Example - * var myTransition = cc.TransitionSlideInT.create(1.5, nextScene) */ cc.TransitionSlideInT.create = function (t, scene) { - var tempScene = new cc.TransitionSlideInT(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSlideInT(t, scene); }; /** * Shrink the outgoing scene while grow the incoming scene * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionShrinkGrow(time,scene); */ cc.TransitionShrinkGrow = cc.TransitionScene.extend(/** @lends cc.TransitionShrinkGrow# */{ - + /** + * Constructor of TransitionShrinkGrow + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * Custom on enter */ @@ -778,12 +876,12 @@ cc.TransitionShrinkGrow = cc.TransitionScene.extend(/** @lends cc.TransitionShri anchorY: 0.5 }); - var scaleOut = cc.ScaleTo.create(this._duration, 0.01); - var scaleIn = cc.ScaleTo.create(this._duration, 1.0); + var scaleOut = cc.scaleTo(this._duration, 0.01); + var scaleIn = cc.scaleTo(this._duration, 1.0); this._inScene.runAction(this.easeActionWithAction(scaleIn)); this._outScene.runAction( - cc.Sequence.create(this.easeActionWithAction(scaleOut), cc.CallFunc.create(this.finish, this)) + cc.sequence(this.easeActionWithAction(scaleOut), cc.callFunc(this.finish, this)) ); }, @@ -792,25 +890,19 @@ cc.TransitionShrinkGrow = cc.TransitionScene.extend(/** @lends cc.TransitionShri * @return {cc.EaseOut} */ easeActionWithAction:function (action) { - return cc.EaseOut.create(action, 2.0); + return new cc.EaseOut(action, 2.0); } }); /** * Shrink the outgoing scene while grow the incoming scene + * @deprecated since v3.0,please use new cc.TransitionShrinkGrow(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionShrinkGrow} - * @example - * // Example - * var myTransition = cc.TransitionShrinkGrow.create(1.5, nextScene) */ cc.TransitionShrinkGrow.create = function (t, scene) { - var tempScene = new cc.TransitionShrinkGrow(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionShrinkGrow(t, scene); }; /** @@ -818,8 +910,26 @@ cc.TransitionShrinkGrow.create = function (t, scene) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionFlipX(t,scene,o); */ cc.TransitionFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionFlipX# */{ + /** + * Constructor of TransitionFlipX + * @function + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter @@ -844,15 +954,15 @@ cc.TransitionFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionF outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), cc.Show.create(), - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 0, 0), - cc.CallFunc.create(this.finish, this) + inA = cc.sequence( + cc.delayTime(this._duration / 2), cc.show(), + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 0, 0), + cc.callFunc(this.finish, this) ); - outA = cc.Sequence.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 0, 0), - cc.Hide.create(), cc.DelayTime.create(this._duration / 2) + outA = cc.sequence( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 0, 0), + cc.hide(), cc.delayTime(this._duration / 2) ); this._inScene.runAction(inA); @@ -863,24 +973,14 @@ cc.TransitionFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionF /** * Flips the screen horizontally.
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionFlipX(t, scene,o) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionFlipX} - * @example - * // Example - * var myTransition = cc.TransitionFlipX.create(1.5, nextScene) //default is cc.TRANSITION_ORIENTATION_RIGHT_OVER - * - * //OR - * var myTransition = cc.TransitionFlipX.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_UP_OVER) */ cc.TransitionFlipX.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; - - var tempScene = new cc.TransitionFlipX(); - tempScene.initWithDuration(t, scene, o); - return tempScene; + return new cc.TransitionFlipX(t, scene, o); }; /** @@ -888,9 +988,26 @@ cc.TransitionFlipX.create = function (t, scene, o) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionFlipY(time,scene,0); */ cc.TransitionFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionFlipY# */{ + /** + * Constructor of TransitionFlipY + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_UP_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter */ @@ -902,7 +1019,7 @@ cc.TransitionFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionF var inDeltaZ, inAngleZ, outDeltaZ, outAngleZ; - if (this._orientation == cc.TRANSITION_ORIENTATION_UP_OVER) { + if (this._orientation === cc.TRANSITION_ORIENTATION_UP_OVER) { inDeltaZ = 90; inAngleZ = 270; outDeltaZ = 90; @@ -914,14 +1031,14 @@ cc.TransitionFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionF outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), cc.Show.create(), - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 90, 0), - cc.CallFunc.create(this.finish, this) + inA = cc.sequence( + cc.delayTime(this._duration / 2), cc.show(), + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 90, 0), + cc.callFunc(this.finish, this) ); - outA = cc.Sequence.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 90, 0), - cc.Hide.create(), cc.DelayTime.create(this._duration / 2) + outA = cc.sequence( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 90, 0), + cc.hide(), cc.delayTime(this._duration / 2) ); this._inScene.runAction(inA); @@ -932,25 +1049,14 @@ cc.TransitionFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionF /** * Flips the screen vertically.
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionFlipY(t, scene,o) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionFlipY} - * @example - * // Example - * var myTransition = cc.TransitionFlipY.create(1.5, nextScene)//default is cc.TRANSITION_ORIENTATION_UP_OVER - * - * //OR - * var myTransition = cc.TransitionFlipY.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_RIGHT_OVER) */ cc.TransitionFlipY.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_UP_OVER; - - var tempScene = new cc.TransitionFlipY(); - tempScene.initWithDuration(t, scene, o); - - return tempScene; + return new cc.TransitionFlipY(t, scene, o); }; /** @@ -958,8 +1064,25 @@ cc.TransitionFlipY.create = function (t, scene, o) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = cc.TransitionFlipAngular(time,scene,o); */ cc.TransitionFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionFlipAngular# */{ + /** + * Constructor of TransitionFlipAngular + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter */ @@ -983,14 +1106,14 @@ cc.TransitionFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.Trans outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), cc.Show.create(), - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, -45, 0), - cc.CallFunc.create(this.finish, this) + inA = cc.sequence( + cc.delayTime(this._duration / 2), cc.show(), + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, -45, 0), + cc.callFunc(this.finish, this) ); - outA = cc.Sequence.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 45, 0), - cc.Hide.create(), cc.DelayTime.create(this._duration / 2) + outA = cc.sequence( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 45, 0), + cc.hide(), cc.delayTime(this._duration / 2) ); this._inScene.runAction(inA); @@ -1001,25 +1124,14 @@ cc.TransitionFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.Trans /** * Flips the screen half horizontally and half vertically.
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new new cc.TransitionFlipAngular(t, scene, o) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionFlipAngular} - * @example - * // Example - * var myTransition = cc.TransitionFlipAngular.create(1.5, nextScene)//default is cc.TRANSITION_ORIENTATION_RIGHT_OVER - * - * //or - * var myTransition = cc.TransitionFlipAngular.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_DOWN_OVER) */ cc.TransitionFlipAngular.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; - - var tempScene = new cc.TransitionFlipAngular(); - tempScene.initWithDuration(t, scene, o); - - return tempScene; + return new cc.TransitionFlipAngular(t, scene, o); }; /** @@ -1027,9 +1139,26 @@ cc.TransitionFlipAngular.create = function (t, scene, o) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionZoomFlipX(time,scene,o); */ cc.TransitionZoomFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionZoomFlipX# */{ + /** + * Constructor of TransitionZoomFlipX + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter */ @@ -1053,19 +1182,19 @@ cc.TransitionZoomFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.Transit outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 0, 0), - cc.ScaleTo.create(this._duration / 2, 1), cc.Show.create()), - cc.CallFunc.create(this.finish, this) + inA = cc.sequence( + cc.delayTime(this._duration / 2), + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 0, 0), + cc.scaleTo(this._duration / 2, 1), cc.show()), + cc.callFunc(this.finish, this) ); - outA = cc.Sequence.create( - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 0, 0), - cc.ScaleTo.create(this._duration / 2, 0.5)), - cc.Hide.create(), - cc.DelayTime.create(this._duration / 2) + outA = cc.sequence( + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 0, 0), + cc.scaleTo(this._duration / 2, 0.5)), + cc.hide(), + cc.delayTime(this._duration / 2) ); this._inScene.scale = 0.5; @@ -1077,25 +1206,14 @@ cc.TransitionZoomFlipX = cc.TransitionSceneOriented.extend(/** @lends cc.Transit /** * Flips the screen horizontally doing a zoom out/in
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new new cc.TransitionZoomFlipX(t, scene, o) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionZoomFlipX} - * @example - * // Example - * var myTransition = cc.TransitionZoomFlipX.create(1.5, nextScene)//default is cc.TRANSITION_ORIENTATION_RIGHT_OVER - * - * //OR - * var myTransition = cc.TransitionZoomFlipX.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_DOWN_OVER) */ cc.TransitionZoomFlipX.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; - - var tempScene = new cc.TransitionZoomFlipX(); - tempScene.initWithDuration(t, scene, o); - - return tempScene; + return new cc.TransitionZoomFlipX(t, scene, o); }; /** @@ -1103,9 +1221,26 @@ cc.TransitionZoomFlipX.create = function (t, scene, o) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionZoomFlipY(t,scene,o); */ cc.TransitionZoomFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionZoomFlipY# */{ + /** + * Constructor of TransitionZoomFlipY + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_UP_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter */ @@ -1129,18 +1264,18 @@ cc.TransitionZoomFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.Transit outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 90, 0), - cc.ScaleTo.create(this._duration / 2, 1), cc.Show.create()), - cc.CallFunc.create(this.finish, this)); + inA = cc.sequence( + cc.delayTime(this._duration / 2), + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, 90, 0), + cc.scaleTo(this._duration / 2, 1), cc.show()), + cc.callFunc(this.finish, this)); - outA = cc.Sequence.create( - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 90, 0), - cc.ScaleTo.create(this._duration / 2, 0.5)), - cc.Hide.create(), cc.DelayTime.create(this._duration / 2)); + outA = cc.sequence( + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 90, 0), + cc.scaleTo(this._duration / 2, 0.5)), + cc.hide(), cc.delayTime(this._duration / 2)); this._inScene.scale = 0.5; this._inScene.runAction(inA); @@ -1151,25 +1286,14 @@ cc.TransitionZoomFlipY = cc.TransitionSceneOriented.extend(/** @lends cc.Transit /** * Flips the screen vertically doing a little zooming out/in
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new new cc.TransitionZoomFlipY(t, scene, o) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionZoomFlipY} - * @example - * // Example - * var myTransition = cc.TransitionZoomFlipY.create(1.5, nextScene)//default is cc.TRANSITION_ORIENTATION_UP_OVER - * - * //OR - * var myTransition = cc.TransitionZoomFlipY.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_DOWN_OVER) */ cc.TransitionZoomFlipY.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_UP_OVER; - - var tempScene = new cc.TransitionZoomFlipY(); - tempScene.initWithDuration(t, scene, o); - - return tempScene; + return new cc.TransitionZoomFlipY(t, scene, o); }; /** @@ -1177,9 +1301,26 @@ cc.TransitionZoomFlipY.create = function (t, scene, o) { * The front face is the outgoing scene and the back face is the incoming scene. * @class * @extends cc.TransitionSceneOriented + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionZoomFlipAngular(time,scene,o); */ cc.TransitionZoomFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.TransitionZoomFlipAngular# */{ + /** + * Constructor of TransitionZoomFlipAngular + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + */ + ctor:function (t, scene, o) { + cc.TransitionSceneOriented.prototype.ctor.call(this); + if(o == null) + o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; + scene && this.initWithDuration(t, scene, o); + }, /** * custom on enter */ @@ -1202,18 +1343,18 @@ cc.TransitionZoomFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.T outAngleZ = 0; } - inA = cc.Sequence.create( - cc.DelayTime.create(this._duration / 2), - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, -45, 0), - cc.ScaleTo.create(this._duration / 2, 1), cc.Show.create()), - cc.Show.create(), - cc.CallFunc.create(this.finish, this)); - outA = cc.Sequence.create( - cc.Spawn.create( - cc.OrbitCamera.create(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 45, 0), - cc.ScaleTo.create(this._duration / 2, 0.5)), - cc.Hide.create(), cc.DelayTime.create(this._duration / 2)); + inA = cc.sequence( + cc.delayTime(this._duration / 2), + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, inAngleZ, inDeltaZ, -45, 0), + cc.scaleTo(this._duration / 2, 1), cc.show()), + cc.show(), + cc.callFunc(this.finish, this)); + outA = cc.sequence( + cc.spawn( + cc.orbitCamera(this._duration / 2, 1, 0, outAngleZ, outDeltaZ, 45, 0), + cc.scaleTo(this._duration / 2, 0.5)), + cc.hide(), cc.delayTime(this._duration / 2)); this._inScene.scale = 0.5; this._inScene.runAction(inA); @@ -1224,41 +1365,39 @@ cc.TransitionZoomFlipAngular = cc.TransitionSceneOriented.extend(/** @lends cc.T /** * Flips the screen half horizontally and half vertically doing a little zooming out/in.
    * The front face is the outgoing scene and the back face is the incoming scene. + * @deprecated since v3.0,please use new new cc.TransitionZoomFlipAngular(t, scene, o) instead * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o * @return {cc.TransitionZoomFlipAngular} - * @example - * // Example - * var myTransition = cc.TransitionZoomFlipAngular.create(1.5, nextScene)//default is cc.TRANSITION_ORIENTATION_RIGHT_OVER - * - * //OR - * var myTransition = cc.TransitionZoomFlipAngular.create(1.5, nextScene, cc.TRANSITION_ORIENTATION_DOWN_OVER) */ cc.TransitionZoomFlipAngular.create = function (t, scene, o) { - if (o == null) - o = cc.TRANSITION_ORIENTATION_RIGHT_OVER; - - var tempScene = new cc.TransitionZoomFlipAngular(); - tempScene.initWithDuration(t, scene, o); - - return tempScene; + return new cc.TransitionZoomFlipAngular(t, scene, o); }; /** * Fade out the outgoing scene and then fade in the incoming scene. * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o + * @example + * var trans = new cc.TransitionFade(time,scene,color) */ cc.TransitionFade = cc.TransitionScene.extend(/** @lends cc.TransitionFade# */{ _color:null, /** - * Constructor + * Constructor of TransitionFade + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {cc.TRANSITION_ORIENTATION_LEFT_OVER|cc.TRANSITION_ORIENTATION_RIGHT_OVER|cc.TRANSITION_ORIENTATION_UP_OVER|cc.TRANSITION_ORIENTATION_DOWN_OVER} o */ - ctor:function () { + ctor:function (t, scene, color) { cc.TransitionScene.prototype.ctor.call(this); - this._color = cc.color() + this._color = cc.color(); + scene && this.initWithDuration(t, scene, color); }, /** @@ -1267,17 +1406,17 @@ cc.TransitionFade = cc.TransitionScene.extend(/** @lends cc.TransitionFade# */{ onEnter:function () { cc.TransitionScene.prototype.onEnter.call(this); - var l = cc.LayerColor.create(this._color); + var l = new cc.LayerColor(this._color); this._inScene.visible = false; this.addChild(l, 2, cc.SCENE_FADE); var f = this.getChildByTag(cc.SCENE_FADE); - var a = cc.Sequence.create( - cc.FadeIn.create(this._duration / 2), - cc.CallFunc.create(this.hideOutShowIn, this), //CCCallFunc.actionWithTarget:self selector:@selector(hideOutShowIn)], - cc.FadeOut.create(this._duration / 2), - cc.CallFunc.create(this.finish, this) //:self selector:@selector(finish)], + var a = cc.sequence( + cc.fadeIn(this._duration / 2), + cc.callFunc(this.hideOutShowIn, this), + cc.fadeOut(this._duration / 2), + cc.callFunc(this.finish, this) ); f.runAction(a); }, @@ -1312,26 +1451,35 @@ cc.TransitionFade = cc.TransitionScene.extend(/** @lends cc.TransitionFade# */{ /** * Fade out the outgoing scene and then fade in the incoming scene. + * @deprecated since v3.0,please use new cc.TransitionFade(time,scene,color) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {cc.Color} color * @return {cc.TransitionFade} - * @example - * // Example - * var myTransition = cc.TransitionFade.create(1.5, nextScene, cc.color(255,0,0))//fade to red */ cc.TransitionFade.create = function (t, scene, color) { - var transition = new cc.TransitionFade(); - transition.initWithDuration(t, scene, color); - return transition; + return new cc.TransitionFade(t, scene, color); }; /** * Cross fades two scenes using the cc.RenderTexture object. * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionCrossFade(time,scene); */ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCrossFade# */{ + /** + * Constructor of TransitionCrossFade + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * custom on enter */ @@ -1342,13 +1490,10 @@ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCross // in which we are going to add our rendertextures var color = cc.color(0, 0, 0, 0); var winSize = cc.director.getWinSize(); - var layer = cc.LayerColor.create(color); + var layer = new cc.LayerColor(color); // create the first render texture for inScene - var inTexture = cc.RenderTexture.create(winSize.width, winSize.height); - - if (null == inTexture) - return; + var inTexture = new cc.RenderTexture(winSize.width, winSize.height); inTexture.sprite.anchorX = 0.5; inTexture.sprite.anchorY = 0.5; @@ -1365,7 +1510,7 @@ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCross inTexture.end(); // create the second render texture for outScene - var outTexture = cc.RenderTexture.create(winSize.width, winSize.height); + var outTexture = new cc.RenderTexture(winSize.width, winSize.height); outTexture.setPosition(winSize.width / 2, winSize.height / 2); outTexture.sprite.anchorX = outTexture.anchorX = 0.5; outTexture.sprite.anchorY = outTexture.anchorY = 0.5; @@ -1387,9 +1532,9 @@ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCross outTexture.sprite.opacity = 255; // create the blend action - var layerAction = cc.Sequence.create( - cc.FadeTo.create(this._duration, 0), cc.CallFunc.create(this.hideOutShowIn, this), - cc.CallFunc.create(this.finish, this) + var layerAction = cc.sequence( + cc.fadeTo(this._duration, 0), cc.callFunc(this.hideOutShowIn, this), + cc.callFunc(this.finish, this) ); // run the blend action @@ -1407,6 +1552,13 @@ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCross cc.TransitionScene.prototype.onExit.call(this); }, + /** + * stuff gets drawn here + */ + visit:function () { + cc.Node.prototype.visit.call(this); + }, + /** * overide draw */ @@ -1417,25 +1569,37 @@ cc.TransitionCrossFade = cc.TransitionScene.extend(/** @lends cc.TransitionCross /** * Cross fades two scenes using the cc.RenderTexture object. + * @deprecated since v3.0,please use new cc.TransitionCrossFade(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionCrossFade} - * @example - * // Example - * var myTransition = cc.TransitionCrossFade.create(1.5, nextScene) */ cc.TransitionCrossFade.create = function (t, scene) { - var Transition = new cc.TransitionCrossFade(); - Transition.initWithDuration(t, scene); - return Transition; + return new cc.TransitionCrossFade(t, scene); }; /** * Turn off the tiles of the outgoing scene in random order * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionTurnOffTiles(time,scene); */ cc.TransitionTurnOffTiles = cc.TransitionScene.extend(/** @lends cc.TransitionTurnOffTiles# */{ + _gridProxy: null, + /** + * Constructor of TransitionCrossFade + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + this._gridProxy = new cc.NodeGrid(); + scene && this.initWithDuration(t, scene); + }, + _sceneOrder:function () { this._isInSceneOnTop = false; }, @@ -1445,13 +1609,21 @@ cc.TransitionTurnOffTiles = cc.TransitionScene.extend(/** @lends cc.TransitionTu */ onEnter:function () { cc.TransitionScene.prototype.onEnter.call(this); + this._gridProxy.setTarget(this._outScene); + this._gridProxy.onEnter(); + var winSize = cc.director.getWinSize(); var aspect = winSize.width / winSize.height; var x = 0 | (12 * aspect); var y = 12; - var toff = cc.TurnOffTiles.create(this._duration, cc.size(x, y)); + var toff = cc.turnOffTiles(this._duration, cc.size(x, y)); var action = this.easeActionWithAction(toff); - this._outScene.runAction(cc.Sequence.create(action, cc.CallFunc.create(this.finish, this), cc.StopGrid.create())); + this._gridProxy.runAction(cc.sequence(action, cc.callFunc(this.finish, this), cc.stopGrid())); + }, + + visit: function(){ + this._inScene.visit(); + this._gridProxy.visit(); }, /** @@ -1465,114 +1637,156 @@ cc.TransitionTurnOffTiles = cc.TransitionScene.extend(/** @lends cc.TransitionTu /** * Turn off the tiles of the outgoing scene in random order + * @deprecated since v3.0,please use new cc.TransitionTurnOffTiles(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionTurnOffTiles} - * @example - * // Example - * var myTransition = cc.TransitionTurnOffTiles.create(1.5, nextScene) */ cc.TransitionTurnOffTiles.create = function (t, scene) { - var tempScene = new cc.TransitionTurnOffTiles(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionTurnOffTiles(t, scene); }; /** * The odd columns goes upwards while the even columns goes downwards. * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionSplitCols(time,scene); */ cc.TransitionSplitCols = cc.TransitionScene.extend(/** @lends cc.TransitionSplitCols# */{ + _gridProxy: null, + + _switchTargetToInscene: function(){ + this._gridProxy.setTarget(this._inScene); + }, + /** + * Constructor of TransitionSplitCols + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + this._gridProxy = new cc.NodeGrid(); + scene && this.initWithDuration(t, scene); + }, /** * custom on enter */ onEnter:function () { cc.TransitionScene.prototype.onEnter.call(this); - this._inScene.visible = false; + //this._inScene.visible = false; + this._gridProxy.setTarget(this._outScene); + this._gridProxy.onEnter(); var split = this.action(); - var seq = cc.Sequence.create( - split, cc.CallFunc.create(this.hideOutShowIn, this), split.reverse()); + var seq = cc.sequence( + split, cc.callFunc(this._switchTargetToInscene, this), split.reverse()); - this.runAction( - cc.Sequence.create(this.easeActionWithAction(seq), cc.CallFunc.create(this.finish, this), cc.StopGrid.create()) + this._gridProxy.runAction( + cc.sequence(this.easeActionWithAction(seq), cc.callFunc(this.finish, this), cc.stopGrid()) ); }, + onExit: function(){ + this._gridProxy.setTarget(null); + this._gridProxy.onExit(); + cc.TransitionScene.prototype.onExit.call(this); + }, + + visit: function(){ + this._gridProxy.visit(); + }, + /** * @param {cc.ActionInterval} action * @return {cc.EaseInOut} */ easeActionWithAction:function (action) { - return cc.EaseInOut.create(action, 3.0); + return new cc.EaseInOut(action, 3.0); }, /** * @return {*} */ action:function () { - return cc.SplitCols.create(this._duration / 2.0, 3); + return cc.splitCols(this._duration / 2.0, 3); } }); /** * The odd columns goes upwards while the even columns goes downwards. + * @deprecated since v3.0,please use new cc.TransitionSplitCols(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSplitCols} - * @example - * // Example - * var myTransition = cc.TransitionSplitCols.create(1.5, nextScene) */ cc.TransitionSplitCols.create = function (t, scene) { - var tempScene = new cc.TransitionSplitCols(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSplitCols(t, scene); }; /** * The odd rows goes to the left while the even rows goes to the right. * @class * @extends cc.TransitionSplitCols + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionSplitRows(time,scene); */ cc.TransitionSplitRows = cc.TransitionSplitCols.extend(/** @lends cc.TransitionSplitRows# */{ + + /** + * Constructor of TransitionSplitRows + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionSplitCols.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * @return {*} */ action:function () { - return cc.SplitRows.create(this._duration / 2.0, 3); + return cc.splitRows(this._duration / 2.0, 3); } }); /** * The odd rows goes to the left while the even rows goes to the right. + * @deprecated since v3.0,please use new cc.TransitionSplitRows(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionSplitRows} - * @example - * // Example - * var myTransition = cc.TransitionSplitRows.create(1.5, nextScene) */ cc.TransitionSplitRows.create = function (t, scene) { - var tempScene = new cc.TransitionSplitRows(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionSplitRows(t, scene); }; /** * Fade the tiles of the outgoing scene from the left-bottom corner the to top-right corner. * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionFadeTR(time,scene); */ cc.TransitionFadeTR = cc.TransitionScene.extend(/** @lends cc.TransitionFadeTR# */{ + _gridProxy: null, + /** + * Constructor of TransitionFadeTR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + this._gridProxy = new cc.NodeGrid(); + scene && this.initWithDuration(t, scene); + }, _sceneOrder:function () { this._isInSceneOnTop = false; }, @@ -1583,18 +1797,25 @@ cc.TransitionFadeTR = cc.TransitionScene.extend(/** @lends cc.TransitionFadeTR# onEnter:function () { cc.TransitionScene.prototype.onEnter.call(this); + this._gridProxy.setTarget(this._outScene); + this._gridProxy.onEnter(); + var winSize = cc.director.getWinSize(); var aspect = winSize.width / winSize.height; var x = 0 | (12 * aspect); var y = 12; var action = this.actionWithSize(cc.size(x, y)); - this._outScene.runAction( - cc.Sequence.create(this.easeActionWithAction(action), cc.CallFunc.create(this.finish, this), - cc.StopGrid.create()) + this._gridProxy.runAction( + cc.sequence(this.easeActionWithAction(action), cc.callFunc(this.finish, this), cc.stopGrid()) ); }, + visit: function(){ + this._inScene.visit(); + this._gridProxy.visit(); + }, + /** * @param {cc.ActionInterval} action * @return {cc.ActionInterval} @@ -1608,120 +1829,140 @@ cc.TransitionFadeTR = cc.TransitionScene.extend(/** @lends cc.TransitionFadeTR# * @return {*} */ actionWithSize:function (size) { - return cc.FadeOutTRTiles.create(this._duration, size); + return cc.fadeOutTRTiles(this._duration, size); } }); /** * Fade the tiles of the outgoing scene from the left-bottom corner the to top-right corner. + * @deprecated since v3.0 please use new cc.TransitionFadeTR(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionFadeTR} - * @example - * // Example - * var myTransition = cc.TransitionFadeTR.create(1.5, nextScene) */ cc.TransitionFadeTR.create = function (t, scene) { - var tempScene = new cc.TransitionFadeTR(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) - return tempScene; - return null; + return new cc.TransitionFadeTR(t, scene); }; /** * Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. * @class * @extends cc.TransitionFadeTR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionFadeBL(time,scene) */ cc.TransitionFadeBL = cc.TransitionFadeTR.extend(/** @lends cc.TransitionFadeBL# */{ + /** + * Constructor of TransitionFadeBL + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionFadeTR.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, /** * @param {cc.Size} size * @return {*} */ actionWithSize:function (size) { - return cc.FadeOutBLTiles.create(this._duration, size); + return cc.fadeOutBLTiles(this._duration, size); } }); /** * Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. + * @deprecated since v3.0,please use new cc.TransitionFadeBL(t, scene); * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionFadeBL} - * @example - * // Example - * var myTransition = cc.TransitionFadeBL.create(1.5, nextScene) */ cc.TransitionFadeBL.create = function (t, scene) { - var tempScene = new cc.TransitionFadeBL(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) - return tempScene; - return null; + return new cc.TransitionFadeBL(t, scene); }; /** * Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. * @class * @extends cc.TransitionFadeTR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionFadeUp(time,scene); */ cc.TransitionFadeUp = cc.TransitionFadeTR.extend(/** @lends cc.TransitionFadeUp# */{ + /** + * Constructor of TransitionFadeUp + * @function + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionFadeTR.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + /** * @param {cc.Size} size - * @return {*} + * @return {cc.FadeOutUpTiles} */ actionWithSize:function (size) { - return cc.FadeOutUpTiles.create(this._duration, size); + return new cc.FadeOutUpTiles(this._duration, size); } }); /** * Fade the tiles of the outgoing scene from the top-right corner to the bottom-left corner. + * @deprecated since v3.0,please use new cc.TransitionFadeUp(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionFadeUp} - * @example - * // Example - * var myTransition = cc.TransitionFadeUp.create(1.5, nextScene) */ cc.TransitionFadeUp.create = function (t, scene) { - var tempScene = new cc.TransitionFadeUp(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionFadeUp(t, scene); }; /** * Fade the tiles of the outgoing scene from the top to the bottom. * @class * @extends cc.TransitionFadeTR + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionFadeDown(time,scene); */ cc.TransitionFadeDown = cc.TransitionFadeTR.extend(/** @lends cc.TransitionFadeDown# */{ + /** + * Constructor of TransitionFadeDown + * @param {Number} t time in seconds + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionFadeTR.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + /** * @param {cc.Size} size * @return {*} */ actionWithSize:function (size) { - return cc.FadeOutDownTiles.create( this._duration, size); + return cc.fadeOutDownTiles( this._duration, size); } }); /** * Fade the tiles of the outgoing scene from the top to the bottom. + * @deprecated since v3.0,please use new cc.TransitionFadeDown(t, scene) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @return {cc.TransitionFadeDown} - * @example - * // Example - * var myTransition = cc.TransitionFadeDown.create(1.5, nextScene) */ cc.TransitionFadeDown.create = function (t, scene) { - var tempScene = new cc.TransitionFadeDown(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionFadeDown(t, scene); }; diff --git a/cocos2d/transitions/CCTransitionPageTurn.js b/cocos2d/transitions/CCTransitionPageTurn.js index 49baf685fb..6b71fd848b 100644 --- a/cocos2d/transitions/CCTransitionPageTurn.js +++ b/cocos2d/transitions/CCTransitionPageTurn.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -34,12 +34,30 @@ *

    cc.director.setDepthBufferFormat(kDepthBuffer16);

    * @class * @extends cc.TransitionScene + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {Boolean} backwards + * @example + * var trans = new cc.TransitionPageTurn(t, scene, backwards); */ cc.TransitionPageTurn = cc.TransitionScene.extend(/** @lends cc.TransitionPageTurn# */{ + + /** + * @param {Number} t time in seconds + * @param {cc.Scene} scene + * @param {Boolean} backwards + */ + ctor:function (t, scene, backwards) { + cc.TransitionScene.prototype.ctor.call(this); + this._gridProxy = new cc.NodeGrid(); + this.initWithDuration(t, scene, backwards); + }, + /** * @type Boolean */ _back:true, + _gridProxy: null, _className:"TransitionPageTurn", /** @@ -67,9 +85,9 @@ cc.TransitionPageTurn = cc.TransitionScene.extend(/** @lends cc.TransitionPageTu */ actionWithSize:function (vector) { if (this._back) - return cc.ReverseTime.create(cc.PageTurn3D.create(this._duration, vector)); // Get hold of the PageTurn3DAction + return cc.reverseTime(cc.pageTurn3D(this._duration, vector)); // Get hold of the PageTurn3DAction else - return cc.PageTurn3D.create(this._duration, vector); // Get hold of the PageTurn3DAction + return cc.pageTurn3D(this._duration, vector); // Get hold of the PageTurn3DAction }, /** @@ -87,19 +105,33 @@ cc.TransitionPageTurn = cc.TransitionScene.extend(/** @lends cc.TransitionPageTu y = 16; } - var action = this.actionWithSize(cc.size(x, y)); + var action = this.actionWithSize(cc.size(x, y)), gridProxy = this._gridProxy; if (!this._back) { - this._outScene.runAction( cc.Sequence.create(action,cc.CallFunc.create(this.finish, this),cc.StopGrid.create())); + gridProxy.setTarget(this._outScene); + gridProxy.onEnter(); + gridProxy.runAction( cc.sequence(action,cc.callFunc(this.finish, this),cc.stopGrid())); } else { + gridProxy.setTarget(this._inScene); + gridProxy.onEnter(); // to prevent initial flicker this._inScene.visible = false; - this._inScene.runAction( - cc.Sequence.create(cc.Show.create(),action, cc.CallFunc.create(this.finish, this), cc.StopGrid.create()) + gridProxy.runAction( + cc.sequence(action, cc.callFunc(this.finish, this), cc.stopGrid()) ); + this._inScene.runAction(cc.show()); } }, + visit: function(){ + //cc.TransitionScene.prototype.visit.call(this); + if(this._back) + this._outScene.visit(); + else + this._inScene.visit(); + this._gridProxy.visit(); + }, + _sceneOrder:function () { this._isInSceneOnTop = this._back; } @@ -109,16 +141,12 @@ cc.TransitionPageTurn = cc.TransitionScene.extend(/** @lends cc.TransitionPageTu * Creates a base transition with duration and incoming scene.
    * If back is true then the effect is reversed to appear as if the incoming
    * scene is being turned from left over the outgoing scene. + * @deprecated since v3.0,please use new cc.TransitionPageTurn(t, scene, backwards) instead. * @param {Number} t time in seconds * @param {cc.Scene} scene * @param {Boolean} backwards * @return {cc.TransitionPageTurn} - * @example - * // Example - * var myTransition = cc.TransitionPageTurn.create(1.5, nextScene, true)//true means backwards */ cc.TransitionPageTurn.create = function (t, scene, backwards) { - var transition = new cc.TransitionPageTurn(); - transition.initWithDuration(t, scene, backwards); - return transition; + return new cc.TransitionPageTurn(t, scene, backwards); }; diff --git a/cocos2d/transitions/CCTransitionProgress.js b/cocos2d/transitions/CCTransitionProgress.js index 275163c22e..803fe4d20f 100644 --- a/cocos2d/transitions/CCTransitionProgress.js +++ b/cocos2d/transitions/CCTransitionProgress.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -35,6 +35,10 @@ cc.SCENE_RADIAL = 0xc001; * cc.TransitionProgress transition. * @class * @extends cc.TransitionScene + * @param {Number} t time + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionProgress(time,scene); */ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgress# */{ _to:0, @@ -42,6 +46,15 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre _sceneToBeModified:null, _className:"TransitionProgress", + /** + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionScene.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _setAttrs: function(node, x, y) { node.attr({ x: x, @@ -53,6 +66,7 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre /** * @override + * custom on enter */ onEnter:function () { cc.TransitionScene.prototype.onEnter.call(this); @@ -63,7 +77,7 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre var winSize = cc.director.getWinSize(); // create the second render texture for outScene - var texture = cc.RenderTexture.create(winSize.width, winSize.height); + var texture = new cc.RenderTexture(winSize.width, winSize.height); texture.sprite.anchorX = 0.5; texture.sprite.anchorY = 0.5; this._setAttrs(texture, winSize.width / 2, winSize.height / 2); @@ -75,16 +89,16 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre texture.end(); // Since we've passed the outScene to the texture we don't need it. - if (this._sceneToBeModified == this._outScene) + if (this._sceneToBeModified === this._outScene) this.hideOutShowIn(); // We need the texture in RenderTexture. var pNode = this._progressTimerNodeWithRenderTexture(texture); // create the blend action - var layerAction = cc.Sequence.create( - cc.ProgressFromTo.create(this._duration, this._from, this._to), - cc.CallFunc.create(this.finish, this)); + var layerAction = cc.sequence( + cc.progressFromTo(this._duration, this._from, this._to), + cc.callFunc(this.finish, this)); // run the blend action pNode.runAction(layerAction); @@ -94,6 +108,7 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre /** * @override + * custom on exit */ onExit:function () { // remove our layer and release all containing objects @@ -119,17 +134,14 @@ cc.TransitionProgress = cc.TransitionScene.extend(/** @lends cc.TransitionProgre /** * create a cc.TransitionProgress object + * @deprecated since v3.0,please use new cc.TransitionProgress(t, scene) instead. * @function * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgress} */ cc.TransitionProgress.create = function (t, scene) { - var tempScene = new cc.TransitionProgress(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgress(t, scene); }; /** @@ -137,17 +149,31 @@ cc.TransitionProgress.create = function (t, scene) { * A counter clock-wise radial transition to the next scene * @class * @extends cc.TransitionProgress + * @param {Number} t time + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionProgressRadialCCW(t, scene); */ cc.TransitionProgressRadialCCW = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressRadialCCW# */{ + + /** + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_RADIAL; + pNode.type = cc.ProgressTimer.TYPE_RADIAL; // Return the radial type that we want to use pNode.reverseDir = false; @@ -160,17 +186,15 @@ cc.TransitionProgressRadialCCW = cc.TransitionProgress.extend(/** @lends cc.Tran /** * create a cc.TransitionProgressRadialCCW object - * @function + * @deprecated since v3.0,please use new cc.TransitionProgressRadialCCW(t, scene) instead. * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressRadialCCW} + * @example + * var trans = new cc.TransitionProgressRadialCCW(time,scene); */ cc.TransitionProgressRadialCCW.create = function (t, scene) { - var tempScene = new cc.TransitionProgressRadialCCW(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgressRadialCCW(t, scene); }; /** @@ -178,17 +202,30 @@ cc.TransitionProgressRadialCCW.create = function (t, scene) { * A counter colock-wise radial transition to the next scene * @class * @extends cc.TransitionProgress + * @param {Number} t time + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionProgressRadialCW(t, scene); */ cc.TransitionProgressRadialCW = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressRadialCW# */{ + /** + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_RADIAL; + pNode.type = cc.ProgressTimer.TYPE_RADIAL; // Return the radial type that we want to use pNode.reverseDir = true; @@ -201,17 +238,17 @@ cc.TransitionProgressRadialCW = cc.TransitionProgress.extend(/** @lends cc.Trans /** * create a cc.TransitionProgressRadialCW object - * @function + * @deprecated since v3.0,please use cc.TransitionProgressRadialCW(t, scene) instead. * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressRadialCW} */ cc.TransitionProgressRadialCW.create = function (t, scene) { var tempScene = new cc.TransitionProgressRadialCW(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { + if ((tempScene !== null) && (tempScene.initWithDuration(t, scene))) { return tempScene; } - return null; + return new cc.TransitionProgressRadialCW(t, scene); }; /** @@ -219,17 +256,30 @@ cc.TransitionProgressRadialCW.create = function (t, scene) { * A colock-wise radial transition to the next scene * @class * @extends cc.TransitionProgress + * @param {Number} t time + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionProgressHorizontal(t, scene); */ cc.TransitionProgressHorizontal = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressHorizontal# */{ + /** + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_BAR; + pNode.type = cc.ProgressTimer.TYPE_BAR; pNode.midPoint = cc.p(1, 0); pNode.barChangeRate = cc.p(1, 0); @@ -243,34 +293,44 @@ cc.TransitionProgressHorizontal = cc.TransitionProgress.extend(/** @lends cc.Tra /** * create a cc.TransitionProgressHorizontal object - * @function + * @deprecated since v3.0,please use new cc.TransitionProgressHorizontal(t, scene) instead. * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressHorizontal} */ cc.TransitionProgressHorizontal.create = function (t, scene) { - var tempScene = new cc.TransitionProgressHorizontal(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgressHorizontal(t, scene); }; /** * cc.TransitionProgressVertical transition. * @class * @extends cc.TransitionProgress + * @param {Number} t time + * @param {cc.Scene} scene + * @example + * var trans = new cc.TransitionProgressVertical(t, scene); */ cc.TransitionProgressVertical = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressVertical# */{ + + /** + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_BAR; + pNode.type = cc.ProgressTimer.TYPE_BAR; pNode.midPoint = cc.p(0, 0); pNode.barChangeRate = cc.p(0, 1); @@ -284,17 +344,13 @@ cc.TransitionProgressVertical = cc.TransitionProgress.extend(/** @lends cc.Trans /** * create a cc.TransitionProgressVertical object - * @function + * @deprecated since v3.0,please use new cc.TransitionProgressVertical(t, scene) instead. * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressVertical} */ cc.TransitionProgressVertical.create = function (t, scene) { - var tempScene = new cc.TransitionProgressVertical(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgressVertical(t, scene); }; /** @@ -303,14 +359,25 @@ cc.TransitionProgressVertical.create = function (t, scene) { * @extends cc.TransitionProgress */ cc.TransitionProgressInOut = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressInOut# */{ + + /** + * The constructor of cc.TransitionProgressInOut. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_BAR; + pNode.type = cc.ProgressTimer.TYPE_BAR; pNode.midPoint = cc.p(0.5, 0.5); pNode.barChangeRate = cc.p(1, 1); @@ -333,16 +400,13 @@ cc.TransitionProgressInOut = cc.TransitionProgress.extend(/** @lends cc.Transiti /** * create a cc.TransitionProgressInOut object * @function + * @deprecated * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressInOut} */ cc.TransitionProgressInOut.create = function (t, scene) { - var tempScene = new cc.TransitionProgressInOut(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgressInOut(t, scene); }; /** @@ -351,20 +415,31 @@ cc.TransitionProgressInOut.create = function (t, scene) { * @extends cc.TransitionProgress */ cc.TransitionProgressOutIn = cc.TransitionProgress.extend(/** @lends cc.TransitionProgressOutIn# */{ + + /** + * The constructor of cc.TransitionProgressOutIn. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {Number} t time + * @param {cc.Scene} scene + */ + ctor:function (t, scene) { + cc.TransitionProgress.prototype.ctor.call(this); + scene && this.initWithDuration(t, scene); + }, + _progressTimerNodeWithRenderTexture:function (texture) { var size = cc.director.getWinSize(); - var pNode = cc.ProgressTimer.create(texture.sprite); + var pNode = new cc.ProgressTimer(texture.sprite); // but it is flipped upside down so we flip the sprite if (cc._renderType === cc._RENDER_TYPE_WEBGL) pNode.sprite.flippedY = true; - pNode.type = cc.PROGRESS_TIMER_TYPE_BAR; + pNode.type = cc.ProgressTimer.TYPE_BAR; pNode.midPoint = cc.p(0.5, 0.5); pNode.barChangeRate = cc.p(1, 1); pNode.percentage = 100; - this._setAttrs(pNode, winSize.width / 2, winSize.height / 2); + this._setAttrs(pNode, size.width / 2, size.height / 2); return pNode; } @@ -373,14 +448,11 @@ cc.TransitionProgressOutIn = cc.TransitionProgress.extend(/** @lends cc.Transiti /** * create a cc.TransitionProgressOutIn object * @function + * @deprecated * @param {Number} t time * @param {cc.Scene} scene * @return {cc.TransitionProgressOutIn} */ cc.TransitionProgressOutIn.create = function (t, scene) { - var tempScene = new cc.TransitionProgressOutIn(); - if ((tempScene != null) && (tempScene.initWithDuration(t, scene))) { - return tempScene; - } - return null; + return new cc.TransitionProgressOutIn(t, scene); }; diff --git a/extensions/ccb-reader/CCBAnimationManager.js b/extensions/ccb-reader/CCBAnimationManager.js index 17c4b4317a..8952fc9de7 100644 --- a/extensions/ccb-reader/CCBAnimationManager.js +++ b/extensions/ccb-reader/CCBAnimationManager.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -205,7 +205,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ // Move base values var locBaseValues = this._baseValues; var baseValue = locBaseValues.objectForKey(fromNode); - if(baseValue != null) { + if(baseValue !== null) { locBaseValues.setObject(baseValue, toNode); locBaseValues.removeObjectForKey(fromNode); } @@ -231,7 +231,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var timeSinceLastKeyframe = keyframe.getTime() - lastKeyframeTime; lastKeyframeTime = keyframe.getTime(); if(timeSinceLastKeyframe > 0) { - actions.push(cc.DelayTime.create(timeSinceLastKeyframe)); + actions.push(cc.delayTime(timeSinceLastKeyframe)); } var keyVal = keyframe.getValue(); @@ -246,23 +246,21 @@ cc.BuilderAnimationManager = cc.Class.extend({ actions.push(callback); } else { var target; - if(selectorTarget == CCB_TARGETTYPE_DOCUMENTROOT) + if(selectorTarget === CCB_TARGETTYPE_DOCUMENTROOT) target = this._rootNode; - else if (selectorTarget == CCB_TARGETTYPE_OWNER) + else if (selectorTarget === CCB_TARGETTYPE_OWNER) target = this._owner; if(target != null) { if(selectorName.length > 0) { var selCallFunc = 0; - var targetAsCCBSelectorResolver = target; - if(target.onResolveCCBCCCallFuncSelector != null) - selCallFunc = targetAsCCBSelectorResolver.onResolveCCBCCCallFuncSelector(target, selectorName); - if(selCallFunc == 0) + selCallFunc = target.onResolveCCBCCCallFuncSelector(target, selectorName); + if(selCallFunc === 0) cc.log("Skipping selector '" + selectorName + "' since no CCBSelectorResolver is present."); else - actions.push(cc.CallFunc.create(selCallFunc,target)); + actions.push(cc.callFunc(selCallFunc,target)); } else { cc.log("Unexpected empty selector."); } @@ -272,7 +270,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ if(actions.length < 1) return null; - return cc.Sequence.create(actions); + return cc.sequence(actions); }, getActionForSoundChannel:function(channel) { var lastKeyframeTime = 0; @@ -286,7 +284,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var timeSinceLastKeyframe = keyframe.getTime() - lastKeyframeTime; lastKeyframeTime = keyframe.getTime(); if(timeSinceLastKeyframe > 0) { - actions.push(cc.DelayTime.create(timeSinceLastKeyframe)); + actions.push(cc.delayTime(timeSinceLastKeyframe)); } var keyVal = keyframe.getValue(); @@ -298,7 +296,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ if(actions.length < 1) return null; - return cc.Sequence.create(actions); + return cc.sequence(actions); }, runAnimationsForSequenceNamed:function(name){ @@ -342,7 +340,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var baseKeys = nodeBaseValues.allKeys(); for(j = 0; j < baseKeys.length;j++){ var selBaseKey = baseKeys[j]; - if(seqNodePropNames.indexOf(selBaseKey) == -1){ + if(seqNodePropNames.indexOf(selBaseKey) === -1){ var value = nodeBaseValues.objectForKey(selBaseKey); if(value != null) this._setAnimatedProperty(selBaseKey,node, value, tweenDuration); @@ -353,8 +351,8 @@ cc.BuilderAnimationManager = cc.Class.extend({ // Make callback at end of sequence var seq = this._getSequence(nSeqId); - var completeAction = cc.Sequence.create(cc.DelayTime.create(seq.getDuration() + tweenDuration), - cc.CallFunc.create(this._sequenceCompleted,this)); + var completeAction = cc.sequence(cc.delayTime(seq.getDuration() + tweenDuration), + cc.callFunc(this._sequenceCompleted,this)); this._rootNode.runAction(completeAction); // Playback callbacks and sounds @@ -381,7 +379,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ runAnimations:function (name, tweenDuration) { tweenDuration = tweenDuration || 0; var nSeqId; - if(typeof(name) === "string") + if(cc.isString(name)) nSeqId = this._getSequenceId(name); else nSeqId = name; @@ -444,19 +442,19 @@ cc.BuilderAnimationManager = cc.Class.extend({ } else if (propName === "rotationY") { return cc.BuilderRotateYTo.create(duration, keyframe1.getValue()); } else if (propName === "opacity") { - return cc.FadeTo.create(duration, keyframe1.getValue()); + return cc.fadeTo(duration, keyframe1.getValue()); } else if (propName === "color") { var selColor = keyframe1.getValue().getColor(); - return cc.TintTo.create(duration, selColor.r, selColor.g, selColor.b); + return cc.tintTo(duration, selColor.r, selColor.g, selColor.b); } else if (propName === "visible") { var isVisible = keyframe1.getValue(); if (isVisible) { - return cc.Sequence.create(cc.DelayTime.create(duration), cc.Show.create()); + return cc.sequence(cc.delayTime(duration), cc.show()); } else { - return cc.Sequence.create(cc.DelayTime.create(duration), cc.Hide.create()); + return cc.sequence(cc.delayTime(duration), cc.hide()); } } else if (propName === "displayFrame") { - return cc.Sequence.create(cc.DelayTime.create(duration), cc.BuilderSetSpriteFrame.create(keyframe1.getValue())); + return cc.sequence(cc.delayTime(duration), cc.BuilderSetSpriteFrame.create(keyframe1.getValue())); } else if(propName === "position"){ getArr = this._getBaseValue(node,propName); type = getArr[2]; @@ -470,7 +468,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var absPos = cc._getAbsolutePosition(x,y, type,containerSize,propName); - return cc.MoveTo.create(duration,absPos); + return cc.moveTo(duration,absPos); } else if( propName === "scale"){ getArr = this._getBaseValue(node,propName); type = getArr[2]; @@ -487,13 +485,13 @@ cc.BuilderAnimationManager = cc.Class.extend({ y *= resolutionScale; } - return cc.ScaleTo.create(duration,x,y); + return cc.scaleTo(duration,x,y); } else if( propName === "skew") { //get relative position getValueArr = keyframe1.getValue(); x = getValueArr[0]; y = getValueArr[1]; - return cc.SkewTo.create(duration,x,y); + return cc.skewTo(duration,x,y); } else { cc.log("BuilderReader: Failed to create animation for property: " + propName); } @@ -539,7 +537,13 @@ cc.BuilderAnimationManager = cc.Class.extend({ // TODO only handle rotation, opacity, displayFrame, color if(propName === "rotation"){ node.setRotation(value); - } else if(propName === "opacity"){ + } else if(propName === "rotationX") + { + node.setRotationSkewX(value); + }else if(propName === "rotationY") + { + node.setRotationSkewY(value); + }else if(propName === "opacity"){ node.setOpacity(value); } else if(propName === "displayFrame"){ node.setSpriteFrame(value); @@ -578,29 +582,29 @@ cc.BuilderAnimationManager = cc.Class.extend({ if (easingType === CCB_KEYFRAME_EASING_LINEAR || easingType === CCB_KEYFRAME_EASING_INSTANT ) { return action; } else if (easingType === CCB_KEYFRAME_EASING_CUBIC_IN) { - return cc.EaseIn.create(action, easingOpt); + return action.easing(cc.easeIn(easingOpt)); } else if (easingType === CCB_KEYFRAME_EASING_CUBIC_OUT) { - return cc.EaseOut.create(action, easingOpt); + return action.easing(cc.easeOut(easingOpt)); } else if (easingType === CCB_KEYFRAME_EASING_CUBIC_INOUT) { - return cc.EaseInOut.create(action, easingOpt); + return action.easing(cc.easeInOut(easingOpt)); } else if (easingType === CCB_KEYFRAME_EASING_BACK_IN) { - return cc.EaseBackIn.create(action); + return action.easing(cc.easeBackIn()); } else if (easingType === CCB_KEYFRAME_EASING_BACK_OUT) { - return cc.EaseBackOut.create(action); + return action.easing(cc.easeBackOut()); } else if (easingType === CCB_KEYFRAME_EASING_BACK_INOUT) { - return cc.EaseBackInOut.create(action); + return action.easing(cc.easeBackInOut()); } else if (easingType === CCB_KEYFRAME_EASING_BOUNCE_IN) { - return cc.EaseBounceIn.create(action); + return action.easing(cc.easeBounceIn()); } else if (easingType === CCB_KEYFRAME_EASING_BOUNCE_OUT) { - return cc.EaseBounceOut.create(action); + return action.easing(cc.easeBounceOut()); } else if (easingType === CCB_KEYFRAME_EASING_BOUNCE_INOUT) { - return cc.EaseBounceInOut.create(action); + return action.easing(cc.easeBounceInOut()); } else if (easingType === CCB_KEYFRAME_EASING_ELASTIC_IN) { - return cc.EaseElasticIn.create(action, easingOpt); + return action.easing(cc.easeElasticIn(easingOpt)); } else if (easingType === CCB_KEYFRAME_EASING_ELASTIC_OUT) { - return cc.EaseElasticOut.create(action, easingOpt); + return action.easing(cc.easeElasticOut(easingOpt)); } else if (easingType === CCB_KEYFRAME_EASING_ELASTIC_INOUT) { - return cc.EaseElasticInOut.create(action, easingOpt); + return action.easing(cc.easeElasticInOut(easingOpt)); } else { cc.log("BuilderReader: Unkown easing type " + easingType); return action; @@ -619,7 +623,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var timeFirst = keyframeFirst.getTime() + tweenDuration; if (timeFirst > 0) { - actions.push(cc.DelayTime.create(timeFirst)); + actions.push(cc.delayTime(timeFirst)); } for (var i = 0; i < numKeyframes - 1; ++i) { @@ -634,8 +638,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ } } - var seq = cc.Sequence.create(actions); - node.runAction(seq); + node.runAction(cc.sequence(actions)); } }, @@ -651,7 +654,7 @@ cc.BuilderAnimationManager = cc.Class.extend({ var nextSeqId = locRunningSequence.getChainedSequenceId(); this._runningSequence = null; - if (nextSeqId != -1) + if (nextSeqId !== -1) this.runAnimations(nextSeqId, 0); if (this._delegate) diff --git a/extensions/ccb-reader/CCBKeyframe.js b/extensions/ccb-reader/CCBKeyframe.js index 57da466e85..c3eb7afaeb 100644 --- a/extensions/ccb-reader/CCBKeyframe.js +++ b/extensions/ccb-reader/CCBKeyframe.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/extensions/ccb-reader/CCBReader.js b/extensions/ccb-reader/CCBReader.js index 98636f9c47..657f68f607 100644 --- a/extensions/ccb-reader/CCBReader.js +++ b/extensions/ccb-reader/CCBReader.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -159,7 +159,7 @@ cc.BuilderReader = cc.Class.extend({ this._currentBit = -1; this._currentByte = -1; - if (arguments.length != 0) { + if (arguments.length !== 0) { if (ccNodeLoaderLibrary instanceof cc.BuilderReader) { var ccbReader = ccNodeLoaderLibrary; @@ -222,7 +222,7 @@ cc.BuilderReader = cc.Class.extend({ if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { req.setRequestHeader("Accept-Charset", "x-user-defined"); req.send(null); - if (req.status != 200) { + if (req.status !== 200) { cc.log(errInfo); return null; } @@ -236,7 +236,7 @@ cc.BuilderReader = cc.Class.extend({ if (req.overrideMimeType) req.overrideMimeType('text\/plain; charset=x-user-defined'); req.send(null); - if (req.status != 200) { + if (req.status !== 200) { cc.log(errInfo); return null; } @@ -280,7 +280,7 @@ cc.BuilderReader = cc.Class.extend({ var nodeGraph = this.readFileWithCleanUp(true); - if (nodeGraph && locAnimationManager.getAutoPlaySequenceId() != -1) { + if (nodeGraph && locAnimationManager.getAutoPlaySequenceId() !== -1) { //auto play animations locAnimationManager.runAnimations(locAnimationManager.getAutoPlaySequenceId(), 0); } @@ -305,7 +305,7 @@ cc.BuilderReader = cc.Class.extend({ createSceneWithNodeGraphFromFile:function (ccbFileName, owner, parentSize, animationManager) { var node = this.readNodeGraphFromFile(ccbFileName, owner, parentSize, animationManager); - var scene = cc.Scene.create(); + var scene = new cc.Scene(); scene.addChild(node); return scene; }, @@ -376,7 +376,7 @@ cc.BuilderReader = cc.Class.extend({ }, readBool:function () { - return (0 != this.readByte()); + return (0 !== this.readByte()); }, readFloat:function () { @@ -428,7 +428,7 @@ cc.BuilderReader = cc.Class.extend({ this._currentByte += size; - return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity + return exponent === (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand : Math.pow(2, exponent - bias) * (1 + significand) : 0); }, @@ -458,7 +458,7 @@ cc.BuilderReader = cc.Class.extend({ }, _shl:function (a, b) { - for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) === 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); return a; }, @@ -669,34 +669,34 @@ cc.BuilderReader = cc.Class.extend({ keyframe.setEasingType(easingType); keyframe.setEasingOpt(easingOpt); - if (type == CCB_PROPTYPE_CHECK) { + if (type === CCB_PROPTYPE_CHECK) { value = this.readBool(); - } else if (type == CCB_PROPTYPE_BYTE) { + } else if (type === CCB_PROPTYPE_BYTE) { value = this.readByte(); - } else if (type == CCB_PROPTYPE_COLOR3) { + } else if (type === CCB_PROPTYPE_COLOR3) { var c = cc.color(this.readByte(), this.readByte(), this.readByte()); value = cc.Color3BWapper.create(c); - } else if (type == CCB_PROPTYPE_FLOATXY) { + } else if (type === CCB_PROPTYPE_FLOATXY) { value = [this.readFloat(), this.readFloat()]; - } else if (type == CCB_PROPTYPE_DEGREES) { + } else if (type === CCB_PROPTYPE_DEGREES) { value = this.readFloat(); - } else if (type == CCB_PROPTYPE_SCALELOCK || type == CCB_PROPTYPE_POSITION || type == CCB_PROPTYPE_FLOATXY) { + } else if (type === CCB_PROPTYPE_SCALELOCK || type === CCB_PROPTYPE_POSITION || type === CCB_PROPTYPE_FLOATXY) { value = [this.readFloat(), this.readFloat()]; - } else if (type == CCB_PROPTYPE_SPRITEFRAME) { + } else if (type === CCB_PROPTYPE_SPRITEFRAME) { var spriteSheet = this.readCachedString(); var spriteFile = this.readCachedString(); - if (spriteSheet == "") { + if (spriteSheet === "") { spriteFile = this._ccbRootPath + spriteFile; var texture = cc.textureCache.addImage(spriteFile); var locContentSize = texture.getContentSize(); var bounds = cc.rect(0, 0, locContentSize.width, locContentSize.height); - value = cc.SpriteFrame.create(texture, bounds); + value = new cc.SpriteFrame(texture, bounds); } else { spriteSheet = this._ccbRootPath + spriteSheet; var frameCache = cc.spriteFrameCache; // Load the sprite sheet only if it is not loaded - if (this._loadedSpriteSheets.indexOf(spriteSheet) == -1) { + if (this._loadedSpriteSheets.indexOf(spriteSheet) === -1) { frameCache.addSpriteFrames(spriteSheet); this._loadedSpriteSheets.push(spriteSheet); } @@ -709,21 +709,20 @@ cc.BuilderReader = cc.Class.extend({ _readHeader:function () { /* If no bytes loaded, don't crash about it. */ - if (this._data == null) { + if (!this._data) return false; - } /* Read magic bytes */ var magicBytes = this._readStringFromBytes(this._currentByte, 4, true); this._currentByte += 4; - if (magicBytes != 'ccbi') { + if (magicBytes !== 'ccbi') { return false; } /* Read version. */ var version = this.readInt(false); - if (version != CCB_VERSION) { + if (version !== CCB_VERSION) { cc.log("WARNING! Incompatible ccbi file version (file: " + version + " reader: " + CCB_VERSION + ")"); return false; } @@ -783,7 +782,7 @@ cc.BuilderReader = cc.Class.extend({ var memberVarAssignmentType = this.readInt(false); var memberVarAssignmentName; - if (memberVarAssignmentType != CCB_TARGETTYPE_NONE) { + if (memberVarAssignmentType !== CCB_TARGETTYPE_NONE) { memberVarAssignmentName = this.readCachedString(); } @@ -799,7 +798,7 @@ cc.BuilderReader = cc.Class.extend({ if (!locActionManager.getRootNode()) locActionManager.setRootNode(node); - if (locJsControlled && node == locActionManager.getRootNode()) { + if (locJsControlled && node === locActionManager.getRootNode()) { locActionManager.setDocumentControllerName(jsControlledName); } @@ -855,7 +854,7 @@ cc.BuilderReader = cc.Class.extend({ node = embeddedNode; } var target = null, locMemberAssigner = null; - if (memberVarAssignmentType != CCB_TARGETTYPE_NONE) { + if (memberVarAssignmentType !== CCB_TARGETTYPE_NONE) { if (!locJsControlled) { if (memberVarAssignmentType === CCB_TARGETTYPE_DOCUMENTROOT) { target = locActionManager.getRootNode(); @@ -863,19 +862,19 @@ cc.BuilderReader = cc.Class.extend({ target = this._owner; } - if (target != null) { + if (!target) { var assigned = false; - if (target != null && (target.onAssignCCBMemberVariable)) { + if (target.onAssignCCBMemberVariable) assigned = target.onAssignCCBMemberVariable(target, memberVarAssignmentName, node); - } + locMemberAssigner = this._ccbMemberVariableAssigner; if (!assigned && locMemberAssigner != null && locMemberAssigner.onAssignCCBMemberVariable) { locMemberAssigner.onAssignCCBMemberVariable(target, memberVarAssignmentName, node); } } } else { - if (memberVarAssignmentType == CCB_TARGETTYPE_DOCUMENTROOT) { + if (memberVarAssignmentType === CCB_TARGETTYPE_DOCUMENTROOT) { locActionManager.addDocumentOutletName(memberVarAssignmentName); locActionManager.addDocumentOutletNode(node); } else { @@ -928,15 +927,15 @@ cc.BuilderReader = cc.Class.extend({ }, _getBit:function () { - var bit = (this._data[this._currentByte] & (1 << this._currentBit)) != 0; - + var bit = (this._data[this._currentByte] & (1 << this._currentBit)) !== 0; this._currentBit++; if (this._currentBit >= 8) { this._currentBit = 0; this._currentByte++; + if(this._currentByte > this._data.length) + throw "out of the data bound"; } - return bit; }, @@ -965,7 +964,7 @@ cc.BuilderReader.loadAsScene = function (ccbFilePath, owner, parentSize, ccbRoot var getNode = cc.BuilderReader.load(ccbFilePath, owner, parentSize, ccbRootPath); - var scene = cc.Scene.create(); + var scene = new cc.Scene(); scene.addChild(getNode); return scene; }; @@ -978,7 +977,7 @@ cc.BuilderReader.load = function (ccbFilePath, owner, parentSize, ccbRootPath) { ccbRootPath = ccbRootPath || cc.BuilderReader.getResourcePath(); var reader = new cc.BuilderReader(cc.NodeLoaderLibrary.newDefaultCCNodeLoaderLibrary()); reader.setCCBRootPath(ccbRootPath); - if((ccbFilePath.length < 5)||(ccbFilePath.toLowerCase().lastIndexOf(".ccbi") != ccbFilePath.length - 5)) + if((ccbFilePath.length < 5)||(ccbFilePath.toLowerCase().lastIndexOf(".ccbi") !== ccbFilePath.length - 5)) ccbFilePath = ccbFilePath + ".ccbi"; var node = reader.readNodeGraphFromFile(ccbFilePath, owner, parentSize); @@ -1060,7 +1059,7 @@ cc.BuilderReader.load = function (ccbFilePath, owner, parentSize, ccbRootPath) { controller[outletName] = outletNode; } - if (controller.onDidLoadFromCCB && typeof(controller.onDidLoadFromCCB) == "function") + if (controller.onDidLoadFromCCB && cc.isFunction(controller.onDidLoadFromCCB)) controller.onDidLoadFromCCB(); // Setup timeline callbacks @@ -1071,13 +1070,16 @@ cc.BuilderReader.load = function (ccbFilePath, owner, parentSize, ccbRootPath) { var kfCallbackName = callbackSplit[1]; if (callbackType == 1){ // Document callback - animationManager.setCallFunc(cc.CallFunc.create(controller[kfCallbackName], controller), keyframeCallbacks[j]); + animationManager.setCallFunc(cc.callFunc(controller[kfCallbackName], controller), keyframeCallbacks[j]); } else if (callbackType == 2 && owner) {// Owner callback - animationManager.setCallFunc(cc.CallFunc.create(owner[kfCallbackName], owner), keyframeCallbacks[j]); + animationManager.setCallFunc(cc.callFunc(owner[kfCallbackName], owner), keyframeCallbacks[j]); } } } + //auto play animations + animationManager.runAnimations(animationManager.getAutoPlaySequenceId(), 0); + return node; }; @@ -1092,7 +1094,7 @@ cc.BuilderReader.getResourcePath = function () { cc.BuilderReader.lastPathComponent = function (pathStr) { var slashPos = pathStr.lastIndexOf("/"); - if (slashPos != -1) { + if (slashPos !== -1) { return pathStr.substring(slashPos + 1, pathStr.length - slashPos); } return pathStr; @@ -1100,7 +1102,7 @@ cc.BuilderReader.lastPathComponent = function (pathStr) { cc.BuilderReader.deletePathExtension = function (pathStr) { var dotPos = pathStr.lastIndexOf("."); - if (dotPos != -1) { + if (dotPos !== -1) { return pathStr.substring(0, dotPos); } return pathStr; @@ -1112,7 +1114,7 @@ cc.BuilderReader.toLowerCase = function (sourceStr) { cc.BuilderReader.endsWith = function (sourceStr, ending) { if (sourceStr.length >= ending.length) - return (sourceStr.lastIndexOf(ending) == 0); + return (sourceStr.lastIndexOf(ending) === 0); else return false; }; diff --git a/extensions/ccb-reader/CCBReaderUtil.js b/extensions/ccb-reader/CCBReaderUtil.js index ec327c8533..d3ebcfa821 100644 --- a/extensions/ccb-reader/CCBReaderUtil.js +++ b/extensions/ccb-reader/CCBReaderUtil.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/extensions/ccb-reader/CCBRelativePositioning.js b/extensions/ccb-reader/CCBRelativePositioning.js index b314bab304..53c7e901a9 100644 --- a/extensions/ccb-reader/CCBRelativePositioning.js +++ b/extensions/ccb-reader/CCBRelativePositioning.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/extensions/ccb-reader/CCBSequence.js b/extensions/ccb-reader/CCBSequence.js index b991c48e4b..a1bc0e2734 100644 --- a/extensions/ccb-reader/CCBSequence.js +++ b/extensions/ccb-reader/CCBSequence.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/extensions/ccb-reader/CCBValue.js b/extensions/ccb-reader/CCBValue.js index c8f028f0c7..781c25d861 100644 --- a/extensions/ccb-reader/CCBValue.js +++ b/extensions/ccb-reader/CCBValue.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -76,12 +76,6 @@ cc.BuilderValue = cc.Class.extend({ }); cc.BuilderValue.create = function (value) { - var ret = new cc.BuilderValue(); - if(ret){ - if(typeof(value) == "number"){ - - } - } - return ret; + return new cc.BuilderValue(); }; diff --git a/extensions/ccb-reader/CCControlLoader.js b/extensions/ccb-reader/CCControlLoader.js index 859f9eceed..901f8509dd 100644 --- a/extensions/ccb-reader/CCControlLoader.js +++ b/extensions/ccb-reader/CCControlLoader.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -31,7 +31,7 @@ cc.BuilderFileLoader = cc.NodeLoader.extend({ return cc.BuilderFile.create(); }, onHandlePropTypeCCBFile:function (node, parent, propertyName, ccbFileNode, ccbReader) { - if (propertyName == PROPERTY_CCBFILE) { + if (propertyName === PROPERTY_CCBFILE) { node.setCCBFileNode(ccbFileNode); } else { cc.NodeLoader.prototype.onHandlePropTypeCCBFile.call(this, node, parent, propertyName, ccbFileNode, ccbReader); @@ -51,16 +51,16 @@ cc.ControlLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReander) { }, onHandlePropTypeBlockCCControl:function (node, parent, propertyName, blockCCControlData, ccbReader) { - if (propertyName == PROPERTY_CCCONTROL) { + if (propertyName === PROPERTY_CCCONTROL) { node.addTargetWithActionForControlEvents(blockCCControlData.target, blockCCControlData.selCCControlHandler, blockCCControlData.controlEvents); } else { cc.NodeLoader.prototype.onHandlePropTypeBlockCCControl.call(this, node, parent, propertyName, blockCCControlData, ccbReader); } }, onHandlePropTypeCheck:function (node, parent, propertyName, check, ccbReader) { - if (propertyName == PROPERTY_ENABLED) { + if (propertyName === PROPERTY_ENABLED) { node.setEnabled(check); - } else if (propertyName == PROPERTY_SELECTED) { + } else if (propertyName === PROPERTY_SELECTED) { node.setSelected(check); } else { cc.NodeLoader.prototype.onHandlePropTypeCheck.call(this, node, parent, propertyName, check, ccbReader); @@ -89,73 +89,73 @@ var PROPERTY_BACKGROUNDSPRITEFRAME_DISABLED = "backgroundSpriteFrame|3"; cc.ControlButtonLoader = cc.ControlLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.ControlButton.create(); + return new cc.ControlButton(); }, onHandlePropTypeCheck:function (node, parent, propertyName, check, ccbReader) { - if (propertyName == PROPERTY_ZOOMONTOUCHDOWN) { + if (propertyName === PROPERTY_ZOOMONTOUCHDOWN) { node.setZoomOnTouchDown(check); } else { cc.ControlLoader.prototype.onHandlePropTypeCheck.call(this, node, parent, propertyName, check, ccbReader); } }, onHandlePropTypeString:function (node, parent, propertyName, stringValue, ccbReader) { - if (propertyName == PROPERTY_TITLE_NORMAL) { + if (propertyName === PROPERTY_TITLE_NORMAL) { node.setTitleForState(stringValue, cc.CONTROL_STATE_NORMAL); - } else if (propertyName == PROPERTY_TITLE_HIGHLIGHTED) { + } else if (propertyName === PROPERTY_TITLE_HIGHLIGHTED) { node.setTitleForState(stringValue, cc.CONTROL_STATE_HIGHLIGHTED); - } else if (propertyName == PROPERTY_TITLE_DISABLED) { + } else if (propertyName === PROPERTY_TITLE_DISABLED) { node.setTitleForState(stringValue, cc.CONTROL_STATE_DISABLED); } else { cc.ControlLoader.prototype.onHandlePropTypeString.call(this, node, parent, propertyName, stringValue, ccbReader); } }, onHandlePropTypeFontTTF:function (node, parent, propertyName, fontTTF, ccbReader) { - if (propertyName == PROPERTY_TITLETTF_NORMAL) { + if (propertyName === PROPERTY_TITLETTF_NORMAL) { node.setTitleTTFForState(fontTTF, cc.CONTROL_STATE_NORMAL); - } else if (propertyName == PROPERTY_TITLETTF_HIGHLIGHTED) { + } else if (propertyName === PROPERTY_TITLETTF_HIGHLIGHTED) { node.setTitleTTFForState(fontTTF, cc.CONTROL_STATE_HIGHLIGHTED); - } else if (propertyName == PROPERTY_TITLETTF_DISABLED) { + } else if (propertyName === PROPERTY_TITLETTF_DISABLED) { node.setTitleTTFForState(fontTTF, cc.CONTROL_STATE_DISABLED); } else { cc.ControlLoader.prototype.onHandlePropTypeFontTTF.call(this, node, parent, propertyName, fontTTF, ccbReader); } }, onHandlePropTypeFloatScale:function (node, parent, propertyName, floatScale, ccbReader) { - if (propertyName == PROPERTY_TITLETTFSIZE_NORMAL) { + if (propertyName === PROPERTY_TITLETTFSIZE_NORMAL) { node.setTitleTTFSizeForState(floatScale, cc.CONTROL_STATE_NORMAL); - } else if (propertyName == PROPERTY_TITLETTFSIZE_HIGHLIGHTED) { + } else if (propertyName === PROPERTY_TITLETTFSIZE_HIGHLIGHTED) { node.setTitleTTFSizeForState(floatScale, cc.CONTROL_STATE_HIGHLIGHTED); - } else if (propertyName == PROPERTY_TITLETTFSIZE_DISABLED) { + } else if (propertyName === PROPERTY_TITLETTFSIZE_DISABLED) { node.setTitleTTFSizeForState(floatScale, cc.CONTROL_STATE_DISABLED); } else { cc.ControlLoader.prototype.onHandlePropTypeFloatScale.call(this, node, parent, propertyName, floatScale, ccbReader); } }, onHandlePropTypePoint:function (node, parent, propertyName, point, ccbReader) { - if (propertyName == PROPERTY_LABELANCHORPOINT) { + if (propertyName === PROPERTY_LABELANCHORPOINT) { node.setLabelAnchorPoint(point); } else { cc.ControlLoader.prototype.onHandlePropTypePoint.call(this, node, parent, propertyName, point, ccbReader); } }, onHandlePropTypeSize:function (node, parent, propertyName, size, ccbReader) { - if (propertyName == PROPERTY_PREFEREDSIZE) { + if (propertyName === PROPERTY_PREFEREDSIZE) { node.setPreferredSize(size); } else { cc.ControlLoader.prototype.onHandlePropTypeSize.call(this, node, parent, propertyName, size, ccbReader); } }, onHandlePropTypeSpriteFrame:function (node, parent, propertyName, spriteFrame, ccbReader) { - if (propertyName == PROPERTY_BACKGROUNDSPRITEFRAME_NORMAL) { + if (propertyName === PROPERTY_BACKGROUNDSPRITEFRAME_NORMAL) { if (spriteFrame != null) { node.setBackgroundSpriteFrameForState(spriteFrame, cc.CONTROL_STATE_NORMAL); } - } else if (propertyName == PROPERTY_BACKGROUNDSPRITEFRAME_HIGHLIGHTED) { + } else if (propertyName === PROPERTY_BACKGROUNDSPRITEFRAME_HIGHLIGHTED) { if (spriteFrame != null) { node.setBackgroundSpriteFrameForState(spriteFrame, cc.CONTROL_STATE_HIGHLIGHTED); } - } else if (propertyName == PROPERTY_BACKGROUNDSPRITEFRAME_DISABLED) { + } else if (propertyName === PROPERTY_BACKGROUNDSPRITEFRAME_DISABLED) { if (spriteFrame != null) { node.setBackgroundSpriteFrameForState(spriteFrame, cc.CONTROL_STATE_DISABLED); } @@ -164,11 +164,11 @@ cc.ControlButtonLoader = cc.ControlLoader.extend({ } }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { - if (propertyName == PROPERTY_TITLECOLOR_NORMAL) { + if (propertyName === PROPERTY_TITLECOLOR_NORMAL) { node.setTitleColorForState(ccColor3B, cc.CONTROL_STATE_NORMAL); - } else if (propertyName == PROPERTY_TITLECOLOR_HIGHLIGHTED) { + } else if (propertyName === PROPERTY_TITLECOLOR_HIGHLIGHTED) { node.setTitleColorForState(ccColor3B, cc.CONTROL_STATE_HIGHLIGHTED); - } else if (propertyName == PROPERTY_TITLECOLOR_DISABLED) { + } else if (propertyName === PROPERTY_TITLECOLOR_DISABLED) { node.setTitleColorForState(ccColor3B, cc.CONTROL_STATE_DISABLED); } else { cc.ControlLoader.prototype.onHandlePropTypeColor3.call(this, node, parent, propertyName, ccColor3B, ccbReader); @@ -188,11 +188,11 @@ var PROPERTY_SCALE = "scale"; cc.ScrollViewLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.ScrollView.create(); + return new cc.ScrollView(); }, onHandlePropTypeSize:function(node,parent,propertyName,size,ccbReader){ - if(propertyName == PROPERTY_CONTENTSIZE){ + if(propertyName === PROPERTY_CONTENTSIZE){ node.setViewSize(size); }else{ cc.NodeLoader.prototype.onHandlePropTypeSize.call(this, node,parent,propertyName,size,ccbReader); @@ -200,7 +200,7 @@ cc.ScrollViewLoader = cc.NodeLoader.extend({ }, onHandlePropTypeCCBFile:function (node, parent, propertyName, ccbFileNode, ccbReader) { - if (propertyName == PROPERTY_CONTAINER) { + if (propertyName === PROPERTY_CONTAINER) { node.setContainer(ccbFileNode); node.updateInset(); } else { @@ -208,23 +208,23 @@ cc.ScrollViewLoader = cc.NodeLoader.extend({ } }, onHandlePropTypeCheck:function (node, parent, propertyName, check, ccbReader) { - if (propertyName == PROPERTY_CLIPSTOBOUNDS) { + if (propertyName === PROPERTY_CLIPSTOBOUNDS) { node.setClippingToBounds(check); - } else if (propertyName == PROPERTY_BOUNCES) { + } else if (propertyName === PROPERTY_BOUNCES) { node.setBounceable(check); } else { cc.NodeLoader.prototype.onHandlePropTypeCheck.call(this, node, parent, propertyName, check, ccbReader); } }, onHandlePropTypeFloat:function (node, parent, propertyName, floatValue, ccbReader) { - if (propertyName == PROPERTY_SCALE) { + if (propertyName === PROPERTY_SCALE) { node.setScale(floatValue); } else { cc.NodeLoader.prototype.onHandlePropTypeFloat.call(this, node, parent, propertyName, floatValue, ccbReader); } }, onHandlePropTypeIntegerLabeled:function (node, parent, propertyName, integerLabeled, ccbReader) { - if (propertyName == PROPERTY_DIRECTION) { + if (propertyName === PROPERTY_DIRECTION) { node.setDirection(integerLabeled); } else { cc.NodeLoader.prototype.onHandlePropTypeIntegerLabeled.call(this, node, parent, propertyName, integerLabeled, ccbReader); @@ -248,7 +248,7 @@ var PROPERTY_INSETBOTTOM = "insetBottom"; cc.Scale9SpriteLoader = cc.NodeLoader.extend({ _createCCNode:function(parent,ccbReader){ - var sprite = cc.Scale9Sprite.create(); + var sprite = new cc.Scale9Sprite(); sprite.setAnchorPoint(0, 0); @@ -256,7 +256,7 @@ cc.Scale9SpriteLoader = cc.NodeLoader.extend({ }, onHandlePropTypeColor3:function(node, parent, propertyName, ccColor3B,ccbReader){ - if(propertyName == PROPERTY_COLOR) { + if(propertyName === PROPERTY_COLOR) { if(ccColor3B.r !== 255 || ccColor3B.g !== 255 || ccColor3B.b !== 255){ node.setColor(ccColor3B); } @@ -265,14 +265,14 @@ cc.Scale9SpriteLoader = cc.NodeLoader.extend({ } }, onHandlePropTypeByte:function(node, parent, propertyName, byteValue,ccbReader){ - if(propertyName == PROPERTY_OPACITY) { + if(propertyName === PROPERTY_OPACITY) { node.setOpacity(byteValue); } else { cc.NodeLoader.prototype.onHandlePropTypeByte.call(this, node, parent, propertyName, byteValue,ccbReader); } }, onHandlePropTypeBlendFunc:function(node, parent, propertyName, ccBlendFunc,ccbReader){ - if(propertyName == PROPERTY_BLENDFUNC) { + if(propertyName === PROPERTY_BLENDFUNC) { // TODO Not exported by CocosBuilder yet! // node.setBlendFunc(ccBlendFunc); } else { @@ -280,29 +280,29 @@ cc.Scale9SpriteLoader = cc.NodeLoader.extend({ } }, onHandlePropTypeSpriteFrame:function(node, parent, propertyName, spriteFrame,ccbReader){ - if(propertyName == PROPERTY_SPRITEFRAME) { + if(propertyName === PROPERTY_SPRITEFRAME) { node.setSpriteFrame(spriteFrame); } else { cc.NodeLoader.prototype.onHandlePropTypeSpriteFrame.call(this, node, parent, propertyName, spriteFrame,ccbReader); } }, onHandlePropTypeSize:function(node, parent, propertyName, size,ccbReader){ - if(propertyName == PROPERTY_CONTENTSIZE) { + if(propertyName === PROPERTY_CONTENTSIZE) { //node.setContentSize(size); - } else if(propertyName == PROPERTY_PREFEREDSIZE) { + } else if(propertyName === PROPERTY_PREFEREDSIZE) { node.setPreferredSize(size); } else { cc.NodeLoader.prototype.onHandlePropTypeSize.call(this, node, parent, propertyName, size,ccbReader); } }, onHandlePropTypeFloat:function(node, parent, propertyName, floatValue,ccbReader){ - if(propertyName == PROPERTY_INSETLEFT) { + if(propertyName === PROPERTY_INSETLEFT) { node.setInsetLeft(floatValue); - } else if(propertyName == PROPERTY_INSETTOP) { + } else if(propertyName === PROPERTY_INSETTOP) { node.setInsetTop(floatValue); - } else if(propertyName == PROPERTY_INSETRIGHT) { + } else if(propertyName === PROPERTY_INSETRIGHT) { node.setInsetRight(floatValue); - } else if(propertyName == PROPERTY_INSETBOTTOM) { + } else if(propertyName === PROPERTY_INSETBOTTOM) { node.setInsetBottom(floatValue); } else { cc.NodeLoader.prototype.onHandlePropTypeFloat.call(this, node, parent, propertyName, floatValue,ccbReader); diff --git a/extensions/ccb-reader/CCNodeLoader.js b/extensions/ccb-reader/CCNodeLoader.js index 4a2da84488..67b575f41a 100644 --- a/extensions/ccb-reader/CCNodeLoader.js +++ b/extensions/ccb-reader/CCNodeLoader.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -89,9 +89,9 @@ cc.NodeLoader = cc.Class.extend({ node = node.getCCBFileNode(); //skip properties that doesn't have a value to override var getExtraPropsNames = node.userObject; - setProp = getExtraPropsNames.indexOf(propertyName) != -1; + setProp = getExtraPropsNames.indexOf(propertyName) !== -1; } - } else if(isExtraProp && node == ccbReader.getAnimationManager().getRootNode()){ + } else if(isExtraProp && node === ccbReader.getAnimationManager().getRootNode()){ var extraPropsNames = node.userObject; if(!extraPropsNames){ extraPropsNames = []; @@ -332,7 +332,7 @@ cc.NodeLoader = cc.Class.extend({ }, _createCCNode:function (parent, ccbReader) { - return cc.Node.create(); + return new cc.Node(); }, parsePropTypePosition:function (node, parent, ccbReader, propertyName) { @@ -418,7 +418,7 @@ cc.NodeLoader = cc.Class.extend({ ccbReader.getAnimationManager().setBaseValue([x,y,type],node,propertyName); } - if (type == CCB_SCALETYPE_MULTIPLY_RESOLUTION) { + if (type === CCB_SCALETYPE_MULTIPLY_RESOLUTION) { x *= cc.BuilderReader.getResolutionScale(); y *= cc.BuilderReader.getResolutionScale(); } @@ -443,7 +443,7 @@ cc.NodeLoader = cc.Class.extend({ var type = ccbReader.readInt(false); - if (type == CCB_SCALETYPE_MULTIPLY_RESOLUTION) { + if (type === CCB_SCALETYPE_MULTIPLY_RESOLUTION) { f *= cc.BuilderReader.getResolutionScale(); } @@ -477,19 +477,19 @@ cc.NodeLoader = cc.Class.extend({ var spriteFile = ccbReader.readCachedString(); var spriteFrame; - if(spriteFile != null && spriteFile.length != 0){ - if(spriteSheet.length == 0){ + if(spriteFile != null && spriteFile.length !== 0){ + if(spriteSheet.length === 0){ spriteFile = ccbReader.getCCBRootPath() + spriteFile; var texture = cc.textureCache.addImage(spriteFile); var locContentSize = texture.getContentSize(); var bounds = cc.rect(0, 0, locContentSize.width, locContentSize.height); - spriteFrame = cc.SpriteFrame.create(texture, bounds); + spriteFrame = new cc.SpriteFrame(texture, bounds); } else { var frameCache = cc.spriteFrameCache; spriteSheet = ccbReader.getCCBRootPath() + spriteSheet; //load the sprite sheet only if it is not loaded - if(ccbReader.getLoadedSpriteSheet().indexOf(spriteSheet) == -1){ + if(ccbReader.getLoadedSpriteSheet().indexOf(spriteSheet) === -1){ frameCache.addSpriteFrames(spriteSheet); ccbReader.getLoadedSpriteSheet().push(spriteSheet); } @@ -517,7 +517,7 @@ cc.NodeLoader = cc.Class.extend({ animation = cc.BuilderReader.lastPathComponent(animation); animationFile = cc.BuilderReader.lastPathComponent(animationFile); - if (animation != null && animation != "") { + if (animation != null && animation !== "") { var animationCache = cc.animationCache; animationCache.addAnimations(animationFile); @@ -529,7 +529,7 @@ cc.NodeLoader = cc.Class.extend({ parsePropTypeTexture:function (node, parent, ccbReader) { var spriteFile = ccbReader.getCCBRootPath() + ccbReader.readCachedString(); - if(spriteFile != "") + if(spriteFile !== "") return cc.textureCache.addImage(spriteFile); return null; }, @@ -624,21 +624,21 @@ cc.NodeLoader = cc.Class.extend({ target = ccbReader.getOwner(); } - if (target != null) { + if (target !== null) { if (selectorName.length > 0) { var selMenuHandler = 0; //var targetAsCCBSelectorResolver = target; - if (target != null && target.onResolveCCBCCMenuItemSelector) + if (target.onResolveCCBCCMenuItemSelector) selMenuHandler = target.onResolveCCBCCMenuItemSelector(target, selectorName); - if (selMenuHandler == 0) { + if (selMenuHandler === 0) { var ccbSelectorResolver = ccbReader.getCCBSelectorResolver(); if (ccbSelectorResolver != null) selMenuHandler = ccbSelectorResolver.onResolveCCBCCMenuItemSelector(target, selectorName); } - if (selMenuHandler == 0) { + if (selMenuHandler === 0) { cc.log("Skipping selector '" +selectorName+ "' since no CCBSelectorResolver is present."); } else { return new BlockData(selMenuHandler,target); @@ -672,27 +672,27 @@ cc.NodeLoader = cc.Class.extend({ if (selectorTarget !== CCB_TARGETTYPE_NONE) { if(!ccbReader.isJSControlled()){ var target = null; - if (selectorTarget == CCB_TARGETTYPE_DOCUMENTROOT) { + if (selectorTarget === CCB_TARGETTYPE_DOCUMENTROOT) { target = ccbReader.getAnimationManager().getRootNode(); - } else if (selectorTarget == CCB_TARGETTYPE_OWNER) { + } else if (selectorTarget === CCB_TARGETTYPE_OWNER) { target = ccbReader.getOwner(); } - if (target != null) { + if (target !== null) { if (selectorName.length > 0) { var selCCControlHandler = 0; - if (target != null && target.onResolveCCBCCControlSelector) { + if (target.onResolveCCBCCControlSelector) { selCCControlHandler = target.onResolveCCBCCControlSelector(target, selectorName); } - if (selCCControlHandler == 0) { + if (selCCControlHandler === 0) { var ccbSelectorResolver = ccbReader.getCCBSelectorResolver(); if (ccbSelectorResolver != null) { selCCControlHandler = ccbSelectorResolver.onResolveCCBCCControlSelector(target, selectorName); } } - if (selCCControlHandler == 0) { + if (selCCControlHandler === 0) { cc.log("Skipping selector '" + selectorName + "' since no CCBSelectorResolver is present."); } else { return new BlockCCControlData(selCCControlHandler,target,controlEvents); @@ -704,7 +704,7 @@ cc.NodeLoader = cc.Class.extend({ cc.log("Unexpected NULL target for selector."); } } else { - if(selectorTarget == CCB_TARGETTYPE_DOCUMENTROOT){ + if(selectorTarget === CCB_TARGETTYPE_DOCUMENTROOT){ ccbReader.addDocumentCallbackNode(node); ccbReader.addDocumentCallbackName(selectorName); ccbReader.addDocumentCallbackControlEvents(controlEvents); @@ -740,10 +740,9 @@ cc.NodeLoader = cc.Class.extend({ myCCBReader.getAnimationManager().setOwner(ccbReader.getOwner()); var ccbFileNode = myCCBReader.readFileWithCleanUp(false); - ccbReader.setAnimationManagers(myCCBReader.getAnimationManagers()); - if(ccbFileNode && myCCBReader.getAnimationManager().getAutoPlaySequenceId() != -1) + if(ccbFileNode && myCCBReader.getAnimationManager().getAutoPlaySequenceId() !== -1) myCCBReader.getAnimationManager().runAnimations(myCCBReader.getAnimationManager().getAutoPlaySequenceId(),0); return ccbFileNode; diff --git a/extensions/ccb-reader/CCNodeLoaderLibrary.js b/extensions/ccb-reader/CCNodeLoaderLibrary.js index 85a6b4cbfb..487dc7b2fe 100644 --- a/extensions/ccb-reader/CCNodeLoaderLibrary.js +++ b/extensions/ccb-reader/CCNodeLoaderLibrary.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org diff --git a/extensions/ccb-reader/CCSpriteLoader.js b/extensions/ccb-reader/CCSpriteLoader.js index 13c0ceaee6..857b2bb025 100644 --- a/extensions/ccb-reader/CCSpriteLoader.js +++ b/extensions/ccb-reader/CCSpriteLoader.js @@ -1,7 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -32,7 +32,7 @@ var PROPERTY_BLENDFUNC = "blendFunc"; cc.SpriteLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.Sprite.create(); + return new cc.Sprite(); }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { @@ -94,7 +94,7 @@ var PROPERTY_IS_KEYBOARD_ENABLED = "isKeyboardEnabled"; cc.LayerLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - var layer=cc.Layer.create(); + var layer = new cc.Layer(); layer.setContentSize(0,0); @@ -128,7 +128,7 @@ cc.LayerLoader.loader = function () { cc.LayerColorLoader = cc.LayerLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.LayerColor.create(); + return new cc.LayerColor(); }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { @@ -166,12 +166,12 @@ var PROPERTY_VECTOR = "vector"; cc.LayerGradientLoader = cc.LayerLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.LayerGradient.create(); + return new cc.LayerGradient(); }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { if (propertyName === PROPERTY_STARTCOLOR) { node.setStartColor(ccColor3B); - } else if (propertyName == PROPERTY_ENDCOLOR) { + } else if (propertyName === PROPERTY_ENDCOLOR) { node.setEndColor(ccColor3B); } else { cc.LayerLoader.prototype.onHandlePropTypeColor3.call(this, node, parent, propertyName, ccColor3B, ccbReader); @@ -210,7 +210,7 @@ cc.LayerGradientLoader.loader = function () { cc.MenuLoader = cc.LayerLoader.extend({ _createCCNode:function (parent, ccbReader) { - var menu = cc.Menu.create(); + var menu = new cc.Menu(); menu.setContentSize(0,0); @@ -254,7 +254,7 @@ var PROPERTY_DISABLEDDISPLAYFRAME = "disabledSpriteFrame"; cc.MenuItemImageLoader = cc.MenuItemLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.MenuItemImage.create(); + return new cc.MenuItemImage(); }, onHandlePropTypeSpriteFrame:function (node, parent, propertyName, spriteFrame, ccbReader) { @@ -289,7 +289,7 @@ var PROPERTY_DIMENSIONS = "dimensions"; cc.LabelTTFLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.LabelTTF.create(); + return new cc.LabelTTF(); }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { if (propertyName === PROPERTY_COLOR) { @@ -361,7 +361,7 @@ var PROPERTY_FNTFILE = "fntFile"; cc.LabelBMFontLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.LabelBMFont.create(); + return new cc.LabelBMFont(); }, onHandlePropTypeColor3:function (node, parent, propertyName, ccColor3B, ccbReader) { @@ -429,7 +429,7 @@ var PROPERTY_ROTATEPERSECOND = "rotatePerSecond"; cc.ParticleSystemLoader = cc.NodeLoader.extend({ _createCCNode:function (parent, ccbReader) { - return cc.ParticleSystem.create(); + return new cc.ParticleSystem(); }, onHandlePropTypeIntegerLabeled:function (node, parent, propertyName, integerLabeled, ccbReader) { diff --git a/extensions/ccpool/CCPool.js b/extensions/ccpool/CCPool.js new file mode 100644 index 0000000000..205c8a2295 --- /dev/null +++ b/extensions/ccpool/CCPool.js @@ -0,0 +1,146 @@ +/**************************************************************************** + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + *

    + * cc.pool is a singleton object serves as an object cache pool.
    + * It can helps you to improve your game performance for objects which need frequent release and recreate operations
    + * Some common use case is : + * 1. Bullets in game (die very soon, massive creation and recreation, no side effect on other objects) + * 2. Blocks in candy crash (massive creation and recreation) + * etc... + *

    + * + * @example + * var sp = new cc.Sprite("a.png"); + * this.addChild(sp); + * cc.pool.putInPool(sp); + * + * cc.pool.getFromPool(cc.Sprite, "a.png"); + * @class + * @name cc.pool + */ +cc.pool = /** @lends cc.pool# */{ + _pool: {}, + + _releaseCB: function () { + this.release(); + }, + + _autoRelease: function (obj) { + var running = obj._running === undefined ? false : !obj._running; + cc.director.getScheduler().schedule(this._releaseCB, obj, 0, 0, 0, running) + }, + + /** + * Put the obj in pool + * @param obj + */ + putInPool: function (obj) { + var pid = obj.constructor.prototype.__pid; + if (!pid) { + var desc = { writable: true, enumerable: false, configurable: true }; + desc.value = ClassManager.getNewID(); + Object.defineProperty(obj.constructor.prototype, '__pid', desc); + } + if (!this._pool[pid]) { + this._pool[pid] = []; + } + // JSB retain to avoid being auto released + obj.retain && obj.retain(); + // User implementation for disable the object + obj.unuse && obj.unuse(); + this._pool[pid].push(obj); + }, + + /** + * Check if this kind of obj has already in pool + * @param objClass + * @returns {boolean} if this kind of obj is already in pool return true,else return false; + */ + hasObject: function (objClass) { + var pid = objClass.prototype.__pid; + var list = this._pool[pid]; + if (!list || list.length === 0) { + return false; + } + return true; + }, + + /** + * Remove the obj if you want to delete it; + * @param obj + */ + removeObject: function (obj) { + var pid = obj.constructor.prototype.__pid; + if (pid) { + var list = this._pool[pid]; + if (list) { + for (var i = 0; i < list.length; i++) { + if (obj === list[i]) { + // JSB release to avoid memory leak + obj.release && obj.release(); + list.splice(i, 1); + } + } + } + } + }, + + /** + * Get the obj from pool + * @param args + * @returns {*} call the reuse function an return the obj + */ + getFromPool: function (objClass/*,args*/) { + if (this.hasObject(objClass)) { + var pid = objClass.prototype.__pid; + var list = this._pool[pid]; + var args = Array.prototype.slice.call(arguments); + args.shift(); + var obj = list.pop(); + // User implementation for re-enable the object + obj.reuse && obj.reuse.apply(obj, args); + // JSB release to avoid memory leak + cc.sys.isNative && obj.release && this._autoRelease(obj); + return obj; + } + }, + + /** + * remove all objs in pool and reset the pool + */ + drainAllPools: function () { + for (var i in this._pool) { + for (var j = 0; j < this._pool[i].length; j++) { + var obj = this._pool[i][j]; + // JSB release to avoid memory leak + obj.release && obj.release(); + } + } + this._pool = {}; + } +}; \ No newline at end of file diff --git a/extensions/ccui/base-classes/CCProtectedNode.js b/extensions/ccui/base-classes/CCProtectedNode.js new file mode 100644 index 0000000000..ad1e3c8f90 --- /dev/null +++ b/extensions/ccui/base-classes/CCProtectedNode.js @@ -0,0 +1,305 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * A class inhert from cc.Node, use for saving some protected children in other list. + * @class + * @extends cc.Node + */ +cc.ProtectedNode = cc.Node.extend(/** @lends cc.ProtectedNode# */{ + _protectedChildren: null, + _reorderProtectedChildDirty: false, + + _insertProtectedChild: function(child, z){ + this._reorderProtectedChildDirty = true; + this._protectedChildren.push(child); + child._setLocalZOrder(z); + }, + + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @function + */ + ctor: function(){ + cc.Node.prototype.ctor.call(this); + this._protectedChildren = []; + }, + + /** + *

    + * Adds a child to the container with z order and tag
    + * If the child is added to a 'running' node, then 'onEnter' and 'onEnterTransitionDidFinish' will be called immediately.
    + *

    + * @param {cc.Node} child A child node + * @param {Number} [localZOrder] Z order for drawing priority. Please refer to `setLocalZOrder(int)` + * @param {Number} [tag] An integer to identify the node easily. Please refer to `setTag(int)` + */ + addProtectedChild: function(child, localZOrder, tag){ + cc.assert(child != null, "child must be non-nil"); + cc.assert(!child.parent, "child already added. It can't be added again"); + + localZOrder = localZOrder || child.getLocalZOrder(); + if(tag) + child.setTag(tag); + + this._insertProtectedChild(child, localZOrder); + child.setParent(this); + child.setOrderOfArrival(cc.s_globalOrderOfArrival); + + if(this._running){ + child.onEnter(); + // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter + if(this._isTransitionFinished) + child.onEnterTransitionDidFinish(); + } + if(this._cascadeColorEnabled) + this._renderCmd.setCascadeColorEnabledDirty(); + if (this._cascadeOpacityEnabled) + this._renderCmd.setCascadeOpacityEnabledDirty(); + }, + + /** + * Gets a child from the container with its tag + * @param {Number} tag An identifier to find the child node. + * @return {cc.Node} a Node object whose tag equals to the input parameter + */ + getProtectedChildByTag: function(tag){ + cc.assert(tag !== cc.NODE_TAG_INVALID, "Invalid tag"); + var locChildren = this._protectedChildren; + for(var i = 0, len = locChildren.length; i < len; i++) + if(locChildren.getTag() === tag) + return locChildren[i]; + return null; + }, + + /** + * Removes a child from the container. It will also cleanup all running actions depending on the cleanup parameter. + * @param {cc.Node} child The child node which will be removed. + * @param {Boolean} [cleanup=true] true if all running actions and callbacks on the child node will be cleanup, false otherwise. + */ + removeProtectedChild: function(child, cleanup){ + if(cleanup == null) + cleanup = true; + var locChildren = this._protectedChildren; + if(locChildren.length === 0) + return; + var idx = locChildren.indexOf(child); + if(idx > -1){ + if(this._running){ + child.onExitTransitionDidStart(); + child.onExit(); + } + + // If you don't do cleanup, the child's actions will not get removed and the + // its scheduledSelectors_ dict will not get released! + if (cleanup) + child.cleanup(); + + // set parent nil at the end + child.setParent(null); + locChildren.splice(idx, 1); + } + }, + + /** + * Removes a child from the container by tag value.
    + * It will also cleanup all running actions depending on the cleanup parameter + * @param {Number} tag + * @param {Boolean} [cleanup=true] + */ + removeProtectedChildByTag: function(tag, cleanup){ + cc.assert( tag !== cc.NODE_TAG_INVALID, "Invalid tag"); + + if(cleanup == null) + cleanup = true; + + var child = this.getProtectedChildByTag(tag); + + if (child == null) + cc.log("cocos2d: removeChildByTag(tag = %d): child not found!", tag); + else + this.removeProtectedChild(child, cleanup); + }, + + /** + * Removes all children from the container with a cleanup. + * @see cc.ProtectedNode#removeAllProtectedChildrenWithCleanup + */ + removeAllProtectedChildren: function(){ + this.removeAllProtectedChildrenWithCleanup(true); + }, + + /** + * Removes all children from the container, and do a cleanup to all running actions depending on the cleanup parameter. + * @param {Boolean} [cleanup=true] true if all running actions on all children nodes should be cleanup, false otherwise. + */ + removeAllProtectedChildrenWithCleanup: function(cleanup){ + if(cleanup == null) + cleanup = true; + var locChildren = this._protectedChildren; + // not using detachChild improves speed here + for (var i = 0, len = locChildren.length; i< len; i++) { + var child = locChildren[i]; + // IMPORTANT: + // -1st do onExit + // -2nd cleanup + if(this._running){ + child.onExitTransitionDidStart(); + child.onExit(); + } + + if (cleanup) + child.cleanup(); + // set parent nil at the end + child.setParent(null); + } + locChildren.length = 0; + }, + + /** + * Reorders a child according to a new z value. + * @param {cc.Node} child An already added child node. It MUST be already added. + * @param {Number} localZOrder Z order for drawing priority. Please refer to setLocalZOrder(int) + */ + reorderProtectedChild: function(child, localZOrder){ + cc.assert( child != null, "Child must be non-nil"); + this._reorderProtectedChildDirty = true; + child.setOrderOfArrival(cc.s_globalOrderOfArrival++); + child._setLocalZOrder(localZOrder); + }, + + /** + *

    + * Sorts the children array once before drawing, instead of every time when a child is added or reordered.
    + * This approach can improves the performance massively.
    + * @note Don't call this manually unless a child added needs to be removed in the same frame + *

    + */ + sortAllProtectedChildren: function(){ + if (this._reorderProtectedChildDirty) { + var _children = this._protectedChildren; + + // insertion sort + var len = _children.length, i, j, tmp; + for(i=1; i= 0){ + if(tmp._localZOrder < _children[j]._localZOrder){ + _children[j+1] = _children[j]; + }else if(tmp._localZOrder === _children[j]._localZOrder && tmp.arrivalOrder < _children[j].arrivalOrder){ + _children[j+1] = _children[j]; + }else + break; + j--; + } + _children[j+1] = tmp; + } + + //don't need to check children recursively, that's done in visit of each child + this._reorderProtectedChildDirty = false; + } + }, + + _changePosition: function(){}, + + /** + * Stops itself and its children and protected children's all running actions and schedulers + * @override + */ + cleanup: function(){ + cc.Node.prototype.cleanup.call(this); + var locChildren = this._protectedChildren; + for(var i = 0 , len = locChildren.length; i < len; i++) + locChildren[i].cleanup(); + }, + + /** + * Calls its parent's onEnter and calls its protected children's onEnter + * @override + */ + onEnter: function(){ + cc.Node.prototype.onEnter.call(this); + var locChildren = this._protectedChildren; + for(var i = 0, len = locChildren.length;i< len;i++) + locChildren[i].onEnter(); + }, + + /** + *

    + * Event callback that is invoked when the Node enters in the 'stage'.
    + * If the Node enters the 'stage' with a transition, this event is called when the transition finishes.
    + * If you override onEnterTransitionDidFinish, you shall call its parent's one, e.g. Node::onEnterTransitionDidFinish() + *

    + * @override + */ + onEnterTransitionDidFinish: function(){ + cc.Node.prototype.onEnterTransitionDidFinish.call(this); + var locChildren = this._protectedChildren; + for(var i = 0, len = locChildren.length;i< len;i++) + locChildren[i].onEnterTransitionDidFinish(); + }, + + /** + * Calls its parent's onExit and calls its protected children's onExit + * @override + */ + onExit:function(){ + cc.Node.prototype.onExit.call(this); + var locChildren = this._protectedChildren; + for(var i = 0, len = locChildren.length;i< len;i++) + locChildren[i].onExit(); + }, + + /** + *

    + * Event callback that is called every time the Node leaves the 'stage'.
    + * If the Node leaves the 'stage' with a transition, this callback is called when the transition starts. + *

    + */ + onExitTransitionDidStart: function(){ + cc.Node.prototype.onExitTransitionDidStart.call(this); + var locChildren = this._protectedChildren; + for(var i = 0, len = locChildren.length;i< len;i++) + locChildren[i].onExitTransitionDidStart(); + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.ProtectedNode.CanvasRenderCmd(this); + else + return new cc.ProtectedNode.WebGLRenderCmd(this); + } +}); + +/** + * create a cc.ProtectedNode object; + * @deprecated since v3.0, please use new cc.ProtectedNode() instead. + * @return cc.ProtectedNode + */ +cc.ProtectedNode.create = function(){ + return new cc.ProtectedNode(); +}; \ No newline at end of file diff --git a/extensions/ccui/base-classes/CCProtectedNodeCanvasRenderCmd.js b/extensions/ccui/base-classes/CCProtectedNodeCanvasRenderCmd.js new file mode 100644 index 0000000000..c3ecd0bb7d --- /dev/null +++ b/extensions/ccui/base-classes/CCProtectedNodeCanvasRenderCmd.js @@ -0,0 +1,240 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + cc.ProtectedNode.RenderCmd = { + _updateDisplayColor: function (parentColor) { + var node = this._node; + var locDispColor = this._displayedColor, locRealColor = node._realColor; + var i, len, selChildren, item; + if (this._cascadeColorEnabledDirty && !node._cascadeColorEnabled) { + locDispColor.r = locRealColor.r; + locDispColor.g = locRealColor.g; + locDispColor.b = locRealColor.b; + var whiteColor = new cc.Color(255, 255, 255, 255); + selChildren = node._children; + for (i = 0, len = selChildren.length; i < len; i++) { + item = selChildren[i]; + if (item && item._renderCmd) + item._renderCmd._updateDisplayColor(whiteColor); + } + this._cascadeColorEnabledDirty = false; + } else { + if (parentColor === undefined) { + var locParent = node._parent; + if (locParent && locParent._cascadeColorEnabled) + parentColor = locParent.getDisplayedColor(); + else + parentColor = cc.color.WHITE; + } + locDispColor.r = 0 | (locRealColor.r * parentColor.r / 255.0); + locDispColor.g = 0 | (locRealColor.g * parentColor.g / 255.0); + locDispColor.b = 0 | (locRealColor.b * parentColor.b / 255.0); + if (node._cascadeColorEnabled) { + selChildren = node._children; + for (i = 0, len = selChildren.length; i < len; i++) { + item = selChildren[i]; + if (item && item._renderCmd){ + item._renderCmd._updateDisplayColor(locDispColor); + item._renderCmd._updateColor(); + } + } + } + selChildren = node._protectedChildren; + for(i = 0, len = selChildren.length;i < len; i++){ + item = selChildren[i]; + if(item && item._renderCmd){ + item._renderCmd._updateDisplayColor(locDispColor); + item._renderCmd._updateColor(); + } + } + } + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.colorDirty ^ this._dirtyFlag; + }, + + _updateDisplayOpacity: function (parentOpacity) { + var node = this._node; + var i, len, selChildren, item; + if (this._cascadeOpacityEnabledDirty && !node._cascadeOpacityEnabled) { + this._displayedOpacity = node._realOpacity; + selChildren = node._children; + for (i = 0, len = selChildren.length; i < len; i++) { + item = selChildren[i]; + if (item && item._renderCmd) + item._renderCmd._updateDisplayOpacity(255); + } + this._cascadeOpacityEnabledDirty = false; + } else { + if (parentOpacity === undefined) { + var locParent = node._parent; + parentOpacity = 255; + if (locParent && locParent._cascadeOpacityEnabled) + parentOpacity = locParent.getDisplayedOpacity(); + } + this._displayedOpacity = node._realOpacity * parentOpacity / 255.0; + if (node._cascadeOpacityEnabled) { + selChildren = node._children; + for (i = 0, len = selChildren.length; i < len; i++) { + item = selChildren[i]; + if (item && item._renderCmd){ + item._renderCmd._updateDisplayOpacity(this._displayedOpacity); + item._renderCmd._updateColor(); + } + } + } + selChildren = node._protectedChildren; + for(i = 0, len = selChildren.length;i < len; i++){ + item = selChildren[i]; + if(item && item._renderCmd){ + item._renderCmd._updateDisplayOpacity(this._displayedOpacity); + item._renderCmd._updateColor(); + } + } + } + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.opacityDirty ^ this._dirtyFlag; + }, + + _changeProtectedChild: function (child) { + var cmd = child._renderCmd, + dirty = cmd._dirtyFlag, + flags = cc.Node._dirtyFlags; + + if (this._dirtyFlag & flags.colorDirty) + dirty |= flags.colorDirty; + + if (this._dirtyFlag & flags.opacityDirty) + dirty |= flags.opacityDirty; + + var colorDirty = dirty & flags.colorDirty, + opacityDirty = dirty & flags.opacityDirty; + + if (colorDirty) + cmd._updateDisplayColor(this._displayedColor); + if (opacityDirty) + cmd._updateDisplayOpacity(this._displayedOpacity); + if (colorDirty || opacityDirty) + cmd._updateColor(); + } + }; + + cc.ProtectedNode.CanvasRenderCmd = function (renderable) { + cc.Node.CanvasRenderCmd.call(this, renderable); + this._cachedParent = null; + this._cacheDirty = false; + }; + + var proto = cc.ProtectedNode.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + cc.inject(cc.ProtectedNode.RenderCmd, proto); + proto.constructor = cc.ProtectedNode.CanvasRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + + //visit for canvas + var i, j; + var children = node._children, child; + var locChildren = node._children, locProtectedChildren = node._protectedChildren; + var childLen = locChildren.length, pLen = locProtectedChildren.length; + + this._syncStatus(parentCmd); + + node.sortAllChildren(); + node.sortAllProtectedChildren(); + + var pChild; + // draw children zOrder < 0 + for (i = 0; i < childLen; i++) { + child = children[i]; + if (child._localZOrder < 0) + child.visit(this); + else + break; + } + for (j = 0; j < pLen; j++) { + pChild = locProtectedChildren[j]; + if (pChild && pChild._localZOrder < 0){ + this._changeProtectedChild(pChild); + pChild.visit(this); + } + else + break; + } + + cc.renderer.pushRenderCommand(this); + + for (; i < childLen; i++) + children[i] && children[i].visit(this); + for (; j < pLen; j++){ + pChild = locProtectedChildren[j]; + if(!pChild) continue; + this._changeProtectedChild(pChild); + pChild.visit(this); + } + + this._dirtyFlag = 0; + this._cacheDirty = false; + }; + + proto.transform = function(parentCmd, recursive){ + var node = this._node; + + if(node._changePosition) + node._changePosition(); + + var t = node.getNodeToParentTransform(), worldT = this._worldTransform; + if (parentCmd) { + var pt = parentCmd._worldTransform; + // cc.AffineTransformConcat is incorrect at get world transform + worldT.a = t.a * pt.a + t.b * pt.c; //a + worldT.b = t.a * pt.b + t.b * pt.d; //b + worldT.c = t.c * pt.a + t.d * pt.c; //c + worldT.d = t.c * pt.b + t.d * pt.d; //d + + worldT.tx = pt.a * t.tx + pt.c * t.ty + pt.tx; + worldT.ty = pt.d * t.ty + pt.ty + pt.b * t.tx; + } else { + worldT.a = t.a; + worldT.b = t.b; + worldT.c = t.c; + worldT.d = t.d; + worldT.tx = t.tx; + worldT.ty = t.ty; + } + var i, len, locChildren = node._children; + if(recursive && locChildren && locChildren.length !== 0){ + for(i = 0, len = locChildren.length; i< len; i++){ + locChildren[i]._renderCmd.transform(this, recursive); + } + } + locChildren = node._protectedChildren; + if(recursive && locChildren && locChildren.length !== 0){ + for(i = 0, len = locChildren.length; i< len; i++){ + locChildren[i]._renderCmd.transform(this, recursive); + } + } + }; +})(); \ No newline at end of file diff --git a/extensions/ccui/base-classes/CCProtectedNodeWebGLRenderCmd.js b/extensions/ccui/base-classes/CCProtectedNodeWebGLRenderCmd.js new file mode 100644 index 0000000000..0074027217 --- /dev/null +++ b/extensions/ccui/base-classes/CCProtectedNodeWebGLRenderCmd.js @@ -0,0 +1,161 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + if(!cc.Node.WebGLRenderCmd) + return; + cc.ProtectedNode.WebGLRenderCmd = function (renderable) { + cc.Node.WebGLRenderCmd.call(this, renderable); + }; + + var proto = cc.ProtectedNode.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + cc.inject(cc.ProtectedNode.RenderCmd, proto); + proto.constructor = cc.ProtectedNode.WebGLRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible + if (!node._visible) + return; + var i, j, currentStack = cc.current_stack; + + //optimize performance for javascript + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + currentStack.top = this._stackMatrix; + + var locGrid = node.grid; + if (locGrid && locGrid._active) + locGrid.beforeDraw(); + + //node.transform(node._parent && node._parent._renderCmd); + + var locChildren = node._children, locProtectedChildren = node._protectedChildren; + var childLen = locChildren.length, pLen = locProtectedChildren.length; + node.sortAllChildren(); + node.sortAllProtectedChildren(); + + var pChild; + // draw children zOrder < 0 + for (i = 0; i < childLen; i++) { + if (locChildren[i] && locChildren[i]._localZOrder < 0) + locChildren[i].visit(this); + else + break; + } + for(j = 0; j < pLen; j++){ + pChild = locProtectedChildren[j]; + if (pChild && pChild._localZOrder < 0){ + this._changeProtectedChild(pChild); + pChild.visit(this); + }else + break; + } + + cc.renderer.pushRenderCommand(this); + + // draw children zOrder >= 0 + for (; i < childLen; i++) { + locChildren[i] && locChildren[i].visit(this); + } + for (; j < pLen; j++) { + pChild = locProtectedChildren[j]; + if(!pChild) continue; + this._changeProtectedChild(pChild); + pChild.visit(this); + } + + if (locGrid && locGrid._active) + locGrid.afterDraw(node); + + this._dirtyFlag = 0; + //optimize performance for javascript + currentStack.top = currentStack.stack.pop(); + }; + + proto.transform = function(parentCmd, recursive){ + var node = this._node; + var t4x4 = this._transform4x4, stackMatrix = this._stackMatrix, + parentMatrix = parentCmd ? parentCmd._stackMatrix : cc.current_stack.top; + + // Convert 3x3 into 4x4 matrix + var trans = node.getNodeToParentTransform(); + + if(node._changePosition) + node._changePosition(); + + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.transformDirty ^ this._dirtyFlag; + + var t4x4Mat = t4x4.mat; + t4x4Mat[0] = trans.a; + t4x4Mat[4] = trans.c; + t4x4Mat[12] = trans.tx; + t4x4Mat[1] = trans.b; + t4x4Mat[5] = trans.d; + t4x4Mat[13] = trans.ty; + + // Update Z vertex manually + t4x4Mat[14] = node._vertexZ; + + //optimize performance for Javascript + cc.kmMat4Multiply(stackMatrix, parentMatrix, t4x4); + + // XXX: Expensive calls. Camera should be integrated into the cached affine matrix + if (node._camera !== null && !(node.grid !== null && node.grid.isActive())) { + var apx = this._anchorPointInPoints.x, apy = this._anchorPointInPoints.y; + var translate = (apx !== 0.0 || apy !== 0.0); + if (translate){ + if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { + apx = 0 | apx; + apy = 0 | apy; + } + //cc.kmGLTranslatef(apx, apy, 0); + var translation = cc.math.Matrix4.createByTranslation(apx, apy, 0, t4x4); //t4x4 as a temp matrix + stackMatrix.multiply(translate); + + node._camera._locateForRenderer(stackMatrix); + + //cc.kmGLTranslatef(-apx, -apy, 0); + translation = cc.math.Matrix4.createByTranslation(-apx, -apy, 0, translation); + stackMatrix.multiply(translation); + t4x4.identity(); //reset t4x4; + } else { + node._camera._locateForRenderer(stackMatrix); + } + } + + var i, len, locChildren = node._children; + if(recursive && locChildren && locChildren.length !== 0){ + for(i = 0, len = locChildren.length; i< len; i++){ + locChildren[i]._renderCmd.transform(this, recursive); + } + } + locChildren = node._protectedChildren; + if(recursive && locChildren && locChildren.length !== 0){ + for(i = 0, len = locChildren.length; i< len; i++){ + locChildren[i]._renderCmd.transform(this, recursive); + } + } + }; +})(); \ No newline at end of file diff --git a/extensions/ccui/base-classes/UIScale9Sprite.js b/extensions/ccui/base-classes/UIScale9Sprite.js new file mode 100644 index 0000000000..e9afd7b658 --- /dev/null +++ b/extensions/ccui/base-classes/UIScale9Sprite.js @@ -0,0 +1,1107 @@ +/**************************************************************************** + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2012 Neofect. All rights reserved. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + Created by Jung Sang-Taik on 2012-03-16 + ****************************************************************************/ + +/** + *

    + * A 9-slice sprite for cocos2d UI.
    + *
    + * 9-slice scaling allows you to specify how scaling is applied
    + * to specific areas of a sprite. With 9-slice scaling (3x3 grid),
    + * you can ensure that the sprite does not become distorted when
    + * scaled.
    + * @note: it will refactor in v3.1
    + * @see http://yannickloriot.com/library/ios/cccontrolextension/Classes/CCScale9Sprite.html
    + *

    + * @class + * @extends cc.Node + * + * @property {cc.Size} preferredSize - The preferred size of the 9-slice sprite + * @property {cc.Rect} capInsets - The cap insets of the 9-slice sprite + * @property {Number} insetLeft - The left inset of the 9-slice sprite + * @property {Number} insetTop - The top inset of the 9-slice sprite + * @property {Number} insetRight - The right inset of the 9-slice sprite + * @property {Number} insetBottom - The bottom inset of the 9-slice sprite + */ + +//todo checking here. Maybe need synchronous. + +ccui.Scale9Sprite = cc.Node.extend(/** @lends ccui.Scale9Sprite# */{ + _spriteRect: null, + _capInsetsInternal: null, + _positionsAreDirty: false, + + _scale9Image: null, + _topLeft: null, + _top: null, + _topRight: null, + _left: null, + _centre: null, + _right: null, + _bottomLeft: null, + _bottom: null, + _bottomRight: null, + + _scale9Dirty: true, + + _opacityModifyRGB: false, + + _originalSize: null, + _preferredSize: null, + _opacity: 0, + _color: null, + _capInsets: null, + _insetLeft: 0, + _insetTop: 0, + _insetRight: 0, + _insetBottom: 0, + + _spritesGenerated: false, + _spriteFrameRotated: false, + _textureLoaded:false, + _className:"Scale9Sprite", + + //v3.3 + _flippedX: false, + _flippedY: false, + + /** + * return texture is loaded + * @returns {boolean} + */ + textureLoaded:function(){ + return this._textureLoaded; + }, + + /** + * add texture loaded event listener + * @param {Function} callback + * @param {Object} target + * @deprecated since 3.1, please use addEventListener instead + */ + addLoadedEventListener:function(callback, target){ + this.addEventListener("load", callback, target); + }, + + _updateCapInset: function () { + var insets, locInsetLeft = this._insetLeft, locInsetTop = this._insetTop, locInsetRight = this._insetRight; + var locSpriteRect = this._spriteRect, locInsetBottom = this._insetBottom; + if (locInsetLeft === 0 && locInsetTop === 0 && locInsetRight === 0 && locInsetBottom === 0) { + insets = cc.rect(0, 0, 0, 0); + } else { + insets = this._spriteFrameRotated ? cc.rect(locInsetBottom, locInsetLeft, + locSpriteRect.width - locInsetRight - locInsetLeft, + locSpriteRect.height - locInsetTop - locInsetBottom) : + cc.rect(locInsetLeft, locInsetTop, + locSpriteRect.width - locInsetLeft - locInsetRight, + locSpriteRect.height - locInsetTop - locInsetBottom); + } + this.setCapInsets(insets); + }, + + _updatePositions: function () { + // Check that instances are non-NULL + if (!((this._topLeft) && (this._topRight) && (this._bottomRight) && + (this._bottomLeft) && (this._centre))) { + // if any of the above sprites are NULL, return + return; + } + + var size = this._contentSize; + var locTopLeft = this._topLeft, locTopRight = this._topRight, locBottomRight = this._bottomRight, locBottomLeft = this._bottomLeft; + var locCenter = this._centre, locCenterContentSize = this._centre.getContentSize(); + var locTopLeftContentSize = locTopLeft.getContentSize(); + var locBottomLeftContentSize = locBottomLeft.getContentSize(); + + var sizableWidth = size.width - locTopLeftContentSize.width - locTopRight.getContentSize().width; + var sizableHeight = size.height - locTopLeftContentSize.height - locBottomRight.getContentSize().height; + + var horizontalScale = sizableWidth / locCenterContentSize.width; + var verticalScale = sizableHeight / locCenterContentSize.height; + + var rescaledWidth = locCenterContentSize.width * horizontalScale; + var rescaledHeight = locCenterContentSize.height * verticalScale; + + var leftWidth = locBottomLeftContentSize.width; + var bottomHeight = locBottomLeftContentSize.height; + + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { + //browser is in canvas mode, need to manually control rounding to prevent overlapping pixels + var roundedRescaledWidth = Math.round(rescaledWidth); + if (rescaledWidth !== roundedRescaledWidth) { + rescaledWidth = roundedRescaledWidth; + horizontalScale = rescaledWidth / locCenterContentSize.width; + } + var roundedRescaledHeight = Math.round(rescaledHeight); + if (rescaledHeight !== roundedRescaledHeight) { + rescaledHeight = roundedRescaledHeight; + verticalScale = rescaledHeight / locCenterContentSize.height; + } + } + + locCenter.setScaleX(horizontalScale); + locCenter.setScaleY(verticalScale); + + var locLeft = this._left, locRight = this._right, locTop = this._top, locBottom = this._bottom; + var tempAP = cc.p(0, 0); + locBottomLeft.setAnchorPoint(tempAP); + locBottomRight.setAnchorPoint(tempAP); + locTopLeft.setAnchorPoint(tempAP); + locTopRight.setAnchorPoint(tempAP); + locLeft.setAnchorPoint(tempAP); + locRight.setAnchorPoint(tempAP); + locTop.setAnchorPoint(tempAP); + locBottom.setAnchorPoint(tempAP); + locCenter.setAnchorPoint(tempAP); + + // Position corners + locBottomLeft.setPosition(0, 0); + locBottomRight.setPosition(leftWidth + rescaledWidth, 0); + locTopLeft.setPosition(0, bottomHeight + rescaledHeight); + locTopRight.setPosition(leftWidth + rescaledWidth, bottomHeight + rescaledHeight); + + // Scale and position borders + locLeft.setPosition(0, bottomHeight); + locLeft.setScaleY(verticalScale); + locRight.setPosition(leftWidth + rescaledWidth, bottomHeight); + locRight.setScaleY(verticalScale); + locBottom.setPosition(leftWidth, 0); + locBottom.setScaleX(horizontalScale); + locTop.setPosition(leftWidth, bottomHeight + rescaledHeight); + locTop.setScaleX(horizontalScale); + + // Position centre + locCenter.setPosition(leftWidth, bottomHeight); + }, + + /** + * Constructor function. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @function + * @param {string|cc.SpriteFrame} file file name of texture or a SpriteFrame + * @param {cc.Rect} rect + * @param {cc.Rect} capInsets + * @returns {Scale9Sprite} + */ + ctor: function (file, rect, capInsets) { + cc.Node.prototype.ctor.call(this); + this._spriteRect = cc.rect(0, 0, 0, 0); + this._capInsetsInternal = cc.rect(0, 0, 0, 0); + + this._originalSize = cc.size(0, 0); + this._preferredSize = cc.size(0, 0); + this._capInsets = cc.rect(0, 0, 0, 0); + + if(file != undefined){ + if(file instanceof cc.SpriteFrame) + this.initWithSpriteFrame(file, rect); + else{ + var frame = cc.spriteFrameCache.getSpriteFrame(file); + if(frame != null) + this.initWithSpriteFrame(frame, rect); + else + this.initWithFile(file, rect, capInsets); + } + }else{ + this.init(); + } + }, + + getSprite: function () { + return this._scale9Image; + }, + + /** Original sprite's size. */ + getOriginalSize: function () { + return cc.size(this._originalSize); + }, + + //if the preferredSize component is given as -1, it is ignored + getPreferredSize: function () { + return cc.size(this._preferredSize); + }, + _getPreferredWidth: function () { + return this._preferredSize.width; + }, + _getPreferredHeight: function () { + return this._preferredSize.height; + }, + setPreferredSize: function (preferredSize) { + this.setContentSize(preferredSize); + this._preferredSize = preferredSize; + + if (this._positionsAreDirty) { + this._updatePositions(); + this._positionsAreDirty = false; + this._scale9Dirty = true; + } + }, + _setPreferredWidth: function (value) { + this._setWidth(value); + this._preferredSize.width = value; + }, + _setPreferredHeight: function (value) { + this._setHeight(value); + this._preferredSize.height = value; + }, + + /** Opacity: conforms to CCRGBAProtocol protocol */ + setOpacity: function (opacity) { + if(!this._scale9Image) + return; + cc.Node.prototype.setOpacity.call(this, opacity); + var scaleChildren = this._scale9Image.getChildren(); + for (var i = 0; i < scaleChildren.length; i++) { + var selChild = scaleChildren[i]; + if (selChild) + selChild.setOpacity(opacity); + } + this._scale9Dirty = true; + }, + + /** Color: conforms to CCRGBAProtocol protocol */ + setColor: function (color) { + if(!this._scale9Image) + return; + + cc.Node.prototype.setColor.call(this, color); + var scaleChildren = this._scale9Image.getChildren(); + for (var i = 0; i < scaleChildren.length; i++) { + var selChild = scaleChildren[i]; + if (selChild) + selChild.setColor(color); + } + this._scale9Dirty = true; + }, + + getCapInsets: function () { + return cc.rect(this._capInsets); + }, + + setCapInsets: function (capInsets) { + if(!this._scale9Image) + return; + //backup the contentSize + var contentSize = this._contentSize; + var tempWidth = contentSize.width, tempHeight = contentSize.height; + + this.updateWithBatchNode(this._scale9Image, this._spriteRect, this._spriteFrameRotated, capInsets); + //restore the contentSize + this.setContentSize(tempWidth, tempHeight); + }, + + /** + * Gets the left side inset + * @returns {number} + */ + getInsetLeft: function () { + return this._insetLeft; + }, + + /** + * Sets the left side inset + * @param {Number} insetLeft + */ + setInsetLeft: function (insetLeft) { + this._insetLeft = insetLeft; + this._updateCapInset(); + }, + + /** + * Gets the top side inset + * @returns {number} + */ + getInsetTop: function () { + return this._insetTop; + }, + + /** + * Sets the top side inset + * @param {Number} insetTop + */ + setInsetTop: function (insetTop) { + this._insetTop = insetTop; + this._updateCapInset(); + }, + + /** + * Gets the right side inset + * @returns {number} + */ + getInsetRight: function () { + return this._insetRight; + }, + /** + * Sets the right side inset + * @param {Number} insetRight + */ + setInsetRight: function (insetRight) { + this._insetRight = insetRight; + this._updateCapInset(); + }, + + /** + * Gets the bottom side inset + * @returns {number} + */ + getInsetBottom: function () { + return this._insetBottom; + }, + /** + * Sets the bottom side inset + * @param {number} insetBottom + */ + setInsetBottom: function (insetBottom) { + this._insetBottom = insetBottom; + this._updateCapInset(); + }, + + /** + * Sets the untransformed size of the Scale9Sprite. + * @override + * @param {cc.Size|Number} size The untransformed size of the Scale9Sprite or The untransformed size's width of the Scale9Sprite. + * @param {Number} [height] The untransformed size's height of the Scale9Sprite. + */ + setContentSize: function (size, height) { + cc.Node.prototype.setContentSize.call(this, size, height); + this._positionsAreDirty = true; + }, + + _setWidth: function (value) { + cc.Node.prototype._setWidth.call(this, value); + this._positionsAreDirty = true; + }, + + _setHeight: function (value) { + cc.Node.prototype._setHeight.call(this, value); + this._positionsAreDirty = true; + }, + + /** + * Initializes a ccui.Scale9Sprite. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + */ + init: function () { + return this.initWithBatchNode(null, cc.rect(0, 0, 0, 0), false, cc.rect(0, 0, 0, 0)); + }, + + /** + * Initializes a 9-slice sprite with a SpriteBatchNode. + * @param {cc.SpriteBatchNode} batchNode + * @param {cc.Rect} rect + * @param {boolean|cc.Rect} rotated + * @param {cc.Rect} [capInsets] + * @returns {boolean} + */ + initWithBatchNode: function (batchNode, rect, rotated, capInsets) { + if (capInsets === undefined) { + capInsets = rotated; + rotated = false; + } + + if (batchNode) + this.updateWithBatchNode(batchNode, rect, rotated, capInsets); + this.setCascadeColorEnabled(true); + this.setCascadeOpacityEnabled(true); + this.setAnchorPoint(0.5, 0.5); + this._positionsAreDirty = true; + return true; + }, + + /** + * Initializes a 9-slice sprite with a texture file, a delimitation zone and + * with the specified cap insets. + * Once the sprite is created, you can then call its "setContentSize:" method + * to resize the sprite will all it's 9-slice goodness intact. + * It respects the anchorPoint too. + * + * @param {String} file The name of the texture file. + * @param {cc.Rect} rect The rectangle that describes the sub-part of the texture that + * is the whole image. If the shape is the whole texture, set this to the texture's full rect. + * @param {cc.Rect} capInsets The values to use for the cap insets. + */ + initWithFile: function (file, rect, capInsets) { + if (file instanceof cc.Rect) { + file = arguments[1]; + capInsets = arguments[0]; + rect = cc.rect(0, 0, 0, 0); + } else { + rect = rect || cc.rect(0, 0, 0, 0); + capInsets = capInsets || cc.rect(0, 0, 0, 0); + } + + if(!file) + throw "ccui.Scale9Sprite.initWithFile(): file should be non-null"; + + var texture = cc.textureCache.getTextureForKey(file); + if (!texture) { + texture = cc.textureCache.addImage(file); + } + + var locLoaded = texture.isLoaded(); + this._textureLoaded = locLoaded; + if(!locLoaded){ + texture.addEventListener("load", function(sender){ + // the texture is rotated on Canvas render mode, so isRotated always is false. + var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0; + if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height); + var size = sender.getContentSize(); + this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets); + if (restorePreferredSize)this.setPreferredSize(preferredSize); + this._positionsAreDirty = true; + this.dispatchEvent("load"); + }, this); + } + + return this.initWithBatchNode(new cc.SpriteBatchNode(file, 9), rect, false, capInsets); + }, + + /** + * Initializes a 9-slice sprite with an sprite frame and with the specified + * cap insets. + * Once the sprite is created, you can then call its "setContentSize:" method + * to resize the sprite will all it's 9-slice goodness interact. + * It respects the anchorPoint too. + * + * @param spriteFrame The sprite frame object. + * @param capInsets The values to use for the cap insets. + */ + initWithSpriteFrame: function (spriteFrame, capInsets) { + if(!spriteFrame || !spriteFrame.getTexture()) + throw "ccui.Scale9Sprite.initWithSpriteFrame(): spriteFrame should be non-null and its texture should be non-null"; + + capInsets = capInsets || cc.rect(0, 0, 0, 0); + var locLoaded = spriteFrame.textureLoaded(); + this._textureLoaded = locLoaded; + if(!locLoaded){ + spriteFrame.addEventListener("load", function(sender){ + // the texture is rotated on Canvas render mode, so isRotated always is false. + var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0; + if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height); + this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); + if (restorePreferredSize)this.setPreferredSize(preferredSize); + this._positionsAreDirty = true; + this.dispatchEvent("load"); + },this); + } + var batchNode = new cc.SpriteBatchNode(spriteFrame.getTexture(), 9); + // the texture is rotated on Canvas render mode, so isRotated always is false. + return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), capInsets); + }, + + /** + * Initializes a 9-slice sprite with an sprite frame name and with the specified + * cap insets. + * Once the sprite is created, you can then call its "setContentSize:" method + * to resize the sprite will all it's 9-slice goodness interact. + * It respects the anchorPoint too. + * + * @param spriteFrameName The sprite frame name. + * @param capInsets The values to use for the cap insets. + */ + initWithSpriteFrameName: function (spriteFrameName, capInsets) { + if(!spriteFrameName) + throw "ccui.Scale9Sprite.initWithSpriteFrameName(): spriteFrameName should be non-null"; + capInsets = capInsets || cc.rect(0, 0, 0, 0); + + var frame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName); + if (frame == null) { + cc.log("ccui.Scale9Sprite.initWithSpriteFrameName(): can't find the sprite frame by spriteFrameName"); + return false; + } + + return this.initWithSpriteFrame(frame, capInsets); + }, + + /** + * Creates and returns a new sprite object with the specified cap insets. + * You use this method to add cap insets to a sprite or to change the existing + * cap insets of a sprite. In both cases, you get back a new image and the + * original sprite remains untouched. + * + * @param {cc.Rect} capInsets The values to use for the cap insets. + */ + resizableSpriteWithCapInsets: function (capInsets) { + var pReturn = new ccui.Scale9Sprite(); + if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets)) + return pReturn; + return null; + }, + + /** sets the premultipliedAlphaOpacity property. + If set to NO then opacity will be applied as: glColor(R,G,B,opacity); + If set to YES then opacity will be applied as: glColor(opacity, opacity, opacity, opacity ); + Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO + @since v0.8 + */ + setOpacityModifyRGB: function (value) { + if(!this._scale9Image) + return; + this._opacityModifyRGB = value; + var scaleChildren = this._scale9Image.getChildren(); + if (scaleChildren) { + for (var i = 0, len = scaleChildren.length; i < len; i++) + scaleChildren[i].setOpacityModifyRGB(value); + } + }, + + /** returns whether or not the opacity will be applied using glColor(R,G,B,opacity) or glColor(opacity, opacity, opacity, opacity); + @since v0.8 + */ + isOpacityModifyRGB: function () { + return this._opacityModifyRGB; + }, + + /** + * Update the scale9Sprite with a SpriteBatchNode. + * @param {cc.SpriteBatchNode} batchNode + * @param {cc.Rect} originalRect + * @param {boolean} rotated + * @param {cc.Rect} capInsets + * @returns {boolean} + */ + updateWithBatchNode: function (batchNode, originalRect, rotated, capInsets) { + var opacity = this.getOpacity(); + var color = this.getColor(); + var rect = cc.rect(originalRect.x, originalRect.y, originalRect.width, originalRect.height); + + // Release old sprites + this.removeAllChildren(true); + + if (this._scale9Image !== batchNode) + this._scale9Image = batchNode; + + if(!this._scale9Image) + return false; + + var tmpTexture = batchNode.getTexture(); + var locLoaded = tmpTexture.isLoaded(); + this._textureLoaded = locLoaded; + + //this._capInsets = capInsets; + var locCapInsets = this._capInsets; + locCapInsets.x = capInsets.x; + locCapInsets.y = capInsets.y; + locCapInsets.width = capInsets.width; + locCapInsets.height = capInsets.height; + + if(!locLoaded){ + tmpTexture.addEventListener("load", function(sender){ + this._positionsAreDirty = true; + this.dispatchEvent("load"); + },this); + return true; + } + var locScale9Image = this._scale9Image; + locScale9Image.removeAllChildren(true); + + this._spriteFrameRotated = rotated; + + var selTexture = locScale9Image.getTexture(); + + // If there is no given rect + if (cc._rectEqualToZero(rect)) { + // Get the texture size as original + var textureSize = selTexture.getContentSize(); + rect = cc.rect(0, 0, textureSize.width, textureSize.height); + } + + // Set the given rect's size as original size + this._spriteRect = rect; + var locSpriteRect = this._spriteRect; + locSpriteRect.x = rect.x; + locSpriteRect.y = rect.y; + locSpriteRect.width = rect.width; + locSpriteRect.height = rect.height; + + this._originalSize.width = rect.width; + this._originalSize.height = rect.height; + + var locPreferredSize = this._preferredSize; + if(locPreferredSize.width === 0 && locPreferredSize.height === 0){ + locPreferredSize.width = rect.width; + locPreferredSize.height = rect.height; + } + + var locCapInsetsInternal = this._capInsetsInternal; + if(capInsets){ + locCapInsetsInternal.x = capInsets.x; + locCapInsetsInternal.y = capInsets.y; + locCapInsetsInternal.width = capInsets.width; + locCapInsetsInternal.height = capInsets.height; + } + var w = rect.width, h = rect.height; + + // If there is no specified center region + if (cc._rectEqualToZero(locCapInsetsInternal)) { + // CCLog("... cap insets not specified : using default cap insets ..."); + locCapInsetsInternal.x = w / 3; + locCapInsetsInternal.y = h / 3; + locCapInsetsInternal.width = w / 3; + locCapInsetsInternal.height = h / 3; + } + + var left_w = locCapInsetsInternal.x, center_w = locCapInsetsInternal.width, right_w = w - (left_w + center_w); + + var top_h = locCapInsetsInternal.y, center_h = locCapInsetsInternal.height, bottom_h = h - (top_h + center_h); + + // calculate rects + // ... top row + var x = 0.0, y = 0.0; + + // top left + var lefttopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, top_h + 0.5 | 0); + + // top center + x += left_w; + var centertopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, top_h + 0.5 | 0); + + // top right + x += center_w; + var righttopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, top_h + 0.5 | 0); + + // ... center row + x = 0.0; + y = 0.0; + + y += top_h; + // center left + var leftcenterbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, center_h + 0.5 | 0); + + // center center + x += left_w; + var centerbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, center_h + 0.5 | 0); + + // center right + x += center_w; + var rightcenterbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, center_h + 0.5 | 0); + + // ... bottom row + x = 0.0; + y = 0.0; + y += top_h; + y += center_h; + + // bottom left + var leftbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, bottom_h + 0.5 | 0); + + // bottom center + x += left_w; + var centerbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, bottom_h + 0.5 | 0); + + // bottom right + x += center_w; + var rightbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, bottom_h + 0.5 | 0); + + var t = cc.affineTransformMakeIdentity(); + if (!rotated) { + // CCLog("!rotated"); + t = cc.affineTransformTranslate(t, rect.x, rect.y); + + cc._rectApplyAffineTransformIn(centerbounds, t); + cc._rectApplyAffineTransformIn(rightbottombounds, t); + cc._rectApplyAffineTransformIn(leftbottombounds, t); + cc._rectApplyAffineTransformIn(righttopbounds, t); + cc._rectApplyAffineTransformIn(lefttopbounds, t); + cc._rectApplyAffineTransformIn(rightcenterbounds, t); + cc._rectApplyAffineTransformIn(leftcenterbounds, t); + cc._rectApplyAffineTransformIn(centerbottombounds, t); + cc._rectApplyAffineTransformIn(centertopbounds, t); + + // Centre + this._centre = new cc.Sprite(); + this._centre.initWithTexture(selTexture, centerbounds); + locScale9Image.addChild(this._centre, 0, ccui.Scale9Sprite.POSITIONS_CENTRE); + + // Top + this._top = new cc.Sprite(); + this._top.initWithTexture(selTexture, centertopbounds); + locScale9Image.addChild(this._top, 1, ccui.Scale9Sprite.POSITIONS_TOP); + + // Bottom + this._bottom = new cc.Sprite(); + this._bottom.initWithTexture(selTexture, centerbottombounds); + locScale9Image.addChild(this._bottom, 1, ccui.Scale9Sprite.POSITIONS_BOTTOM); + + // Left + this._left = new cc.Sprite(); + this._left.initWithTexture(selTexture, leftcenterbounds); + locScale9Image.addChild(this._left, 1, ccui.Scale9Sprite.POSITIONS_LEFT); + + // Right + this._right = new cc.Sprite(); + this._right.initWithTexture(selTexture, rightcenterbounds); + locScale9Image.addChild(this._right, 1, ccui.Scale9Sprite.POSITIONS_RIGHT); + + // Top left + this._topLeft = new cc.Sprite(); + this._topLeft.initWithTexture(selTexture, lefttopbounds); + locScale9Image.addChild(this._topLeft, 2, ccui.Scale9Sprite.POSITIONS_TOPLEFT); + + // Top right + this._topRight = new cc.Sprite(); + this._topRight.initWithTexture(selTexture, righttopbounds); + locScale9Image.addChild(this._topRight, 2, ccui.Scale9Sprite.POSITIONS_TOPRIGHT); + + // Bottom left + this._bottomLeft = new cc.Sprite(); + this._bottomLeft.initWithTexture(selTexture, leftbottombounds); + locScale9Image.addChild(this._bottomLeft, 2, ccui.Scale9Sprite.POSITIONS_BOTTOMLEFT); + + // Bottom right + this._bottomRight = new cc.Sprite(); + this._bottomRight.initWithTexture(selTexture, rightbottombounds); + locScale9Image.addChild(this._bottomRight, 2, ccui.Scale9Sprite.POSITIONS_BOTTOMRIGHT); + } else { + // set up transformation of coordinates + // to handle the case where the sprite is stored rotated + // in the spritesheet + // CCLog("rotated"); + var rotatedcenterbounds = centerbounds; + var rotatedrightbottombounds = rightbottombounds; + var rotatedleftbottombounds = leftbottombounds; + var rotatedrighttopbounds = righttopbounds; + var rotatedlefttopbounds = lefttopbounds; + var rotatedrightcenterbounds = rightcenterbounds; + var rotatedleftcenterbounds = leftcenterbounds; + var rotatedcenterbottombounds = centerbottombounds; + var rotatedcentertopbounds = centertopbounds; + + t = cc.affineTransformTranslate(t, rect.height + rect.x, rect.y); + t = cc.affineTransformRotate(t, 1.57079633); + + centerbounds = cc.rectApplyAffineTransform(centerbounds, t); + rightbottombounds = cc.rectApplyAffineTransform(rightbottombounds, t); + leftbottombounds = cc.rectApplyAffineTransform(leftbottombounds, t); + righttopbounds = cc.rectApplyAffineTransform(righttopbounds, t); + lefttopbounds = cc.rectApplyAffineTransform(lefttopbounds, t); + rightcenterbounds = cc.rectApplyAffineTransform(rightcenterbounds, t); + leftcenterbounds = cc.rectApplyAffineTransform(leftcenterbounds, t); + centerbottombounds = cc.rectApplyAffineTransform(centerbottombounds, t); + centertopbounds = cc.rectApplyAffineTransform(centertopbounds, t); + + rotatedcenterbounds.x = centerbounds.x; + rotatedcenterbounds.y = centerbounds.y; + + rotatedrightbottombounds.x = rightbottombounds.x; + rotatedrightbottombounds.y = rightbottombounds.y; + + rotatedleftbottombounds.x = leftbottombounds.x; + rotatedleftbottombounds.y = leftbottombounds.y; + + rotatedrighttopbounds.x = righttopbounds.x; + rotatedrighttopbounds.y = righttopbounds.y; + + rotatedlefttopbounds.x = lefttopbounds.x; + rotatedlefttopbounds.y = lefttopbounds.y; + + rotatedrightcenterbounds.x = rightcenterbounds.x; + rotatedrightcenterbounds.y = rightcenterbounds.y; + + rotatedleftcenterbounds.x = leftcenterbounds.x; + rotatedleftcenterbounds.y = leftcenterbounds.y; + + rotatedcenterbottombounds.x = centerbottombounds.x; + rotatedcenterbottombounds.y = centerbottombounds.y; + + rotatedcentertopbounds.x = centertopbounds.x; + rotatedcentertopbounds.y = centertopbounds.y; + + // Centre + this._centre = new cc.Sprite(); + this._centre.initWithTexture(selTexture, rotatedcenterbounds, true); + locScale9Image.addChild(this._centre, 0, ccui.Scale9Sprite.POSITIONS_CENTRE); + + // Top + this._top = new cc.Sprite(); + this._top.initWithTexture(selTexture, rotatedcentertopbounds, true); + locScale9Image.addChild(this._top, 1, ccui.Scale9Sprite.POSITIONS_TOP); + + // Bottom + this._bottom = new cc.Sprite(); + this._bottom.initWithTexture(selTexture, rotatedcenterbottombounds, true); + locScale9Image.addChild(this._bottom, 1, ccui.Scale9Sprite.POSITIONS_BOTTOM); + + // Left + this._left = new cc.Sprite(); + this._left.initWithTexture(selTexture, rotatedleftcenterbounds, true); + locScale9Image.addChild(this._left, 1, ccui.Scale9Sprite.POSITIONS_LEFT); + + // Right + this._right = new cc.Sprite(); + this._right.initWithTexture(selTexture, rotatedrightcenterbounds, true); + locScale9Image.addChild(this._right, 1, ccui.Scale9Sprite.POSITIONS_RIGHT); + + // Top left + this._topLeft = new cc.Sprite(); + this._topLeft.initWithTexture(selTexture, rotatedlefttopbounds, true); + locScale9Image.addChild(this._topLeft, 2, ccui.Scale9Sprite.POSITIONS_TOPLEFT); + + // Top right + this._topRight = new cc.Sprite(); + this._topRight.initWithTexture(selTexture, rotatedrighttopbounds, true); + locScale9Image.addChild(this._topRight, 2, ccui.Scale9Sprite.POSITIONS_TOPRIGHT); + + // Bottom left + this._bottomLeft = new cc.Sprite(); + this._bottomLeft.initWithTexture(selTexture, rotatedleftbottombounds, true); + locScale9Image.addChild(this._bottomLeft, 2, ccui.Scale9Sprite.POSITIONS_BOTTOMLEFT); + + // Bottom right + this._bottomRight = new cc.Sprite(); + this._bottomRight.initWithTexture(selTexture, rotatedrightbottombounds, true); + locScale9Image.addChild(this._bottomRight, 2, ccui.Scale9Sprite.POSITIONS_BOTTOMRIGHT); + } + + this.setContentSize(rect.width, rect.height); + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + this.addChild(locScale9Image); + + if (this._spritesGenerated) { + // Restore color and opacity + this.setOpacity(opacity); + this.setColor(color); + } + this._spritesGenerated = true; + return true; + }, + + /** + * set the sprite frame of ccui.Scale9Sprite + * @param {cc.SpriteFrame} spriteFrame + */ + setSpriteFrame: function (spriteFrame) { + var batchNode = new cc.SpriteBatchNode(spriteFrame.getTexture(), 9); + // the texture is rotated on Canvas render mode, so isRotated always is false. + var locLoaded = spriteFrame.textureLoaded(); + this._textureLoaded = locLoaded; + if(!locLoaded){ + spriteFrame.addEventListener("load", function(sender){ + // the texture is rotated on Canvas render mode, so isRotated always is false. + var preferredSize = this._preferredSize, restorePreferredSize = preferredSize.width !== 0 && preferredSize.height !== 0; + if (restorePreferredSize) preferredSize = cc.size(preferredSize.width, preferredSize.height); + this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); + if (restorePreferredSize)this.setPreferredSize(preferredSize); + this._positionsAreDirty = true; + this.dispatchEvent("load"); + },this); + } + this.updateWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), cc.rect(0, 0, 0, 0)); + + // Reset insets + this._insetLeft = 0; + this._insetTop = 0; + this._insetRight = 0; + this._insetBottom = 0; + }, + + //v3.3 + /** + * Sets ccui.Scale9Sprite's state + * @since v3.3 + * @param {Number} state + */ + setState: function(state){ + this._renderCmd.setState(state); + }, + + //setScale9Enabled implement late + + /** + * Sets whether the widget should be flipped horizontally or not. + * @since v3.3 + * @param flippedX true if the widget should be flipped horizontally, false otherwise. + */ + setFlippedX: function(flippedX){ + var realScale = this.getScaleX(); + this._flippedX = flippedX; + this.setScaleX(realScale); + }, + + /** + *

    + * Returns the flag which indicates whether the widget is flipped horizontally or not.
    + *
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget->setScaleX(sprite->getScaleX() * -1);
    + *

    + * @since v3.3 + * @return {Boolean} true if the widget is flipped horizontally, false otherwise. + */ + isFlippedX: function(){ + return this._flippedX; + }, + + /** + * Sets whether the widget should be flipped vertically or not. + * @since v3.3 + * @param flippedY true if the widget should be flipped vertically, false otherwise. + */ + setFlippedY:function(flippedY){ + var realScale = this.getScaleY(); + this._flippedY = flippedY; + this.setScaleY(realScale); + }, + + /** + *

    + * Return the flag which indicates whether the widget is flipped vertically or not.
    + *
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget->setScaleY(widget->getScaleY() * -1);
    + *

    + * @since v3.3 + * @return {Boolean} true if the widget is flipped vertically, false otherwise. + */ + isFlippedY:function(){ + return this._flippedY; + }, + + setScaleX: function (scaleX) { + if (this._flippedX) + scaleX = scaleX * -1; + cc.Node.prototype.setScaleX.call(this, scaleX); + }, + + setScaleY: function (scaleY) { + if (this._flippedY) + scaleY = scaleY * -1; + cc.Node.prototype.setScaleY.call(this, scaleY); + }, + + setScale: function (scaleX, scaleY) { + if(scaleY === undefined) + scaleY = scaleX; + this.setScaleX(scaleX); + this.setScaleY(scaleY); + }, + + getScaleX: function () { + var originalScale = cc.Node.prototype.getScaleX.call(this); + if (this._flippedX) + originalScale = originalScale * -1.0; + return originalScale; + }, + + getScaleY: function () { + var originalScale = cc.Node.prototype.getScaleY.call(this); + if (this._flippedY) + originalScale = originalScale * -1.0; + return originalScale; + }, + + getScale: function () { + if(this.getScaleX() !== this.getScaleY()) + cc.log("Scale9Sprite#scale. ScaleX != ScaleY. Don't know which one to return"); + return this.getScaleX(); + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new ccui.Scale9Sprite.CanvasRenderCmd(this); + else + return new ccui.Scale9Sprite.WebGLRenderCmd(this); + } +}); + +var _p = ccui.Scale9Sprite.prototype; +cc.EventHelper.prototype.apply(_p); + +// Extended properties +/** @expose */ +_p.preferredSize; +cc.defineGetterSetter(_p, "preferredSize", _p.getPreferredSize, _p.setPreferredSize); +/** @expose */ +_p.capInsets; +cc.defineGetterSetter(_p, "capInsets", _p.getCapInsets, _p.setCapInsets); +/** @expose */ +_p.insetLeft; +cc.defineGetterSetter(_p, "insetLeft", _p.getInsetLeft, _p.setInsetLeft); +/** @expose */ +_p.insetTop; +cc.defineGetterSetter(_p, "insetTop", _p.getInsetTop, _p.setInsetTop); +/** @expose */ +_p.insetRight; +cc.defineGetterSetter(_p, "insetRight", _p.getInsetRight, _p.setInsetRight); +/** @expose */ +_p.insetBottom; +cc.defineGetterSetter(_p, "insetBottom", _p.getInsetBottom, _p.setInsetBottom); + +_p = null; + +/** + * Creates a 9-slice sprite with a texture file, a delimitation zone and + * with the specified cap insets. + * @deprecated since v3.0, please use new ccui.Scale9Sprite(file, rect, capInsets) instead. + * @param {String|cc.SpriteFrame} file file name of texture or a cc.Sprite object + * @param {cc.Rect} rect the rect of the texture + * @param {cc.Rect} capInsets the cap insets of ccui.Scale9Sprite + * @returns {ccui.Scale9Sprite} + */ +ccui.Scale9Sprite.create = function (file, rect, capInsets) { + return new ccui.Scale9Sprite(file, rect, capInsets); +}; + +/** + * create a ccui.Scale9Sprite with Sprite frame. + * @deprecated since v3.0, please use "new ccui.Scale9Sprite(spriteFrame, capInsets)" instead. + * @param {cc.SpriteFrame} spriteFrame + * @param {cc.Rect} capInsets + * @returns {ccui.Scale9Sprite} + */ +ccui.Scale9Sprite.createWithSpriteFrame = function (spriteFrame, capInsets) { + return new ccui.Scale9Sprite(spriteFrame, capInsets); +}; + +/** + * create a ccui.Scale9Sprite with a Sprite frame name + * @deprecated since v3.0, please use "new ccui.Scale9Sprite(spriteFrameName, capInsets)" instead. + * @param {string} spriteFrameName + * @param {cc.Rect} capInsets + * @returns {Scale9Sprite} + */ +ccui.Scale9Sprite.createWithSpriteFrameName = function (spriteFrameName, capInsets) { + return new ccui.Scale9Sprite(spriteFrameName, capInsets); +}; + +/** + * @ignore + */ +ccui.Scale9Sprite.POSITIONS_CENTRE = 0; +ccui.Scale9Sprite.POSITIONS_TOP = 1; +ccui.Scale9Sprite.POSITIONS_LEFT = 2; +ccui.Scale9Sprite.POSITIONS_RIGHT = 3; +ccui.Scale9Sprite.POSITIONS_BOTTOM = 4; +ccui.Scale9Sprite.POSITIONS_TOPRIGHT = 5; +ccui.Scale9Sprite.POSITIONS_TOPLEFT = 6; +ccui.Scale9Sprite.POSITIONS_BOTTOMRIGHT = 7; + +ccui.Scale9Sprite.state = {NORMAL: 0, GRAY: 1}; diff --git a/extensions/ccui/base-classes/UIScale9SpriteCanvasRenderCmd.js b/extensions/ccui/base-classes/UIScale9SpriteCanvasRenderCmd.js new file mode 100644 index 0000000000..33dca3d05a --- /dev/null +++ b/extensions/ccui/base-classes/UIScale9SpriteCanvasRenderCmd.js @@ -0,0 +1,144 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function() { + ccui.Scale9Sprite.CanvasRenderCmd = function (renderable) { + cc.Node.CanvasRenderCmd.call(this, renderable); + this._cachedParent = null; + this._cacheDirty = false; + this._state = ccui.Scale9Sprite.state.NORMAL; + + var node = this._node; + var locCacheCanvas = this._cacheCanvas = cc.newElement('canvas'); + locCacheCanvas.width = 1; + locCacheCanvas.height = 1; + this._cacheContext = new cc.CanvasContextWrapper(locCacheCanvas.getContext("2d")); + var locTexture = this._cacheTexture = new cc.Texture2D(); + locTexture.initWithElement(locCacheCanvas); + locTexture.handleLoadedTexture(); + this._cacheSprite = new cc.Sprite(locTexture); + this._cacheSprite.setAnchorPoint(0,0); + node.addChild(this._cacheSprite); + }; + + var proto = ccui.Scale9Sprite.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = ccui.Scale9Sprite.CanvasRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + if(!node._visible) + return; + + if (node._positionsAreDirty) { + node._updatePositions(); + node._positionsAreDirty = false; + node._scale9Dirty = true; + } + node._scale9Dirty = false; + this._cacheScale9Sprite(); + + cc.Node.CanvasRenderCmd.prototype.visit.call(this, parentCmd); + }; + + proto.transform = function(parentCmd){ + var node = this._node; + cc.Node.CanvasRenderCmd.prototype.transform.call(this, parentCmd); + if (node._positionsAreDirty) { + node._updatePositions(); + node._positionsAreDirty = false; + node._scale9Dirty = true; + } + this._cacheScale9Sprite(); + + var children = node._children; + for(var i=0; i The direct parent when it's a widget also, otherwise equals null + * @property {ccui.Widget} widgetParent - <@readonly> The direct parent when it's a widget also, otherwise equals null * @property {Boolean} enabled - Indicate whether the widget is enabled * @property {Boolean} focused - Indicate whether the widget is focused * @property {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} sizeType - The size type of the widget @@ -45,17 +104,16 @@ * @property {String} name - The name of the widget * @property {Number} actionTag - The action tag of the widget */ -ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ +ccui.Widget = ccui.ProtectedNode.extend(/** @lends ccui.Widget# */{ _enabled: true, ///< Highest control of widget _bright: true, ///< is this widget bright _touchEnabled: false, ///< is this widget touch endabled - _touchPassedEnabled: false, ///< is the touch event should be passed - _focus: false, ///< is the widget on focus + _brightStyle: null, ///< bright style - _updateEnabled: false, ///< is "update" method scheduled - _touchStartPos: null, ///< touch began point - _touchMovePos: null, ///< touch moved point - _touchEndPos: null, ///< touch ended point + + _touchBeganPosition: null, ///< touch began point + _touchMovePosition: null, ///< touch moved point + _touchEndPosition: null, ///< touch ended point _touchEventListener: null, _touchEventSelector: null, @@ -63,381 +121,311 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ _name: "default", _widgetType: null, _actionTag: 0, - _size: null, _customSize: null, _layoutParameterDictionary: null, + _layoutParameterType:0, + + _focused: false, + _focusEnabled: true, + _ignoreSize: false, - _widgetChildren: null, _affectByClipping: false, _sizeType: null, _sizePercent: null, - positionType: null, + _positionType: null, _positionPercent: null, - _reorderWidgetChildDirty: false, - _hitted: false, + _hit: false, _nodes: null, - _touchListener : null, - _color:null, - _className:"Widget", + _touchListener: null, + _className: "Widget", _flippedX: false, _flippedY: false, + _opacity: 255, + _highlight: false, + + _touchEventCallback: null, + _clickEventListener: null, + + _propagateTouchEvents: true, + _unifySize: false, + + _callbackName: null, + _callbackType: null, + _usingLayoutComponent: false, + + /** + * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @function + */ ctor: function () { - cc.Node.prototype.ctor.call(this); - this._enabled = true; - this._bright = true; - this._touchEnabled = false; - this._touchPassedEnabled = false; - this._focus = false; + cc.ProtectedNode.prototype.ctor.call(this); this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; - this._updateEnabled = false; - this._touchStartPos = cc.p(0,0); - this._touchMovePos = cc.p(0,0); - this._touchEndPos = cc.p(0,0); - this._touchEventListener = null; - this._touchEventSelector = null; - this._name = "default"; + this._touchBeganPosition = cc.p(0, 0); + this._touchMovePosition = cc.p(0, 0); + this._touchEndPosition = cc.p(0, 0); this._widgetType = ccui.Widget.TYPE_WIDGET; - this._actionTag = 0; - this._size = cc.size(0, 0); this._customSize = cc.size(0, 0); this._layoutParameterDictionary = {}; - this._ignoreSize = false; - this._widgetChildren = []; - this._affectByClipping = false; this._sizeType = ccui.Widget.SIZE_ABSOLUTE; - this._sizePercent = cc.p(0,0); - this.positionType = ccui.Widget.POSITION_ABSOLUTE; - this._positionPercent = cc.p(0,0); - this._reorderWidgetChildDirty = false; - this._hitted = false; + this._sizePercent = cc.p(0, 0); + this._positionType = ccui.Widget.POSITION_ABSOLUTE; + this._positionPercent = cc.p(0, 0); this._nodes = []; - this._color = cc.color(255,255,255,255); - this._touchListener = null; - this._flippedX = false; - this._flippedY = false; + this._layoutParameterType = ccui.LayoutParameter.NONE; + this.init(); //TODO }, /** - * initializes state of widget. + * initializes state of widget. please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. * @returns {boolean} */ init: function () { - if (cc.Node.prototype.init.call(this)){ + if (cc.ProtectedNode.prototype.init.call(this)) { this._layoutParameterDictionary = {}; - this._widgetChildren = []; - this.initRenderer(); + this._initRenderer(); this.setBright(true); - this.ignoreContentAdaptWithSize(true); - this.setAnchorPoint(cc.p(0.5, 0.5)); - } - return true; - }, - - onEnter: function () { - this.updateSizeAndPosition(); - cc.Node.prototype.onEnter.call(this); - }, - - visit: function (ctx) { - if (this._enabled) { - cc.Node.prototype.visit.call(this,ctx); - } - }, - sortAllChildren: function () { - this._reorderWidgetChildDirty = this._reorderChildDirty; - cc.Node.prototype.sortAllChildren.call(this); - if (this._reorderWidgetChildDirty) { - var _children = this._widgetChildren; - var i, j, length = _children.length, tempChild; - - // insertion sort - for (i = 0; i < length; i++) { - var tempItem = _children[i]; - j = i - 1; - tempChild = _children[j]; - - //continue moving element downwards while zOrder is smaller or when zOrder is the same but mutatedIndex is smaller - while (j >= 0 && ( tempItem._localZOrder < tempChild._localZOrder || - ( tempItem._localZOrder == tempChild._localZOrder && tempItem.arrivalOrder < tempChild.arrivalOrder ))) { - _children[j + 1] = tempChild; - j = j - 1; - tempChild = _children[j]; - } - _children[j + 1] = tempItem; - } - - //don't need to check children recursively, that's done in visit of each child + this.onFocusChanged = this.onFocusChange.bind(this); + this.onNextFocusedWidget = null; + this.setAnchorPoint(cc.p(0.5, 0.5)); - this._reorderWidgetChildDirty = false; + this.ignoreContentAdaptWithSize(true); + return true; } + return false; }, /** - * Adds a child to the container. - * @param {ccui.Widget} widget - * @param {Number} zOrder - * @param {Number} tag + * Calls updateSizeAndPosition and its parent's onEnter + * @override */ - addChild: function (widget, zOrder, tag) { - if(widget instanceof ccui.Widget){ - cc.Node.prototype.addChild.call(this, widget, zOrder, tag); - this._widgetChildren.push(widget); - return; - } - if(widget instanceof cc.Node){ - cc.log("Please use addNode to add a CCNode."); - return; - } + onEnter: function () { + var locListener = this._touchListener; + if (locListener && !locListener._isRegistered() && this._touchEnabled) + cc.eventManager.addListener(locListener, this); + if(!this._usingLayoutComponent) + this.updateSizeAndPosition(); + cc.ProtectedNode.prototype.onEnter.call(this); }, /** - * - * @param tag - * @returns {ccui.Widget} + * Calls unscheduleUpdate and its parent's onExit + * @override */ - getChildByTag:function(tag){ - var __children = this._widgetChildren; - if (__children != null) { - for (var i = 0; i < __children.length; i++) { - var node = __children[i]; - if (node && node._tag == tag) - return node; - } - } - return null; + onExit: function(){ + this.unscheduleUpdate(); + cc.ProtectedNode.prototype.onExit.call(this); }, - /** - * Return an array of children - * @returns {Array} - */ - getChildren: function () { - return this._widgetChildren; + _getOrCreateLayoutComponent: function(){ + var layoutComponent = this.getComponent(ccui.__LAYOUT_COMPONENT_NAME); + if (null == layoutComponent){ + layoutComponent = new ccui.LayoutComponent(); + this.addComponent(layoutComponent); + } + return layoutComponent; }, /** - * get the count of children - * @returns {Number} + * The direct parent when it's a widget also, otherwise equals null + * @returns {ccui.Widget|null} */ - getChildrenCount: function () { - return this._widgetChildren.length; - }, - getWidgetParent: function () { var widget = this.getParent(); - if(widget instanceof ccui.Widget){ + if (widget instanceof ccui.Widget) return widget; - } return null; }, - /** - * remove child - * @param {ccui.Widget} widget - * @param {Boolean} cleanup - */ - removeChild: function (widget, cleanup) { - if(!(widget instanceof ccui.Widget)){ - cc.log("child must a type of ccui.Widget"); + _updateContentSizeWithTextureSize: function(size){ + if(this._unifySize){ + this.setContentSize(size); return; } - cc.Node.prototype.removeChild.call(this, widget, cleanup); - cc.arrayRemoveObject(this._widgetChildren, widget); + this.setContentSize(this._ignoreSize ? size : this._customSize); }, - removeChildByTag: function (tag, cleanup) { - var child = this.getChildByTag(tag); + _isAncestorsEnabled: function(){ + var parentWidget = this._getAncensterWidget(this); + if (parentWidget == null) + return true; + if (parentWidget && !parentWidget.isEnabled()) + return false; - if (child == null) { - cc.log("cocos2d: removeChildByTag(tag = " + tag + "): child not found!"); - } - else { - this.removeChild(child, cleanup); - } + return parentWidget._isAncestorsEnabled(); }, /** - * Removes all children from the container, and do a cleanup to all running actions depending on the cleanup parameter. + * Allow widget touch events to propagate to its parents. Set false will disable propagation + * @since v3.2 + * @param {Boolean} isPropagate */ - removeAllChildren: function (cleanup) { - for (var i = 0; i < this._widgetChildren.length; i++) { - var widget = this._widgetChildren[i]; - cc.Node.prototype.removeChild.call(this, widget, cleanup); - } - this._widgetChildren.length = 0; + setPropagateTouchEvents: function(isPropagate){ + this._propagateTouchEvents = isPropagate; }, /** - * Set enabled renderer - * @param {Boolean} enabled + * Return whether the widget is propagate touch events to its parents or not + * @since v3.2 + * @returns {boolean} */ - setEnabled: function (enabled) { - this._enabled = enabled; - var arrayChildren = this._widgetChildren; - var childrenCount = arrayChildren.length; - for (var i = 0; i < childrenCount; i++) { - var child = arrayChildren[i]; - child.setEnabled(enabled); - } + isPropagateTouchEvents: function(){ + return this._propagateTouchEvents; }, /** - * Gets a child from the container with its name - * @param {string} name - * @returns {ccui.Widget} + * Specify widget to swallow touches or not + * @since v3.2 + * @param {Boolean} swallow */ - getChildByName: function (name) { - var arrayChildren = this._widgetChildren; - var childrenCount = arrayChildren.length; - for (var i = 0; i < childrenCount; i++) { - var child = arrayChildren[i]; - if (child.getName() == name) { - return child; - } - } + setSwallowTouches: function(swallow){ + if (this._touchListener) + this._touchListener.setSwallowTouches(swallow); }, /** - * initializes renderer of widget. + * Return whether the widget is swallowing touch or not + * @since v3.2 + * @returns {boolean} */ - initRenderer: function () { + isSwallowTouches: function(){ + if (this._touchListener){ + //return true; //todo need test + return this._touchListener.isSwallowTouches(); + } + return false; }, - /** - * add node for widget - * @param {cc.Node} node - * @param {Number} zOrder - * @param {Number} tag - */ - addNode: function (node, zOrder, tag) { - if (node instanceof ccui.Widget) { - cc.log("Please use addChild to add a Widget."); - return; - } - cc.Node.prototype.addChild.call(this, node, zOrder, tag); - this._nodes.push(node); + _getAncensterWidget: function(node){ + if (null == node) + return null; + + var parent = node.getParent(); + if (null == parent) + return null; + + if (parent instanceof ccui.Widget) + return parent; + else + return this._getAncensterWidget(parent.getParent()); }, - /** - * get node by tag - * @param {Number} tag - * @returns {cc.Node} - */ - getNodeByTag: function (tag) { - var _nodes = this._nodes; - for (var i = 0; i < _nodes.length; i++) { - var node = _nodes[i]; - if (node && node.getTag() == tag) { - return node; - } + _isAncestorsVisible: function(node){ + if (null == node) + return true; + + var parent = node.getParent(); + + if (parent && !parent.isVisible()) + return false; + return this._isAncestorsVisible(parent); + }, + + _cleanupWidget: function(){ + //clean up _touchListener + this._eventDispatcher.removeEventListener(this._touchListener); + this._touchEnabled = false; + this._touchListener = null; + + //cleanup focused widget and focus navigation controller + if (ccui.Widget._focusedWidget === this){ + ccui.Widget._focusedWidget = null; + ccui.Widget._focusNavigationController = null; } - return null; }, /** - * get all node - * @returns {Array} + *

    + * Sets whether the widget is enabled
    + * true if the widget is enabled, widget may be touched , false if the widget is disabled, widget cannot be touched.
    + * The default value is true, a widget is default to enabled + *

    + * @param {Boolean} enabled */ - getNodes: function () { - return this._nodes; + setEnabled: function (enabled) { + this._enabled = enabled; }, /** - * remove node - * @param {cc.Node} node - * @param {Boolean} cleanup + * initializes renderer of widget. */ - removeNode: function (node, cleanup) { - cc.Node.prototype.removeChild.call(this, node); - cc.arrayRemoveObject(this._nodes, node); - }, + _initRenderer: function () {}, /** - * remove node by tag - * @param {Number} tag - * @param {Boolean} cleanup + * Sets _customSize of ccui.Widget, if ignoreSize is true, the content size is its renderer's contentSize, otherwise the content size is parameter. + * and updates size percent by parent content size. At last, updates its children's size and position. + * @param {cc.Size|Number} contentSize content size or width of content size + * @param {Number} [height] + * @override */ - removeNodeByTag: function (tag, cleanup) { - var node = this.getNodeByTag(tag); - if (!node) { - cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag); + setContentSize: function(contentSize, height){ + var locWidth = (height === undefined) ? contentSize.width : contentSize; + var locHeight = (height === undefined) ? contentSize.height : height; + cc.Node.prototype.setContentSize.call(this, locWidth, locHeight); + + this._customSize.width = locWidth; + this._customSize.height = locHeight; + if(this._unifySize){ + //unify size logic + } else if (this._ignoreSize){ + this._contentSize = this.getVirtualRendererSize(); } - else { - this.removeNode(node); + if (!this._usingLayoutComponent && this._running) { + var widgetParent = this.getWidgetParent(); + var pSize = widgetParent ? widgetParent.getContentSize() : this._parent.getContentSize(); + this._sizePercent.x = (pSize.width > 0.0) ? locWidth / pSize.width : 0.0; + this._sizePercent.y = (pSize.height > 0.0) ? locHeight / pSize.height : 0.0; } + this._onSizeChanged(); }, - /** - * remove all node - */ - removeAllNodes: function () { - for (var i = 0; i < this._nodes.length; i++) { - var node = this._nodes[i]; - cc.Node.prototype.removeChild.call(this, node); + _setWidth: function (w) { + cc.Node.prototype._setWidth.call(this, w); + this._customSize.width = w; + if(this._unifySize){ + //unify size logic + } else if (this._ignoreSize){ + this._contentSize = this.getVirtualRendererSize(); } - this._nodes.length = 0; - }, - /** - * Changes the size that is widget's size - * @param {cc.Size} size - */ - setSize: function (size) { - var locW = this._customSize.width = size.width; - var locH = this._customSize.height = size.height; - if (this._ignoreSize) { - locW = this.width; - locH = this.height; + if (!this._usingLayoutComponent && this._running) { + var widgetParent = this.getWidgetParent(); + var locWidth = widgetParent ? widgetParent.width : this._parent.width; + this._sizePercent.x = locWidth > 0 ? this._customSize.width / locWidth : 0; } - this._size.width = locW; - this._size.height = locH; - - if(this._running){ - var widgetParent = this.getWidgetParent(); - if(widgetParent){ - locW = widgetParent.width; - locH = widgetParent.height; - }else{ - locW = this._parent.width; - locH = this._parent.height; - } - this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0; - this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; + this._onSizeChanged(); + }, + _setHeight: function (h) { + cc.Node.prototype._setHeight.call(this, h); + this._customSize.height = h; + if(this._unifySize){ + //unify size logic + } else if (this._ignoreSize){ + this._contentSize = this.getVirtualRendererSize(); + } + + if (!this._usingLayoutComponent && this._running) { + var widgetParent = this.getWidgetParent(); + var locH = widgetParent ? widgetParent.height : this._parent.height; + this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; } - this.onSizeChanged(); - }, - _setWidth: function (w) { - var locW = this._customSize.width = w; - this._ignoreSize && (locW = this.width); - this._size.width = locW; - - if(this._running){ - var widgetParent = this.getWidgetParent(); - locW = widgetParent ? widgetParent.width : this._parent.width; - this._sizePercent.x = locW > 0 ? this._customSize.width / locW : 0; - } - this.onSizeChanged(); - }, - _setHeight: function (h) { - var locH = this._customSize.height = h; - this._ignoreSize && (locH = this.height); - this._size.height = locH; - - if(this._running){ - var widgetParent = this.getWidgetParent(); - locH = widgetParent ? widgetParent.height : this._parent.height; - this._sizePercent.y = locH > 0 ? this._customSize.height / locH : 0; - } - this.onSizeChanged(); - }, + this._onSizeChanged(); + }, /** * Changes the percent that is widget's percent size - * @param {cc.Point} percent + * @param {cc.Point} percent that is widget's percent size, width and height value from 0 to 1. */ setSizePercent: function (percent) { + if(this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + component.setUsingPercentContentSize(true); + component.setPercentContentSize(percent); + component.refreshLayout(); + return; + } + this._sizePercent.x = percent.x; this._sizePercent.y = percent.y; var width = this._customSize.width, height = this._customSize.height; @@ -446,146 +434,121 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ if (widgetParent) { width = widgetParent.width * percent.x; height = widgetParent.height * percent.y; - } - else { + } else { width = this._parent.width * percent.x; height = this._parent.height * percent.y; } } - if (!this._ignoreSize) { - this._size.width = width; - this._size.height = height; + if (this._ignoreSize) + this.setContentSize(this.getVirtualRendererSize()); + else + this.setContentSize(width, height); + + this._customSize.width = width; + this._customSize.height = height; + }, + + _setWidthPercent: function (percent) { + this._sizePercent.x = percent; + var width = this._customSize.width; + if (this._running) { + var widgetParent = this.getWidgetParent(); + width = (widgetParent ? widgetParent.width : this._parent.width) * percent; } + if (this._ignoreSize) + this._setWidth(this.getVirtualRendererSize().width); + else + this._setWidth(width); this._customSize.width = width; + }, + _setHeightPercent: function (percent) { + this._sizePercent.y = percent; + var height = this._customSize.height; + if (this._running) { + var widgetParent = this.getWidgetParent(); + height = (widgetParent ? widgetParent.height : this._parent.height) * percent; + } + if (this._ignoreSize) + this._setHeight(this.getVirtualRendererSize().height); + else + this._setHeight(height); this._customSize.height = height; - this.onSizeChanged(); - }, - _setWidthPercent: function (percent) { - this._sizePercent.x = percent; - var width = this._customSize.width; - if (this._running) { - var widgetParent = this.getWidgetParent(); - width = (widgetParent ? widgetParent.width : this._parent.width) * percent; - } - this._ignoreSize || (this._size.width = width); - this._customSize.width = width; - this.onSizeChanged(); - }, - _setHeightPercent: function (percent) { - this._sizePercent.y = percent; - var height = this._customSize.height; - if (this._running) { - var widgetParent = this.getWidgetParent(); - height = (widgetParent ? widgetParent.height : this._parent.height) * percent; - } - this._ignoreSize || (this._size.height = height); - this._customSize.height = height; - this.onSizeChanged(); - }, - - /** - * update size and position - */ - updateSizeAndPosition: function () { + }, + + /** + * updates its size by size type and its position by position type. + * @param {cc.Size} [parentSize] parent size + */ + updateSizeAndPosition: function (parentSize) { + if(!parentSize){ + var widgetParent = this.getWidgetParent(); + if(widgetParent) + parentSize = widgetParent.getLayoutSize(); + else + parentSize = this._parent.getContentSize(); + } + switch (this._sizeType) { case ccui.Widget.SIZE_ABSOLUTE: - var locSize; - if (this._ignoreSize) { - locSize = this.getContentSize(); - } - else { - locSize = this._customSize; - } - this._size.width = locSize.width; - this._size.height = locSize.height; - - var pSize, spx = 0, spy = 0; - var widgetParent = this.getWidgetParent(); - if (widgetParent){ - pSize = widgetParent.getSize(); - }else{ - pSize = this._parent.getContentSize(); - } - if (pSize.width > 0) { - spx = this._customSize.width / pSize.width; - } - if (pSize.height > 0) { - spy = this._customSize.height / pSize.height; - } - this._sizePercent.x = spx; - this._sizePercent.y = spy; + if(this._ignoreSize) + this.setContentSize(this.getVirtualRendererSize()); + else + this.setContentSize(this._customSize); + this._sizePercent.x = (parentSize.width > 0) ? this._customSize.width / parentSize.width : 0; + this._sizePercent.y = (parentSize.height > 0) ? this._customSize.height / parentSize.height : 0; break; case ccui.Widget.SIZE_PERCENT: - var widgetParent = this.getWidgetParent(); - var cSize = cc.size(0,0); - if (widgetParent){ - cSize.width = widgetParent.getSize().width * this._sizePercent.x; - cSize.height = widgetParent.getSize().height * this._sizePercent.y; - }else{ - cSize.width = this._parent.getContentSize().width * this._sizePercent.x; - cSize.height = this._parent.getContentSize().height * this._sizePercent.y; - } - var locSize; - if (this._ignoreSize) { - locSize = this.getContentSize(); - } - else { - locSize = cSize; - } - this._size.width = locSize.width; - this._size.height = locSize.height; + var cSize = cc.size(parentSize.width * this._sizePercent.x , parentSize.height * this._sizePercent.y); + if(this._ignoreSize) + this.setContentSize(this.getVirtualRendererSize()); + else + this.setContentSize(cSize); this._customSize.width = cSize.width; this._customSize.height = cSize.height; break; default: break; } - this.onSizeChanged(); + this._onSizeChanged(); var absPos = this.getPosition(); - switch (this.positionType) { + switch (this._positionType) { case ccui.Widget.POSITION_ABSOLUTE: - var widgetParent = this.getWidgetParent(); - var pSize; - if(widgetParent){ - pSize = widgetParent.getSize(); - }else{ - pSize = this._parent.getContentSize(); - } - if(pSize.width<=0||pSize.height<=0){ - this._positionPercent.x = 0; - this._positionPercent.y = 0; - }else{ - this._positionPercent.x = absPos.x / pSize.width; - this._positionPercent.y = absPos.y / pSize.height; + if (parentSize.width <= 0 || parentSize.height <= 0) { + this._positionPercent.x = this._positionPercent.y = 0; + } else { + this._positionPercent.x = absPos.x / parentSize.width; + this._positionPercent.y = absPos.y / parentSize.height; } break; case ccui.Widget.POSITION_PERCENT: - var widgetParent = this.getWidgetParent(); - var pSize; - if(widgetParent){ - pSize = widgetParent.getSize(); - }else{ - pSize = this._parent.getContentSize(); - } - absPos = cc.p(pSize.width * this._positionPercent.x, pSize.height * this._positionPercent.y); + absPos = cc.p(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y); break; default: break; } + if(this._parent instanceof ccui.ImageView){ + var renderer = this._parent._imageRenderer; + if(renderer && !renderer._textureLoaded) + return; + } this.setPosition(absPos); }, /**TEXTURE_RES_TYPE * Changes the size type of widget. - * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type + * @param {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} type that is widget's size type */ setSizeType: function (type) { this._sizeType = type; + if (this._usingLayoutComponent) { + var component = this._getOrCreateLayoutComponent(); + component.setUsingPercentContentSize(this._sizeType === ccui.SIZE_PERCENT); + } }, /** * Gets the size type of widget. - * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} + * @returns {ccui.Widget.SIZE_ABSOLUTE|ccui.Widget.SIZE_PERCENT} that is widget's size type */ getSizeType: function () { return this._sizeType; @@ -593,294 +556,445 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ /** * Ignore the widget size - * @param {Boolean} ignore + * @param {Boolean} ignore true that widget will ignore it's size, use texture size, false otherwise. Default value is true. */ ignoreContentAdaptWithSize: function (ignore) { - this._ignoreSize = ignore; - var locSize; - if (this._ignoreSize) { - locSize = this.getContentSize(); - } - else { - locSize = this._customSize; + if(this._unifySize){ + this.setContentSize(this._customSize); + return; } - this._size.width = locSize.width; - this._size.height = locSize.height; - this.onSizeChanged(); + + if(this._ignoreSize === ignore) + return; + + this._ignoreSize = ignore; + this.setContentSize( ignore ? this.getVirtualRendererSize() : this._customSize ); + //this._onSizeChanged(); }, /** - * Gets the widget if is ignore it's size. - * @returns {boolean} + * Gets whether ignore the content size (custom size) + * @returns {boolean} true that widget will ignore it's size, use texture size, false otherwise. */ isIgnoreContentAdaptWithSize: function () { return this._ignoreSize; }, /** - * Returns size of widget + * Get custom size of ccui.Widget * @returns {cc.Size} */ - getSize: function () { - return this._size; + getCustomSize: function () { + return cc.size(this._customSize); }, /** - * Get custom size + * Gets layout size of ccui.Widget. * @returns {cc.Size} */ - getCustomSize:function(){ - return this._customSize + getLayoutSize: function(){ + return cc.size(this._contentSize); }, /** - * Returns size percent of widget + * Returns size percent of ccui.Widget * @returns {cc.Point} */ getSizePercent: function () { + if(this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + this._sizePercent = component.getPercentContentSize(); + } return this._sizePercent; }, - _getWidthPercent: function () { - return this._sizePercent.x; - }, - _getHeightPercent: function () { - return this._sizePercent.y; - }, + _getWidthPercent: function () { + return this._sizePercent.x; + }, + _getHeightPercent: function () { + return this._sizePercent.y; + }, /** - * Gets world position of widget. - * @returns {cc.Point} + * Gets world position of ccui.Widget. + * @returns {cc.Point} world position of ccui.Widget. */ getWorldPosition: function () { - return this.convertToWorldSpace(cc.p(0,0)); + return this.convertToWorldSpace(cc.p(this._anchorPoint.x * this._contentSize.width, this._anchorPoint.y * this._contentSize.height)); }, /** * Gets the Virtual Renderer of widget. - * @returns {cc.Node} + * @returns {ccui.Widget} */ getVirtualRenderer: function () { return this; }, /** - * call back function called when size changed. + * Gets the content size of widget. Content size is widget's texture size. */ - onSizeChanged: function () { - for (var i = 0; i < this._widgetChildren.length; i++) { - var child = this._widgetChildren[i]; - child.updateSizeAndPosition(); - } + getVirtualRendererSize:function(){ + return cc.size(this._contentSize); }, /** - * Gets the content size of widget. - * @returns {cc.Size} + * call back function called when size changed. */ - getContentSize: function () { - return this._size; + _onSizeChanged: function () { + if(!this._usingLayoutComponent){ + var locChildren = this.getChildren(); + for (var i = 0, len = locChildren.length; i < len; i++) { + var child = locChildren[i]; + if(child instanceof ccui.Widget) + child.updateSizeAndPosition(); + } + } }, - _getWidth: function () { - return this._size.width; - }, - _getHeight: function () { - return this._size.height; - }, /** - * Sets whether the widget is touch enabled - * @param enable + * Sets whether the widget is touch enabled. The default value is false, a widget is default to touch disabled + * @param {Boolean} enable true if the widget is touch enabled, false if the widget is touch disabled. */ setTouchEnabled: function (enable) { - if (this._touchEnabled === enable) { + if (this._touchEnabled === enable) return; - } - this._touchEnabled = enable; - if(this._touchEnabled){ - this._touchListener = cc.EventListener.create({ - event: cc.EventListener.TOUCH_ONE_BY_ONE, - swallowTouches: true, - onTouchBegan: this.onTouchBegan.bind(this), - onTouchMoved: this.onTouchMoved.bind(this), - onTouchEnded: this.onTouchEnded.bind(this) - }); + + this._touchEnabled = enable; //TODO need consider remove and re-add. + if (this._touchEnabled) { + if(!this._touchListener) + this._touchListener = cc.EventListener.create({ + event: cc.EventListener.TOUCH_ONE_BY_ONE, + swallowTouches: true, + onTouchBegan: this.onTouchBegan.bind(this), + onTouchMoved: this.onTouchMoved.bind(this), + onTouchEnded: this.onTouchEnded.bind(this) + }); cc.eventManager.addListener(this._touchListener, this); - }else{ + } else { cc.eventManager.removeListener(this._touchListener); } }, /** - * To set the bright style of widget. - * @returns {boolean} + * Returns whether or not touch is enabled. + * @returns {boolean} true if the widget is touch enabled, false if the widget is touch disabled. */ isTouchEnabled: function () { return this._touchEnabled; }, /** - * Schedules the "update" method. - * @param enable + * Determines if the widget is highlighted + * @returns {boolean} true if the widget is highlighted, false if the widget is not highlighted . */ - setUpdateEnabled: function (enable) { - if (this._updateEnabled == enable) { - return; - } - this._updateEnabled = enable; - if (enable) { - this.scheduleUpdate(); - } - else { - this.unscheduleUpdate(); - } + isHighlighted: function(){ + return this._highlight; }, /** - * is the "update" method scheduled. - * @returns {boolean} + * Sets whether the widget is highlighted. The default value is false, a widget is default to not highlighted + * @param highlight true if the widget is highlighted, false if the widget is not highlighted. */ - isUpdateEnabled: function () { - return this._updateEnabled; + setHighlighted:function(highlight){ + if (highlight === this._highlight) + return; + this._highlight = highlight; + if (this._bright) { + if (this._highlight) + this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT); + else + this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); + } else + this._onPressStateChangedToDisabled(); }, /** * Determines if the widget is on focused - * @returns {boolean} + * @returns {boolean} whether the widget is focused or not */ isFocused: function () { - return this._focus; + return this._focused; }, /** * Sets whether the widget is on focused * The default value is false, a widget is default to not on focused - * @param {boolean} fucos - */ - setFocused: function (fucos) { - if (fucos == this._focus) { - return; + * @param {boolean} focus pass true to let the widget get focus or pass false to let the widget lose focus + */ + setFocused: function (focus) { + this._focused = focus; + //make sure there is only one focusedWidget + if (focus){ + ccui.Widget._focusedWidget = this; + if(ccui.Widget._focusNavigationController) + ccui.Widget._focusNavigationController._setFirstFocsuedWidget(this); } - this._focus = fucos; - if (this._bright) { - if (this._focus) { - this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT); - } - else { - this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); - } + }, + + /** + * returns whether the widget could accept focus. + * @returns {boolean} true represent the widget could accept focus, false represent the widget couldn't accept focus + */ + isFocusEnabled: function(){ + return this._focusEnabled; + }, + + /** + * sets whether the widget could accept focus. + * @param {Boolean} enable true represent the widget could accept focus, false represent the widget couldn't accept focus + */ + setFocusEnabled: function(enable){ + this._focusEnabled = enable; + }, + + /** + *

    + * When a widget is in a layout, you could call this method to get the next focused widget within a specified direction.
    + * If the widget is not in a layout, it will return itself + *

    + * @param direction the direction to look for the next focused widget in a layout + * @param current the current focused widget + * @return the next focused widget in a layout + */ + findNextFocusedWidget: function( direction, current){ + if (null === this.onNextFocusedWidget || null == this.onNextFocusedWidget(direction) ) { + var isLayout = current instanceof ccui.Layout; + if (this.isFocused() || isLayout) { + var layout = this.getParent(); + if (null === layout || !(layout instanceof ccui.Layout)){ + //the outer layout's default behaviour is : loop focus + if (isLayout) + return current.findNextFocusedWidget(direction, current); + return current; + } else + return layout.findNextFocusedWidget(direction, current); + } else + return current; + } else { + var getFocusWidget = this.onNextFocusedWidget(direction); + this.dispatchFocusEvent(this, getFocusWidget); + return getFocusWidget; } - else { - this.onPressStateChangedToDisabled(); + }, + + /** + * when a widget calls this method, it will get focus immediately. + */ + requestFocus: function(){ + if (this === ccui.Widget._focusedWidget) + return; + this.dispatchFocusEvent(ccui.Widget._focusedWidget, this); + }, + + /** + * no matter what widget object you call this method on , it will return you the exact one focused widget + */ + getCurrentFocusedWidget: function(){ + return ccui.Widget._focusedWidget; + }, + + /** + *

    + * When a widget lose/get focus, this method will be called. Be Caution when you provide your own version,
    + * you must call widget.setFocused(true/false) to change the focus state of the current focused widget; + *

    + */ + onFocusChanged: null, + + /** + * use this function to manually specify the next focused widget regards to each direction + */ + onNextFocusedWidget: null, + + /** + * Sends the touch event to widget's parent, its subclass will override it, e.g. ccui.ScrollView, ccui.PageView + * @param {Number} eventType + * @param {ccui.Widget} sender + * @param {cc.Touch} touch + */ + interceptTouchEvent: function(eventType, sender, touch){ + var widgetParent = this.getWidgetParent(); + if (widgetParent) + widgetParent.interceptTouchEvent(eventType,sender,touch); + }, + + /** + * This method is called when a focus change event happens + * @param {ccui.Widget} widgetLostFocus + * @param {ccui.Widget} widgetGetFocus + */ + onFocusChange: function(widgetLostFocus, widgetGetFocus){ + //only change focus when there is indeed a get&lose happens + if (widgetLostFocus) + widgetLostFocus.setFocused(false); + if (widgetGetFocus) + widgetGetFocus.setFocused(true); + }, + + /** + * Dispatch a EventFocus through a EventDispatcher + * @param {ccui.Widget} widgetLostFocus + * @param {ccui.Widget} widgetGetFocus + */ + dispatchFocusEvent: function(widgetLostFocus, widgetGetFocus){ + //if the widgetLoseFocus doesn't get focus, it will use the previous focused widget instead + if (widgetLostFocus && !widgetLostFocus.isFocused()) + widgetLostFocus = ccui.Widget._focusedWidget; + + if (widgetGetFocus !== widgetLostFocus){ + if (widgetGetFocus && widgetGetFocus.onFocusChanged) + widgetGetFocus.onFocusChanged(widgetLostFocus, widgetGetFocus); + if (widgetLostFocus && widgetGetFocus.onFocusChanged) + widgetLostFocus.onFocusChanged(widgetLostFocus, widgetGetFocus); + cc.eventManager.dispatchEvent(new cc.EventFocus(widgetLostFocus, widgetGetFocus)); } }, - setBright: function (bright, containChild) { + /** + * Sets whether the widget is bright. The default value is true, a widget is default to bright + * @param {Boolean} bright true if the widget is bright, false if the widget is dark. + */ + setBright: function (bright) { this._bright = bright; if (this._bright) { this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; this.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL); - } - else { - this.onPressStateChangedToDisabled(); - } + } else + this._onPressStateChangedToDisabled(); }, /** - * To set the bright style of widget. - * @param {ccui.Widget.BRIGHT_STYLE_NONE|ccui.Widget.BRIGHT_STYLE_NORMAL|ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT} style + * To set the bright style of ccui.Widget. + * @param {Number} style BRIGHT_NORMAL the widget is normal state, BRIGHT_HIGHLIGHT the widget is height light state. */ setBrightStyle: function (style) { - if (this._brightStyle == style) { + if (this._brightStyle === style) return; - } - style = style|| ccui.Widget.BRIGHT_STYLE_NORMAL; + + style = style || ccui.Widget.BRIGHT_STYLE_NORMAL; this._brightStyle = style; switch (this._brightStyle) { case ccui.Widget.BRIGHT_STYLE_NORMAL: - this.onPressStateChangedToNormal(); + this._onPressStateChangedToNormal(); break; case ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT: - this.onPressStateChangedToPressed(); + this._onPressStateChangedToPressed(); break; default: break; } }, - /** - * call back function called widget's state changed to normal. - */ - onPressStateChangedToNormal: function () { - - }, - - /** - * call back function called widget's state changed to selected. - */ - onPressStateChangedToPressed: function () { + _onPressStateChangedToNormal: function () {}, - }, + _onPressStateChangedToPressed: function () {}, - /** - * call back function called widget's state changed to dark. - */ - onPressStateChangedToDisabled: function () { + _onPressStateChangedToDisabled: function () {}, + _updateChildrenDisplayedRGBA: function(){ + this.setColor(this.getColor()); + this.setOpacity(this.getOpacity()); }, /** * A call back function when widget lost of focus. */ - didNotSelectSelf: function () { - - }, - - onTouchBegan: function (touch,event) { - var touchPoint = touch.getLocation(); - this._touchStartPos.x = touchPoint.x; - this._touchStartPos.y = touchPoint.y; - this._hitted = this.isEnabled() && this.isTouchEnabled()&& this.hitTest(touchPoint)&& this.clippingParentAreaContainPoint(touchPoint); - if(!this._hitted){ + didNotSelectSelf: function () {}, + + /** + *

    + * The callback of touch began event.
    + * If the bounding box of ccui.Widget contains the touch point, it will do the following things:
    + * 1. sets highlight state,
    + * 2. sends event to parent widget by interceptTouchEvent
    + * 3. calls the callback of touch began event.
    + * 4. returns true,
    + * otherwise returns false directly.
    + *

    + * @override + * @param {cc.Touch} touch + * @param {cc.Event} event + * @returns {boolean} + */ + onTouchBegan: function (touch, event) { + this._hit = false; + if (this.isVisible() && this.isEnabled() && this._isAncestorsEnabled() && this._isAncestorsVisible(this) ){ + var touchPoint = touch.getLocation(); + this._touchBeganPosition.x = touchPoint.x; + this._touchBeganPosition.y = touchPoint.y; + if(this.hitTest(this._touchBeganPosition) && this.isClippingParentContainsPoint(this._touchBeganPosition)) + this._hit = true; + } + if (!this._hit) { return false; } - this.setFocused(true); - var widgetParent = this.getWidgetParent(); - if (widgetParent) { - widgetParent.checkChildInfo(0, this, touchPoint); + this.setHighlighted(true); + + /* + * Propagate touch events to its parents + */ + if (this._propagateTouchEvents) { + this.propagateTouchEvent(ccui.Widget.TOUCH_BEGAN, this, touch); } - this.pushDownEvent(); - return !this._touchPassedEnabled; + + this._pushDownEvent(); + return true; }, - onTouchMoved: function (touch,event) { - var touchPoint = touch.getLocation(); - this._touchMovePos.x = touchPoint.x; - this._touchMovePos.y = touchPoint.y; - this.setFocused(this.hitTest(touchPoint)); + propagateTouchEvent: function(event, sender, touch){ var widgetParent = this.getWidgetParent(); - if (widgetParent) { - widgetParent.checkChildInfo(1, this, touchPoint); + if (widgetParent){ + widgetParent.interceptTouchEvent(event, sender, touch); } - this.moveEvent(); }, - - onTouchEnded: function (touch,event) { + /** + *

    + * The callback of touch moved event.
    + * It sets the highlight state by touch, sends event to parent widget by interceptTouchEvent and calls the callback of touch moved event. + *

    + * @param {cc.Touch} touch + * @param {cc.Event} event + */ + onTouchMoved: function (touch, event) { var touchPoint = touch.getLocation(); - this._touchEndPos.x = touchPoint.x; - this._touchEndPos.y = touchPoint.y; - var focus = this._focus; - this.setFocused(false); - var widgetParent = this.getWidgetParent(); - if (widgetParent) { - widgetParent.checkChildInfo(2, this, touchPoint); - } - if (focus) { - this.releaseUpEvent(); - } - else { - this.cancelUpEvent(); - } + this._touchMovePosition.x = touchPoint.x; + this._touchMovePosition.y = touchPoint.y; + this.setHighlighted(this.hitTest(touchPoint)); + /* + * Propagate touch events to its parents + */ + if (this._propagateTouchEvents) + this.propagateTouchEvent(ccui.Widget.TOUCH_MOVED, this, touch); + this._moveEvent(); + }, + + /** + *

    + * The callback of touch end event + * It sends event to parent widget by interceptTouchEvent, + * calls the callback of touch end event (highlight= true) or touch canceled event (highlight= false). + * sets the highlight state to false , + *

    + * @param touch + * @param event + */ + onTouchEnded: function (touch, event) { + var touchPoint = touch.getLocation(); + this._touchEndPosition.x = touchPoint.x; + this._touchEndPosition.y = touchPoint.y; + /* + * Propagate touch events to its parents + */ + if (this._propagateTouchEvents) + this.propagateTouchEvent(ccui.Widget.TOUCH_ENDED, this, touch); + + var highlight = this._highlight; + this.setHighlighted(false); + if (highlight) + this._releaseUpEvent(); + else + this._cancelUpEvent(); }, /** @@ -888,8 +1002,8 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ * @param {cc.Point} touchPoint */ onTouchCancelled: function (touchPoint) { - this.setFocused(false); - this.cancelUpEvent(); + this.setHighlighted(false); + this._cancelUpEvent(); }, /** @@ -901,71 +1015,74 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ }, //call back function called widget's state changed to dark. - - pushDownEvent: function () { - if (this._touchEventListener && this._touchEventSelector) { - if (this._touchEventSelector) { - this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN); - } - } + _pushDownEvent: function () { + if (this._touchEventCallback) + this._touchEventCallback(this, ccui.Widget.TOUCH_BEGAN); + if (this._touchEventListener && this._touchEventSelector) + this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_BEGAN); }, - moveEvent: function () { - if (this._touchEventListener && this._touchEventSelector) { - if (this._touchEventSelector) { - this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED); - } - } + _moveEvent: function () { + if (this._touchEventCallback) + this._touchEventCallback(this, ccui.Widget.TOUCH_MOVED); + if (this._touchEventListener && this._touchEventSelector) + this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_MOVED); }, - releaseUpEvent: function () { - if (this._touchEventListener && this._touchEventSelector) { - if (this._touchEventSelector) { - this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED); - } - } + _releaseUpEvent: function () { + if (this._touchEventCallback) + this._touchEventCallback(this, ccui.Widget.TOUCH_ENDED); + if (this._touchEventListener && this._touchEventSelector) + this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_ENDED); + if (this._clickEventListener) + this._clickEventListener(this); }, - cancelUpEvent: function () { - if (this._touchEventSelector) { + _cancelUpEvent: function () { + if (this._touchEventCallback) + this._touchEventCallback(this, ccui.Widget.TOUCH_CANCELED); + if (this._touchEventListener && this._touchEventSelector) this._touchEventSelector.call(this._touchEventListener, this, ccui.Widget.TOUCH_CANCELED); - } }, longClickEvent: function () { - + //TODO it will implement in v3.1 }, /** - * Sets the touch event target/selector of the menu item + * Sets the touch event target/selector of the ccui.Widget * @param {Function} selector * @param {Object} target */ addTouchEventListener: function (selector, target) { - this._touchEventSelector = selector; - this._touchEventListener = target; + if(target === undefined) + this._touchEventCallback = selector; + else { + this._touchEventSelector = selector; + this._touchEventListener = target; + } + }, + + addClickEventListener: function(callback){ + this._clickEventListener = callback; }, /** * Checks a point if is in widget's space * @param {cc.Point} pt - * @returns {boolean} + * @returns {boolean} true if the point is in widget's space, false otherwise. */ hitTest: function (pt) { - var nsp = this.convertToNodeSpace(pt); - var bb = cc.rect(-this._size.width * this._anchorPoint.x, -this._size.height * this._anchorPoint.y, this._size.width, this._size.height); - if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) { - return true; - } - return false; + var bb = cc.rect(0,0, this._contentSize.width, this._contentSize.height); + return cc.rectContainsPoint(bb, this.convertToNodeSpace(pt)); }, /** - * Checks a point if in parent's area. - * @param {cc.Point} pt + * returns whether clipping parent widget contains point. + * @param {cc.Point} pt location point * @returns {Boolean} */ - clippingParentAreaContainPoint: function (pt) { + isClippingParentContainsPoint: function(pt){ this._affectByClipping = false; var parent = this.getParent(); var clippingParent = null; @@ -980,209 +1097,235 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ parent = parent.getParent(); } - if (!this._affectByClipping) { + if (!this._affectByClipping) return true; - } - if (clippingParent) { - var bRet = false; - if (clippingParent.hitTest(pt)) { - bRet = true; - } - if (bRet) { - return clippingParent.clippingParentAreaContainPoint(pt); - } + if (clippingParent.hitTest(pt)) + return clippingParent.isClippingParentContainsPoint(pt); return false; } return true; }, /** - * Sends the touch event to widget's parent + * Calls the checkChildInfo of widget's parent, its subclass will override it. * @param {number} handleState * @param {ccui.Widget} sender * @param {cc.Point} touchPoint */ checkChildInfo: function (handleState, sender, touchPoint) { var widgetParent = this.getWidgetParent(); - if (widgetParent) { + if (widgetParent) widgetParent.checkChildInfo(handleState, sender, touchPoint); - } }, /** * Changes the position (x,y) of the widget . - * @param {cc.Point||Number} pos - * @param {Number} posY + * The original point (0,0) is at the left-bottom corner of screen. + * @override + * @param {cc.Point|Number} pos + * @param {Number} [posY] */ setPosition: function (pos, posY) { - if (this._running) { + if (!this._usingLayoutComponent && this._running) { var widgetParent = this.getWidgetParent(); if (widgetParent) { - var pSize = widgetParent.getSize(); + var pSize = widgetParent.getContentSize(); if (pSize.width <= 0 || pSize.height <= 0) { this._positionPercent.x = 0; this._positionPercent.y = 0; - } - else { - if(posY){ - this._positionPercent.x = pos / pSize.width; - this._positionPercent.y = posY / pSize.height; - }else{ + } else { + if (posY === undefined) { this._positionPercent.x = pos.x / pSize.width; this._positionPercent.y = pos.y / pSize.height; + } else { + this._positionPercent.x = pos / pSize.width; + this._positionPercent.y = posY / pSize.height; } } } } - cc.Node.prototype.setPosition.apply(this, arguments); - }, - - setPositionX: function (x) { - if (this._running) { - var widgetParent = this.getWidgetParent(); - if (widgetParent) { - var pw = widgetParent.width; - if (pw <= 0) - this._positionPercent.x = 0; - else - this._positionPercent.x = x / pw; - } - } - - cc.Node.prototype.setPositionX.call(this, x); - }, - setPositionY: function (y) { - if (this._running) { - var widgetParent = this.getWidgetParent(); - if (widgetParent) { - var ph = widgetParent.height; - if (ph <= 0) - this._positionPercent.y = 0; - else - this._positionPercent.y = y / ph; - } - } - - cc.Node.prototype.setPositionY.call(this, y); - }, + cc.Node.prototype.setPosition.call(this, pos, posY); + //this._positionType = ccui.Widget.POSITION_ABSOLUTE; + }, + + setPositionX: function (x) { + if (this._running) { + var widgetParent = this.getWidgetParent(); + if (widgetParent) { + var pw = widgetParent.width; + if (pw <= 0) + this._positionPercent.x = 0; + else + this._positionPercent.x = x / pw; + } + } + + cc.Node.prototype.setPositionX.call(this, x); + }, + setPositionY: function (y) { + if (this._running) { + var widgetParent = this.getWidgetParent(); + if (widgetParent) { + var ph = widgetParent.height; + if (ph <= 0) + this._positionPercent.y = 0; + else + this._positionPercent.y = y / ph; + } + } + + cc.Node.prototype.setPositionY.call(this, y); + }, /** * Changes the position (x,y) of the widget * @param {cc.Point} percent */ setPositionPercent: function (percent) { - this._positionPercent = percent; - if (this._running) { - var widgetParent = this.getWidgetParent(); - if(widgetParent){ - var parentSize = widgetParent.getSize(); - this.setPosition(parentSize.width * this._positionPercent.x, parentSize.height * this._positionPercent.y); - } + if (this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + component.setPositionPercentX(percent.x); + component.setPositionPercentY(percent.y); + component.refreshLayout(); + return; + }else{ + this._setXPercent(percent.x); + this._setYPercent(percent.y); } + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, - _setXPercent: function (percent) { - this._positionPercent.x = percent; - if (this._running) { - var widgetParent = this.getWidgetParent(); - if(widgetParent){ - var absX = widgetParent.width * percent; - this.setPositionX(absX); - } - } - }, - _setYPercent: function (percent) { - this._positionPercent.y = percent; - if (this._running) { - var widgetParent = this.getWidgetParent(); - if(widgetParent){ - var absY = widgetParent.height * percent; - this.setPositionY(absY); - } - } - }, - - updateAnchorPoint:function(){ - this.setAnchorPoint(this.getAnchorPoint()); + _setXPercent: function (percent) { + if (this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + component.setPositionPercentX(percent.x); + component.refreshLayout(); + return; + } + this._positionPercent.x = percent; + }, + _setYPercent: function (percent) { + if (this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + component.setPositionPercentY(percent.x); + component.refreshLayout(); + return; + } + this._positionPercent.y = percent; }, /** * Gets the percent (x,y) of the widget - * @returns {cc.Point} + * @returns {cc.Point} The percent (x,y) of the widget in OpenGL coordinates */ getPositionPercent: function () { - return this._positionPercent; + if (this._usingLayoutComponent) { + var component = this._getOrCreateLayoutComponent(); + this._positionPercent.x = component.getPositionPercentX(); + this._positionPercent.y = component.getPositionPercentY(); + } + return cc.p(this._positionPercent); + }, + + _getXPercent: function () { + if (this._usingLayoutComponent) { + var component = this._getOrCreateLayoutComponent(); + this._positionPercent.x = component.getPositionPercentX(); + this._positionPercent.y = component.getPositionPercentY(); + } + return this._positionPercent.x; + }, + _getYPercent: function () { + if (this._usingLayoutComponent) { + var component = this._getOrCreateLayoutComponent(); + this._positionPercent.x = component.getPositionPercentX(); + this._positionPercent.y = component.getPositionPercentY(); + } + return this._positionPercent.y; }, - _getXPercent: function () { - return this._positionPercent.x; - }, - _getYPercent: function () { - return this._positionPercent.y; - }, /** * Changes the position type of the widget - * @param {ccui.Widget.POSITION_ABSOLUTE|ccui.Widget.POSITION_PERCENT} type + * @param {Number} type the position type of widget */ setPositionType: function (type) { - this.positionType = type; + this._positionType = type; + if(this._usingLayoutComponent){ + var component = this._getOrCreateLayoutComponent(); + if (type === ccui.POSITION_ABSOLUTE){ + component.setPositionPercentXEnabled(false); + component.setPositionPercentYEnabled(false); + } else { + component.setPositionPercentXEnabled(true); + component.setPositionPercentYEnabled(true); + } + } + this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); }, /** * Gets the position type of the widget - * @returns {cc.pPositionType} + * @returns {Number} the position type of widget */ getPositionType: function () { - return this.positionType; + return this._positionType; }, /** - * Set flipped x - * @param {Boolean} flipX + * Sets whether the widget should be flipped horizontally or not. + * @param {Boolean} flipX true if the widget should be flipped horizontally, false otherwise. */ setFlippedX: function (flipX) { + var realScale = this.getScaleX(); this._flippedX = flipX; - this.updateFlippedX(); + this.setScaleX(realScale); }, /** - * Get flipped x - * @returns {Boolean} + *

    + * Returns the flag which indicates whether the widget is flipped horizontally or not.
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget.setScaleX(sprite.getScaleX() * -1); + *

    + * @returns {Boolean} true if the widget is flipped horizontally, false otherwise. */ isFlippedX: function () { return this._flippedX; }, /** - * Set flipped y - * @param {Boolean} flipY + * Sets whether the widget should be flipped vertically or not. + * @param {Boolean} flipY true if the widget should be flipped vertically, false otherwise. */ setFlippedY: function (flipY) { + var realScale = this.getScaleY(); this._flippedY = flipY; - this.updateFlippedY(); + this.setScaleY(realScale); }, /** - * Get flipped y - * @returns {Boolean} + *

    + * Return the flag which indicates whether the widget is flipped vertically or not.
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget.setScaleY(widget.getScaleY() * -1); + *

    + * @returns {Boolean} true if the widget is flipped vertically, false otherwise. */ isFlippedY: function () { return this._flippedY; }, - updateFlippedX:function(){ - - }, - - updateFlippedY:function(){ - - }, + _adaptRenderers: function(){}, /** * Determines if the widget is bright - * @returns {boolean} + * @returns {boolean} true if the widget is bright, false if the widget is dark. */ isBright: function () { return this._bright; @@ -1200,72 +1343,56 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ * Gets the left boundary position of this widget. * @returns {number} */ - getLeftInParent: function () { - return this.getPositionX() - this._getAnchorX() * this._size.width; + getLeftBoundary: function () { + return this.getPositionX() - this._getAnchorX() * this._contentSize.width; }, /** * Gets the bottom boundary position of this widget. * @returns {number} */ - getBottomInParent: function () { - return this.getPositionY() - this._getAnchorY() * this._size.height; + getBottomBoundary: function () { + return this.getPositionY() - this._getAnchorY() * this._contentSize.height; }, /** * Gets the right boundary position of this widget. * @returns {number} */ - getRightInParent: function () { - return this.getLeftInParent() + this._size.width; + getRightBoundary: function () { + return this.getLeftBoundary() + this._contentSize.width; }, /** * Gets the top boundary position of this widget. * @returns {number} */ - getTopInParent: function () { - return this.getBottomInParent() + this._size.height; + getTopBoundary: function () { + return this.getBottomBoundary() + this._contentSize.height; }, /** - * Gets touch start position + * Gets the position of touch began event. * @returns {cc.Point} */ - getTouchStartPos: function () { - return this._touchStartPos; + getTouchBeganPosition: function(){ + return cc.p(this._touchBeganPosition); }, /** - * Gets touch move position + * Gets the position of touch moved event * @returns {cc.Point} */ - getTouchMovePos: function () { - return this._touchMovePos; + getTouchMovePosition: function(){ + return cc.p(this._touchMovePosition); }, /** - * Gets touch end position + * Gets the position of touch end event * @returns {cc.Point} */ - getTouchEndPos: function () { - return this._touchEndPos; - }, - - /** - * Sets the name of widget - * @param {String} name - */ - setName: function (name) { - this._name = name; - }, - - /** - * Gets the name of widget - * @returns {string} - */ - getName: function () { - return this._name; + getTouchEndPosition:function(){ + return cc.p(this._touchEndPosition); }, /** @@ -1277,11 +1404,14 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ }, /** - * Sets layout parameter + * Gets LayoutParameter of widget. * @param {ccui.LayoutParameter} parameter */ setLayoutParameter: function (parameter) { + if(!parameter) + return; this._layoutParameterDictionary[parameter.getLayoutType()] = parameter; + this._layoutParameterType = parameter.getLayoutType(); }, /** @@ -1290,6 +1420,7 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ * @returns {ccui.LayoutParameter} */ getLayoutParameter: function (type) { + type = type || this._layoutParameterType; return this._layoutParameterDictionary[type]; }, @@ -1301,50 +1432,57 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ return "Widget"; }, + /** + * Clones a new widget. + * @returns {ccui.Widget} + */ clone: function () { - var clonedWidget = this.createCloneInstance(); - clonedWidget.copyProperties(this); - clonedWidget.copyClonedWidgetChildren(this); + var clonedWidget = this._createCloneInstance(); + clonedWidget._copyProperties(this); + clonedWidget._copyClonedWidgetChildren(this); return clonedWidget; }, - createCloneInstance: function () { - return ccui.Widget.create(); + _createCloneInstance: function () { + return new ccui.Widget(); }, - copyClonedWidgetChildren: function (model) { + _copyClonedWidgetChildren: function (model) { var widgetChildren = model.getChildren(); for (var i = 0; i < widgetChildren.length; i++) { var locChild = widgetChildren[i]; - if(locChild instanceof ccui.Widget){ + if (locChild instanceof ccui.Widget) this.addChild(locChild.clone()); - } } }, - copySpecialProperties: function (model) { - - }, + _copySpecialProperties: function (model) {}, - copyProperties: function (widget) { + _copyProperties: function (widget) { this.setEnabled(widget.isEnabled()); this.setVisible(widget.isVisible()); this.setBright(widget.isBright()); this.setTouchEnabled(widget.isTouchEnabled()); - this._touchPassedEnabled = false; this.setLocalZOrder(widget.getLocalZOrder()); - this.setUpdateEnabled(widget.isUpdateEnabled()); this.setTag(widget.getTag()); this.setName(widget.getName()); this.setActionTag(widget.getActionTag()); + this._ignoreSize = widget._ignoreSize; - this._size = cc.size(widget._size.width, widget._size.height); - this._customSize = cc.size(widget._customSize.width, widget._customSize.height); - this.copySpecialProperties(widget); + + this.setContentSize(widget._contentSize); + this._customSize.width = widget._customSize.width; + this._customSize.height = widget._customSize.height; + + this._copySpecialProperties(widget); this._sizeType = widget.getSizeType(); - this._sizePercent = cc.p(widget._sizePercent.x, widget._sizePercent.y); - this.positionType = widget.positionType; - this._positionPercent = cc.p(widget._positionPercent.x, widget._positionPercent.y); + this._sizePercent.x = widget._sizePercent.x; + this._sizePercent.y = widget._sizePercent.y; + + this._positionType = widget._positionType; + this._positionPercent.x = widget._positionPercent.x; + this._positionPercent.y = widget._positionPercent.y; + this.setPosition(widget.getPosition()); this.setAnchorPoint(widget.getAnchorPoint()); this.setScaleX(widget.getScaleX()); @@ -1356,14 +1494,23 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ this.setFlippedY(widget.isFlippedY()); this.setColor(widget.getColor()); this.setOpacity(widget.getOpacity()); + + this._touchEventCallback = widget._touchEventCallback; + this._touchEventListener = widget._touchEventListener; + this._touchEventSelector = widget._touchEventSelector; + this._clickEventListener = widget._clickEventListener; + this._focused = widget._focused; + this._focusEnabled = widget._focusEnabled; + this._propagateTouchEvents = widget._propagateTouchEvents; + for (var key in widget._layoutParameterDictionary) { var parameter = widget._layoutParameterDictionary[key]; if (parameter) this.setLayoutParameter(parameter.clone()); } - this.onSizeChanged(); + this._onSizeChanged(); }, - + /*temp action*/ setActionTag: function (tag) { this._actionTag = tag; @@ -1372,68 +1519,323 @@ ccui.Widget = ccui.Node.extend(/** @lends ccui.Widget# */{ getActionTag: function () { return this._actionTag; }, + + /** + * Gets the left boundary position of this widget. + * @deprecated since v3.0, please use getLeftBoundary instead. + * @returns {number} + */ + getLeftInParent: function(){ + cc.log("getLeftInParent is deprecated. Please use getLeftBoundary instead."); + return this.getLeftBoundary(); + }, + /** - * Set color - * @param {cc.Color} color + * Gets the bottom boundary position of this widget. + * @deprecated since v3.0, please use getBottomBoundary instead. + * @returns {number} */ - setColor: function (color) { - this._color.r = color.r; - this._color.g = color.g; - this._color.b = color.b; - this.updateTextureColor(); - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } + getBottomInParent: function(){ + cc.log("getBottomInParent is deprecated. Please use getBottomBoundary instead."); + return this.getBottomBoundary(); + }, + + /** + * Gets the right boundary position of this widget. + * @deprecated since v3.0, please use getRightBoundary instead. + * @returns {number} + */ + getRightInParent: function(){ + cc.log("getRightInParent is deprecated. Please use getRightBoundary instead."); + return this.getRightBoundary(); + }, + + /** + * Gets the top boundary position of this widget. + * @deprecated since v3.0, please use getTopBoundary instead. + * @returns {number} + */ + getTopInParent: function(){ + cc.log("getTopInParent is deprecated. Please use getTopBoundary instead."); + return this.getTopBoundary(); + }, + + /** + * Gets the touch end point of widget when widget is selected. + * @deprecated since v3.0, please use getTouchEndPosition instead. + * @returns {cc.Point} the touch end point. + */ + getTouchEndPos: function () { + cc.log("getTouchEndPos is deprecated. Please use getTouchEndPosition instead."); + return this.getTouchEndPosition(); + }, + + /** + *Gets the touch move point of widget when widget is selected. + * @deprecated since v3.0, please use getTouchMovePosition instead. + * @returns {cc.Point} the touch move point. + */ + getTouchMovePos: function () { + cc.log("getTouchMovePos is deprecated. Please use getTouchMovePosition instead."); + return this.getTouchMovePosition(); + }, + + /** + * Checks a point if in parent's area. + * @deprecated since v3.0, please use isClippingParentContainsPoint instead. + * @param {cc.Point} pt + * @returns {Boolean} + */ + clippingParentAreaContainPoint: function (pt) { + cc.log("clippingParentAreaContainPoint is deprecated. Please use isClippingParentContainsPoint instead."); + this.isClippingParentContainsPoint(pt); }, /** - * Get color - * @returns {cc.Color} + * Gets the touch began point of widget when widget is selected. + * @deprecated since v3.0, please use getTouchBeganPosition instead. + * @returns {cc.Point} the touch began point. */ - getColor:function(){ - return cc.color(this._color.r,this._color.g,this._color.b,this._color.a) ; + getTouchStartPos: function () { + cc.log("getTouchStartPos is deprecated. Please use getTouchBeganPosition instead."); + return this.getTouchBeganPosition(); }, /** - * Set opacity - * @param {Number} opacity + * Changes the size that is widget's size + * @deprecated since v3.0, please use setContentSize instead. + * @param {cc.Size} size that is widget's size */ - setOpacity: function (opacity) { - this._color.a = opacity; - this.updateTextureOpacity(); + setSize: function (size) { + this.setContentSize(size); }, /** - * Get opacity - * @returns {Number} + * Returns size of widget + * @deprecated since v3.0, please use getContentSize instead. + * @returns {cc.Size} */ - getOpacity: function () { - return this._color.a; + getSize: function () { + return this.getContentSize(); }, - updateTextureColor: function () { + /** + * Adds a node for widget (this function is deleted in -x) + * @param {cc.Node} node + * @param {Number} zOrder + * @param {Number} tag + * @deprecated since v3.0, please use addChild instead. + */ + addNode: function (node, zOrder, tag) { + if (node instanceof ccui.Widget) { + cc.log("Please use addChild to add a Widget."); + return; + } + cc.Node.prototype.addChild.call(this, node, zOrder, tag); + this._nodes.push(node); + }, + /** + * Gets node by tag + * @deprecated since v3.0, please use getChildByTag instead. + * @param {Number} tag + * @returns {cc.Node} + */ + getNodeByTag: function (tag) { + var _nodes = this._nodes; + for (var i = 0; i < _nodes.length; i++) { + var node = _nodes[i]; + if (node && node.getTag() === tag) { + return node; + } + } + return null; }, - updateTextureOpacity: function () { + /** + * Returns all children. + * @deprecated since v3.0, please use getChildren instead. + * @returns {Array} + */ + getNodes: function () { + return this._nodes; + }, + /** + * Removes a node from ccui.Widget + * @deprecated since v3.0, please use removeChild instead. + * @param {cc.Node} node + * @param {Boolean} cleanup + */ + removeNode: function (node, cleanup) { + cc.Node.prototype.removeChild.call(this, node, cleanup); + cc.arrayRemoveObject(this._nodes, node); }, + /** + * Removes node by tag + * @deprecated since v3.0, please use removeChildByTag instead. + * @param {Number} tag + * @param {Boolean} [cleanup] + */ + removeNodeByTag: function (tag, cleanup) { + var node = this.getChildByTag(tag); + if (!node) + cc.log("cocos2d: removeNodeByTag(tag = %d): child not found!", tag); + else + this.removeChild(node, cleanup); + }, - updateColorToRenderer: function (renderer) { - if (renderer.RGBAProtocol) { - renderer.setColor(this._color); + /** + * Removes all node + * @deprecated since v3.0, please use removeAllChildren instead. + */ + removeAllNodes: function () { + for (var i = 0; i < this._nodes.length; i++) { + var node = this._nodes[i]; + cc.Node.prototype.removeChild.call(this, node); } + this._nodes.length = 0; }, - updateOpacityToRenderer: function (renderer) { - if (renderer.RGBAProtocol) { - renderer.setOpacity(this._color.a); + _findLayout: function(){ + cc.renderer.childrenOrderDirty = true; + var layout = this._parent; + while(layout){ + if(layout._doLayout){ + layout._doLayoutDirty = true; + break; + }else + layout = layout._parent; } + }, + + /** + * @since v3.2 + * @returns {boolean} true represent the widget use Unify Size, false represent the widget couldn't use Unify Size + */ + isUnifySizeEnabled: function(){ + return this._unifySize; + }, + + /** + * @since v3.2 + * @param {Boolean} enable enable Unify Size of a widget + */ + setUnifySizeEnabled: function(enable){ + this._unifySize = enable; + }, + + //v3.3 + _ccEventCallback: null, + /** + * Set a event handler to the widget in order to use cocostudio editor and framework + * @since v3.3 + * @param {function} callback + */ + addCCSEventListener: function(callback){ + this._ccEventCallback = callback; + }, + + //override the scale functions. + setScaleX: function(scaleX){ + if (this._flippedX) + scaleX = scaleX * -1; + cc.Node.prototype.setScaleX.call(this, scaleX); + }, + setScaleY: function(scaleY){ + if (this._flippedY) + scaleY = scaleY * -1; + cc.Node.prototype.setScaleY.call(this, scaleY); + }, + setScale: function(scaleX, scaleY){ + if(scaleY === undefined) + scaleY = scaleX; + this.setScaleX(scaleX); + this.setScaleY(scaleY); + }, + + getScaleX: function(){ + var originalScale = cc.Node.prototype.getScaleX.call(this); + if (this._flippedX) + originalScale = originalScale * -1.0; + return originalScale; + }, + getScaleY: function(){ + var originalScale = cc.Node.prototype.getScaleY.call(this); + if (this._flippedY) + originalScale = originalScale * -1.0; + return originalScale; + }, + getScale: function(){ + if(this.getScaleX() === this.getScaleY()) + cc.log("Widget#scale. ScaleX != ScaleY. Don't know which one to return"); + return this.getScaleX(); + }, + + /** + * Sets callback name to widget. + * @since v3.3 + * @param {String} callbackName + */ + setCallbackName: function(callbackName){ + this._callbackName = callbackName; + }, + + /** + * Gets callback name of widget + * @since v3.3 + * @returns {String|Null} + */ + getCallbackName: function(){ + return this._callbackName; + }, + + /** + * Sets callback type to widget + * @since v3.3 + * @param {String} callbackType + */ + setCallbackType: function(callbackType){ + this._callbackType = callbackType; + }, + + /** + * Gets callback type of widget + * @since v3.3 + * @returns {String|null} + */ + getCallbackType: function(){ + return this._callbackType; + }, + + /** + * Whether enable layout component of a widget + * @since v3.3 + * @param {Boolean} enable enable layout Component of a widget + */ + setLayoutComponentEnabled: function(enable){ + this._usingLayoutComponent = enable; + }, + + /** + * Returns whether enable layout component of a widget + * @return {Boolean} true represent the widget use Layout Component, false represent the widget couldn't use Layout Component. + */ + isLayoutComponentEnabled: function(){ + return this._usingLayoutComponent; + }, + + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + return new ccui.Widget.WebGLRenderCmd(this); + else + return new ccui.Widget.CanvasRenderCmd(this); } }); -window._p = ccui.Widget.prototype; +var _p = ccui.Widget.prototype; // Extended properties /** @expose */ @@ -1478,50 +1880,180 @@ cc.defineGetterSetter(_p, "name", _p.getName, _p.setName); /** @expose */ _p.actionTag; cc.defineGetterSetter(_p, "actionTag", _p.getActionTag, _p.setActionTag); +/** @expose */ +_p.opacity; +cc.defineGetterSetter(_p, "opacity", _p.getOpacity, _p.setOpacity); -delete window._p; +_p = null; /** * allocates and initializes a UIWidget. - * @constructs + * @deprecated * @return {ccui.Widget} - * @example - * // example - * var uiWidget = ccui.Widget.create(); */ ccui.Widget.create = function () { - var widget = new ccui.Widget(); - if (widget && widget.init()) { - return widget; + return new ccui.Widget(); +}; + +ccui.Widget._focusedWidget = null; //both layout & widget will be stored in this variable +ccui.Widget._focusNavigationController = null; + +/** + * call this method with parameter true to enable the Android Dpad focus navigation feature + * @note it doesn't implemented on Web + * @param {Boolean} enable set true to enable dpad focus navigation, otherwise disable dpad focus navigation + */ +ccui.Widget.enableDpadNavigation = function(enable){ + if (enable){ + if (null == ccui.Widget._focusNavigationController) { + ccui.Widget._focusNavigationController = new ccui._FocusNavigationController(); + if (ccui.Widget._focusedWidget) { + ccui.Widget._focusNavigationController._setFirstFocsuedWidget(ccui.Widget._focusedWidget); + } + } + ccui.Widget._focusNavigationController.enableFocusNavigation(true); + } else { + if(ccui.Widget._focusNavigationController){ + ccui.Widget._focusNavigationController.enableFocusNavigation(false); + ccui.Widget._focusNavigationController = null; + } } - return null; }; +/** + * Gets the focused widget of current stage. + * @function + * @returns {null|ccui.Widget} + */ +ccui.Widget.getCurrentFocusedWidget = function(){ + return ccui.Widget._focusedWidget; +}; // Constants //bright style +/** + * None bright style of ccui.Widget. + * @constant + * @type {number} + */ ccui.Widget.BRIGHT_STYLE_NONE = -1; +/** + * Normal bright style of ccui.Widget. + * @constant + * @type {number} + */ ccui.Widget.BRIGHT_STYLE_NORMAL = 0; +/** + * Light bright style of ccui.Widget. + * @constant + * @type {number} + */ ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT = 1; //widget type +/** + * The type code of Widget for ccui controls. + * @constant + * @type {number} + */ ccui.Widget.TYPE_WIDGET = 0; +/** + * The type code of Container for ccui controls. + * @constant + * @type {number} + */ ccui.Widget.TYPE_CONTAINER = 1; +//Focus Direction +/** + * The left of Focus direction for ccui.Widget + * @constant + * @type {number} + */ +ccui.Widget.LEFT = 0; +/** + * The right of Focus direction for ccui.Widget + * @constant + * @type {number} + */ +ccui.Widget.RIGHT = 1; +/** + * The up of Focus direction for ccui.Widget + * @constant + * @type {number} + */ +ccui.Widget.UP = 2; +/** + * The down of Focus direction for ccui.Widget + * @constant + * @type {number} + */ +ccui.Widget.DOWN = 3; + //texture resource type +/** + * The image file texture type of ccui.Widget loads. + * @constant + * @type {number} + */ ccui.Widget.LOCAL_TEXTURE = 0; +/** + * The sprite frame texture type of ccui.Widget loads. + * @constant + * @type {number} + */ ccui.Widget.PLIST_TEXTURE = 1; //touch event type +/** + * The touch began type of ccui.Widget's touch event + * @constant + * @type {number} + */ ccui.Widget.TOUCH_BEGAN = 0; +/** + * The touch moved type of ccui.Widget's touch event + * @constant + * @type {number} + */ ccui.Widget.TOUCH_MOVED = 1; +/** + * The touch end type of ccui.Widget's touch event + * @constant + * @type {number} + */ ccui.Widget.TOUCH_ENDED = 2; +/** + * The touch canceled type of ccui.Widget's touch event + * @constant + * @type {number} + */ ccui.Widget.TOUCH_CANCELED = 3; //size type +/** + * The absolute of ccui.Widget's size type. + * @constant + * @type {number} + */ ccui.Widget.SIZE_ABSOLUTE = 0; +/** + * The percent of ccui.Widget's size type. + * @constant + * @type {number} + */ ccui.Widget.SIZE_PERCENT = 1; //position type +/** + * The absolute of ccui.Widget's position type. + * @constant + * @type {number} + */ ccui.Widget.POSITION_ABSOLUTE = 0; -ccui.Widget.POSITION_PERCENT = 1; \ No newline at end of file +/** + * The percent of ccui.Widget's position type. + * @constant + * @type {number} + */ +ccui.Widget.POSITION_PERCENT = 1; diff --git a/extensions/ccui/base-classes/UIWidgetRenderCmd.js b/extensions/ccui/base-classes/UIWidgetRenderCmd.js new file mode 100644 index 0000000000..3faca0b751 --- /dev/null +++ b/extensions/ccui/base-classes/UIWidgetRenderCmd.js @@ -0,0 +1,100 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +if (cc._renderType === cc._RENDER_TYPE_CANVAS) { + (function () { + ccui.Widget.CanvasRenderCmd = function (renderable) { + cc.ProtectedNode.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = ccui.Widget.CanvasRenderCmd.prototype = Object.create(cc.ProtectedNode.CanvasRenderCmd.prototype); + proto.constructor = ccui.Widget.CanvasRenderCmd; + + proto.visit = function (parentCmd) { + var node = this._node; + if (node._visible) { + node._adaptRenderers(); + cc.ProtectedNode.CanvasRenderCmd.prototype.visit.call(this, parentCmd); + } + }; + + proto.transform = function (parentCmd, recursive) { + var node = this._node; + + if (node._visible) { + node._adaptRenderers(); + if(!this._usingLayoutComponent){ + var widgetParent = node.getWidgetParent(); + if (widgetParent) { + var parentSize = widgetParent.getContentSize(); + if (parentSize.width !== 0 && parentSize.height !== 0) { + node._position.x = parentSize.width * node._positionPercent.x; + node._position.y = parentSize.height * node._positionPercent.y; + } + } + } + cc.ProtectedNode.CanvasRenderCmd.prototype.transform.call(this, parentCmd, recursive); + } + }; + })(); +} else { + (function () { + ccui.Widget.WebGLRenderCmd = function (renderable) { + cc.ProtectedNode.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = ccui.Widget.WebGLRenderCmd.prototype = Object.create(cc.ProtectedNode.WebGLRenderCmd.prototype); + proto.constructor = ccui.Widget.WebGLRenderCmd; + + proto.visit = function (parentCmd) { + var node = this._node; + if (node._visible) { + node._adaptRenderers(); + cc.ProtectedNode.WebGLRenderCmd.prototype.visit.call(this, parentCmd); + } + }; + + proto.transform = function(parentCmd, recursive){ + var node = this._node; + if (node._visible) { + node._adaptRenderers(); + + if(!this._usingLayoutComponent) { + var widgetParent = node.getWidgetParent(); + if (widgetParent) { + var parentSize = widgetParent.getContentSize(); + if (parentSize.width !== 0 && parentSize.height !== 0) { + node._position.x = parentSize.width * node._positionPercent.x; + node._position.y = parentSize.height * node._positionPercent.y; + } + } + } + cc.ProtectedNode.WebGLRenderCmd.prototype.transform.call(this, parentCmd, recursive); + } + }; + })(); +} + diff --git a/extensions/ccui/layouts/UIHBox.js b/extensions/ccui/layouts/UIHBox.js new file mode 100644 index 0000000000..4e32002dd4 --- /dev/null +++ b/extensions/ccui/layouts/UIHBox.js @@ -0,0 +1,80 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * The horizontal box of Cocos UI. Its layout type is ccui.Layout.LINEAR_HORIZONTAL. + * @class + * @extends ccui.Layout + */ +ccui.HBox = ccui.Layout.extend(/** @lends ccui.HBox# */{ + /** + * The constructor of ccui.HBox + * @function + * @param {cc.Size} [size] + */ + ctor: function(size){ + ccui.Layout.prototype.ctor.call(this, size); + if(size !== undefined) + this.initWithSize(size); + else + this.init(); + }, + + /** + * Initialize a HBox. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @override + * @returns {boolean} + */ + init: function(){ + if(ccui.Layout.prototype.init.call(this)){ + this.setLayoutType(ccui.Layout.LINEAR_HORIZONTAL); + return true; + } + return false; + }, + + /** + * Initializes a HBox with size. + * @param size + * @returns {boolean} + */ + initWithSize: function(size){ + if(this.init()){ + this.setContentSize(size); + return true; + } + return false; + } +}); + +/** + * Creates a HBox object + * @deprecated since v3.0, please use new ccui.HBox(size) instead. + * @param {cc.Size} size + * @returns {ccui.HBox} + */ +ccui.HBox.create = function(size){ + return new ccui.HBox(size); +}; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayout.js b/extensions/ccui/layouts/UILayout.js index 875092e05a..99b242c2ae 100644 --- a/extensions/ccui/layouts/UILayout.js +++ b/extensions/ccui/layouts/UILayout.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,8 @@ ****************************************************************************/ /** - * Base class for ccui.Layout + * ccui.Layout is the base class of ccui.PageView and ccui.ScrollView, it does layout by layout manager + * and clips area by its _clippingStencil when clippingEnabled is true. * @class * @extends ccui.Widget * @@ -33,436 +35,325 @@ * */ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ - _clippingEnabled: null, + _clippingEnabled: false, _backGroundScale9Enabled: null, _backGroundImage: null, _backGroundImageFileName: null, _backGroundImageCapInsets: null, _colorType: null, - _bgImageTexType: null, + _bgImageTexType: ccui.Widget.LOCAL_TEXTURE, _colorRender: null, _gradientRender: null, _color: null, _startColor: null, _endColor: null, _alongVector: null, - _opacity: null, + _opacity: 255, _backGroundImageTextureSize: null, _layoutType: null, - _doLayoutDirty: false, - _clippingRectDirty: false, - _clippingType : null, + _doLayoutDirty: true, + _clippingRectDirty: true, + _clippingType: null, _clippingStencil: null, - _handleScissor: false, _scissorRectDirty: false, _clippingRect: null, _clippingParent: null, - _className:"Layout", - _backGroundImageColor:null, + _className: "Layout", + _backGroundImageColor: null, + _finalPositionX: 0, + _finalPositionY: 0, + + _backGroundImageOpacity:0, + + _loopFocus: false, //whether enable loop focus or not + __passFocusToChild: true, //on default, it will pass the focus to the next nearest widget + _isFocusPassing:false, //when finding the next focused widget, use this variable to pass focus between layout & widget + _isInterceptTouch: false, + + /** + * Allocates and initializes an UILayout. + * Constructor of ccui.Layout + * @function + * @example + * // example + * var uiLayout = new ccui.Layout(); + */ ctor: function () { + this._layoutType = ccui.Layout.ABSOLUTE; + this._widgetType = ccui.Widget.TYPE_CONTAINER; + this._clippingType = ccui.Layout.CLIPPING_STENCIL; + this._colorType = ccui.Layout.BG_COLOR_NONE; + ccui.Widget.prototype.ctor.call(this); - this._clippingEnabled = false; - this._backGroundScale9Enabled = false; - this._backGroundImage = null; - this._backGroundImageFileName = ""; this._backGroundImageCapInsets = cc.rect(0, 0, 0, 0); - this._colorType = ccui.Layout.BG_COLOR_NONE; - this._bgImageTexType = ccui.Widget.LOCAL_TEXTURE; - this._colorRender = null; - this._gradientRender = null; + this._color = cc.color(255, 255, 255, 255); this._startColor = cc.color(255, 255, 255, 255); this._endColor = cc.color(255, 255, 255, 255); this._alongVector = cc.p(0, -1); - this._opacity = 255; this._backGroundImageTextureSize = cc.size(0, 0); - this._layoutType = ccui.Layout.ABSOLUTE; - this._widgetType = ccui.Widget.TYPE_CONTAINER; - this._doLayoutDirty = true; - this._clippingRectDirty = true; - this._clippingType = ccui.Layout.CLIPPING_STENCIL; - this._clippingStencil = null; - this._handleScissor = false; - this._scissorRectDirty = false; + this._clippingRect = cc.rect(0, 0, 0, 0); - this._clippingParent = null; this._backGroundImageColor = cc.color(255, 255, 255, 255); }, + + /** + * Calls its parent's onEnter, and calls its clippingStencil's onEnter if clippingStencil isn't null. + * @override + */ + onEnter: function(){ + ccui.Widget.prototype.onEnter.call(this); + if (this._clippingStencil) + this._clippingStencil.onEnter(); + this._doLayoutDirty = true; + this._clippingRectDirty = true; + }, + + /** + * Calls its parent's onExit, and calls its clippingStencil's onExit if clippingStencil isn't null. + * @override + */ + onExit: function(){ + ccui.Widget.prototype.onExit.call(this); + if (this._clippingStencil) + this._clippingStencil.onExit(); + }, + + /** + * If a layout is loop focused which means that the focus movement will be inside the layout + * @param {Boolean} loop pass true to let the focus movement loop inside the layout + */ + setLoopFocus: function(loop){ + this._loopFocus = loop; + }, + + /** + * Gets whether enable focus loop + * @returns {boolean} If focus loop is enabled, then it will return true, otherwise it returns false. The default value is false. + */ + isLoopFocus: function(){ + return this._loopFocus; + }, + + /** + * Specifies whether the layout pass its focus to its child + * @param pass To specify whether the layout pass its focus to its child + */ + setPassFocusToChild: function(pass){ + this.__passFocusToChild = pass; + }, + + /** + * Returns whether the layout will pass the focus to its children or not. The default value is true + * @returns {boolean} To query whether the layout will pass the focus to its children or not. The default value is true + */ + isPassFocusToChild: function(){ + return this.__passFocusToChild; + }, + + /** + * When a widget is in a layout, you could call this method to get the next focused widget within a specified direction. + * If the widget is not in a layout, it will return itself + * @param {Number} direction the direction to look for the next focused widget in a layout + * @param {ccui.Widget} current the current focused widget + * @returns {ccui.Widget} return the index of widget in the layout + */ + findNextFocusedWidget: function(direction, current){ + if (this._isFocusPassing || this.isFocused()) { + var parent = this.getParent(); + this._isFocusPassing = false; + if (this.__passFocusToChild) { + var w = this._passFocusToChild(direction, current); + if (w instanceof ccui.Layout && parent) { + parent._isFocusPassing = true; + return parent.findNextFocusedWidget(direction, this); + } + return w; + } + + if (null == parent || !(parent instanceof ccui.Layout)) + return this; + parent._isFocusPassing = true; + return parent.findNextFocusedWidget(direction, this); + } else if(current.isFocused() || current instanceof ccui.Layout) { + if (this._layoutType === ccui.Layout.LINEAR_HORIZONTAL) { + switch (direction){ + case ccui.Widget.LEFT: + return this._getPreviousFocusedWidget(direction, current); + break; + case ccui.Widget.RIGHT: + return this._getNextFocusedWidget(direction, current); + break; + case ccui.Widget.DOWN: + case ccui.Widget.UP: + if (this._isLastWidgetInContainer(this, direction)){ + if (this._isWidgetAncestorSupportLoopFocus(current, direction)) + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + return current; + } else { + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + } + break; + default: + cc.assert(0, "Invalid Focus Direction"); + return current; + } + } else if (this._layoutType === ccui.Layout.LINEAR_VERTICAL) { + switch (direction){ + case ccui.Widget.LEFT: + case ccui.Widget.RIGHT: + if (this._isLastWidgetInContainer(this, direction)) { + if (this._isWidgetAncestorSupportLoopFocus(current, direction)) + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + return current; + } + else + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + break; + case ccui.Widget.DOWN: + return this._getNextFocusedWidget(direction, current); + break; + case ccui.Widget.UP: + return this._getPreviousFocusedWidget(direction, current); + break; + default: + cc.assert(0, "Invalid Focus Direction"); + return current; + } + } else { + cc.assert(0, "Un Supported Layout type, please use VBox and HBox instead!!!"); + return current; + } + } else + return current; + }, + + /** + * To specify a user-defined functor to decide which child widget of the layout should get focused + * @function + * @param {Number} direction + * @param {ccui.Widget} current + */ + onPassFocusToChild: null, + + /** + * override "init" method of widget. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + * @override + */ init: function () { - if (cc.Node.prototype.init.call(this)){ - this._layoutParameterDictionary = {}; - this._widgetChildren = []; - this.initRenderer(); + if (ccui.Widget.prototype.init.call(this)) { this.ignoreContentAdaptWithSize(false); - this.setSize(cc.size(0, 0)); - this.setBright(true); + this.setContentSize(cc.size(0, 0)); this.setAnchorPoint(0, 0); - this.initStencil(); + this.onPassFocusToChild = this._findNearestChildWidgetIndex.bind(this); return true; } return false; }, - initStencil : null, - _initStencilForWebGL:function(){ - this._clippingStencil = cc.DrawNode.create(); - ccui.Layout._init_once = true; - if (ccui.Layout._init_once) { - cc.stencilBits = cc._renderContext.getParameter(cc._renderContext.STENCIL_BITS); - if (cc.stencilBits <= 0) - cc.log("Stencil buffer is not enabled."); - ccui.Layout._init_once = false; - } - }, - _initStencilForCanvas: function () { - this._clippingStencil = cc.DrawNode.create(); - var locEGL_ScaleX = cc.view.getScaleX(), locEGL_ScaleY = cc.view.getScaleY(); - var locContext = cc._renderContext; - var stencil = this._clippingStencil; - stencil.draw = function () { - for (var i = 0; i < stencil._buffer.length; i++) { - var element = stencil._buffer[i]; - var vertices = element.verts; - var firstPoint = vertices[0]; - locContext.beginPath(); - locContext.moveTo(firstPoint.x * locEGL_ScaleX, -firstPoint.y * locEGL_ScaleY); - for (var j = 1, len = vertices.length; j < len; j++) - locContext.lineTo(vertices[j].x * locEGL_ScaleX, -vertices[j].y * locEGL_ScaleY); - } - } - }, /** * Adds a widget to the container. * @param {ccui.Widget} widget - * @param {Number} zOrder - * @param {Number} tag + * @param {Number} [zOrder] + * @param {Number|string} [tag] tag or name + * @override */ addChild: function (widget, zOrder, tag) { - if(!(widget instanceof ccui.Widget)){ - throw "the child add to Layout must a type of cc.Widget"; + if ((widget instanceof ccui.Widget)) { + this._supplyTheLayoutParameterLackToChild(widget); } - this.supplyTheLayoutParameterLackToChild(widget); ccui.Widget.prototype.addChild.call(this, widget, zOrder, tag); this._doLayoutDirty = true; }, /** - * Remove widget + * Removes child widget from ccui.Layout, and sets the layout dirty flag to true. * @param {ccui.Widget} widget - * @param {Boolean} cleanup + * @param {Boolean} [cleanup=true] + * @override */ - removeChild:function(widget,cleanup){ - ccui.Widget.prototype.removeChild.call(this, widget,cleanup); + removeChild: function (widget, cleanup) { + ccui.Widget.prototype.removeChild.call(this, widget, cleanup); this._doLayoutDirty = true; }, /** - * Remove all widget + * Removes all children from the container with a cleanup, and sets the layout dirty flag to true. * @param {Boolean} cleanup */ - removeAllChildren:function(cleanup){ + removeAllChildren: function (cleanup) { ccui.Widget.prototype.removeAllChildren.call(this, cleanup); this._doLayoutDirty = true; }, + /** + * Removes all children from the container, do a cleanup to all running actions depending on the cleanup parameter, + * and sets the layout dirty flag to true. + * @param {Boolean} cleanup true if all running actions on all children nodes should be cleanup, false otherwise. + */ + removeAllChildrenWithCleanup: function(cleanup){ + ccui.Widget.prototype.removeAllChildrenWithCleanup.call(this, cleanup); + this._doLayoutDirty = true; + }, + /** * Gets if layout is clipping enabled. - * @returns {Boolean} + * @returns {Boolean} if layout is clipping enabled. */ isClippingEnabled: function () { return this._clippingEnabled; }, - visit: function (ctx) { - if (!this._enabled) { + /** + *

    + * Calls adaptRenderers (its subclass will override it.) and do layout. + * If clippingEnabled is true, it will clip/scissor area. + *

    + * @override + * @param {cc.Node.RenderCmd} [parentCmd] + */ + visit: function (parentCmd) { + if (!this._visible) return; - } + this._adaptRenderers(); + this._doLayout(); + if (this._clippingEnabled) { switch (this._clippingType) { case ccui.Layout.CLIPPING_STENCIL: - this.stencilClippingVisit(ctx); + this._renderCmd.stencilClippingVisit(parentCmd); break; case ccui.Layout.CLIPPING_SCISSOR: - this.scissorClippingVisit(ctx); + this._renderCmd.scissorClippingVisit(parentCmd); break; default: break; } - } - else { - cc.Node.prototype.visit.call(this,ctx); - } - }, - - sortAllChildren: function () { - ccui.Widget.prototype.sortAllChildren.call(this); - this._doLayout(); - }, - - stencilClippingVisit : null, - - _stencilClippingVisitForWebGL: function (ctx) { - var gl = ctx || cc._renderContext; - - // if stencil buffer disabled - if (cc.stencilBits < 1) { - // draw everything, as if there where no stencil - cc.Node.prototype.visit.call(this, ctx); - return; - } - - // return fast (draw nothing, or draw everything if in inverted mode) if: - // - nil stencil node - // - or stencil node invisible: - if (!this._clippingStencil || !this._clippingStencil.isVisible()) { - return; - } - - // store the current stencil layer (position in the stencil buffer), - // this will allow nesting up to n CCClippingNode, - // where n is the number of bits of the stencil buffer. - ccui.Layout._layer = -1; - - // all the _stencilBits are in use? - if (ccui.Layout._layer + 1 == cc.stencilBits) { - // warn once - ccui.Layout._visit_once = true; - if (ccui.Layout._visit_once) { - cc.log("Nesting more than " + cc.stencilBits + "stencils is not supported. Everything will be drawn without stencil for this node and its childs."); - ccui.Layout._visit_once = false; - } - // draw everything, as if there where no stencil - cc.Node.prototype.visit.call(this, ctx); - return; - } - - /////////////////////////////////// - // INIT - - // increment the current layer - ccui.Layout._layer++; - - // mask of the current layer (ie: for layer 3: 00000100) - var mask_layer = 0x1 << ccui.Layout._layer; - // mask of all layers less than the current (ie: for layer 3: 00000011) - var mask_layer_l = mask_layer - 1; - // mask of all layers less than or equal to the current (ie: for layer 3: 00000111) - var mask_layer_le = mask_layer | mask_layer_l; - - // manually save the stencil state - var currentStencilEnabled = gl.isEnabled(gl.STENCIL_TEST); - var currentStencilWriteMask = gl.getParameter(gl.STENCIL_WRITEMASK); - var currentStencilFunc = gl.getParameter(gl.STENCIL_FUNC); - var currentStencilRef = gl.getParameter(gl.STENCIL_REF); - var currentStencilValueMask = gl.getParameter(gl.STENCIL_VALUE_MASK); - var currentStencilFail = gl.getParameter(gl.STENCIL_FAIL); - var currentStencilPassDepthFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL); - var currentStencilPassDepthPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS); - - // enable stencil use - gl.enable(gl.STENCIL_TEST); - // check for OpenGL error while enabling stencil test - //cc.checkGLErrorDebug(); - - // all bits on the stencil buffer are readonly, except the current layer bit, - // this means that operation like glClear or glStencilOp will be masked with this value - gl.stencilMask(mask_layer); - - // manually save the depth test state - //GLboolean currentDepthTestEnabled = GL_TRUE; - //currentDepthTestEnabled = glIsEnabled(GL_DEPTH_TEST); - var currentDepthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK); - - // disable depth test while drawing the stencil - //glDisable(GL_DEPTH_TEST); - // disable update to the depth buffer while drawing the stencil, - // as the stencil is not meant to be rendered in the real scene, - // it should never prevent something else to be drawn, - // only disabling depth buffer update should do - gl.depthMask(false); - - /////////////////////////////////// - // CLEAR STENCIL BUFFER - - // manually clear the stencil buffer by drawing a fullscreen rectangle on it - // setup the stencil test func like this: - // for each pixel in the fullscreen rectangle - // never draw it into the frame buffer - // if not in inverted mode: set the current layer value to 0 in the stencil buffer - // if in inverted mode: set the current layer value to 1 in the stencil buffer - gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); - gl.stencilOp(gl.ZERO, gl.KEEP, gl.KEEP); - - // draw a fullscreen solid rectangle to clear the stencil buffer - //ccDrawSolidRect(CCPointZero, ccpFromSize([[CCDirector sharedDirector] winSize]), ccc4f(1, 1, 1, 1)); - cc._drawingUtil.drawSolidRect(cc.p(0,0), cc.pFromSize(cc.director.getWinSize()), cc.color(255, 255, 255, 255)); - - /////////////////////////////////// - // DRAW CLIPPING STENCIL - - // setup the stencil test func like this: - // for each pixel in the stencil node - // never draw it into the frame buffer - // if not in inverted mode: set the current layer value to 1 in the stencil buffer - // if in inverted mode: set the current layer value to 0 in the stencil buffer - gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); - gl.stencilOp(gl.REPLACE, gl.KEEP, gl.KEEP); - - - // draw the stencil node as if it was one of our child - // (according to the stencil test func/op and alpha (or alpha shader) test) - cc.kmGLPushMatrix(); - this.transform(); - this._clippingStencil.visit(); - cc.kmGLPopMatrix(); - - // restore alpha test state - //if (this._alphaThreshold < 1) { - // XXX: we need to find a way to restore the shaders of the stencil node and its childs - //} - - // restore the depth test state - gl.depthMask(currentDepthWriteMask); - //if (currentDepthTestEnabled) { - // glEnable(GL_DEPTH_TEST); - //} - - /////////////////////////////////// - // DRAW CONTENT - - // setup the stencil test func like this: - // for each pixel of this node and its childs - // if all layers less than or equals to the current are set to 1 in the stencil buffer - // draw the pixel and keep the current layer in the stencil buffer - // else - // do not draw the pixel but keep the current layer in the stencil buffer - gl.stencilFunc(gl.EQUAL, mask_layer_le, mask_layer_le); - gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); - - // draw (according to the stencil test func) this node and its childs - cc.Node.prototype.visit.call(this, ctx); - - /////////////////////////////////// - // CLEANUP - - // manually restore the stencil state - gl.stencilFunc(currentStencilFunc, currentStencilRef, currentStencilValueMask); - gl.stencilOp(currentStencilFail, currentStencilPassDepthFail, currentStencilPassDepthPass); - gl.stencilMask(currentStencilWriteMask); - if (!currentStencilEnabled) - gl.disable(gl.STENCIL_TEST); - - // we are done using this layer, decrement - ccui.Layout._layer--; - }, - - _stencilClippingVisitForCanvas: function (ctx) { - // return fast (draw nothing, or draw everything if in inverted mode) if: - // - nil stencil node - // - or stencil node invisible: - if (!this._clippingStencil || !this._clippingStencil.isVisible()) { - return; - } - var context = ctx || cc._renderContext; - // Composition mode, costy but support texture stencil - if (this._cangodhelpme() || this._clippingStencil instanceof cc.Sprite) { - // Cache the current canvas, for later use (This is a little bit heavy, replace this solution with other walkthrough) - var canvas = context.canvas; - var locCache = ccui.Layout._getSharedCache(); - locCache.width = canvas.width; - locCache.height = canvas.height; - var locCacheCtx = locCache.getContext("2d"); - locCacheCtx.drawImage(canvas, 0, 0); - - context.save(); - // Draw everything first using node visit function - cc.Node.prototype.visit.call(this, context); - - context.globalCompositeOperation = "destination-in"; - - this.transform(context); - this._clippingStencil.visit(); - - context.restore(); - - // Redraw the cached canvas, so that the cliped area shows the background etc. - context.save(); - context.setTransform(1, 0, 0, 1, 0, 0); - context.globalCompositeOperation = "destination-over"; - context.drawImage(locCache, 0, 0); - context.restore(); - } - // Clip mode, fast, but only support cc.DrawNode - else { - var i, children = this._children, locChild; - - context.save(); - this.transform(context); - this._clippingStencil.visit(context); - context.clip(); - - // Clip mode doesn't support recusive stencil, so once we used a clip stencil, - // so if it has ClippingNode as a child, the child must uses composition stencil. - this._cangodhelpme(true); - var len = children.length; - if (len > 0) { - this.sortAllChildren(); - // draw children zOrder < 0 - for (i = 0; i < len; i++) { - locChild = children[i]; - if (locChild._localZOrder < 0) - locChild.visit(context); - else - break; - } - this.draw(context); - for (; i < len; i++) { - children[i].visit(context); - } - } else - this.draw(context); - this._cangodhelpme(false); - - context.restore(); - } - }, - - _godhelpme:false, - _cangodhelpme: function (godhelpme) { - if (godhelpme === true || godhelpme === false) - cc.ClippingNode.prototype._godhelpme = godhelpme; - return cc.ClippingNode.prototype._godhelpme; - }, - - scissorClippingVisit : null, - _scissorClippingVisitForWebGL: function (ctx) { - var clippingRect = this.getClippingRect(); - var gl = ctx || cc._renderContext; - if (this._handleScissor) { - gl.enable(gl.SCISSOR_TEST); - } - cc.view.setScissorInPoints(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); - cc.Node.prototype.visit.call(this); - if (this._handleScissor) { - gl.disable(gl.SCISSOR_TEST); - } + } else + ccui.Widget.prototype.visit.call(this, parentCmd); }, /** * Changes if layout can clip it's content and locChild. - * @param {Boolean} able + * If you really need this, please enable it. But it would reduce the rendering efficiency. + * @param {Boolean} able clipping enabled. */ setClippingEnabled: function (able) { - if (able == this._clippingEnabled) { + if (able === this._clippingEnabled) return; - } this._clippingEnabled = able; switch (this._clippingType) { case ccui.Layout.CLIPPING_STENCIL: - if (able) { - this.setStencilClippingSize(this._size); - } - else { + if (able){ + this._clippingStencil = new cc.DrawNode(); + this._renderCmd.rebindStencilRendering(this._clippingStencil); + if (this._running) + this._clippingStencil.onEnter(); + this._setStencilClippingSize(this._contentSize); + } else { + if (this._running && this._clippingStencil) + this._clippingStencil.onExit(); this._clippingStencil = null; } break; @@ -472,11 +363,14 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Set clipping type + * Sets clipping type to ccui.Layout * @param {ccui.Layout.CLIPPING_STENCIL|ccui.Layout.CLIPPING_SCISSOR} type */ setClippingType: function (type) { - if (type == this._clippingType) { + if (type === this._clippingType) + return; + if(cc._renderType === cc._RENDER_TYPE_CANVAS && type === ccui.Layout.CLIPPING_SCISSOR){ + cc.log("Only supports STENCIL on canvas mode."); return; } var clippingEnabled = this.isClippingEnabled(); @@ -486,15 +380,15 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get clipping type + * Gets clipping type of ccui.Layout * @returns {ccui.Layout.CLIPPING_STENCIL|ccui.Layout.CLIPPING_SCISSOR} */ - getClippingType : function(){ + getClippingType: function () { return this._clippingType; }, - setStencilClippingSize: function (size) { - if (this._clippingEnabled && this._clippingType == ccui.Layout.CLIPPING_STENCIL) { + _setStencilClippingSize: function (size) { + if (this._clippingEnabled && this._clippingType === ccui.Layout.CLIPPING_STENCIL) { var rect = []; rect[0] = cc.p(0, 0); rect[1] = cc.p(size.width, 0); @@ -506,39 +400,25 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ } }, - rendererVisitCallBack: function () { - this._doLayout(); - }, - - getClippingRect: function () { - if (this._clippingRectDirty){ - this._handleScissor = true; + _getClippingRect: function () { + if (this._clippingRectDirty) { var worldPos = this.convertToWorldSpace(cc.p(0, 0)); - var t = this.nodeToWorldTransform(); - var scissorWidth = this._size.width * t.a; - var scissorHeight = this._size.height * t.d; + var t = this.getNodeToWorldTransform(); + var scissorWidth = this._contentSize.width * t.a; + var scissorHeight = this._contentSize.height * t.d; var parentClippingRect; var parent = this; - var firstClippingParentFounded = false; + while (parent) { parent = parent.getParent(); - if (parent && parent instanceof ccui.Layout) { - if (parent.isClippingEnabled()) { - if (!firstClippingParentFounded) { - this._clippingParent = parent; - firstClippingParentFounded = true; - } - - if (parent._clippingType == ccui.Layout.CLIPPING_SCISSOR) { - this._handleScissor = false; - break; - } - } + if (parent && parent instanceof ccui.Layout && parent.isClippingEnabled()) { + this._clippingParent = parent; + break; } } if (this._clippingParent) { - parentClippingRect = this._clippingParent.getClippingRect(); + parentClippingRect = this._clippingParent._getClippingRect(); var finalX = worldPos.x - (scissorWidth * this._anchorPoint.x); var finalY = worldPos.y - (scissorHeight * this._anchorPoint.y); var finalWidth = scissorWidth; @@ -550,30 +430,25 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ finalWidth += leftOffset; } var rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.x + parentClippingRect.width); - if (rightOffset > 0) { + if (rightOffset > 0) finalWidth -= rightOffset; - } var topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.y + parentClippingRect.height); - if (topOffset > 0) { + if (topOffset > 0) finalHeight -= topOffset; - } var bottomOffset = worldPos.y - parentClippingRect.y; if (bottomOffset < 0) { finalY = parentClippingRect.x; finalHeight += bottomOffset; } - if (finalWidth < 0) { + if (finalWidth < 0) finalWidth = 0; - } - if (finalHeight < 0) { + if (finalHeight < 0) finalHeight = 0; - } this._clippingRect.x = finalX; this._clippingRect.y = finalY; this._clippingRect.width = finalWidth; this._clippingRect.height = finalHeight; - } - else { + } else { this._clippingRect.x = worldPos.x - (scissorWidth * this._anchorPoint.x); this._clippingRect.y = worldPos.y - (scissorHeight * this._anchorPoint.y); this._clippingRect.width = scissorWidth; @@ -584,55 +459,43 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ return this._clippingRect; }, - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.setContentSize(this._size); - this.setStencilClippingSize(this._size); + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + var locContentSize = this._contentSize; + this._setStencilClippingSize(locContentSize); this._doLayoutDirty = true; this._clippingRectDirty = true; if (this._backGroundImage) { - this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0); - if (this._backGroundScale9Enabled) { - if (this._backGroundImage instanceof cc.Scale9Sprite) { - this._backGroundImage.setPreferredSize(this._size); - } - } - } - if (this._colorRender) { - this._colorRender.setContentSize(this._size); - } - if (this._gradientRender) { - this._gradientRender.setContentSize(this._size); + this._backGroundImage.setPosition(locContentSize.width * 0.5, locContentSize.height * 0.5); + if (this._backGroundScale9Enabled && this._backGroundImage instanceof ccui.Scale9Sprite) + this._backGroundImage.setPreferredSize(locContentSize); } + if (this._colorRender) + this._colorRender.setContentSize(locContentSize); + if (this._gradientRender) + this._gradientRender.setContentSize(locContentSize); }, /** * Sets background image use scale9 renderer. - * @param {Boolean} able + * @param {Boolean} able true that use scale9 renderer, false otherwise. */ setBackGroundImageScale9Enabled: function (able) { - if (this._backGroundScale9Enabled == able) { + if (this._backGroundScale9Enabled === able) return; - } - cc.Node.prototype.removeChild.call(this, this._backGroundImage, true); + this.removeProtectedChild(this._backGroundImage); this._backGroundImage = null; this._backGroundScale9Enabled = able; - if (this._backGroundScale9Enabled) { - this._backGroundImage = cc.Scale9Sprite.create(); - } - else { - this._backGroundImage = cc.Sprite.create(); - } - cc.Node.prototype.addChild.call(this, this._backGroundImage, ccui.Layout.BACKGROUND_IMAGE_ZORDER, -1); + this._addBackGroundImage(); this.setBackGroundImage(this._backGroundImageFileName, this._bgImageTexType); this.setBackGroundImageCapInsets(this._backGroundImageCapInsets); }, /** - * Get background image is use scale9 renderer. + * Get whether background image is use scale9 renderer. * @returns {Boolean} */ - isBackGroundImageScale9Enabled:function(){ + isBackGroundImageScale9Enabled: function () { return this._backGroundScale9Enabled; }, @@ -642,53 +505,59 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ setBackGroundImage: function (fileName, texType) { - if (!fileName) { + if (!fileName) return; - } texType = texType || ccui.Widget.LOCAL_TEXTURE; - if (this._backGroundImage == null) { - this.addBackGroundImage(); + if (this._backGroundImage === null){ + this._addBackGroundImage(); + this.setBackGroundImageScale9Enabled(this._backGroundScale9Enabled); } this._backGroundImageFileName = fileName; this._bgImageTexType = texType; + var locBackgroundImage = this._backGroundImage; switch (this._bgImageTexType) { case ccui.Widget.LOCAL_TEXTURE: - this._backGroundImage.initWithFile(fileName); + locBackgroundImage.initWithFile(fileName); break; case ccui.Widget.PLIST_TEXTURE: - this._backGroundImage.initWithSpriteFrameName(fileName); + locBackgroundImage.initWithSpriteFrameName(fileName); break; default: break; } - if (this._backGroundScale9Enabled) { - this._backGroundImage.setPreferredSize(this._size); - } - this._backGroundImageTextureSize = this._backGroundImage.getContentSize(); - this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0); - this.updateBackGroundImageColor(); + if (this._backGroundScale9Enabled) + locBackgroundImage.setPreferredSize(this._contentSize); + + this._backGroundImageTextureSize = locBackgroundImage.getContentSize(); + locBackgroundImage.setPosition(this._contentSize.width * 0.5, this._contentSize.height * 0.5); + this._updateBackGroundImageColor(); }, /** - * Sets a background image capinsets for layout, if the background image is a scale9 render. - * @param {cc.Rect} capInsets + * Sets a background image CapInsets for layout, if the background image is a scale9 render. + * @param {cc.Rect} capInsets capinsets of background image. */ setBackGroundImageCapInsets: function (capInsets) { - this._backGroundImageCapInsets = capInsets; - if (this._backGroundScale9Enabled) { + if(!capInsets) + return; + var locInsets = this._backGroundImageCapInsets; + locInsets.x = capInsets.x; + locInsets.y = capInsets.y; + locInsets.width = capInsets.width; + locInsets.height = capInsets.height; + if (this._backGroundScale9Enabled) this._backGroundImage.setCapInsets(capInsets); - } }, /** - * Get background image cap insets. + * Gets background image capinsets of ccui.Layout. * @returns {cc.Rect} */ - getBackGroundImageCapInsets:function(){ - return this._backGroundImageCapInsets; + getBackGroundImageCapInsets: function () { + return cc.rect(this._backGroundImageCapInsets); }, - supplyTheLayoutParameterLackToChild: function (locChild) { + _supplyTheLayoutParameterLackToChild: function (locChild) { if (!locChild) { return; } @@ -698,77 +567,70 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ case ccui.Layout.LINEAR_HORIZONTAL: case ccui.Layout.LINEAR_VERTICAL: var layoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.LINEAR); - if (!layoutParameter) { - locChild.setLayoutParameter(ccui.LinearLayoutParameter.create()); - } + if (!layoutParameter) + locChild.setLayoutParameter(new ccui.LinearLayoutParameter()); break; case ccui.Layout.RELATIVE: var layoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.RELATIVE); - if (!layoutParameter) { - locChild.setLayoutParameter(ccui.RelativeLayoutParameter.create()); - } + if (!layoutParameter) + locChild.setLayoutParameter(new ccui.RelativeLayoutParameter()); break; default: break; } }, - /** - * init background image renderer. - */ - addBackGroundImage: function () { + _addBackGroundImage: function () { + var contentSize = this._contentSize; if (this._backGroundScale9Enabled) { - this._backGroundImage = cc.Scale9Sprite.create(); - this._backGroundImage.setPreferredSize(this._size); - } - else { - this._backGroundImage = cc.Sprite.create(); - } - cc.Node.prototype.addChild.call(this, this._backGroundImage, ccui.Layout.BACKGROUND_IMAGE_ZORDER, -1); - this._backGroundImage.setPosition(this._size.width / 2.0, this._size.height / 2.0); + this._backGroundImage = new ccui.Scale9Sprite(); + this._backGroundImage.setPreferredSize(contentSize); + } else + this._backGroundImage = new cc.Sprite(); + this.addProtectedChild(this._backGroundImage, ccui.Layout.BACKGROUND_IMAGE_ZORDER, -1); + this._backGroundImage.setPosition(contentSize.width * 0.5, contentSize.height * 0.5); }, /** - * Remove the background image of layout. + * Remove the background image of ccui.Layout. */ removeBackGroundImage: function () { - if (!this._backGroundImage) { + if (!this._backGroundImage) return; - } - cc.Node.prototype.removeChild.call(this, this._backGroundImage, true); + this.removeProtectedChild(this._backGroundImage); this._backGroundImage = null; this._backGroundImageFileName = ""; - this._backGroundImageTextureSize = cc.size(0, 0); + this._backGroundImageTextureSize.width = 0; + this._backGroundImageTextureSize.height = 0; }, /** - * Sets Color Type for layout. + * Sets Color Type for ccui.Layout. * @param {ccui.Layout.BG_COLOR_NONE|ccui.Layout.BG_COLOR_SOLID|ccui.Layout.BG_COLOR_GRADIENT} type */ setBackGroundColorType: function (type) { - if (this._colorType == type) { + if (this._colorType === type) return; - } switch (this._colorType) { case ccui.Layout.BG_COLOR_NONE: if (this._colorRender) { - cc.Node.prototype.removeChild.call(this, this._colorRender, true); + this.removeProtectedChild(this._colorRender); this._colorRender = null; } if (this._gradientRender) { - cc.Node.prototype.removeChild.call(this, this._gradientRender, true); + this.removeProtectedChild(this._gradientRender); this._gradientRender = null; } break; case ccui.Layout.BG_COLOR_SOLID: if (this._colorRender) { - cc.Node.prototype.removeChild.call(this, this._colorRender, true); + this.removeProtectedChild(this._colorRender); this._colorRender = null; } break; case ccui.Layout.BG_COLOR_GRADIENT: if (this._gradientRender) { - cc.Node.prototype.removeChild.call(this, this._gradientRender, true); + this.removeProtectedChild(this._gradientRender); this._gradientRender = null; } break; @@ -780,20 +642,20 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ case ccui.Layout.BG_COLOR_NONE: break; case ccui.Layout.BG_COLOR_SOLID: - this._colorRender = cc.LayerColor.create(); - this._colorRender.setContentSize(this._size); + this._colorRender = new cc.LayerColor(); + this._colorRender.setContentSize(this._contentSize); this._colorRender.setOpacity(this._opacity); this._colorRender.setColor(this._color); - cc.Node.prototype.addChild.call(this, this._colorRender, ccui.Layout.BACKGROUND_RENDERER_ZORDER, -1); + this.addProtectedChild(this._colorRender, ccui.Layout.BACKGROUND_RENDERER_ZORDER, -1); break; case ccui.Layout.BG_COLOR_GRADIENT: - this._gradientRender = cc.LayerGradient.create(cc.color(255, 0, 0, 255), cc.color(0, 255, 0, 255)); - this._gradientRender.setContentSize(this._size); + this._gradientRender = new cc.LayerGradient(cc.color(255, 0, 0, 255), cc.color(0, 255, 0, 255)); + this._gradientRender.setContentSize(this._contentSize); this._gradientRender.setOpacity(this._opacity); this._gradientRender.setStartColor(this._startColor); this._gradientRender.setEndColor(this._endColor); this._gradientRender.setVector(this._alongVector); - cc.Node.prototype.addChild.call(this, this._gradientRender, ccui.Layout.BACKGROUND_RENDERER_ZORDER, -1); + this.addProtectedChild(this._gradientRender, ccui.Layout.BACKGROUND_RENDERER_ZORDER, -1); break; default: break; @@ -801,67 +663,69 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get color type. + * Get background color type of ccui.Layout. * @returns {ccui.Layout.BG_COLOR_NONE|ccui.Layout.BG_COLOR_SOLID|ccui.Layout.BG_COLOR_GRADIENT} */ - getBackGroundColorType:function(){ + getBackGroundColorType: function () { return this._colorType; }, /** * Sets background color for layout, if color type is Layout.COLOR_SOLID * @param {cc.Color} color - * @param {cc.Color} endColor + * @param {cc.Color} [endColor] */ setBackGroundColor: function (color, endColor) { if (!endColor) { this._color.r = color.r; this._color.g = color.g; this._color.b = color.b; - if (this._colorRender) { + if (this._colorRender) this._colorRender.setColor(color); - } } else { this._startColor.r = color.r; this._startColor.g = color.g; this._startColor.b = color.b; - - if (this._gradientRender) { + if (this._gradientRender) this._gradientRender.setStartColor(color); - } - this._endColor = endColor; - if (this._gradientRender) { + + this._endColor.r = endColor.r; + this._endColor.g = endColor.g; + this._endColor.b = endColor.b; + if (this._gradientRender) this._gradientRender.setEndColor(endColor); - } } }, /** - * Get back ground color + * Gets background color of ccui.Layout, if color type is Layout.COLOR_SOLID. * @returns {cc.Color} */ - getBackGroundColor:function(){ - return this._color; + getBackGroundColor: function () { + var tmpColor = this._color; + return cc.color(tmpColor.r, tmpColor.g, tmpColor.b, tmpColor.a); }, /** - * Get back ground start color + * Gets background start color of ccui.Layout * @returns {cc.Color} */ - getBackGroundStartColor:function(){ - return this._startColor; + getBackGroundStartColor: function () { + var tmpColor = this._startColor; + return cc.color(tmpColor.r, tmpColor.g, tmpColor.b, tmpColor.a); }, /** - * Get back ground end color + * Gets background end color of ccui.Layout * @returns {cc.Color} */ - getBackGroundEndColor:function(){ - return this._endColor; + getBackGroundEndColor: function () { + var tmpColor = this._endColor; + return cc.color(tmpColor.r, tmpColor.g, tmpColor.b, tmpColor.a); }, /** - * Sets background opacity layout. + * Sets background opacity to ccui.Layout. * @param {number} opacity */ setBackGroundColorOpacity: function (opacity) { @@ -881,10 +745,10 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get background opacity value. + * Get background opacity value of ccui.Layout. * @returns {Number} */ - getBackGroundColorOpacity:function(){ + getBackGroundColorOpacity: function () { return this._opacity; }, @@ -901,15 +765,15 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get background color value. + * Gets background color vector of ccui.Layout, if color type is Layout.COLOR_GRADIENT * @returns {cc.Point} */ - getBackGroundColorVector:function(){ + getBackGroundColorVector: function () { return this._alongVector; }, /** - * Set backGround image color + * Sets backGround image color * @param {cc.Color} color */ setBackGroundImageColor: function (color) { @@ -917,14 +781,11 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ this._backGroundImageColor.g = color.g; this._backGroundImageColor.b = color.b; - this.updateBackGroundImageColor(); - if (color.a !== undefined && !color.a_undefined) { - this.setBackGroundImageOpacity(color.a); - } + this._updateBackGroundImageColor(); }, /** - * Get backGround image color + * Sets backGround image Opacity * @param {Number} opacity */ setBackGroundImageOpacity: function (opacity) { @@ -933,7 +794,7 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get backGround image color + * Gets backGround image color * @returns {cc.Color} */ getBackGroundImageColor: function () { @@ -942,15 +803,16 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Get backGround image opacity + * Gets backGround image opacity * @returns {Number} */ getBackGroundImageOpacity: function () { return this._backGroundImageColor.a; }, - updateBackGroundImageColor: function () { - this._backGroundImage.setColor(this._backGroundImageColor); + _updateBackGroundImageColor: function () { + if(this._backGroundImage) + this._backGroundImage.setColor(this._backGroundImageColor); }, /** @@ -962,22 +824,23 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * Sets LayoutType. + * Sets LayoutType to ccui.Layout, LayoutManager will do layout by layout type.. * @param {ccui.Layout.ABSOLUTE|ccui.Layout.LINEAR_VERTICAL|ccui.Layout.LINEAR_HORIZONTAL|ccui.Layout.RELATIVE} type */ setLayoutType: function (type) { this._layoutType = type; - var layoutChildrenArray = this._widgetChildren; + var layoutChildrenArray = this._children; var locChild = null; for (var i = 0; i < layoutChildrenArray.length; i++) { locChild = layoutChildrenArray[i]; - this.supplyTheLayoutParameterLackToChild(locChild); + if(locChild instanceof ccui.Widget) + this._supplyTheLayoutParameterLackToChild(locChild); } this._doLayoutDirty = true; }, /** - * Gets LayoutType. + * Gets LayoutType of ccui.Layout. * @returns {null} */ getLayoutType: function () { @@ -985,489 +848,563 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ }, /** - * request do layout + * request to refresh widget layout, it will do layout at visit calls */ requestDoLayout: function () { this._doLayoutDirty = true; }, - doLayout_LINEAR_VERTICAL: function () { - var layoutChildrenArray = this._widgetChildren; - var layoutSize = this.getSize(); - var topBoundary = layoutSize.height; - for (var i = 0; i < layoutChildrenArray.length; ++i) { - var locChild = layoutChildrenArray[i]; - var locLayoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.LINEAR); - - if (locLayoutParameter) { - var locChildGravity = locLayoutParameter.getGravity(); - var locAP = locChild.getAnchorPoint(); - var locSize = locChild.getSize(); - var locFinalPosX = locAP.x * locSize.width; - var locFinalPosY = topBoundary - ((1 - locAP.y) * locSize.height); - switch (locChildGravity) { - case ccui.LINEAR_GRAVITY_NONE: - case ccui.LINEAR_GRAVITY_LEFT: - break; - case ccui.LINEAR_GRAVITY_RIGHT: - locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width); - break; - case ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL: - locFinalPosX = layoutSize.width / 2 - locSize.width * (0.5 - locAP.x); - break; - default: - break; + _doLayout: function () { + if (!this._doLayoutDirty) + return; + + this.sortAllChildren(); + + var executant = ccui.getLayoutManager(this._layoutType); + if (executant) + executant._doLayout(this); + this._doLayoutDirty = false; + }, + + _getLayoutContentSize: function(){ + return this.getContentSize(); + }, + + _getLayoutElements: function(){ + return this.getChildren(); + }, + + _updateBackGroundImageOpacity: function(){ + if (this._backGroundImage) + this._backGroundImage.setOpacity(this._backGroundImageOpacity); + }, + + _updateBackGroundImageRGBA: function(){ + if (this._backGroundImage) { + this._backGroundImage.setColor(this._backGroundImageColor); + this._backGroundImage.setOpacity(this._backGroundImageOpacity); + } + }, + + /** + * Gets the content size of the layout, it will accumulate all its children's content size + * @returns {cc.Size} + * @private + */ + _getLayoutAccumulatedSize: function(){ + var children = this.getChildren(); + var layoutSize = cc.size(0, 0); + var widgetCount = 0, locSize; + for(var i = 0, len = children.length; i < len; i++) { + var layout = children[i]; + if (null !== layout && layout instanceof ccui.Layout){ + locSize = layout._getLayoutAccumulatedSize(); + layoutSize.width += locSize.width; + layoutSize.height += locSize.height; + } else { + if (layout instanceof ccui.Widget) { + widgetCount++; + var m = layout.getLayoutParameter().getMargin(); + locSize = layout.getContentSize(); + layoutSize.width += locSize.width + (m.right + m.left) * 0.5; + layoutSize.height += locSize.height + (m.top + m.bottom) * 0.5; } - var locMargin = locLayoutParameter.getMargin(); - locFinalPosX += locMargin.left; - locFinalPosY -= locMargin.top; - locChild.setPosition(locFinalPosX, locFinalPosY); - topBoundary = locChild.getBottomInParent() - locMargin.bottom; } } + + //substract extra size + var type = this.getLayoutType(); + if (type === ccui.Layout.LINEAR_HORIZONTAL) + layoutSize.height = layoutSize.height - layoutSize.height/widgetCount * (widgetCount-1); + + if (type === ccui.Layout.LINEAR_VERTICAL) + layoutSize.width = layoutSize.width - layoutSize.width/widgetCount * (widgetCount-1); + return layoutSize; }, - doLayout_LINEAR_HORIZONTAL: function () { - var layoutChildrenArray = this._widgetChildren; - var layoutSize = this.getSize(); - var leftBoundary = 0; - for (var i = 0; i < layoutChildrenArray.length; ++i) { - var locChild = layoutChildrenArray[i]; - var locLayoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.LINEAR); - - if (locLayoutParameter) { - var locChildGravity = locLayoutParameter.getGravity(); - var locAP = locChild.getAnchorPoint(); - var locSize = locChild.getSize(); - var locFinalPosX = leftBoundary + (locAP.x * locSize.width); - var locFinalPosY = layoutSize.height - (1 - locAP.y) * locSize.height; - switch (locChildGravity) { - case ccui.LINEAR_GRAVITY_NONE: - case ccui.LINEAR_GRAVITY_TOP: - break; - case ccui.LINEAR_GRAVITY_BOTTOM: - locFinalPosY = locAP.y * locSize.height; - break; - case ccui.LINEAR_GRAVITY_CENTER_VERTICAL: - locFinalPosY = layoutSize.height / 2 - locSize.height * (0.5 - locAP.y); - break; - default: - break; + + /** + * When the layout get focused, it the layout pass the focus to its child, it will use this method to determine which child
    + * will get the focus. The current algorithm to determine which child will get focus is nearest-distance-priority algorithm + * @param {Number} direction next focused widget direction + * @param {ccui.Widget} baseWidget + * @returns {Number} + * @private + */ + _findNearestChildWidgetIndex: function(direction, baseWidget){ + if (baseWidget == null || baseWidget === this) + return this._findFirstFocusEnabledWidgetIndex(); + + var index = 0, locChildren = this.getChildren(); + var count = locChildren.length, widgetPosition; + + var distance = cc.FLT_MAX, found = 0; + if (direction === ccui.Widget.LEFT || direction === ccui.Widget.RIGHT || direction === ccui.Widget.DOWN || direction === ccui.Widget.UP) { + widgetPosition = this._getWorldCenterPoint(baseWidget); + while (index < count) { + var w = locChildren[index]; + if (w && w instanceof ccui.Widget && w.isFocusEnabled()) { + var length = (w instanceof ccui.Layout)? w._calculateNearestDistance(baseWidget) + : cc.pLength(cc.pSub(this._getWorldCenterPoint(w), widgetPosition)); + if (length < distance){ + found = index; + distance = length; + } } - var locMargin = locLayoutParameter.getMargin(); - locFinalPosX += locMargin.left; - locFinalPosY -= locMargin.top; - locChild.setPosition(locFinalPosX, locFinalPosY); - leftBoundary = locChild.getRightInParent() + locMargin.right; + index++; } + return found; } + cc.log("invalid focus direction!"); + return 0; }, - doLayout_RELATIVE: function () { - var layoutChildrenArray = this._widgetChildren; - var length = layoutChildrenArray.length; - var unlayoutChildCount = length; - var layoutSize = this.getSize(); - for (var i = 0; i < length; i++) { - var locChild = layoutChildrenArray[i]; - var locLayoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.RELATIVE); - locLayoutParameter._put = false; + /** + * When the layout get focused, it the layout pass the focus to its child, it will use this method to determine which child + * will get the focus. The current algorithm to determine which child will get focus is farthest-distance-priority algorithm + * @param {Number} direction next focused widget direction + * @param {ccui.Widget} baseWidget + * @returns {Number} The index of child widget in the container + * @private + */ + _findFarthestChildWidgetIndex: function(direction, baseWidget){ + if (baseWidget == null || baseWidget === this) + return this._findFirstFocusEnabledWidgetIndex(); + + var index = 0, locChildren = this.getChildren(); + var count = locChildren.length; + + var distance = -cc.FLT_MAX, found = 0; + if (direction === ccui.Widget.LEFT || direction === ccui.Widget.RIGHT || direction === ccui.Widget.DOWN || direction === ccui.Widget.UP) { + var widgetPosition = this._getWorldCenterPoint(baseWidget); + while (index < count) { + var w = locChildren[index]; + if (w && w instanceof ccui.Widget && w.isFocusEnabled()) { + var length = (w instanceof ccui.Layout)?w._calculateFarthestDistance(baseWidget) + : cc.pLength(cc.pSub(this._getWorldCenterPoint(w), widgetPosition)); + if (length > distance){ + found = index; + distance = length; + } + } + index++; + } + return found; } + cc.log("invalid focus direction!!!"); + return 0; + }, - while (unlayoutChildCount > 0) { - for (var i = 0; i < length; i++) { - var locChild = layoutChildrenArray[i]; - var locLayoutParameter = locChild.getLayoutParameter(ccui.LayoutParameter.RELATIVE); + /** + * calculate the nearest distance between the baseWidget and the children of the layout + * @param {ccui.Widget} baseWidget the base widget which will be used to calculate the distance between the layout's children and itself + * @returns {Number} return the nearest distance between the baseWidget and the layout's children + * @private + */ + _calculateNearestDistance: function(baseWidget){ + var distance = cc.FLT_MAX; + var widgetPosition = this._getWorldCenterPoint(baseWidget); + var locChildren = this._children; + + for (var i = 0, len = locChildren.length; i < len; i++) { + var widget = locChildren[i], length; + if (widget instanceof ccui.Layout) + length = widget._calculateNearestDistance(baseWidget); + else { + if (widget instanceof ccui.Widget && widget.isFocusEnabled()) + length = cc.pLength(cc.pSub(this._getWorldCenterPoint(widget), widgetPosition)); + else + continue; + } + if (length < distance) + distance = length; + } + return distance; + }, - if (locLayoutParameter) { - if (locLayoutParameter._put) { - continue; + /** + * calculate the farthest distance between the baseWidget and the children of the layout + * @param baseWidget + * @returns {number} + * @private + */ + _calculateFarthestDistance:function(baseWidget){ + var distance = -cc.FLT_MAX; + var widgetPosition = this._getWorldCenterPoint(baseWidget); + var locChildren = this._children; + + for (var i = 0, len = locChildren.length; i < len; i++) { + var layout = locChildren[i]; + var length; + if (layout instanceof ccui.Layout) + length = layout._calculateFarthestDistance(baseWidget); + else { + if (layout instanceof ccui.Widget && layout.isFocusEnabled()) { + var wPosition = this._getWorldCenterPoint(layout); + length = cc.pLength(cc.pSub(wPosition, widgetPosition)); + } else + continue; + } + + if (length > distance) + distance = length; + } + return distance; + }, + + /** + * when a layout pass the focus to it's child, use this method to determine which algorithm to use, nearest or farthest distance algorithm or not + * @param direction + * @param baseWidget + * @private + */ + _findProperSearchingFunctor: function(direction, baseWidget){ + if (baseWidget == null) + return; + + var previousWidgetPosition = this._getWorldCenterPoint(baseWidget); + var widgetPosition = this._getWorldCenterPoint(this._findFirstNonLayoutWidget()); + if (direction === ccui.Widget.LEFT) { + this.onPassFocusToChild = (previousWidgetPosition.x > widgetPosition.x) ? this._findNearestChildWidgetIndex.bind(this) + : this._findFarthestChildWidgetIndex.bind(this); + } else if (direction === ccui.Widget.RIGHT) { + this.onPassFocusToChild = (previousWidgetPosition.x > widgetPosition.x) ? this._findFarthestChildWidgetIndex.bind(this) + : this._findNearestChildWidgetIndex.bind(this); + }else if(direction === ccui.Widget.DOWN) { + this.onPassFocusToChild = (previousWidgetPosition.y > widgetPosition.y) ? this._findNearestChildWidgetIndex.bind(this) + : this._findFarthestChildWidgetIndex.bind(this); + }else if(direction === ccui.Widget.UP) { + this.onPassFocusToChild = (previousWidgetPosition.y < widgetPosition.y) ? this._findNearestChildWidgetIndex.bind(this) + : this._findFarthestChildWidgetIndex.bind(this); + }else + cc.log("invalid direction!"); + }, + + /** + * find the first non-layout widget in this layout + * @returns {ccui.Widget} + * @private + */ + _findFirstNonLayoutWidget:function(){ + var locChildren = this._children; + for(var i = 0, len = locChildren.length; i < len; i++) { + var child = locChildren[i]; + if (child instanceof ccui.Layout){ + var widget = child._findFirstNonLayoutWidget(); + if(widget) + return widget; + } else{ + if (child instanceof ccui.Widget) + return child; + } + } + return null; + }, + + /** + * find the first focus enabled widget index in the layout, it will recursive searching the child widget + * @returns {number} + * @private + */ + _findFirstFocusEnabledWidgetIndex: function(){ + var index = 0, locChildren = this.getChildren(); + var count = locChildren.length; + while (index < count) { + var w = locChildren[index]; + if (w && w instanceof ccui.Widget && w.isFocusEnabled()) + return index; + index++; + } + return 0; + }, + + /** + * find a focus enabled child Widget in the layout by index + * @param index + * @returns {*} + * @private + */ + _findFocusEnabledChildWidgetByIndex: function(index){ + var widget = this._getChildWidgetByIndex(index); + if (widget){ + if (widget.isFocusEnabled()) + return widget; + index = index + 1; + return this._findFocusEnabledChildWidgetByIndex(index); + } + return null; + }, + + /** + * get the center point of a widget in world space + * @param {ccui.Widget} widget + * @returns {cc.Point} + * @private + */ + _getWorldCenterPoint: function(widget){ + //FIXEDME: we don't need to calculate the content size of layout anymore + var widgetSize = widget instanceof ccui.Layout ? widget._getLayoutAccumulatedSize() : widget.getContentSize(); + return widget.convertToWorldSpace(cc.p(widgetSize.width /2, widgetSize.height /2)); + }, + + /** + * this method is called internally by nextFocusedWidget. When the dir is Right/Down, then this method will be called + * @param {Number} direction + * @param {ccui.Widget} current the current focused widget + * @returns {ccui.Widget} the next focused widget + * @private + */ + _getNextFocusedWidget: function(direction, current){ + var nextWidget = null, locChildren = this._children; + var previousWidgetPos = locChildren.indexOf(current); + previousWidgetPos = previousWidgetPos + 1; + if (previousWidgetPos < locChildren.length) { + nextWidget = this._getChildWidgetByIndex(previousWidgetPos); + //handle widget + if (nextWidget) { + if (nextWidget.isFocusEnabled()) { + if (nextWidget instanceof ccui.Layout) { + nextWidget._isFocusPassing = true; + return nextWidget.findNextFocusedWidget(direction, nextWidget); + } else { + this.dispatchFocusEvent(current, nextWidget); + return nextWidget; } - var locAP = locChild.getAnchorPoint(); - var locSize = locChild.getSize(); - var locAlign = locLayoutParameter.getAlign(); - var locRelativeName = locLayoutParameter.getRelativeToWidgetName(); - var locRelativeWidget = null; - var locRelativeWidgetLP = null; - var locFinalPosX = 0; - var locFinalPosY = 0; - if (locRelativeName) { - locRelativeWidget = ccui.helper.seekWidgetByRelativeName(this, locRelativeName); - if (locRelativeWidget) { - locRelativeWidgetLP = locRelativeWidget.getLayoutParameter(ccui.LayoutParameter.RELATIVE); + } else + return this._getNextFocusedWidget(direction, nextWidget); + } else + return current; + } else { + if (this._loopFocus) { + if (this._checkFocusEnabledChild()) { + previousWidgetPos = 0; + nextWidget = this._getChildWidgetByIndex(previousWidgetPos); + if (nextWidget.isFocusEnabled()) { + if (nextWidget instanceof ccui.Layout) { + nextWidget._isFocusPassing = true; + return nextWidget.findNextFocusedWidget(direction, nextWidget); + } else { + this.dispatchFocusEvent(current, nextWidget); + return nextWidget; } - } - switch (locAlign) { - case ccui.RELATIVE_ALIGN_NONE: - case ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT: - locFinalPosX = locAP.x * locSize.width; - locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height); - break; - case ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL: - locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x); - locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height); - break; - case ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT: - locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width); - locFinalPosY = layoutSize.height - ((1 - locAP.y) * locSize.height); - break; - case ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL: - locFinalPosX = locAP.x * locSize.width; - locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y); - break; - case ccui.RELATIVE_ALIGN_PARENT_CENTER: - locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x); - locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y); - break; - case ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL: - locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width); - locFinalPosY = layoutSize.height * 0.5 - locSize.height * (0.5 - locAP.y); - break; - case ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM: - locFinalPosX = locAP.x * locSize.width; - locFinalPosY = locAP.y * locSize.height; - break; - case ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL: - locFinalPosX = layoutSize.width * 0.5 - locSize.width * (0.5 - locAP.x); - locFinalPosY = locAP.y * locSize.height; - break; - case ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM: - locFinalPosX = layoutSize.width - ((1 - locAP.x) * locSize.width); - locFinalPosY = locAP.y * locSize.height; - break; - - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_LEFT: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationBottom = locRelativeWidget.getTopInParent(); - var locationLeft = locRelativeWidget.getLeftInParent(); - locFinalPosY = locationBottom + locAP.y * locSize.height; - locFinalPosX = locationLeft + locAP.x * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_CENTER: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var rbs = locRelativeWidget.getSize(); - var locationBottom = locRelativeWidget.getTopInParent(); - - locFinalPosY = locationBottom + locAP.y * locSize.height; - locFinalPosX = locRelativeWidget.getLeftInParent() + rbs.width * 0.5 + locAP.x * locSize.width - locSize.width * 0.5; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_RIGHT: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationBottom = locRelativeWidget.getTopInParent(); - var locationRight = locRelativeWidget.getRightInParent(); - locFinalPosY = locationBottom + locAP.y * locSize.height; - locFinalPosX = locationRight - (1 - locAP.x) * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_TOP: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationTop = locRelativeWidget.getTopInParent(); - var locationRight = locRelativeWidget.getLeftInParent(); - locFinalPosY = locationTop - (1 - locAP.y) * locSize.height; - locFinalPosX = locationRight - (1 - locAP.x) * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_CENTER: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var rbs = locRelativeWidget.getSize(); - var locationRight = locRelativeWidget.getLeftInParent(); - locFinalPosX = locationRight - (1 - locAP.x) * locSize.width; - - locFinalPosY = locRelativeWidget.getBottomInParent() + rbs.height * 0.5 + locAP.y * locSize.height - locSize.height * 0.5; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_BOTTOM: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationBottom = locRelativeWidget.getBottomInParent(); - var locationRight = locRelativeWidget.getLeftInParent(); - locFinalPosY = locationBottom + locAP.y * locSize.height; - locFinalPosX = locationRight - (1 - locAP.x) * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_TOP: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationTop = locRelativeWidget.getTopInParent(); - var locationLeft = locRelativeWidget.getRightInParent(); - locFinalPosY = locationTop - (1 - locAP.y) * locSize.height; - locFinalPosX = locationLeft + locAP.x * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_CENTER: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var rbs = locRelativeWidget.getSize(); - var locationLeft = locRelativeWidget.getRightInParent(); - locFinalPosX = locationLeft + locAP.x * locSize.width; - - locFinalPosY = locRelativeWidget.getBottomInParent() + rbs.height * 0.5 + locAP.y * locSize.height - locSize.height * 0.5; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_BOTTOM: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationBottom = locRelativeWidget.getBottomInParent(); - var locationLeft = locRelativeWidget.getRightInParent(); - locFinalPosY = locationBottom + locAP.y * locSize.height; - locFinalPosX = locationLeft + locAP.x * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_TOP: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationTop = locRelativeWidget.getBottomInParent(); - var locationLeft = locRelativeWidget.getLeftInParent(); - locFinalPosY = locationTop - (1 - locAP.y) * locSize.height; - locFinalPosX = locationLeft + locAP.x * locSize.width; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_CENTER: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var rbs = locRelativeWidget.getSize(); - var locationTop = locRelativeWidget.getBottomInParent(); - - locFinalPosY = locationTop - (1 - locAP.y) * locSize.height; - locFinalPosX = locRelativeWidget.getLeftInParent() + rbs.width * 0.5 + locAP.x * locSize.width - locSize.width * 0.5; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_BOTTOM: - if (locRelativeWidget) { - if (locRelativeWidgetLP && !locRelativeWidgetLP._put) { - continue; - } - var locationTop = locRelativeWidget.getBottomInParent(); - var locationRight = locRelativeWidget.getRightInParent(); - locFinalPosY = locationTop - (1 - locAP.y) * locSize.height; - locFinalPosX = locationRight - (1 - locAP.x) * locSize.width; - } - break; - default: - break; - } - var locRelativeWidgetMargin,locRelativeWidgetLPAlign; - var locMargin = locLayoutParameter.getMargin(); - if (locRelativeWidgetLP) { - locRelativeWidgetMargin = locRelativeWidgetLP.getMargin(); - locRelativeWidgetLPAlign = locRelativeWidgetLP.getAlign(); - } - //handle margin - switch (locAlign) { - case ccui.RELATIVE_ALIGN_NONE: - case ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT: - locFinalPosX += locMargin.left; - locFinalPosY -= locMargin.top; - break; - case ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL: - locFinalPosY -= locMargin.top; - break; - case ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT: - locFinalPosX -= locMargin.right; - locFinalPosY -= locMargin.top; - break; - case ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL: - locFinalPosX += locMargin.left; - break; - case ccui.RELATIVE_ALIGN_PARENT_CENTER: - break; - case ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL: - locFinalPosX -= locMargin.right; - break; - case ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM: - locFinalPosX += locMargin.left; - locFinalPosY += locMargin.bottom; - break; - case ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL: - locFinalPosY += locMargin.bottom; - break; - case ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM: - locFinalPosX -= locMargin.right; - locFinalPosY += locMargin.bottom; - break; - - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_LEFT: - locFinalPosY += locMargin.bottom; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT) - { - locFinalPosY += locRelativeWidgetMargin.top; - } - locFinalPosY += locMargin.left; - break; - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_CENTER: - locFinalPosY += locMargin.bottom; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT) - { - locFinalPosY += locRelativeWidgetMargin.top; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_ABOVE_RIGHT: - locFinalPosY += locMargin.bottom; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT) - { - locFinalPosY += locRelativeWidgetMargin.top; - } - locFinalPosX -= locMargin.right; - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_TOP: - locFinalPosX -= locMargin.right; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL) - { - locFinalPosX -= locRelativeWidgetMargin.left; - } - locFinalPosY -= locMargin.top; - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_CENTER: - locFinalPosX -= locMargin.right; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL) - { - locFinalPosX -= locRelativeWidgetMargin.left; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_LEFT_BOTTOM: - locFinalPosX -= locMargin.right; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_NONE - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL) - { - locFinalPosX -= locRelativeWidgetMargin.left; - } - locFinalPosY += locMargin.bottom; - break; - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_TOP: - locFinalPosX += locMargin.left; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL) - { - locFinalPosX += locRelativeWidgetMargin.right; - } - locFinalPosY -= locMargin.top; - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_CENTER: - locFinalPosX += locMargin.left; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL) - { - locFinalPosX += locRelativeWidgetMargin.right; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_RIGHT_BOTTOM: - locFinalPosX += locMargin.left; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL) - { - locFinalPosX += locRelativeWidgetMargin.right; - } - locFinalPosY += locMargin.bottom; - break; - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_TOP: - locFinalPosY -= locMargin.top; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL) - { - locFinalPosY -= locRelativeWidgetMargin.bottom; - } - locFinalPosX += locMargin.left; - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_CENTER: - locFinalPosY -= locMargin.top; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL) - { - locFinalPosY -= locRelativeWidgetMargin.bottom; - } - break; - case ccui.RELATIVE_ALIGN_LOCATION_BELOW_BOTTOM: - locFinalPosY -= locMargin.top; - if (locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM - && locRelativeWidgetLPAlign != ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL) - { - locFinalPosY -= locRelativeWidgetMargin.bottom; - } - locFinalPosX -= locMargin.right; - break; - default: - break; - } - locChild.setPosition(locFinalPosX, locFinalPosY); - locLayoutParameter._put = true; - unlayoutChildCount--; + } else + return this._getNextFocusedWidget(direction, nextWidget); + } else + return (current instanceof ccui.Layout) ? current : ccui.Widget._focusedWidget; + } else{ + if (this._isLastWidgetInContainer(current, direction)){ + if (this._isWidgetAncestorSupportLoopFocus(this, direction)) + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + return (current instanceof ccui.Layout) ? current : ccui.Widget._focusedWidget; + } else + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + } + } + }, + + /** + * this method is called internally by nextFocusedWidget. When the dir is Left/Up, then this method will be called + * @param direction + * @param {ccui.Widget} current the current focused widget + * @returns {ccui.Widget} the next focused widget + * @private + */ + _getPreviousFocusedWidget: function(direction, current){ + var nextWidget = null, locChildren = this._children; + var previousWidgetPos = locChildren.indexOf(current); + previousWidgetPos = previousWidgetPos - 1; + if (previousWidgetPos >= 0){ + nextWidget = this._getChildWidgetByIndex(previousWidgetPos); + if (nextWidget.isFocusEnabled()) { + if (nextWidget instanceof ccui.Layout){ + nextWidget._isFocusPassing = true; + return nextWidget.findNextFocusedWidget(direction, nextWidget); } + this.dispatchFocusEvent(current, nextWidget); + return nextWidget; + } else + return this._getPreviousFocusedWidget(direction, nextWidget); //handling the disabled widget, there is no actual focus lose or get, so we don't need any envet + }else { + if (this._loopFocus){ + if (this._checkFocusEnabledChild()) { + previousWidgetPos = locChildren.length -1; + nextWidget = this._getChildWidgetByIndex(previousWidgetPos); + if (nextWidget.isFocusEnabled()){ + if (nextWidget instanceof ccui.Layout){ + nextWidget._isFocusPassing = true; + return nextWidget.findNextFocusedWidget(direction, nextWidget); + } else { + this.dispatchFocusEvent(current, nextWidget); + return nextWidget; + } + } else + return this._getPreviousFocusedWidget(direction, nextWidget); + } else + return (current instanceof ccui.Layout) ? current : ccui.Widget._focusedWidget; + } else { + if (this._isLastWidgetInContainer(current, direction)) { + if (this._isWidgetAncestorSupportLoopFocus(this, direction)) + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); + return (current instanceof ccui.Layout) ? current : ccui.Widget._focusedWidget; + } else + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, this); } } }, - _doLayout: function () { - if(!this._doLayoutDirty){ - return; + + /** + * find the nth element in the _children array. Only the Widget descendant object will be returned + * @param {Number} index + * @returns {ccui.Widget} + * @private + */ + _getChildWidgetByIndex: function (index) { + var locChildren = this._children; + var size = locChildren.length, count = 0, oldIndex = index; + while (index < size) { + var firstChild = locChildren[index]; + if (firstChild && firstChild instanceof ccui.Widget) + return firstChild; + count++; + index++; } - switch (this._layoutType) { - case ccui.Layout.ABSOLUTE: - break; - case ccui.Layout.LINEAR_VERTICAL: - this.doLayout_LINEAR_VERTICAL(); - break; - case ccui.Layout.LINEAR_HORIZONTAL: - this.doLayout_LINEAR_HORIZONTAL(); - break; - case ccui.Layout.RELATIVE: - this.doLayout_RELATIVE(); - break; - default: - break; + + var begin = 0; + while (begin < oldIndex) { + var child = locChildren[begin]; + if (child && child instanceof ccui.Widget) + return child; + count++; + begin++; } - this._doLayoutDirty = false; + return null; + }, + + /** + * whether it is the last element according to all their parents + * @param {ccui.Widget} widget + * @param {Number} direction + * @returns {Boolean} + * @private + */ + _isLastWidgetInContainer:function(widget, direction){ + var parent = widget.getParent(); + if (parent == null || !(parent instanceof ccui.Layout)) + return true; + + var container = parent.getChildren(); + var index = container.indexOf(widget); + if (parent.getLayoutType() === ccui.Layout.LINEAR_HORIZONTAL) { + if (direction === ccui.Widget.LEFT) { + if (index === 0) + return this._isLastWidgetInContainer(parent, direction); + else + return false; + } + if (direction === ccui.Widget.RIGHT) { + if (index === container.length - 1) + return this._isLastWidgetInContainer(parent, direction); + else + return false; + } + if (direction === ccui.Widget.DOWN) + return this._isLastWidgetInContainer(parent, direction); + + if (direction === ccui.Widget.UP) + return this._isLastWidgetInContainer(parent, direction); + } else if(parent.getLayoutType() === ccui.Layout.LINEAR_VERTICAL){ + if (direction === ccui.Widget.UP){ + if (index === 0) + return this._isLastWidgetInContainer(parent, direction); + else + return false; + } + if (direction === ccui.Widget.DOWN) { + if (index === container.length - 1) + return this._isLastWidgetInContainer(parent, direction); + else + return false; + } + if (direction === ccui.Widget.LEFT) + return this._isLastWidgetInContainer(parent, direction); + + if (direction === ccui.Widget.RIGHT) + return this._isLastWidgetInContainer(parent, direction); + } else { + cc.log("invalid layout Type"); + return false; + } + }, + + /** + * Lookup any parent widget with a layout type as the direction, if the layout is loop focused, then return true, otherwise it returns false. + * @param {ccui.Widget} widget + * @param {Number} direction + * @returns {Boolean} + * @private + */ + _isWidgetAncestorSupportLoopFocus: function(widget, direction){ + var parent = widget.getParent(); + if (parent == null || !(parent instanceof ccui.Layout)) + return false; + if (parent.isLoopFocus()) { + var layoutType = parent.getLayoutType(); + if (layoutType === ccui.Layout.LINEAR_HORIZONTAL) { + if (direction === ccui.Widget.LEFT || direction === ccui.Widget.RIGHT) + return true; + else + return this._isWidgetAncestorSupportLoopFocus(parent, direction); + } + if (layoutType === ccui.Layout.LINEAR_VERTICAL){ + if (direction === ccui.Widget.DOWN || direction === ccui.Widget.UP) + return true; + else + return this._isWidgetAncestorSupportLoopFocus(parent, direction); + } else{ + cc.assert(0, "invalid layout type"); + return false; + } + } else + return this._isWidgetAncestorSupportLoopFocus(parent, direction); + }, + + /** + * pass the focus to the layout's next focus enabled child + * @param {Number} direction + * @param {ccui.Widget} current + * @returns {ccui.Widget} + * @private + */ + _passFocusToChild: function(direction, current){ + if (this._checkFocusEnabledChild()) { + var previousWidget = ccui.Widget.getCurrentFocusedWidget(); + this._findProperSearchingFunctor(direction, previousWidget); + var index = this.onPassFocusToChild(direction, previousWidget); + + var widget = this._getChildWidgetByIndex(index); + if (widget instanceof ccui.Layout) { + widget._isFocusPassing = true; + return widget.findNextFocusedWidget(direction, widget); + } else { + this.dispatchFocusEvent(current, widget); + return widget; + } + }else + return this; + }, + + /** + * If there are no focus enabled child in the layout, it will return false, otherwise it returns true + * @returns {boolean} + * @private + */ + _checkFocusEnabledChild: function(){ + var locChildren = this._children; + for(var i = 0, len = locChildren.length; i < len; i++){ + var widget = locChildren[i]; + if (widget && widget instanceof ccui.Widget && widget.isFocusEnabled()) + return true; + } + return false; }, /** @@ -1478,15 +1415,17 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ return "Layout"; }, - createCloneInstance: function () { - return ccui.Layout.create(); + _createCloneInstance: function () { + return new ccui.Layout(); }, - copyClonedWidgetChildren: function (model) { - ccui.Widget.prototype.copyClonedWidgetChildren.call(this, model); + _copyClonedWidgetChildren: function (model) { + ccui.Widget.prototype._copyClonedWidgetChildren.call(this, model); }, - copySpecialProperties: function (layout) { + _copySpecialProperties: function (layout) { + if(!(layout instanceof ccui.Layout)) + return; this.setBackGroundImageScale9Enabled(layout._backGroundScale9Enabled); this.setBackGroundImage(layout._backGroundImageFileName, layout._bgImageTexType); this.setBackGroundImageCapInsets(layout._backGroundImageCapInsets); @@ -1498,28 +1437,28 @@ ccui.Layout = ccui.Widget.extend(/** @lends ccui.Layout# */{ this.setLayoutType(layout._layoutType); this.setClippingEnabled(layout._clippingEnabled); this.setClippingType(layout._clippingType); + this._loopFocus = layout._loopFocus; + this.__passFocusToChild = layout.__passFocusToChild; + this._isInterceptTouch = layout._isInterceptTouch; + }, + + /** + * force refresh widget layout + */ + forceDoLayout: function(){ + this.requestDoLayout(); + this._doLayout(); + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + return new ccui.Layout.WebGLRenderCmd(this); + else + return new ccui.Layout.CanvasRenderCmd(this); } }); -ccui.Layout._init_once = null; -ccui.Layout._visit_once = null; -ccui.Layout._layer = null; -ccui.Layout._sharedCache = null; - -if(cc._renderType == cc._RENDER_TYPE_WEBGL){ - //WebGL - ccui.Layout.prototype.initStencil = ccui.Layout.prototype._initStencilForWebGL; - ccui.Layout.prototype.stencilClippingVisit = ccui.Layout.prototype._stencilClippingVisitForWebGL; - ccui.Layout.prototype.scissorClippingVisit = ccui.Layout.prototype._scissorClippingVisitForWebGL; -}else{ - ccui.Layout.prototype.initStencil = ccui.Layout.prototype._initStencilForCanvas; - ccui.Layout.prototype.stencilClippingVisit = ccui.Layout.prototype._stencilClippingVisitForCanvas; - ccui.Layout.prototype.scissorClippingVisit = ccui.Layout.prototype._stencilClippingVisitForCanvas; -} -ccui.Layout._getSharedCache = function () { - return (cc.ClippingNode._sharedCache) || (cc.ClippingNode._sharedCache = cc.newElement("canvas")); -}; -window._p = ccui.Layout.prototype; +var _p = ccui.Layout.prototype; // Extended properties /** @expose */ @@ -1532,40 +1471,88 @@ cc.defineGetterSetter(_p, "clippingType", null, _p.setClippingType); _p.layoutType; cc.defineGetterSetter(_p, "layoutType", _p.getLayoutType, _p.setLayoutType); -delete window._p; +_p = null; /** * allocates and initializes a UILayout. - * @constructs + * @deprecated since v3.0, please use new ccui.Layout() instead. * @return {ccui.Layout} - * @example - * // example - * var uiLayout = ccui.Layout.create(); */ ccui.Layout.create = function () { - var layout = new ccui.Layout(); - if (layout && layout.init()) { - return layout; - } - return null; + return new ccui.Layout(); }; // Constants //layoutBackGround color type +/** + * The None of ccui.Layout's background color type + * @constant + * @type {number} + */ ccui.Layout.BG_COLOR_NONE = 0; +/** + * The solid of ccui.Layout's background color type, it will use a LayerColor to draw the background. + * @constant + * @type {number} + */ ccui.Layout.BG_COLOR_SOLID = 1; +/** + * The gradient of ccui.Layout's background color type, it will use a LayerGradient to draw the background. + * @constant + * @type {number} + */ ccui.Layout.BG_COLOR_GRADIENT = 2; //Layout type +/** + * The absolute of ccui.Layout's layout type. + * @type {number} + * @constant + */ ccui.Layout.ABSOLUTE = 0; +/** + * The vertical of ccui.Layout's layout type. + * @type {number} + * @constant + */ ccui.Layout.LINEAR_VERTICAL = 1; +/** + * The horizontal of ccui.Layout's layout type. + * @type {number} + * @constant + */ ccui.Layout.LINEAR_HORIZONTAL = 2; +/** + * The relative of ccui.Layout's layout type. + * @type {number} + * @constant + */ ccui.Layout.RELATIVE = 3; //Layout clipping type +/** + * The stencil of ccui.Layout's clipping type. + * @type {number} + * @constant + */ ccui.Layout.CLIPPING_STENCIL = 0; +/** + * The scissor of ccui.Layout's clipping type. + * @type {number} + * @constant + */ ccui.Layout.CLIPPING_SCISSOR = 1; +/** + * The zOrder value of ccui.Layout's image background. + * @type {number} + * @constant + */ ccui.Layout.BACKGROUND_IMAGE_ZORDER = -2; +/** + * The zOrder value of ccui.Layout's color background. + * @type {number} + * @constant + */ ccui.Layout.BACKGROUND_RENDERER_ZORDER = -2; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutCanvasRenderCmd.js b/extensions/ccui/layouts/UILayoutCanvasRenderCmd.js new file mode 100644 index 0000000000..d3861d2573 --- /dev/null +++ b/extensions/ccui/layouts/UILayoutCanvasRenderCmd.js @@ -0,0 +1,179 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + ccui.Layout.CanvasRenderCmd = function(renderable){ + ccui.ProtectedNode.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + + this._clipElemType = false; + this._locCache = null; + this._rendererSaveCmd = new cc.CustomRenderCmd(this, this._onRenderSaveCmd); + this._rendererSaveCmdSprite = new cc.CustomRenderCmd(this, this._onRenderSaveSpriteCmd); + this._rendererClipCmd = new cc.CustomRenderCmd(this, this._onRenderClipCmd); + this._rendererRestoreCmd = new cc.CustomRenderCmd(this, this._onRenderRestoreCmd); + }; + + var proto = ccui.Layout.CanvasRenderCmd.prototype = Object.create(ccui.ProtectedNode.CanvasRenderCmd.prototype); + proto.constructor = ccui.Layout.CanvasRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + if (!node._visible) + return; + node._adaptRenderers(); + node._doLayout(); + + if (node._clippingEnabled) { + switch (node._clippingType) { + case ccui.Layout.CLIPPING_STENCIL: + this.stencilClippingVisit(parentCmd); + break; + case ccui.Layout.CLIPPING_SCISSOR: + this.scissorClippingVisit(parentCmd); + break; + default: + break; + } + } else + ccui.Widget.CanvasRenderCmd.prototype.visit.call(this, parentCmd); + }; + + proto._onRenderSaveCmd = function(ctx, scaleX, scaleY){ + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + if (this._clipElemType) { + var canvas = context.canvas; + this._locCache = ccui.Layout.CanvasRenderCmd._getSharedCache(); + this._locCache.width = canvas.width; + this._locCache.height = canvas.height; + var locCacheCtx = this._locCache.getContext("2d"); + locCacheCtx.drawImage(canvas, 0, 0); + } else { + wrapper.save(); + wrapper.save(); + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + } + }; + + proto._onRenderSaveSpriteCmd = function(ctx){ + var wrapper = ctx || cc._renderContext; + //var node = this._node; + if (this._clipElemType) { + wrapper.setCompositeOperation("destination-in"); + } + }; + + proto._onRenderClipCmd = function(ctx){ + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + if (!this._clipElemType) { + wrapper.restore(); + context.clip(); + } + }; + + proto._onRenderRestoreCmd = function(ctx){ + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + + if (this._clipElemType) { + // Redraw the cached canvas, so that the cliped area shows the background etc. + context.save(); + context.setTransform(1, 0, 0, 1, 0, 0); + context.globalCompositeOperation = "destination-over"; + context.drawImage(this._locCache, 0, 0); + context.restore(); + }else{ + wrapper.restore(); //use for restore clip operation + } + }; + + proto.rebindStencilRendering = function(stencil){ + stencil._renderCmd.rendering = this.__stencilDraw; + }; + + proto.__stencilDraw = function(ctx,scaleX, scaleY){ //Only for Canvas + var wrapper = ctx || cc._renderContext, locContext = wrapper.getContext(), buffer = this._buffer; + + for (var i = 0, bufLen = buffer.length; i < bufLen; i++) { + var element = buffer[i], vertices = element.verts; + var firstPoint = vertices[0]; + locContext.beginPath(); + locContext.moveTo(firstPoint.x * scaleX, -firstPoint.y * scaleY); + for (var j = 1, len = vertices.length; j < len; j++) + locContext.lineTo(vertices[j].x * scaleX, -vertices[j].y * scaleY); + locContext.closePath(); + } + }; + + proto.stencilClippingVisit = proto.scissorClippingVisit = function(parentCmd){ + var node = this._node; + if (!node._clippingStencil || !node._clippingStencil.isVisible()) + return; + + this._clipElemType = node._stencil instanceof cc.Sprite; + this._syncStatus(parentCmd); + this._dirtyFlag = 0; + + cc.renderer.pushRenderCommand(this._rendererSaveCmd); + if (this._clipElemType) { + cc.ProtectedNode.prototype.visit.call(node, parentCmd); + cc.renderer.pushRenderCommand(this._rendererSaveCmdSprite); + } + node._clippingStencil.visit(this); + + cc.renderer.pushRenderCommand(this._rendererClipCmd); + if (!this._clipElemType) { + node.sortAllChildren(); + node.sortAllProtectedChildren(); + + var children = node._children; + var j=0, locProtectChildren = node._protectedChildren, i = 0, locChild; + var iLen = children.length, jLen = locProtectChildren.length; + + for( ; i < iLen; i++ ){ + locChild = children[i]; + if ( locChild && locChild.getLocalZOrder() < 0 ) + locChild.visit(this); + else + break; + } + for( ; j < jLen; j++ ) { + locChild = locProtectChildren[j]; + if ( locChild && locChild.getLocalZOrder() < 0 ) + locChild.visit(this); + else + break; + } + for (; i < iLen; i++) + children[i].visit(this); + for (; j < jLen; j++) + locProtectChildren[j].visit(this); + cc.renderer.pushRenderCommand(this._rendererRestoreCmd); + } + }; + + ccui.Layout.CanvasRenderCmd._getSharedCache = function () { + return (cc.ClippingNode._sharedCache) || (cc.ClippingNode._sharedCache = cc.newElement("canvas")); + }; +})(); \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutComponent.js b/extensions/ccui/layouts/UILayoutComponent.js new file mode 100644 index 0000000000..96a9dbf3fa --- /dev/null +++ b/extensions/ccui/layouts/UILayoutComponent.js @@ -0,0 +1,585 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +ccui.LayoutComponent_ReferencePoint = { + BOTTOM_LEFT: 0, + TOP_LEFT: 1, + BOTTOM_RIGHT: 2, + TOP_RIGHT: 3 +}; +ccui.LayoutComponent_PositionType = { + Position: 0, + RelativePosition: 1, + PreRelativePosition: 2, + PreRelativePositionEnable: 3 +}; +ccui.LayoutComponent_SizeType = { + Size: 0, + PreSize: 1, + PreSizeEnable: 2 +}; + +//refactor since v3.3 +ccui.LayoutComponent = cc.Component.extend({ + _horizontalEdge: 0, + _verticalEdge: 0, + + _leftMargin: 0, + _rightMargin: 0, + _bottomMargin: 0, + _topMargin: 0, + + _usingPositionPercentX: false, + _positionPercentX: 0, + _usingPositionPercentY: false, + _positionPercentY: 0, + + _usingStretchWidth: false, + _usingStretchHeight: false, + + _percentWidth: 0, + _usingPercentWidth: false, + + _percentHeight: 0, + _usingPercentHeight: false, + + _actived: true, + _isPercentOnly: false, + + ctor: function () { + this._name = ccui.LayoutComponent.NAME; + }, + + init: function () { + var ret = true; + + if (!cc.Component.prototype.init.call(this)) { + return false; + } + + //put layout component initalized code here + + return ret; + }, + + getPercentContentSize: function () { + return cc.p(this._percentWidth, this._percentHeight); + }, + setPercentContentSize: function (percent) { + this.setPercentWidth(percent.x); + this.setPercentHeight(percent.y); + }, + + setUsingPercentContentSize: function (isUsed) { + this._usingPercentWidth = this._usingPercentHeight = isUsed; + }, + + //old + SetActiveEnable: function (enable) { + this._actived = enable; + }, + + //v3.3 + getUsingPercentContentSize: function () { + return this._usingPercentWidth && this._usingPercentHeight; + }, + + //position & margin + getAnchorPosition: function () { + return this._owner.getAnchorPoint(); + }, + + setAnchorPosition: function (point, y) { + var oldRect = this._owner.getBoundingBox(); + this._owner.setAnchorPoint(point, y); + var newRect = this._owner.getBoundingBox(); + var offSetX = oldRect.x - newRect.x, offSetY = oldRect.y - newRect.y; + + var ownerPosition = this._owner.getPosition(); + ownerPosition.x += offSetX; + ownerPosition.y += offSetY; + this.setPosition(ownerPosition); + }, + + getPosition: function () { + return this._owner.getPosition(); + }, + + setPosition: function (position, y) { + var parent = this._getOwnerParent(), x; + if (parent != null) { + if (y === undefined) { + x = position.x; + y = position.y; + } else + x = position; + var parentSize = parent.getContentSize(); + + if (parentSize.width !== 0) + this._positionPercentX = x / parentSize.width; + else { + this._positionPercentX = 0; + if (this._usingPositionPercentX) + x = 0; + } + + if (parentSize.height !== 0) + this._positionPercentY = y / parentSize.height; + else { + this._positionPercentY = 0; + if (this._usingPositionPercentY) + y = 0; + } + + this._owner.setPosition(x, y); + this._refreshHorizontalMargin(); + this._refreshVerticalMargin(); + } else + this._owner.setPosition(position, y); + }, + + isPositionPercentXEnabled: function () { + return this._usingPositionPercentX; + }, + setPositionPercentXEnabled: function (isUsed) { + this._usingPositionPercentX = isUsed; + if (this._usingPositionPercentX) + this._horizontalEdge = ccui.LayoutComponent.horizontalEdge.NONE; + }, + + getPositionPercentX: function () { + return this._positionPercentX; + }, + setPositionPercentX: function (percentMargin) { + this._positionPercentX = percentMargin; + + var parent = this._getOwnerParent(); + if (parent !== null) { + this._owner.setPositionX(parent.width * this._positionPercentX); + this._refreshHorizontalMargin(); + } + }, + + isPositionPercentYEnabled: function () { + return this._usingPositionPercentY; + }, + setPositionPercentYEnabled: function (isUsed) { + this._usingPositionPercentY = isUsed; + if (this._usingPositionPercentY) + this._verticalEdge = ccui.LayoutComponent.verticalEdge.NONE; + }, + + getPositionPercentY: function () { + return this._positionPercentY; + }, + setPositionPercentY: function (percentMargin) { + this._positionPercentY = percentMargin; + + var parent = this._getOwnerParent(); + if (parent !== null) { + this._owner.setPositionY(parent.height * this._positionPercentY); + this._refreshVerticalMargin(); + } + }, + + getHorizontalEdge: function () { + return this._horizontalEdge; + }, + setHorizontalEdge: function (hEdge) { + this._horizontalEdge = hEdge; + if (this._horizontalEdge !== ccui.LayoutComponent.horizontalEdge.NONE) + this._usingPositionPercentX = false; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var ownerPoint = this._owner.getPosition(); + var parentSize = parent.getContentSize(); + if (parentSize.width !== 0) + this._positionPercentX = ownerPoint.x / parentSize.width; + else { + this._positionPercentX = 0; + ownerPoint.x = 0; + if (this._usingPositionPercentX) + this._owner.setPosition(ownerPoint); + } + this._refreshHorizontalMargin(); + } + }, + + getVerticalEdge: function () { + return this._verticalEdge; + }, + setVerticalEdge: function (vEdge) { + this._verticalEdge = vEdge; + if (this._verticalEdge !== ccui.LayoutComponent.verticalEdge.NONE) + this._usingPositionPercentY = false; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var ownerPoint = this._owner.getPosition(); + var parentSize = parent.getContentSize(); + if (parentSize.height !== 0) + this._positionPercentY = ownerPoint.y / parentSize.height; + else { + this._positionPercentY = 0; + ownerPoint.y = 0; + if (this._usingPositionPercentY) + this._owner.setPosition(ownerPoint); + } + this._refreshVerticalMargin(); + } + }, + + getLeftMargin: function () { + return this._leftMargin; + }, + setLeftMargin: function (margin) { + this._leftMargin = margin; + }, + + getRightMargin: function () { + return this._rightMargin; + }, + setRightMargin: function (margin) { + this._rightMargin = margin; + }, + + getTopMargin: function () { + return this._topMargin; + }, + setTopMargin: function (margin) { + this._topMargin = margin; + }, + + getBottomMargin: function () { + return this._bottomMargin; + }, + setBottomMargin: function (margin) { + this._bottomMargin = margin; + }, + + //size & + getSize: function () { + return this.getOwner().getContentSize(); + }, + setSize: function (size) { + var parent = this._getOwnerParent(); + if (parent !== null) { + var ownerSize = size, parentSize = parent.getContentSize(); + + if (parentSize.width !== 0) + this._percentWidth = ownerSize.width / parentSize.width; + else { + this._percentWidth = 0; + if (this._usingPercentWidth) + ownerSize.width = 0; + } + + if (parentSize.height !== 0) + this._percentHeight = ownerSize.height / parentSize.height; + else { + this._percentHeight = 0; + if (this._usingPercentHeight) + ownerSize.height = 0; + } + + this._owner.setContentSize(ownerSize); + + this._refreshHorizontalMargin(); + this._refreshVerticalMargin(); + } + else + this._owner.setContentSize(size); + }, + + isPercentWidthEnabled: function () { + return this._usingPercentWidth; + }, + setPercentWidthEnabled: function (isUsed) { + this._usingPercentWidth = isUsed; + if (this._usingPercentWidth) + this._usingStretchWidth = false; + }, + + getSizeWidth: function () { + return this._owner.width; + }, + setSizeWidth: function (width) { + var ownerSize = this._owner.getContentSize(); + ownerSize.width = width; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var parentSize = parent.getContentSize(); + if (parentSize.width !== 0) + this._percentWidth = ownerSize.width / parentSize.width; + else { + this._percentWidth = 0; + if (this._usingPercentWidth) + ownerSize.width = 0; + } + this._owner.setContentSize(ownerSize); + this._refreshHorizontalMargin(); + } else + this._owner.setContentSize(ownerSize); + }, + + getPercentWidth: function () { + return this._percentWidth; + }, + setPercentWidth: function (percentWidth) { + this._percentWidth = percentWidth; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var ownerSize = this._owner.getContentSize(); + ownerSize.width = parent.width * this._percentWidth; + this._owner.setContentSize(ownerSize); + this._refreshHorizontalMargin(); + } + }, + + isPercentHeightEnabled: function () { + return this._usingPercentHeight; + }, + setPercentHeightEnabled: function (isUsed) { + this._usingPercentHeight = isUsed; + if (this._usingPercentHeight) + this._usingStretchHeight = false; + }, + + getSizeHeight: function () { + return this._owner.height; + }, + setSizeHeight: function (height) { + var ownerSize = this._owner.getContentSize(); + ownerSize.height = height; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var parentSize = parent.getContentSize(); + if (parentSize.height !== 0) + this._percentHeight = ownerSize.height / parentSize.height; + else { + this._percentHeight = 0; + if (this._usingPercentHeight) + ownerSize.height = 0; + } + this._owner.setContentSize(ownerSize); + this._refreshVerticalMargin(); + } + else + this._owner.setContentSize(ownerSize); + }, + + getPercentHeight: function () { + return this._percentHeight; + }, + setPercentHeight: function (percentHeight) { + this._percentHeight = percentHeight; + + var parent = this._getOwnerParent(); + if (parent !== null) { + var ownerSize = this._owner.getContentSize(); + ownerSize.height = parent.height * this._percentHeight; + this._owner.setContentSize(ownerSize); + this._refreshVerticalMargin(); + } + }, + + isStretchWidthEnabled: function () { + return this._usingStretchWidth; + }, + setStretchWidthEnabled: function (isUsed) { + this._usingStretchWidth = isUsed; + if (this._usingStretchWidth) + this._usingPercentWidth = false; + }, + + isStretchHeightEnabled: function () { + return this._usingStretchHeight; + }, + setStretchHeightEnabled: function (isUsed) { + this._usingStretchHeight = isUsed; + if (this._usingStretchHeight) + this._usingPercentHeight = false; + }, + + setPercentOnlyEnabled: function(enable){ + this._isPercentOnly = enable; + }, + + setActiveEnabled: function (enable) { + this._actived = enable; + }, + refreshLayout: function () { + if(!this._actived) + return; + + var parent = this._getOwnerParent(); + if (parent === null) + return; + + var parentSize = parent.getContentSize(), locOwner = this._owner; + var ownerAnchor = locOwner.getAnchorPoint(), ownerSize = locOwner.getContentSize(); + var ownerPosition = locOwner.getPosition(); + + switch (this._horizontalEdge) { + case ccui.LayoutComponent.horizontalEdge.NONE: + if (this._usingStretchWidth && !this._isPercentOnly) { + ownerSize.width = parentSize.width * this._percentWidth; + ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width; + } else { + if (this._usingPositionPercentX) + ownerPosition.x = parentSize.width * this._positionPercentX; + if (this._usingPercentWidth) + ownerSize.width = parentSize.width * this._percentWidth; + } + break; + case ccui.LayoutComponent.horizontalEdge.LEFT: + if(this._isPercentOnly) + break; + if (this._usingPercentWidth || this._usingStretchWidth) + ownerSize.width = parentSize.width * this._percentWidth; + ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width; + break; + case ccui.LayoutComponent.horizontalEdge.RIGHT: + if(this._isPercentOnly) + break; + if (this._usingPercentWidth || this._usingStretchWidth) + ownerSize.width = parentSize.width * this._percentWidth; + ownerPosition.x = parentSize.width - (this._rightMargin + (1 - ownerAnchor.x) * ownerSize.width); + break; + case ccui.LayoutComponent.horizontalEdge.CENTER: + if(this._isPercentOnly) + break; + if (this._usingStretchWidth) { + ownerSize.width = parentSize.width - this._leftMargin - this._rightMargin; + if (ownerSize.width < 0) + ownerSize.width = 0; + ownerPosition.x = this._leftMargin + ownerAnchor.x * ownerSize.width; + } else { + if (this._usingPercentWidth) + ownerSize.width = parentSize.width * this._percentWidth; + ownerPosition.x = parentSize.width * this._positionPercentX; + } + break; + default: + break; + } + + switch (this._verticalEdge) { + case ccui.LayoutComponent.verticalEdge.NONE: + if (this._usingStretchHeight && !this._isPercentOnly) { + ownerSize.height = parentSize.height * this._percentHeight; + ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height; + } else { + if (this._usingPositionPercentY) + ownerPosition.y = parentSize.height * this._positionPercentY; + if (this._usingPercentHeight) + ownerSize.height = parentSize.height * this._percentHeight; + } + break; + case ccui.LayoutComponent.verticalEdge.BOTTOM: + if(this._isPercentOnly) + break; + if (this._usingPercentHeight || this._usingStretchHeight) + ownerSize.height = parentSize.height * this._percentHeight; + ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height; + break; + case ccui.LayoutComponent.verticalEdge.TOP: + if(this._isPercentOnly) + break; + if (this._usingPercentHeight || this._usingStretchHeight) + ownerSize.height = parentSize.height * this._percentHeight; + ownerPosition.y = parentSize.height - (this._topMargin + (1 - ownerAnchor.y) * ownerSize.height); + break; + case ccui.LayoutComponent.verticalEdge.CENTER: + if(this._isPercentOnly) + break; + if (this._usingStretchHeight) { + ownerSize.height = parentSize.height - this._topMargin - this._bottomMargin; + if (ownerSize.height < 0) + ownerSize.height = 0; + ownerPosition.y = this._bottomMargin + ownerAnchor.y * ownerSize.height; + } else { + if(this._usingPercentHeight) + ownerSize.height = parentSize.height * this._percentHeight; + ownerPosition.y = parentSize.height * this._positionPercentY; + } + break; + default: + break; + } + + locOwner.setPosition(ownerPosition); + locOwner.setContentSize(ownerSize); + + ccui.helper.doLayout(locOwner); + }, + + _getOwnerParent: function () { + return this._owner ? this._owner.getParent() : null; + }, + _refreshHorizontalMargin: function () { + var parent = this._getOwnerParent(); + if (parent === null) + return; + + var ownerPoint = this._owner.getPosition(), ownerAnchor = this._owner.getAnchorPoint(); + var ownerSize = this._owner.getContentSize(), parentSize = parent.getContentSize(); + + this._leftMargin = ownerPoint.x - ownerAnchor.x * ownerSize.width; + this._rightMargin = parentSize.width - (ownerPoint.x + (1 - ownerAnchor.x) * ownerSize.width); + }, + _refreshVerticalMargin: function () { + var parent = this._getOwnerParent(); + if (parent === null) + return; + + var ownerPoint = this._owner.getPosition(), ownerAnchor = this._owner.getAnchorPoint(); + var ownerSize = this._owner.getContentSize(), parentSize = parent.getContentSize(); + + this._bottomMargin = ownerPoint.y - ownerAnchor.y * ownerSize.height; + this._topMargin = parentSize.height - (ownerPoint.y + (1 - ownerAnchor.y) * ownerSize.height); + } +}); + +ccui.LayoutComponent.horizontalEdge = {NONE: 0, LEFT: 1, RIGHT: 2, CENTER: 3}; +ccui.LayoutComponent.verticalEdge = {NONE: 0, BOTTOM: 1, TOP: 2, CENTER: 3}; + +ccui.LayoutComponent.NAME = "__ui_layout"; +ccui.LayoutComponent.bindLayoutComponent = function (node) { + var layout = node.getComponent(ccui.LayoutComponent.NAME); + if (layout !== undefined) + return layout; + + layout = new ccui.LayoutComponent(); + if (layout && layout.init()) { + node.addComponent(layout); + return layout; + } + return null; +}; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutDefine.js b/extensions/ccui/layouts/UILayoutDefine.js deleted file mode 100644 index ab8ba0afb1..0000000000 --- a/extensions/ccui/layouts/UILayoutDefine.js +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -//LinearGravity -/** - * @ignore - */ -ccui.LINEAR_GRAVITY_NONE = 0; -ccui.LINEAR_GRAVITY_LEFT = 1; -ccui.LINEAR_GRAVITY_TOP = 2; -ccui.LINEAR_GRAVITY_RIGHT = 3; -ccui.LINEAR_GRAVITY_BOTTOM = 4; -ccui.LINEAR_GRAVITY_CENTER_VERTICAL = 5; -ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL = 6; - -//RelativeAlign -ccui.RELATIVE_ALIGN_NONE = 0; -ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT = 1; -ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL = 2; -ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT = 3; -ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL = 4; -ccui.RELATIVE_ALIGN_PARENT_CENTER = 5; -ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL = 6; -ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM = 7; -ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL = 8; -ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM = 9; - -ccui.RELATIVE_ALIGN_LOCATION_ABOVE_LEFT = 10; -ccui.RELATIVE_ALIGN_LOCATION_ABOVE_CENTER = 11; -ccui.RELATIVE_ALIGN_LOCATION_ABOVE_RIGHT = 12; - -ccui.RELATIVE_ALIGN_LOCATION_LEFT_TOP = 13; -ccui.RELATIVE_ALIGN_LOCATION_LEFT_CENTER = 14; -ccui.RELATIVE_ALIGN_LOCATION_LEFT_BOTTOM = 15; - -ccui.RELATIVE_ALIGN_LOCATION_RIGHT_TOP = 16; -ccui.RELATIVE_ALIGN_LOCATION_RIGHT_CENTER = 17; -ccui.RELATIVE_ALIGN_LOCATION_RIGHT_BOTTOM = 18; - -ccui.RELATIVE_ALIGN_LOCATION_BELOW_TOP = 19; -ccui.RELATIVE_ALIGN_LOCATION_BELOW_CENTER = 20; -ccui.RELATIVE_ALIGN_LOCATION_BELOW_BOTTOM = 21; - -/** - * Base class for ccui.Margin - * @class - * @extends ccui.Class - */ -ccui.Margin = ccui.Class.extend(/** @lends ccui.Margin# */{ - left: 0, - top: 0, - right: 0, - bottom: 0, - ctor: function (margin, top, right, bottom) { - if (margin && top === undefined) { - this.left = margin.left; - this.top = margin.top; - this.right = margin.right; - this.bottom = margin.bottom; - } - if (bottom !== undefined) { - this.left = margin; - this.top = top; - this.right = right; - this.bottom = bottom; - } - }, - /** - * set margin - * @param {Number} l - * @param {Number} t - * @param {Number} r - * @param {Number} b - */ - setMargin: function (l, t, r, b) { - this.left = l; - this.top = t; - this.right = r; - this.bottom = b; - }, - /** - * check is equals - * @param {ccui.Margin} target - * @returns {boolean} - */ - equals: function (target) { - return (this.left == target.left && this.top == target.top && this.right == target.right && this.bottom == target.bottom); - } -}); - -ccui.MarginZero = function(){ - return new ccui.Margin(0,0,0,0); -}; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutManager.js b/extensions/ccui/layouts/UILayoutManager.js new file mode 100644 index 0000000000..e12cc31333 --- /dev/null +++ b/extensions/ccui/layouts/UILayoutManager.js @@ -0,0 +1,457 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * Gets the layout manager by ccui.Layout's layout type. + * @param {Number} type + * @returns {ccui.linearVerticalLayoutManager|ccui.linearHorizontalLayoutManager|ccui.relativeLayoutManager|null} + */ +ccui.getLayoutManager = function (type) { + switch (type) { + case ccui.Layout.LINEAR_VERTICAL: + return ccui.linearVerticalLayoutManager; + case ccui.Layout.LINEAR_HORIZONTAL: + return ccui.linearHorizontalLayoutManager; + case ccui.Layout.RELATIVE: + return ccui.relativeLayoutManager; + } + return null; +}; + +/** + * ccui.linearVerticalLayoutManager is a singleton object which is the linear vertical layout manager for ccui.Layout. + * @class + * @name ccui.linearVerticalLayoutManager + */ +ccui.linearVerticalLayoutManager = /** @lends ccui.linearVerticalLayoutManager# */{ + _doLayout: function(layout){ + var layoutSize = layout._getLayoutContentSize(); + var container = layout._getLayoutElements(); + var topBoundary = layoutSize.height; + + for (var i = 0, len = container.length; i < len; i++) { + var child = container[i]; + if (child) { + var layoutParameter = child.getLayoutParameter(); + + if (layoutParameter){ + var childGravity = layoutParameter.getGravity(); + var ap = child.getAnchorPoint(); + var cs = child.getContentSize(); + var finalPosX = ap.x * cs.width; + var finalPosY = topBoundary - ((1.0 - ap.y) * cs.height); + switch (childGravity){ + case ccui.LinearLayoutParameter.NONE: + case ccui.LinearLayoutParameter.LEFT: + break; + case ccui.LinearLayoutParameter.RIGHT: + finalPosX = layoutSize.width - ((1.0 - ap.x) * cs.width); + break; + case ccui.LinearLayoutParameter.CENTER_HORIZONTAL: + finalPosX = layoutSize.width / 2.0 - cs.width * (0.5 - ap.x); + break; + default: + break; + } + var mg = layoutParameter.getMargin(); + finalPosX += mg.left; + finalPosY -= mg.top; + child.setPosition(finalPosX, finalPosY); + topBoundary = child.getPositionY() - ap.y * cs.height - mg.bottom; + } + } + } + } +}; + +/** + * ccui.linearHorizontalLayoutManager is a singleton object which is the linear horizontal layout manager for ccui.Layout + * @class + * @name ccui.linearHorizontalLayoutManager + */ +ccui.linearHorizontalLayoutManager = /** @lends ccui.linearHorizontalLayoutManager# */{ + _doLayout: function(layout){ + var layoutSize = layout._getLayoutContentSize(); + var container = layout._getLayoutElements(); + var leftBoundary = 0.0; + for (var i = 0, len = container.length; i < len; i++) { + var child = container[i]; + if (child) { + var layoutParameter = child.getLayoutParameter(); + if (layoutParameter){ + var childGravity = layoutParameter.getGravity(); + var ap = child.getAnchorPoint(); + var cs = child.getContentSize(); + var finalPosX = leftBoundary + (ap.x * cs.width); + var finalPosY = layoutSize.height - (1.0 - ap.y) * cs.height; + switch (childGravity){ + case ccui.LinearLayoutParameter.NONE: + case ccui.LinearLayoutParameter.TOP: + break; + case ccui.LinearLayoutParameter.BOTTOM: + finalPosY = ap.y * cs.height; + break; + case ccui.LinearLayoutParameter.CENTER_VERTICAL: + finalPosY = layoutSize.height / 2.0 - cs.height * (0.5 - ap.y); + break; + default: + break; + } + var mg = layoutParameter.getMargin(); + finalPosX += mg.left; + finalPosY -= mg.top; + child.setPosition(finalPosX, finalPosY); + leftBoundary = child.getRightBoundary() + mg.right; + } + } + } + } +}; + +/** + * ccui.relativeLayoutManager is the singleton object which is the relative layout manager for ccui.Layout, it has a _doLayout function to do layout. + * @class + * @name ccui.relativeLayoutManager + */ +ccui.relativeLayoutManager = /** @lends ccui.relativeLayoutManager# */{ + _unlayoutChildCount: 0, + _widgetChildren: [], + _widget: null, + _finalPositionX:0, + _finalPositionY:0, + _relativeWidgetLP:null, + + _doLayout: function(layout){ + this._widgetChildren = this._getAllWidgets(layout); + + var locChildren = this._widgetChildren; + while (this._unlayoutChildCount > 0) { + for (var i = 0, len = locChildren.length; i < len; i++) { + this._widget = locChildren[i]; + + var layoutParameter = this._widget.getLayoutParameter(); + if (layoutParameter){ + if (layoutParameter._put) + continue; + + var ret = this._calculateFinalPositionWithRelativeWidget(layout); + if (!ret) + continue; + + this._calculateFinalPositionWithRelativeAlign(); + + this._widget.setPosition(this._finalPositionX, this._finalPositionY); + layoutParameter._put = true; + } + } + this._unlayoutChildCount--; + } + this._widgetChildren.length = 0; + }, + + _getAllWidgets: function(layout){ + var container = layout._getLayoutElements(); + var locWidgetChildren = this._widgetChildren; + locWidgetChildren.length = 0; + for (var i = 0, len = container.length; i < len; i++){ + var child = container[i]; + if (child) { + var layoutParameter = child.getLayoutParameter(); + layoutParameter._put = false; + this._unlayoutChildCount++; + locWidgetChildren.push(child); + } + } + return locWidgetChildren; + }, + + _getRelativeWidget: function(widget){ + var relativeWidget = null; + var layoutParameter = widget.getLayoutParameter(); + var relativeName = layoutParameter.getRelativeToWidgetName(); + + if (relativeName && relativeName.length !== 0) { + var locChildren = this._widgetChildren; + for(var i = 0, len = locChildren.length; i < len; i++){ + var child = locChildren[i]; + if (child){ + var rlayoutParameter = child.getLayoutParameter(); + if (rlayoutParameter && rlayoutParameter.getRelativeName() === relativeName) { + relativeWidget = child; + this._relativeWidgetLP = rlayoutParameter; + break; + } + } + } + } + return relativeWidget; + }, + + _calculateFinalPositionWithRelativeWidget: function(layout){ + var locWidget = this._widget; + var ap = locWidget.getAnchorPoint(); + var cs = locWidget.getContentSize(); + + this._finalPositionX = 0.0; + this._finalPositionY = 0.0; + + var relativeWidget = this._getRelativeWidget(locWidget); + var layoutParameter = locWidget.getLayoutParameter(); + var align = layoutParameter.getAlign(); + var layoutSize = layout._getLayoutContentSize(); + + switch (align) { + case ccui.RelativeLayoutParameter.NONE: + case ccui.RelativeLayoutParameter.PARENT_TOP_LEFT: + this._finalPositionX = ap.x * cs.width; + this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height); + break; + case ccui.RelativeLayoutParameter.PARENT_TOP_CENTER_HORIZONTAL: + this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x); + this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height); + break; + case ccui.RelativeLayoutParameter.PARENT_TOP_RIGHT: + this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width); + this._finalPositionY = layoutSize.height - ((1.0 - ap.y) * cs.height); + break; + case ccui.RelativeLayoutParameter.PARENT_LEFT_CENTER_VERTICAL: + this._finalPositionX = ap.x * cs.width; + this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y); + break; + case ccui.RelativeLayoutParameter.CENTER_IN_PARENT: + this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x); + this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y); + break; + case ccui.RelativeLayoutParameter.PARENT_RIGHT_CENTER_VERTICAL: + this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width); + this._finalPositionY = layoutSize.height * 0.5 - cs.height * (0.5 - ap.y); + break; + case ccui.RelativeLayoutParameter.PARENT_LEFT_BOTTOM: + this._finalPositionX = ap.x * cs.width; + this._finalPositionY = ap.y * cs.height; + break; + case ccui.RelativeLayoutParameter.PARENT_BOTTOM_CENTER_HORIZONTAL: + this._finalPositionX = layoutSize.width * 0.5 - cs.width * (0.5 - ap.x); + this._finalPositionY = ap.y * cs.height; + break; + case ccui.RelativeLayoutParameter.PARENT_RIGHT_BOTTOM: + this._finalPositionX = layoutSize.width - ((1.0 - ap.x) * cs.width); + this._finalPositionY = ap.y * cs.height; + break; + + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_LEFTALIGN: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() + ap.x * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_CENTER: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + var rbs = relativeWidget.getContentSize(); + this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() + rbs.width * 0.5 + ap.x * cs.width - cs.width * 0.5; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_RIGHTALIGN: + if (relativeWidget) { + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getTopBoundary() + ap.y * cs.height; + this._finalPositionX = relativeWidget.getRightBoundary() - (1.0 - ap.x) * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_TOPALIGN: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getTopBoundary() - (1.0 - ap.y) * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_CENTER: + if (relativeWidget) { + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + var rbs = relativeWidget.getContentSize(); + this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width; + this._finalPositionY = relativeWidget.getBottomBoundary() + rbs.height * 0.5 + ap.y * cs.height - cs.height * 0.5; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_BOTTOMALIGN: + if (relativeWidget) { + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getBottomBoundary() + ap.y * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() - (1.0 - ap.x) * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_TOPALIGN: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getTopBoundary() - (1.0 - ap.y) * cs.height; + this._finalPositionX = relativeWidget.getRightBoundary() + ap.x * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_CENTER: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + var rbs = relativeWidget.getContentSize(); + var locationRight = relativeWidget.getRightBoundary(); + this._finalPositionX = locationRight + ap.x * cs.width; + this._finalPositionY = relativeWidget.getBottomBoundary() + rbs.height * 0.5 + ap.y * cs.height - cs.height * 0.5; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_BOTTOMALIGN: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getBottomBoundary() + ap.y * cs.height; + this._finalPositionX = relativeWidget.getRightBoundary() + ap.x * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN: + if (relativeWidget){ + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() + ap.x * cs.width; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_CENTER: + if (relativeWidget) { + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + var rbs = relativeWidget.getContentSize(); + this._finalPositionY = relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height; + this._finalPositionX = relativeWidget.getLeftBoundary() + rbs.width * 0.5 + ap.x * cs.width - cs.width * 0.5; + } + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN: + if (relativeWidget) { + if (this._relativeWidgetLP && !this._relativeWidgetLP._put) + return false; + this._finalPositionY = relativeWidget.getBottomBoundary() - (1.0 - ap.y) * cs.height; + this._finalPositionX = relativeWidget.getRightBoundary() - (1.0 - ap.x) * cs.width; + } + break; + default: + break; + } + return true; + }, + + _calculateFinalPositionWithRelativeAlign: function(){ + var layoutParameter = this._widget.getLayoutParameter(); + + var mg = layoutParameter.getMargin(); + var align = layoutParameter.getAlign(); + + //handle margin + switch (align) { + case ccui.RelativeLayoutParameter.NONE: + case ccui.RelativeLayoutParameter.PARENT_TOP_LEFT: + this._finalPositionX += mg.left; + this._finalPositionY -= mg.top; + break; + case ccui.RelativeLayoutParameter.PARENT_TOP_CENTER_HORIZONTAL: + this._finalPositionY -= mg.top; + break; + case ccui.RelativeLayoutParameter.PARENT_TOP_RIGHT: + this._finalPositionX -= mg.right; + this._finalPositionY -= mg.top; + break; + case ccui.RelativeLayoutParameter.PARENT_LEFT_CENTER_VERTICAL: + this._finalPositionX += mg.left; + break; + case ccui.RelativeLayoutParameter.CENTER_IN_PARENT: + break; + case ccui.RelativeLayoutParameter.PARENT_RIGHT_CENTER_VERTICAL: + this._finalPositionX -= mg.right; + break; + case ccui.RelativeLayoutParameter.PARENT_LEFT_BOTTOM: + this._finalPositionX += mg.left; + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.PARENT_BOTTOM_CENTER_HORIZONTAL: + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.PARENT_RIGHT_BOTTOM: + this._finalPositionX -= mg.right; + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_LEFTALIGN: + this._finalPositionY += mg.bottom; + this._finalPositionX += mg.left; + break; + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_RIGHTALIGN: + this._finalPositionY += mg.bottom; + this._finalPositionX -= mg.right; + break; + case ccui.RelativeLayoutParameter.LOCATION_ABOVE_CENTER: + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_TOPALIGN: + this._finalPositionX -= mg.right; + this._finalPositionY -= mg.top; + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_BOTTOMALIGN: + this._finalPositionX -= mg.right; + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_CENTER: + this._finalPositionX -= mg.right; + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_TOPALIGN: + this._finalPositionX += mg.left; + this._finalPositionY -= mg.top; + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_BOTTOMALIGN: + this._finalPositionX += mg.left; + this._finalPositionY += mg.bottom; + break; + case ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_CENTER: + this._finalPositionX += mg.left; + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN: + this._finalPositionY -= mg.top; + this._finalPositionX += mg.left; + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN: + this._finalPositionY -= mg.top; + this._finalPositionX -= mg.right; + break; + case ccui.RelativeLayoutParameter.LOCATION_BELOW_CENTER: + this._finalPositionY -= mg.top; + break; + default: + break; + } + } +}; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutParameter.js b/extensions/ccui/layouts/UILayoutParameter.js index ab0d88d7a8..2ea2919426 100644 --- a/extensions/ccui/layouts/UILayoutParameter.js +++ b/extensions/ccui/layouts/UILayoutParameter.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,31 +24,111 @@ ****************************************************************************/ /** - * Base class for ccui.LayoutParameter + * Base class for ccui.Margin + * @class + * @extends ccui.Class + * + * @property {Number} left - Left of margin + * @property {Number} top - Top of margin + * @property {Number} right - right of margin + * @property {Number} bottom - bottom of margin + */ +ccui.Margin = ccui.Class.extend(/** @lends ccui.Margin# */{ + left: 0, + top: 0, + right: 0, + bottom: 0, + /** + * Constructor of ccui.Margin. + * @param {Number|ccui.Margin} margin a margin or left + * @param {Number} [top] + * @param {Number} [right] + * @param {Number} [bottom] + */ + ctor: function (margin, top, right, bottom) { + if (margin !== undefined && top === undefined) { + this.left = margin.left; + this.top = margin.top; + this.right = margin.right; + this.bottom = margin.bottom; + } + if (bottom !== undefined) { + this.left = margin; + this.top = top; + this.right = right; + this.bottom = bottom; + } + }, + /** + * Sets boundary of margin + * @param {Number} l left + * @param {Number} t top + * @param {Number} r right + * @param {Number} b bottom + */ + setMargin: function (l, t, r, b) { + this.left = l; + this.top = t; + this.right = r; + this.bottom = b; + }, + /** + * Checks target whether equals itself. + * @param {ccui.Margin} target + * @returns {boolean} + */ + equals: function (target) { + return (this.left === target.left && this.top === target.top && this.right === target.right && this.bottom === target.bottom); + } +}); + +/** + * Gets a zero margin object + * @function + * @returns {ccui.Margin} + */ +ccui.MarginZero = function(){ + return new ccui.Margin(0,0,0,0); +}; + +/** + * Layout parameter contains a margin and layout parameter type. It uses for ccui.LayoutManager. * @class * @extends ccui.Class */ ccui.LayoutParameter = ccui.Class.extend(/** @lends ccui.LayoutParameter# */{ _margin: null, _layoutParameterType: null, + + /** + * The constructor of ccui.LayoutParameter. + * @function + */ ctor: function () { this._margin = new ccui.Margin(); this._layoutParameterType = ccui.LayoutParameter.NONE; }, /** - * Sets Margin parameter for LayoutParameter. + * Sets Margin to LayoutParameter. * @param {ccui.Margin} margin */ setMargin: function (margin) { - this._margin.left = margin.left; - this._margin.top = margin.top; - this._margin.right = margin.right; - this._margin.bottom = margin.bottom; + if(cc.isObject(margin)){ + this._margin.left = margin.left; + this._margin.top = margin.top; + this._margin.right = margin.right; + this._margin.bottom = margin.bottom; + }else{ + this._margin.left = arguments[0]; + this._margin.top = arguments[1]; + this._margin.right = arguments[2]; + this._margin.bottom = arguments[3]; + } }, /** - * Gets Margin parameter of LayoutParameter. + * Gets Margin of LayoutParameter. * @returns {ccui.Margin} */ getMargin: function () { @@ -56,15 +137,19 @@ ccui.LayoutParameter = ccui.Class.extend(/** @lends ccui.LayoutParameter# */{ /** * Gets LayoutParameterType of LayoutParameter. - * @returns {ccui.UILayoutParameterType} + * @returns {Number} */ getLayoutType: function () { return this._layoutParameterType; }, + /** + * Clones a ccui.LayoutParameter object from itself. + * @returns {ccui.LayoutParameter} + */ clone:function(){ - var parameter = this.createCloneInstance(); - parameter.copyProperties(this); + var parameter = this._createCloneInstance(); + parameter._copyProperties(this); return parameter; }, @@ -72,19 +157,19 @@ ccui.LayoutParameter = ccui.Class.extend(/** @lends ccui.LayoutParameter# */{ * create clone instance. * @returns {ccui.LayoutParameter} */ - createCloneInstance:function(){ - return ccui.LayoutParameter.create(); + _createCloneInstance:function(){ + return new ccui.LayoutParameter(); }, /** - * copy properties + * copy properties from model. * @param {ccui.LayoutParameter} model */ - copyProperties:function(model){ + _copyProperties:function(model){ + this._margin.bottom = model._margin.bottom; this._margin.left = model._margin.left; - this._margin.top = model._margin.top; this._margin.right = model._margin.right; - this._margin.bottom = model._margin.bottom; + this._margin.top = model._margin.top; } }); @@ -92,59 +177,73 @@ ccui.LayoutParameter = ccui.Class.extend(/** @lends ccui.LayoutParameter# */{ * allocates and initializes a LayoutParameter. * @constructs * @return {ccui.LayoutParameter} - * @example - * // example - * var uiLayoutParameter = ccui.LayoutParameter.create(); */ ccui.LayoutParameter.create = function () { - var parameter = new ccui.LayoutParameter(); - return parameter; + return new ccui.LayoutParameter(); }; +// Constants +//layout parameter type +/** + * The none of ccui.LayoutParameter's type. + * @constant + * @type {number} + */ +ccui.LayoutParameter.NONE = 0; +/** + * The linear of ccui.LayoutParameter's type. + * @constant + * @type {number} + */ +ccui.LayoutParameter.LINEAR = 1; +/** + * The relative of ccui.LayoutParameter's type. + * @constant + * @type {number} + */ +ccui.LayoutParameter.RELATIVE = 2; + /** - * Base class for ccui.LinearLayoutParameter + * The linear of Layout parameter. its parameter type is ccui.LayoutParameter.LINEAR. * @class * @extends ccui.LayoutParameter */ ccui.LinearLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.LinearLayoutParameter# */{ _linearGravity: null, + /** + * The constructor of ccui.LinearLayoutParameter. + * @function + */ ctor: function () { ccui.LayoutParameter.prototype.ctor.call(this); - this._linearGravity = ccui.LINEAR_GRAVITY_NONE; + this._linearGravity = ccui.LinearLayoutParameter.NONE; this._layoutParameterType = ccui.LayoutParameter.LINEAR; }, /** - * Sets LinearGravity parameter for LayoutParameter. - * @param {ccui.LINEAR_GRAVITY_NONE|ccui.LINEAR_GRAVITY_TOP|ccui.LINEAR_GRAVITY_RIGHT|ccui.LINEAR_GRAVITY_BOTTOM|ccui.LINEAR_GRAVITY_CENTER_VERTICAL|ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL} gravity + * Sets LinearGravity to LayoutParameter. + * @param {Number} gravity */ setGravity: function (gravity) { this._linearGravity = gravity; }, /** - * Gets LinearGravity parameter for LayoutParameter. - * @returns {ccui.LINEAR_GRAVITY_NONE|ccui.LINEAR_GRAVITY_TOP|ccui.LINEAR_GRAVITY_RIGHT|ccui.LINEAR_GRAVITY_BOTTOM|ccui.LINEAR_GRAVITY_CENTER_VERTICAL|ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL} + * Gets LinearGravity of LayoutParameter. + * @returns {Number} */ getGravity: function () { return this._linearGravity; }, - /** - * create clone instance. - * @returns {ccui.LinearLayoutParameter} - */ - createCloneInstance: function () { - return ccui.LinearLayoutParameter.create(); + _createCloneInstance: function () { + return new ccui.LinearLayoutParameter(); }, - /** - * copy properties - * @param {ccui.LinearLayoutParameter} model - */ - copyProperties: function (model) { - ccui.LayoutParameter.prototype.copyProperties.call(this, model); - this.setGravity(model._linearGravity); + _copyProperties: function (model) { + ccui.LayoutParameter.prototype._copyProperties.call(this, model); + if (model instanceof ccui.LinearLayoutParameter) + this.setGravity(model._linearGravity); } }); @@ -152,17 +251,60 @@ ccui.LinearLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.LinearL * allocates and initializes a LinearLayoutParameter. * @constructs * @return {ccui.LinearLayoutParameter} - * @example - * // example - * var uiLinearLayoutParameter = ccui.LinearLayoutParameter.create(); + * @deprecated since v3.0, please use new construction instead */ ccui.LinearLayoutParameter.create = function () { - var parameter = new ccui.LinearLayoutParameter(); - return parameter; + return new ccui.LinearLayoutParameter(); }; +// Constants +//Linear layout parameter LinearGravity /** - * Base class for ccui.RelativeLayoutParameter + * The none of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.NONE = 0; + +/** + * The left of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.LEFT = 1; +/** + * The top of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.TOP = 2; +/** + * The right of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.RIGHT = 3; +/** + * The bottom of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.BOTTOM = 4; +/** + * The center vertical of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.CENTER_VERTICAL = 5; +/** + * The center horizontal of ccui.LinearLayoutParameter's linear gravity. + * @constant + * @type {number} + */ +ccui.LinearLayoutParameter.CENTER_HORIZONTAL = 6; + +/** + * The relative of layout parameter. Its layout parameter type is ccui.LayoutParameter.RELATIVE. * @class * @extends ccui.LayoutParameter */ @@ -171,9 +313,13 @@ ccui.RelativeLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.Relat _relativeWidgetName: "", _relativeLayoutName: "", _put:false, + /** + * The constructor of ccui.RelativeLayoutParameter + * @function + */ ctor: function () { ccui.LayoutParameter.prototype.ctor.call(this); - this._relativeAlign = ccui.RELATIVE_ALIGN_NONE; + this._relativeAlign = ccui.RelativeLayoutParameter.NONE; this._relativeWidgetName = ""; this._relativeLayoutName = ""; this._put = false; @@ -182,7 +328,7 @@ ccui.RelativeLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.Relat /** * Sets RelativeAlign parameter for LayoutParameter. - * @param {ccui.RELATIVE_ALIGN_*} align + * @param {Number} align */ setAlign: function (align) { this._relativeAlign = align; @@ -190,7 +336,7 @@ ccui.RelativeLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.Relat /** * Gets RelativeAlign parameter for LayoutParameter. - * @returns {ccui.RELATIVE_ALIGN_*} + * @returns {Number} */ getAlign: function () { return this._relativeAlign; @@ -228,42 +374,203 @@ ccui.RelativeLayoutParameter = ccui.LayoutParameter.extend(/** @lends ccui.Relat return this._relativeLayoutName; }, - /** - * create clone instance. - * @returns {ccui.RelativeLayoutParameter} - */ - createCloneInstance:function(){ - return ccui.LinearLayoutParameter.create(); + _createCloneInstance:function(){ + return new ccui.RelativeLayoutParameter(); }, - /** - * copy properties - * @param {ccui.RelativeLayoutParameter} model - */ - copyProperties:function(model){ - ccui.LayoutParameter.prototype.copyProperties.call(this, model); - this.setAlign(model._relativeAlign); - this.setRelativeToWidgetName(model._relativeWidgetName); - this.setRelativeName(model._relativeLayoutName); + _copyProperties:function(model){ + ccui.LayoutParameter.prototype._copyProperties.call(this, model); + if (model instanceof ccui.RelativeLayoutParameter) { + this.setAlign(model._relativeAlign); + this.setRelativeToWidgetName(model._relativeWidgetName); + this.setRelativeName(model._relativeLayoutName); + } } }); /** - * allocates and initializes a RelativeLayoutParameter. - * @constructs + * Allocates and initializes a RelativeLayoutParameter. + * @function + * @deprecated since v3.0, please use new ccui.RelativeLayoutParameter() instead. * @return {ccui.RelativeLayoutParameter} - * @example - * // example - * var uiRelativeLayoutParameter = ccui.RelativeLayoutParameter.create(); */ ccui.RelativeLayoutParameter.create = function () { - var parameter = new ccui.RelativeLayoutParameter(); - return parameter; + return new ccui.RelativeLayoutParameter(); }; - // Constants -//layout parameter type -ccui.LayoutParameter.NONE = 0; -ccui.LayoutParameter.LINEAR = 1; -ccui.LayoutParameter.RELATIVE = 2; \ No newline at end of file +//Relative layout parameter RelativeAlign +/** + * The none of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.NONE = 0; +/** + * The parent's top left of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_TOP_LEFT = 1; +/** + * The parent's top center horizontal of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_TOP_CENTER_HORIZONTAL = 2; +/** + * The parent's top right of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_TOP_RIGHT = 3; +/** + * The parent's left center vertical of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_LEFT_CENTER_VERTICAL = 4; + +/** + * The center in parent of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.CENTER_IN_PARENT = 5; + +/** + * The parent's right center vertical of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_RIGHT_CENTER_VERTICAL = 6; +/** + * The parent's left bottom of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_LEFT_BOTTOM = 7; +/** + * The parent's bottom center horizontal of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_BOTTOM_CENTER_HORIZONTAL = 8; +/** + * The parent's right bottom of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.PARENT_RIGHT_BOTTOM = 9; + +/** + * The location above left align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_ABOVE_LEFTALIGN = 10; +/** + * The location above center of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_ABOVE_CENTER = 11; +/** + * The location above right align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_ABOVE_RIGHTALIGN = 12; +/** + * The location left of top align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_TOPALIGN = 13; +/** + * The location left of center of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_CENTER = 14; +/** + * The location left of bottom align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_LEFT_OF_BOTTOMALIGN = 15; +/** + * The location right of top align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_TOPALIGN = 16; +/** + * The location right of center of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_CENTER = 17; +/** + * The location right of bottom align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_RIGHT_OF_BOTTOMALIGN = 18; +/** + * The location below left align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_BELOW_LEFTALIGN = 19; +/** + * The location below center of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_BELOW_CENTER = 20; +/** + * The location below right align of ccui.RelativeLayoutParameter's relative align. + * @constant + * @type {number} + */ +ccui.RelativeLayoutParameter.LOCATION_BELOW_RIGHTALIGN = 21; + +/** + * @ignore + */ +ccui.LINEAR_GRAVITY_NONE = 0; +ccui.LINEAR_GRAVITY_LEFT = 1; +ccui.LINEAR_GRAVITY_TOP = 2; +ccui.LINEAR_GRAVITY_RIGHT = 3; +ccui.LINEAR_GRAVITY_BOTTOM = 4; +ccui.LINEAR_GRAVITY_CENTER_VERTICAL = 5; +ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL = 6; + +//RelativeAlign +ccui.RELATIVE_ALIGN_NONE = 0; +ccui.RELATIVE_ALIGN_PARENT_TOP_LEFT = 1; +ccui.RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL = 2; +ccui.RELATIVE_ALIGN_PARENT_TOP_RIGHT = 3; +ccui.RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL = 4; +ccui.RELATIVE_ALIGN_PARENT_CENTER = 5; +ccui.RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL = 6; +ccui.RELATIVE_ALIGN_PARENT_LEFT_BOTTOM = 7; +ccui.RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL = 8; +ccui.RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM = 9; + +ccui.RELATIVE_ALIGN_LOCATION_ABOVE_LEFT = 10; +ccui.RELATIVE_ALIGN_LOCATION_ABOVE_CENTER = 11; +ccui.RELATIVE_ALIGN_LOCATION_ABOVE_RIGHT = 12; + +ccui.RELATIVE_ALIGN_LOCATION_LEFT_TOP = 13; +ccui.RELATIVE_ALIGN_LOCATION_LEFT_CENTER = 14; +ccui.RELATIVE_ALIGN_LOCATION_LEFT_BOTTOM = 15; + +ccui.RELATIVE_ALIGN_LOCATION_RIGHT_TOP = 16; +ccui.RELATIVE_ALIGN_LOCATION_RIGHT_CENTER = 17; +ccui.RELATIVE_ALIGN_LOCATION_RIGHT_BOTTOM = 18; + +ccui.RELATIVE_ALIGN_LOCATION_BELOW_TOP = 19; +ccui.RELATIVE_ALIGN_LOCATION_BELOW_CENTER = 20; +ccui.RELATIVE_ALIGN_LOCATION_BELOW_BOTTOM = 21; \ No newline at end of file diff --git a/extensions/ccui/layouts/UILayoutWebGLRenderCmd.js b/extensions/ccui/layouts/UILayoutWebGLRenderCmd.js new file mode 100644 index 0000000000..baf4773fca --- /dev/null +++ b/extensions/ccui/layouts/UILayoutWebGLRenderCmd.js @@ -0,0 +1,242 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + if(!ccui.ProtectedNode.WebGLRenderCmd) + return; + ccui.Layout.WebGLRenderCmd = function(renderable){ + ccui.ProtectedNode.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + + this._currentStencilEnabled = 0; + this._currentStencilWriteMask = 0; + this._currentStencilFunc = 0; + this._currentStencilRef = 0; + this._currentStencilValueMask = 0; + this._currentStencilFail = 0; + this._currentStencilPassDepthFail = 0; + this._currentStencilPassDepthPass = 0; + this._currentDepthWriteMask = false; + + this._mask_layer_le = 0; + + this._beforeVisitCmdStencil = new cc.CustomRenderCmd(this, this._onBeforeVisitStencil); + this._afterDrawStencilCmd = new cc.CustomRenderCmd(this, this._onAfterDrawStencil); + this._afterVisitCmdStencil = new cc.CustomRenderCmd(this, this._onAfterVisitStencil); + this._beforeVisitCmdScissor = new cc.CustomRenderCmd(this, this._onBeforeVisitScissor); + this._afterVisitCmdScissor = new cc.CustomRenderCmd(this, this._onAfterVisitScissor); + }; + + var proto = ccui.Layout.WebGLRenderCmd.prototype = Object.create(ccui.ProtectedNode.WebGLRenderCmd.prototype); + proto.constructor = ccui.Layout.WebGLRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + if (!node._visible) + return; + node._adaptRenderers(); + node._doLayout(); + + if (node._clippingEnabled) { + switch (node._clippingType) { + case ccui.Layout.CLIPPING_STENCIL: + this.stencilClippingVisit(parentCmd); + break; + case ccui.Layout.CLIPPING_SCISSOR: + this.scissorClippingVisit(parentCmd); + break; + default: + break; + } + } else + ccui.Widget.WebGLRenderCmd.prototype.visit.call(this, parentCmd); + }; + + proto._onBeforeVisitStencil = function(ctx){ + var gl = ctx || cc._renderContext; + + ccui.Layout.WebGLRenderCmd._layer++; + + var mask_layer = 0x1 << ccui.Layout.WebGLRenderCmd._layer; + var mask_layer_l = mask_layer - 1; + this._mask_layer_le = mask_layer | mask_layer_l; + + // manually save the stencil state + this._currentStencilEnabled = gl.isEnabled(gl.STENCIL_TEST); + this._currentStencilWriteMask = gl.getParameter(gl.STENCIL_WRITEMASK); + this._currentStencilFunc = gl.getParameter(gl.STENCIL_FUNC); + this._currentStencilRef = gl.getParameter(gl.STENCIL_REF); + this._currentStencilValueMask = gl.getParameter(gl.STENCIL_VALUE_MASK); + this._currentStencilFail = gl.getParameter(gl.STENCIL_FAIL); + this._currentStencilPassDepthFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL); + this._currentStencilPassDepthPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS); + + gl.enable(gl.STENCIL_TEST); + + gl.stencilMask(mask_layer); + + this._currentDepthWriteMask = gl.getParameter(gl.DEPTH_WRITEMASK); + + gl.depthMask(false); + + gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); + gl.stencilOp(gl.ZERO, gl.KEEP, gl.KEEP); + + // draw a fullscreen solid rectangle to clear the stencil buffer + this._drawFullScreenQuadClearStencil(); + + gl.stencilFunc(gl.NEVER, mask_layer, mask_layer); + gl.stencilOp(gl.REPLACE, gl.KEEP, gl.KEEP); + }; + + proto._onAfterDrawStencil = function(ctx){ + var gl = ctx || cc._renderContext; + gl.depthMask(this._currentDepthWriteMask); + gl.stencilFunc(gl.EQUAL, this._mask_layer_le, this._mask_layer_le); + gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); + }; + + proto._onAfterVisitStencil = function(ctx){ + var gl = ctx || cc._renderContext; + // manually restore the stencil state + gl.stencilFunc(this._currentStencilFunc, this._currentStencilRef, this._currentStencilValueMask); + gl.stencilOp(this._currentStencilFail, this._currentStencilPassDepthFail, this._currentStencilPassDepthPass); + gl.stencilMask(this._currentStencilWriteMask); + if (!this._currentStencilEnabled) + gl.disable(gl.STENCIL_TEST); + ccui.Layout.WebGLRenderCmd._layer--; + }; + + proto._onBeforeVisitScissor = function(ctx){ + var clippingRect = this._getClippingRect(); + var gl = ctx || cc._renderContext; + gl.enable(gl.SCISSOR_TEST); + + cc.view.setScissorInPoints(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); + }; + + proto._onAfterVisitScissor = function(ctx){ + var gl = ctx || cc._renderContext; + gl.disable(gl.SCISSOR_TEST); + }; + + proto._drawFullScreenQuadClearStencil = function(){ + // draw a fullscreen solid rectangle to clear the stencil buffer + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLPushMatrix(); + cc.kmGLLoadIdentity(); + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLPushMatrix(); + cc.kmGLLoadIdentity(); + cc._drawingUtil.drawSolidRect(cc.p(-1,-1), cc.p(1,1), cc.color(255, 255, 255, 255)); + cc.kmGLMatrixMode(cc.KM_GL_PROJECTION); + cc.kmGLPopMatrix(); + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLPopMatrix(); + }; + + proto.rebindStencilRendering = function(stencil){}; + + proto.transform = function(parentCmd, recursive){ + var node = this._node; + ccui.ProtectedNode.WebGLRenderCmd.prototype.transform.call(this, parentCmd, recursive); + if(node._clippingStencil) + node._clippingStencil._renderCmd.transform(this, recursive); + }; + + proto.stencilClippingVisit = function (parentCmd) { + var node = this._node; + if (!node._clippingStencil || !node._clippingStencil.isVisible()) + return; + + // all the _stencilBits are in use? + if (ccui.Layout.WebGLRenderCmd._layer + 1 === cc.stencilBits) { + // warn once + ccui.Layout.WebGLRenderCmd._visit_once = true; + if (ccui.Layout.WebGLRenderCmd._visit_once) { + cc.log("Nesting more than " + cc.stencilBits + "stencils is not supported. Everything will be drawn without stencil for this node and its childs."); + ccui.Layout.WebGLRenderCmd._visit_once = false; + } + // draw everything, as if there where no stencil + cc.Node.prototype.visit.call(node, parentCmd); + return; + } + + cc.renderer.pushRenderCommand(this._beforeVisitCmdStencil); + + //optimize performance for javascript + var currentStack = cc.current_stack; + currentStack.stack.push(currentStack.top); + this._syncStatus(parentCmd); + this._dirtyFlag = 0; + currentStack.top = this._stackMatrix; + + node._clippingStencil.visit(this); + + cc.renderer.pushRenderCommand(this._afterDrawStencilCmd); + + // draw (according to the stencil test func) this node and its childs + var i = 0; // used by _children + var j = 0; // used by _protectedChildren + + node.sortAllChildren(); + node.sortAllProtectedChildren(); + var locChildren = node._children, locProtectChildren = node._protectedChildren; + var iLen = locChildren.length, jLen = locProtectChildren.length, child; + for( ; i < iLen; i++ ){ + child = locChildren[i]; + if ( child && child.getLocalZOrder() < 0 ) + child.visit(this); + else + break; + } + for( ; j < jLen; j++ ) { + child = locProtectChildren[j]; + if ( child && child.getLocalZOrder() < 0 ) + child.visit(this); + else + break; + } + + for (; i < iLen; i++) + locChildren[i].visit(this); + for (; j < jLen; j++) + locProtectChildren[j].visit(this); + + cc.renderer.pushRenderCommand(this._afterVisitCmdStencil); + + //optimize performance for javascript + currentStack.top = currentStack.stack.pop(); + }; + + proto.scissorClippingVisit = function(parentCmd){ + cc.renderer.pushRenderCommand(this._beforeVisitCmdScissor); + cc.ProtectedNode.prototype.visit.call(this._node, parentCmd); + cc.renderer.pushRenderCommand(this._afterVisitCmdScissor); + }; + + ccui.Layout.WebGLRenderCmd._layer = -1; + ccui.Layout.WebGLRenderCmd._visit_once = null; +})(); diff --git a/extensions/ccui/layouts/UIRelativeBox.js b/extensions/ccui/layouts/UIRelativeBox.js new file mode 100644 index 0000000000..500c9eee2b --- /dev/null +++ b/extensions/ccui/layouts/UIRelativeBox.js @@ -0,0 +1,79 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * The Relative box for Cocos UI layout. Its layout type is ccui.Layout.RELATIVE. + * @class + * @extends ccui.Layout + */ +ccui.RelativeBox = ccui.Layout.extend(/** @lends ccui.RelativeBox# */{ + /** + * The constructor of ccui.RelativeBox + * @function + * @param {cc.Size} [size] + */ + ctor: function(size){ + if(size) + this.initWithSize(size); + else + this.init(); + }, + + /** + * Initializes a relative box. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @override + * @returns {boolean} + */ + init: function(){ + if(ccui.Layout.prototype.init.call(this)){ + this.setLayoutType(ccui.Layout.RELATIVE); + return true; + } + return false; + }, + + /** + * Initializes a relative box with size + * @param {cc.Size} [size] + * @returns {boolean} + */ + initWithSize: function(size){ + if(this.init()){ + this.setContentSize(size); + return true; + } + return false; + } +}); + +/** + * Creates a relative box + * @deprecated since v3.0, please use new ccui.RelativeBox(size) instead. + * @param {cc.Size} size + * @returns {ccui.RelativeBox} + */ +ccui.RelativeBox.create = function(size){ + return new ccui.RelativeBox(size); +}; \ No newline at end of file diff --git a/extensions/ccui/layouts/UIVBox.js b/extensions/ccui/layouts/UIVBox.js new file mode 100644 index 0000000000..d816c729db --- /dev/null +++ b/extensions/ccui/layouts/UIVBox.js @@ -0,0 +1,79 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * The vertical box of Cocos UI. Its layout type is ccui.Layout.LINEAR_VERTICAL. + * @class + * @extends ccui.Layout + */ +ccui.VBox = ccui.Layout.extend(/** @lends ccui.VBox# */{ + /** + * The constructor of ccui.VBox + * @function + * @param {cc.Size} size + */ + ctor: function(size){ + ccui.Layout.prototype.ctor.call(this, size); + if(size !== undefined) + this.initWithSize(size); + else + this.init(); + }, + + /** + * Initializes a VBox. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @override + * @returns {boolean} + */ + init: function(){ + if(ccui.Layout.prototype.init.call(this)){ + this.setLayoutType(ccui.Layout.LINEAR_VERTICAL); + return true; + } + return false; + }, + + /** + * Initializes a VBox with size. + * @param {cc.Size} size + * @returns {boolean} + */ + initWithSize: function(size){ + if(this.init()){ + this.setContentSize(size); + return true; + } + return false; + } +}); + +/** + * Creates a VBox + * @param {cc.Size} size + * @returns {ccui.VBox} + */ +ccui.VBox.create = function(size){ + return new ccui.VBox(size); +}; \ No newline at end of file diff --git a/extensions/ccui/system/CocosGUI.js b/extensions/ccui/system/CocosGUI.js index 5d8966092b..30622d0c97 100644 --- a/extensions/ccui/system/CocosGUI.js +++ b/extensions/ccui/system/CocosGUI.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -21,12 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ + /** - * @namespace Base namespace of Cocos GUI + * The namespace of Cocos UI + * @namespace * @name ccui */ var ccui = ccui || {}; +//These classes defines are use for jsDoc /** * The same as cc.Class * @class @@ -42,8 +46,17 @@ ccui.Class.extend = ccui.Class.extend || cc.Class.extend; ccui.Node = ccui.Node || cc.Node; ccui.Node.extend = ccui.Node.extend || cc.Node.extend; + +/** + * that same as cc.Node + * @class + * @extends ccui.Node + */ +ccui.ProtectedNode = ccui.ProtectedNode || cc.ProtectedNode; +ccui.ProtectedNode.extend = ccui.ProtectedNode.extend || cc.ProtectedNode.extend; + /** - * Cocos GUI version + * Cocos UI version * @type {String} */ ccui.cocosGUIVersion = "CocosGUI v1.0.0.0"; \ No newline at end of file diff --git a/extensions/ccui/system/UIHelper.js b/extensions/ccui/system/UIHelper.js index 9497372000..70d82c9b84 100644 --- a/extensions/ccui/system/UIHelper.js +++ b/extensions/ccui/system/UIHelper.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,9 +23,13 @@ THE SOFTWARE. ****************************************************************************/ +//todo maybe need change here + + /** - * UI Helper - * @type {Object} + * ccui.helper is the singleton object which is the Helper object contains some functions for seek widget + * @class + * @name ccui.helper */ ccui.helper = { /** @@ -34,20 +39,18 @@ ccui.helper = { * @returns {ccui.Widget} */ seekWidgetByTag: function (root, tag) { - if (!root) { + if (!root) return null; - } - if (root.getTag() == tag) { + if (root.getTag() === tag) return root; - } + var arrayRootChildren = root.getChildren(); var length = arrayRootChildren.length; for (var i = 0; i < length; i++) { var child = arrayRootChildren[i]; - var res = this.seekWidgetByTag(child, tag); - if (res != null) { + var res = ccui.helper.seekWidgetByTag(child, tag); + if (res !== null) return res; - } } return null; }, @@ -59,20 +62,17 @@ ccui.helper = { * @returns {ccui.Widget} */ seekWidgetByName: function (root, name) { - if (!root) { + if (!root) return null; - } - if (root.getName() == name) { + if (root.getName() === name) return root; - } var arrayRootChildren = root.getChildren(); var length = arrayRootChildren.length; for (var i = 0; i < length; i++) { var child = arrayRootChildren[i]; - var res = this.seekWidgetByName(child, name); - if (res != null) { + var res = ccui.helper.seekWidgetByName(child, name); + if (res !== null) return res; - } } return null; }, @@ -85,39 +85,80 @@ ccui.helper = { * @returns {ccui.Widget} */ seekWidgetByRelativeName: function (root, name) { - if (!root) { + if (!root) return null; - } var arrayRootChildren = root.getChildren(); var length = arrayRootChildren.length; for (var i = 0; i < length; i++) { var child = arrayRootChildren[i]; var layoutParameter = child.getLayoutParameter(ccui.LayoutParameter.RELATIVE); - if (layoutParameter && layoutParameter.getRelativeName() == name) { + if (layoutParameter && layoutParameter.getRelativeName() === name) return child; - } } return null; }, - /*temp action*/ + /** + * Finds a widget whose action tag equals to param name from root widget. + * @param {ccui.Widget} root + * @param {Number} tag + * @returns {ccui.Widget} + */ seekActionWidgetByActionTag: function (root, tag) { - if (!root) { + if (!root) return null; - } - if (root.getActionTag() == tag) { + if (root.getActionTag() === tag) return root; - } var arrayRootChildren = root.getChildren(); for (var i = 0; i < arrayRootChildren.length; i++) { var child = arrayRootChildren[i]; - var res = this.seekActionWidgetByActionTag(child, tag); - if (res != null) { + var res = ccui.helper.seekActionWidgetByActionTag(child, tag); + if (res !== null) return res; - } } return null; - } + } , + + _activeLayout: true, + /** + * Refresh object and it's children layout state + * @param {cc.Node} rootNode + */ + doLayout: function(rootNode){ + if(!this._activeLayout) + return; + var children = rootNode.getChildren(), node; + for(var i = 0, len = children.length;i < len; i++) { + node = children[i]; + var com = node.getComponent(ccui.LayoutComponent.NAME); + var parent = node.getParent(); + if (null != com && null !== parent && com.refreshLayout) + com.refreshLayout(); + } + }, + + changeLayoutSystemActiveState: function(active){ + this._activeLayout = active; + }, + + /** + * restrict capInsetSize, when the capInsets' width is larger than the textureSize, it will restrict to 0,
    + * the height goes the same way as width. + * @param {cc.Rect} capInsets + * @param {cc.Size} textureSize + */ + restrictCapInsetRect: function (capInsets, textureSize) { + var x = capInsets.x, y = capInsets.y; + var width = capInsets.width, height = capInsets.height; + if (textureSize.width < width) { + x = 0.0; + width = 0.0; + } + if (textureSize.height < height) { + y = 0.0; + height = 0.0; + } + return cc.rect(x, y, width, height); + } }; -ccui.helper; diff --git a/extensions/ccui/uiwidgets/UIButton.js b/extensions/ccui/uiwidgets/UIButton.js index 97529c3601..3d6a21103d 100644 --- a/extensions/ccui/uiwidgets/UIButton.js +++ b/extensions/ccui/uiwidgets/UIButton.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccui.Button + * The button controls of Cocos UI. * @class * @extends ccui.Widget * @@ -39,152 +40,200 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ _buttonClickedRenderer: null, _buttonDisableRenderer: null, _titleRenderer: null, + _normalFileName: "", _clickedFileName: "", _disabledFileName: "", + _prevIgnoreSize: true, _scale9Enabled: false, -// CCRect _capInsets:null, + _capInsetsNormal: null, _capInsetsPressed: null, _capInsetsDisabled: null, - _normalTexType: null, - _pressedTexType: null, - _disabledTexType: null, + + _normalTexType: ccui.Widget.LOCAL_TEXTURE, + _pressedTexType: ccui.Widget.LOCAL_TEXTURE, + _disabledTexType: ccui.Widget.LOCAL_TEXTURE, + _normalTextureSize: null, _pressedTextureSize: null, _disabledTextureSize: null, + pressedActionEnabled: false, _titleColor: null, _normalTextureScaleXInSize: 1, _normalTextureScaleYInSize: 1, _pressedTextureScaleXInSize: 1, _pressedTextureScaleYInSize: 1, + + _zoomScale: 0.1, + _normalTextureLoaded: false, _pressedTextureLoaded: false, _disabledTextureLoaded: false, - _className:"Button", - ctor: function () { - ccui.Widget.prototype.ctor.call(this); - this._buttonNormalRenderer = null; - this._buttonClickedRenderer = null; - this._buttonDisableRenderer = null; - this._titleRenderer = null; - this._normalFileName = ""; - this._clickedFileName = ""; - this._disabledFileName = ""; - this._prevIgnoreSize = true; - this._scale9Enabled = false; + + _className: "Button", + _normalTextureAdaptDirty: true, + _pressedTextureAdaptDirty: true, + _disabledTextureAdaptDirty: true, + + _fontName: "Thonburi", + _fontSize: 12, + _type: 0, + + /** + * Allocates and initializes a UIButton. + * Constructor of ccui.Button. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {String} normalImage + * @param {String} [selectedImage=""] + * @param {String} [disableImage=""] + * @param {Number} [texType=ccui.Widget.LOCAL_TEXTURE] + * @example + * // example + * var uiButton = new ccui.Button(); + */ + ctor: function (normalImage, selectedImage, disableImage, texType) { this._capInsetsNormal = cc.rect(0, 0, 0, 0); this._capInsetsPressed = cc.rect(0, 0, 0, 0); this._capInsetsDisabled = cc.rect(0, 0, 0, 0); - this._normalTexType = ccui.Widget.LOCAL_TEXTURE; - this._pressedTexType = ccui.Widget.LOCAL_TEXTURE; - this._disabledTexType = ccui.Widget.LOCAL_TEXTURE; - var locSize = this._size; - this._normalTextureSize = cc.size(locSize.width, locSize.height); - this._pressedTextureSize = cc.size(locSize.width, locSize.height); - this._disabledTextureSize = cc.size(locSize.width, locSize.height); - this.pressedActionEnabled = false; + this._normalTextureSize = cc.size(0, 0); + this._pressedTextureSize = cc.size(0, 0); + this._disabledTextureSize = cc.size(0, 0); this._titleColor = cc.color.WHITE; - this._normalTextureScaleXInSize = 1; - this._normalTextureScaleYInSize = 1; - this._pressedTextureScaleXInSize = 1; - this._pressedTextureScaleYInSize = 1; - this._normalTextureLoaded = false; - this._pressedTextureLoaded = false; - this._disabledTextureLoaded = false; - }, - - init: function () { - if (ccui.Widget.prototype.init.call(this)){ - this.setTouchEnabled(true); - return true; + ccui.Widget.prototype.ctor.call(this); + this.setTouchEnabled(true); + this.init(normalImage, selectedImage, disableImage, texType); + }, + + /** + * Initializes a button. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @param {String} normalImage + * @param {String} [selectedImage=""] + * @param {String} [disableImage=""] + * @param {Number} [texType=ccui.Widget.LOCAL_TEXTURE] + * @returns {boolean} + * @override + */ + init: function (normalImage, selectedImage,disableImage, texType) { + if (ccui.Widget.prototype.init.call(this)) { + if(normalImage === undefined) + return true; + this.loadTextures(normalImage, selectedImage,disableImage, texType); } return false; }, - initRenderer: function () { - this._buttonNormalRenderer = cc.Sprite.create(); - this._buttonClickedRenderer = cc.Sprite.create(); - this._buttonDisableRenderer = cc.Sprite.create(); - this._titleRenderer = cc.LabelTTF.create(""); - cc.Node.prototype.addChild.call(this, this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER); - cc.Node.prototype.addChild.call(this, this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER); - cc.Node.prototype.addChild.call(this, this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER); - cc.Node.prototype.addChild.call(this, this._titleRenderer, ccui.Button.TITLE_RENDERER_ZORDER); + _initRenderer: function () { + //todo create Scale9Sprite + this._buttonNormalRenderer = new cc.Sprite(); + this._buttonClickedRenderer = new cc.Sprite(); + this._buttonDisableRenderer = new cc.Sprite(); + this._titleRenderer = new cc.LabelTTF(""); + this._titleRenderer.setAnchorPoint(0.5, 0.5); + + this.addProtectedChild(this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER, -1); + this.addProtectedChild(this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER, -1); + this.addProtectedChild(this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER, -1); + this.addProtectedChild(this._titleRenderer, ccui.Button.TITLE_RENDERER_ZORDER, -1); }, /** * Sets if button is using scale9 renderer. - * @param {Boolean} able + * @param {Boolean} able true that using scale9 renderer, false otherwise. */ setScale9Enabled: function (able) { - if (this._scale9Enabled == able) { + //todo create Scale9Sprite + if (this._scale9Enabled === able) return; - } + this._brightStyle = ccui.Widget.BRIGHT_STYLE_NONE; this._scale9Enabled = able; - cc.Node.prototype.removeChild.call(this, this._buttonNormalRenderer, true); - cc.Node.prototype.removeChild.call(this, this._buttonClickedRenderer, true); - cc.Node.prototype.removeChild.call(this, this._buttonDisableRenderer, true); + this.removeProtectedChild(this._buttonNormalRenderer); + this.removeProtectedChild(this._buttonClickedRenderer); + this.removeProtectedChild(this._buttonDisableRenderer); if (this._scale9Enabled) { - this._buttonNormalRenderer = cc.Scale9Sprite.create(); - this._buttonClickedRenderer = cc.Scale9Sprite.create(); - this._buttonDisableRenderer = cc.Scale9Sprite.create(); - } - else { - this._buttonNormalRenderer = cc.Sprite.create(); - this._buttonClickedRenderer = cc.Sprite.create(); - this._buttonDisableRenderer = cc.Sprite.create(); + this._buttonNormalRenderer = new ccui.Scale9Sprite(); + this._buttonClickedRenderer = new ccui.Scale9Sprite(); + this._buttonDisableRenderer = new ccui.Scale9Sprite(); + } else { + this._buttonNormalRenderer = new cc.Sprite(); + this._buttonClickedRenderer = new cc.Sprite(); + this._buttonDisableRenderer = new cc.Sprite(); } + this._buttonClickedRenderer.setVisible(false); + this._buttonDisableRenderer.setVisible(false); + this.loadTextureNormal(this._normalFileName, this._normalTexType); this.loadTexturePressed(this._clickedFileName, this._pressedTexType); this.loadTextureDisabled(this._disabledFileName, this._disabledTexType); - cc.Node.prototype.addChild.call(this, this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER); - cc.Node.prototype.addChild.call(this, this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER); - cc.Node.prototype.addChild.call(this, this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER); + + this.addProtectedChild(this._buttonNormalRenderer, ccui.Button.NORMAL_RENDERER_ZORDER, -1); + this.addProtectedChild(this._buttonClickedRenderer, ccui.Button.PRESSED_RENDERER_ZORDER, -1); + this.addProtectedChild(this._buttonDisableRenderer, ccui.Button.DISABLED_RENDERER_ZORDER, -1); if (this._scale9Enabled) { var ignoreBefore = this._ignoreSize; this.ignoreContentAdaptWithSize(false); this._prevIgnoreSize = ignoreBefore; - } - else { + } else { this.ignoreContentAdaptWithSize(this._prevIgnoreSize); } this.setCapInsetsNormalRenderer(this._capInsetsNormal); this.setCapInsetsPressedRenderer(this._capInsetsPressed); this.setCapInsetsDisabledRenderer(this._capInsetsDisabled); this.setBright(this._bright); + + this._normalTextureAdaptDirty = true; + this._pressedTextureAdaptDirty = true; + this._disabledTextureAdaptDirty = true; }, /** - * Get button is using scale9 renderer or not. + * Returns button is using scale9 renderer or not. * @returns {Boolean} */ - isScale9Enabled:function(){ + isScale9Enabled: function () { return this._scale9Enabled; }, /** - * ignoreContentAdaptWithSize - * @param {Boolean} ignore + * Sets whether ignore the widget size + * @param {Boolean} ignore true that widget will ignore it's size, use texture size, false otherwise. Default value is true. + * @override */ ignoreContentAdaptWithSize: function (ignore) { + if(this._unifySize){ + this._updateContentSize(); + return; + } if (!this._scale9Enabled || (this._scale9Enabled && !ignore)) { ccui.Widget.prototype.ignoreContentAdaptWithSize.call(this, ignore); this._prevIgnoreSize = ignore; } }, + /** + * Returns the renderer size. + * @returns {cc.Size} + */ + getVirtualRendererSize: function(){ + if (this._unifySize) + return this._getNormalSize(); + + if (!this._normalTextureLoaded && this._titleRenderer.getString().length > 0) { + return this._titleRenderer.getContentSize(); + } + return cc.size(this._normalTextureSize); + }, + /** * Load textures for button. - * @param {String} normal - * @param {String} selected - * @param {String} disabled + * @param {String} normal normal state of texture's filename. + * @param {String} selected selected state of texture's filename. + * @param {String} disabled disabled state of texture's filename. * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ loadTextures: function (normal, selected, disabled, texType) { @@ -195,151 +244,138 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ /** * Load normal state texture for button. - * @param {String} normal + * @param {String} normal normal state of texture's filename. * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ loadTextureNormal: function (normal, texType) { - if (!normal) { + if (!normal) return; - } - texType = texType||ccui.Widget.LOCAL_TEXTURE; + texType = texType || ccui.Widget.LOCAL_TEXTURE; this._normalFileName = normal; this._normalTexType = texType; - var buttonNormalRenderer = this._buttonNormalRenderer; - switch (this._normalTexType) { + + var self = this; + var normalRenderer = this._buttonNormalRenderer; + if(!normalRenderer._textureLoaded){ + normalRenderer.addEventListener("load", function(){ + self.loadTextureNormal(self._normalFileName, self._normalTexType); + }); + } + switch (this._normalTexType){ case ccui.Widget.LOCAL_TEXTURE: - buttonNormalRenderer.initWithFile(normal); + //SetTexture cannot load resource + normalRenderer.initWithFile(normal); break; case ccui.Widget.PLIST_TEXTURE: - buttonNormalRenderer.initWithSpriteFrameName(normal); + //SetTexture cannot load resource + normalRenderer.initWithSpriteFrameName(normal); break; default: break; } - var buttonRenderSize = buttonNormalRenderer.getContentSize(); - if(buttonNormalRenderer.textureLoaded()){ - this._normalTextureSize.width = buttonRenderSize.width; - this._normalTextureSize.height = buttonRenderSize.height; - }else{ - buttonNormalRenderer.addLoadedEventListener(function(){ - this._normalTextureSize = buttonNormalRenderer.getContentSize(); - if (buttonNormalRenderer.setCapInsets) { - buttonNormalRenderer.setCapInsets(this._capInsetsNormal); - } - this.normalTextureScaleChangedWithSize(); - },this); - this._normalTextureSize.width = this._customSize.width; - this._normalTextureSize.height = this._customSize.height; - } - if (this._scale9Enabled) { - buttonNormalRenderer.setCapInsets(this._capInsetsNormal); - } + this._normalTextureSize = this._buttonNormalRenderer.getContentSize(); + this._updateChildrenDisplayedRGBA(); + if (this._unifySize){ + if (this._scale9Enabled){ + normalRenderer.setCapInsets(this._capInsetsNormal); + this._updateContentSizeWithTextureSize(this._getNormalSize()); + } + }else + this._updateContentSizeWithTextureSize(this._normalTextureSize); - this.updateColorToRenderer(buttonNormalRenderer); - this.updateAnchorPoint(); - this.updateFlippedX(); - this.updateFlippedY(); - this.normalTextureScaleChangedWithSize(); this._normalTextureLoaded = true; + this._normalTextureAdaptDirty = true; + this._findLayout(); }, /** * Load selected state texture for button. - * @param {String} selected + * @param {String} selected selected state of texture's filename. * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ loadTexturePressed: function (selected, texType) { - if (!selected) { + if (!selected) return; - } texType = texType || ccui.Widget.LOCAL_TEXTURE; this._clickedFileName = selected; this._pressedTexType = texType; + + var self = this; var clickedRenderer = this._buttonClickedRenderer; + if(!clickedRenderer._textureLoaded){ + clickedRenderer.addEventListener("load", function(){ + self.loadTexturePressed(self._clickedFileName, self._pressedTexType); + }); + } + switch (this._pressedTexType) { case ccui.Widget.LOCAL_TEXTURE: + //SetTexture cannot load resource clickedRenderer.initWithFile(selected); break; case ccui.Widget.PLIST_TEXTURE: + //SetTexture cannot load resource clickedRenderer.initWithSpriteFrameName(selected); break; default: break; } - if(clickedRenderer.textureLoaded()){ - this._pressedTextureSize = clickedRenderer.getContentSize(); - }else{ - clickedRenderer.addLoadedEventListener(function(){ - this._pressedTextureSize = clickedRenderer.getContentSize(); - if (clickedRenderer.setCapInsets) { - clickedRenderer.setCapInsets(this._capInsetsNormal); - } - this.pressedTextureScaleChangedWithSize(); - },this); - this._pressedTextureSize.width = this._customSize.width; - this._pressedTextureSize.height = this._customSize.height; - } + if (this._scale9Enabled) + clickedRenderer.setCapInsets(this._capInsetsPressed); + + this._pressedTextureSize = this._buttonClickedRenderer.getContentSize(); + this._updateChildrenDisplayedRGBA(); - if (this._scale9Enabled) { - clickedRenderer.setCapInsets(this._capInsetsNormal); - } - this.updateColorToRenderer(clickedRenderer); - this.updateAnchorPoint(); - this.updateFlippedX(); - this.updateFlippedY(); - this.pressedTextureScaleChangedWithSize(); this._pressedTextureLoaded = true; + this._pressedTextureAdaptDirty = true; + this._findLayout(); }, /** * Load dark state texture for button. - * @param {String} disabled + * @param {String} disabled disabled state of texture's filename. * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ loadTextureDisabled: function (disabled, texType) { - if (!disabled) { + if (!disabled) return; - } + texType = texType || ccui.Widget.LOCAL_TEXTURE; this._disabledFileName = disabled; this._disabledTexType = texType; - var disableRenderer = this._buttonDisableRenderer; + + var self = this; + var disabledRenderer = this._buttonDisableRenderer; + if(!disabledRenderer._textureLoaded){ + disabledRenderer.addEventListener("load", function() { + self.loadTextureDisabled(self._disabledFileName, self._disabledTexType); + }); + } + switch (this._disabledTexType) { case ccui.Widget.LOCAL_TEXTURE: - disableRenderer.initWithFile(disabled); + //SetTexture cannot load resource + disabledRenderer.initWithFile(disabled); break; case ccui.Widget.PLIST_TEXTURE: - disableRenderer.initWithSpriteFrameName(disabled); + //SetTexture cannot load resource + disabledRenderer.initWithSpriteFrameName(disabled); break; default: break; } - if(disableRenderer.textureLoaded()){ - this._disabledTextureSize = disableRenderer.getContentSize(); - }else{ - disableRenderer.addLoadedEventListener(function(){ - this._disabledTextureSize = disableRenderer.getContentSize(); - if (disableRenderer.setCapInsets) { - disableRenderer.setCapInsets(this._capInsetsNormal); - } - this.disabledTextureScaleChangedWithSize(); - },this); - this._disabledTextureSize.width = this._customSize.width; - this._disabledTextureSize.height = this._customSize.height; - } + if (this._scale9Enabled) + disabledRenderer.setCapInsets(this._capInsetsDisabled); + + this._disabledTextureSize = this._buttonDisableRenderer.getContentSize(); + this._updateChildrenDisplayedRGBA(); - if (this._scale9Enabled) { - disableRenderer.setCapInsets(this._capInsetsNormal); - } - this.updateColorToRenderer(disableRenderer); - this.updateAnchorPoint(); - this.updateFlippedX(); - this.updateFlippedY(); - this.disabledTextureScaleChangedWithSize(); this._disabledTextureLoaded = true; + this._disabledTextureAdaptDirty = true; + this._findLayout(); }, /** @@ -357,19 +393,37 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ * @param {cc.Rect} capInsets */ setCapInsetsNormalRenderer: function (capInsets) { - this._capInsetsNormal = capInsets; - if (!this._scale9Enabled) { + if(!capInsets) return; + + var x = capInsets.x, y = capInsets.y; + var width = capInsets.width, height = capInsets.height; + if (this._normalTextureSize.width < width){ + x = 0; + width = 0; } - this._buttonNormalRenderer.setCapInsets(capInsets); + if (this._normalTextureSize.height < height){ + y = 0; + height = 0; + } + + var locInsets = this._capInsetsNormal; + locInsets.x = x; + locInsets.y = y; + locInsets.width = width; + locInsets.height = height; + + if (!this._scale9Enabled) + return; + this._buttonNormalRenderer.setCapInsets(locInsets); }, /** - * Get normal renderer cap insets . + * Returns normal renderer cap insets. * @returns {cc.Rect} */ - getCapInsetNormalRenderer:function(){ - return this._capInsetsNormal; + getCapInsetsNormalRenderer:function(){ + return cc.rect(this._capInsetsNormal); }, /** @@ -377,19 +431,36 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ * @param {cc.Rect} capInsets */ setCapInsetsPressedRenderer: function (capInsets) { - this._capInsetsPressed = capInsets; - if (!this._scale9Enabled) { + if(!capInsets || !this._scale9Enabled) return; + + var x = capInsets.x, y = capInsets.y; + var width = capInsets.width, height = capInsets.height; + + if (this._pressedTextureSize.width < width) { + x = 0; + width = 0; } - this._buttonClickedRenderer.setCapInsets(capInsets); + if (this._pressedTextureSize.height < height) { + y = 0; + height = 0; + } + + var locInsets = this._capInsetsPressed; + locInsets.x = x; + locInsets.y = y; + locInsets.width = width; + locInsets.height = height; + + this._buttonClickedRenderer.setCapInsets(locInsets); }, /** - * Get pressed renderer cap insets . + * Returns pressed renderer cap insets. * @returns {cc.Rect} */ - getCapInsetPressedRenderer:function(){ - return this._capInsetsPressed; + getCapInsetsPressedRenderer: function () { + return cc.rect(this._capInsetsPressed); }, /** @@ -397,172 +468,157 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ * @param {cc.Rect} capInsets */ setCapInsetsDisabledRenderer: function (capInsets) { - this._capInsetsDisabled = capInsets; - if (!this._scale9Enabled) { + if(!capInsets || !this._scale9Enabled) return; + + var x = capInsets.x, y = capInsets.y; + var width = capInsets.width, height = capInsets.height; + + if (this._disabledTextureSize.width < width) { + x = 0; + width = 0; + } + if (this._disabledTextureSize.height < height) { + y = 0; + height = 0; } - this._buttonDisableRenderer.setCapInsets(capInsets); + + var locInsets = this._capInsetsDisabled; + locInsets.x = x; + locInsets.y = y; + locInsets.width = width; + locInsets.height = height; + + this._buttonDisableRenderer.setCapInsets(locInsets); }, /** - * Get disable renderer cap insets . + * Returns disable renderer cap insets. * @returns {cc.Rect} */ - getCapInsetDisabledRenderer:function(){ - return this._capInsetsDisabled; + getCapInsetsDisabledRenderer: function () { + return cc.rect(this._capInsetsDisabled); }, - onPressStateChangedToNormal: function () { + _onPressStateChangedToNormal: function () { this._buttonNormalRenderer.setVisible(true); this._buttonClickedRenderer.setVisible(false); this._buttonDisableRenderer.setVisible(false); + if (this._scale9Enabled) + this._buttonNormalRenderer.setState( ccui.Scale9Sprite.state.NORMAL); if (this._pressedTextureLoaded) { - if (this.pressedActionEnabled) { + if (this.pressedActionEnabled){ this._buttonNormalRenderer.stopAllActions(); this._buttonClickedRenderer.stopAllActions(); - this._buttonDisableRenderer.stopAllActions(); - var zoomAction = cc.ScaleTo.create(0.05, 1.0); - var zoomAction1 = cc.ScaleTo.create(0.05, 1.0); - var zoomAction2 = cc.ScaleTo.create(0.05, 1.0); - this._buttonNormalRenderer.runAction(zoomAction); - this._buttonClickedRenderer.runAction(zoomAction1); - this._buttonDisableRenderer.runAction(zoomAction2); + //var zoomAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, this._normalTextureScaleXInSize, this._normalTextureScaleYInSize); + //fixme: the zoomAction will run in the next frame which will cause the _buttonNormalRenderer to a wrong scale + //this._buttonNormalRenderer.runAction(zoomAction); + this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize); + this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize); + + this._titleRenderer.stopAllActions(); + if (this._unifySize){ + var zoomTitleAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, 1, 1); + this._titleRenderer.runAction(zoomTitleAction); + }else{ + this._titleRenderer.setScaleX(1); + this._titleRenderer.setScaleY(1); + } } } else { this._buttonNormalRenderer.stopAllActions(); this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize); + + this._titleRenderer.stopAllActions(); + if (this._scale9Enabled) + this._buttonNormalRenderer.setColor(cc.color.WHITE); + + this._titleRenderer.setScaleX(1); + this._titleRenderer.setScaleY(1); } }, - onPressStateChangedToPressed: function () { + _onPressStateChangedToPressed: function () { + var locNormalRenderer = this._buttonNormalRenderer; + if (this._scale9Enabled) + locNormalRenderer.setState(ccui.Scale9Sprite.state.NORMAL); + if (this._pressedTextureLoaded) { - this._buttonNormalRenderer.setVisible(false); + locNormalRenderer.setVisible(false); this._buttonClickedRenderer.setVisible(true); this._buttonDisableRenderer.setVisible(false); if (this.pressedActionEnabled) { - this._buttonNormalRenderer.stopAllActions(); + locNormalRenderer.stopAllActions(); this._buttonClickedRenderer.stopAllActions(); - this._buttonDisableRenderer.stopAllActions(); - var zoomAction = cc.ScaleTo.create(0.05, 1.1); - var zoomAction1 = cc.ScaleTo.create(0.05, 1.1); - var zoomAction2 = cc.ScaleTo.create(0.05, 1.1); - this._buttonNormalRenderer.runAction(zoomAction); - this._buttonClickedRenderer.runAction(zoomAction1); - this._buttonDisableRenderer.runAction(zoomAction2); + var zoomAction = cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, this._pressedTextureScaleXInSize + this._zoomScale, + this._pressedTextureScaleYInSize + this._zoomScale); + this._buttonClickedRenderer.runAction(zoomAction); + locNormalRenderer.setScale(this._pressedTextureScaleXInSize + this._zoomScale, this._pressedTextureScaleYInSize + this._zoomScale); + + this._titleRenderer.stopAllActions(); + this._titleRenderer.runAction(cc.scaleTo(ccui.Button.ZOOM_ACTION_TIME_STEP, 1 + this._zoomScale, 1 + this._zoomScale)); } } else { - this._buttonNormalRenderer.setVisible(true); + locNormalRenderer.setVisible(true); this._buttonClickedRenderer.setVisible(true); this._buttonDisableRenderer.setVisible(false); - this._buttonNormalRenderer.stopAllActions(); - this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize); + locNormalRenderer.stopAllActions(); + locNormalRenderer.setScale(this._normalTextureScaleXInSize + this._zoomScale, this._normalTextureScaleYInSize + this._zoomScale); + + this._titleRenderer.stopAllActions(); + this._titleRenderer.setScaleX(1 + this._zoomScale); + this._titleRenderer.setScaleY(1 + this._zoomScale); } }, - onPressStateChangedToDisabled: function () { - this._buttonNormalRenderer.setVisible(false); + _onPressStateChangedToDisabled: function () { + //if disable resource is null + if (!this._disabledTextureLoaded){ + if (this._normalTextureLoaded && this._scale9Enabled) + this._buttonNormalRenderer.setState(ccui.Scale9Sprite.state.GRAY); + }else{ + this._buttonNormalRenderer.setVisible(false); + this._buttonDisableRenderer.setVisible(true); + } + this._buttonClickedRenderer.setVisible(false); - this._buttonDisableRenderer.setVisible(true); this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize); this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize); }, - updateFlippedX: function () { - this._titleRenderer.setFlippedX(this._flippedX); - if (this._scale9Enabled) { - if (this._flippedX) { - this._buttonNormalRenderer.setScaleX(-1); - this._buttonClickedRenderer.setScaleX(-1); - this._buttonDisableRenderer.setScaleX(-1); - } - else { - this._buttonNormalRenderer.setScaleX(1); - this._buttonClickedRenderer.setScaleX(1); - this._buttonDisableRenderer.setScaleX(1); - } - } else { - this._buttonNormalRenderer.setFlippedX(this._flippedX); - this._buttonClickedRenderer.setFlippedX(this._flippedX); - this._buttonDisableRenderer.setFlippedX(this._flippedX); - } - }, - - updateFlippedY: function () { - this._titleRenderer.setFlippedY(this._flippedY); - if (this._scale9Enabled) { - if (this._flippedX) { - this._buttonNormalRenderer.setScaleY(-1); - this._buttonClickedRenderer.setScaleX(-1); - this._buttonDisableRenderer.setScaleX(-1); - } - else { - this._buttonNormalRenderer.setScaleY(1); - this._buttonClickedRenderer.setScaleY(1); - this._buttonDisableRenderer.setScaleY(1); + _updateContentSize: function(){ + if (this._unifySize){ + if (this._scale9Enabled) + ccui.ProtectedNode.setContentSize(this._customSize); + else{ + var s = this._getNormalSize(); + ccui.ProtectedNode.setContentSize(s); } - }else{ - this._buttonNormalRenderer.setFlippedY(this._flippedY); - this._buttonClickedRenderer.setFlippedY(this._flippedY); - this._buttonDisableRenderer.setFlippedY(this._flippedY); + this._onSizeChanged(); + return; } - }, - /** - * override "setAnchorPoint" of widget. - * @param {cc.Point|Number} point The anchor point of UIButton or The anchor point.x of UIButton. - * @param {Number} [y] The anchor point.y of UIButton. - */ - setAnchorPoint: function (point, y) { - if(y === undefined){ - ccui.Widget.prototype.setAnchorPoint.call(this, point); - this._buttonNormalRenderer.setAnchorPoint(point); - this._buttonClickedRenderer.setAnchorPoint(point); - this._buttonDisableRenderer.setAnchorPoint(point); - } else { - ccui.Widget.prototype.setAnchorPoint.call(this, point, y); - this._buttonNormalRenderer.setAnchorPoint(point, y); - this._buttonClickedRenderer.setAnchorPoint(point, y); - this._buttonDisableRenderer.setAnchorPoint(point, y); - } - this._titleRenderer.setPosition(this._size.width * (0.5 - this._anchorPoint.x), this._size.height * (0.5 - this._anchorPoint.y)); + if (this._ignoreSize) + this.setContentSize(this.getVirtualRendererSize()); }, - _setAnchorX: function (value) { - ccui.Widget.prototype._setAnchorX.call(this, value); - this._buttonNormalRenderer._setAnchorX(value); - this._buttonClickedRenderer._setAnchorX(value); - this._buttonDisableRenderer._setAnchorX(value); - this._titleRenderer.setPositionX(this._size.width * (0.5 - this._anchorPoint.x)); - }, - _setAnchorY: function (value) { - ccui.Widget.prototype._setAnchorY.call(this, value); - this._buttonNormalRenderer._setAnchorY(value); - this._buttonClickedRenderer._setAnchorY(value); - this._buttonDisableRenderer._setAnchorY(value); + _updateTexturesRGBA: function(){ + this._buttonNormalRenderer.setColor(this.getColor()); + this._buttonClickedRenderer.setColor(this.getColor()); + this._buttonDisableRenderer.setColor(this.getColor()); - this._titleRenderer.setPositionY(this._size.height * (0.5 - this._anchorPoint.y)); - }, - - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.normalTextureScaleChangedWithSize(); - this.pressedTextureScaleChangedWithSize(); - this.disabledTextureScaleChangedWithSize(); + this._buttonNormalRenderer.setOpacity(this.getOpacity()); + this._buttonClickedRenderer.setOpacity(this.getOpacity()); + this._buttonDisableRenderer.setOpacity(this.getOpacity()); }, - /** - * override "getContentSize" method of widget. - * @returns {cc.Size} - */ - getContentSize: function () { - return this._normalTextureSize; + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._updateTitleLocation(); + this._normalTextureAdaptDirty = true; + this._pressedTextureAdaptDirty = true; + this._disabledTextureAdaptDirty = true; }, - _getWidth: function () { - return this._scale9Enabled ? this._size.width : this._normalTextureSize.width; - }, - _getHeight: function () { - return this._scale9Enabled ? this._size.height : this._normalTextureSize.height; - }, /** * Gets the Virtual Renderer of widget. @@ -578,92 +634,107 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ default: return null; } - } - else { + } else return this._buttonDisableRenderer; - } }, - normalTextureScaleChangedWithSize: function () { - if (this._ignoreSize) { - if (!this._scale9Enabled) { - this._buttonNormalRenderer.setScale(1.0); + _normalTextureScaleChangedWithSize: function () { + if(this._ignoreSize && !this._unifySize){ + if(!this._scale9Enabled){ + this._buttonNormalRenderer.setScale(1); this._normalTextureScaleXInSize = this._normalTextureScaleYInSize = 1; - this._size.width = this._normalTextureSize.width; - this._size.height = this._normalTextureSize.height; } - } - else { - if (this._scale9Enabled) { - this._buttonNormalRenderer.setPreferredSize(this._size); + }else{ + if (this._scale9Enabled){ + this._buttonNormalRenderer.setPreferredSize(this._contentSize); this._normalTextureScaleXInSize = this._normalTextureScaleYInSize = 1; - } - else { + this._buttonNormalRenderer.setScale(this._normalTextureScaleXInSize, this._normalTextureScaleYInSize); + }else{ var textureSize = this._normalTextureSize; - if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._buttonNormalRenderer.setScale(1.0); + if (textureSize.width <= 0 || textureSize.height <= 0) + { + this._buttonNormalRenderer.setScale(1); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; + var scaleX = this._contentSize.width / textureSize.width; + var scaleY = this._contentSize.height / textureSize.height; this._buttonNormalRenderer.setScaleX(scaleX); this._buttonNormalRenderer.setScaleY(scaleY); this._normalTextureScaleXInSize = scaleX; this._normalTextureScaleYInSize = scaleY; } } + this._buttonNormalRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2); }, - pressedTextureScaleChangedWithSize: function () { - if (this._ignoreSize) { + _pressedTextureScaleChangedWithSize: function () { + if (this._ignoreSize && !this._unifySize) { if (!this._scale9Enabled) { - this._buttonClickedRenderer.setScale(1.0); + this._buttonClickedRenderer.setScale(1); this._pressedTextureScaleXInSize = this._pressedTextureScaleYInSize = 1; } - } - else { + } else { if (this._scale9Enabled) { - this._buttonClickedRenderer.setPreferredSize(this._size); + this._buttonClickedRenderer.setPreferredSize(this._contentSize); this._pressedTextureScaleXInSize = this._pressedTextureScaleYInSize = 1; - } - else { + this._buttonClickedRenderer.setScale(this._pressedTextureScaleXInSize, this._pressedTextureScaleYInSize); + } else { var textureSize = this._pressedTextureSize; - if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._buttonClickedRenderer.setScale(1.0); + if (textureSize.width <= 0 || textureSize.height <= 0) { + this._buttonClickedRenderer.setScale(1); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; + var scaleX = this._contentSize.width / textureSize.width; + var scaleY = this._contentSize.height / textureSize.height; this._buttonClickedRenderer.setScaleX(scaleX); this._buttonClickedRenderer.setScaleY(scaleY); this._pressedTextureScaleXInSize = scaleX; this._pressedTextureScaleYInSize = scaleY; } } + this._buttonClickedRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2); }, - disabledTextureScaleChangedWithSize: function () { - if (this._ignoreSize) { - if (!this._scale9Enabled) { - this._buttonDisableRenderer.setScale(1.0); - } - } - else { - if (this._scale9Enabled) { - this._buttonDisableRenderer.setPreferredSize(this._size); - } - else { + _disabledTextureScaleChangedWithSize: function () { + if(this._ignoreSize && !this._unifySize){ + if (this._scale9Enabled) + this._buttonDisableRenderer.setScale(1); + }else { + if (this._scale9Enabled){ + this._buttonDisableRenderer.setScale(1); + this._buttonDisableRenderer.setPreferredSize(this._contentSize); + }else{ var textureSize = this._disabledTextureSize; - if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._buttonDisableRenderer.setScale(1.0); + if (textureSize.width <= 0 || textureSize.height <= 0) { + this._buttonDisableRenderer.setScale(1); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; + var scaleX = this._contentSize.width / textureSize.width; + var scaleY = this._contentSize.height / textureSize.height; this._buttonDisableRenderer.setScaleX(scaleX); this._buttonDisableRenderer.setScaleY(scaleY); } } + this._buttonDisableRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2); + }, + + _adaptRenderers: function(){ + if (this._normalTextureAdaptDirty) { + this._normalTextureScaleChangedWithSize(); + this._normalTextureAdaptDirty = false; + } + if (this._pressedTextureAdaptDirty) { + this._pressedTextureScaleChangedWithSize(); + this._pressedTextureAdaptDirty = false; + } + if (this._disabledTextureAdaptDirty) { + this._disabledTextureScaleChangedWithSize(); + this._disabledTextureAdaptDirty = false; + } + }, + + _updateTitleLocation: function(){ + this._titleRenderer.setPosition(this._contentSize.width * 0.5, this._contentSize.height * 0.5); }, /** @@ -675,15 +746,23 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ }, /** - * set title text + * Sets title text to ccui.Button * @param {String} text */ setTitleText: function (text) { + if(text === this.getTitleText()) + return; this._titleRenderer.setString(text); + if (this._ignoreSize){ + var s = this.getVirtualRendererSize(); + this.setContentSize(s); + }else{ + this._titleRenderer._renderCmd._updateTTF(); + } }, /** - * get title text + * Returns title text of ccui.Button * @returns {String} text */ getTitleText: function () { @@ -691,88 +770,113 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ }, /** - * set title color + * Sets title color to ccui.Button. * @param {cc.Color} color */ setTitleColor: function (color) { - this._titleColor.r = color.r; - this._titleColor.g = color.g; - this._titleColor.b = color.b; - this._titleRenderer.setColor(color); + this._titleRenderer.setFontFillColor(color); }, /** - * get title color + * Returns title color of ccui.Button * @returns {cc.Color} */ getTitleColor: function () { - return this._titleRenderer.getColor(); + return this._titleRenderer._getFillStyle(); }, /** - * set title fontSize + * Sets title fontSize to ccui.Button * @param {cc.Size} size */ setTitleFontSize: function (size) { this._titleRenderer.setFontSize(size); + this._fontSize = size; }, /** - * get title fontSize - * @returns {cc.Size} + * Returns title fontSize of ccui.Button. + * @returns {Number} */ getTitleFontSize: function () { return this._titleRenderer.getFontSize(); }, /** - * set title fontName + * When user pressed the button, the button will zoom to a scale. + * The final scale of the button equals (button original scale + _zoomScale) + * @since v3.2 + * @param scale + */ + setZoomScale: function(scale){ + this._zoomScale = scale; + }, + + /** + * Returns a zoom scale + * @since v3.2 + * @returns {number} + */ + getZoomScale: function(){ + return this._zoomScale; + }, + + /** + * Returns the normalize of texture size + * @since v3.3 + * @returns {cc.Size} + */ + getNormalTextureSize: function(){ + return this._normalTextureSize; + }, + + /** + * Sets title fontName to ccui.Button. * @param {String} fontName */ setTitleFontName: function (fontName) { this._titleRenderer.setFontName(fontName); + this._fontName = fontName; + }, + + /** + * Get the title renderer. + * title ttf object. + * @returns {cc.LabelTTF} + */ + getTitleRenderer: function(){ + return this._titleRenderer; }, /** - * get title fontName + * Gets title fontName of ccui.Button. * @returns {String} */ getTitleFontName: function () { return this._titleRenderer.getFontName(); }, - _setTitleFont: function (font) { - this._titleRenderer.font = font; - }, - _getTitleFont: function () { - return this._titleRenderer.font; - }, - - updateTextureColor: function () { - this.updateColorToRenderer(this._buttonNormalRenderer); - this.updateColorToRenderer(this._buttonClickedRenderer); - this.updateColorToRenderer(this._buttonDisableRenderer); + _setTitleFont: function (font) { + this._titleRenderer.font = font; }, - - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._buttonNormalRenderer); - this.updateOpacityToRenderer(this._buttonClickedRenderer); - this.updateOpacityToRenderer(this._buttonDisableRenderer); + _getTitleFont: function () { + return this._titleRenderer.font; }, /** * Returns the "class name" of widget. + * @override * @returns {string} */ getDescription: function () { return "Button"; }, - createCloneInstance:function(){ - return ccui.Button.create(); + _createCloneInstance: function () { + return new ccui.Button(); }, - copySpecialProperties:function(uiButton){ + _copySpecialProperties: function (uiButton) { this._prevIgnoreSize = uiButton._prevIgnoreSize; this.setScale9Enabled(uiButton._scale9Enabled); this.loadTextureNormal(uiButton._normalFileName, uiButton._normalTexType); @@ -786,11 +890,30 @@ ccui.Button = ccui.Widget.extend(/** @lends ccui.Button# */{ this.setTitleFontSize(uiButton.getTitleFontSize()); this.setTitleColor(uiButton.getTitleColor()); this.setPressedActionEnabled(uiButton.pressedActionEnabled); - } + this.setZoomScale(uiButton._zoomScale); + }, + + setColor: function(color){ + cc.ProtectedNode.prototype.setColor.call(this, color); + this._updateTexturesRGBA(); + }, + + _getNormalSize: function(){ + var titleSize; + if (this._titleRenderer !== null) + titleSize = this._titleRenderer.getContentSize(); + var imageSize; + if (this._buttonNormalRenderer !== null) + imageSize = this._buttonNormalRenderer.getContentSize(); + var width = titleSize.width > imageSize.width ? titleSize.width : imageSize.width; + var height = titleSize.height > imageSize.height ? titleSize.height : imageSize.height; + + return cc.size(width,height); + } }); -window._p = ccui.Button.prototype; +var _p = ccui.Button.prototype; // Extended properties /** @expose */ @@ -809,26 +932,56 @@ cc.defineGetterSetter(_p, "titleFontName", _p.getTitleFontName, _p.setTitleFontN _p.titleColor; cc.defineGetterSetter(_p, "titleColor", _p.getTitleColor, _p.setTitleColor); -delete window._p; +_p = null; /** * allocates and initializes a UIButton. - * @constructs + * @deprecated since v3.0, please use new ccui.Button() instead. + * @param {string} [normalImage] normal state texture name + * @param {string} [selectedImage] selected state texture name + * @param {string} [disableImage] disabled state texture name + * @param {string} [texType] * @return {ccui.Button} - * @example - * // example - * var uiButton = ccui.Button.create(); */ -ccui.Button.create = function () { - var uiButton = new ccui.Button(); - if (uiButton && uiButton.init()) { - return uiButton; - } - return null; +ccui.Button.create = function (normalImage, selectedImage, disableImage, texType) { + return new ccui.Button(normalImage, selectedImage, disableImage, texType); }; // Constants +/** + * The normal renderer's zOrder value of ccui.Button. + * @constant + * @type {number} + */ ccui.Button.NORMAL_RENDERER_ZORDER = -2; +/** + * The pressed renderer's zOrder value ccui.Button. + * @constant + * @type {number} + */ ccui.Button.PRESSED_RENDERER_ZORDER = -2; +/** + * The disabled renderer's zOrder value of ccui.Button. + * @constant + * @type {number} + */ ccui.Button.DISABLED_RENDERER_ZORDER = -2; +/** + * The title renderer's zOrder value of ccui.Button. + * @constant + * @type {number} + */ ccui.Button.TITLE_RENDERER_ZORDER = -1; + +/** + * the zoom action time step of ccui.Button + * @constant + * @type {number} + */ +ccui.Button.ZOOM_ACTION_TIME_STEP = 0.05; + +/** + * @ignore + */ +ccui.Button.SYSTEM = 0; +ccui.Button.TTF = 1; diff --git a/extensions/ccui/uiwidgets/UICheckBox.js b/extensions/ccui/uiwidgets/UICheckBox.js index 859adcf853..dc4b3ed922 100644 --- a/extensions/ccui/uiwidgets/UICheckBox.js +++ b/extensions/ccui/uiwidgets/UICheckBox.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccui.CheckBox + * The CheckBox control of Cocos UI. * @class * @extends ccui.Widget * @@ -35,65 +36,112 @@ ccui.CheckBox = ccui.Widget.extend(/** @lends ccui.CheckBox# */{ _frontCrossRenderer: null, _backGroundBoxDisabledRenderer: null, _frontCrossDisabledRenderer: null, + _isSelected: true, + _checkBoxEventListener: null, - _checkBoxEventSelector: null, - _backGroundTexType: null, - _backGroundSelectedTexType: null, - _frontCrossTexType: null, - _backGroundDisabledTexType: null, - _frontCrossDisabledTexType: null, + _checkBoxEventSelector:null, + + _backGroundTexType: ccui.Widget.LOCAL_TEXTURE, + _backGroundSelectedTexType: ccui.Widget.LOCAL_TEXTURE, + _frontCrossTexType: ccui.Widget.LOCAL_TEXTURE, + _backGroundDisabledTexType: ccui.Widget.LOCAL_TEXTURE, + _frontCrossDisabledTexType: ccui.Widget.LOCAL_TEXTURE, + _backGroundFileName: "", _backGroundSelectedFileName: "", _frontCrossFileName: "", _backGroundDisabledFileName: "", _frontCrossDisabledFileName: "", - _className:"CheckBox", - ctor: function () { + _className: "CheckBox", + + _zoomScale: 0.1, + _backgroundTextureScaleX: 0.1, + _backgroundTextureScaleY: 0.1, + + _backGroundBoxRendererAdaptDirty:true, + _backGroundSelectedBoxRendererAdaptDirty:true, + _frontCrossRendererAdaptDirty: true, + _backGroundBoxDisabledRendererAdaptDirty: true, + _frontCrossDisabledRendererAdaptDirty: true, + + /** + * allocates and initializes a UICheckBox. + * Constructor of ccui.CheckBox, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {String} backGround + * @param {String} backGroundSelected + * @param {String} cross + * @param {String} backGroundDisabled + * @param {String} frontCrossDisabled + * @param {Number} [texType=ccui.Widget.LOCAL_TEXTURE] + * @example + * // example + * var uiCheckBox = new ccui.CheckBox(); + */ + ctor: function (backGround, backGroundSelected,cross,backGroundDisabled,frontCrossDisabled,texType) { ccui.Widget.prototype.ctor.call(this); - this._backGroundBoxRenderer = null; - this._backGroundSelectedBoxRenderer = null; - this._frontCrossRenderer = null; - this._backGroundBoxDisabledRenderer = null; - this._frontCrossDisabledRenderer = null; - this._isSelected = true; - this._checkBoxEventListener = null; - this._checkBoxEventSelector = null; - this._backGroundTexType = ccui.Widget.LOCAL_TEXTURE; - this._backGroundSelectedTexType = ccui.Widget.LOCAL_TEXTURE; - this._frontCrossTexType = ccui.Widget.LOCAL_TEXTURE; - this._backGroundDisabledTexType = ccui.Widget.LOCAL_TEXTURE; - this._frontCrossDisabledTexType = ccui.Widget.LOCAL_TEXTURE; - this._backGroundFileName = ""; - this._backGroundSelectedFileName = ""; - this._frontCrossFileName = ""; - this._backGroundDisabledFileName = ""; - this._frontCrossDisabledFileName = ""; - }, - init: function () { + this.setTouchEnabled(true); + var strNum = 0; + for(var i=0; i + * Constructor of ccui.LoadingBar, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {string} textureName + * @param {Number} percentage + * @example + * // example + * var uiLoadingBar = new ccui.LoadingBar; + */ + ctor: function (textureName, percentage) { + this._direction = ccui.LoadingBar.TYPE_LEFT; this._barRendererTextureSize = cc.size(0, 0); - this._scale9Enabled = false; - this._prevIgnoreSize = true; this._capInsets = cc.rect(0, 0, 0, 0); - this._textureFile = ""; + ccui.Widget.prototype.ctor.call(this); + + if(textureName !== undefined) + this.loadTexture(textureName); + if(percentage !== undefined) + this.setPercent(percentage); }, - initRenderer: function () { - this._barRenderer = cc.Sprite.create(); - cc.Node.prototype.addChild.call(this, this._barRenderer, ccui.LoadingBar.RENDERER_ZORDER, -1); + _initRenderer: function () { + //todo use Scale9Sprite + this._barRenderer = new cc.Sprite(); + this.addProtectedChild(this._barRenderer, ccui.LoadingBar.RENDERER_ZORDER, -1); this._barRenderer.setAnchorPoint(0.0, 0.5); }, /** - * Changes the progress direction of loadingbar. + * Changes the progress direction of LoadingBar.
    * LoadingBarTypeLeft means progress left to right, LoadingBarTypeRight otherwise. * @param {ccui.LoadingBar.TYPE_LEFT | ccui.LoadingBar.TYPE_RIGHT} dir */ setDirection: function (dir) { - if (this._barType == dir) { + if (this._direction === dir) return; - } - this._barType = dir; - - switch (this._barType) { + this._direction = dir; + switch (this._direction) { case ccui.LoadingBar.TYPE_LEFT: - this._barRenderer.setAnchorPoint(0.0, 0.5); - this._barRenderer.setPosition(-this._totalLength * 0.5, 0.0); - if (!this._scale9Enabled) { + this._barRenderer.setAnchorPoint(0, 0.5); + this._barRenderer.setPosition(0, this._contentSize.height*0.5); + if (!this._scale9Enabled) this._barRenderer.setFlippedX(false); - } break; case ccui.LoadingBar.TYPE_RIGHT: - this._barRenderer.setAnchorPoint(1.0, 0.5); - this._barRenderer.setPosition(this._totalLength * 0.5, 0.0); - if (!this._scale9Enabled) { + this._barRenderer.setAnchorPoint(1, 0.5); + this._barRenderer.setPosition(this._totalLength,this._contentSize.height*0.5); + if (!this._scale9Enabled) this._barRenderer.setFlippedX(true); - } break; } }, /** - * Gets the progress direction of loadingbar. + * Returns the progress direction of LoadingBar.
    * LoadingBarTypeLeft means progress left to right, LoadingBarTypeRight otherwise. * @returns {ccui.LoadingBar.TYPE_LEFT | ccui.LoadingBar.TYPE_RIGHT} */ getDirection: function () { - return this._barType; + return this._direction; }, /** - * Load texture for loadingbar. + * Loads texture for LoadingBar. * @param {String} texture * @param {ccui.Widget.LOCAL_TEXTURE|ccui.Widget.PLIST_TEXTURE} texType */ loadTexture: function (texture, texType) { - if (!texture) { + if (!texture) return; - } texType = texType || ccui.Widget.LOCAL_TEXTURE; this._renderBarTexType = texType; this._textureFile = texture; var barRenderer = this._barRenderer; + + var self = this; + if(!barRenderer._textureLoaded){ + barRenderer.addEventListener("load", function(){ + self.loadTexture(self._textureFile, self._renderBarTexType); + self._setPercent(self._percent); + }); + } + switch (this._renderBarTexType) { case ccui.Widget.LOCAL_TEXTURE: - if(this._scale9Enabled) - barRenderer.initWithFile(texture); - else - barRenderer.init(texture); + barRenderer.initWithFile(texture); break; case ccui.Widget.PLIST_TEXTURE: barRenderer.initWithSpriteFrameName(texture); @@ -127,156 +139,163 @@ ccui.LoadingBar = ccui.Widget.extend(/** @lends ccui.LoadingBar# */{ default: break; } - if (this._scale9Enabled){ - barRenderer.setCapInsets(this._capInsets); - } - this.updateColorToRenderer(barRenderer); - - var textLoaded = barRenderer.textureLoaded(); - this._isTextureLoaded = textLoaded; - if (!textLoaded) { - this._barRendererTextureSize.width = this._customSize.width; - this._barRendererTextureSize.height = this._customSize.height; - barRenderer.addLoadedEventListener(function () { - this._isTextureLoaded = true; - if (barRenderer.setCapInsets) { - barRenderer.setCapInsets(this._capInsets); - } - var locSize = barRenderer.getContentSize(); - this._barRendererTextureSize.width = locSize.width; - this._barRendererTextureSize.height = locSize.height; - this.barRendererScaleChangedWithSize(); - this.setPercent(this._percent); - }, this); - } else { - var locBarSize = barRenderer.getContentSize(); - this._barRendererTextureSize.width = locBarSize.width; - this._barRendererTextureSize.height = locBarSize.height; - } - switch (this._barType) { + var bz = barRenderer.getContentSize(); + this._barRendererTextureSize.width = bz.width; + this._barRendererTextureSize.height = bz.height; + + switch (this._direction) { case ccui.LoadingBar.TYPE_LEFT: - barRenderer.setAnchorPoint(0.0, 0.5); - if (!this._scale9Enabled) { + barRenderer.setAnchorPoint(0,0.5); + if (!this._scale9Enabled) barRenderer.setFlippedX(false); - } break; case ccui.LoadingBar.TYPE_RIGHT: - barRenderer.setAnchorPoint(1.0, 0.5); - if (!this._scale9Enabled) { + barRenderer.setAnchorPoint(1,0.5); + if (!this._scale9Enabled) barRenderer.setFlippedX(true); - } break; } - this.barRendererScaleChangedWithSize(); + if (this._scale9Enabled) + barRenderer.setCapInsets(this._capInsets); + + this._updateChildrenDisplayedRGBA(); + this._barRendererScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._barRendererTextureSize); + this._barRendererAdaptDirty = true; + this._findLayout(); }, /** - * Sets if loadingbar is using scale9 renderer. + * Sets if LoadingBar is using scale9 renderer. * @param {Boolean} enabled */ setScale9Enabled: function (enabled) { - if (this._scale9Enabled == enabled) { + //todo use setScale9Enabled + if (this._scale9Enabled === enabled) return; - } this._scale9Enabled = enabled; - cc.Node.prototype.removeChild.call(this, this._barRenderer, true); - this._barRenderer = null; - if (this._scale9Enabled) { - this._barRenderer = cc.Scale9Sprite.create(); - } - else { - this._barRenderer = cc.Sprite.create(); - } + this.removeProtectedChild(this._barRenderer); + + this._barRenderer = this._scale9Enabled ? new ccui.Scale9Sprite() : new cc.Sprite(); + this.loadTexture(this._textureFile, this._renderBarTexType); - cc.Node.prototype.addChild.call(this, this._barRenderer, ccui.LoadingBar.RENDERER_ZORDER, -1); + this.addProtectedChild(this._barRenderer, ccui.LoadingBar.RENDERER_ZORDER, -1); if (this._scale9Enabled) { var ignoreBefore = this._ignoreSize; this.ignoreContentAdaptWithSize(false); this._prevIgnoreSize = ignoreBefore; - } - else { + } else this.ignoreContentAdaptWithSize(this._prevIgnoreSize); - } this.setCapInsets(this._capInsets); this.setPercent(this._percent); + this._barRendererAdaptDirty = true; }, /** - * Get loadingBar is using scale9 renderer or not.. + * Returns LoadingBar is using scale9 renderer or not.. * @returns {Boolean} */ - isScale9Enabled:function(){ + isScale9Enabled: function () { return this._scale9Enabled; }, /** - * Sets capinsets for loadingbar, if loadingbar is using scale9 renderer. + * Sets capinsets for LoadingBar, if LoadingBar is using scale9 renderer. * @param {cc.Rect} capInsets */ setCapInsets: function (capInsets) { - this._capInsets = capInsets; - if (!this._scale9Enabled) { + if(!capInsets) return; - } - this._barRenderer.setCapInsets(capInsets); + var locInsets = this._capInsets; + locInsets.x = capInsets.x; + locInsets.y = capInsets.y; + locInsets.width = capInsets.width; + locInsets.height = capInsets.height; + + if (this._scale9Enabled) + this._barRenderer.setCapInsets(capInsets); }, /** - * Get cap insets for loadingBar. + * Returns cap insets for loadingBar. * @returns {cc.Rect} */ - getCapInsets:function(){ - return this._capInsets; + getCapInsets: function () { + return cc.rect(this._capInsets); }, /** - * The current progress of loadingbar - * @param {number} percent + * The current progress of loadingBar + * @param {number} percent percent value from 1 to 100. */ setPercent: function (percent) { - if (percent < 0 || percent > 100) { - return; - } - if (this._totalLength <= 0) { + if(percent > 100) + percent = 100; + if(percent < 0) + percent = 0; + if (percent === this._percent) return; - } this._percent = percent; - if(!this._isTextureLoaded){ + this._setPercent(percent); + }, + + _setPercent: function(percent){ + if (this._totalLength <= 0) return; - } var res = this._percent / 100.0; - var x = 0, y = 0; - if(this._renderBarTexType==ccui.Widget.PLIST_TEXTURE){ - var barNode = this._barRenderer; - if (barNode) { - var to = barNode.getTextureRect()._origin; - x = to.x; - y = to.y; - } - } if (this._scale9Enabled) - this.setScale9Scale(); - else - this._barRenderer.setTextureRect(cc.rect(x, y, this._barRendererTextureSize.width * res, this._barRendererTextureSize.height)); + this._setScale9Scale(); + else { + var spriteRenderer = this._barRenderer; + var rect = spriteRenderer.getTextureRect(); + rect.width = this._barRendererTextureSize.width * res; + this._barRenderer.setTextureRect( + cc.rect( + rect.x, + rect.y, + this._barRendererTextureSize.width * res, + this._barRendererTextureSize.height + ) + ); + } }, /** - * Gets the progress direction of loadingbar. - * @returns {number} + * Sets the contentSize of ccui.LoadingBar + * @override + * @param {Number|cc.Size} contentSize + * @param {Number} [height] + */ + setContentSize: function(contentSize, height){ + ccui.Widget.prototype.setContentSize.call(this, contentSize, height); + this._totalLength = (height === undefined) ? contentSize.width : contentSize; + }, + + /** + * Returns the progress direction of LoadingBar. + * @returns {number} percent value from 1 to 100. */ getPercent: function () { return this._percent; }, - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.barRendererScaleChangedWithSize(); + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._barRendererAdaptDirty = true; + }, + + _adaptRenderers: function(){ + if (this._barRendererAdaptDirty){ + this._barRendererScaleChangedWithSize(); + this._barRendererAdaptDirty = false; + } }, /** - * override "ignoreContentAdaptWithSize" method of widget. + * Ignore the LoadingBar's custom size, if ignore is true that LoadingBar will ignore it's custom size, use renderer's content size, false otherwise. + * @override * @param {Boolean}ignore */ ignoreContentAdaptWithSize: function (ignore) { @@ -287,76 +306,64 @@ ccui.LoadingBar = ccui.Widget.extend(/** @lends ccui.LoadingBar# */{ }, /** - * override "getContentSize" method of widget. - * @returns {cc.Size} + * Returns the texture size of renderer. + * @returns {cc.Size|*} */ - getContentSize: function () { - return this._barRendererTextureSize; + getVirtualRendererSize:function(){ + return cc.size(this._barRendererTextureSize); }, - _getWidth: function () { - return this._barRendererTextureSize.width; - }, - _getHeight: function () { - return this._barRendererTextureSize.height; - }, /** - * override "getContentSize" method of widget. + * Returns the renderer of ccui.LoadingBar + * @override * @returns {cc.Node} */ getVirtualRenderer: function () { return this._barRenderer; }, - barRendererScaleChangedWithSize: function () { - if (this._ignoreSize) { + _barRendererScaleChangedWithSize: function () { + var locBarRender = this._barRenderer, locContentSize = this._contentSize; + if(this._unifySize){ + this._totalLength = this._contentSize.width; + this.setPercent(this._percent); + }else if (this._ignoreSize) { if (!this._scale9Enabled) { this._totalLength = this._barRendererTextureSize.width; - this._barRenderer.setScale(1.0); - this._size.width = this._barRendererTextureSize.width; + locBarRender.setScale(1.0); } - } - else { - this._totalLength = this._size.width; - if (this._scale9Enabled) { - this.setScale9Scale(); - } - else { - + } else { + this._totalLength = locContentSize.width; + if (this._scale9Enabled){ + this._setScale9Scale(); + locBarRender.setScale(1.0); + } else { var textureSize = this._barRendererTextureSize; if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._barRenderer.setScale(1.0); + locBarRender.setScale(1.0); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; - this._barRenderer.setScaleX(scaleX); - this._barRenderer.setScaleY(scaleY); + var scaleX = locContentSize.width / textureSize.width; + var scaleY = locContentSize.height / textureSize.height; + locBarRender.setScaleX(scaleX); + locBarRender.setScaleY(scaleY); } } - switch (this._barType) { + switch (this._direction) { case ccui.LoadingBar.TYPE_LEFT: - this._barRenderer.setPosition(-this._totalLength * 0.5, 0.0); + locBarRender.setPosition(0, locContentSize.height * 0.5); break; case ccui.LoadingBar.TYPE_RIGHT: - this._barRenderer.setPosition(this._totalLength * 0.5, 0.0); + locBarRender.setPosition(this._totalLength, locContentSize.height * 0.5); break; default: break; } }, - setScale9Scale: function () { + _setScale9Scale: function () { var width = (this._percent) / 100 * this._totalLength; - this._barRenderer.setPreferredSize(cc.size(width, this._size.height)); - }, - - updateTextureColor: function () { - this.updateColorToRenderer(this._barRenderer); - }, - - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._barRenderer); + this._barRenderer.setPreferredSize(cc.size(width, this._contentSize.height)); }, /** @@ -367,21 +374,23 @@ ccui.LoadingBar = ccui.Widget.extend(/** @lends ccui.LoadingBar# */{ return "LoadingBar"; }, - createCloneInstance: function () { - return ccui.LoadingBar.create(); + _createCloneInstance: function () { + return new ccui.LoadingBar(); }, - copySpecialProperties: function (loadingBar) { - this._prevIgnoreSize = loadingBar._prevIgnoreSize; - this.setScale9Enabled(loadingBar._scale9Enabled); - this.loadTexture(loadingBar._textureFile, loadingBar._renderBarTexType); - this.setCapInsets(loadingBar._capInsets); - this.setPercent(loadingBar._percent); - this.setDirection(loadingBar._barType); + _copySpecialProperties: function (loadingBar) { + if(loadingBar instanceof ccui.LoadingBar){ + this._prevIgnoreSize = loadingBar._prevIgnoreSize; + this.setScale9Enabled(loadingBar._scale9Enabled); + this.loadTexture(loadingBar._textureFile, loadingBar._renderBarTexType); + this.setCapInsets(loadingBar._capInsets); + this.setPercent(loadingBar._percent); + this.setDirection(loadingBar._direction); + } } }); -window._p = ccui.LoadingBar.prototype; +var _p = ccui.LoadingBar.prototype; // Extended properties /** @expose */ @@ -391,27 +400,38 @@ cc.defineGetterSetter(_p, "direction", _p.getDirection, _p.setDirection); _p.percent; cc.defineGetterSetter(_p, "percent", _p.getPercent, _p.setPercent); -delete window._p; +_p = null; /** - * allocates and initializes a UILoadingBar. - * @constructs + * Allocates and initializes a UILoadingBar. + * @deprecated since v3.0, please use new ccui.LoadingBar() instead. + * @param {string} textureName + * @param {Number} percentage * @return {ccui.LoadingBar} - * @example - * // example - * var uiLoadingBar = ccui.LoadingBar.create(); */ -ccui.LoadingBar.create = function () { - var uiLoadingBar = new ccui.LoadingBar(); - if (uiLoadingBar && uiLoadingBar.init()) { - return uiLoadingBar; - } - return null; +ccui.LoadingBar.create = function (textureName, percentage) { + return new ccui.LoadingBar(textureName, percentage); }; // Constants //loadingBar Type + +/** + * The left direction of ccui.LoadingBar. + * @constant + * @type {number} + */ ccui.LoadingBar.TYPE_LEFT = 0; +/** + * The right direction of ccui.LoadingBar. + * @constant + * @type {number} + */ ccui.LoadingBar.TYPE_RIGHT = 1; +/** + * The zOrder value of ccui.LoadingBar's renderer. + * @constant + * @type {number} + */ ccui.LoadingBar.RENDERER_ZORDER = -1; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/UIRichText.js b/extensions/ccui/uiwidgets/UIRichText.js index a3b15e9df5..a92b642063 100644 --- a/extensions/ccui/uiwidgets/UIRichText.js +++ b/extensions/ccui/uiwidgets/UIRichText.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,53 +24,117 @@ ****************************************************************************/ /** - * Base class for ccui.RichElement + * ccui.RichElement is the base class of RichElementText, RichElementImage etc. It has type, tag, color and opacity attributes. * @class * @extends ccui.Class */ ccui.RichElement = ccui.Class.extend(/** @lends ccui.RichElement# */{ - type: 0, - tag: 0, - color: null, + _type: 0, + _tag: 0, + _color: null, + _opacity:0, + /** + * Constructor of ccui.RichElement + */ ctor: function () { - this.tag = 0; - this.color = cc.color(255, 255, 255, 255); + this._type = 0; + this._tag = 0; + this._color = cc.color(255, 255, 255, 255); }, + + /** + * Initializes a richElement. + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + */ init: function (tag, color, opacity) { - this.tag = tag; - this.color.r = color.r; - this.color.g = color.g; - this.color.b = color.b; - this.color.a = opacity; + this._tag = tag; + this._color.r = color.r; + this._color.g = color.g; + this._color.b = color.b; + this._opacity = opacity; + if(opacity === undefined) + this._color.a = color.a; + else + this._color.a = opacity; } }); /** - * Base class for ccui.RichElementText + * The text element for RichText, it has text, fontName, fontSize attributes. * @class * @extends ccui.RichElement */ ccui.RichElementText = ccui.RichElement.extend(/** @lends ccui.RichElementText# */{ - text: "", - fontName: "", - fontSize: 0, - ctor: function () { + _text: "", + _fontName: "", + _fontSize: 0, + /** @type cc.FontDefinition */ + _fontDefinition: null, + /** + * Usage Example using FontDefinition: + * + * var rtEl = new ccui.RichElementText("tag", new cc.FontDefinition({ + * fillStyle: cc.color.BLACK, + * fontName: "Arial", + * fontSize: 12, + * fontWeight: "bold", + * fontStyle: "normal", + * lineHeight: 14 + * }), 255, "Some Text"); + * + * Constructor of ccui.RichElementText + * @param {Number} tag + * @param {cc.Color|cc.FontDefinition} colorOrFontDef + * @param {Number} opacity + * @param {String} text + * @param {String} fontName + * @param {Number} fontSize + */ + ctor: function (tag, colorOrFontDef, opacity, text, fontName, fontSize) { ccui.RichElement.prototype.ctor.call(this); - this.type = ccui.RichElement.TYPE_TEXT; - this.text = ""; - this.fontName = ""; - this.fontSize = 0; + this._type = ccui.RichElement.TEXT; + this._text = ""; + this._fontName = ""; + this._fontSize = 0; + + if( colorOrFontDef && colorOrFontDef instanceof cc.FontDefinition) + this.initWithStringAndTextDefinition(tag, text, colorOrFontDef, opacity); + else + fontSize && this.init(tag, colorOrFontDef, opacity, text, fontName, fontSize); }, + + /** + * Initializes a ccui.RichElementText. + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + * @param {String} text + * @param {String} fontName + * @param {Number} fontSize + * @override + */ init: function (tag, color, opacity, text, fontName, fontSize) { ccui.RichElement.prototype.init.call(this, tag, color, opacity); - this.text = text; - this.fontName = fontName; - this.fontSize = fontSize; + this._text = text; + this._fontName = fontName; + this._fontSize = fontSize; + }, + initWithStringAndTextDefinition: function(tag, text, fontDef, opacity){ + + ccui.RichElement.prototype.init.call(this, tag, fontDef.fillStyle, opacity); + this._fontDefinition = fontDef; + this._text = text; + this._fontName = fontDef.fontName; + this._fontSize = fontDef.fontSize; + } }); /** * Create a richElementText + * @deprecated since v3.0, please use new ccui.RichElementText() instead. * @param {Number} tag * @param {cc.Color} color * @param {Number} opacity @@ -79,81 +144,115 @@ ccui.RichElementText = ccui.RichElement.extend(/** @lends ccui.RichElementText# * @returns {ccui.RichElementText} */ ccui.RichElementText.create = function (tag, color, opacity, text, fontName, fontSize) { - var element = new ccui.RichElementText(); - element.init(tag, color, opacity, text, fontName, fontSize); - return element; + return new ccui.RichElementText(tag, color, opacity, text, fontName, fontSize); }; /** - * Base class for ccui.RichElementImage + * The image element for RichText, it has filePath, textureRect, textureType attributes. * @class * @extends ccui.RichElement */ ccui.RichElementImage = ccui.RichElement.extend(/** @lends ccui.RichElementImage# */{ - filePath: "", - textureRect: null, - textureType: 0, - ctor: function () { + _filePath: "", + _textureRect: null, + _textureType: 0, + + /** + * Constructor of ccui.RichElementImage + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + * @param {String} filePath + */ + ctor: function (tag, color, opacity, filePath) { ccui.RichElement.prototype.ctor.call(this); - this.type = ccui.RichElement.TYPE_IMAGE; - this.filePath = ""; - this.textureRect = cc.rect(0, 0, 0, 0); - this.textureType = 0; + this._type = ccui.RichElement.IMAGE; + this._filePath = ""; + this._textureRect = cc.rect(0, 0, 0, 0); + this._textureType = 0; + + filePath !== undefined && this.init(tag, color, opacity, filePath); }, + + /** + * Initializes a ccui.RichElementImage + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + * @param {String} filePath + * @override + */ init: function (tag, color, opacity, filePath) { ccui.RichElement.prototype.init.call(this, tag, color, opacity); - this.filePath = filePath; + this._filePath = filePath; } }); /** * Create a richElementImage + * @deprecated since v3.0, please use new ccui.RichElementImage() instead. * @param {Number} tag * @param {cc.Color} color * @param {Number} opacity * @param {String} filePath - * @returns {ccui.RichElementText} + * @returns {ccui.RichElementImage} */ ccui.RichElementImage.create = function (tag, color, opacity, filePath) { - var element = new ccui.RichElementImage(); - element.init(tag, color, opacity, filePath); - return element; + return new ccui.RichElementImage(tag, color, opacity, filePath); }; /** - * Base class for ccui.RichElementCustomNode + * The custom node element for RichText. * @class * @extends ccui.RichElement */ ccui.RichElementCustomNode = ccui.RichElement.extend(/** @lends ccui.RichElementCustomNode# */{ - customNode: null, - ctor: function () { + _customNode: null, + + /** + * Constructor of ccui.RichElementCustomNode + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + * @param {cc.Node} customNode + */ + ctor: function (tag, color, opacity, customNode) { ccui.RichElement.prototype.ctor.call(this); - this.type = ccui.RichElement.TYPE_CUSTOM; - this.customNode = null; + this._type = ccui.RichElement.CUSTOM; + this._customNode = null; + + customNode !== undefined && this.init(tag, color, opacity, customNode); }, + + /** + * Initializes a ccui.RichElementCustomNode + * @param {Number} tag + * @param {cc.Color} color + * @param {Number} opacity + * @param {cc.Node} customNode + * @override + */ init: function (tag, color, opacity, customNode) { ccui.RichElement.prototype.init.call(this, tag, color, opacity); - this.customNode = customNode; + this._customNode = customNode; } }); /** * Create a richElementCustomNode + * @deprecated since v3.0, please use new ccui.RichElementCustomNode() instead. * @param {Number} tag * @param {Number} color * @param {Number} opacity * @param {cc.Node} customNode - * @returns {RichElementText} + * @returns {ccui.RichElementCustomNode} */ ccui.RichElementCustomNode.create = function (tag, color, opacity, customNode) { - var element = new ccui.RichElementCustomNode(); - element.init(tag, color, opacity, customNode); - return element; + return new ccui.RichElementCustomNode(tag, color, opacity, customNode); }; /** - * Base class for ccui.RichText + * The rich text control of Cocos UI. It receives text, image, and custom node as its children to display. * @class * @extends ccui.Widget */ @@ -164,7 +263,16 @@ ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{ _leftSpaceWidth: 0, _verticalSpace: 0, _elementRenderersContainer: null, + _lineBreakOnSpace: false, + _textHorizontalAlignment: null, + _textVerticalAlignment: null, + /** + * create a rich text + * Constructor of ccui.RichText. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @example + * var uiRichText = new ccui.RichTex(); + */ ctor: function () { ccui.Widget.prototype.ctor.call(this); this._formatTextDirty = false; @@ -172,13 +280,14 @@ ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{ this._elementRenders = []; this._leftSpaceWidth = 0; this._verticalSpace = 0; - this._elementRenderersContainer = null; + this._textHorizontalAlignment = cc.TEXT_ALIGNMENT_LEFT; + this._textVerticalAlignment = cc.VERTICAL_TEXT_ALIGNMENT_TOP; }, - initRenderer: function () { - this._elementRenderersContainer = cc.Node.create(); - this._elementRenderersContainer.setAnchorPoint(cc.p(0.5, 0.5)); - cc.Node.prototype.addChild.call(this,this._elementRenderersContainer, 0, -1); + _initRenderer: function () { + this._elementRenderersContainer = new cc.Node(); + this._elementRenderersContainer.setAnchorPoint(0.5, 0.5); + this.addProtectedChild(this._elementRenderersContainer, 0, -1); }, /** @@ -205,53 +314,62 @@ ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{ * @param {ccui.RichElement} element */ removeElement: function (element) { - if (typeof element === "number") { + if (cc.isNumber(element)) this._richElements.splice(element, 1); - } else { + else cc.arrayRemoveObject(this._richElements, element); - } this._formatTextDirty = true; }, + /** + * Formats the richText's content. + */ formatText: function () { if (this._formatTextDirty) { this._elementRenderersContainer.removeAllChildren(); this._elementRenders.length = 0; + var i, element, locRichElements = this._richElements; if (this._ignoreSize) { - this.addNewLine(); - for (var i = 0; i < this._richElements.length; i++) { - var element = this._richElements[i]; + this._addNewLine(); + for (i = 0; i < locRichElements.length; i++) { + element = locRichElements[i]; var elementRenderer = null; - switch (element.type) { - case ccui.RichElement.TYPE_TEXT: - elementRenderer = cc.LabelTTF.create(element.text, element.fontName, element.fontSize); + switch (element._type) { + case ccui.RichElement.TEXT: + if( element._fontDefinition) + elementRenderer = new cc.LabelTTF(element._text, element._fontDefinition); + else //todo: There may be ambiguous + elementRenderer = new cc.LabelTTF(element._text, element._fontName, element._fontSize); break; - case ccui.RichElement.TYPE_IMAGE: - elementRenderer = cc.Sprite.create(element.filePath); + case ccui.RichElement.IMAGE: + elementRenderer = new cc.Sprite(element._filePath); break; - case ccui.RichElement.TYPE_CUSTOM: - elementRenderer = element.customNode; + case ccui.RichElement.CUSTOM: + elementRenderer = element._customNode; break; default: break; } - elementRenderer.setColor(element.color); - this.pushToContainer(elementRenderer); + elementRenderer.setColor(element._color); + elementRenderer.setOpacity(element._color.a); + this._pushToContainer(elementRenderer); } - } - else { - this.addNewLine(); - for (var i = 0; i < this._richElements.length; i++) { - var element = this._richElements[i]; - switch (element.type) { - case ccui.RichElement.TYPE_TEXT: - this.handleTextRenderer(element.text, element.fontName, element.fontSize, element.color); + } else { + this._addNewLine(); + for (i = 0; i < locRichElements.length; i++) { + element = locRichElements[i]; + switch (element._type) { + case ccui.RichElement.TEXT: + if( element._fontDefinition) + this._handleTextRenderer(element._text, element._fontDefinition, element._fontDefinition.fontSize, element._fontDefinition.fillStyle); + else + this._handleTextRenderer(element._text, element._fontName, element._fontSize, element._color); break; - case ccui.RichElement.TYPE_IMAGE: - this.handleImageRenderer(element.filePath, element.color); + case ccui.RichElement.IMAGE: + this._handleImageRenderer(element._filePath, element._color, element._color.a); break; - case ccui.RichElement.TYPE_CUSTOM: - this.handleCustomRenderer(element.customNode); + case ccui.RichElement.CUSTOM: + this._handleCustomRenderer(element._customNode); break; default: break; @@ -262,16 +380,24 @@ ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{ this._formatTextDirty = false; } }, - /** - * Handle text renderer + * Prepare the child LabelTTF based on line breaking * @param {String} text - * @param {String} fontName + * @param {String|cc.FontDefinition} fontNameOrFontDef * @param {Number} fontSize * @param {cc.Color} color + * @private */ - handleTextRenderer: function (text, fontName, fontSize, color) { - var textRenderer = cc.LabelTTF.create(text, fontName, fontSize); + _handleTextRenderer: function (text, fontNameOrFontDef, fontSize, color) { + if(text === "") + return; + + if(text === "\n"){ //Force Line Breaking + this._addNewLine(); + return; + } + + var textRenderer = fontNameOrFontDef instanceof cc.FontDefinition ? new cc.LabelTTF(text, fontNameOrFontDef) : new cc.LabelTTF(text, fontNameOrFontDef, fontSize); var textRendererWidth = textRenderer.getContentSize().width; this._leftSpaceWidth -= textRendererWidth; if (this._leftSpaceWidth < 0) { @@ -281,137 +407,180 @@ ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{ var leftLength = stringLength * (1 - overstepPercent); var leftWords = curText.substr(0, leftLength); var cutWords = curText.substr(leftLength, curText.length - 1); - if (leftLength > 0) { - var leftRenderer = cc.LabelTTF.create(leftWords.substr(0, leftLength), fontName, fontSize); - leftRenderer.setColor(color); - this.pushToContainer(leftRenderer); + var validLeftLength = leftLength > 0; + + if(this._lineBreakOnSpace){ + var lastSpaceIndex = leftWords.lastIndexOf(' '); + leftLength = lastSpaceIndex === -1 ? leftLength : lastSpaceIndex+1 ; + cutWords = curText.substr(leftLength, curText.length - 1); + validLeftLength = leftLength > 0 && cutWords !== " "; } - this.addNewLine(); - this.handleTextRenderer(cutWords, fontName, fontSize, color); - } - else { - textRenderer.setColor(color); - this.pushToContainer(textRenderer); + if (validLeftLength) { + var leftRenderer = null; + if( fontNameOrFontDef instanceof cc.FontDefinition) + { + leftRenderer = new cc.LabelTTF(leftWords.substr(0, leftLength), fontNameOrFontDef); + leftRenderer.setOpacity(fontNameOrFontDef.fillStyle.a); //TODO: Verify that might not be needed... + }else{ + leftRenderer = new cc.LabelTTF(leftWords.substr(0, leftLength), fontNameOrFontDef, fontSize); + leftRenderer.setColor(color); + leftRenderer.setOpacity(color.a); + } + this._pushToContainer(leftRenderer); + } + + this._addNewLine(); + this._handleTextRenderer(cutWords, fontNameOrFontDef, fontSize, color); + } else { + if( fontNameOrFontDef instanceof cc.FontDefinition) { + textRenderer.setOpacity(fontNameOrFontDef.fillStyle.a); //TODO: Verify that might not be needed... + }else { + textRenderer.setColor(color); + textRenderer.setOpacity(color.a); + } + this._pushToContainer(textRenderer); } }, - /** - * Handle image renderer - * @param {String} filePath - * @param {cc.Color} color - * @param {Number} opacity - */ - handleImageRenderer: function (filePath, color, opacity) { - var imageRenderer = cc.Sprite.create(filePath); - this.handleCustomRenderer(imageRenderer); + _handleImageRenderer: function (filePath, color, opacity) { + var imageRenderer = new cc.Sprite(filePath); + this._handleCustomRenderer(imageRenderer); }, - /** - * Handle custom renderer - * @param {cc.Node} renderer - */ - handleCustomRenderer: function (renderer) { + _handleCustomRenderer: function (renderer) { var imgSize = renderer.getContentSize(); this._leftSpaceWidth -= imgSize.width; if (this._leftSpaceWidth < 0) { - this.addNewLine(); - this.pushToContainer(renderer); + this._addNewLine(); + this._pushToContainer(renderer); this._leftSpaceWidth -= imgSize.width; - } - else { - this.pushToContainer(renderer); - } + } else + this._pushToContainer(renderer); }, - addNewLine: function () { + _addNewLine: function () { this._leftSpaceWidth = this._customSize.width; this._elementRenders.push([]); }, + /** + * Formats richText's renderer. + */ formatRenderers: function () { + var newContentSizeHeight = 0, locRenderersContainer = this._elementRenderersContainer; + var locElementRenders = this._elementRenders; + var i, j, row, nextPosX, l; if (this._ignoreSize) { var newContentSizeWidth = 0; - var newContentSizeHeight = 0; + row = locElementRenders[0]; + nextPosX = 0; - var row = this._elementRenders[0]; - var nextPosX = 0; - for (var j = 0; j < row.length; j++) { - var l = row[j]; + for (j = 0; j < row.length; j++) { + l = row[j]; l.setAnchorPoint(cc.p(0, 0)); - l.setPosition(cc.p(nextPosX, 0)); - this._elementRenderersContainer.addChild(l, 1, j); + l.setPosition(nextPosX, 0); + locRenderersContainer.addChild(l, 1, j); + + var lineHeight = l.getLineHeight ? l.getLineHeight() : newContentSizeHeight; + var iSize = l.getContentSize(); newContentSizeWidth += iSize.width; - newContentSizeHeight = Math.max(newContentSizeHeight, iSize.height); + newContentSizeHeight = Math.max(Math.min(newContentSizeHeight, lineHeight), iSize.height); nextPosX += iSize.width; } - this._elementRenderersContainer.setContentSize(cc.size(newContentSizeWidth, newContentSizeHeight)); - } - else { - var newContentSizeHeight = 0; - var maxHeights = []; - for (var i = 0; i < this._elementRenders.length; i++) { - var row = this._elementRenders[i]; + //Text flow horizontal alignment: + if(this._textHorizontalAlignment !== cc.TEXT_ALIGNMENT_LEFT) { + var offsetX = 0; + if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_RIGHT) + offsetX = this._contentSize.width - nextPosX; + else if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_CENTER) + offsetX = (this._contentSize.width - nextPosX) / 2; + + for (j = 0; j < row.length; j++) + row[j].x += offsetX; + } + + locRenderersContainer.setContentSize(newContentSizeWidth, newContentSizeHeight); + } else { + var maxHeights = []; + for (i = 0; i < locElementRenders.length; i++) { + row = locElementRenders[i]; var maxHeight = 0; - for (var j = 0; j < row.length; j++) { - var l = row[j]; - maxHeight = Math.max(l.getContentSize().height, maxHeight); + for (j = 0; j < row.length; j++) { + l = row[j]; + var lineHeight = l.getLineHeight ? l.getLineHeight() : l.getContentSize().height; + cc.log(lineHeight); + maxHeight = Math.max(Math.min(l.getContentSize().height, lineHeight), maxHeight); } maxHeights[i] = maxHeight; newContentSizeHeight += maxHeights[i]; } - var nextPosY = this._customSize.height; - for (var i = 0; i < this._elementRenders.length; i++) { - var row = this._elementRenders[i]; - var nextPosX = 0; + + for (i = 0; i < locElementRenders.length; i++) { + row = locElementRenders[i]; + nextPosX = 0; nextPosY -= (maxHeights[i] + this._verticalSpace); - for (var j = 0; j < row.length; j++) { - var l = row[j]; + for (j = 0; j < row.length; j++) { + l = row[j]; l.setAnchorPoint(cc.p(0, 0)); l.setPosition(cc.p(nextPosX, nextPosY)); - this._elementRenderersContainer.addChild(l, 1, i * 10 + j); + locRenderersContainer.addChild(l, 1); nextPosX += l.getContentSize().width; } + //Text flow alignment(s) + if( this._textHorizontalAlignment !== cc.TEXT_ALIGNMENT_LEFT || this._textVerticalAlignment !== cc.VERTICAL_TEXT_ALIGNMENT_TOP) { + var offsetX = 0; + if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_RIGHT) + offsetX = this._contentSize.width - nextPosX; + else if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_CENTER) + offsetX = (this._contentSize.width - nextPosX) / 2; + + var offsetY = 0; + if (this._textVerticalAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) + offsetY = this._customSize.height - newContentSizeHeight; + else if (this._textVerticalAlignment === cc.VERTICAL_TEXT_ALIGNMENT_CENTER) + offsetY = (this._customSize.height - newContentSizeHeight) / 2; + + for (j = 0; j < row.length; j++) { + l = row[j]; + l.x += offsetX; + l.y -= offsetY; + } + } } - this._elementRenderersContainer.setContentSize(this._size); - } - this._elementRenders.length = 0; - if (this._ignoreSize) { - var s = this.getContentSize(); - this._size.width = s.width; - this._size.height = s.height; + + locRenderersContainer.setContentSize(this._contentSize); } - else { - this._size.width = this._customSize.width; - this._size.height = this._customSize.height; + + var length = locElementRenders.length; + for (i = 0; i 100) { + if (percent > 100) percent = 100; - } - if (percent < 0) { + if (percent < 0) percent = 0; - } this._percent = percent; - if(!this._isTextureLoaded){ - return; - } - var dis = this._barLength * (percent / 100.0); - this._slidBallRenderer.setPosition(-this._barLength / 2.0 + dis, 0.0); - if (this._scale9Enabled) { - this._progressBarRenderer.setPreferredSize(cc.size(dis, this._progressBarTextureSize.height)); - } + var res = percent / 100.0; + var dis = this._barLength * res; + this._slidBallRenderer.setPosition(dis, this._contentSize.height / 2); + if (this._scale9Enabled) + this._progressBarRenderer.setPreferredSize(cc.size(dis, this._contentSize.height)); else { - var x = 0, y = 0; - if (this._progressBarTexType == ccui.Widget.PLIST_TEXTURE) { - var barNode = this._progressBarRenderer; - if (barNode) { - var to = barNode.getTextureRect()._origin; - x = to.x; - y = to.y; - } - } - this._progressBarRenderer.setTextureRect(cc.rect(x, y, this._progressBarTextureSize.width * (percent / 100.0), this._progressBarTextureSize.height)); + var spriteRenderer = this._progressBarRenderer; + var rect = spriteRenderer.getTextureRect(); + spriteRenderer.setTextureRect( + cc.rect(rect.x, rect.y, dis / spriteRenderer._scaleX, rect.height), + spriteRenderer.isTextureRectRotated() + ); } }, - onTouchBegan: function (touch , event) { - var pass = ccui.Widget.prototype.onTouchBegan.call(this,touch , event); - if(this._hitted){ - var nsp = this.convertToNodeSpace(this._touchStartPos); - this.setPercent(this.getPercentWithBallPos(nsp.x)); - this.percentChangedEvent(); + /** + * test the point whether location in loadingBar's bounding box. + * @override + * @param {cc.Point} pt + * @returns {boolean} + */ + hitTest: function(pt){ + var nsp = this._slidBallNormalRenderer.convertToNodeSpace(pt); + var ballSize = this._slidBallNormalRenderer.getContentSize(); + var ballRect = cc.rect(0,0, ballSize.width, ballSize.height); +// if (ballRect.containsPoint(nsp)) { + return (nsp.x >= ballRect.x && + nsp.x <= (ballRect.x + ballRect.width) && + nsp.y >= ballRect.y && + nsp.y <= (ballRect.y +ballRect.height)); + }, + + onTouchBegan: function (touch, event) { + var pass = ccui.Widget.prototype.onTouchBegan.call(this, touch, event); + if (this._hit) { + var nsp = this.convertToNodeSpace(this._touchBeganPosition); + this.setPercent(this._getPercentWithBallPos(nsp.x)); + this._percentChangedEvent(); } return pass; }, - onTouchMoved: function (touch , event) { + onTouchMoved: function (touch, event) { var touchPoint = touch.getLocation(); - this._touchMovePos.x = touchPoint.x; - this._touchMovePos.y = touchPoint.y; var nsp = this.convertToNodeSpace(touchPoint); - this._slidBallRenderer.setPosition(nsp.x, 0); - this.setPercent(this.getPercentWithBallPos(nsp.x)); - this.percentChangedEvent(); + this.setPercent(this._getPercentWithBallPos(nsp.x)); + this._percentChangedEvent(); }, - onTouchEnded: function (touch , event) { - ccui.Widget.prototype.onTouchEnded.call(this, touch , event); + onTouchEnded: function (touch, event) { + ccui.Widget.prototype.onTouchEnded.call(this, touch, event); }, - onTouchCancelled: function (touch , event) { - ccui.Widget.prototype.onTouchCancelled.call(this, touch , event); + onTouchCancelled: function (touch, event) { + ccui.Widget.prototype.onTouchCancelled.call(this, touch, event); }, /** - * get percent with ballPos + * Returns percent with ball's position. * @param {cc.Point} px * @returns {number} */ - getPercentWithBallPos: function (px) { - return (((px - (-this._barLength / 2.0)) / this._barLength) * 100.0); + _getPercentWithBallPos: function (px) { + return ((px/this._barLength)*100); }, /** * add event listener * @param {Function} selector - * @param {Object} target + * @param {Object} [target=] + * @deprecated since v3.0, please use addEventListener instead. */ addEventListenerSlider: function (selector, target) { - this._sliderEventSelector = selector; + this.addEventListener(selector, target); + }, + + /** + * Adds a callback + * @param {Function} selector + * @param {Object} [target=] + */ + addEventListener: function(selector, target){ + this._sliderEventSelector = selector; //when target is undefined, _sliderEventSelector = _eventCallback this._sliderEventListener = target; }, - percentChangedEvent: function () { - if (this._sliderEventListener && this._sliderEventSelector) { - this._sliderEventSelector.call(this._sliderEventListener, this, ccui.Slider.EVENT_PERCENT_CHANGED); + _percentChangedEvent: function () { + if(this._sliderEventSelector){ + if (this._sliderEventListener) + this._sliderEventSelector.call(this._sliderEventListener, this, ccui.Slider.EVENT_PERCENT_CHANGED); + else + this._sliderEventSelector(this, ccui.Slider.EVENT_PERCENT_CHANGED); // _eventCallback } + if (this._ccEventCallback) + this._ccEventCallback(this, ccui.Slider.EVENT_PERCENT_CHANGED); }, /** @@ -478,76 +554,85 @@ ccui.Slider = ccui.Widget.extend(/** @lends ccui.Slider# */{ return this._percent; }, - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.barRendererScaleChangedWithSize(); - this.progressBarRendererScaleChangedWithSize(); + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._barRendererAdaptDirty = true; + this._progressBarRendererDirty = true; + }, + + _adaptRenderers: function(){ + if (this._barRendererAdaptDirty) + { + this._barRendererScaleChangedWithSize(); + this._barRendererAdaptDirty = false; + } + if (this._progressBarRendererDirty) + { + this._progressBarRendererScaleChangedWithSize(); + this._progressBarRendererDirty = false; + } }, /** - * override "getContentSize" method of widget. + * Returns the content size of bar renderer. * @returns {cc.Size} */ - getContentSize: function () { - var locContentSize = this._barRenderer.getContentSize(); - return cc.size(locContentSize.width,locContentSize.height); + getVirtualRendererSize: function(){ + return this._barRenderer.getContentSize(); }, - _getWidth: function () { - return this._barRenderer._getWidth(); - }, - _getHeight: function () { - return this._barRenderer._getHeight(); - }, /** - * override "getContentSize" method of widget. + * Returns the bar renderer. * @returns {cc.Node} */ getVirtualRenderer: function () { return this._barRenderer; }, - barRendererScaleChangedWithSize: function () { - if (this._ignoreSize) { + _barRendererScaleChangedWithSize: function () { + if (this._unifySize){ + this._barLength = this._contentSize.width; + this._barRenderer.setPreferredSize(this._contentSize); + }else if(this._ignoreSize) { this._barRenderer.setScale(1.0); - var locSize = this._barRenderer.getContentSize(); - this._size.width = locSize.width; - this._size.height = locSize.height; - this._barLength = locSize.width; - } - else { - this._barLength = this._size.width; + this._barLength = this._contentSize.width; + }else { + this._barLength = this._contentSize.width; if (this._scale9Enabled) { - this._barRenderer.setPreferredSize(cc.size(this._size.width,this._size.height)); - } - else { - var btextureSize = this._barRenderer.getContentSize(); + this._barRenderer.setPreferredSize(this._contentSize); + this._barRenderer.setScale(1.0); + } else { + var btextureSize = this._barTextureSize; if (btextureSize.width <= 0.0 || btextureSize.height <= 0.0) { this._barRenderer.setScale(1.0); return; } - var bscaleX = this._size.width / btextureSize.width; - var bscaleY = this._size.height / btextureSize.height; + var bscaleX = this._contentSize.width / btextureSize.width; + var bscaleY = this._contentSize.height / btextureSize.height; this._barRenderer.setScaleX(bscaleX); this._barRenderer.setScaleY(bscaleY); } } + this._barRenderer.setPosition(this._contentSize.width / 2.0, this._contentSize.height / 2.0); this.setPercent(this._percent); }, - progressBarRendererScaleChangedWithSize: function () { - if (this._ignoreSize) { + _progressBarRendererScaleChangedWithSize: function () { + if(this._unifySize){ + this._progressBarRenderer.setPreferredSize(this._contentSize); + }else if(this._ignoreSize) { if (!this._scale9Enabled) { var ptextureSize = this._progressBarTextureSize; - var pscaleX = this._size.width / ptextureSize.width; - var pscaleY = this._size.height / ptextureSize.height; + var pscaleX = this._contentSize.width / ptextureSize.width; + var pscaleY = this._contentSize.height / ptextureSize.height; this._progressBarRenderer.setScaleX(pscaleX); this._progressBarRenderer.setScaleY(pscaleY); } } else { if (this._scale9Enabled) { - this._progressBarRenderer.setPreferredSize(cc.size(this._size.width,this._size.height)); + this._progressBarRenderer.setPreferredSize(this._contentSize); + this._progressBarRenderer.setScale(1); } else { var ptextureSize = this._progressBarTextureSize; @@ -555,63 +640,64 @@ ccui.Slider = ccui.Widget.extend(/** @lends ccui.Slider# */{ this._progressBarRenderer.setScale(1.0); return; } - var pscaleX = this._size.width / ptextureSize.width; - var pscaleY = this._size.height / ptextureSize.height; + var pscaleX = this._contentSize.width / ptextureSize.width; + var pscaleY = this._contentSize.height / ptextureSize.height; this._progressBarRenderer.setScaleX(pscaleX); this._progressBarRenderer.setScaleY(pscaleY); } } - this._progressBarRenderer.setPosition(-this._barLength * 0.5, 0.0); + this._progressBarRenderer.setPosition(0.0, this._contentSize.height / 2.0); this.setPercent(this._percent); }, - onPressStateChangedToNormal: function () { + _onPressStateChangedToNormal: function () { this._slidBallNormalRenderer.setVisible(true); this._slidBallPressedRenderer.setVisible(false); this._slidBallDisabledRenderer.setVisible(false); + + this._slidBallNormalRenderer.setScale(this._sliderBallNormalTextureScaleX, this._sliderBallNormalTextureScaleY); }, - onPressStateChangedToPressed: function () { - this._slidBallNormalRenderer.setVisible(false); - this._slidBallPressedRenderer.setVisible(true); - this._slidBallDisabledRenderer.setVisible(false); + _onPressStateChangedToPressed: function () { + if (!this._slidBallPressedTextureFile){ + this._slidBallNormalRenderer.setScale(this._sliderBallNormalTextureScaleX + this._zoomScale, this._sliderBallNormalTextureScaleY + this._zoomScale); + }else{ + this._slidBallNormalRenderer.setVisible(false); + this._slidBallPressedRenderer.setVisible(true); + this._slidBallDisabledRenderer.setVisible(false); + } }, - onPressStateChangedToDisabled: function () { - this._slidBallNormalRenderer.setVisible(false); + _onPressStateChangedToDisabled: function () { + if (this._slidBallDisabledTextureFile){ + this._slidBallNormalRenderer.setVisible(false); + this._slidBallDisabledRenderer.setVisible(true); + } + this._slidBallNormalRenderer.setScale(this._sliderBallNormalTextureScaleX, this._sliderBallNormalTextureScaleY); this._slidBallPressedRenderer.setVisible(false); - this._slidBallDisabledRenderer.setVisible(true); }, - updateTextureColor: function () { - this.updateColorToRenderer(this._barRenderer); - this.updateColorToRenderer(this._progressBarRenderer); - this.updateColorToRenderer(this._slidBallNormalRenderer); - this.updateColorToRenderer(this._slidBallPressedRenderer); - this.updateColorToRenderer(this._slidBallDisabledRenderer); + setZoomScale: function(scale){ + this._zoomScale = scale; }, - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._barRenderer); - this.updateOpacityToRenderer(this._progressBarRenderer); - this.updateOpacityToRenderer(this._slidBallNormalRenderer); - this.updateOpacityToRenderer(this._slidBallPressedRenderer); - this.updateOpacityToRenderer(this._slidBallDisabledRenderer); + getZoomScale: function(){ + return this._zoomScale; }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.LoadingBar. * @returns {string} */ getDescription: function () { return "Slider"; }, - createCloneInstance: function () { - return ccui.Slider.create(); + _createCloneInstance: function () { + return new ccui.Slider(); }, - copySpecialProperties: function (slider) { + _copySpecialProperties: function (slider) { this._prevIgnoreSize = slider._prevIgnoreSize; this.setScale9Enabled(slider._scale9Enabled); this.loadBarTexture(slider._textureFile, slider._barTexType); @@ -620,39 +706,57 @@ ccui.Slider = ccui.Widget.extend(/** @lends ccui.Slider# */{ this.loadSlidBallTexturePressed(slider._slidBallPressedTextureFile, slider._ballPTexType); this.loadSlidBallTextureDisabled(slider._slidBallDisabledTextureFile, slider._ballDTexType); this.setPercent(slider.getPercent()); + this._sliderEventListener = slider._sliderEventListener; + this._sliderEventSelector = slider._sliderEventSelector; + this._zoomScale = slider._zoomScale; + this._ccEventCallback = slider._ccEventCallback; + } }); -window._p = ccui.Slider.prototype; +var _p = ccui.Slider.prototype; // Extended properties /** @expose */ _p.percent; cc.defineGetterSetter(_p, "percent", _p.getPercent, _p.setPercent); -delete window._p; +_p = null; /** * allocates and initializes a UISlider. - * @constructs + * @deprecated since v3.0, please use new ccui.Slider() instead. * @return {ccui.Slider} - * @example - * // example - * var uiSlider = ccui.Slider.create(); */ -ccui.Slider.create = function () { - var uiSlider = new ccui.Slider(); - if (uiSlider && uiSlider.init()) { - return uiSlider; - } - return null; +ccui.Slider.create = function (barTextureName, normalBallTextureName, resType) { + return new ccui.Slider(barTextureName, normalBallTextureName, resType); }; // Constant //Slider event type +/** + * The percent change event flag of ccui.Slider. + * @constant + * @type {number} + */ ccui.Slider.EVENT_PERCENT_CHANGED = 0; //Render zorder +/** + * The zOrder value of ccui.Slider's base bar renderer. + * @constant + * @type {number} + */ ccui.Slider.BASEBAR_RENDERER_ZORDER = -3; +/** + * The zOrder value of ccui.Slider's progress bar renderer. + * @constant + * @type {number} + */ ccui.Slider.PROGRESSBAR_RENDERER_ZORDER = -2; +/** + * The zOrder value of ccui.Slider's ball renderer. + * @constant + * @type {number} + */ ccui.Slider.BALL_RENDERER_ZORDER = -1; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/UIText.js b/extensions/ccui/uiwidgets/UIText.js index 7ffa1b2c41..5d7bfc107a 100644 --- a/extensions/ccui/uiwidgets/UIText.js +++ b/extensions/ccui/uiwidgets/UIText.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccui.Button + * The text control of Cocos UI. * @class * @extends ccui.Widget * @@ -39,187 +40,228 @@ * @property {Boolean} touchScaleEnabled - Indicate whether the label will scale when touching */ ccui.Text = ccui.Widget.extend(/** @lends ccui.Text# */{ - touchScaleEnabled: false, - _normalScaleValueX: 0, - _normalScaleValueY: 0, - _fontName: "", - _fontSize: 0, - _onSelectedScaleOffset: 0, + _touchScaleChangeEnabled: false, + _normalScaleValueX: 1, + _normalScaleValueY: 1, + _fontName: "Thonburi", + _fontSize: 10, + _onSelectedScaleOffset:0.5, _labelRenderer: "", - _textAreaSize:null, - _textVerticalAlignment:0, - _textHorizontalAlignment:0, - _className:"Text", - ctor: function () { - ccui.Widget.prototype.ctor.call(this); - this.touchScaleEnabled = false; - this._normalScaleValueX = 0; - this._normalScaleValueY = 0; - this._fontName = "Thonburi"; - this._fontSize = 10; - this._onSelectedScaleOffset = 0.5; - this._labelRenderer = ""; + _textAreaSize: null, + _textVerticalAlignment: 0, + _textHorizontalAlignment: 0, + _className: "Text", + _type: null, + _labelRendererAdaptDirty: true, + + /** + * allocates and initializes a UILabel. + * Constructor of ccui.Text. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {String} textContent + * @param {String} fontName + * @param {Number} fontSize + * @example + * // example + * var uiLabel = new ccui.Text(); + */ + ctor: function (textContent, fontName, fontSize) { + this._type = ccui.Text.Type.SYSTEM; this._textAreaSize = cc.size(0, 0); - this._textVerticalAlignment = 0; - this._textHorizontalAlignment = 0; + ccui.Widget.prototype.ctor.call(this); + + fontSize !== undefined && this.init(textContent, fontName, fontSize); + }, - init: function () { + /** + * Initializes a ccui.Text. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @param {String} textContent + * @param {String} fontName + * @param {Number} fontSize + * @returns {boolean} + * @override + */ + init: function (textContent, fontName, fontSize) { if (ccui.Widget.prototype.init.call(this)) { + if(arguments.length > 0){ + this.setFontName(fontName); + this.setFontSize(fontSize); + this.setString(textContent); + }else{ + this.setFontName(this._fontName); + } return true; } return false; }, - initRenderer: function () { - this._labelRenderer = cc.LabelTTF.create(); - cc.Node.prototype.addChild.call(this, this._labelRenderer, ccui.Text.RENDERER_ZORDER, -1); + _initRenderer: function () { + this._labelRenderer = new cc.LabelTTF(); + this.addProtectedChild(this._labelRenderer, ccui.Text.RENDERER_ZORDER, -1); }, /** - * Changes the string value of label. + * Changes the value of ccui.Text. + * @deprecated since v3.0, please use setString() instead. * @param {String} text */ setText: function (text) { + cc.log("Please use the setString"); + this.setString(text); + }, + + /** + * Changes the value of ccui.Text. + * @param {String} text + */ + setString: function (text) { + if(text === this._labelRenderer.getString()) + return; this._labelRenderer.setString(text); - this.labelScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; }, /** - * Gets the string value of label. + * Gets the string value of ccui.Text. + * @deprecated since v3.0, please use getString instead. * @returns {String} */ getStringValue: function () { + cc.log("Please use the getString"); + return this._labelRenderer.getString(); + }, + + /** + * Gets the string value of ccui.Text. + * @returns {String} + */ + getString: function () { return this._labelRenderer.getString(); }, /** - * Gets the string length of label. + * Gets the string length of ccui.Text. * @returns {Number} */ getStringLength: function () { - var str = this._labelRenderer.getString(); - return str.length; + return this._labelRenderer.getStringLength(); }, /** - * set fontSize + * Sets fontSize * @param {Number} size */ setFontSize: function (size) { - this._fontSize = size; this._labelRenderer.setFontSize(size); - this.labelScaleChangedWithSize(); + this._fontSize = size; + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; }, /** - * Get font Size + * Returns font Size of ccui.Text * @returns {Number} */ - getFontSize:function(){ + getFontSize: function () { return this._fontSize; }, /** - * Set font name + * Sets font name * @return {String} name */ setFontName: function (name) { this._fontName = name; this._labelRenderer.setFontName(name); - this.labelScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; }, /** - * Get font name + * Returns font name of ccui.Text. * @returns {string} */ - getFontName:function(){ + getFontName: function () { return this._fontName; }, - _setFont: function (font) { - var res = cc.LabelTTF._fontStyleRE.exec(font); - if(res) { - this._fontSize = parseInt(res[1]); - this._fontName = res[2]; - this._labelRenderer._setFont(font); - this.labelScaleChangedWithSize(); - } - }, - _getFont: function () { - return this._labelRenderer._getFont(); - }, + _setFont: function (font) { + var res = cc.LabelTTF._fontStyleRE.exec(font); + if (res) { + this._fontSize = parseInt(res[1]); + this._fontName = res[2]; + this._labelRenderer._setFont(font); + this._labelScaleChangedWithSize(); + } + }, + _getFont: function () { + return this._labelRenderer._getFont(); + }, + + /** + * Returns the type of ccui.Text. + * @returns {null} + */ + getType: function(){ + return this._type; + }, /** - * set textAreaSize + * Sets text Area Size * @param {cc.Size} size */ setTextAreaSize: function (size) { - this._textAreaSize.width = size.width; - this._textAreaSize.height = size.height; this._labelRenderer.setDimensions(size); - this.labelScaleChangedWithSize(); - }, - _setBoundingWidth: function (value) { - this._textAreaSize.width = value; - this._labelRenderer._setBoundingWidth(value); - this.labelScaleChangedWithSize(); - }, - _setBoundingHeight: function (value) { - this._textAreaSize.height = value; - this._labelRenderer._setBoundingHeight(value); - this.labelScaleChangedWithSize(); - }, - _getBoundingWidth: function () { - return this._textAreaSize.width; - }, - _getBoundingHeight: function () { - return this._textAreaSize.height; - }, + if (!this._ignoreSize){ + this._customSize = size; + } + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; + }, + + /** + * Returns renderer's dimension. + * @returns {cc.Size} + */ + getTextAreaSize: function(){ + return this._labelRenderer.getDimensions(); + }, /** - * set Horizontal Alignment of cc.LabelTTF + * Sets Horizontal Alignment of cc.LabelTTF * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment Horizontal Alignment */ setTextHorizontalAlignment: function (alignment) { - this._textHorizontalAlignment = alignment; this._labelRenderer.setHorizontalAlignment(alignment); - this.labelScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; }, /** - * Return Horizontal Alignment of label + * Returns Horizontal Alignment of label * @returns {TEXT_ALIGNMENT_LEFT|TEXT_ALIGNMENT_CENTER|TEXT_ALIGNMENT_RIGHT} */ - getTextHorizontalAlignment:function(){ - return this._textHorizontalAlignment; + getTextHorizontalAlignment: function () { + return this._labelRenderer.getHorizontalAlignment(); }, /** - * Set Vertical Alignment of label - * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} verticalAlignment + * Sets Vertical Alignment of label + * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} alignment */ setTextVerticalAlignment: function (alignment) { - this._textVerticalAlignment = alignment; this._labelRenderer.setVerticalAlignment(alignment); - this.labelScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._labelRenderer.getContentSize()); + this._labelRendererAdaptDirty = true; }, /** - * Get text vertical alignment. + * Gets text vertical alignment. * @returns {VERTICAL_TEXT_ALIGNMENT_TOP|VERTICAL_TEXT_ALIGNMENT_CENTER|VERTICAL_TEXT_ALIGNMENT_BOTTOM} */ - getTextVerticalAlignment:function(){ - return this._textVerticalAlignment; - }, - - /** - * Gets the touch scale enabled of label. - * @returns {Boolean} - */ - getTouchScaleChangeAble: function () { - return this.isTouchScaleChangeEnabled(); + getTextVerticalAlignment: function () { + return this._labelRenderer.getVerticalAlignment(); }, /** @@ -227,7 +269,7 @@ ccui.Text = ccui.Widget.extend(/** @lends ccui.Text# */{ * @param {Boolean} enable */ setTouchScaleChangeEnabled: function (enable) { - this.touchScaleEnabled = enable; + this._touchScaleChangeEnabled = enable; }, /** @@ -235,143 +277,186 @@ ccui.Text = ccui.Widget.extend(/** @lends ccui.Text# */{ * @returns {Boolean} */ isTouchScaleChangeEnabled: function () { - return this.touchScaleEnabled; + return this._touchScaleChangeEnabled; }, - onPressStateChangedToNormal: function () { - if (!this.touchScaleEnabled) { + _onPressStateChangedToNormal: function () { + if (!this._touchScaleChangeEnabled) return; - } this._labelRenderer.setScaleX(this._normalScaleValueX); this._labelRenderer.setScaleY(this._normalScaleValueY); }, - onPressStateChangedToPressed: function () { - if (!this.touchScaleEnabled) { + _onPressStateChangedToPressed: function () { + if (!this._touchScaleChangeEnabled) return; - } this._labelRenderer.setScaleX(this._normalScaleValueX + this._onSelectedScaleOffset); this._labelRenderer.setScaleY(this._normalScaleValueY + this._onSelectedScaleOffset); }, - onPressStateChangedToDisabled: function () { - - }, - - - updateFlippedX: function () { - this._labelRenderer.setFlippedX(this._flippedX); + _onPressStateChangedToDisabled: function () { }, - updateFlippedY: function () { - this._labelRenderer.setFlippedY(this._flippedY); + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._labelRendererAdaptDirty = true; }, - /** - * override "setAnchorPoint" of widget. - * @param {cc.Point|Number} point The anchor point of UILabel or The anchor point.x of UILabel. - * @param {Number} [y] The anchor point.y of UILabel. - */ - setAnchorPoint: function (point, y) { - if(y === undefined){ - ccui.Widget.prototype.setAnchorPoint.call(this, point); - this._labelRenderer.setAnchorPoint(point); - } else { - ccui.Widget.prototype.setAnchorPoint.call(this, point, y); - this._labelRenderer.setAnchorPoint(point, y); + _adaptRenderers: function(){ + if (this._labelRendererAdaptDirty) { + this._labelScaleChangedWithSize(); + this._labelRendererAdaptDirty = false; } }, - _setAnchorX: function (value) { - ccui.Widget.prototype._setAnchorX.call(this, value); - this._labelRenderer._setAnchorX(value); - }, - _setAnchorY: function (value) { - ccui.Widget.prototype._setAnchorY.call(this, value); - this._labelRenderer._setAnchorY(value); - }, - - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.labelScaleChangedWithSize(); - }, /** - * override "getContentSize" method of widget. + * Returns the renderer's content size. + * @override * @returns {cc.Size} */ - getContentSize: function () { + getVirtualRendererSize: function(){ return this._labelRenderer.getContentSize(); }, - _getWidth: function () { - return this._labelRenderer._getWidth(); - }, - _getHeight: function () { - return this._labelRenderer._getHeight(); - }, /** - * override "getVirtualRenderer" method of widget. + * Returns the renderer of ccui.Text. * @returns {cc.Node} */ getVirtualRenderer: function () { return this._labelRenderer; }, - labelScaleChangedWithSize: function () { + //@since v3.3 + getAutoRenderSize: function(){ + var virtualSize = this._labelRenderer.getContentSize(); + if (!this._ignoreSize) { + this._labelRenderer.setDimensions(0, 0); + virtualSize = this._labelRenderer.getContentSize(); + this._labelRenderer.setDimensions(this._contentSize.width, this._contentSize.height); + } + return virtualSize; + }, + + _labelScaleChangedWithSize: function () { + var locContentSize = this._contentSize; if (this._ignoreSize) { + this._labelRenderer.setDimensions(0,0); this._labelRenderer.setScale(1.0); - var renderSize = this._labelRenderer.getContentSize(); - this._size.width = renderSize.width; - this._size.height = renderSize.height; this._normalScaleValueX = this._normalScaleValueY = 1; - } - else { + } else { + this._labelRenderer.setDimensions(cc.size(locContentSize.width, locContentSize.height)); var textureSize = this._labelRenderer.getContentSize(); if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { this._labelRenderer.setScale(1.0); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; + var scaleX = locContentSize.width / textureSize.width; + var scaleY = locContentSize.height / textureSize.height; this._labelRenderer.setScaleX(scaleX); this._labelRenderer.setScaleY(scaleY); this._normalScaleValueX = scaleX; this._normalScaleValueY = scaleY; } + this._labelRenderer.setPosition(locContentSize.width / 2.0, locContentSize.height / 2.0); }, - updateTextureColor: function () { - this.updateColorToRenderer(this._labelRenderer); + /** + * Returns the "class name" of ccui.Text. + * @returns {string} + */ + getDescription: function () { + return "Label"; }, - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._labelRenderer); + /** + * Enables shadow style and sets color, offset and blur radius styles. + * @param {cc.Color} shadowColor + * @param {cc.Size} offset + * @param {Number} blurRadius + */ + enableShadow: function(shadowColor, offset, blurRadius){ + this._labelRenderer.enableShadow(shadowColor, offset, blurRadius); }, /** - * Returns the "class name" of widget. - * @returns {string} + * Enables outline style and sets outline's color and size. + * @param {cc.Color} outlineColor + * @param {cc.Size} outlineSize */ - getDescription: function () { - return "Label"; + enableOutline: function(outlineColor, outlineSize){ + this._labelRenderer.enableStroke(outlineColor, outlineSize); }, - createCloneInstance: function () { - return ccui.Text.create(); + /** + * Enables glow color + * @param glowColor + */ + enableGlow: function(glowColor){ + if (this._type === ccui.Text.Type.TTF) + this._labelRenderer.enableGlow(glowColor); }, - copySpecialProperties: function (uiLabel) { - this.setFontName(uiLabel._fontName); - this.setFontSize(uiLabel._labelRenderer.getFontSize()); - this.setText(uiLabel.getStringValue()); - this.setTouchScaleChangeEnabled(uiLabel.touchScaleEnabled); - this.setTextAreaSize(uiLabel._size); - this.setTextHorizontalAlignment(uiLabel._textHorizontalAlignment); - this.setTextVerticalAlignment(uiLabel._textVerticalAlignment); + /** + * Disables renderer's effect. + */ + disableEffect: function(){ + if(this._labelRenderer.disableEffect) + this._labelRenderer.disableEffect(); + }, + + _createCloneInstance: function () { + return new ccui.Text(); + }, + + _copySpecialProperties: function (uiLabel) { + if(uiLabel instanceof ccui.Text){ + this.setFontName(uiLabel._fontName); + this.setFontSize(uiLabel.getFontSize()); + this.setString(uiLabel.getString()); + this.setTouchScaleChangeEnabled(uiLabel.touchScaleEnabled); + this.setTextAreaSize(uiLabel._textAreaSize); + this.setTextHorizontalAlignment(uiLabel._labelRenderer.getHorizontalAlignment()); + this.setTextVerticalAlignment(uiLabel._labelRenderer.getVerticalAlignment()); + this.setContentSize(uiLabel.getContentSize()); + } + }, + + _setBoundingWidth: function (value) { + this._textAreaSize.width = value; + this._labelRenderer._setBoundingWidth(value); + this._labelScaleChangedWithSize(); + }, + _setBoundingHeight: function (value) { + this._textAreaSize.height = value; + this._labelRenderer._setBoundingHeight(value); + this._labelScaleChangedWithSize(); + }, + _getBoundingWidth: function () { + return this._textAreaSize.width; + }, + _getBoundingHeight: function () { + return this._textAreaSize.height; + }, + + _changePosition: function(){ + this._adaptRenderers(); + }, + + setColor: function(color){ + cc.ProtectedNode.prototype.setColor.call(this, color); + this._labelRenderer.setColor(color); + }, + + setTextColor: function(color){ + this._labelRenderer.setFontFillColor(color); + }, + + getTextColor: function(){ + return this._labelRenderer._getFillStyle(); } }); -window._p = ccui.Text.prototype; +var _p = ccui.Text.prototype; // Extended properties /** @expose */ @@ -382,7 +467,7 @@ _p.boundingHeight; cc.defineGetterSetter(_p, "boundingHeight", _p._getBoundingHeight, _p._setBoundingHeight); /** @expose */ _p.string; -cc.defineGetterSetter(_p, "string", _p.getStringValue, _p.setText); +cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); /** @expose */ _p.stringLength; cc.defineGetterSetter(_p, "stringLength", _p.getStringLength); @@ -402,22 +487,28 @@ cc.defineGetterSetter(_p, "textAlign", _p.getTextHorizontalAlignment, _p.setText _p.verticalAlign; cc.defineGetterSetter(_p, "verticalAlign", _p.getTextVerticalAlignment, _p.setTextVerticalAlignment); -delete window._p; +_p = null; /** * allocates and initializes a UILabel. - * @constructs + * @deprecated since v3.0, please use new ccui.Text() instead. * @return {ccui.Text} - * @example - * // example - * var uiLabel = ccui.Text.create(); */ -ccui.Text.create = function () { - var uiLabel = new ccui.Text(); - if (uiLabel && uiLabel.init()) { - return uiLabel; - } - return null; +ccui.Label = ccui.Text.create = function (textContent, fontName, fontSize) { + return new ccui.Text(textContent, fontName, fontSize); }; -ccui.Text.RENDERER_ZORDER = -1; \ No newline at end of file +/** + * The zOrder value of ccui.Text's renderer. + * @constant + * @type {number} + */ +ccui.Text.RENDERER_ZORDER = -1; + +/** + * @ignore + */ +ccui.Text.Type = { + SYSTEM: 0, + TTF: 1 +}; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/UITextAtlas.js b/extensions/ccui/uiwidgets/UITextAtlas.js index 9c3a557cc8..bb7e0d27ca 100644 --- a/extensions/ccui/uiwidgets/UITextAtlas.js +++ b/extensions/ccui/uiwidgets/UITextAtlas.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccui.TextAtlas + * The text atlas control of Cocos UI. * @class * @extends ccui.Widget * @@ -36,15 +37,30 @@ ccui.TextAtlas = ccui.Widget.extend(/** @lends ccui.TextAtlas# */{ _itemWidth: 0, _itemHeight: 0, _startCharMap: "", - _className:"TextAtlas", - ctor: function () { + _className: "TextAtlas", + _labelAtlasRendererAdaptDirty: null, + + /** + * Allocates and initializes a UILabelAtlas.
    + * Constructor of ccui.TextAtlas, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {String} stringValue + * @param {String} charMapFile + * @param {number} itemWidth + * @param {number} itemHeight + * @param {String} startCharMap + * @example + * // example + * var uiLabelAtlas = new ccui.TextAtlas(); + */ + ctor: function (stringValue, charMapFile, itemWidth, itemHeight, startCharMap) { ccui.Widget.prototype.ctor.call(this); - this._labelAtlasRenderer = null; + startCharMap !== undefined && this.setProperty(stringValue, charMapFile, itemWidth, itemHeight, startCharMap); }, - initRenderer: function () { + _initRenderer: function () { this._labelAtlasRenderer = new cc.LabelAtlas(); - cc.Node.prototype.addChild.call(this, this._labelAtlasRenderer, ccui.TextAtlas.RENDERER_ZORDER, -1); + this._labelAtlasRenderer.setAnchorPoint(cc.p(0.5, 0.5)); + this.addProtectedChild(this._labelAtlasRenderer, ccui.TextAtlas.RENDERER_ZORDER, -1); }, /** @@ -61,155 +77,153 @@ ccui.TextAtlas = ccui.Widget.extend(/** @lends ccui.TextAtlas# */{ this._itemWidth = itemWidth; this._itemHeight = itemHeight; this._startCharMap = startCharMap; - var renderer = this._labelAtlasRenderer; - renderer.initWithString(stringValue, charMapFile, itemWidth, itemHeight, startCharMap[0]); - this.updateAnchorPoint(); - this.labelAtlasScaleChangedWithSize(); - - if (!renderer.textureLoaded()) { - renderer.addLoadedEventListener(function () { - this.labelAtlasScaleChangedWithSize(); - }, this); - } + + this._labelAtlasRenderer.initWithString( + stringValue, + this._charMapFileName, + this._itemWidth, + this._itemHeight, + this._startCharMap[0] + ); + + this._updateContentSizeWithTextureSize(this._labelAtlasRenderer.getContentSize()); + this._labelAtlasRendererAdaptDirty = true; }, /** - * set string value for labelatlas. + * Sets string value for ui text atlas. * @param {String} value */ - setStringValue: function (value) { + setString: function (value) { + if(value === this._labelAtlasRenderer.getString()) + return; this._stringValue = value; this._labelAtlasRenderer.setString(value); - this.labelAtlasScaleChangedWithSize(); + this._updateContentSizeWithTextureSize(this._labelAtlasRenderer.getContentSize()); + this._labelAtlasRendererAdaptDirty = true; + }, + + /** + * Sets string value for text atlas. + * @deprecated since v3.0, please use setString instead. + * @param {String} value + */ + setStringValue: function (value) { + cc.log("Please use the setString"); + this.setString(value); }, /** - * get string value for labelatlas. + * get string value for text atlas. + * @deprecated since v3.0, please use getString instead. * @returns {String} */ getStringValue: function () { + cc.log("Please use the getString"); + return this.getString(); + }, + + /** + * get string value for ui text atlas. + * @returns {String} + */ + getString: function () { return this._labelAtlasRenderer.getString(); }, /** - * override "setAnchorPoint" of widget. - * @param {cc.Point|Number} point The anchor point of UILabelAtlas or The anchor point.x of UILabelAtlas. - * @param {Number} [y] The anchor point.y of UILabelAtlas. + * Returns the length of string. + * @returns {*|Number|long|int} */ - setAnchorPoint: function (point, y) { - if (y === undefined) { - ccui.Widget.prototype.setAnchorPoint.call(this, point); - this._labelAtlasRenderer.setAnchorPoint(point); - } else { - ccui.Widget.prototype.setAnchorPoint.call(this, point, y); - this._labelAtlasRenderer.setAnchorPoint(point, y); - } + getStringLength: function(){ + return this._labelAtlasRenderer.getStringLength(); }, - _setAnchorX: function (value) { - ccui.Widget.prototype._setAnchorX.call(this, value); - this._labelAtlasRenderer._setAnchorX(value); - }, - _setAnchorY: function (value) { - ccui.Widget.prototype._setAnchorY.call(this, value); - this._labelAtlasRenderer._setAnchorY(value); - }, - - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.labelAtlasScaleChangedWithSize(); + + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._labelAtlasRendererAdaptDirty = true; + }, + + _adaptRenderers: function(){ + if (this._labelAtlasRendererAdaptDirty){ + this._labelAtlasScaleChangedWithSize(); + this._labelAtlasRendererAdaptDirty = false; + } }, /** - * override "getContentSize" method of widget. + * Returns the renderer's content size + * @overrider * @returns {cc.Size} */ - getContentSize: function () { + getVirtualRendererSize: function(){ return this._labelAtlasRenderer.getContentSize(); }, - _getWidth: function () { - return this._labelAtlasRenderer._getWidth(); - }, - _getHeight: function () { - return this._labelAtlasRenderer._getHeight(); - }, /** - * override "getVirtualRenderer" method of widget. + * Returns the renderer of ccui.TextAtlas. * @returns {cc.Node} */ getVirtualRenderer: function () { return this._labelAtlasRenderer; }, - labelAtlasScaleChangedWithSize: function () { + _labelAtlasScaleChangedWithSize: function () { + var locRenderer = this._labelAtlasRenderer; if (this._ignoreSize) { - this._labelAtlasRenderer.setScale(1.0); - var atlasRenderSize = this._labelAtlasRenderer.getContentSize(); - this._size.width = atlasRenderSize.width; - this._size.height = atlasRenderSize.height; - } - else { - var textureSize = this._labelAtlasRenderer.getContentSize(); + locRenderer.setScale(1.0); + } else { + var textureSize = locRenderer.getContentSize(); if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._labelAtlasRenderer.setScale(1.0); + locRenderer.setScale(1.0); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; - this._labelAtlasRenderer.setScaleX(scaleX); - this._labelAtlasRenderer.setScaleY(scaleY); + locRenderer.setScaleX(this._contentSize.width / textureSize.width); + locRenderer.setScaleY(this._contentSize.height / textureSize.height); } - }, - - updateTextureColor: function () { - this.updateColorToRenderer(this._labelAtlasRenderer); - }, - - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._labelAtlasRenderer); + locRenderer.setPosition(this._contentSize.width / 2.0, this._contentSize.height / 2.0); }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.TextAtlas. * @returns {string} */ getDescription: function () { return "LabelAtlas"; }, - createCloneInstance: function () { - return ccui.TextAtlas.create(); + _copySpecialProperties: function (labelAtlas) { + if (labelAtlas){ + this.setProperty(labelAtlas._stringValue, labelAtlas._charMapFileName, labelAtlas._itemWidth, labelAtlas._itemHeight, labelAtlas._startCharMap); + } }, - copySpecialProperties: function (labelAtlas) { - this.setProperty(labelAtlas._stringValue, labelAtlas._charMapFileName, labelAtlas._itemWidth, labelAtlas._itemHeight, labelAtlas._startCharMap); + _createCloneInstance: function () { + return new ccui.TextAtlas(); } }); -window._p = ccui.TextAtlas.prototype; +var _p = ccui.TextAtlas.prototype; // Extended properties /** @expose */ _p.string; -cc.defineGetterSetter(_p, "string", _p.getStringValue, _p.setStringValue); +cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); -delete window._p; +_p = null; /** * allocates and initializes a UILabelAtlas. - * @constructs + * @deprecated since v3.0, please use new ccui.TextAtlas() instead. * @return {ccui.TextAtlas} - * @example - * // example - * var uiLabelAtlas = ccui.TextAtlas.create(); */ -ccui.TextAtlas.create = function () { - var uiLabelAtlas = new ccui.TextAtlas(); - if (uiLabelAtlas && uiLabelAtlas.init()) { - return uiLabelAtlas; - } - return null; +ccui.TextAtlas.create = function (stringValue, charMapFile, itemWidth, itemHeight, startCharMap) { + return new ccui.TextAtlas(stringValue, charMapFile, itemWidth, itemHeight, startCharMap); }; // Constants +/** + * The zOrder value of ccui.TextAtlas's renderer. + * @type {number} + */ ccui.TextAtlas.RENDERER_ZORDER = -1; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/UITextBMFont.js b/extensions/ccui/uiwidgets/UITextBMFont.js index 99823bc98d..e77f043765 100644 --- a/extensions/ccui/uiwidgets/UITextBMFont.js +++ b/extensions/ccui/uiwidgets/UITextBMFont.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,191 +24,193 @@ ****************************************************************************/ /** - * Base class for ccui.TextBMFont + * The TextBMFont control of Cocos UI, it rendered by LabelBMFont. * @class * @extends ccui.Widget * * @property {String} string - Content string of the label */ -ccui.TextBMFont = ccui.Widget.extend(/** @lends ccui.TextBMFont# */{ +ccui.LabelBMFont = ccui.TextBMFont = ccui.Widget.extend(/** @lends ccui.TextBMFont# */{ _labelBMFontRenderer: null, - _fileHasInit: false, + _fntFileHasInit: false, _fntFileName: "", _stringValue: "", - _className:"TextBMFont", - ctor: function () { + _className: "TextBMFont", + _labelBMFontRendererAdaptDirty: true, + + /** + * Allocates and initializes a TextBMFont.
    + * Constructor of ccui.TextBMFont. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {String} text + * @param {String} filename + * @example + * // example + * var uiLabelBMFont = new ccui.TextBMFont(); + */ + ctor: function (text, filename) { ccui.Widget.prototype.ctor.call(this); - this._labelBMFontRenderer = null; - this._fileHasInit = false; + + if(filename != undefined){ + this.setFntFile(filename); + this.setString(text); + } }, - initRenderer: function () { - this._labelBMFontRenderer = cc.LabelBMFont.create(); - cc.Node.prototype.addChild.call(this, this._labelBMFontRenderer, ccui.TextBMFont.RENDERER_ZORDER, -1); + + _initRenderer: function () { + this._labelBMFontRenderer = new cc.LabelBMFont(); + this.addProtectedChild(this._labelBMFontRenderer, ccui.TextBMFont.RENDERER_ZORDER, -1); }, /** - * init a bitmap font atlas with an initial string and the FNT file + * Initializes a bitmap font atlas with an initial string and the FNT file * @param {String} fileName */ setFntFile: function (fileName) { - if (!fileName) { + if (!fileName) return; - } this._fntFileName = fileName; - this._labelBMFontRenderer.initWithString("", fileName); - this.updateAnchorPoint(); - this.labelBMFontScaleChangedWithSize(); - this._fileHasInit = true; - this.setText(this._stringValue); - - if (!this._labelBMFontRenderer.textureLoaded()) { - this._labelBMFontRenderer.addLoadedEventListener(function () { - this.labelBMFontScaleChangedWithSize(); - }, this); + + this._fntFileHasInit = true; + this._labelBMFontRenderer.initWithString(this._stringValue, fileName); + this._updateContentSizeWithTextureSize(this._labelBMFontRenderer.getContentSize()); + this._labelBMFontRendererAdaptDirty = true; + + var _self = this; + var locRenderer = _self._labelBMFontRenderer; + if(!locRenderer._textureLoaded){ + locRenderer.addEventListener("load", function(){ + _self.setFntFile(_self._fntFileName); + }); } }, /** - * set string value for labelbmfont + * Sets string value for TextBMFont + * @deprecated since v3.0, please use setString instead. * @param {String} value */ setText: function (value) { - if (!value) { + cc.log("Please use the setString"); + this.setString(value); + }, + + /** + * Sets string value for TextBMFont + * @param {String} value + */ + setString: function (value) { + if(value === this._labelBMFontRenderer.getString()) return; - } this._stringValue = value; this._labelBMFontRenderer.setString(value); - this.labelBMFontScaleChangedWithSize(); + if (!this._fntFileHasInit) + return; + this._updateContentSizeWithTextureSize(this._labelBMFontRenderer.getContentSize()); + this._labelBMFontRendererAdaptDirty = true; }, /** - * get string value for labelbmfont. + * Returns string value for TextBMFont. * @returns {String} */ - getStringValue: function () { + getString: function () { return this._stringValue; }, /** - * override "setAnchorPoint" of widget. - * @param {cc.Point|Number} point The anchor point of UILabelBMFont or The anchor point.x of UILabelBMFont. - * @param {Number} [y] The anchor point.y of UILabelBMFont. + * Returns the length of TextBMFont's string. + * @returns {Number} */ - setAnchorPoint: function (point, y) { - if(y === undefined){ - ccui.Widget.prototype.setAnchorPoint.call(this, point); - this._labelBMFontRenderer.setAnchorPoint(point); - } else { - ccui.Widget.prototype.setAnchorPoint.call(this, point, y); - this._labelBMFontRenderer.setAnchorPoint(point, y); - } + getStringLength: function(){ + return this._labelBMFontRenderer.getStringLength(); }, - _setAnchorX: function (value) { - ccui.Widget.prototype._setAnchorX.call(this, value); - this._labelBMFontRenderer._setAnchorX(value); - }, - _setAnchorY: function (value) { - ccui.Widget.prototype._setAnchorY.call(this, value); - this._labelBMFontRenderer._setAnchorY(value); - }, - - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.labelBMFontScaleChangedWithSize(); + + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._labelBMFontRendererAdaptDirty = true; + }, + + _adaptRenderers: function(){ + if (this._labelBMFontRendererAdaptDirty){ + this._labelBMFontScaleChangedWithSize(); + this._labelBMFontRendererAdaptDirty = false; + } }, /** - * get content size + * Returns TextBMFont's content size + * @override * @returns {cc.Size} */ - getContentSize: function () { + getVirtualRendererSize: function(){ return this._labelBMFontRenderer.getContentSize(); }, - _getWidth: function () { - return this._labelBMFontRenderer._getWidth(); - }, - _getHeight: function () { - return this._labelBMFontRenderer._getHeight(); - }, /** - * override "getVirtualRenderer" method of widget. + * Returns the renderer of TextBMFont + * @override * @returns {cc.Node} */ getVirtualRenderer: function () { return this._labelBMFontRenderer; }, - labelBMFontScaleChangedWithSize: function () { - if (this._ignoreSize) { - this._labelBMFontRenderer.setScale(1.0); - var rendererSize = this._labelBMFontRenderer.getContentSize(); - this._size.width = rendererSize.width; - this._size.height = rendererSize.height; - } + _labelBMFontScaleChangedWithSize: function () { + var locRenderer = this._labelBMFontRenderer; + if (this._ignoreSize) + locRenderer.setScale(1.0); else { - var textureSize = this._labelBMFontRenderer.getContentSize(); + var textureSize = locRenderer.getContentSize(); if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._labelBMFontRenderer.setScale(1.0); + locRenderer.setScale(1.0); return; } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; - this._labelBMFontRenderer.setScaleX(scaleX); - this._labelBMFontRenderer.setScaleY(scaleY); + locRenderer.setScaleX(this._contentSize.width / textureSize.width); + locRenderer.setScaleY(this._contentSize.height / textureSize.height); } - }, - - updateTextureColor: function () { - this.updateColorToRenderer(this._labelBMFontRenderer); - }, - - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._labelBMFontRenderer); + locRenderer.setPosition(this._contentSize.width / 2.0, this._contentSize.height / 2.0); }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.TextBMFont. * @returns {string} */ getDescription: function () { - return "LabelBMFont"; + return "TextBMFont"; }, - createCloneInstance: function () { - return ccui.TextBMFont.create(); + _createCloneInstance: function () { + return new ccui.TextBMFont(); }, - copySpecialProperties: function (labelBMFont) { + _copySpecialProperties: function (labelBMFont) { this.setFntFile(labelBMFont._fntFileName); - this.setText(labelBMFont._stringValue); + this.setString(labelBMFont._stringValue); } }); -window._p = ccui.TextBMFont.prototype; +var _p = ccui.TextBMFont.prototype; // Extended properties /** @expose */ _p.string; -cc.defineGetterSetter(_p, "string", _p.getStringValue, _p.setStringValue); +cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); -delete window._p; +_p = null; /** * allocates and initializes a UILabelBMFont. - * @constructs + * @deprecated since v3.0, please use new ccui.TextBMFont() instead. * @return {ccui.TextBMFont} - * @example - * // example - * var uiLabelBMFont = ccui.TextBMFont.create(); */ -ccui.TextBMFont.create = function () { - var uiLabelBMFont = new ccui.TextBMFont(); - if (uiLabelBMFont && uiLabelBMFont.init()) { - return uiLabelBMFont; - } - return null; +ccui.TextBMFont.create = function (text, filename) { + return new ccui.TextBMFont(text, filename); }; // Constants -ccui.TextBMFont.RENDERER_ZORDER = -1; \ No newline at end of file +/** + * The zOrder value of TextBMFont's renderer. + * @constant + * @type {number} + */ +ccui.TextBMFont.RENDERER_ZORDER = -1; diff --git a/extensions/ccui/uiwidgets/UITextField.js b/extensions/ccui/uiwidgets/UITextField.js index 711e371c48..8fd34e0173 100644 --- a/extensions/ccui/uiwidgets/UITextField.js +++ b/extensions/ccui/uiwidgets/UITextField.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,66 +24,48 @@ ****************************************************************************/ /** - * Base class for ccui.UICCTextField - * @class - * @extends cc.TextFieldTTF - * - * @property {Boolean} maxLengthEnabled - Indicate whether max length limit is enabled - * @property {Number} maxLength - The max length of the text field - * @property {Boolean} passwordEnabled - Indicate whether the text field is for entering password + * @ignore */ -ccui.UICCTextField = cc.TextFieldTTF.extend(/** @lends ccui.UICCTextField# */{ - maxLengthEnabled: false, - maxLength: 0, - passwordEnabled: false, +//it's a private class, it's a renderer of ccui.TextField. +ccui._TextFieldRenderer = cc.TextFieldTTF.extend({ + _maxLengthEnabled: false, + _maxLength: 0, + _passwordEnabled: false, _passwordStyleText: "", _attachWithIME: false, _detachWithIME: false, _insertText: false, _deleteBackward: false, - _className:"UICCTextField", + _className: "_TextFieldRenderer", + ctor: function () { cc.TextFieldTTF.prototype.ctor.call(this); - this.maxLengthEnabled = false; - this.maxLength = 0; - this.passwordEnabled = false; + this._maxLengthEnabled = false; + this._maxLength = 0; + this._passwordEnabled = false; this._passwordStyleText = "*"; this._attachWithIME = false; this._detachWithIME = false; this._insertText = false; this._deleteBackward = false; }, - init:function(){ - if(ccui.Widget.prototype.init.call(this)){ - this.setTouchEnabled(true); - return true; - } - return false; - }, + onEnter: function () { cc.TextFieldTTF.prototype.onEnter.call(this); - cc.TextFieldTTF.prototype.setDelegate.call(this,this); + cc.TextFieldTTF.prototype.setDelegate.call(this, this); }, - //CCTextFieldDelegate - onTextFieldAttachWithIME: function (sender) { this.setAttachWithIME(true); return false; }, onTextFieldInsertText: function (sender, text, len) { - if (len == 1 && text == "\n") { + if (len === 1 && text === "\n") return false; - } - this.setInsertText(true); - if (this.maxLengthEnabled) { - if (cc.TextFieldTTF.prototype.getCharCount.call(this) >= this.maxLength) { - return true; - } - } - return false; + this.setInsertText(true); + return (this._maxLengthEnabled) && (cc.TextFieldTTF.prototype.getCharCount.call(this) >= this._maxLength); }, onTextFieldDeleteBackward: function (sender, delText, nLen) { @@ -96,43 +79,31 @@ ccui.UICCTextField = cc.TextFieldTTF.extend(/** @lends ccui.UICCTextField# */{ }, insertText: function (text, len) { - var str_text = text; - var locString = cc.TextFieldTTF.prototype.getString.call(this); - var str_len = locString.length; - var multiple, header; - if (text != "\n") { - if (this.maxLengthEnabled) { - multiple = 1; - header = text.charCodeAt(0); - if (header < 0 || header > 127) { - multiple = 3; - } - - if (str_len + len > this.maxLength * multiple) { - str_text = str_text.substr(0, this.maxLength * multiple); - len = this.maxLength * multiple; + var input_text = text; + + if (text !== "\n"){ + if (this._maxLengthEnabled){ + var text_count = this.getString().length; + if (text_count >= this._maxLength){ + // password + if (this._passwordEnabled) + this.setPasswordText(this.getString()); + return; } } } - cc.TextFieldTTF.prototype.insertText.call(this,str_text, len); + cc.TextFieldTTF.prototype.insertText.call(this, input_text, len); // password - if (this.passwordEnabled) { - if (cc.TextFieldTTF.prototype.getCharCount.call(this) > 0) { - this.setPasswordText(this._inputText); - } - } + if (this._passwordEnabled && cc.TextFieldTTF.prototype.getCharCount.call(this) > 0) + this.setPasswordText(this.getString()); }, deleteBackward: function () { cc.TextFieldTTF.prototype.deleteBackward.call(this); - if (cc.TextFieldTTF.prototype.getCharCount.call(this) > 0) { - // password - if (this.passwordEnabled) { - this.setPasswordText(this._inputText); - } - } + if (cc.TextFieldTTF.prototype.getCharCount.call(this) > 0 && this._passwordEnabled) + this.setPasswordText(this._inputText); }, openIME: function () { @@ -142,23 +113,21 @@ ccui.UICCTextField = cc.TextFieldTTF.extend(/** @lends ccui.UICCTextField# */{ closeIME: function () { cc.TextFieldTTF.prototype.detachWithIME.call(this); }, - onDraw:function (sender) { - return false; - }, + setMaxLengthEnabled: function (enable) { - this.maxLengthEnabled = enable; + this._maxLengthEnabled = enable; }, isMaxLengthEnabled: function () { - return this.maxLengthEnabled; + return this._maxLengthEnabled; }, setMaxLength: function (length) { - this.maxLength = length; + this._maxLength = length; }, getMaxLength: function () { - return this.maxLength; + return this._maxLength; }, getCharCount: function () { @@ -166,29 +135,33 @@ ccui.UICCTextField = cc.TextFieldTTF.extend(/** @lends ccui.UICCTextField# */{ }, setPasswordEnabled: function (enable) { - this.passwordEnabled = enable; + this._passwordEnabled = enable; }, isPasswordEnabled: function () { - return this.passwordEnabled; + return this._passwordEnabled; }, setPasswordStyleText: function (styleText) { - if (styleText.length > 1) { + if (styleText.length > 1) return; - } var header = styleText.charCodeAt(0); - if (header < 33 || header > 126) { + if (header < 33 || header > 126) return; - } this._passwordStyleText = styleText; }, setPasswordText: function (text) { var tempStr = ""; - for (var i = 0; i < text.length; ++i) { + var text_count = text.length; + var max = text_count; + + if (this._maxLengthEnabled && text_count > this._maxLength) + max = this._maxLength; + + for (var i = 0; i < max; ++i) tempStr += this._passwordStyleText; - } + cc.LabelTTF.prototype.setString.call(this, tempStr); }, @@ -222,27 +195,30 @@ ccui.UICCTextField = cc.TextFieldTTF.extend(/** @lends ccui.UICCTextField# */{ getDeleteBackward: function () { return this._deleteBackward; + }, + + onDraw: function (sender) { + return false; } }); -ccui.UICCTextField.create = function (placeholder, fontName, fontSize) { - var ret = new ccui.UICCTextField(); +ccui._TextFieldRenderer.create = function (placeholder, fontName, fontSize) { + var ret = new ccui._TextFieldRenderer(); if (ret && ret.initWithString("", fontName, fontSize)) { - if (placeholder) { + if (placeholder) ret.setPlaceHolder(placeholder); - } return ret; } return null; }; /** - * Base class for ccui.TextField + * * @class * @extends ccui.Widget * * @property {String} string - The content string of the label - * @property {Number} placeHolder - The place holder of the text field + * @property {String} placeHolder - The place holder of the text field * @property {String} font - The text field font with a style string: e.g. "18px Verdana" * @property {String} fontName - The text field font name * @property {Number} fontSize - The text field font size @@ -251,471 +227,567 @@ ccui.UICCTextField.create = function (placeholder, fontName, fontSize) { * @property {Boolean} passwordEnabled - Indicate whether the text field is for entering password */ ccui.TextField = ccui.Widget.extend(/** @lends ccui.TextField# */{ - _textFieldRender: null, + _textFieldRenderer: null, _touchWidth: 0, _touchHeight: 0, _useTouchArea: false, _textFieldEventListener: null, _textFieldEventSelector: null, - _attachWithIMEListener: null, - _detachWithIMEListener: null, - _insertTextListener: null, - _deleteBackwardListener: null, - _attachWithIMESelector: null, - _detachWithIMESelector: null, - _insertTextSelector: null, - _deleteBackwardSelector: null, - _passwordStyleText:"", - ctor: function () { + _passwordStyleText: "", + _textFieldRendererAdaptDirty: true, + _fontName: "", + _fontSize: 12, + + _ccEventCallback: null, + + /** + * allocates and initializes a UITextField. + * Constructor of ccui.TextField. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @param {string} placeholder + * @param {string} fontName + * @param {Number} fontSize + * @example + * // example + * var uiTextField = new ccui.TextField(); + */ + ctor: function (placeholder, fontName, fontSize) { ccui.Widget.prototype.ctor.call(this); - this._textFieldRender = null; - this._touchWidth = 0; - this._touchHeight = 0; - this._useTouchArea = false; - - this._textFieldEventListener = null; - this._textFieldEventSelector = null; - this._attachWithIMEListener = null; - this._detachWithIMEListener = null; - this._insertTextListener = null; - this._deleteBackwardListener = null; - this._attachWithIMESelector = null; - this._detachWithIMESelector = null; - this._insertTextSelector = null; - this._deleteBackwardSelector = null; - }, - - onEnter:function(){ - ccui.Widget.prototype.onEnter.call(this); - this.setUpdateEnabled(true); + if (fontName) + this.setFontName(fontName); + if (fontSize) + this.setFontSize(fontSize); + if (placeholder) + this.setPlaceHolder(placeholder); }, - initRenderer: function () { - this._textFieldRender = ccui.UICCTextField.create("input words here", "Thonburi", 20); - cc.Node.prototype.addChild.call(this, this._textFieldRender, ccui.TextField.RENDERER_ZORDER, -1); + /** + * Initializes a ccui.TextField. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + * @override + */ + init: function(){ + if(ccui.Widget.prototype.init.call(this)){ + this.setTouchEnabled(true); + return true; + } + return false; + }, + /** + * Calls parent class' onEnter and schedules update function. + * @override + */ + onEnter: function () { + ccui.Widget.prototype.onEnter.call(this); + this.scheduleUpdate(); + }, + + _initRenderer: function () { + this._textFieldRenderer = ccui._TextFieldRenderer.create("input words here", "Thonburi", 20); + this.addProtectedChild(this._textFieldRenderer, ccui.TextField.RENDERER_ZORDER, -1); }, /** - * Set touch size + * Sets touch size of ccui.TextField. * @param {cc.Size} size */ setTouchSize: function (size) { - this._useTouchArea = true; this._touchWidth = size.width; this._touchHeight = size.height; }, /** - * Get touch size. + * Sets whether use touch area. + * @param enable + */ + setTouchAreaEnabled: function(enable){ + this._useTouchArea = enable; + }, + + /** + * Checks a point if is in ccui.TextField's space + * @param {cc.Point} pt + * @returns {boolean} + */ + hitTest: function(pt){ + if (this._useTouchArea) { + var nsp = this.convertToNodeSpace(pt); + var bb = cc.rect( + -this._touchWidth * this._anchorPoint.x, + -this._touchHeight * this._anchorPoint.y, + this._touchWidth, this._touchHeight + ); + + return ( nsp.x >= bb.x && nsp.x <= bb.x + bb.width && + nsp.y >= bb.y && nsp.y <= bb.y + bb.height ); + } else + return ccui.Widget.prototype.hitTest.call(this, pt); + }, + + /** + * Returns touch size of ccui.TextField. * @returns {cc.Size} */ - getTouchSize:function(){ - return cc.size(this._touchWidth,this._touchHeight); + getTouchSize: function () { + return cc.size(this._touchWidth, this._touchHeight); }, /** * Changes the string value of textField. + * @deprecated since v3.0, please use setString instead. * @param {String} text */ setText: function (text) { - if (!text) { + cc.log("Please use the setString"); + this.setString(text); + }, + + /** + * Changes the string value of textField. + * @param {String} text + */ + setString: function (text) { + if (text == null) return; - } + text = String(text); - if (this.isMaxLengthEnabled()) { + if (this.isMaxLengthEnabled()) text = text.substr(0, this.getMaxLength()); - } if (this.isPasswordEnabled()) { - this._textFieldRender.setPasswordText(text); - this._textFieldRender.insertText(text, text.length); - } - else { - this._textFieldRender.setString(text); - } - this._textFieldRender.setString(text); - this.textfieldRendererScaleChangedWithSize(); + this._textFieldRenderer.setPasswordText(text); + this._textFieldRenderer.setString(""); + this._textFieldRenderer.insertText(text, text.length); + } else + this._textFieldRenderer.setString(text); + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); }, /** + * Sets the placeholder string.
    + * display this string if string equal "". * @param {String} value */ setPlaceHolder: function (value) { - this._textFieldRender.setPlaceHolder(value); - this.textfieldRendererScaleChangedWithSize(); + this._textFieldRenderer.setPlaceHolder(value); + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); }, /** + * Returns the placeholder string. * @returns {String} */ - getPlaceHolder:function(){ - return this._textFieldRender.getPlaceHolder(); + getPlaceHolder: function () { + return this._textFieldRenderer.getPlaceHolder(); }, - _setFont: function (font) { - this._textFieldRender._setFont(font); - this.textfieldRendererScaleChangedWithSize(); - }, + /** + * Returns the color of ccui.TextField's place holder. + * @returns {cc.Color} + */ + getPlaceHolderColor: function(){ + return this._textFieldRenderer.getPlaceHolderColor(); + }, - _getFont: function () { - return this._textFieldRender._getFont(); - }, + /** + * Sets the place holder color to ccui.TextField. + * @param color + */ + setPlaceHolderColor: function(color){ + this._textFieldRenderer.setColorSpaceHolder(color); + }, /** - * Set font size for text field content - * @param {cc.Size} size + * Sets the text color to ccui.TextField + * @param textColor + */ + setTextColor: function(textColor){ + this._textFieldRenderer.setTextColor(textColor); + }, + + /** + * Sets font size for ccui.TextField. + * @param {Number} size */ setFontSize: function (size) { - this._textFieldRender.setFontSize(size); - this.textfieldRendererScaleChangedWithSize(); + this._textFieldRenderer.setFontSize(size); + this._fontSize = size; + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); }, - /** - * Get font size for text field content - * @param {cc.Size} size - */ - getFontSize: function () { - return this._textFieldRender.getFontSize(); - }, + /** + * Gets font size of ccui.TextField. + * @return {Number} size + */ + getFontSize: function () { + return this._fontSize; + }, /** - * Set font name for text field content + * Sets font name for ccui.TextField * @param {String} name */ setFontName: function (name) { - this._textFieldRender.setFontName(name); - this.textfieldRendererScaleChangedWithSize(); + this._textFieldRenderer.setFontName(name); + this._fontName = name; + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); }, - /** - * Get font name for text field content - * @param {cc.Size} size - */ - getFontName: function () { - return this._textFieldRender.getFontName(); - }, + /** + * Returns font name of ccui.TextField. + * @return {String} font name + */ + getFontName: function () { + return this._fontName; + }, /** * detach with IME */ didNotSelectSelf: function () { - this._textFieldRender.detachWithIME(); + this._textFieldRenderer.detachWithIME(); }, /** - * get textField string value + * Returns textField string value + * @deprecated since v3.0, please use getString instead. * @returns {String} */ getStringValue: function () { - return this._textFieldRender.getString(); + cc.log("Please use the getString"); + return this.getString(); }, /** - * touch began - * @param {cc.Point} touchPoint + * Returns string value of ccui.TextField. + * @returns {String} */ - onTouchBegan: function (touchPoint) { - var pass = ccui.Widget.prototype.onTouchBegan.call(this, touchPoint); - return pass; + getString: function () { + return this._textFieldRenderer.getString(); }, /** - * touch ended - * @param touchPoint + * Returns the length of ccui.TextField. + * @returns {Number} */ - onTouchEnded: function (touchPoint) { - ccui.Widget.prototype.onTouchEnded.call(this, touchPoint); - this._textFieldRender.attachWithIME(); + getStringLength: function(){ + return this._textFieldRenderer.getStringLength(); }, /** + * The touch began event callback handler. + * @param {cc.Point} touchPoint + */ + onTouchBegan: function (touchPoint, unusedEvent) { + var self = this; + var pass = ccui.Widget.prototype.onTouchBegan.call(self, touchPoint, unusedEvent); + if (self._hit) { + setTimeout(function(){ + self._textFieldRenderer.attachWithIME(); + }, 0); + }else{ + setTimeout(function(){ + self._textFieldRenderer.detachWithIME(); + }, 0); + } + return pass; + }, + + /** + * Sets Whether to open string length limit for ccui.TextField. * @param {Boolean} enable */ setMaxLengthEnabled: function (enable) { - this._textFieldRender.setMaxLengthEnabled(enable); + this._textFieldRenderer.setMaxLengthEnabled(enable); }, /** + * Returns Whether to open string length limit. * @returns {Boolean} */ isMaxLengthEnabled: function () { - return this._textFieldRender.isMaxLengthEnabled(); + return this._textFieldRenderer.isMaxLengthEnabled(); }, /** + * Sets the max length of ccui.TextField. Only when you turn on the string length limit, it is valid. * @param {number} length */ setMaxLength: function (length) { - this._textFieldRender.setMaxLength(length); + this._textFieldRenderer.setMaxLength(length); + this.setString(this.getString()); }, /** + * Returns the max length of ccui.TextField. * @returns {number} length */ getMaxLength: function () { - return this._textFieldRender.getMaxLength(); + return this._textFieldRenderer.getMaxLength(); }, /** + * Sets whether to open setting string as password character. * @param {Boolean} enable */ setPasswordEnabled: function (enable) { - this._textFieldRender.setPasswordEnabled(enable); + this._textFieldRenderer.setPasswordEnabled(enable); }, /** + * Returns whether to open setting string as password character. * @returns {Boolean} */ isPasswordEnabled: function () { - return this._textFieldRender.isPasswordEnabled(); + return this._textFieldRenderer.isPasswordEnabled(); }, /** - * @param {String} enable + * Sets the password style character, Only when you turn on setting string as password character, it is valid. + * @param styleText */ - setPasswordStyleText: function (styleText) { - this._textFieldRender.setPasswordStyleText(styleText); + setPasswordStyleText: function(styleText){ + this._textFieldRenderer.setPasswordStyleText(styleText); this._passwordStyleText = styleText; + + this.setString(this.getString()); }, /** + * Returns the password style character. * @returns {String} */ - getPasswordStyleText:function(){ + getPasswordStyleText: function () { return this._passwordStyleText; }, update: function (dt) { - if (this.getAttachWithIME()) { - this.attachWithIMEEvent(); - this.setAttachWithIME(false); - } if (this.getDetachWithIME()) { - this.detachWithIMEEvent(); + this._detachWithIMEEvent(); this.setDetachWithIME(false); } + if (this.getAttachWithIME()) { + this._attachWithIMEEvent(); + this.setAttachWithIME(false); + } if (this.getInsertText()) { - this.insertTextEvent(); - this.setInsertText(false); + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); - this.textfieldRendererScaleChangedWithSize(); + this._insertTextEvent(); + this.setInsertText(false); } if (this.getDeleteBackward()) { - this.deleteBackwardEvent(); + this._textFieldRendererAdaptDirty = true; + this._updateContentSizeWithTextureSize(this._textFieldRenderer.getContentSize()); + + this._deleteBackwardEvent(); this.setDeleteBackward(false); } }, /** - * get whether attach with IME. + * Returns whether attach with IME. * @returns {Boolean} */ getAttachWithIME: function () { - return this._textFieldRender.getAttachWithIME(); + return this._textFieldRenderer.getAttachWithIME(); }, /** - * set attach with IME. + * Sets attach with IME. * @param {Boolean} attach */ setAttachWithIME: function (attach) { - this._textFieldRender.setAttachWithIME(attach); + this._textFieldRenderer.setAttachWithIME(attach); }, /** - * get whether eetach with IME. + * Returns whether detach with IME. * @returns {Boolean} */ getDetachWithIME: function () { - return this._textFieldRender.getDetachWithIME(); + return this._textFieldRenderer.getDetachWithIME(); }, /** - * set detach with IME. + * Sets detach with IME. * @param {Boolean} detach */ setDetachWithIME: function (detach) { - this._textFieldRender.setDetachWithIME(detach); + this._textFieldRenderer.setDetachWithIME(detach); }, /** - * get insertText + * Returns insertText string of ccui.TextField. * @returns {String} */ getInsertText: function () { - return this._textFieldRender.getInsertText(); + return this._textFieldRenderer.getInsertText(); }, /** - * set insertText + * Sets insertText string to ccui.TextField. * @param {String} insertText */ setInsertText: function (insertText) { - this._textFieldRender.setInsertText(insertText); + this._textFieldRenderer.setInsertText(insertText); }, /** + * Returns the delete backward of ccui.TextField. * @returns {Boolean} */ getDeleteBackward: function () { - return this._textFieldRender.getDeleteBackward(); + return this._textFieldRenderer.getDeleteBackward(); }, /** + * Sets the delete backward of ccui.TextField. * @param {Boolean} deleteBackward */ setDeleteBackward: function (deleteBackward) { - this._textFieldRender.setDeleteBackward(deleteBackward); + this._textFieldRenderer.setDeleteBackward(deleteBackward); }, - attachWithIMEEvent: function () { - if (this._textFieldEventListener && this._textFieldEventSelector) { - this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_ATTACH_WITH_ME); + _attachWithIMEEvent: function () { + if(this._textFieldEventSelector){ + if (this._textFieldEventListener) + this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_ATTACH_WITH_IME); + else + this._textFieldEventSelector(this, ccui.TextField.EVENT_ATTACH_WITH_IME); + } + if (this._ccEventCallback){ + this._ccEventCallback(this, ccui.TextField.EVENT_ATTACH_WITH_IME); } }, - detachWithIMEEvent: function () { - if (this._textFieldEventListener && this._textFieldEventSelector) { - this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_DETACH_WITH_ME); + _detachWithIMEEvent: function () { + if(this._textFieldEventSelector){ + if (this._textFieldEventListener) + this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_DETACH_WITH_IME); + else + this._textFieldEventSelector(this, ccui.TextField.EVENT_DETACH_WITH_IME); } + if (this._ccEventCallback) + this._ccEventCallback(this, ccui.TextField.EVENT_DETACH_WITH_IME); }, - insertTextEvent: function () { - if (this._textFieldEventListener && this._textFieldEventSelector) { - this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_INSERT_TEXT); + _insertTextEvent: function () { + if(this._textFieldEventSelector){ + if (this._textFieldEventListener) + this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_INSERT_TEXT); + else + this._textFieldEventSelector(this, ccui.TextField.EVENT_INSERT_TEXT); //eventCallback } + if (this._ccEventCallback) + this._ccEventCallback(this, ccui.TextField.EVENT_INSERT_TEXT); }, - deleteBackwardEvent: function () { - if (this._textFieldEventListener && this._textFieldEventSelector) { - this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_DELETE_BACKWARD); + _deleteBackwardEvent: function () { + if(this._textFieldEventSelector){ + if (this._textFieldEventListener) + this._textFieldEventSelector.call(this._textFieldEventListener, this, ccui.TextField.EVENT_DELETE_BACKWARD); + else + this._textFieldEventSelector(this, ccui.TextField.EVENT_DELETE_BACKWARD); //eventCallback } + if (this._ccEventCallback) + this._ccEventCallback(this, ccui.TextField.EVENT_DELETE_BACKWARD); }, /** - * add event listener + * Adds event listener to cuci.TextField. + * @param {Object} [target=] * @param {Function} selector - * @param {Object} target + * @deprecated since v3.0, please use addEventListener instead. */ addEventListenerTextField: function (selector, target) { - this._textFieldEventSelector = selector; - this._textFieldEventListener = target; + this.addEventListener(selector, target); }, /** - * check hit - * @param {cc.Point} pt - * @returns {boolean} + * Adds event listener callback. + * @param {Object} [target=] + * @param {Function} selector */ - hitTest: function (pt) { - var nsp = this.convertToNodeSpace(pt); - var locSize = this._textFieldRender.getContentSize(); - var bb = cc.rect(-locSize.width * this._anchorPoint.x, -locSize.height * this._anchorPoint.y, locSize.width, locSize.height); - if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) { - return true; - } - return false; + addEventListener: function(selector, target){ + this._textFieldEventSelector = selector; //when target is undefined, _textFieldEventSelector is ccEventCallback. + this._textFieldEventListener = target; }, - /** - * override "setAnchorPoint" of widget. - * @param {cc.Point|Number} point The anchor point of UILabelBMFont or The anchor point.x of UILabelBMFont. - * @param {Number} [y] The anchor point.y of UILabelBMFont. - */ - setAnchorPoint: function (point, y) { - if(y === undefined){ - ccui.Widget.prototype.setAnchorPoint.call(this, point); - this._textFieldRender.setAnchorPoint(point); - } else { - ccui.Widget.prototype.setAnchorPoint.call(this, point, y); - this._textFieldRender.setAnchorPoint(point, y); - } + _onSizeChanged: function () { + ccui.Widget.prototype._onSizeChanged.call(this); + this._textFieldRendererAdaptDirty = true; }, - _setAnchorX: function (value) { - ccui.Widget.prototype._setAnchorX.call(this, value); - this._textFieldRender._setAnchorX(value); - }, - _setAnchorY: function (value) { - ccui.Widget.prototype._setAnchorY.call(this, value); - this._textFieldRender._setAnchorY(value); - }, - - onSizeChanged: function () { - ccui.Widget.prototype.onSizeChanged.call(this); - this.textfieldRendererScaleChangedWithSize(); - }, - - textfieldRendererScaleChangedWithSize: function () { - if (this._ignoreSize) { - this._textFieldRender.setScale(1.0); - var rendererSize = this.getContentSize(); - this._size.width = rendererSize.width; - this._size.height = rendererSize.height; + + _adaptRenderers: function(){ + if (this._textFieldRendererAdaptDirty) { + this._textfieldRendererScaleChangedWithSize(); + this._textFieldRendererAdaptDirty = false; } - else { - var textureSize = this.getContentSize(); - if (textureSize.width <= 0.0 || textureSize.height <= 0.0) { - this._textFieldRender.setScale(1.0); - return; - } - var scaleX = this._size.width / textureSize.width; - var scaleY = this._size.height / textureSize.height; - this._textFieldRender.setScaleX(scaleX); - this._textFieldRender.setScaleY(scaleY); + }, + + _textfieldRendererScaleChangedWithSize: function () { + if (!this._ignoreSize) + this._textFieldRenderer.setDimensions(this._contentSize); + this._textFieldRenderer.setPosition(this._contentSize.width / 2, this._contentSize.height / 2); + }, + + //@since v3.3 + getAutoRenderSize: function(){ + var virtualSize = this._textFieldRenderer.getContentSize(); + if (!this._ignoreSize) { + this._textFieldRenderer.setDimensions(0, 0); + virtualSize = this._textFieldRenderer.getContentSize(); + this._textFieldRenderer.setDimensions(this._contentSize.width, this._contentSize.height); } + return virtualSize; }, /** - * override "getContentSize" method of widget. + * Returns the ccui.TextField's content size. * @returns {cc.Size} */ - getContentSize: function () { - return this._textFieldRender.getContentSize(); + getVirtualRendererSize: function(){ + return this._textFieldRenderer.getContentSize(); }, - _getWidth: function () { - return this._textFieldRender._getWidth(); - }, - _getHeight: function () { - return this._textFieldRender._getHeight(); - }, /** - * override "getContentSize" method of widget. + * Returns the renderer of ccui.TextField. * @returns {cc.Node} */ getVirtualRenderer: function () { - return this._textFieldRender; - }, - - updateTextureColor: function () { - this.updateColorToRenderer(this._textFieldRender); - }, - - updateTextureOpacity: function () { - this.updateOpacityToRenderer(this._textFieldRender); + return this._textFieldRenderer; }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.TextField. * @returns {string} */ getDescription: function () { return "TextField"; }, + /** + * Open keyboard and receive input text. + * @return {Boolean} + */ attachWithIME: function () { - this._textFieldRender.attachWithIME(); + this._textFieldRenderer.attachWithIME(); }, - createCloneInstance: function () { - return ccui.TextField.create(); + _createCloneInstance: function () { + return new ccui.TextField(); }, - copySpecialProperties: function (textField) { - this.setText(textField._textFieldRender.getString()); - this.setPlaceHolder(textField.getStringValue()); - this.setFontSize(textField._textFieldRender.getFontSize()); - this.setFontName(textField._textFieldRender.getFontName()); + _copySpecialProperties: function (textField) { + this.setString(textField._textFieldRenderer.getString()); + this.setPlaceHolder(textField.getString()); + this.setFontSize(textField._textFieldRenderer.getFontSize()); + this.setFontName(textField._textFieldRenderer.getFontName()); this.setMaxLengthEnabled(textField.isMaxLengthEnabled()); this.setMaxLength(textField.getMaxLength()); this.setPasswordEnabled(textField.isPasswordEnabled()); @@ -724,15 +796,66 @@ ccui.TextField = ccui.Widget.extend(/** @lends ccui.TextField# */{ this.setDetachWithIME(textField.getDetachWithIME()); this.setInsertText(textField.getInsertText()); this.setDeleteBackward(textField.getDeleteBackward()); + this._ccEventCallback = textField._ccEventCallback; + this._textFieldEventListener = textField._textFieldEventListener; + this._textFieldEventSelector = textField._textFieldEventSelector; + }, + + /** + * Sets the text area size to ccui.TextField. + * @param {cc.Size} size + */ + setTextAreaSize: function(size){ + this.setContentSize(size); + }, + + /** + * Sets the text horizontal alignment of ccui.TextField. + * @param alignment + */ + setTextHorizontalAlignment: function(alignment){ + this._textFieldRenderer.setHorizontalAlignment(alignment); + }, + + /** + * Sets the text vertical alignment of ccui.TextField. + * @param alignment + */ + setTextVerticalAlignment: function(alignment){ + this._textFieldRenderer.setVerticalAlignment(alignment); + }, + _setFont: function (font) { + this._textFieldRenderer._setFont(font); + this._textFieldRendererAdaptDirty = true; + }, + + _getFont: function () { + return this._textFieldRenderer._getFont(); + }, + + _changePosition: function(){ + this._adaptRenderers(); } }); -window._p = ccui.TextField.prototype; +/** + * Creates a ccui.TextField. + * @deprecated since v3.0, please use new ccui.TextField() instead. + * @param {String} placeholder + * @param {String} fontName + * @param {Number} fontSize + * @returns {ccui.TextField} + */ +ccui.TextField.create = function(placeholder, fontName, fontSize){ + return new ccui.TextField(placeholder, fontName, fontSize); +}; + +var _p = ccui.TextField.prototype; // Extended properties /** @expose */ _p.string; -cc.defineGetterSetter(_p, "string", _p.getStringValue, _p.setText); +cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); /** @expose */ _p.placeHolder; cc.defineGetterSetter(_p, "placeHolder", _p.getPlaceHolder, _p.setPlaceHolder); @@ -755,29 +878,38 @@ cc.defineGetterSetter(_p, "maxLength", _p.getMaxLength, _p.setMaxLength); _p.passwordEnabled; cc.defineGetterSetter(_p, "passwordEnabled", _p.isPasswordEnabled, _p.setPasswordEnabled); -delete window._p; - -/** - * allocates and initializes a UITextField. - * @constructs - * @return {ccui.TextField} - * @example - * // example - * var uiTextField = ccui.TextField.create(); - */ -ccui.TextField.create = function () { - var uiTextField = new ccui.TextField(); - if (uiTextField && uiTextField.init()) { - return uiTextField; - } - return null; -}; +_p = null; // Constants //TextField event -ccui.TextField.EVENT_ATTACH_WITH_ME = 0; -ccui.TextField.EVENT_DETACH_WITH_ME = 1; +/** + * The attach with IME event flag of ccui.TextField + * @constant + * @type {number} + */ +ccui.TextField.EVENT_ATTACH_WITH_IME = 0; +/** + * The detach with IME event flag of ccui.TextField + * @constant + * @type {number} + */ +ccui.TextField.EVENT_DETACH_WITH_IME = 1; +/** + * The insert text event flag of ccui.TextField + * @constant + * @type {number} + */ ccui.TextField.EVENT_INSERT_TEXT = 2; +/** + * The delete backward event flag of ccui.TextField + * @constant + * @type {number} + */ ccui.TextField.EVENT_DELETE_BACKWARD = 3; +/** + * The zOrder value of ccui.TextField's renderer. + * @constant + * @type {number} + */ ccui.TextField.RENDERER_ZORDER = -1; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/scroll-widget/UIListView.js b/extensions/ccui/uiwidgets/scroll-widget/UIListView.js index 0c5be09bd6..370dd411b3 100644 --- a/extensions/ccui/uiwidgets/scroll-widget/UIListView.js +++ b/extensions/ccui/uiwidgets/scroll-widget/UIListView.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,35 +24,54 @@ ****************************************************************************/ /** - * Base class for ccui.ListView + * The list view control of Cocos UI. * @class * @extends ccui.ScrollView + * @example + * var listView = new ccui.ListView(); + * // set list view ex direction + * listView.setDirection(ccui.ScrollView.DIR_VERTICAL); + * listView.setTouchEnabled(true); + * listView.setBounceEnabled(true); + * listView.setBackGroundImage("res/cocosui/green_edit.png"); + * listView.setBackGroundImageScale9Enabled(true); + * listView.setContentSize(cc.size(240, 130)); + * this.addChild(listView); */ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ _model: null, _items: null, _gravity: null, _itemsMargin: 0, - _listViewEventListener: null, - _listViewEventSelector: null, + _curSelectedIndex: 0, _refreshViewDirty: true, - _className:"ListView", + + _listViewEventListener: null, + _listViewEventSelector: null, + /** + * allocates and initializes a UIListView. + * Constructor of ccui.ListView, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @example + * // example + * var aListView = new ccui.ListView(); + */ ctor: function () { ccui.ScrollView.prototype.ctor.call(this); - this._model = null; this._items = []; - this._gravity = ccui.ListView.GRAVITY_CENTER_HORIZONTAL; - this._itemsMargin = 0; - this._listViewEventListener = null; - this._listViewEventSelector = null; - this._curSelectedIndex = 0; - this._refreshViewDirty = true; + this._gravity = ccui.ListView.GRAVITY_CENTER_VERTICAL; + this.setTouchEnabled(true); + + this.init(); }, + /** + * Initializes a ccui.ListView. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + * @override + */ init: function () { if (ccui.ScrollView.prototype.init.call(this)) { - this._items = []; this.setLayoutType(ccui.Layout.LINEAR_VERTICAL); return true; } @@ -59,198 +79,206 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ }, /** - * Sets a item model for listview. A model will be cloned for adding default item. + * Sets a item model for ListView. A model will be cloned for adding default item. * @param {ccui.Widget} model */ setItemModel: function (model) { - if (!model) { + if (!model){ + cc.log("Can't set a null to item model!"); return; } + this._model = model; }, - updateInnerContainerSize: function () { + _updateInnerContainerSize: function () { + var locItems = this._items, length, i; switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: - var length = this._items.length; + length = locItems.length; var totalHeight = (length - 1) * this._itemsMargin; - for (var i = 0; i < length; i++) { - var item = this._items[i]; - totalHeight += item.getSize().height; + for (i = 0; i < length; i++) { + totalHeight += locItems[i].getContentSize().height; } - var finalWidth = this._size.width; - var finalHeight = totalHeight; - this.setInnerContainerSize(cc.size(finalWidth, finalHeight)); + this.setInnerContainerSize(cc.size(this._contentSize.width, totalHeight)); break; case ccui.ScrollView.DIR_HORIZONTAL: - var length = this._items.length; + length = locItems.length; var totalWidth = (length - 1) * this._itemsMargin; - for (var i = 0; i < length; i++) { - var item = this._items[i]; - totalWidth += item.getSize().width; + for (i = 0; i < length; i++) { + totalWidth += locItems[i].getContentSize().width; } - var finalWidth = totalWidth; - var finalHeight = this._size.height; - this.setInnerContainerSize(cc.size(finalWidth, finalHeight)); + this.setInnerContainerSize(cc.size(totalWidth, this._contentSize.height)); break; default: break; } }, - remedyLayoutParameter: function (item) { - if (!item) { - return; + _remedyLayoutParameter: function (item) { + cc.assert(null != item, "ListView Item can't be nil!"); + + var linearLayoutParameter = item.getLayoutParameter(); + var isLayoutParameterExists = true; + if (!linearLayoutParameter) { + linearLayoutParameter = new ccui.LinearLayoutParameter(); + isLayoutParameterExists = false; } + var itemIndex = this.getIndex(item); switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: - var llp = item.getLayoutParameter(ccui.LayoutParameter.LINEAR); - if (!llp) { - var defaultLp = ccui.LinearLayoutParameter.create(); - switch (this._gravity) { - case ccui.ListView.GRAVITY_LEFT: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_LEFT); - break; - case ccui.ListView.GRAVITY_RIGHT: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_RIGHT); - break; - case ccui.ListView.GRAVITY_CENTER_HORIZONTAL: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL); - break; - default: - break; - } - if (this.getIndex(item) == 0) { - defaultLp.setMargin(ccui.MarginZero()); - } - else { - defaultLp.setMargin(new ccui.Margin(0.0, this._itemsMargin, 0.0, 0.0)); - } - item.setLayoutParameter(defaultLp); - } - else { - if (this.getIndex(item) == 0) { - llp.setMargin(ccui.MarginZero()); - } - else { - llp.setMargin(new ccui.Margin(0, this._itemsMargin, 0, 0)); - } - switch (this._gravity) { - case ccui.ListView.GRAVITY_LEFT: - llp.setGravity(ccui.LINEAR_GRAVITY_LEFT); - break; - case ccui.ListView.GRAVITY_RIGHT: - llp.setGravity(ccui.LINEAR_GRAVITY_RIGHT); - break; - case ccui.ListView.GRAVITY_CENTER_HORIZONTAL: - llp.setGravity(ccui.LINEAR_GRAVITY_CENTER_HORIZONTAL); - break; - default: - break; - } - } + this._remedyVerticalLayoutParameter(linearLayoutParameter, itemIndex); break; case ccui.ScrollView.DIR_HORIZONTAL: - var llp = item.getLayoutParameter(ccui.LayoutParameter.LINEAR); - if (!llp) { - var defaultLp = ccui.LinearLayoutParameter.create(); - switch (this._gravity) { - case ccui.ListView.GRAVITY_TOP: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_TOP); - break; - case ccui.ListView.GRAVITY_BOTTOM: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_BOTTOM); - break; - case ccui.ListView.GRAVITY_CENTER_VERTICAL: - defaultLp.setGravity(ccui.LINEAR_GRAVITY_CENTER_VERTICAL); - break; - default: - break; - } - if (this.getIndex(item) == 0) { - defaultLp.setMargin(ccui.MarginZero()); - } - else { - defaultLp.setMargin(new ccui.Margin(this._itemsMargin, 0.0, 0.0, 0.0)); - } - item.setLayoutParameter(defaultLp); - } - else { - if (this.getIndex(item) == 0) { - llp.setMargin(ccui.MarginZero()); - } - else { - llp.setMargin(new ccui.Margin(this._itemsMargin, 0.0, 0.0, 0.0)); - } - switch (this._gravity) { - case ccui.ListView.GRAVITY_TOP: - llp.setGravity(ccui.LINEAR_GRAVITY_TOP); - break; - case ccui.ListView.GRAVITY_BOTTOM: - llp.setGravity(ccui.LINEAR_GRAVITY_BOTTOM); - break; - case ccui.ListView.GRAVITY_CENTER_VERTICAL: - llp.setGravity(ccui.LINEAR_GRAVITY_CENTER_VERTICAL); - break; - default: - break; - } - } + this._remedyHorizontalLayoutParameter(linearLayoutParameter, itemIndex); + break; + default: + break; + } + if (!isLayoutParameterExists) + item.setLayoutParameter(linearLayoutParameter); + }, + + //@since v3.3 + _remedyVerticalLayoutParameter: function (layoutParameter, itemIndex) { + cc.assert(null != layoutParameter, "Layout parameter can't be nil!"); + + switch (this._gravity) { + case ccui.ListView.GRAVITY_LEFT: + layoutParameter.setGravity(ccui.LinearLayoutParameter.LEFT); + break; + case ccui.ListView.GRAVITY_RIGHT: + layoutParameter.setGravity(ccui.LinearLayoutParameter.RIGHT); + break; + case ccui.ListView.GRAVITY_CENTER_HORIZONTAL: + layoutParameter.setGravity(ccui.LinearLayoutParameter.CENTER_HORIZONTAL); + break; + default: + break; + } + if (0 === itemIndex) + layoutParameter.setMargin(ccui.MarginZero()); + else + layoutParameter.setMargin(new ccui.Margin(0.0, this._itemsMargin, 0.0, 0.0)); + }, + + //@since v3.3 + _remedyHorizontalLayoutParameter: function (layoutParameter, itemIndex) { + cc.assert(null != layoutParameter, "Layout parameter can't be nil!"); + + switch (this._gravity) { + case ccui.ListView.GRAVITY_TOP: + layoutParameter.setGravity(ccui.LinearLayoutParameter.TOP); + break; + case ccui.ListView.GRAVITY_BOTTOM: + layoutParameter.setGravity(ccui.LinearLayoutParameter.BOTTOM); + break; + case ccui.ListView.GRAVITY_CENTER_VERTICAL: + layoutParameter.setGravity(ccui.LinearLayoutParameter.CENTER_VERTICAL); break; default: break; } + if (0 === itemIndex) + layoutParameter.setMargin(ccui.MarginZero()); + else + layoutParameter.setMargin(new ccui.Margin(this._itemsMargin, 0.0, 0.0, 0.0)); }, /** - * Push back a default item(create by a cloned model) into listview. + * Push back a default item(create by a cloned model) into ListView. */ pushBackDefaultItem: function () { - if (!this._model) { + if (this._model == null) return; - } var newItem = this._model.clone(); - this._items.push(newItem); - this.remedyLayoutParameter(newItem); + this._remedyLayoutParameter(newItem); this.addChild(newItem); this._refreshViewDirty = true; }, /** - * Insert a default item(create by a cloned model) into listview. + * Insert a default item(create by a cloned model) into ListView. * @param {Number} index */ insertDefaultItem: function (index) { - if (!this._model) { + if (this._model == null) return; - } var newItem = this._model.clone(); this._items.splice(index, 0, newItem); - this.remedyLayoutParameter(newItem); - this.addChild(newItem); + ccui.ScrollView.prototype.addChild.call(this, newItem); + this._remedyLayoutParameter(newItem); + this._refreshViewDirty = true; }, /** - * Push back custom item into listview. + * Push back custom item into ListView. * @param {ccui.Widget} item */ pushBackCustomItem: function (item) { - this._items.push(item); - this.remedyLayoutParameter(item); + this._remedyLayoutParameter(item); this.addChild(item); this._refreshViewDirty = true; }, /** - * Push back custom item into listview. + * add child to ListView + * @override + * @param {cc.Node} widget + * @param {Number} [zOrder] + * @param {Number|String} [tag] tag or name + */ + addChild: function (widget, zOrder, tag) { + if (widget) { + zOrder = zOrder || widget.getLocalZOrder(); + tag = tag || widget.getName(); + ccui.ScrollView.prototype.addChild.call(this, widget, zOrder, tag); + if(widget instanceof ccui.Widget) + this._items.push(widget); + } + }, + + /** + * remove child from ListView + * @override + * @param {cc.Node} widget + * @param {Boolean} [cleanup=true] + */ + removeChild: function(widget, cleanup){ + if (widget) { + var index = this._items.indexOf(widget); + if(index > -1) + this._items.splice(index, 1); + ccui.ScrollView.prototype.removeChild.call(this, widget, cleanup); + } + }, + + /** + * Removes all children from ccui.ListView. + */ + removeAllChildren: function(){ + this.removeAllChildrenWithCleanup(true); + }, + + /** + * Removes all children from ccui.ListView and do a cleanup all running actions depending on the cleanup parameter. + * @param {Boolean} cleanup + */ + removeAllChildrenWithCleanup: function(cleanup){ + ccui.ScrollView.prototype.removeAllChildrenWithCleanup.call(this, cleanup); + this._items = []; + }, + + /** + * Push back custom item into ccui.ListView. * @param {ccui.Widget} item * @param {Number} index */ insertCustomItem: function (item, index) { this._items.splice(index, 0, item); - this.remedyLayoutParameter(item); - this.addChild(item); + ccui.ScrollView.prototype.addChild.call(this, item); + this._remedyLayoutParameter(item); this._refreshViewDirty = true; }, @@ -260,30 +288,34 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ */ removeItem: function (index) { var item = this.getItem(index); - if (!item) { + if (item == null) return; - } - cc.arrayRemoveObject(this._items, item); - this.removeChild(item); + this.removeChild(item, true); this._refreshViewDirty = true; }, /** - * Removes the last item of listview. + * Removes the last item of ccui.ListView. */ removeLastItem: function () { this.removeItem(this._items.length - 1); }, + /** + * Removes all items from ccui.ListView. + */ + removeAllItems: function(){ + this.removeAllChildren(); + }, + /** * Returns a item whose index is same as the parameter. * @param {Number} index - * @returns {cc.Widget} + * @returns {ccui.Widget} */ getItem: function (index) { - if (index < 0 || index >= this._items.length) { + if (index < 0 || index >= this._items.length) return null; - } return this._items[index]; }, @@ -297,21 +329,22 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ /** * Returns the index of item. - * @param {ccui.Widget} item - * @returns {Number} + * @param {ccui.Widget} item the item which need to be checked. + * @returns {Number} the index of item. */ getIndex: function (item) { + if(item == null) + return -1; return this._items.indexOf(item); }, /** - * Changes the gravity of listview. + * Changes the gravity of ListView. * @param {ccui.ListView.GRAVITY_LEFT|ccui.ListView.GRAVITY_RIGHT|ccui.ListView.GRAVITY_CENTER_HORIZONTAL|ccui.ListView.GRAVITY_BOTTOM|ccui.ListView.GRAVITY_CENTER_VERTICAL} gravity */ setGravity: function (gravity) { - if (this._gravity == gravity) { + if (this._gravity === gravity) return; - } this._gravity = gravity; this._refreshViewDirty = true; }, @@ -321,15 +354,14 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ * @param {Number} margin */ setItemsMargin: function (margin) { - if (this._itemsMargin == margin) { + if (this._itemsMargin === margin) return; - } this._itemsMargin = margin; this._refreshViewDirty = true; }, /** - * Get the margin between each item. + * Returns the margin between each item. * @returns {Number} */ getItemsMargin:function(){ @@ -337,7 +369,7 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ }, /** - * Changes scroll direction of scrollview. + * Changes scroll direction of ccui.ListView. * @param {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} dir */ setDirection: function (dir) { @@ -355,90 +387,123 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ break; } ccui.ScrollView.prototype.setDirection.call(this, dir); + }, + /** + * Requests refresh list view. + */ + requestRefreshView: function () { + this._refreshViewDirty = true; + }, + + /** + * Refreshes list view. + */ + refreshView: function () { + var locItems = this._items; + for (var i = 0; i < locItems.length; i++) { + var item = locItems[i]; + item.setLocalZOrder(i); + this._remedyLayoutParameter(item); + } + this._updateInnerContainerSize(); + }, + + /** + * provides a public _doLayout function for Editor. it calls _doLayout. + */ + doLayout: function(){ + this._doLayout(); + }, + + _doLayout: function(){ + ccui.Layout.prototype._doLayout.call(this); + if (this._refreshViewDirty) { + this.refreshView(); + this._refreshViewDirty = false; + } }, /** - * add event listener + * Adds event listener to ccui.ListView. * @param {Function} selector - * @param {Object} target + * @param {Object} [target=] + * @deprecated since v3.0, please use addEventListener instead. */ addEventListenerListView: function (selector, target) { + this.addEventListener(selector, target); + }, + + /** + * Adds event listener to ccui.ListView. + * @param {Function} selector + * @param {Object} [target=] + */ + addEventListener: function(selector, target){ this._listViewEventListener = target; this._listViewEventSelector = selector; }, - selectedItemEvent: function () { - if(this._listViewEventSelector&&this._listViewEventListener){ - this._listViewEventSelector.call(this._listViewEventListener, this, ccui.ListView.EVENT_SELECTED_ITEM); + _selectedItemEvent: function (event) { + var eventEnum = (event === ccui.Widget.TOUCH_BEGAN) ? ccui.ListView.ON_SELECTED_ITEM_START : ccui.ListView.ON_SELECTED_ITEM_END; + if(this._listViewEventSelector){ + if (this._listViewEventListener) + this._listViewEventSelector.call(this._listViewEventListener, this, eventEnum); + else + this._listViewEventSelector(this, eventEnum); } + if(this._ccEventCallback) + this._ccEventCallback(this, eventEnum); }, - interceptTouchEvent: function (handleState, sender, touchPoint) { - ccui.ScrollView.prototype.interceptTouchEvent.call(this, handleState, sender, touchPoint); - if (handleState != 1) { + /** + * Intercept touch event, handle its child's touch event. + * @param {Number} eventType + * @param {ccui.Widget} sender + * @param {cc.Touch} touch + */ + interceptTouchEvent: function (eventType, sender, touch) { + ccui.ScrollView.prototype.interceptTouchEvent.call(this, eventType, sender, touch); + if (eventType !== ccui.Widget.TOUCH_MOVED) { var parent = sender; while (parent) { - if (parent && parent.getParent() == this._innerContainer) { + if (parent && parent.getParent() === this._innerContainer) { this._curSelectedIndex = this.getIndex(parent); break; } parent = parent.getParent(); } - this.selectedItemEvent(); + if (sender.isHighlighted()) + this._selectedItemEvent(eventType); } }, /** - * get current selected index + * Returns current selected index * @returns {number} */ getCurSelectedIndex: function () { return this._curSelectedIndex; }, - /** - * request refresh view - */ - requestRefreshView: function () { - this._refreshViewDirty = true; - }, - - refreshView: function () { - for (var i = 0; i < this._items.length; i++) { - var item = this._items[i]; - item.setLocalZOrder(i); - this.remedyLayoutParameter(item); - } - this.updateInnerContainerSize(); - }, - - sortAllChildren: function () { - ccui.ScrollView.prototype.sortAllChildren.call(this); - if (this._refreshViewDirty) { - this.refreshView(); - this._refreshViewDirty = false; - } - }, - - onSizeChanged: function () { - ccui.ScrollView.prototype.onSizeChanged.call(this); + _onSizeChanged: function () { + ccui.ScrollView.prototype._onSizeChanged.call(this); this._refreshViewDirty = true; }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.ListView. * @returns {string} */ getDescription: function () { return "ListView"; }, - createCloneInstance: function () { - return ccui.ListView.create(); + _createCloneInstance: function () { + return new ccui.ListView(); }, - copyClonedWidgetChildren: function (model) { + _copyClonedWidgetChildren: function (model) { var arrayItems = model.getItems(); for (var i = 0; i < arrayItems.length; i++) { var item = arrayItems[i]; @@ -446,30 +511,92 @@ ccui.ListView = ccui.ScrollView.extend(/** @lends ccui.ListView# */{ } }, - copySpecialProperties: function (listView) { - ccui.ScrollView.prototype.copySpecialProperties.call(this, listView); - this.setItemModel(listView._model); - this.setItemsMargin(listView._itemsMargin); - this.setGravity(listView._gravity); + _copySpecialProperties: function (listView) { + if(listView instanceof ccui.ListView){ + ccui.ScrollView.prototype._copySpecialProperties.call(this, listView); + this.setItemModel(listView._model); + this.setItemsMargin(listView._itemsMargin); + this.setGravity(listView._gravity); + + this._listViewEventListener = listView._listViewEventListener; + this._listViewEventSelector = listView._listViewEventSelector; + } + }, + + //v3.3 + forceDoLayout: function(){ + if (this._refreshViewDirty) { + this.refreshView(); + this._refreshViewDirty = false; + } + this._innerContainer.forceDoLayout(); } }); +/** + * allocates and initializes a UIListView. + * @deprecated since v3.0, please use new ccui.ListView() instead. + */ ccui.ListView.create = function () { - var uiListView = new ccui.ListView(); - if (uiListView && uiListView.init()) { - return uiListView; - } - return null; + return new ccui.ListView(); }; // Constants //listView event type +/** + * The flag selected item of ccui.ListView's event. + * @constant + * @type {number} + */ ccui.ListView.EVENT_SELECTED_ITEM = 0; +/** + * The flag selected item start of ccui.ListView's event. + * @constant + * @type {number} + */ +ccui.ListView.ON_SELECTED_ITEM_START = 0; +/** + * The flag selected item end of ccui.ListView's event. + * @constant + * @type {number} + */ +ccui.ListView.ON_SELECTED_ITEM_END = 1; + //listView gravity +/** + * The left flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_LEFT = 0; +/** + * The right flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_RIGHT = 1; +/** + * The center horizontal flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_CENTER_HORIZONTAL = 2; +/** + * The top flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_TOP = 3; +/** + * The bottom flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_BOTTOM = 4; +/** + * The center vertical flag of ccui.ListView's gravity. + * @constant + * @type {number} + */ ccui.ListView.GRAVITY_CENTER_VERTICAL = 5; \ No newline at end of file diff --git a/extensions/ccui/uiwidgets/scroll-widget/UIPageView.js b/extensions/ccui/uiwidgets/scroll-widget/UIPageView.js index ff0b8e2543..49210ef9b2 100644 --- a/extensions/ccui/uiwidgets/scroll-widget/UIPageView.js +++ b/extensions/ccui/uiwidgets/scroll-widget/UIPageView.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,212 +24,196 @@ ****************************************************************************/ /** - * Base class for ccui.PageView + * The PageView control of Cocos UI. * @class * @extends ccui.Layout + * @exmaple + * var pageView = new ccui.PageView(); + * pageView.setTouchEnabled(true); + * pageView.addPage(new ccui.Layout()); + * this.addChild(pageView); */ ccui.PageView = ccui.Layout.extend(/** @lends ccui.PageView# */{ _curPageIdx: 0, _pages: null, - _touchMoveDir: null, + _touchMoveDirection: null, _touchStartLocation: 0, _touchMoveStartLocation: 0, _movePagePoint: null, - _leftChild: null, - _rightChild: null, + _leftBoundaryChild: null, + _rightBoundaryChild: null, _leftBoundary: 0, _rightBoundary: 0, + _isAutoScrolling: false, _autoScrollDistance: 0, _autoScrollSpeed: 0, - _autoScrollDir: 0, + _autoScrollDirection: 0, + _childFocusCancelOffset: 0, _pageViewEventListener: null, _pageViewEventSelector: null, _className:"PageView", + //v3.2 + _customScrollThreshold: 0, + _usingCustomScrollThreshold: false, + + /** + * Allocates and initializes a UIPageView. + * Constructor of ccui.PageView. please do not call this function by yourself, you should pass the parameters to constructor to initialize it
. + * @example + * // example + * var uiPageView = new ccui.PageView(); + */ ctor: function () { ccui.Layout.prototype.ctor.call(this); - this._curPageIdx = 0; this._pages = []; - this._touchMoveDir = ccui.PageView.TOUCH_DIR_LEFT; - this._touchStartLocation = 0; - this._touchMoveStartLocation = 0; + this._touchMoveDirection = ccui.PageView.TOUCH_DIR_LEFT; + this._movePagePoint = null; - this._leftChild = null; - this._rightChild = null; - this._leftBoundary = 0; - this._rightBoundary = 0; - this._isAutoScrolling = false; - this._autoScrollDistance = 0; - this._autoScrollSpeed = 0; - this._autoScrollDir = 0; + this._leftBoundaryChild = null; + this._rightBoundaryChild = null; + this._childFocusCancelOffset = 5; this._pageViewEventListener = null; this._pageViewEventSelector = null; + this.setTouchEnabled(true); }, + /** + * Initializes a ccui.PageView. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + */ init: function () { if (ccui.Layout.prototype.init.call(this)) { - this._pages = []; this.setClippingEnabled(true); - this.setTouchEnabled(true); return true; } return false; }, + /** + * Calls the parent class' onEnter and schedules update function. + * @override + */ onEnter:function(){ ccui.Layout.prototype.onEnter.call(this); - this.setUpdateEnabled(true); + this.scheduleUpdate(true); }, /** - * Add a widget to a page of pageview. - * @param {ccui.Widget} widget - * @param {number} pageIdx - * @param {Boolean} forceCreate + * Add a widget to a page of PageView. + * @param {ccui.Widget} widget widget to be added to PageView. + * @param {number} pageIdx index of page. + * @param {Boolean} forceCreate if force create and there is no page exist, PageView would create a default page for adding widget. */ addWidgetToPage: function (widget, pageIdx, forceCreate) { - if (!widget) { - return; - } - if(pageIdx<0){ + if (!widget || pageIdx < 0) return; - } - var pageCount = this._pages.length; - if (pageIdx >= pageCount) { + + var pageCount = this._getPageCount(); + if (pageIdx < 0 || pageIdx >= pageCount) { if (forceCreate) { - if (pageIdx > pageCount) { + if (pageIdx > pageCount) cc.log("pageIdx is %d, it will be added as page id [%d]", pageIdx, pageCount); - } - var newPage = this.createPage(); + var newPage = this._createPage(); newPage.addChild(widget); this.addPage(newPage); } - } - else { + } else { var page = this._pages[pageIdx]; - if (page) { + if (page) page.addChild(widget); - } } }, - /** - * create page - * @returns {ccui.Layout} - */ - createPage: function () { - var newPage = ccui.Layout.create(); - newPage.setSize(this.getSize()); + _createPage: function () { + var newPage = new ccui.Layout(); + newPage.setContentSize(this.getContentSize()); return newPage; }, /** - * Push back a page to pageview. + * Adds a page to ccui.PageView. * @param {ccui.Layout} page */ addPage: function (page) { - if (!page) { - return; - } - if (page.getWidgetType() != ccui.Widget.TYPE_CONTAINER) { + if (!page || this._pages.indexOf(page) !== -1) return; - } - if (this._pages.indexOf(page) != -1) { - return; - } - var pSize = page.getSize(); - var pvSize = this.getSize(); - if (!(pSize.width==pvSize.width&&pSize.height==pvSize.height)) { - cc.log("page size does not match pageview size, it will be force sized!"); - page.setSize(pvSize); - } - page.setPosition(this.getPositionXByIndex(this._pages.length), 0); - this._pages.push(page); + this.addChild(page); - this.updateBoundaryPages(); + this._pages.push(page); + this._doLayoutDirty = true; }, /** - * Inert a page to pageview. - * @param {ccui.Layout} page - * @param {Number} idx + * Inserts a page in the specified location. + * @param {ccui.Layout} page page to be added to PageView. + * @param {Number} idx index */ insertPage: function (page, idx) { - if (idx < 0) { + if (idx < 0 || !page || this._pages.indexOf(page) !== -1) return; - } - if (!page) { - return; - } - if (page.getWidgetType() != ccui.Widget.TYPE_CONTAINER) { - return; - } - if (this._pages.indexOf(page) != -1) { - return; - } - var pageCount = this._pages.length; - if (idx >= pageCount) { + var pageCount = this._getPageCount(); + if (idx >= pageCount) this.addPage(page); - } else { - this._pages.splice(idx, 0, page); - page.setPosition(this.getPositionXByIndex(idx), 0); + this._pages[idx] = page; this.addChild(page); - var pSize = page.getSize(); - var pvSize = this.getSize(); - if (!pSize.equals(pvSize)) { - cc.log("page size does not match pageview size, it will be force sized!"); - page.setSize(pvSize); - } - var arrayPages = this._pages; - var length = arrayPages.length; - for (var i = (idx + 1); i < length; i++) { - var behindPage = arrayPages[i]; - var formerPos = behindPage.getPosition(); - behindPage.setPosition(formerPos.x + this.getSize().width, 0); - } - this.updateBoundaryPages(); } + this._doLayoutDirty = true; }, /** - * Remove a page of pageview. + * Removes a page from PageView. * @param {ccui.Layout} page */ removePage: function (page) { - if (!page) { + if (!page) return; - } this.removeChild(page); - this.updateChildrenPosition(); - this.updateBoundaryPages(); + var index = this._pages.indexOf(page); + if(index > -1) + this._pages.splice(index, 1); + this._doLayoutDirty = true; }, /** - * Remove a page at index of pageview. + * Removes a page at index of PageView. * @param {number} index */ removePageAtIndex: function (index) { - if (index < 0 || index >= this._pages.length) { + if (index < 0 || index >= this._pages.length) return; - } var page = this._pages[index]; - if (page) { + if (page) this.removePage(page); - } }, - updateBoundaryPages: function () { - if (this._pages.length <= 0) { - this._leftChild = null; - this._rightChild = null; + /** + * Removes all pages from PageView + */ + removeAllPages: function(){ + var locPages = this._pages; + for(var i = 0, len = locPages.length; i < len; i++) + this.removeChild(locPages[i]); + this._pages.length = 0; + }, + + _updateBoundaryPages: function () { + var locPages = this._pages; + if (locPages.length <= 0) { + this._leftBoundaryChild = null; + this._rightBoundaryChild = null; return; } - this._leftChild = this._pages[0]; - this._rightChild = this._pages[this._pages.length-1]; + this._leftBoundaryChild = locPages[0]; + this._rightBoundaryChild = locPages[locPages.length - 1]; + }, + + _getPageCount: function(){ + return this._pages.length; }, /** @@ -236,203 +221,192 @@ ccui.PageView = ccui.Layout.extend(/** @lends ccui.PageView# */{ * @param {number} idx * @returns {number} */ - getPositionXByIndex: function (idx) { - return (this.getSize().width * (idx - this._curPageIdx)); - }, - - /** - * Add widget - * @param {ccui.Widget} widget - * @param {Number} zOrder - * @param {Number} tag - * @returns {boolean} - */ - addChild: function (widget, zOrder, tag) { - return ccui.Layout.prototype.addChild.call(this, widget, zOrder, tag); + _getPositionXByIndex: function (idx) { + return (this.getContentSize().width * (idx - this._curPageIdx)); }, - /** - * remove widget child override - * @param {ccui.Widget} child - * @param {Boolean} cleanup - */ - removeChild: function (child, cleanup) { - if(cleanup) - cc.arrayRemoveObject(this._pages, child); - ccui.Layout.prototype.removeChild.call(this, child, cleanup); + _onSizeChanged: function () { + ccui.Layout.prototype._onSizeChanged.call(this); + this._rightBoundary = this.getContentSize().width; + this._doLayoutDirty = true; }, - onSizeChanged: function () { - ccui.Layout.prototype.onSizeChanged.call(this); - this._rightBoundary = this.getSize().width; - this.updateChildrenSize(); - this.updateChildrenPosition(); + _updateAllPagesSize: function(){ + var selfSize = this.getContentSize(); + var locPages = this._pages; + for (var i = 0, len = locPages.length; i < len; i++) + locPages[i].setContentSize(selfSize); }, - updateChildrenSize: function () { - if (!this._pages.length <= 0) { - return; - } - - var selfSize = this.getSize(); - for (var i = 0; i < this._pages.length; i++) { - var page = this._pages[i]; - page.setSize(selfSize); - } - }, - - updateChildrenPosition: function () { - if (!this._pages) { - return; - } - - var pageCount = this._pages.length; + _updateAllPagesPosition: function(){ + var pageCount = this._getPageCount(); if (pageCount <= 0) { this._curPageIdx = 0; return; } - if (this._curPageIdx >= pageCount) { - this._curPageIdx = pageCount - 1; - } - var pageWidth = this.getSize().width; - var arrayPages = this._pages; - for (var i = 0; i < pageCount; i++) { - var page = arrayPages[i]; - page.setPosition((i - this._curPageIdx) * pageWidth, 0); - } - }, - removeAllChildren: function (cleanup) { - if(cleanup) - this._pages.length = 0; - ccui.Layout.prototype.removeAllChildren.call(this, cleanup); + if (this._curPageIdx >= pageCount) + this._curPageIdx = pageCount-1; + + var pageWidth = this.getContentSize().width; + var locPages = this._pages; + for (var i=0; i< pageCount; i++) + locPages[i].setPosition(cc.p((i - this._curPageIdx) * pageWidth, 0)); }, /** - * scroll pageview to index. - * @param {number} idx + * scroll PageView to index. + * @param {number} idx index of page. */ scrollToPage: function (idx) { - if (idx < 0 || idx >= this._pages.length) { + if (idx < 0 || idx >= this._pages.length) return; - } this._curPageIdx = idx; var curPage = this._pages[idx]; - this._autoScrollDistance = -(curPage.getPositionX()); + this._autoScrollDistance = -(curPage.getPosition().x); this._autoScrollSpeed = Math.abs(this._autoScrollDistance) / 0.2; - this._autoScrollDir = this._autoScrollDistance > 0 ? 1 : 0; + this._autoScrollDirection = this._autoScrollDistance > 0 ? ccui.PageView.DIRECTION_RIGHT : ccui.PageView.DIRECTION_LEFT; this._isAutoScrolling = true; }, + /** + * Called once per frame. Time is the number of seconds of a frame interval. + * @override + * @param {Number} dt + */ update: function (dt) { - if (this._isAutoScrolling) { - switch (this._autoScrollDir) { - case 0: - var step = this._autoScrollSpeed * dt; - if (this._autoScrollDistance + step >= 0.0) { - step = -this._autoScrollDistance; - this._autoScrollDistance = 0.0; - this._isAutoScrolling = false; - } - else { - this._autoScrollDistance += step; - } - this.scrollPages(-step); - if(!this._isAutoScrolling){ - this.pageTurningEvent(); - } - break; - break; - case 1: - var step = this._autoScrollSpeed * dt; - if (this._autoScrollDistance - step <= 0.0) { - step = this._autoScrollDistance; - this._autoScrollDistance = 0.0; - this._isAutoScrolling = false; - } - else { - this._autoScrollDistance -= step; - } - this.scrollPages(step); - if(!this._isAutoScrolling){ - this.pageTurningEvent(); - } - break; - default: - break; - } - } + if (this._isAutoScrolling) + this._autoScroll(dt); }, - onTouchBegan: function (touch,event) { - var pass = ccui.Layout.prototype.onTouchBegan.call(this, touch,event); - if (this._hitted){ - this.handlePressLogic(touch.getLocation()); - } - return pass; + /** + * Does nothing. ccui.PageView's layout type is ccui.Layout.ABSOLUTE. + * @override + * @param {Number} type + */ + setLayoutType:function(type){ }, - onTouchMoved: function (touch,event) { - var touchPoint = touch.getLocation(); - this._touchMovePos.x = touchPoint.x; - this._touchMovePos.y = touchPoint.y; - this.handleMoveLogic(touchPoint); - var widgetParent = this.getWidgetParent(); - if (widgetParent) { - widgetParent.checkChildInfo(1, this, touchPoint); - } - this.moveEvent(); - if (!this.hitTest(touchPoint)) { - this.setFocused(false); - this.onTouchEnded(touch,event); + /** + * Returns the layout type of ccui.PageView. it's always ccui.Layout.ABSOLUTE. + * @returns {number} + */ + getLayoutType: function(){ + return ccui.Layout.ABSOLUTE; + }, + + _autoScroll: function(dt){ + var step; + switch (this._autoScrollDirection) { + case ccui.PageView.DIRECTION_LEFT: + step = this._autoScrollSpeed * dt; + if (this._autoScrollDistance + step >= 0.0) { + step = -this._autoScrollDistance; + this._autoScrollDistance = 0.0; + this._isAutoScrolling = false; + } else + this._autoScrollDistance += step; + this._scrollPages(-step); + if(!this._isAutoScrolling) + this._pageTurningEvent(); + break; + break; + case ccui.PageView.DIRECTION_RIGHT: + step = this._autoScrollSpeed * dt; + if (this._autoScrollDistance - step <= 0.0) { + step = this._autoScrollDistance; + this._autoScrollDistance = 0.0; + this._isAutoScrolling = false; + } else + this._autoScrollDistance -= step; + this._scrollPages(step); + if(!this._isAutoScrolling) + this._pageTurningEvent(); + break; + default: + break; } }, + /** + * The touch moved event callback handler of ccui.PageView. + * @override + * @param {cc.Touch} touch + * @param {cc.Event} event + */ + onTouchMoved: function (touch, event) { + ccui.Layout.prototype.onTouchMoved.call(this, touch, event); + if (!this._isInterceptTouch) + this._handleMoveLogic(touch); + }, + + /** + * The touch ended event callback handler of ccui.PageView. + * @override + * @param {cc.Touch} touch + * @param {cc.Event} event + */ onTouchEnded: function (touch, event) { ccui.Layout.prototype.onTouchEnded.call(this, touch, event); - this.handleReleaseLogic(this._touchEndPos); + if (!this._isInterceptTouch) + this._handleReleaseLogic(touch); + this._isInterceptTouch = false; }, + /** + * The touch canceled event callback handler of ccui.PageView. + * @param {cc.Touch} touch + * @param {cc.Event} event + */ onTouchCancelled: function (touch, event) { - var touchPoint = touch.getLocation(); ccui.Layout.prototype.onTouchCancelled.call(this, touch, event); - this.handleReleaseLogic(touchPoint); + if (!this._isInterceptTouch) + this._handleReleaseLogic(touch); + this._isInterceptTouch = false; }, - movePages: function (offset) { + _doLayout: function(){ + if (!this._doLayoutDirty) + return; + + this._updateAllPagesPosition(); + this._updateAllPagesSize(); + this._updateBoundaryPages(); + this._doLayoutDirty = false; + }, + + _movePages: function (offset) { var arrayPages = this._pages; var length = arrayPages.length; for (var i = 0; i < length; i++) { var child = arrayPages[i]; - var pos = child.getPosition(); - child.setPosition(pos.x + offset, pos.y); + //var pos = child.getPosition(); + //child.setPosition(pos.x + offset, pos.y); + child.setPositionX(child.getPositionX() + offset); } }, - scrollPages: function (touchOffset) { - if (this._pages.length <= 0) { + _scrollPages: function (touchOffset) { + if (this._pages.length <= 0) return false; - } - - if (!this._leftChild || !this._rightChild) { + if (!this._leftBoundaryChild || !this._rightBoundaryChild) return false; - } var realOffset = touchOffset; - - switch (this._touchMoveDir) { + switch (this._touchMoveDirection) { case ccui.PageView.TOUCH_DIR_LEFT: // left - if (this._rightChild.getRightInParent() + touchOffset <= this._rightBoundary) { - realOffset = this._rightBoundary - this._rightChild.getRightInParent(); - this.movePages(realOffset); + var rightBoundary = this._rightBoundaryChild.getRightBoundary(); + if (rightBoundary + touchOffset <= this._rightBoundary) { + realOffset = this._rightBoundary - rightBoundary; + this._movePages(realOffset); return false; } break; - case ccui.PageView.TOUCH_DIR_RIGHT: // right - if (this._leftChild.getLeftInParent() + touchOffset >= this._leftBoundary) { - realOffset = this._leftBoundary - this._leftChild.getLeftInParent(); - this.movePages(realOffset); + var leftBoundary = this._leftBoundaryChild.getLeftBoundary(); + if (leftBoundary + touchOffset >= this._leftBoundary) { + realOffset = this._leftBoundary - leftBoundary; + this._movePages(realOffset); return false; } break; @@ -440,104 +414,156 @@ ccui.PageView = ccui.Layout.extend(/** @lends ccui.PageView# */{ break; } - this.movePages(realOffset); + this._movePages(realOffset); return true; }, - handlePressLogic: function (touchPoint) { - var nsp = this.convertToNodeSpace(touchPoint); - this._touchMoveStartLocation = nsp.x; - this._touchStartLocation = nsp.x; + _handleMoveLogic: function (touch) { + var offset = touch.getLocation().x - touch.getPreviousLocation().x; + if (offset < 0) + this._touchMoveDirection = ccui.PageView.TOUCH_DIR_LEFT; + else if (offset > 0) + this._touchMoveDirection = ccui.PageView.TOUCH_DIR_RIGHT; + this._scrollPages(offset); }, - handleMoveLogic: function (touchPoint) { - var nsp = this.convertToNodeSpace(touchPoint); - var offset = 0.0; - var moveX = nsp.x; - offset = moveX - this._touchMoveStartLocation; - this._touchMoveStartLocation = moveX; - if (offset < 0) { - this._touchMoveDir = ccui.PageView.TOUCH_DIR_LEFT; - } - else if (offset > 0) { - this._touchMoveDir = ccui.PageView.TOUCH_DIR_RIGHT; - } - this.scrollPages(offset); + /** + * Set custom scroll threshold to page view. If you don't specify the value, the pageView will scroll when half page view width reached. + * @since v3.2 + * @param threshold + */ + setCustomScrollThreshold: function(threshold){ + cc.assert(threshold>0, "Invalid threshold!"); + this._customScrollThreshold = threshold; + this.setUsingCustomScrollThreshold(true); + }, + + /** + * Returns user defined scroll page threshold. + * @since v3.2 + */ + getCustomScrollThreshold: function(){ + return this._customScrollThreshold; }, - handleReleaseLogic: function (touchPoint) { - if (this._pages.length <= 0) { + /** + * Set using user defined scroll page threshold or not. If you set it to false, then the default scroll threshold is pageView.width / 2. + * @since v3.2 + */ + setUsingCustomScrollThreshold: function(flag){ + this._usingCustomScrollThreshold = flag; + }, + + /** + * Queries whether we are using user defined scroll page threshold or not + */ + isUsingCustomScrollThreshold: function(){ + return this._usingCustomScrollThreshold; + }, + + _handleReleaseLogic: function (touchPoint) { + if (this._pages.length <= 0) return; - } var curPage = this._pages[this._curPageIdx]; if (curPage) { var curPagePos = curPage.getPosition(); var pageCount = this._pages.length; var curPageLocation = curPagePos.x; var pageWidth = this.getSize().width; - var boundary = pageWidth / 2.0; + if (!this._usingCustomScrollThreshold) + this._customScrollThreshold = pageWidth / 2.0; + var boundary = this._customScrollThreshold; if (curPageLocation <= -boundary) { if (this._curPageIdx >= pageCount - 1) - this.scrollPages(-curPageLocation); + this._scrollPages(-curPageLocation); else this.scrollToPage(this._curPageIdx + 1); - } - else if (curPageLocation >= boundary) { + } else if (curPageLocation >= boundary) { if (this._curPageIdx <= 0) - this.scrollPages(-curPageLocation); + this._scrollPages(-curPageLocation); else this.scrollToPage(this._curPageIdx - 1); - } - else { + } else this.scrollToPage(this._curPageIdx); - } } }, - checkChildInfo: function (handleState, sender, touchPoint) { - if(this._enabled && this._touchEnabled) - this.interceptTouchEvent(handleState, sender, touchPoint); - }, - - interceptTouchEvent: function (handleState, sender, touchPoint) { - switch (handleState) { - case 0: - this.handlePressLogic(touchPoint); + /** + * Intercept touch event, handle its child's touch event. + * @param {Number} eventType event type + * @param {ccui.Widget} sender + * @param {cc.Touch} touch + */ + interceptTouchEvent: function (eventType, sender, touch) { + var touchPoint = touch.getLocation(); + switch (eventType) { + case ccui.Widget.TOUCH_BEGAN: + this._touchBeganPosition.x = touchPoint.x; + this._touchBeganPosition.y = touchPoint.y; + this._isInterceptTouch = true; break; - case 1: + case ccui.Widget.TOUCH_MOVED: + this._touchMovePosition.x = touchPoint.x; + this._touchMovePosition.y = touchPoint.y; var offset = 0; - offset = Math.abs(sender.getTouchStartPos().x - touchPoint.x); + offset = Math.abs(sender.getTouchBeganPosition().x - touchPoint.x); if (offset > this._childFocusCancelOffset) { - sender.setFocused(false); - this.handleMoveLogic(touchPoint); + sender.setHighlighted(false); + this._handleMoveLogic(touch); } break; - case 2: - this.handleReleaseLogic(touchPoint); - break; - - case 3: + case ccui.Widget.TOUCH_ENDED: + case ccui.Widget.TOUCH_CANCELED: + this._touchEndPosition.x = touchPoint.x; + this._touchEndPosition.y = touchPoint.y; + this._handleReleaseLogic(touch); + if (sender.isSwallowTouches()) + this._isInterceptTouch = false; break; } }, - pageTurningEvent: function () { - if (this._pageViewEventListener && this._pageViewEventSelector) { - this._pageViewEventSelector.call(this._pageViewEventListener, this, ccui.PageView.EVENT_TURNING); + _pageTurningEvent: function () { + if(this._pageViewEventSelector){ + if (this._pageViewEventListener) + this._pageViewEventSelector.call(this._pageViewEventListener, this, ccui.PageView.EVENT_TURNING); + else + this._pageViewEventSelector(this, ccui.PageView.EVENT_TURNING); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.PageView.EVENT_TURNING); }, /** + * Adds event listener to ccui.PageView. * @param {Function} selector - * @param {Object} target + * @param {Object} [target=] + * @deprecated since v3.0, please use addEventListener instead. */ addEventListenerPageView: function (selector, target) { + this.addEventListener(selector, target); + }, + + /** + * Adds event listener to ccui.PageView. + * @param {Function} selector + * @param {Object} [target=] + */ + addEventListener: function(selector, target){ this._pageViewEventSelector = selector; this._pageViewEventListener = target; }, /** - * get pages + * Returns current page index + * @returns {number} + */ + getCurPageIndex: function () { + return this._curPageIdx; + }, + + /** + * Returns all pages of PageView * @returns {Array} */ getPages:function(){ @@ -545,26 +571,29 @@ ccui.PageView = ccui.Layout.extend(/** @lends ccui.PageView# */{ }, /** - * get cur page index - * @returns {number} + * Returns a page from PageView by index + * @param {Number} index + * @returns {ccui.Layout} */ - getCurPageIndex: function () { - return this._curPageIdx; + getPage: function(index){ + if (index < 0 || index >= this._pages.length) + return null; + return this._pages[index]; }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.PageView. * @returns {string} */ getDescription: function () { return "PageView"; }, - createCloneInstance: function () { - return ccui.PageView.create(); + _createCloneInstance: function () { + return new ccui.PageView(); }, - copyClonedWidgetChildren: function (model) { + _copyClonedWidgetChildren: function (model) { var arrayPages = model.getPages(); for (var i = 0; i < arrayPages.length; i++) { var page = arrayPages[i]; @@ -572,36 +601,57 @@ ccui.PageView = ccui.Layout.extend(/** @lends ccui.PageView# */{ } }, - copySpecialProperties: function (pageView) { - ccui.Layout.prototype.copySpecialProperties.call(this, pageView); - }, - - _doLayout: function () { - if (!this._doLayoutDirty) - return; - this._doLayoutDirty = false; + _copySpecialProperties: function (pageView) { + ccui.Layout.prototype._copySpecialProperties.call(this, pageView); + this._ccEventCallback = pageView._ccEventCallback; + this._pageViewEventListener = pageView._pageViewEventListener; + this._pageViewEventSelector = pageView._pageViewEventSelector; + this._usingCustomScrollThreshold = pageView._usingCustomScrollThreshold; + this._customScrollThreshold = pageView._customScrollThreshold; } }); /** * allocates and initializes a UIPageView. - * @constructs + * @deprecated since v3.0, please use new ccui.PageView() instead. * @return {ccui.PageView} - * @example - * // example - * var uiPageView = ccui.PageView.create(); */ ccui.PageView.create = function () { - var uiPageView = new ccui.PageView(); - if (uiPageView && uiPageView.init()) { - return uiPageView; - } - return null; + return new ccui.PageView(); }; // Constants //PageView event +/** + * The turning flag of ccui.PageView's event. + * @constant + * @type {number} + */ ccui.PageView.EVENT_TURNING = 0; //PageView touch direction +/** + * The left flag of ccui.PageView's touch direction. + * @constant + * @type {number} + */ ccui.PageView.TOUCH_DIR_LEFT = 0; -ccui.PageView.TOUCH_DIR_RIGHT = 1; \ No newline at end of file +/** + * The right flag of ccui.PageView's touch direction. + * @constant + * @type {number} + */ +ccui.PageView.TOUCH_DIR_RIGHT = 1; + +//PageView auto scroll direction +/** + * The right flag of ccui.PageView's auto scroll direction. + * @constant + * @type {number} + */ +ccui.PageView.DIRECTION_LEFT = 0; +/** + * The right flag of ccui.PageView's auto scroll direction. + * @constant + * @type {number} + */ +ccui.PageView.DIRECTION_RIGHT = 1; diff --git a/extensions/ccui/uiwidgets/scroll-widget/UIScrollView.js b/extensions/ccui/uiwidgets/scroll-widget/UIScrollView.js index 293dbe3873..db3227ffbc 100644 --- a/extensions/ccui/uiwidgets/scroll-widget/UIScrollView.js +++ b/extensions/ccui/uiwidgets/scroll-widget/UIScrollView.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccui.ScrollView + * The ScrollView control of Cocos UI * @class * @extends ccui.Layout * @@ -36,86 +37,76 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ _innerContainer: null, direction: null, - _touchBeganPoint: null, - _touchMovedPoint: null, - _touchEndedPoint: null, - _touchMovingPoint: null, _autoScrollDir: null, - _topBoundary: 0,//test - _bottomBoundary: 0,//test + + _topBoundary: 0, + _bottomBoundary: 0, _leftBoundary: 0, _rightBoundary: 0, + _bounceTopBoundary: 0, _bounceBottomBoundary: 0, _bounceLeftBoundary: 0, _bounceRightBoundary: 0, + _autoScroll: false, _autoScrollAddUpTime: 0, + _autoScrollOriginalSpeed: 0, _autoScrollAcceleration: 0, _isAutoScrollSpeedAttenuated: false, _needCheckAutoScrollDestination: false, _autoScrollDestination: null, + _bePressed: false, _slidTime: 0, _moveChildPoint: null, _childFocusCancelOffset: 0, + _leftBounceNeeded: false, _topBounceNeeded: false, _rightBounceNeeded: false, _bottomBounceNeeded: false, + bounceEnabled: false, _bouncing: false, _bounceDir: null, _bounceOriginalSpeed: 0, inertiaScrollEnabled: false, + _scrollViewEventListener: null, _scrollViewEventSelector: null, - _className:"ScrollView", + _className: "ScrollView", + + /** + * Allocates and initializes a UIScrollView. + * Constructor of ccui.ScrollView. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @example + * // example + * var uiScrollView = new ccui.ScrollView(); + */ ctor: function () { ccui.Layout.prototype.ctor.call(this); - this._innerContainer = null; this.direction = ccui.ScrollView.DIR_NONE; - this._touchBeganPoint = cc.p(0, 0); - this._touchMovedPoint = cc.p(0, 0); - this._touchEndedPoint = cc.p(0, 0); - this._touchMovingPoint = cc.p(0, 0); this._autoScrollDir = cc.p(0, 0); - this._topBoundary = 0;//test - this._bottomBoundary = 0;//test - this._leftBoundary = 0; - this._rightBoundary = 0; - this._bounceTopBoundary = 0; - this._bounceBottomBoundary = 0; - this._bounceLeftBoundary = 0; - this._bounceRightBoundary = 0; - this._autoScroll = false; - this._autoScrollAddUpTime = 0; - this._autoScrollOriginalSpeed = 0; + this._autoScrollAcceleration = -1000; - this._isAutoScrollSpeedAttenuated = false; - this._needCheckAutoScrollDestination = false; this._autoScrollDestination = cc.p(0, 0); - this._bePressed = false; this._slidTime = 0; this._moveChildPoint = cc.p(0, 0); this._childFocusCancelOffset = 5; - this._leftBounceNeeded = false; - this._topBounceNeeded = false; - this._rightBounceNeeded = false; - this._bottomBounceNeeded = false; - this.bounceEnabled = false; - this._bouncing = false; this._bounceDir = cc.p(0, 0); this._bounceOriginalSpeed = 0; this.inertiaScrollEnabled = true; - this._scrollViewEventListener = null; - this._scrollViewEventSelector = null; + this.setTouchEnabled(true); }, + /** + * Initializes a ccui.ScrollView. Please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + */ init: function () { if (ccui.Layout.prototype.init.call(this)) { - this.setTouchEnabled(true); this.setClippingEnabled(true); this._innerContainer.setTouchEnabled(false); return true; @@ -123,20 +114,46 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ return false; }, - onEnter:function(){ + /** + * Calls the parent class' onEnter and schedules update function. + * @override + */ + onEnter: function () { ccui.Layout.prototype.onEnter.call(this); - this.setUpdateEnabled(true); + this.scheduleUpdate(true); + }, + + /** + * When a widget is in a layout, you could call this method to get the next focused widget within a specified direction.
    + * If the widget is not in a layout, it will return itself + * + * @param {Number} direction the direction to look for the next focused widget in a layout + * @param {ccui.Widget} current the current focused widget + * @returns {ccui.Widget} + */ + findNextFocusedWidget: function(direction, current){ + if (this.getLayoutType() === ccui.Layout.LINEAR_VERTICAL + || this.getLayoutType() === ccui.Layout.LINEAR_HORIZONTAL) { + return this._innerContainer.findNextFocusedWidget(direction, current); + } else + return ccui.Widget.prototype.findNextFocusedWidget.call(this, direction, current); }, - initRenderer: function () { - ccui.Layout.prototype.initRenderer.call(this); - this._innerContainer = ccui.Layout.create(); - ccui.Layout.prototype.addChild.call(this, this._innerContainer); + _initRenderer: function () { + ccui.Layout.prototype._initRenderer.call(this); + + this._innerContainer = new ccui.Layout(); + this._innerContainer.setColor(cc.color(255,255,255)); + this._innerContainer.setOpacity(255); + this._innerContainer.setCascadeColorEnabled(true); + this._innerContainer.setCascadeOpacityEnabled(true); + + this.addProtectedChild(this._innerContainer, 1, 1); }, - onSizeChanged: function () { - ccui.Layout.prototype.onSizeChanged.call(this); - var locSize = this._size; + _onSizeChanged: function () { + ccui.Layout.prototype._onSizeChanged.call(this); + var locSize = this._contentSize; this._topBoundary = locSize.height; this._rightBoundary = locSize.width; var bounceBoundaryParameterX = locSize.width / 3; @@ -144,170 +161,183 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ this._bounceTopBoundary = locSize.height - bounceBoundaryParameterY; this._bounceBottomBoundary = bounceBoundaryParameterY; this._bounceLeftBoundary = bounceBoundaryParameterX; - this._bounceRightBoundary = this._size.width - bounceBoundaryParameterX; - var innerSize = this._innerContainer.getSize(); - var orginInnerSizeWidth = innerSize.width; - var orginInnerSizeHeight = innerSize.height; - var innerSizeWidth = Math.max(orginInnerSizeWidth, locSize.width); - var innerSizeHeight = Math.max(orginInnerSizeHeight, locSize.height); - this._innerContainer.setSize(cc.size(innerSizeWidth, innerSizeHeight)); - this._innerContainer.setPosition(0, locSize.height - this._innerContainer.getSize().height); + this._bounceRightBoundary = locSize.width - bounceBoundaryParameterX; + var innerSize = this._innerContainer.getContentSize(); + this._innerContainer.setContentSize(cc.size(Math.max(innerSize.width, locSize.width), Math.max(innerSize.height, locSize.height))); + this._innerContainer.setPosition(0, locSize.height - this._innerContainer.getContentSize().height); }, + /** + * Changes inner container size of ScrollView.
    + * Inner container size must be larger than or equal the size of ScrollView. + * @param {cc.Size} size inner container size. + */ setInnerContainerSize: function (size) { - var locSize = this._size; - var innerSizeWidth = locSize.width; - var innerSizeHeight = locSize.height; - var originalInnerSize = this._innerContainer.getSize(); - if (size.width < locSize.width) { - cc.log("Inner width <= scrollview width, it will be force sized!"); - } - else { + var innerContainer = this._innerContainer; + var locSize = this._contentSize; + var innerSizeWidth = locSize.width, innerSizeHeight = locSize.height; + var originalInnerSize = innerContainer.getContentSize(); + if (size.width < locSize.width) + cc.log("Inner width <= ScrollView width, it will be force sized!"); + else innerSizeWidth = size.width; - } - if (size.height < locSize.height) { - cc.log("Inner height <= scrollview height, it will be force sized!"); - } - else { + + if (size.height < locSize.height) + cc.log("Inner height <= ScrollView height, it will be force sized!"); + else innerSizeHeight = size.height; - } - this._innerContainer.setSize(cc.size(innerSizeWidth, innerSizeHeight)); + + innerContainer.setContentSize(cc.size(innerSizeWidth, innerSizeHeight)); + var newInnerSize, offset; switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: - var newInnerSize = this._innerContainer.getSize(); - var offset = originalInnerSize.height - newInnerSize.height; - this.scrollChildren(0, offset); + newInnerSize = innerContainer.getContentSize(); + offset = originalInnerSize.height - newInnerSize.height; + this._scrollChildren(0, offset); break; case ccui.ScrollView.DIR_HORIZONTAL: - if (this._innerContainer.getRightInParent() <= locSize.width) { - var newInnerSize = this._innerContainer.getSize(); - var offset = originalInnerSize.width - newInnerSize.width; - this.scrollChildren(offset, 0); + if (innerContainer.getRightBoundary() <= locSize.width) { + newInnerSize = innerContainer.getContentSize(); + offset = originalInnerSize.width - newInnerSize.width; + this._scrollChildren(offset, 0); } break; case ccui.ScrollView.DIR_BOTH: - var newInnerSize = this._innerContainer.getSize(); + newInnerSize = innerContainer.getContentSize(); var offsetY = originalInnerSize.height - newInnerSize.height; - var offsetX = 0; - if (this._innerContainer.getRightInParent() <= locSize.width) { - offsetX = originalInnerSize.width - newInnerSize.width; - } - this.scrollChildren(offsetX, offsetY); + var offsetX = (innerContainer.getRightBoundary() <= locSize.width) ? originalInnerSize.width - newInnerSize.width : 0; + this._scrollChildren(offsetX, offsetY); break; default: break; } - var innerContainer = this._innerContainer; - var innerSize = innerContainer.getSize(); + + var innerSize = innerContainer.getContentSize(); var innerPos = innerContainer.getPosition(); var innerAP = innerContainer.getAnchorPoint(); - if (innerContainer.getLeftInParent() > 0.0) { + if (innerContainer.getLeftBoundary() > 0.0) innerContainer.setPosition(innerAP.x * innerSize.width, innerPos.y); - } - if (innerContainer.getRightInParent() < locSize.width) { + if (innerContainer.getRightBoundary() < locSize.width) innerContainer.setPosition(locSize.width - ((1.0 - innerAP.x) * innerSize.width), innerPos.y); - } - if (innerPos.y > 0.0) { + if (innerPos.y > 0.0) innerContainer.setPosition(innerPos.x, innerAP.y * innerSize.height); - } - if (innerContainer.getTopInParent() < locSize.height) { + if (innerContainer.getTopBoundary() < locSize.height) innerContainer.setPosition(innerPos.x, locSize.height - (1.0 - innerAP.y) * innerSize.height); + }, + + _setInnerWidth: function (width) { + var locW = this._contentSize.width, + innerWidth = locW, + container = this._innerContainer, + oldInnerWidth = container.width; + if (width < locW) + cc.log("Inner width <= scrollview width, it will be force sized!"); + else + innerWidth = width; + container.width = innerWidth; + + switch (this.direction) { + case ccui.ScrollView.DIR_HORIZONTAL: + case ccui.ScrollView.DIR_BOTH: + if (container.getRightBoundary() <= locW) { + var newInnerWidth = container.width; + var offset = oldInnerWidth - newInnerWidth; + this._scrollChildren(offset, 0); + } + break; + } + var innerAX = container.anchorX; + if (container.getLeftBoundary() > 0.0) + container.x = innerAX * innerWidth; + if (container.getRightBoundary() < locW) + container.x = locW - ((1.0 - innerAX) * innerWidth); + }, + + _setInnerHeight: function (height) { + var locH = this._contentSize.height, + innerHeight = locH, + container = this._innerContainer, + oldInnerHeight = container.height; + if (height < locH) + cc.log("Inner height <= scrollview height, it will be force sized!"); + else + innerHeight = height; + container.height = innerHeight; + + switch (this.direction) { + case ccui.ScrollView.DIR_VERTICAL: + case ccui.ScrollView.DIR_BOTH: + var newInnerHeight = innerHeight; + var offset = oldInnerHeight - newInnerHeight; + this._scrollChildren(0, offset); + break; } + var innerAY = container.anchorY; + if (container.getLeftBoundary() > 0.0) + container.y = innerAY * innerHeight; + if (container.getRightBoundary() < locH) + container.y = locH - ((1.0 - innerAY) * innerHeight); }, - _setInnerWidth: function (width) { - var locW = this._size.width, - innerWidth = locW, - container = this._innerContainer, - oldInnerWidth = container.width; - if (width < locW) - cc.log("Inner width <= scrollview width, it will be force sized!"); - else - innerWidth = width; - container.width = innerWidth; - - switch (this.direction) { - case ccui.ScrollView.DIR_HORIZONTAL: - case ccui.ScrollView.DIR_BOTH: - if (container.getRightInParent() <= locW) { - var newInnerWidth = container.width; - var offset = oldInnerWidth - newInnerWidth; - this.scrollChildren(offset, 0); - } - break; - } - var innerAX = container.anchorX; - if (container.getLeftInParent() > 0.0) { - container.x = innerAX * innerWidth; - } - if (container.getRightInParent() < locW) { - container.x = locW - ((1.0 - innerAX) * innerWidth); - } - }, - _setInnerHeight: function (height) { - var locH = this._size.height, - innerHeight = locH, - container = this._innerContainer, - oldInnerHeight = container.height; - if (height < locH) - cc.log("Inner height <= scrollview height, it will be force sized!"); - else - innerHeight = height; - container.height = innerHeight; - - switch (this.direction) { - case ccui.ScrollView.DIR_VERTICAL: - case ccui.ScrollView.DIR_BOTH: - var newInnerHeight = innerHeight; - var offset = oldInnerHeight - newInnerHeight; - this.scrollChildren(0, offset); - break; - } - var innerAY = container.anchorY; - if (container.getLeftInParent() > 0.0) { - container.y = innerAY * innerHeight; - } - if (container.getRightInParent() < locH) { - container.y = locH - ((1.0 - innerAY) * innerHeight); - } - }, + /** + * Returns inner container size of ScrollView.
    + * Inner container size must be larger than or equal ScrollView's size. + * + * @return {cc.Size} inner container size. + */ getInnerContainerSize: function () { - return this._innerContainer.getSize(); + return this._innerContainer.getContentSize(); + }, + _getInnerWidth: function () { + return this._innerContainer.width; + }, + _getInnerHeight: function () { + return this._innerContainer.height; }, - _getInnerWidth: function () { - return this._innerContainer.width; - }, - _getInnerHeight: function () { - return this._innerContainer.height; - }, /** - * Add widget - * @param {ccui.Widget} widget - * @param {Number} zOrder - * @param {Number} tag + * Add child to ccui.ScrollView. + * @param {cc.Node} widget + * @param {Number} [zOrder] + * @param {Number|string} [tag] tag or name * @returns {boolean} */ addChild: function (widget, zOrder, tag) { + if(!widget) + return false; + zOrder = zOrder || widget.getLocalZOrder(); + tag = tag || widget.getTag(); return this._innerContainer.addChild(widget, zOrder, tag); }, - removeAllChildren: function (cleanup) { - this._innerContainer.removeAllChildren(cleanup); + /** + * Removes all children. + */ + removeAllChildren: function () { + this.removeAllChildrenWithCleanup(true); }, /** - * remove widget child override + * Removes all children. + * @param {Boolean} cleanup + */ + removeAllChildrenWithCleanup: function(cleanup){ + this._innerContainer.removeAllChildrenWithCleanup(cleanup); + }, + + /** + * Removes widget child + * @override * @param {ccui.Widget} child * @param {Boolean} cleanup * @returns {boolean} */ removeChild: function (child, cleanup) { - return this._innerContainer.removeChild(child,cleanup); + return this._innerContainer.removeChild(child, cleanup); }, /** - * get inner children + * Returns inner container's children * @returns {Array} */ getChildren: function () { @@ -315,7 +345,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * get the count of inner children + * Gets the count of inner container's children * @returns {Number} */ getChildrenCount: function () { @@ -340,213 +370,154 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ return this._innerContainer.getChildByName(name); }, - /** - * Add node for scrollView - * @param {cc.Node}node - * @param {Number} zOrder - * @param {Number} tag - */ - addNode: function (node, zOrder, tag) { - this._innerContainer.addNode(node, zOrder, tag); - }, - - /** - * Get node by tag - * @param {Number} tag - * @returns {cc.Node} - */ - getNodeByTag: function (tag) { - return this._innerContainer.getNodeByTag(tag); - }, - - /** - * Get all node - * @returns {Array} - */ - getNodes: function () { - return this._innerContainer.getNodes(); - }, - - /** - * Remove a node - * @param {cc.Node} node - */ - removeNode: function (node) { - this._innerContainer.removeNode(node); - }, - - /** - * Remove a node by tag - * @param {Number} tag - */ - removeNodeByTag: function (tag) { - this._innerContainer.removeNodeByTag(tag); - }, - - /** - * Remove all node - */ - removeAllNodes: function () { - this._innerContainer.removeAllNodes(); - }, - - moveChildren: function (offsetX, offsetY) { - var pos = this._innerContainer.getPosition(); - this._moveChildPoint.x = pos.x + offsetX; - this._moveChildPoint.y = pos.y + offsetY; + _moveChildren: function (offsetX, offsetY) { + var locContainer = this._innerContainer; + //var pos = this._innerContainer.getPosition(); + this._moveChildPoint.x = locContainer.x + offsetX; + this._moveChildPoint.y = locContainer.y + offsetY; this._innerContainer.setPosition(this._moveChildPoint); }, - autoScrollChildren: function (dt) { + _autoScrollChildren: function (dt) { var lastTime = this._autoScrollAddUpTime; this._autoScrollAddUpTime += dt; if (this._isAutoScrollSpeedAttenuated) { var nowSpeed = this._autoScrollOriginalSpeed + this._autoScrollAcceleration * this._autoScrollAddUpTime; if (nowSpeed <= 0) { - this.stopAutoScrollChildren(); - this.checkNeedBounce(); + this._stopAutoScrollChildren(); + this._checkNeedBounce(); } else { var timeParam = lastTime * 2 + dt; var offset = (this._autoScrollOriginalSpeed + this._autoScrollAcceleration * timeParam * 0.5) * dt; var offsetX = offset * this._autoScrollDir.x; var offsetY = offset * this._autoScrollDir.y; - if (!this.scrollChildren(offsetX, offsetY)) { - this.stopAutoScrollChildren(); - this.checkNeedBounce(); + if (!this._scrollChildren(offsetX, offsetY)) { + this._stopAutoScrollChildren(); + this._checkNeedBounce(); } } - } - else { + } else { if (this._needCheckAutoScrollDestination) { var xOffset = this._autoScrollDir.x * dt * this._autoScrollOriginalSpeed; var yOffset = this._autoScrollDir.y * dt * this._autoScrollOriginalSpeed; - var notDone = this.checkCustomScrollDestination(xOffset, yOffset); - var scrollCheck = this.scrollChildren(xOffset, yOffset); + var notDone = this._checkCustomScrollDestination(xOffset, yOffset); + var scrollCheck = this._scrollChildren(xOffset, yOffset); if (!notDone || !scrollCheck) { - this.stopAutoScrollChildren(); - this.checkNeedBounce(); + this._stopAutoScrollChildren(); + this._checkNeedBounce(); } - } - else { - if (!this.scrollChildren(this._autoScrollDir.x * dt * this._autoScrollOriginalSpeed, this._autoScrollDir.y * dt * this._autoScrollOriginalSpeed)) { - this.stopAutoScrollChildren(); - this.checkNeedBounce(); + } else { + if (!this._scrollChildren(this._autoScrollDir.x * dt * this._autoScrollOriginalSpeed, + this._autoScrollDir.y * dt * this._autoScrollOriginalSpeed)) { + this._stopAutoScrollChildren(); + this._checkNeedBounce(); } } } }, - bounceChildren: function (dt) { + _bounceChildren: function (dt) { var locSpeed = this._bounceOriginalSpeed; var locBounceDir = this._bounceDir; - if (locSpeed <= 0.0) { - this.stopBounceChildren(); - } - if (!this.bounceScrollChildren(locBounceDir.x * dt * locSpeed, locBounceDir.y * dt * locSpeed)) { - this.stopBounceChildren(); - } + if (locSpeed <= 0.0) + this._stopBounceChildren(); + if (!this._bounceScrollChildren(locBounceDir.x * dt * locSpeed, locBounceDir.y * dt * locSpeed)) + this._stopBounceChildren(); }, - checkNeedBounce: function () { - if (!this.bounceEnabled) { + _checkNeedBounce: function () { + if (!this.bounceEnabled) return false; - } - this.checkBounceBoundary(); - if (this._topBounceNeeded || this._bottomBounceNeeded || this._leftBounceNeeded || this._rightBounceNeeded) { - if (this._topBounceNeeded && this._leftBounceNeeded) { - var scrollVector = cc.pSub(cc.p(0.0, this._size.height), cc.p(this._innerContainer.getLeftInParent(), this._innerContainer.getTopInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._checkBounceBoundary(); + var locTopBounceNeeded = this._topBounceNeeded, locBottomBounceNeeded = this._bottomBounceNeeded, + locLeftBounceNeeded = this._leftBounceNeeded, locRightBounceNeeded = this._rightBounceNeeded; + + if (locTopBounceNeeded || locBottomBounceNeeded || locLeftBounceNeeded || locRightBounceNeeded) { + var scrollVector, orSpeed; + var locContentSize = this._contentSize, locInnerContainer = this._innerContainer; + if (locTopBounceNeeded && locLeftBounceNeeded) { + scrollVector = cc.pSub(cc.p(0.0, locContentSize.height), cc.p(locInnerContainer.getLeftBoundary(), locInnerContainer.getTopBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._topBounceNeeded && this._rightBounceNeeded) { - var scrollVector = cc.pSub(cc.p(this._size.width, this._size.height), cc.p(this._innerContainer.getRightInParent(), this._innerContainer.getTopInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locTopBounceNeeded && locRightBounceNeeded) { + scrollVector = cc.pSub(cc.p(locContentSize.width, locContentSize.height), cc.p(locInnerContainer.getRightBoundary(), locInnerContainer.getTopBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._bottomBounceNeeded && this._leftBounceNeeded) { - var scrollVector = cc.pSub(cc.p(0, 0), cc.p(this._innerContainer.getLeftInParent(), this._innerContainer.getBottomInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locBottomBounceNeeded && locLeftBounceNeeded) { + scrollVector = cc.pSub(cc.p(0, 0), cc.p(locInnerContainer.getLeftBoundary(), locInnerContainer.getBottomBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._bottomBounceNeeded && this._rightBounceNeeded) { - var scrollVector = cc.pSub(cc.p(this._size.width, 0.0), cc.p(this._innerContainer.getRightInParent(), this._innerContainer.getBottomInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locBottomBounceNeeded && locRightBounceNeeded) { + scrollVector = cc.pSub(cc.p(locContentSize.width, 0.0), cc.p(locInnerContainer.getRightBoundary(), locInnerContainer.getBottomBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._topBounceNeeded) { - var scrollVector = cc.pSub(cc.p(0, this._size.height), cc.p(0.0, this._innerContainer.getTopInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locTopBounceNeeded) { + scrollVector = cc.pSub(cc.p(0, locContentSize.height), cc.p(0.0, locInnerContainer.getTopBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._bottomBounceNeeded) { - var scrollVector = cc.pSub(cc.p(0, 0), cc.p(0.0, this._innerContainer.getBottomInParent())); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locBottomBounceNeeded) { + scrollVector = cc.pSub(cc.p(0, 0), cc.p(0.0, locInnerContainer.getBottomBoundary())); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._leftBounceNeeded) { - var scrollVector = cc.pSub(cc.p(0, 0), cc.p(this._innerContainer.getLeftInParent(), 0.0)); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locLeftBounceNeeded) { + scrollVector = cc.pSub(cc.p(0, 0), cc.p(locInnerContainer.getLeftBoundary(), 0.0)); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); - } - else if (this._rightBounceNeeded) { - var scrollVector = cc.pSub(cc.p(this._size.width, 0), cc.p(this._innerContainer.getRightInParent(), 0.0)); - var orSpeed = cc.pLength(scrollVector) / 0.2; + this._startBounceChildren(orSpeed); + } else if (locRightBounceNeeded) { + scrollVector = cc.pSub(cc.p(locContentSize.width, 0), cc.p(locInnerContainer.getRightBoundary(), 0.0)); + orSpeed = cc.pLength(scrollVector) / 0.2; this._bounceDir = cc.pNormalize(scrollVector); - this.startBounceChildren(orSpeed); + this._startBounceChildren(orSpeed); } return true; } return false; }, - checkBounceBoundary: function () { - var icBottomPos = this._innerContainer.getBottomInParent(); + _checkBounceBoundary: function () { + var locContainer = this._innerContainer; + var icBottomPos = locContainer.getBottomBoundary(); if (icBottomPos > this._bottomBoundary) { - this.scrollToBottomEvent(); + this._scrollToBottomEvent(); this._bottomBounceNeeded = true; - } - else { + } else this._bottomBounceNeeded = false; - } - var icTopPos = this._innerContainer.getTopInParent(); + + var icTopPos = locContainer.getTopBoundary(); if (icTopPos < this._topBoundary) { - this.scrollToTopEvent(); + this._scrollToTopEvent(); this._topBounceNeeded = true; - } - else { + } else this._topBounceNeeded = false; - } - var icRightPos = this._innerContainer.getRightInParent(); + + var icRightPos = locContainer.getRightBoundary(); if (icRightPos < this._rightBoundary) { - this.scrollToRightEvent(); + this._scrollToRightEvent(); this._rightBounceNeeded = true; - } - else { + } else this._rightBounceNeeded = false; - } - var icLeftPos = this._innerContainer.getLeftInParent(); + + var icLeftPos = locContainer.getLeftBoundary(); if (icLeftPos > this._leftBoundary) { - this.scrollToLeftEvent(); + this._scrollToLeftEvent(); this._leftBounceNeeded = true; - } - else { + } else this._leftBounceNeeded = false; - } }, - startBounceChildren: function (v) { + _startBounceChildren: function (v) { this._bounceOriginalSpeed = v; this._bouncing = true; }, - stopBounceChildren: function () { + _stopBounceChildren: function () { this._bouncing = false; this._bounceOriginalSpeed = 0.0; this._leftBounceNeeded = false; @@ -555,16 +526,17 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ this._bottomBounceNeeded = false; }, - startAutoScrollChildrenWithOriginalSpeed: function (dir, v, attenuated, acceleration) { - this.stopAutoScrollChildren(); - this._autoScrollDir = dir; + _startAutoScrollChildrenWithOriginalSpeed: function (dir, v, attenuated, acceleration) { + this._stopAutoScrollChildren(); + this._autoScrollDir.x = dir.x; + this._autoScrollDir.y = dir.y; this._isAutoScrollSpeedAttenuated = attenuated; this._autoScrollOriginalSpeed = v; this._autoScroll = true; this._autoScrollAcceleration = acceleration; }, - startAutoScrollChildrenWithDestination: function (des, time, attenuated) { + _startAutoScrollChildrenWithDestination: function (des, time, attenuated) { this._needCheckAutoScrollDestination = false; this._autoScrollDestination = des; var dis = cc.pSub(des, this._innerContainer.getPosition()); @@ -575,39 +547,34 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ if (attenuated) { acceleration = -(2 * disLength) / (time * time); orSpeed = 2 * disLength / time; - } - else { + } else { this._needCheckAutoScrollDestination = true; orSpeed = disLength / time; } - this.startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, attenuated, acceleration); + this._startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, attenuated, acceleration); }, - jumpToDestination: function (dstX, dstY) { - if(dstX.x !== undefined) { - dstY = dstX.y; - dstX = dstX.x; - } + _jumpToDestination: function (dstX, dstY) { + if (dstX.x !== undefined) { + dstY = dstX.y; + dstX = dstX.x; + } var finalOffsetX = dstX; var finalOffsetY = dstY; switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: - if (dstY <= 0) { - finalOffsetY = Math.max(dstY, this._size.height - this._innerContainer.getSize().height); - } + if (dstY <= 0) + finalOffsetY = Math.max(dstY, this._contentSize.height - this._innerContainer.getContentSize().height); break; case ccui.ScrollView.DIR_HORIZONTAL: - if (dstX <= 0) { - finalOffsetX = Math.max(dstX, this._size.width - this._innerContainer.getSize().width); - } + if (dstX <= 0) + finalOffsetX = Math.max(dstX, this._contentSize.width - this._innerContainer.getContentSize().width); break; case ccui.ScrollView.DIR_BOTH: - if (dstY <= 0) { - finalOffsetY = Math.max(dstY, this._size.height - this._innerContainer.getSize().height); - } - if (dstX <= 0) { - finalOffsetX = Math.max(dstX, this._size.width - this._innerContainer.getSize().width); - } + if (dstY <= 0) + finalOffsetY = Math.max(dstY, this._contentSize.height - this._innerContainer.getContentSize().height); + if (dstX <= 0) + finalOffsetX = Math.max(dstX, this._contentSize.width - this._innerContainer.getContentSize().width); break; default: break; @@ -615,251 +582,222 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ this._innerContainer.setPosition(finalOffsetX, finalOffsetY); }, - - stopAutoScrollChildren: function () { + _stopAutoScrollChildren: function () { this._autoScroll = false; this._autoScrollOriginalSpeed = 0; this._autoScrollAddUpTime = 0; }, - bounceScrollChildren: function (touchOffsetX, touchOffsetY) { + _bounceScrollChildren: function (touchOffsetX, touchOffsetY) { var scrollEnabled = true; - if (touchOffsetX > 0.0 && touchOffsetY > 0.0) //first quadrant //bounce to top-right - { - var realOffsetX = touchOffsetX; - var realOffsetY = touchOffsetY; - var icRightPos = this._innerContainer.getRightInParent(); + var realOffsetX, realOffsetY, icRightPos, icTopPos, icBottomPos; + var locContainer = this._innerContainer; + if (touchOffsetX > 0.0 && touchOffsetY > 0.0){ //first quadrant //bounce to top-right + realOffsetX = touchOffsetX; + realOffsetY = touchOffsetY; + icRightPos = locContainer.getRightBoundary(); if (icRightPos + realOffsetX >= this._rightBoundary) { realOffsetX = this._rightBoundary - icRightPos; - this.bounceRightEvent(); + this._bounceRightEvent(); scrollEnabled = false; } - var icTopPos = this._innerContainer.getTopInParent(); + icTopPos = locContainer.getTopBoundary(); if (icTopPos + touchOffsetY >= this._topBoundary) { realOffsetY = this._topBoundary - icTopPos; - this.bounceTopEvent(); + this._bounceTopEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, realOffsetY); - } - else if (touchOffsetX < 0.0 && touchOffsetY > 0.0) //second quadrant //bounce to top-left - { - var realOffsetX = touchOffsetX; - var realOffsetY = touchOffsetY; - var icLefrPos = this._innerContainer.getLeftInParent(); + this._moveChildren(realOffsetX, realOffsetY); + } else if (touchOffsetX < 0.0 && touchOffsetY > 0.0){ //second quadrant //bounce to top-left + realOffsetX = touchOffsetX; + realOffsetY = touchOffsetY; + icLefrPos = locContainer.getLeftBoundary(); if (icLefrPos + realOffsetX <= this._leftBoundary) { realOffsetX = this._leftBoundary - icLefrPos; - this.bounceLeftEvent(); + this._bounceLeftEvent(); scrollEnabled = false; } - var icTopPos = this._innerContainer.getTopInParent(); + icTopPos = locContainer.getTopBoundary(); if (icTopPos + touchOffsetY >= this._topBoundary) { realOffsetY = this._topBoundary - icTopPos; - this.bounceTopEvent(); + this._bounceTopEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, realOffsetY); - } - else if (touchOffsetX < 0.0 && touchOffsetY < 0.0) //third quadrant //bounce to bottom-left - { - var realOffsetX = touchOffsetX; - var realOffsetY = touchOffsetY; - var icLefrPos = this._innerContainer.getLeftInParent(); + this._moveChildren(realOffsetX, realOffsetY); + }else if (touchOffsetX < 0.0 && touchOffsetY < 0.0){ //third quadrant //bounce to bottom-left + realOffsetX = touchOffsetX; + realOffsetY = touchOffsetY; + var icLefrPos = locContainer.getLeftBoundary(); if (icLefrPos + realOffsetX <= this._leftBoundary) { realOffsetX = this._leftBoundary - icLefrPos; - this.bounceLeftEvent(); + this._bounceLeftEvent(); scrollEnabled = false; } - var icBottomPos = this._innerContainer.getBottomInParent(); + icBottomPos = locContainer.getBottomBoundary(); if (icBottomPos + touchOffsetY <= this._bottomBoundary) { realOffsetY = this._bottomBoundary - icBottomPos; - this.bounceBottomEvent(); + this._bounceBottomEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, realOffsetY); - } - else if (touchOffsetX > 0.0 && touchOffsetY < 0.0) //forth quadrant //bounce to bottom-right - { - var realOffsetX = touchOffsetX; - var realOffsetY = touchOffsetY; - var icRightPos = this._innerContainer.getRightInParent(); + this._moveChildren(realOffsetX, realOffsetY); + } else if (touchOffsetX > 0.0 && touchOffsetY < 0.0){ //forth quadrant //bounce to bottom-right + realOffsetX = touchOffsetX; + realOffsetY = touchOffsetY; + icRightPos = locContainer.getRightBoundary(); if (icRightPos + realOffsetX >= this._rightBoundary) { realOffsetX = this._rightBoundary - icRightPos; - this.bounceRightEvent(); + this._bounceRightEvent(); scrollEnabled = false; } - var icBottomPos = this._innerContainer.getBottomInParent(); + icBottomPos = locContainer.getBottomBoundary(); if (icBottomPos + touchOffsetY <= this._bottomBoundary) { realOffsetY = this._bottomBoundary - icBottomPos; - this.bounceBottomEvent(); + this._bounceBottomEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, realOffsetY); - } - else if (touchOffsetX == 0.0 && touchOffsetY > 0.0) // bounce to top - { - var realOffsetY = touchOffsetY; - var icTopPos = this._innerContainer.getTopInParent(); + this._moveChildren(realOffsetX, realOffsetY); + } else if (touchOffsetX === 0.0 && touchOffsetY > 0.0){ // bounce to top + realOffsetY = touchOffsetY; + icTopPos = locContainer.getTopBoundary(); if (icTopPos + touchOffsetY >= this._topBoundary) { realOffsetY = this._topBoundary - icTopPos; - this.bounceTopEvent(); + this._bounceTopEvent(); scrollEnabled = false; } - this.moveChildren(0.0, realOffsetY); - } - else if (touchOffsetX == 0.0 && touchOffsetY < 0.0) //bounce to bottom - { - var realOffsetY = touchOffsetY; - var icBottomPos = this._innerContainer.getBottomInParent(); + this._moveChildren(0.0, realOffsetY); + } else if (touchOffsetX === 0.0 && touchOffsetY < 0.0) {//bounce to bottom + realOffsetY = touchOffsetY; + icBottomPos = locContainer.getBottomBoundary(); if (icBottomPos + touchOffsetY <= this._bottomBoundary) { realOffsetY = this._bottomBoundary - icBottomPos; - this.bounceBottomEvent(); + this._bounceBottomEvent(); scrollEnabled = false; } - this.moveChildren(0.0, realOffsetY); - } - else if (touchOffsetX > 0.0 && touchOffsetY == 0.0) //bounce to right - { - var realOffsetX = touchOffsetX; - var icRightPos = this._innerContainer.getRightInParent(); + this._moveChildren(0.0, realOffsetY); + } else if (touchOffsetX > 0.0 && touchOffsetY === 0.0){ //bounce to right + realOffsetX = touchOffsetX; + icRightPos = locContainer.getRightBoundary(); if (icRightPos + realOffsetX >= this._rightBoundary) { realOffsetX = this._rightBoundary - icRightPos; - this.bounceRightEvent(); + this._bounceRightEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, 0.0); - } - else if (touchOffsetX < 0.0 && touchOffsetY == 0.0) //bounce to left - { - var realOffsetX = touchOffsetX; - var icLeftPos = this._innerContainer.getLeftInParent(); + this._moveChildren(realOffsetX, 0.0); + }else if (touchOffsetX < 0.0 && touchOffsetY === 0.0){ //bounce to left + realOffsetX = touchOffsetX; + var icLeftPos = locContainer.getLeftBoundary(); if (icLeftPos + realOffsetX <= this._leftBoundary) { realOffsetX = this._leftBoundary - icLeftPos; - this.bounceLeftEvent(); + this._bounceLeftEvent(); scrollEnabled = false; } - this.moveChildren(realOffsetX, 0.0); + this._moveChildren(realOffsetX, 0.0); } return scrollEnabled; }, - checkCustomScrollDestination: function (touchOffsetX, touchOffsetY) { + _checkCustomScrollDestination: function (touchOffsetX, touchOffsetY) { var scrollEnabled = true; + var icBottomPos, icLeftPos, icRightPos, icTopPos; + var locContainer = this._innerContainer, locDestination = this._autoScrollDestination; switch (this.direction) { - case ccui.ScrollView.DIR_VERTICAL: // vertical + case ccui.ScrollView.DIR_VERTICAL: if (this._autoScrollDir.y > 0) { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icBottomPos; + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= locDestination.y) { + touchOffsetY = locDestination.y - icBottomPos; scrollEnabled = false; } - } - else { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY <= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icBottomPos; + } else { + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY <= locDestination.y) { + touchOffsetY = locDestination.y - icBottomPos; scrollEnabled = false; } } break; - case ccui.ScrollView.DIR_HORIZONTAL: // horizontal + case ccui.ScrollView.DIR_HORIZONTAL: if (this._autoScrollDir.x > 0) { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icLeftPos; + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= locDestination.x) { + touchOffsetX = locDestination.x - icLeftPos; scrollEnabled = false; } - } - else { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX <= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icLeftPos; + } else { + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX <= locDestination.x) { + touchOffsetX = locDestination.x - icLeftPos; scrollEnabled = false; } } break; case ccui.ScrollView.DIR_BOTH: - if (touchOffsetX > 0.0 && touchOffsetY > 0.0) // up right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icLeftPos; + if (touchOffsetX > 0.0 && touchOffsetY > 0.0){ // up right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= locDestination.x) { + touchOffsetX = locDestination.x - icLeftPos; scrollEnabled = false; } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icBottomPos; + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= locDestination.y) { + touchOffsetY = locDestination.y - icBottomPos; scrollEnabled = false; } - } - else if (touchOffsetX < 0.0 && touchOffsetY > 0.0) // up left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icRightPos; + } else if (touchOffsetX < 0.0 && touchOffsetY > 0.0){ // up left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= locDestination.x) { + touchOffsetX = locDestination.x - icRightPos; scrollEnabled = false; } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icBottomPos; + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= locDestination.y) { + touchOffsetY = locDestination.y - icBottomPos; scrollEnabled = false; } - } - else if (touchOffsetX < 0.0 && touchOffsetY < 0.0) // down left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icRightPos; + } else if (touchOffsetX < 0.0 && touchOffsetY < 0.0){ // down left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= locDestination.x) { + touchOffsetX = locDestination.x - icRightPos; scrollEnabled = false; } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icTopPos; + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= locDestination.y) { + touchOffsetY = locDestination.y - icTopPos; scrollEnabled = false; } - } - else if (touchOffsetX > 0.0 && touchOffsetY < 0.0) // down right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icLeftPos; + } else if (touchOffsetX > 0.0 && touchOffsetY < 0.0){ // down right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= locDestination.x) { + touchOffsetX = locDestination.x - icLeftPos; scrollEnabled = false; } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icTopPos; + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= locDestination.y) { + touchOffsetY = locDestination.y - icTopPos; scrollEnabled = false; } - } - else if (touchOffsetX == 0.0 && touchOffsetY > 0.0) // up - { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icBottomPos; + } else if (touchOffsetX === 0.0 && touchOffsetY > 0.0){ // up + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= locDestination.y) { + touchOffsetY = locDestination.y - icBottomPos; scrollEnabled = false; } - } - else if (touchOffsetX < 0.0 && touchOffsetY == 0.0) // left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icRightPos; + } else if (touchOffsetX < 0.0 && touchOffsetY === 0.0){ // left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= locDestination.x) { + touchOffsetX = locDestination.x - icRightPos; scrollEnabled = false; } - } - else if (touchOffsetX == 0.0 && touchOffsetY < 0.0) // down - { - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._autoScrollDestination.y) { - touchOffsetY = this._autoScrollDestination.y - icTopPos; + } else if (touchOffsetX === 0.0 && touchOffsetY < 0.0){ // down + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= locDestination.y) { + touchOffsetY = locDestination.y - icTopPos; scrollEnabled = false; } - } - else if (touchOffsetX > 0.0 && touchOffsetY == 0.0) // right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._autoScrollDestination.x) { - touchOffsetX = this._autoScrollDestination.x - icLeftPos; + } else if (touchOffsetX > 0.0 && touchOffsetY === 0.0){ // right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= locDestination.x) { + touchOffsetX = locDestination.x - icLeftPos; scrollEnabled = false; } } @@ -870,280 +808,18 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ return scrollEnabled; }, - - getCurAutoScrollDistance: function (dt) { - this._autoScrollOriginalSpeed -= this._autoScrollAcceleration * dt; - return this._autoScrollOriginalSpeed * dt; - }, - - scrollChildren: function (touchOffsetX, touchOffsetY) { + _scrollChildren: function (touchOffsetX, touchOffsetY) { var scrollEnabled = true; - this.scrollingEvent(); + this._scrollingEvent(); switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: // vertical - var realOffset = touchOffsetY; - if (this.bounceEnabled) { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { - realOffset = this._bounceBottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { - realOffset = this._bounceTopBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bottomBoundary) { - realOffset = this._bottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._topBoundary) { - realOffset = this._topBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - this.moveChildren(0.0, realOffset); + scrollEnabled = this._scrollChildrenVertical(touchOffsetX, touchOffsetY); break; case ccui.ScrollView.DIR_HORIZONTAL: // horizontal - var realOffset = touchOffsetX; - if (this.bounceEnabled) { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { - realOffset = this._bounceRightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { - realOffset = this._bounceLeftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - } - else { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._rightBoundary) { - realOffset = this._rightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._leftBoundary) { - realOffset = this._leftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - } - this.moveChildren(realOffset, 0.0); + scrollEnabled = this._scrollChildrenHorizontal(touchOffsetX, touchOffsetY); break; case ccui.ScrollView.DIR_BOTH: - var realOffsetX = touchOffsetX; - var realOffsetY = touchOffsetY; - if (this.bounceEnabled) { - if (touchOffsetX > 0.0 && touchOffsetY > 0.0) // up right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { - realOffsetX = this._bounceLeftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { - realOffsetY = this._bounceBottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0.0 && touchOffsetY > 0.0) // up left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { - realOffsetX = this._bounceRightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { - realOffsetY = this._bounceBottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0.0 && touchOffsetY < 0.0) // down left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { - realOffsetX = this._bounceRightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { - realOffsetY = this._bounceTopBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX > 0.0 && touchOffsetY < 0.0) // down right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { - realOffsetX = this._bounceLeftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { - realOffsetY = this._bounceTopBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX == 0.0 && touchOffsetY > 0.0) // up - { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { - realOffsetY = this._bounceBottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0.0 && touchOffsetY == 0.0) // left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { - realOffsetX = this._bounceRightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX == 0.0 && touchOffsetY < 0.0) // down - { - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { - realOffsetY = this._bounceTopBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX > 0.0 && touchOffsetY == 0.0) // right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { - realOffsetX = this._bounceLeftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - } - } - else { - if (touchOffsetX > 0.0 && touchOffsetY > 0.0) // up right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._leftBoundary) { - realOffsetX = this._leftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bottomBoundary) { - realOffsetY = this._bottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0.0 && touchOffsetY > 0.0) // up left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._rightBoundary) { - realOffsetX = this._rightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bottomBoundary) { - realOffsetY = this._bottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0 && touchOffsetY < 0) // down left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._rightBoundary) { - realOffsetX = this._rightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._topBoundary) { - realOffsetY = this._topBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX > 0 && touchOffsetY < 0) // down right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._leftBoundary) { - realOffsetX = this._leftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._topBoundary) { - realOffsetY = this._topBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX == 0.0 && touchOffsetY > 0.0) // up - { - var icBottomPos = this._innerContainer.getBottomInParent(); - if (icBottomPos + touchOffsetY >= this._bottomBoundary) { - realOffsetY = this._bottomBoundary - icBottomPos; - this.scrollToBottomEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX < 0.0 && touchOffsetY == 0.0) // left - { - var icRightPos = this._innerContainer.getRightInParent(); - if (icRightPos + touchOffsetX <= this._rightBoundary) { - realOffsetX = this._rightBoundary - icRightPos; - this.scrollToRightEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX == 0.0 && touchOffsetY < 0) // down - { - var icTopPos = this._innerContainer.getTopInParent(); - if (icTopPos + touchOffsetY <= this._topBoundary) { - realOffsetY = this._topBoundary - icTopPos; - this.scrollToTopEvent(); - scrollEnabled = false; - } - } - else if (touchOffsetX > 0 && touchOffsetY == 0) // right - { - var icLeftPos = this._innerContainer.getLeftInParent(); - if (icLeftPos + touchOffsetX >= this._leftBoundary) { - realOffsetX = this._leftBoundary - icLeftPos; - this.scrollToLeftEvent(); - scrollEnabled = false; - } - } - } - this.moveChildren(realOffsetX, realOffsetY); + scrollEnabled = this._scrollChildrenBoth(touchOffsetX, touchOffsetY); break; default: break; @@ -1151,379 +827,789 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ return scrollEnabled; }, + _scrollChildrenVertical: function(touchOffsetX, touchOffsetY){ + var realOffset = touchOffsetY; + var scrollEnabled = true; + var icBottomPos, icTopPos, locContainer = this._innerContainer; + if (this.bounceEnabled) { + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { + realOffset = this._bounceBottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { + realOffset = this._bounceTopBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + + } + } else { + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bottomBoundary){ + realOffset = this._bottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._topBoundary) { + realOffset = this._topBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } + this._moveChildren(0.0, realOffset); + return scrollEnabled; + }, + + _scrollChildrenHorizontal: function(touchOffsetX, touchOffestY){ + var scrollEnabled = true; + var realOffset = touchOffsetX; + var icRightPos, icLeftPos, locContainer = this._innerContainer; + if (this.bounceEnabled){ + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { + realOffset = this._bounceRightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { + realOffset = this._bounceLeftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + } else { + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._rightBoundary) { + realOffset = this._rightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._leftBoundary) { + realOffset = this._leftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + } + this._moveChildren(realOffset, 0.0); + return scrollEnabled; + }, + + _scrollChildrenBoth: function (touchOffsetX, touchOffsetY) { + var scrollEnabled = true; + var realOffsetX = touchOffsetX; + var realOffsetY = touchOffsetY; + var icLeftPos, icBottomPos, icRightPos, icTopPos; + var locContainer = this._innerContainer; + if (this.bounceEnabled) { + if (touchOffsetX > 0.0 && touchOffsetY > 0.0) { // up right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { + realOffsetX = this._bounceLeftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { + realOffsetY = this._bounceBottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY > 0.0) { // up left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { + realOffsetX = this._bounceRightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { + realOffsetY = this._bounceBottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY < 0.0) { // down left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { + realOffsetX = this._bounceRightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { + realOffsetY = this._bounceTopBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX > 0.0 && touchOffsetY < 0.0){ // down right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { + realOffsetX = this._bounceLeftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { + realOffsetY = this._bounceTopBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX === 0.0 && touchOffsetY > 0.0){ // up + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bounceBottomBoundary) { + realOffsetY = this._bounceBottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY === 0.0){ // left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._bounceRightBoundary) { + realOffsetX = this._bounceRightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX === 0.0 && touchOffsetY < 0.0){ // down + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._bounceTopBoundary) { + realOffsetY = this._bounceTopBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX > 0.0 && touchOffsetY === 0.0){ // right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._bounceLeftBoundary) { + realOffsetX = this._bounceLeftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + } + } else { + if (touchOffsetX > 0.0 && touchOffsetY > 0.0){ // up right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._leftBoundary) { + realOffsetX = this._leftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bottomBoundary) { + realOffsetY = this._bottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY > 0.0){ // up left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._rightBoundary) { + realOffsetX = this._rightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icBottomPos = locContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bottomBoundary) { + realOffsetY = this._bottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY < 0.0){ // down left + icRightPos = locContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._rightBoundary) { + realOffsetX = this._rightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + icTopPos = locContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._topBoundary) { + realOffsetY = this._topBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX > 0.0 && touchOffsetY < 0.0){ // down right + icLeftPos = locContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._leftBoundary) { + realOffsetX = this._leftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + icTopPos = this._innerContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._topBoundary) { + realOffsetY = this._topBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX === 0.0 && touchOffsetY > 0.0) { // up + icBottomPos = this._innerContainer.getBottomBoundary(); + if (icBottomPos + touchOffsetY >= this._bottomBoundary) { + realOffsetY = this._bottomBoundary - icBottomPos; + this._scrollToBottomEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX < 0.0 && touchOffsetY === 0.0){ // left + icRightPos = this._innerContainer.getRightBoundary(); + if (icRightPos + touchOffsetX <= this._rightBoundary) { + realOffsetX = this._rightBoundary - icRightPos; + this._scrollToRightEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX === 0.0 && touchOffsetY < 0.0){ // down + icTopPos = this._innerContainer.getTopBoundary(); + if (icTopPos + touchOffsetY <= this._topBoundary) { + realOffsetY = this._topBoundary - icTopPos; + this._scrollToTopEvent(); + scrollEnabled = false; + } + } else if (touchOffsetX > 0.0 && touchOffsetY === 0.0){ // right + icLeftPos = this._innerContainer.getLeftBoundary(); + if (icLeftPos + touchOffsetX >= this._leftBoundary) { + realOffsetX = this._leftBoundary - icLeftPos; + this._scrollToLeftEvent(); + scrollEnabled = false; + } + } + } + this._moveChildren(realOffsetX, realOffsetY); + return scrollEnabled; + }, + + /** + * Scroll inner container to bottom boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToBottom: function (time, attenuated) { - this.startAutoScrollChildrenWithDestination(cc.p(this._innerContainer.getPositionX(), 0), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(this._innerContainer.getPositionX(), 0), time, attenuated); }, + /** + * Scroll inner container to top boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToTop: function (time, attenuated) { - this.startAutoScrollChildrenWithDestination(cc.p(this._innerContainer.getPositionX(), this._size.height - this._innerContainer.getSize().height), time, attenuated); + this._startAutoScrollChildrenWithDestination( + cc.p(this._innerContainer.getPositionX(), this._contentSize.height - this._innerContainer.getContentSize().height), time, attenuated); }, + /** + * Scroll inner container to left boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToLeft: function (time, attenuated) { - this.startAutoScrollChildrenWithDestination(cc.p(0, this._innerContainer.getPositionY()), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(0, this._innerContainer.getPositionY()), time, attenuated); }, + /** + * Scroll inner container to right boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToRight: function (time, attenuated) { - this.startAutoScrollChildrenWithDestination(cc.p(this._size.width - this._innerContainer.getSize().width, this._innerContainer.getPositionY()), time, attenuated); + this._startAutoScrollChildrenWithDestination( + cc.p(this._contentSize.width - this._innerContainer.getContentSize().width, this._innerContainer.getPositionY()), time, attenuated); }, + /** + * Scroll inner container to top and left boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToTopLeft: function (time, attenuated) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.startAutoScrollChildrenWithDestination(cc.p(0, this._size.height - this._innerContainer.getSize().height), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(0, this._contentSize.height - this._innerContainer.getContentSize().height), time, attenuated); }, + /** + * Scroll inner container to top and right boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToTopRight: function (time, attenuated) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.startAutoScrollChildrenWithDestination(cc.p(this._size.width - this._innerContainer.getSize().width, this._size.height - this._innerContainer.getSize().height), time, attenuated); + var inSize = this._innerContainer.getContentSize(); + this._startAutoScrollChildrenWithDestination(cc.p(this._contentSize.width - inSize.width, + this._contentSize.height - inSize.height), time, attenuated); }, + /** + * Scroll inner container to bottom and left boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToBottomLeft: function (time, attenuated) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.startAutoScrollChildrenWithDestination(cc.p(0, 0), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(0, 0), time, attenuated); }, + /** + * Scroll inner container to bottom and right boundary of ScrollView. + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToBottomRight: function (time, attenuated) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.startAutoScrollChildrenWithDestination(cc.p(this._size.width - this._innerContainer.getSize().width, 0), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(this._contentSize.width - this._innerContainer.getContentSize().width, 0), time, attenuated); }, + /** + * Scroll inner container to vertical percent position of ScrollView. + * @param {Number} percent + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToPercentVertical: function (percent, time, attenuated) { - var minY = this._size.height - this._innerContainer.getSize().height; + var minY = this._contentSize.height - this._innerContainer.getContentSize().height; var h = -minY; - this.startAutoScrollChildrenWithDestination(cc.p(this._innerContainer.getPositionX(), minY + percent * h / 100), time, attenuated); + this._startAutoScrollChildrenWithDestination(cc.p(this._innerContainer.getPositionX(), minY + percent * h / 100), time, attenuated); }, + /** + * Scroll inner container to horizontal percent position of ScrollView. + * @param {Number} percent + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToPercentHorizontal: function (percent, time, attenuated) { - var w = this._innerContainer.getSize().width - this._size.width; - this.startAutoScrollChildrenWithDestination(cc.p(-(percent * w / 100), this._innerContainer.getPositionY()), time, attenuated); + var w = this._innerContainer.getContentSize().width - this._contentSize.width; + this._startAutoScrollChildrenWithDestination(cc.p(-(percent * w / 100), this._innerContainer.getPositionY()), time, attenuated); }, + /** + * Scroll inner container to both direction percent position of ScrollView. + * @param {cc.Point} percent + * @param {Number} time + * @param {Boolean} attenuated + */ scrollToPercentBothDirection: function (percent, time, attenuated) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { + if (this.direction !== ccui.ScrollView.DIR_BOTH) return; - } - var minY = this._size.height - this._innerContainer.getSize().height; + var minY = this._contentSize.height - this._innerContainer.getContentSize().height; var h = -minY; - var w = this._innerContainer.getSize().width - this._size.width; - this.startAutoScrollChildrenWithDestination(cc.p(-(percent.x * w / 100), minY + percent.y * h / 100), time, attenuated); + var w = this._innerContainer.getContentSize().width - this._contentSize.width; + this._startAutoScrollChildrenWithDestination(cc.p(-(percent.x * w / 100), minY + percent.y * h / 100), time, attenuated); }, + /** + * Move inner container to bottom boundary of ScrollView. + */ jumpToBottom: function () { - this.jumpToDestination(this._innerContainer.getPositionX(), 0); + this._jumpToDestination(this._innerContainer.getPositionX(), 0); }, + /** + * Move inner container to top boundary of ScrollView. + */ jumpToTop: function () { - this.jumpToDestination(this._innerContainer.getPositionX(), this._size.height - this._innerContainer.getSize().height); + this._jumpToDestination(this._innerContainer.getPositionX(), this._contentSize.height - this._innerContainer.getContentSize().height); }, + /** + * Move inner container to left boundary of ScrollView. + */ jumpToLeft: function () { - this.jumpToDestination(0, this._innerContainer.getPositionY()); + this._jumpToDestination(0, this._innerContainer.getPositionY()); }, + /** + * Move inner container to right boundary of ScrollView. + */ jumpToRight: function () { - this.jumpToDestination(this._size.width - this._innerContainer.getSize().width, this._innerContainer.getPositionY()); + this._jumpToDestination(this._contentSize.width - this._innerContainer.getContentSize().width, this._innerContainer.getPositionY()); }, + /** + * Move inner container to top and left boundary of ScrollView. + */ jumpToTopLeft: function () { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.jumpToDestination(0, this._size.height - this._innerContainer.getSize().height); + this._jumpToDestination(0, this._contentSize.height - this._innerContainer.getContentSize().height); }, + /** + * Move inner container to top and right boundary of ScrollView. + */ jumpToTopRight: function () { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.jumpToDestination(this._size.width - this._innerContainer.getSize().width, this._size.height - this._innerContainer.getSize().height); + var inSize = this._innerContainer.getContentSize(); + this._jumpToDestination(this._contentSize.width - inSize.width, this._contentSize.height - inSize.height); }, + /** + * Move inner container to bottom and left boundary of ScrollView. + */ jumpToBottomLeft: function () { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.jumpToDestination(0, 0); + this._jumpToDestination(0, 0); }, + /** + * Move inner container to bottom and right boundary of ScrollView. + */ jumpToBottomRight: function () { - if (this.direction != ccui.ScrollView.DIR_BOTH) { - cc.log("Scroll diretion is not both!"); + if (this.direction !== ccui.ScrollView.DIR_BOTH) { + cc.log("Scroll direction is not both!"); return; } - this.jumpToDestination(this._size.width - this._innerContainer.getSize().width, 0); + this._jumpToDestination(this._contentSize.width - this._innerContainer.getContentSize().width, 0); }, + /** + * Move inner container to vertical percent position of ScrollView. + * @param {Number} percent The destination vertical percent, accept value between 0 - 100 + */ jumpToPercentVertical: function (percent) { - var minY = this._size.height - this._innerContainer.getSize().height; + var minY = this._contentSize.height - this._innerContainer.getContentSize().height; var h = -minY; - this.jumpToDestination(this._innerContainer.getPositionX(), minY + percent * h / 100); + this._jumpToDestination(this._innerContainer.getPositionX(), minY + percent * h / 100); }, + /** + * Move inner container to horizontal percent position of ScrollView. + * @param {Number} percent The destination vertical percent, accept value between 0 - 100 + */ jumpToPercentHorizontal: function (percent) { - var w = this._innerContainer.getSize().width - this._size.width; - this.jumpToDestination(-(percent * w / 100), this._innerContainer.getPositionY()); + var w = this._innerContainer.getContentSize().width - this._contentSize.width; + this._jumpToDestination(-(percent * w / 100), this._innerContainer.getPositionY()); }, + /** + * Move inner container to both direction percent position of ScrollView. + * @param {cc.Point} percent The destination vertical percent, accept value between 0 - 100 + */ jumpToPercentBothDirection: function (percent) { - if (this.direction != ccui.ScrollView.DIR_BOTH) { + if (this.direction !== ccui.ScrollView.DIR_BOTH) return; - } - var minY = this._size.height - this._innerContainer.getSize().height; + var inSize = this._innerContainer.getContentSize(); + var minY = this._contentSize.height - inSize.height; var h = -minY; - var w = this._innerContainer.getSize().width - this._size.width; - this.jumpToDestination(-(percent.x * w / 100), minY + percent.y * h / 100); + var w = inSize.width - this._contentSize.width; + this._jumpToDestination(-(percent.x * w / 100), minY + percent.y * h / 100); }, - startRecordSlidAction: function () { - if (this._autoScroll) { - this.stopAutoScrollChildren(); - } - if (this._bouncing) { - this.stopBounceChildren(); - } + _startRecordSlidAction: function () { + if (this._autoScroll) + this._stopAutoScrollChildren(); + if (this._bouncing) + this._stopBounceChildren(); this._slidTime = 0.0; }, - endRecordSlidAction: function () { - if (!this.checkNeedBounce() && this.inertiaScrollEnabled) { - if (this._slidTime <= 0.016) { + _endRecordSlidAction: function () { + if (!this._checkNeedBounce() && this.inertiaScrollEnabled) { + if (this._slidTime <= 0.016) return; - } - var totalDis = 0; - var dir; + var totalDis = 0, dir; + var touchEndPositionInNodeSpace = this.convertToNodeSpace(this._touchEndPosition); + var touchBeganPositionInNodeSpace = this.convertToNodeSpace(this._touchBeganPosition); switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL : - totalDis = this._touchEndedPoint.y - this._touchBeganPoint.y; - if (totalDis < 0) { - dir = ccui.ScrollView.SCROLLDIR_DOWN; - } - else { - dir = ccui.ScrollView.SCROLLDIR_UP; - } + totalDis = touchEndPositionInNodeSpace.y - touchBeganPositionInNodeSpace.y; + dir = (totalDis < 0) ? ccui.ScrollView.SCROLLDIR_DOWN : ccui.ScrollView.SCROLLDIR_UP; break; case ccui.ScrollView.DIR_HORIZONTAL: - totalDis = this._touchEndedPoint.x - this._touchBeganPoint.x; - if (totalDis < 0) { - dir = ccui.ScrollView.SCROLLDIR_LEFT; - } - else { - dir = ccui.ScrollView.SCROLLDIR_RIGHT; - } + totalDis = touchEndPositionInNodeSpace.x - touchBeganPositionInNodeSpace.x; + dir = totalDis < 0 ? ccui.ScrollView.SCROLLDIR_LEFT : ccui.ScrollView.SCROLLDIR_RIGHT; break; case ccui.ScrollView.DIR_BOTH : - var subVector = cc.pSub(this._touchEndedPoint, this._touchBeganPoint); + var subVector = cc.pSub(touchEndPositionInNodeSpace, touchBeganPositionInNodeSpace); totalDis = cc.pLength(subVector); dir = cc.pNormalize(subVector); break; default: + dir = cc.p(0,0); break; } var orSpeed = Math.min(Math.abs(totalDis) / (this._slidTime), ccui.ScrollView.AUTO_SCROLL_MAX_SPEED); - this.startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, true, -1000); + this._startAutoScrollChildrenWithOriginalSpeed(dir, orSpeed, true, -1000); this._slidTime = 0; } }, - handlePressLogic: function (touchPoint) { - this._touchBeganPoint = this.convertToNodeSpace(touchPoint); - this._touchMovingPoint = this._touchBeganPoint; - this.startRecordSlidAction(); + _handlePressLogic: function (touch) { + this._startRecordSlidAction(); this._bePressed = true; }, - handleMoveLogic: function (touchPoint) { - this._touchMovedPoint = this.convertToNodeSpace(touchPoint); - var delta = cc.pSub(this._touchMovedPoint, this._touchMovingPoint); - this._touchMovingPoint = this._touchMovedPoint; + _handleMoveLogic: function (touch) { + var touchPositionInNodeSpace = this.convertToNodeSpace(touch.getLocation()), + previousTouchPositionInNodeSpace = this.convertToNodeSpace(touch.getPreviousLocation()); + var delta = cc.pSub(touchPositionInNodeSpace, previousTouchPositionInNodeSpace); switch (this.direction) { case ccui.ScrollView.DIR_VERTICAL: // vertical - this.scrollChildren(0.0, delta.y); + this._scrollChildren(0.0, delta.y); break; case ccui.ScrollView.DIR_HORIZONTAL: // horizontal - this.scrollChildren(delta.x, 0); + this._scrollChildren(delta.x, 0); break; case ccui.ScrollView.DIR_BOTH: // both - this.scrollChildren(delta.x, delta.y); + this._scrollChildren(delta.x, delta.y); break; default: break; } }, - handleReleaseLogic: function (touchPoint) { - this._touchEndedPoint = this.convertToNodeSpace(touchPoint); - this.endRecordSlidAction(); + _handleReleaseLogic: function (touch) { + this._endRecordSlidAction(); this._bePressed = false; }, - onTouchBegan: function (touch , event) { - var pass = ccui.Layout.prototype.onTouchBegan.call(this, touch , event); - if (this._hitted) { - this.handlePressLogic(this._touchStartPos); + /** + * The touch began event callback handler of ccui.ScrollView. + * @param {cc.Touch} touch + * @param {cc.Event} event + * @returns {boolean} + */ + onTouchBegan: function (touch, event) { + var pass = ccui.Layout.prototype.onTouchBegan.call(this, touch, event); + if(!this._isInterceptTouch){ + if (this._hit) + this._handlePressLogic(touch); } return pass; }, - onTouchMoved: function (touch , event) { - ccui.Layout.prototype.onTouchMoved.call(this, touch , event); - this.handleMoveLogic(this._touchMovePos); - }, - - onTouchEnded: function (touch , event) { - ccui.Layout.prototype.onTouchEnded.call(this, touch , event); - this.handleReleaseLogic(this._touchEndPos); + /** + * The touch moved event callback handler of ccui.ScrollView. + * @param {cc.Touch} touch + * @param {cc.Event} event + */ + onTouchMoved: function (touch, event) { + ccui.Layout.prototype.onTouchMoved.call(this, touch, event); + if(!this._isInterceptTouch) + this._handleMoveLogic(touch); }, - onTouchCancelled: function (touch , event) { - ccui.Layout.prototype.onTouchCancelled.call(this, touch , event); + /** + * The touch ended event callback handler of ccui.ScrollView. + * @param {cc.Touch} touch + * @param {cc.Event} event + */ + onTouchEnded: function (touch, event) { + ccui.Layout.prototype.onTouchEnded.call(this, touch, event); + if(!this._isInterceptTouch) + this._handleReleaseLogic(touch); + this._isInterceptTouch = false; }, - onTouchLongClicked: function (touchPoint) { - + /** + * The touch canceled event callback of ccui.ScrollView. + * @param {cc.Touch} touch + * @param {cc.Event} event + */ + onTouchCancelled: function (touch, event) { + ccui.Layout.prototype.onTouchCancelled.call(this, touch, event); + if (!this._isInterceptTouch) + this.handleReleaseLogic(touch); + this._isInterceptTouch = false; }, + /** + * The update callback handler. + * @param {Number} dt + */ update: function (dt) { - if (this._autoScroll) { - this.autoScrollChildren(dt); - } - if (this._bouncing) { - this.bounceChildren(dt); - } - this.recordSlidTime(dt); + if (this._autoScroll) + this._autoScrollChildren(dt); + if (this._bouncing) + this._bounceChildren(dt); + this._recordSlidTime(dt); }, - recordSlidTime: function (dt) { - if (this._bePressed) { + _recordSlidTime: function (dt) { + if (this._bePressed) this._slidTime += dt; - } }, /** - * Intercept touch event - * @param {number} handleState + * Intercept touch event, handle its child's touch event. + * @override + * @param {number} event event type * @param {ccui.Widget} sender - * @param {cc.Point} touchPoint + * @param {cc.Touch} touch */ - interceptTouchEvent: function (handleState, sender, touchPoint) { - switch (handleState) { - case 0: - this.handlePressLogic(touchPoint); + interceptTouchEvent: function (event, sender, touch) { + var touchPoint = touch.getLocation(); + switch (event) { + case ccui.Widget.TOUCH_BEGAN: + this._isInterceptTouch = true; + this._touchBeganPosition.x = touchPoint.x; + this._touchBeganPosition.y = touchPoint.y; + this._handlePressLogic(touch); break; - case 1: - var offset = cc.pSub(sender.getTouchStartPos(), touchPoint); - if (cc.pLength(offset) > this._childFocusCancelOffset) { - sender.setFocused(false); - this.handleMoveLogic(touchPoint); + case ccui.Widget.TOUCH_MOVED: + var offset = cc.pLength(cc.pSub(sender.getTouchBeganPosition(), touchPoint)); + this._touchMovePosition.x = touchPoint.x; + this._touchMovePosition.y = touchPoint.y; + if (offset > this._childFocusCancelOffset) { + sender.setHighlighted(false); + this._handleMoveLogic(touch); } break; - case 2: - this.handleReleaseLogic(touchPoint); - break; - case 3: - this.handleReleaseLogic(touchPoint); + case ccui.Widget.TOUCH_CANCELED: + case ccui.Widget.TOUCH_ENDED: + this._touchEndPosition.x = touchPoint.x; + this._touchEndPosition.y = touchPoint.y; + this._handleReleaseLogic(touch); + if (sender.isSwallowTouches()) + this._isInterceptTouch = false; break; } }, - /** - * - * @param {number} handleState - * @param {ccui.Widget} sender - * @param {cc.Point} touchPoint - */ - checkChildInfo: function (handleState, sender, touchPoint) { - if(this._enabled && this._touchEnabled) - this.interceptTouchEvent(handleState, sender, touchPoint); - }, - - scrollToTopEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_TOP); + _scrollToTopEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_TOP); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_SCROLL_TO_TOP); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_SCROLL_TO_TOP); }, - scrollToBottomEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM); + _scrollToBottomEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM); }, - scrollToLeftEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_LEFT); + _scrollToLeftEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_LEFT); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_SCROLL_TO_LEFT); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_SCROLL_TO_LEFT); }, - scrollToRightEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_RIGHT); + _scrollToRightEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLL_TO_RIGHT); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_SCROLL_TO_RIGHT); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_SCROLL_TO_RIGHT); }, - scrollingEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLLING); + _scrollingEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_SCROLLING); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_SCROLLING); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_SCROLLING); }, - bounceTopEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_TOP); + _bounceTopEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_TOP); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_BOUNCE_TOP); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_BOUNCE_TOP); }, - bounceBottomEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_BOTTOM); + _bounceBottomEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_BOTTOM); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_BOUNCE_BOTTOM); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_BOUNCE_BOTTOM); }, - bounceLeftEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_LEFT); + _bounceLeftEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_LEFT); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_BOUNCE_LEFT); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_BOUNCE_LEFT); }, - bounceRightEvent: function () { - if (this._scrollViewEventListener && this._scrollViewEventSelector) { - this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_RIGHT); + _bounceRightEvent: function () { + if(this._scrollViewEventSelector){ + if (this._scrollViewEventListener) + this._scrollViewEventSelector.call(this._scrollViewEventListener, this, ccui.ScrollView.EVENT_BOUNCE_RIGHT); + else + this._scrollViewEventSelector(this, ccui.ScrollView.EVENT_BOUNCE_RIGHT); } + if(this._ccEventCallback) + this._ccEventCallback(this, ccui.ScrollView.EVENT_BOUNCE_RIGHT); }, /** + * Adds callback function called ScrollView event triggered * @param {Function} selector - * @param {Object} target + * @param {Object} [target=] + * @deprecated since v3.0, please use addEventListener instead. */ addEventListenerScrollView: function (selector, target) { + this.addEventListener(selector, target); + }, + + /** + * Adds callback function called ScrollView event triggered + * @param {Function} selector + * @param {Object} [target=] + */ + addEventListener: function(selector, target){ this._scrollViewEventSelector = selector; this._scrollViewEventListener = target; }, /** - * set direction + * Changes scroll direction of ScrollView. * @param {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} dir + * Direction::VERTICAL means vertical scroll, Direction::HORIZONTAL means horizontal scroll */ setDirection: function (dir) { this.direction = dir; }, /** - * get direction + * Returns scroll direction of ScrollView. * @returns {ccui.ScrollView.DIR_NONE | ccui.ScrollView.DIR_VERTICAL | ccui.ScrollView.DIR_HORIZONTAL | ccui.ScrollView.DIR_BOTH} */ getDirection: function () { @@ -1531,7 +1617,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * set bounce enabled + * Sets bounce enabled * @param {Boolean} enabled */ setBounceEnabled: function (enabled) { @@ -1539,7 +1625,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * get whether bounce is enabled + * Returns whether bounce is enabled * @returns {boolean} */ isBounceEnabled: function () { @@ -1547,7 +1633,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * set inertiaScroll enabled + * Sets inertiaScroll enabled * @param {boolean} enabled */ setInertiaScrollEnabled: function (enabled) { @@ -1555,7 +1641,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * get whether inertiaScroll is enabled + * Returns whether inertiaScroll is enabled * @returns {boolean} */ isInertiaScrollEnabled: function () { @@ -1563,7 +1649,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * get inner container + * Gets inner container of ScrollView. Inner container is the container of ScrollView's children. * @returns {ccui.Layout} */ getInnerContainer: function () { @@ -1571,7 +1657,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * Sets LayoutType. + * Sets LayoutType of ccui.ScrollView. * @param {ccui.Layout.ABSOLUTE|ccui.Layout.LINEAR_VERTICAL|ccui.Layout.LINEAR_HORIZONTAL|ccui.Layout.RELATIVE} type */ setLayoutType: function (type) { @@ -1579,7 +1665,7 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * Gets LayoutType. + * Returns the layout type of ccui.ScrollView. * @returns {ccui.Layout.ABSOLUTE|ccui.Layout.LINEAR_VERTICAL|ccui.Layout.LINEAR_HORIZONTAL|ccui.Layout.RELATIVE} */ getLayoutType: function () { @@ -1593,27 +1679,92 @@ ccui.ScrollView = ccui.Layout.extend(/** @lends ccui.ScrollView# */{ }, /** - * Returns the "class name" of widget. + * Returns the "class name" of ccui.ScrollView. * @returns {string} */ getDescription: function () { return "ScrollView"; }, - copyClonedWidgetChildren: function (model) { - ccui.Layout.prototype.copyClonedWidgetChildren.call(this, model); + _createCloneInstance: function(){ + return new ccui.ScrollView(); + }, + + _copyClonedWidgetChildren: function (model) { + ccui.Layout.prototype._copyClonedWidgetChildren.call(this, model); + }, + + _copySpecialProperties: function (scrollView) { + if(scrollView instanceof ccui.ScrollView) { + ccui.Layout.prototype._copySpecialProperties.call(this, scrollView); + this.setInnerContainerSize(scrollView.getInnerContainerSize()); + this.setDirection(scrollView.direction); + this.setBounceEnabled(scrollView.bounceEnabled); + this.setInertiaScrollEnabled(scrollView.inertiaScrollEnabled); + this._scrollViewEventListener = scrollView._scrollViewEventListener; + this._scrollViewEventSelector = scrollView._scrollViewEventSelector; + this._ccEventCallback = scrollView._ccEventCallback; + } + }, + + /** + * Returns a node by tag + * @param {Number} tag + * @returns {cc.Node} + * @deprecated since v3.0, please use getChildByTag instead. + */ + getNodeByTag: function (tag) { + return this._innerContainer.getNodeByTag(tag); + }, + + /** + * Returns all nodes of inner container + * @returns {Array} + * @deprecated since v3.0, please use getChildren instead. + */ + getNodes: function () { + return this._innerContainer.getNodes(); + }, + + /** + * Removes a node from ccui.ScrollView. + * @param {cc.Node} node + * @deprecated since v3.0, please use removeChild instead. + */ + removeNode: function (node) { + this._innerContainer.removeNode(node); + }, + + /** + * Removes a node by tag + * @param {Number} tag + * @deprecated since v3.0, please use removeChildByTag instead. + */ + removeNodeByTag: function (tag) { + this._innerContainer.removeNodeByTag(tag); + }, + + /** + * Remove all node from ccui.ScrollView. + * @deprecated since v3.0, please use removeAllChildren instead. + */ + removeAllNodes: function () { + this._innerContainer.removeAllNodes(); }, - copySpecialProperties: function (scrollView) { - ccui.Layout.prototype.copySpecialProperties.call(this, scrollView); - this.setInnerContainerSize(scrollView.getInnerContainerSize()); - this.setDirection(scrollView.direction); - this.setBounceEnabled(scrollView.bounceEnabled); - this.setInertiaScrollEnabled(scrollView.inertiaScrollEnabled); + /** + * Add node for scrollView + * @param {cc.Node} node + * @param {Number} zOrder + * @param {Number} tag + * @deprecated since v3.0, please use addChild instead. + */ + addNode: function (node, zOrder, tag) { + this._innerContainer.addNode(node, zOrder, tag); } }); -window._p = ccui.ScrollView.prototype; +var _p = ccui.ScrollView.prototype; // Extended properties /** @expose */ @@ -1623,44 +1774,110 @@ cc.defineGetterSetter(_p, "innerWidth", _p._getInnerWidth, _p._setInnerWidth); _p.innerHeight; cc.defineGetterSetter(_p, "innerHeight", _p._getInnerHeight, _p._setInnerHeight); -delete window._p; +_p = null; /** * allocates and initializes a UIScrollView. - * @constructs + * @deprecated since v3.0, please use new ccui.ScrollView() instead. * @return {ccui.ScrollView} - * @example - * // example - * var uiScrollView = ccui.ScrollView.create(); */ ccui.ScrollView.create = function () { - var uiScrollView = new ccui.ScrollView(); - if (uiScrollView && uiScrollView.init()) { - return uiScrollView; - } - return null; + return new ccui.ScrollView(); }; // Constants //ScrollView direction +/** + * The none flag of ccui.ScrollView's direction. + * @constant + * @type {number} + */ ccui.ScrollView.DIR_NONE = 0; +/** + * The vertical flag of ccui.ScrollView's direction. + * @constant + * @type {number} + */ ccui.ScrollView.DIR_VERTICAL = 1; +/** + * The horizontal flag of ccui.ScrollView's direction. + * @constant + * @type {number} + */ ccui.ScrollView.DIR_HORIZONTAL = 2; +/** + * The both flag of ccui.ScrollView's direction. + * @constant + * @type {number} + */ ccui.ScrollView.DIR_BOTH = 3; //ScrollView event +/** + * The flag scroll to top of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_SCROLL_TO_TOP = 0; +/** + * The flag scroll to bottom of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_SCROLL_TO_BOTTOM = 1; +/** + * The flag scroll to left of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_SCROLL_TO_LEFT = 2; +/** + * The flag scroll to right of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_SCROLL_TO_RIGHT = 3; +/** + * The scrolling flag of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_SCROLLING = 4; +/** + * The flag bounce top of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_BOUNCE_TOP = 5; +/** + * The flag bounce bottom of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_BOUNCE_BOTTOM = 6; +/** + * The flag bounce left of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_BOUNCE_LEFT = 7; +/** + * The flag bounce right of ccui.ScrollView's event. + * @constant + * @type {number} + */ ccui.ScrollView.EVENT_BOUNCE_RIGHT = 8; - +/** + * The auto scroll max speed of ccui.ScrollView. + * @constant + * @type {number} + */ ccui.ScrollView.AUTO_SCROLL_MAX_SPEED = 1000; + +/** + * @ignore + */ ccui.ScrollView.SCROLLDIR_UP = cc.p(0, 1); ccui.ScrollView.SCROLLDIR_DOWN = cc.p(0, -1); ccui.ScrollView.SCROLLDIR_LEFT = cc.p(-1, 0); diff --git a/extensions/cocostudio/CocoStudio.js b/extensions/cocostudio/CocoStudio.js index 74ba3c0751..fdb2ddcea8 100644 --- a/extensions/cocostudio/CocoStudio.js +++ b/extensions/cocostudio/CocoStudio.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,7 +23,8 @@ THE SOFTWARE. ****************************************************************************/ /** - * @namespace Base namespace of cocostuidio + * The main namespace of Cocostudio, all classes, functions, properties and constants of Spine are defined in this namespace + * @namespace * @name ccs */ var ccs = ccs || {}; @@ -42,14 +44,6 @@ ccs.Class.extend = ccs.Class.extend || cc.Class.extend; ccs.Node = ccs.Node || cc.Node; ccs.Node.extend = ccs.Node.extend || cc.Node.extend; -/** - * The same as cc.RBGA - * @class - * @extends ccs.Class - */ -ccs.NodeRGBA = ccs.NodeRGBA || cc.NodeRGBA; -ccs.NodeRGBA.extend = ccs.NodeRGBA.extend || cc.NodeRGBA.extend; - /** * The same as cc.Sprite * @class @@ -68,6 +62,7 @@ ccs.Component.extend = ccs.Component.extend || cc.Component.extend; /** * CocoStudio version + * @constant * @type {string} */ ccs.cocostudioVersion = "v1.3.0.0"; \ No newline at end of file diff --git a/extensions/cocostudio/action/CCActionFrame.js b/extensions/cocostudio/action/CCActionFrame.js index e26f347538..2571031de9 100644 --- a/extensions/cocostudio/action/CCActionFrame.js +++ b/extensions/cocostudio/action/CCActionFrame.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -24,49 +25,271 @@ //Action frame type /** - * @ignore + * The flag move action type of Cocostudio frame. + * @constant + * @type {number} */ ccs.FRAME_TYPE_MOVE = 0; +/** + * The flag scale action type of Cocostudio frame. + * @constant + * @type {number} + */ ccs.FRAME_TYPE_SCALE = 1; +/** + * The flag rotate action type of Cocostudio frame. + * @constant + * @type {number} + */ ccs.FRAME_TYPE_ROTATE = 2; +/** + * The flag tint action type of Cocostudio frame. + * @constant + * @type {number} + */ ccs.FRAME_TYPE_TINT = 3; +/** + * The flag fade action type of Cocostudio frame. + * @constant + * @type {number} + */ ccs.FRAME_TYPE_FADE = 4; +/** + * The max flag of Cocostudio frame. + * @constant + * @type {number} + */ ccs.FRAME_TYPE_MAX = 5; /** - * Base class for ccs.ActionFrame + * The ease type of Cocostudio frame. + * @constant + * @type {Object} + */ +ccs.FrameEaseType = { + CUSTOM : -1, + + LINEAR : 0, + + SINE_EASEIN : 1, + SINE_EASEOUT : 2, + SINE_EASEINOUT : 3, + + QUAD_EASEIN : 4, + QUAD_EASEOUT : 5, + QUAD_EASEINOUT : 6, + + CUBIC_EASEIN : 7, + CUBIC_EASEOUT : 8, + CUBIC_EASEINOUT : 9, + + QUART_EASEIN : 10, + QUART_EASEOUT : 11, + QUART_EASEINOUT : 12, + + QUINT_EASEIN : 13, + QUINT_EASEOUT : 14, + QUINT_EASEINOUT : 15, + + EXPO_EASEIN : 16, + EXPO_EASEOUT : 17, + EXPO_EASEINOUT : 18, + + CIRC_EASEIN : 19, + CIRC_EASEOUT : 20, + CIRC_EASEINOUT : 21, + + ELASTIC_EASEIN : 22, + ELASTIC_EASEOUT : 23, + ELASTIC_EASEINOUT : 24, + + BACK_EASEIN : 25, + BACK_EASEOUT : 26, + BACK_EASEINOUT : 27, + + BOUNCE_EASEIN : 28, + BOUNCE_EASEOUT : 29, + BOUNCE_EASEINOUT : 30, + + TWEEN_EASING_MAX: 1000 +}; + + +/** + * The action frame of Cocostudio. It's the base class of ccs.ActionMoveFrame, ccs.ActionScaleFrame etc. * @class * @extends ccs.Class + * + * @property {Number} frameType - frame type of ccs.ActionFrame + * @property {Number} easingType - easing type of ccs.ActionFrame + * @property {Number} frameIndex - frame index of ccs.ActionFrame + * @property {Number} time - time of ccs.ActionFrame */ ccs.ActionFrame = ccs.Class.extend(/** @lends ccs.ActionFrame# */{ frameType: 0, easingType: 0, frameIndex: 0, + _Parameter: null, time: 0, + + /** + * The constructor of cc.ActionFrame. + */ ctor: function () { this.frameType = 0; - this.easingType = 0; + this.easingType = ccs.FrameEaseType.LINEAR; this.frameIndex = 0; this.time = 0; }, /** - * Gets the action of ActionFrame. - * @param {number} duration + * Returns the action of ActionFrame. its subClass need override it. + * @param {number} duration the duration time of ActionFrame + * @param {ccs.ActionFrame} srcFrame source frame. * @returns {null} */ - getAction: function (duration) { + getAction: function (duration, srcFrame) { + cc.log("Need a definition of for ActionFrame"); return null; + }, + + _getEasingAction : function (action) { + if (action === null) { + console.error("Action cannot be null!"); + return null; + } + + var resultAction; + switch (this.easingType) { + case ccs.FrameEaseType.CUSTOM: + break; + case ccs.FrameEaseType.LINEAR: + resultAction = action; + break; + case ccs.FrameEaseType.SINE_EASEIN: + resultAction = action.easing(cc.easeSineIn()); + break; + case ccs.FrameEaseType.SINE_EASEOUT: + resultAction = action.easing(cc.easeSineOut()); + break; + case ccs.FrameEaseType.SINE_EASEINOUT: + resultAction = action.easing(cc.easeSineInOut()); + break; + case ccs.FrameEaseType.QUAD_EASEIN: + resultAction = action.easing(cc.easeQuadraticActionIn()); + break; + case ccs.FrameEaseType.QUAD_EASEOUT: + resultAction = action.easing(cc.easeQuadraticActionOut()); + break; + case ccs.FrameEaseType.QUAD_EASEINOUT: + resultAction = action.easing(cc.easeQuadraticActionInOut()); + break; + case ccs.FrameEaseType.CUBIC_EASEIN: + resultAction = action.easing(cc.easeCubicActionIn()); + break; + case ccs.FrameEaseType.CUBIC_EASEOUT: + resultAction = action.easing(cc.easeCubicActionOut()); + break; + case ccs.FrameEaseType.CUBIC_EASEINOUT: + resultAction = action.easing(cc.easeCubicActionInOut()); + break; + case ccs.FrameEaseType.QUART_EASEIN: + resultAction = action.easing(cc.easeQuarticActionIn()); + break; + case ccs.FrameEaseType.QUART_EASEOUT: + resultAction = action.easing(cc.easeQuarticActionOut()); + break; + case ccs.FrameEaseType.QUART_EASEINOUT: + resultAction = action.easing(cc.easeQuarticActionInOut()); + break; + case ccs.FrameEaseType.QUINT_EASEIN: + resultAction = action.easing(cc.easeQuinticActionIn()); + break; + case ccs.FrameEaseType.QUINT_EASEOUT: + resultAction = action.easing(cc.easeQuinticActionOut()); + break; + case ccs.FrameEaseType.QUINT_EASEINOUT: + resultAction = action.easing(cc.easeQuinticActionInOut()); + break; + case ccs.FrameEaseType.EXPO_EASEIN: + resultAction = action.easing(cc.easeExponentialIn()); + break; + case ccs.FrameEaseType.EXPO_EASEOUT: + resultAction = action.easing(cc.easeExponentialOut()); + break; + case ccs.FrameEaseType.EXPO_EASEINOUT: + resultAction = action.easing(cc.easeExponentialInOut()); + break; + case ccs.FrameEaseType.CIRC_EASEIN: + resultAction = action.easing(cc.easeCircleActionIn()); + break; + case ccs.FrameEaseType.CIRC_EASEOUT: + resultAction = action.easing(cc.easeCircleActionOut()); + break; + case ccs.FrameEaseType.CIRC_EASEINOUT: + resultAction = action.easing(cc.easeCircleActionInOut()); + break; + case ccs.FrameEaseType.ELASTIC_EASEIN: + resultAction = action.easing(cc.easeElasticIn()); + break; + case ccs.FrameEaseType.ELASTIC_EASEOUT: + resultAction = action.easing(cc.easeElasticOut()); + break; + case ccs.FrameEaseType.ELASTIC_EASEINOUT: + resultAction = action.easing(cc.easeElasticInOut()); + break; + case ccs.FrameEaseType.BACK_EASEIN: + resultAction = action.easing(cc.easeBackIn()); + break; + case ccs.FrameEaseType.BACK_EASEOUT: + resultAction = action.easing(cc.easeBackOut()); + break; + case ccs.FrameEaseType.BACK_EASEINOUT: + resultAction = action.easing(cc.easeBackInOut()); + break; + case ccs.FrameEaseType.BOUNCE_EASEIN: + resultAction = action.easing(cc.easeBounceIn()); + break; + case ccs.FrameEaseType.BOUNCE_EASEOUT: + resultAction = action.easing(cc.easeBounceOut()); + break; + case ccs.FrameEaseType.BOUNCE_EASEINOUT: + resultAction = action.easing(cc.easeBounceInOut()); + break; + } + + return resultAction; + }, + + /** + * Sets the easing parameter to action frame. + * @param {Array} parameter + */ + setEasingParameter: function(parameter){ + this._Parameter = []; + for(var i=0;i locFrameIndex ? locFrameIndex : locFrameindex; } - if (!locIsFindFrame) { + if (!bFindFrame) locFrameindex = 0; - } return locFrameindex; }, /** - * Gets index of last ActionFrame. + * Returns the index of last ccs.ActionFrame. * @returns {number} */ getLastFrameIndex: function () { var locFrameindex = -1; - var locIsFindFrame = false; - for (var i = 0; i < this._frameArrayNum; i++) { - var locArray = this._frameArray[i]; - if (locArray.length <= 0) { + var locIsFindFrame = false ,locFrameArray = this._frameArray; + for (var i = 0, len = this._frameArrayNum; i < len; i++) { + var locArray = locFrameArray[i]; + if (locArray.length <= 0) continue; - } locIsFindFrame = true; var locFrame = locArray[locArray.length - 1]; var locFrameIndex = locFrame.frameIndex; locFrameindex = locFrameindex < locFrameIndex ? locFrameIndex : locFrameindex; } - if (!locIsFindFrame) { + if (!locIsFindFrame) locFrameindex = 0; - } return locFrameindex; }, /** * Updates action states to some time. - * @param time + * @param {Number} time * @returns {boolean} */ updateActionToTimeLine: function (time) { @@ -367,28 +368,25 @@ ccs.ActionNode = ccs.Class.extend(/** @lends ccs.ActionNode# */{ var locUnitTime = this.getUnitTime(); for (var i = 0; i < this._frameArrayNum; i++) { var locArray = this._frameArray[i]; - if (locArray == null) { + if (locArray === null) continue; - } for (var j = 0; j < locArray.length; j++) { var locFrame = locArray[j]; - if (locFrame.frameIndex * locUnitTime == time) { - this.easingToFrame(1.0, 1.0, locFrame); + if (locFrame.frameIndex * locUnitTime === time) { + this._easingToFrame(1.0, 1.0, locFrame); locIsFindFrame = true; break; - } - else if (locFrame.frameIndex * locUnitTime > time) { - if (j == 0) { - this.easingToFrame(1.0, 1.0, locFrame); + } else if (locFrame.frameIndex * locUnitTime > time) { + if (j === 0) { + this._easingToFrame(1.0, 1.0, locFrame); locIsFindFrame = false; - } - else { + } else { var locSrcFrame = locArray[j - 1]; var locDuration = (locFrame.frameIndex - locSrcFrame.frameIndex) * locUnitTime; var locDelaytime = time - locSrcFrame.frameIndex * locUnitTime; - this.easingToFrame(locDuration, 1.0, locSrcFrame); - this.easingToFrame(locDuration, locDelaytime / locDuration, locFrame); + this._easingToFrame(locDuration, 1.0, locSrcFrame); + this._easingToFrame(locDuration, locDelaytime / locDuration, locFrame); locIsFindFrame = true; } break; @@ -398,26 +396,22 @@ ccs.ActionNode = ccs.Class.extend(/** @lends ccs.ActionNode# */{ return locIsFindFrame; }, - /** - * Easing to frame - * @param {number} duration - * @param {number} delayTime - * @param {ccs.ActionFrame} destFrame - */ - easingToFrame: function (duration, delayTime, destFrame) { + _easingToFrame: function (duration, delayTime, destFrame) { var action = destFrame.getAction(duration); var node = this.getActionNode(); - if (action == null || node == null) { + if (action == null || node == null) return; - } action.startWithTarget(node); action.update(delayTime); }, + /** + * Returns if the action is done once time. + * @returns {Boolean} that if the action is done once time + */ isActionDoneOnce: function () { - if (this._action == null) { + if (this._action === null) return true; - } return this._action.isDone(); } }); \ No newline at end of file diff --git a/extensions/cocostudio/action/CCActionObject.js b/extensions/cocostudio/action/CCActionObject.js index 8430b73635..88597f382e 100644 --- a/extensions/cocostudio/action/CCActionObject.js +++ b/extensions/cocostudio/action/CCActionObject.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * Base class for ccs.ActionObject + * The Cocostudio's action object. * @class * @extends ccs.Class */ @@ -36,6 +37,12 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ _unitTime: 0, _currentTime: 0, _scheduler:null, + _callback: null, + _fTotalTime: 0, + + /** + * Construction of ccs.ActionObject. + */ ctor: function () { this._actionNodeList = []; this._name = ""; @@ -44,12 +51,12 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ this._playing = false; this._unitTime = 0.1; this._currentTime = 0; - this._scheduler = new cc.Scheduler(); - cc.director.getScheduler().scheduleUpdateForTarget(this._scheduler, 0, false); + this._fTotalTime = 0; + this._scheduler = cc.director.getScheduler(); }, /** - * Sets name for object + * Sets name to ccs.ActionObject * @param {string} name */ setName: function (name) { @@ -57,7 +64,7 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ }, /** - * Gets name for object + * Returns name fo ccs.ActionObject * @returns {string} */ getName: function () { @@ -73,7 +80,7 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ }, /** - * Gets if the action will loop play. + * Returns if the action will loop play. * @returns {boolean} */ getLoop: function () { @@ -94,15 +101,15 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ }, /** - * Gets the time interval of frame. - * @returns {number} + * Returns the time interval of frame. + * @returns {number} the time interval of frame */ getUnitTime: function () { return this._unitTime; }, /** - * Gets the current time of frame. + * Returns the current time of frame. * @returns {number} */ getCurrentTime: function () { @@ -111,15 +118,23 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ /** * Sets the current time of frame. - * @param time + * @param {Number} time the current time of frame */ setCurrentTime: function (time) { this._currentTime = time; }, /** - * Return if the action is playing. - * @returns {boolean} + * Returns the total time of frame. + * @returns {number} the total time of frame + */ + getTotalTime: function(){ + return this._fTotalTime; + }, + + /** + * Returns if the action is playing. + * @returns {boolean} true if the action is playing, false the otherwise */ isPlaying: function () { return this._playing; @@ -135,14 +150,20 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ this.setLoop(dic["loop"]); this.setUnitTime(dic["unittime"]); var actionNodeList = dic["actionnodelist"]; + var maxLength = 0; for (var i = 0; i < actionNodeList.length; i++) { - var locActionNode = new ccs.ActionNode(); - var locActionNodeDic = actionNodeList[i]; - locActionNode.initWithDictionary(locActionNodeDic, root); - locActionNode.setUnitTime(this.getUnitTime()); - this._actionNodeList.push(locActionNode); - locActionNodeDic = null; + var actionNode = new ccs.ActionNode(); + + var actionNodeDic = actionNodeList[i]; + actionNode.initWithDictionary(actionNodeDic, root); + actionNode.setUnitTime(this.getUnitTime()); + this._actionNodeList.push(actionNode); + var length = actionNode.getLastFrameIndex() - actionNode.getFirstFrameIndex(); + if(length > maxLength){ + maxLength = length; + } } + this._fTotalTime = maxLength * this._unitTime; }, /** @@ -150,9 +171,8 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ * @param {ccs.ActionNode} node */ addActionNode: function (node) { - if (!node) { + if (!node) return; - } this._actionNodeList.push(node); node.setUnitTime(this._unitTime); }, @@ -162,50 +182,51 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ * @param {ccs.ActionNode} node */ removeActionNode: function (node) { - if (node == null) { + if (node == null) return; - } cc.arrayRemoveObject(this._actionNodeList, node); }, /** - * Play the action. - * @param {cc.CallFunc} fun + * Plays the action. + * @param {cc.CallFunc} [fun] Action Call Back */ play: function (fun) { this.stop(); this.updateToFrameByTime(0); - var frameNum = this._actionNodeList.length; + var locActionNodeList = this._actionNodeList; + var frameNum = locActionNodeList.length; for (var i = 0; i < frameNum; i++) { - var locActionNode = this._actionNodeList[i]; - locActionNode.playAction(fun); + locActionNodeList[i].playAction(fun); } - if (this._loop) { - this._scheduler.scheduleCallbackForTarget(this, this.simulationActionUpdate, 0, cc.REPEAT_FOREVER, 0, false); - } + if (this._loop) + this._scheduler.schedule(this.simulationActionUpdate, this, 0, cc.REPEAT_FOREVER, 0, false, this.__instanceId + ""); + if(fun !== undefined) + this._callback = fun; }, /** - * pause the action. + * Pauses the action. */ pause: function () { this._pause = true; + this._playing = false; }, /** - * stop the action. + * Stop the action. */ stop: function () { - for (var i = 0; i < this._actionNodeList.length; i++) { - var locActionNode = this._actionNodeList[i]; - locActionNode.stopAction(); - } - this._scheduler.unscheduleCallbackForTarget(this, this.simulationActionUpdate); + var locActionNodeList = this._actionNodeList; + for (var i = 0; i < locActionNodeList.length; i++) + locActionNodeList[i].stopAction(); + this._scheduler.unschedule(this.simulationActionUpdate, this); this._pause = false; + this._playing = false; }, /** - * Method of update frame . + * Updates frame by time. */ updateToFrameByTime: function (time) { this._currentTime = time; @@ -214,19 +235,28 @@ ccs.ActionObject = ccs.Class.extend(/** @lends ccs.ActionObject# */{ locActionNode.updateActionToTimeLine(time); } }, + + /** + * scheduler update function + * @param {Number} dt delta time + */ simulationActionUpdate: function (dt) { - if (this._loop) { - var isEnd = true; - var actionNodeList = this._actionNodeList; - for (var i = 0; i < actionNodeList.length; i++) { - var actionNode = actionNodeList[i]; - if (actionNode.isActionDoneOnce() == false) { - isEnd = false; - break; - } + var isEnd = true, locNodeList = this._actionNodeList; + for(var i = 0, len = locNodeList.length; i < len; i++) { + if (!locNodeList[i].isActionDoneOnce()){ + isEnd = false; + break; } - if (isEnd) { + } + + if (isEnd){ + if (this._callback !== null) + this._callback.execute(); + if (this._loop) this.play(); + else{ + this._playing = false; + this._scheduler.unschedule(this.simulationActionUpdate, this); } } } diff --git a/extensions/cocostudio/armature/CCArmature.js b/extensions/cocostudio/armature/CCArmature.js index 6755985872..7e8c58c3c9 100644 --- a/extensions/cocostudio/armature/CCArmature.js +++ b/extensions/cocostudio/armature/CCArmature.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,9 +24,9 @@ ****************************************************************************/ /** - * Base class for ccs.Armature objects. + * The main class of Armature, it plays armature animation, manages and updates bones' state. * @class - * @extends ccs.NodeRGBA + * @extends ccs.Node * * @property {ccs.Bone} parentBone - The parent bone of the armature node * @property {ccs.ArmatureAnimation} animation - The animation @@ -36,158 +37,147 @@ * @property {Object} body - The body of the armature * @property {ccs.ColliderFilter} colliderFilter - <@writeonly> The collider filter of the armature */ -ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ - animation:null, - armatureData:null, - batchNode:null, - name:"", - _textureAtlas:null, - _parentBone:null, - _boneDic:null, - _topBoneList:null, - _armatureIndexDic:null, - _offsetPoint:null, - version:0, - _armatureTransformDirty:true, - _body:null, - _textureAtlasDic:null, - _blendFunc:null, - _className:"Armature", - - /** - * Create a armature node. - * @constructor - * @param {String} name - * @param {ccs.Bone} parentBone - * @example - * var armature = new ccs.Armature(); - */ - ctor:function (name, parentBone) { - cc.NodeRGBA.prototype.ctor.call(this); - this.animation = null; - this.armatureData = null; - this.batchNode = null; - this.name = ""; - this._textureAtlas = null; - this._parentBone = null; - this._boneDic = null; - this._topBoneList = null; +ccs.Armature = ccs.Node.extend(/** @lends ccs.Armature# */{ + animation: null, + armatureData: null, + batchNode: null, + _textureAtlas: null, + _parentBone: null, + _boneDic: null, + _topBoneList: null, + _armatureIndexDic: null, + _offsetPoint: null, + version: 0, + _armatureTransformDirty: true, + _body: null, + _blendFunc: null, + _className: "Armature", + + /** + * Create a armature node. + * Constructor of ccs.Armature + * @param {String} name + * @param {ccs.Bone} parentBone + * @example + * var armature = new ccs.Armature(); + */ + ctor: function (name, parentBone) { + cc.Node.prototype.ctor.call(this); + this._name = ""; + this._topBoneList = []; this._armatureIndexDic = {}; this._offsetPoint = cc.p(0, 0); - this.version = 0; this._armatureTransformDirty = true; - this._body = null; - this._textureAtlasDic = null; - this._blendFunc = null; - - parentBone && ccs.Armature.prototype.init.call(this, name, parentBone); + this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; + name && ccs.Armature.prototype.init.call(this, name, parentBone); }, /** * Initializes a CCArmature with the specified name and CCBone - * @param {String} name - * @param {ccs.Bone} parentBone + * @param {String} [name] + * @param {ccs.Bone} [parentBone] * @return {Boolean} */ - init:function (name, parentBone) { - cc.NodeRGBA.prototype.init.call(this); - if (parentBone) { + init: function (name, parentBone) { + cc.Node.prototype.init.call(this); + if (parentBone) this._parentBone = parentBone; - } this.removeAllChildren(); this.animation = new ccs.ArmatureAnimation(); this.animation.init(this); + this._boneDic = {}; - this._topBoneList = []; - this._textureAtlasDic = {}; - this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; - this.name = (!name) ? "" : name; + this._topBoneList.length = 0; + + //this._name = name || ""; var armatureDataManager = ccs.armatureDataManager; - if (name != "") { + + var animationData; + if (name !== "") { //animationData - var animationData = armatureDataManager.getAnimationData(name); - if (!animationData) { - cc.log("AnimationData not exist! "); - return false; - } + animationData = armatureDataManager.getAnimationData(name); + cc.assert(animationData, "AnimationData not exist!"); + this.animation.setAnimationData(animationData); //armatureData var armatureData = armatureDataManager.getArmatureData(name); + cc.assert(armatureData, "ArmatureData not exist!"); + this.armatureData = armatureData; //boneDataDic var boneDataDic = armatureData.getBoneDataDic(); for (var key in boneDataDic) { var bone = this.createBone(String(key)); + //! init bone's Tween to 1st movement's 1st frame do { var movData = animationData.getMovement(animationData.movementNames[0]); - if (!movData) { - break; - } + if (!movData) break; + var _movBoneData = movData.getMovementBoneData(bone.getName()); - if (!_movBoneData || _movBoneData.frameList.length <= 0) { - break; - } + if (!_movBoneData || _movBoneData.frameList.length <= 0) break; + var frameData = _movBoneData.getFrameData(0); - if (!frameData) { - break; - } + if (!frameData) break; + bone.getTweenData().copy(frameData); bone.changeDisplayWithIndex(frameData.displayIndex, false); } while (0); } + this.update(0); this.updateOffsetPoint(); } else { - this.name = "new_armature"; + name = "new_armature"; this.armatureData = new ccs.ArmatureData(); - this.armatureData.name = this.name; + this.armatureData.name = name; - var animationData = new ccs.AnimationData(); - animationData.name = this.name; + animationData = new ccs.AnimationData(); + animationData.name = name; - armatureDataManager.addArmatureData(this.name, this.armatureData); - armatureDataManager.addAnimationData(this.name, animationData); + armatureDataManager.addArmatureData(name, this.armatureData); + armatureDataManager.addAnimationData(name, animationData); this.animation.setAnimationData(animationData); } - if (cc._renderType === cc._RENDER_TYPE_WEBGL) { - this.setShaderProgram(cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE_UCOLOR)); - } + + this._renderCmd.initShaderCache(); this.setCascadeOpacityEnabled(true); this.setCascadeColorEnabled(true); return true; }, - onEnter:function(){ - cc.NodeRGBA.prototype.onEnter.call(this); - this.scheduleUpdate(); - }, - onExit:function(){ - cc.NodeRGBA.prototype.onExit.call(this); - this.unscheduleUpdate(); + + addChild: function (child, localZOrder, tag) { + if(child instanceof ccui.Widget){ + cc.log("Armature doesn't support to add Widget as its child, it will be fix soon."); + return; + } + cc.Node.prototype.addChild.call(this, child, localZOrder, tag); }, + /** - * create a bone + * create a bone with name * @param {String} boneName * @return {ccs.Bone} */ - createBone:function (boneName) { + createBone: function (boneName) { var existedBone = this.getBone(boneName); - if (existedBone) { + if (existedBone) return existedBone; - } + var boneData = this.armatureData.getBoneData(boneName); var parentName = boneData.parentName; + var bone = null; - if (parentName != "") { + if (parentName) { this.createBone(parentName); - bone = ccs.Bone.create(boneName); + bone = new ccs.Bone(boneName); this.addBone(bone, parentName); } else { - bone = ccs.Bone.create(boneName); + bone = new ccs.Bone(boneName); this.addBone(bone, ""); } @@ -197,77 +187,66 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ }, /** - * add a bone - * @param {ccs.Bone} bone - * @param {String} parentName + * Add a Bone to this Armature + * @param {ccs.Bone} bone The Bone you want to add to Armature + * @param {String} parentName The parent Bone's name you want to add to. If it's null, then set Armature to its parent */ - addBone:function (bone, parentName) { - if (!bone) { - cc.log("Argument must be non-nil"); - return; - } - if (this._boneDic[bone.getName()]) { - cc.log("bone already added. It can't be added again"); - return; - } + addBone: function (bone, parentName) { + cc.assert(bone, "Argument must be non-nil"); + var locBoneDic = this._boneDic; + if(bone.getName()) + cc.assert(!locBoneDic[bone.getName()], "bone already added. It can't be added again"); if (parentName) { - var boneParent = this._boneDic[parentName]; - if (boneParent) { + var boneParent = locBoneDic[parentName]; + if (boneParent) boneParent.addChildBone(bone); - } - else { + else this._topBoneList.push(bone); - } - } - else { + } else this._topBoneList.push(bone); - } bone.setArmature(this); - this._boneDic[bone.getName()] = bone; + + locBoneDic[bone.getName()] = bone; this.addChild(bone); }, /** - * remove a bone - * @param {ccs.Bone} bone - * @param {Boolean} recursion + * Remove a bone with the specified name. If recursion it will also remove child Bone recursively. + * @param {ccs.Bone} bone The bone you want to remove + * @param {Boolean} recursion Determine whether remove the bone's child recursion. */ - removeBone:function (bone, recursion) { - if (!bone) { - cc.log("bone must be added to the bone dictionary!"); - return; - } + removeBone: function (bone, recursion) { + cc.assert(bone, "bone must be added to the bone dictionary!"); bone.setArmature(null); bone.removeFromParent(recursion); cc.arrayRemoveObject(this._topBoneList, bone); + delete this._boneDic[bone.getName()]; this.removeChild(bone, true); }, /** - * get a bone by name - * @param {String} name + * Gets a bone with the specified name + * @param {String} name The bone's name you want to get * @return {ccs.Bone} */ - getBone:function (name) { + getBone: function (name) { return this._boneDic[name]; }, /** * Change a bone's parent with the specified parent name. - * @param {ccs.Bone} bone - * @param {String} parentName + * @param {ccs.Bone} bone The bone you want to change parent + * @param {String} parentName The new parent's name */ - changeBoneParent:function (bone, parentName) { - if (!bone) { - cc.log("bone must be added to the bone dictionary!"); - return; - } + changeBoneParent: function (bone, parentName) { + cc.assert(bone, "bone must be added to the bone dictionary!"); + var parentBone = bone.getParentBone(); - if(parentBone){ - cc.arrayRemoveObject(parentBone.getChildrenBone(), bone); + if (parentBone) { + cc.arrayRemoveObject(parentBone.getChildren(), bone); bone.setParentBone(null); } @@ -275,242 +254,133 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ var boneParent = this._boneDic[parentName]; if (boneParent) { boneParent.addChildBone(bone); - cc.arrayRemoveObject(this._topBoneList,bone); - }else{ + cc.arrayRemoveObject(this._topBoneList, bone); + } else this._topBoneList.push(bone); - } } }, /** * Get CCArmature's bone dictionary - * @return {Object} + * @return {Object} Armature's bone dictionary */ - getBoneDic:function () { + getBoneDic: function () { return this._boneDic; }, /** * Set contentSize and Calculate anchor point. */ - updateOffsetPoint:function () { + updateOffsetPoint: function () { // Set contentsize and Calculate anchor point. - var rect = this.boundingBox(); + var rect = this.getBoundingBox(); this.setContentSize(rect); var locOffsetPoint = this._offsetPoint; locOffsetPoint.x = -rect.x; locOffsetPoint.y = -rect.y; - if (rect.width != 0 && rect.height != 0) { + if (rect.width !== 0 && rect.height !== 0) this.setAnchorPoint(locOffsetPoint.x / rect.width, locOffsetPoint.y / rect.height); - } }, - update:function (dt) { - this.animation.update(dt); - var locTopBoneList = this._topBoneList; - for (var i = 0; i < locTopBoneList.length; i++) { - locTopBoneList[i].update(dt); - } - this._armatureTransformDirty = false; + getOffsetPoints: function(){ + return {x: this._offsetPoint.x, y: this._offsetPoint.y}; }, + /** + * Sets animation to this Armature + * @param {ccs.ArmatureAnimation} animation + */ + setAnimation: function (animation) { + this.animation = animation; + }, - nodeToParentTransform: null, - - _nodeToParentTransformForWebGL:function () { - if (this._transformDirty) { - this._armatureTransformDirty = true; - // Translate values - var x = this._position.x; - var y = this._position.y; - var apx = this._anchorPointInPoints.x, napx = -apx; - var apy = this._anchorPointInPoints.y, napy = -apy; - var scx = this._scaleX, scy = this._scaleY; - - if (this._ignoreAnchorPointForPosition) { - x += apx; - y += apy; - } - - // Rotation values - // Change rotation code to handle X and Y - // If we skew with the exact same value for both x and y then we're simply just rotating - var cx = 1, sx = 0, cy = 1, sy = 0; - if (this._rotationX !== 0 || this._rotationY !== 0) { - cx = Math.cos(-this._rotationRadiansX); - sx = Math.sin(-this._rotationRadiansX); - cy = Math.cos(-this._rotationRadiansY); - sy = Math.sin(-this._rotationRadiansY); - } - - // Add offset point - x += cy * this._offsetPoint.x * this._scaleX + -sx * this._offsetPoint.y * this._scaleY; - y += sy * this._offsetPoint.x * this._scaleX + cx * this._offsetPoint.y * this._scaleY; - - var needsSkewMatrix = ( this._skewX || this._skewY ); - - // optimization: - // inline anchor point calculation if skew is not needed - // Adjusted transform calculation for rotational skew - if (!needsSkewMatrix && (apx !== 0 || apy !== 0)) { - x += cy * napx * scx + -sx * napy * scy; - y += sy * napx * scx + cx * napy * scy; - } - - // Build Transform Matrix - // Adjusted transform calculation for rotational skew - var t = {a:cy * scx, b:sy * scx, c:-sx * scy, d:cx * scy, tx:x, ty:y}; - - // XXX: Try to inline skew - // If skew is needed, apply skew and then anchor point - if (needsSkewMatrix) { - t = cc.AffineTransformConcat({a:1.0, b:Math.tan(cc.degreesToRadians(this._skewY)), - c:Math.tan(cc.degreesToRadians(this._skewX)), d:1.0, tx:0.0, ty:0.0}, t); - - // adjust anchor point - if (apx !== 0 || apy !== 0) - t = cc.AffineTransformTranslate(t, napx, napy); - } - - if (this._additionalTransformDirty) { - t = cc.AffineTransformConcat(t, this._additionalTransform); - this._additionalTransformDirty = false; - } - this._transform = t; - this._transformDirty = false; - } - return this._transform; - }, - - _nodeToParentTransformForCanvas:function () { - if (!this._transform) - this._transform = {a:1, b:0, c:0, d:1, tx:0, ty:0}; - if (this._transformDirty) { - this._armatureTransformDirty = true; - var t = this._transform;// quick reference - // base position - t.tx = this._position.x; - t.ty = this._position.y; - - // rotation Cos and Sin - var Cos = 1, Sin = 0; - if (this._rotationX) { - Cos = Math.cos(-this._rotationRadiansX); - Sin = Math.sin(-this._rotationRadiansX); - } - - // base abcd - t.a = t.d = Cos; - t.c = -Sin; - t.b = Sin; - - var lScaleX = this._scaleX, lScaleY = this._scaleY; - var appX = this._anchorPointInPoints.x, appY = this._anchorPointInPoints.y; - - // Firefox on Vista and XP crashes - // GPU thread in case of scale(0.0, 0.0) - var sx = (lScaleX < 0.000001 && lScaleX > -0.000001) ? 0.000001 : lScaleX, - sy = (lScaleY < 0.000001 && lScaleY > -0.000001) ? 0.000001 : lScaleY; - - // Add offset point - t.tx += Cos * this._offsetPoint.x * lScaleX + -Sin * this._offsetPoint.y * lScaleY; - t.ty += Sin * this._offsetPoint.x * lScaleX + Cos * this._offsetPoint.y * lScaleY; - - // skew - if (this._skewX || this._skewY) { - // offset the anchorpoint - var skx = Math.tan(-this._skewX * Math.PI / 180); - var sky = Math.tan(-this._skewY * Math.PI / 180); - var xx = appY * skx * sx; - var yy = appX * sky * sy; - t.a = Cos + -Sin * sky; - t.c = Cos * skx + -Sin; - t.b = Sin + Cos * sky; - t.d = Sin * skx + Cos; - t.tx += Cos * xx + -Sin * yy; - t.ty += Sin * xx + Cos * yy; - } - - // scale - if (lScaleX !== 1 || lScaleY !== 1) { - t.a *= sx; - t.b *= sx; - t.c *= sy; - t.d *= sy; - } - - // adjust anchorPoint - t.tx += Cos * -appX * sx + -Sin * -appY * sy; - t.ty += Sin * -appX * sx + Cos * -appY * sy; - - // if ignore anchorPoint - if (this._ignoreAnchorPointForPosition) { - t.tx += appX - t.ty += appY; - } - - if (this._additionalTransformDirty) { - this._transform = cc.AffineTransformConcat(this._transform, this._additionalTransform); - this._additionalTransformDirty = false; - } + /** + * Gets the animation of this Armature. + * @return {ccs.ArmatureAnimation} + */ + getAnimation: function () { + return this.animation; + }, - t.tx = t.tx | 0; - t.ty = t.ty | 0; - this._transformDirty = false; - } - return this._transform; + /** + * armatureTransformDirty getter + * @returns {Boolean} + */ + getArmatureTransformDirty: function () { + return this._armatureTransformDirty; }, - draw:function () { - //cc.g_NumberOfDraws++; + /** + * The update callback of ccs.Armature, it updates animation's state and updates bone's state. + * @override + * @param {Number} dt + */ + update: function (dt) { + this.animation.update(dt); + var locTopBoneList = this._topBoneList; + for (var i = 0; i < locTopBoneList.length; i++) + locTopBoneList[i].update(dt); + this._armatureTransformDirty = false; }, /** - * conforms to cc.TextureProtocol protocol - * @param {cc.BlendFunc} blendFunc + * The callback when ccs.Armature enter stage. + * @override */ - setBlendFunc: function (blendFunc) { - this._blendFunc = blendFunc; + onEnter: function () { + cc.Node.prototype.onEnter.call(this); + this.scheduleUpdate(); }, /** - * blendFunc getter - * @returns {cc.BlendFunc} + * The callback when ccs.Armature exit stage. + * @override */ - getBlendFunc: function () { - return this._blendFunc; + onExit: function () { + cc.Node.prototype.onExit.call(this); + this.unscheduleUpdate(); }, /** * This boundingBox will calculate all bones' boundingBox every time - * @return {cc.rect} + * @returns {cc.Rect} */ - boundingBox:function () { - var minx = 0, miny = 0, maxx = 0, maxy = 0; + getBoundingBox: function(){ + var minX, minY, maxX, maxY = 0; var first = true; - var boundingBox = cc.rect(0, 0, 0, 0); - for (var i = 0; i < this._children.length; i++) { - var bone = this._children[i]; - if (bone instanceof ccs.Bone) { - var r = bone.getDisplayManager().getBoundingBox(); - if (first) { - minx = cc.rectGetMinX(r); - miny = cc.rectGetMinY(r); - maxx = cc.rectGetMaxX(r); - maxy = cc.rectGetMaxY(r); + var boundingBox = cc.rect(0, 0, 0, 0), locChildren = this._children; + + var len = locChildren.length; + for (var i=0; i boundingBox.x + boundingBox.width ? + r.x + r.width : boundingBox.x + boundingBox.width; + maxY = r.y + r.height > boundingBox.y + boundingBox.height ? + r.y + r.height : boundingBox.y + boundingBox.height; } - else { - minx = cc.rectGetMinX(r) < cc.rectGetMinX(boundingBox) ? cc.rectGetMinX(r) : cc.rectGetMinX(boundingBox); - miny = cc.rectGetMinY(r) < cc.rectGetMinY(boundingBox) ? cc.rectGetMinY(r) : cc.rectGetMinY(boundingBox); - maxx = cc.rectGetMaxX(r) > cc.rectGetMaxX(boundingBox) ? cc.rectGetMaxX(r) : cc.rectGetMaxX(boundingBox); - maxy = cc.rectGetMaxY(r) > cc.rectGetMaxY(boundingBox) ? cc.rectGetMaxY(r) : cc.rectGetMaxY(boundingBox); - } - boundingBox = cc.rect(minx, miny, maxx - minx, maxy - miny); + + boundingBox.x = minX; + boundingBox.y = minY; + boundingBox.width = maxX - minX; + boundingBox.height = maxY - minY; } } - return cc.RectApplyAffineTransform(boundingBox, this.nodeToParentTransform()); + return cc.rectApplyAffineTransform(boundingBox, this.getNodeToParentTransform()); }, /** @@ -520,42 +390,33 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ * @returns {ccs.Bone} */ getBoneAtPoint: function (x, y) { - for (var i = this._children.length - 1; i >= 0; i--) { - var child = this._children[i]; - if (child instanceof ccs.Bone) { - if (child.getDisplayManager().containPoint(x, y)) { - return child; - } - } + var locChildren = this._children; + for (var i = locChildren.length - 1; i >= 0; i--) { + var child = locChildren[i]; + if (child instanceof ccs.Bone && child.getDisplayManager().containPoint(x, y)) + return child; } return null; }, - getTexureAtlasWithTexture:function(){ - return null; - }, - /** - * parent bone setter + * Sets parent bone of this Armature * @param {ccs.Bone} parentBone */ setParentBone: function (parentBone) { this._parentBone = parentBone; - for (var key in this._boneDic) { - var bone = this._boneDic[key]; - bone.setArmature(this); + var locBoneDic = this._boneDic; + for (var key in locBoneDic) { + locBoneDic[key].setArmature(this); } }, /** - * set collider filter - * @param {ccs.ColliderFilter} filter + * Return parent bone of ccs.Armature. + * @returns {ccs.Bone} */ - setColliderFilter: function (filter) { - for (var key in this._boneDic) { - var bone = this._boneDic[key]; - bone.setColliderFilter(filter); - } + getParentBone: function () { + return this._parentBone; }, /** @@ -564,9 +425,13 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ drawContour: function () { cc._drawingUtil.setDrawColor(255, 255, 255, 255); cc._drawingUtil.setLineWidth(1); - for (var key in this._boneDic) { - var bone = this._boneDic[key]; - var bodyList = bone.getColliderBodyList(); + var locBoneDic = this._boneDic; + for (var key in locBoneDic) { + var bone = locBoneDic[key]; + var detector = bone.getColliderDetector(); + if(!detector) + continue; + var bodyList = detector.getColliderBodyList(); for (var i = 0; i < bodyList.length; i++) { var body = bodyList[i]; var vertexList = body.getCalculatedVertexList(); @@ -575,55 +440,91 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ } }, + setBody: function (body) { + if (this._body === body) + return; + + this._body = body; + this._body.data = this; + var child, displayObject, locChildren = this._children; + for (var i = 0; i < locChildren.length; i++) { + child = locChildren[i]; + if (child instanceof ccs.Bone) { + var displayList = child.getDisplayManager().getDecorativeDisplayList(); + for (var j = 0; j < displayList.length; j++) { + displayObject = displayList[j]; + var detector = displayObject.getColliderDetector(); + if (detector) + detector.setBody(this._body); + } + } + } + }, + + getShapeList: function () { + if (this._body) + return this._body.shapeList; + return null; + }, + + getBody: function () { + return this._body; + }, + /** - * return parent bone - * @returns {ccs.Bone} + * Sets the blendFunc to ccs.Armature + * @param {cc.BlendFunc|Number} blendFunc + * @param {Number} [dst] */ - getParentBone:function(){ - return this._parentBone; + setBlendFunc: function (blendFunc, dst) { + if(dst === undefined){ + this._blendFunc.src = blendFunc.src; + this._blendFunc.dst = blendFunc.dst; + } else { + this._blendFunc.src = blendFunc; + this._blendFunc.dst = dst; + } }, /** - * armatureAnimation getter - * @return {ccs.ArmatureAnimation} + * Returns the blendFunc of ccs.Armature + * @returns {cc.BlendFunc} */ - getAnimation:function () { - return this.animation; + getBlendFunc: function () { + return new cc.BlendFunc(this._blendFunc.src, this._blendFunc.dst); }, /** - * armatureAnimation setter - * @param {ccs.ArmatureAnimation} animation + * set collider filter + * @param {ccs.ColliderFilter} filter */ - setAnimation:function (animation) { - this.animation = animation; + setColliderFilter: function (filter) { + var locBoneDic = this._boneDic; + for (var key in locBoneDic) + locBoneDic[key].setColliderFilter(filter); }, /** - * armatureData getter + * Returns the armatureData of ccs.Armature * @return {ccs.ArmatureData} */ - getArmatureData:function () { + getArmatureData: function () { return this.armatureData; }, /** - * armatureData setter + * Sets armatureData to this Armature * @param {ccs.ArmatureData} armatureData */ - setArmatureData:function (armatureData) { + setArmatureData: function (armatureData) { this.armatureData = armatureData; }, - getName:function () { - return this.name; - }, - setName:function (name) { - this.name = name; - }, - getBatchNode:function () { + + getBatchNode: function () { return this.batchNode; }, - setBatchNode:function (batchNode) { + + setBatchNode: function (batchNode) { this.batchNode = batchNode; }, @@ -631,7 +532,7 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ * version getter * @returns {Number} */ - getVersion:function () { + getVersion: function () { return this.version; }, @@ -639,59 +540,19 @@ ccs.Armature = ccs.NodeRGBA.extend(/** @lends ccs.Armature# */{ * version setter * @param {Number} version */ - setVersion:function (version) { + setVersion: function (version) { this.version = version; }, - /** - * armatureTransformDirty getter - * @returns {Boolean} - */ - getArmatureTransformDirty:function () { - return this._armatureTransformDirty; - }, - getBody:function(){ - return this._body; - }, - - setBody:function(body){ - if (this._body == body) - return; - - this._body = body; - this._body.data = this; - var child,displayObject; - for (var i = 0; i < this._children.length; i++) { - child = this._children[i]; - if (child instanceof ccs.Bone) { - var displayList = child.getDisplayManager().getDecorativeDisplayList(); - for (var j = 0; j < displayList.length; j++) { - displayObject = displayList[j]; - var detector = displayObject.getColliderDetector(); - if (detector) - detector.setBody(this._body); - } - } - } - }, - getShapeList:function(){ - if(this._body) - return this._body.shapeList; - return []; + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new ccs.Armature.CanvasRenderCmd(this); + else + return new ccs.Armature.WebGLRenderCmd(this); } - }); - -if(cc._renderType == cc._RENDER_TYPE_WEBGL){ - //WebGL - ccs.Armature.prototype.nodeToParentTransform = ccs.Armature.prototype._nodeToParentTransformForWebGL; -}else{ - //Canvas - ccs.Armature.prototype.nodeToParentTransform = ccs.Armature.prototype._nodeToParentTransformForCanvas; -} - -window._p = ccs.Armature.prototype; +var _p = ccs.Armature.prototype; /** @expose */ _p.parentBone; @@ -703,21 +564,15 @@ cc.defineGetterSetter(_p, "body", _p.getBody, _p.setBody); _p.colliderFilter; cc.defineGetterSetter(_p, "colliderFilter", null, _p.setColliderFilter); -delete window._p; +_p = null; /** - * allocates and initializes a armature. - * @param {String} name - * @param {ccs.Bone} parentBone + * Allocates an armature, and use the ArmatureData named name in ArmatureDataManager to initializes the armature. + * @param {String} [name] Bone name + * @param {ccs.Bone} [parentBone] the parent bone * @return {ccs.Armature} - * @example - * // example - * var armature = ccs.Armature.create(); + * @deprecated since v3.1, please use new construction instead */ ccs.Armature.create = function (name, parentBone) { - var armature = new ccs.Armature(); - if (armature && armature.init(name, parentBone)) { - return armature; - } - return null; + return new ccs.Armature(name, parentBone); }; diff --git a/extensions/cocostudio/armature/CCArmatureCanvasRenderCmd.js b/extensions/cocostudio/armature/CCArmatureCanvasRenderCmd.js new file mode 100644 index 0000000000..4d0a4f06f3 --- /dev/null +++ b/extensions/cocostudio/armature/CCArmatureCanvasRenderCmd.js @@ -0,0 +1,190 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + ccs.Armature.RenderCmd = { + _updateAnchorPointInPoint: function(){ + var node = this._node; + var contentSize = node._contentSize, anchorPoint = node._anchorPoint, offsetPoint = node._offsetPoint; + this._anchorPointInPoints.x = contentSize.width * anchorPoint.x - offsetPoint.x; + this._anchorPointInPoints.y = contentSize.height * anchorPoint.y - offsetPoint.y; + + this._realAnchorPointInPoints.x = contentSize.width * anchorPoint.x; + this._realAnchorPointInPoints.y = contentSize.height * anchorPoint.y; + this.setDirtyFlag(cc.Node._dirtyFlags.transformDirty); + }, + + getAnchorPointInPoints: function(){ + return cc.p(this._realAnchorPointInPoints); + } + }; +})(); + +(function(){ + ccs.Armature.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + + this._realAnchorPointInPoints = new cc.Point(0,0); + this._startRenderCmd = new cc.CustomRenderCmd(this, this._startCmdCallback); + this._RestoreRenderCmd = new cc.CustomRenderCmd(this, this._RestoreCmdCallback); + }; + + var proto = ccs.Armature.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + cc.inject(ccs.Armature.RenderCmd, proto); + proto.constructor = ccs.Armature.CanvasRenderCmd; + + proto._startCmdCallback = function(ctx, scaleX, scaleY){ + var node = this._node, parent = node._parent; + this.transform(parent ? parent._renderCmd : null); + + var wrapper = ctx || cc._renderContext; + wrapper.save(); + + //set to armature mode + wrapper._switchToArmatureMode(true, this._worldTransform, scaleX, scaleY); + }; + + proto.transform = function(parentCmd, recursive){ + ccs.Node.CanvasRenderCmd.prototype.transform.call(this, parentCmd, recursive); + + var locChildren = this._node._children; + for (var i = 0, len = locChildren.length; i< len; i++) { + var selBone = locChildren[i]; + if (selBone && selBone.getDisplayRenderNode) { + var selNode = selBone.getDisplayRenderNode(); + if (selNode && selNode._renderCmd){ + var cmd = selNode._renderCmd; + cmd.transform(null); //must be null, use transform in armature mode + + //update displayNode's color and opacity, because skin didn't call visit() + var parentColor = selBone._renderCmd._displayedColor, parentOpacity = selBone._renderCmd._displayedOpacity; + var flags = cc.Node._dirtyFlags, locFlag = cmd._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + if(colorDirty) + cmd._updateDisplayColor(parentColor); + if(opacityDirty) + cmd._updateDisplayOpacity(parentOpacity); + } + } + } + }; + + proto._RestoreCmdCallback = function(wrapper){ + this._cacheDirty = false; + //wrapper.restore(); + wrapper._switchToArmatureMode(false); + wrapper.restore(); + }; + + proto.initShaderCache = function(){}; + proto.setShaderProgram = function(){}; + proto.updateChildPosition = function(ctx, dis){ + //dis.visit(ctx); + cc.renderer.pushRenderCommand(dis._renderCmd); + }; + + proto.rendering = function(ctx, scaleX, scaleY){ + var node = this._node; + var locChildren = node._children; + var alphaPremultiplied = cc.BlendFunc.ALPHA_PREMULTIPLIED, alphaNonPremultipled = cc.BlendFunc.ALPHA_NON_PREMULTIPLIED; + for (var i = 0, len = locChildren.length; i< len; i++) { + var selBone = locChildren[i]; + if (selBone && selBone.getDisplayRenderNode) { + var selNode = selBone.getDisplayRenderNode(); + if (null === selNode) + continue; + + switch (selBone.getDisplayRenderNodeType()) { + case ccs.DISPLAY_TYPE_SPRITE: + if(selNode instanceof ccs.Skin) + this.updateChildPosition(ctx, selNode, selBone, alphaPremultiplied, alphaNonPremultipled); + break; + case ccs.DISPLAY_TYPE_ARMATURE: + selNode._renderCmd.rendering(ctx, scaleX, scaleY); + break; + default: + selNode.visit(this); + break; + } + } else if(selBone instanceof cc.Node) { + this._visitNormalChild(selBone); + //selBone.visit(this); + } + } + }; + + proto._visitNormalChild = function(childNode){ + if(childNode == null) + return; + + var cmd = childNode._renderCmd; + // quick return if not visible + if (!childNode._visible) + return; + cmd._curLevel = this._curLevel + 1; + + //visit for canvas + var i, children = childNode._children, child; + cmd._syncStatus(this); + //because armature use transform, not setTransform + cmd.transform(null); + + var len = children.length; + if (len > 0) { + childNode.sortAllChildren(); + // draw children zOrder < 0 + for (i = 0; i < len; i++) { + child = children[i]; + if (child._localZOrder < 0) + child._renderCmd.visit(cmd); + else + break; + } + cc.renderer.pushRenderCommand(cmd); + for (; i < len; i++) + children[i]._renderCmd.visit(cmd); + } else { + cc.renderer.pushRenderCommand(cmd); + } + this._dirtyFlag = 0; + }; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible. children won't be drawn. + if (!node._visible) + return; + + this.updateStatus(parentCmd); + node.sortAllChildren(); + + cc.renderer.pushRenderCommand(this._startRenderCmd); + this.rendering(); + cc.renderer.pushRenderCommand(this._RestoreRenderCmd); + + this._cacheDirty = false; + }; +})(); \ No newline at end of file diff --git a/extensions/cocostudio/armature/CCArmatureWebGLRenderCmd.js b/extensions/cocostudio/armature/CCArmatureWebGLRenderCmd.js new file mode 100644 index 0000000000..05e86742cd --- /dev/null +++ b/extensions/cocostudio/armature/CCArmatureWebGLRenderCmd.js @@ -0,0 +1,167 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + + ccs.Armature.WebGLRenderCmd = function(renderableObject){ + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + + this._realAnchorPointInPoints = new cc.Point(0,0); + }; + + var proto = ccs.Armature.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + cc.inject(ccs.Armature.RenderCmd, proto); + proto.constructor = ccs.Armature.WebGLRenderCmd; + + proto.rendering = function (ctx, dontChangeMatrix) { + var node = this._node; + + if(!dontChangeMatrix){ + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + cc.kmGLPushMatrix(); + cc.kmGLLoadMatrix(this._stackMatrix); + } + + var locChildren = node._children; + var alphaPremultiplied = cc.BlendFunc.ALPHA_PREMULTIPLIED, alphaNonPremultipled = cc.BlendFunc.ALPHA_NON_PREMULTIPLIED; + for (var i = 0, len = locChildren.length; i < len; i++) { + var selBone = locChildren[i]; + if (selBone && selBone.getDisplayRenderNode) { + var selNode = selBone.getDisplayRenderNode(); + if (null === selNode) + continue; + selNode.setShaderProgram(this._shaderProgram); + switch (selBone.getDisplayRenderNodeType()) { + case ccs.DISPLAY_TYPE_SPRITE: + if (selNode instanceof ccs.Skin) { + this._updateColorAndOpacity(selNode._renderCmd, selBone); //because skin didn't call visit() + selNode.updateTransform(); + + var func = selBone.getBlendFunc(); + if (func.src !== alphaPremultiplied.src || func.dst !== alphaPremultiplied.dst) + selNode.setBlendFunc(selBone.getBlendFunc()); + else { + if ((node._blendFunc.src === alphaPremultiplied.src && node._blendFunc.dst === alphaPremultiplied.dst) + && !selNode.getTexture().hasPremultipliedAlpha()) + selNode.setBlendFunc(alphaNonPremultipled); + else + selNode.setBlendFunc(node._blendFunc); + } + selNode._renderCmd.rendering(ctx); + } + break; + case ccs.DISPLAY_TYPE_ARMATURE: + selNode._renderCmd.rendering(ctx, true); + break; + default: + selNode._renderCmd.transform(); + selNode._renderCmd.rendering(ctx); + break; + } + } else if (selBone instanceof cc.Node) { + selBone.setShaderProgram(this._shaderProgram); + selBone._renderCmd.transform(); + if(selBone._renderCmd.rendering) + selBone._renderCmd.rendering(ctx); + } + } + if(!dontChangeMatrix) + cc.kmGLPopMatrix(); + }; + + proto.initShaderCache = function(){ + this._shaderProgram = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + }; + + proto.setShaderProgram = function(shaderProgram){ + this._shaderProgram = shaderProgram; + }; + + proto._updateColorAndOpacity = function(skinRenderCmd, bone){ + //update displayNode's color and opacity + var parentColor = bone._renderCmd._displayedColor, parentOpacity = bone._renderCmd._displayedOpacity; + var flags = cc.Node._dirtyFlags, locFlag = skinRenderCmd._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + if(colorDirty) + skinRenderCmd._updateDisplayColor(parentColor); + if(opacityDirty) + skinRenderCmd._updateDisplayOpacity(parentOpacity); + if(colorDirty || opacityDirty) + skinRenderCmd._updateColor(); + }; + + proto.updateChildPosition = function(ctx, dis, selBone, alphaPremultiplied, alphaNonPremultipled){ + var node = this._node; + dis.updateTransform(); + + var func = selBone.getBlendFunc(); + if (func.src !== alphaPremultiplied.src || func.dst !== alphaPremultiplied.dst) + dis.setBlendFunc(selBone.getBlendFunc()); + else { + if ((node._blendFunc.src === alphaPremultiplied.src && node_blendFunc.dst === alphaPremultiplied.dst) + && !dis.getTexture().hasPremultipliedAlpha()) + dis.setBlendFunc(alphaNonPremultipled); + else + dis.setBlendFunc(node._blendFunc); + } + dis.rendering(ctx); + }; + + proto.updateStatus = function () { + var flags = cc.Node._dirtyFlags, locFlag = this._dirtyFlag; + var colorDirty = locFlag & flags.colorDirty, + opacityDirty = locFlag & flags.opacityDirty; + if(colorDirty) + this._updateDisplayColor(); + + if(opacityDirty) + this._updateDisplayOpacity(); + + if(colorDirty || opacityDirty) + this._updateColor(); + + //update the transform every visit, needn't dirty flag, + this.transform(this.getParentRenderCmd(), true); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + // quick return if not visible. children won't be drawn. + if (!node._visible) + return; + + var currentStack = cc.current_stack; + currentStack.stack.push(currentStack.top); + this.updateStatus(parentCmd); + currentStack.top = this._stackMatrix; + + node.sortAllChildren(); + cc.renderer.pushRenderCommand(this); + + this._dirtyFlag = 0; + currentStack.top = currentStack.stack.pop(); + }; +})(); \ No newline at end of file diff --git a/extensions/cocostudio/armature/CCBone.js b/extensions/cocostudio/armature/CCBone.js index 04a787286c..32f12553f5 100644 --- a/extensions/cocostudio/armature/CCBone.js +++ b/extensions/cocostudio/armature/CCBone.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,9 +24,14 @@ ****************************************************************************/ /** - * Base class for ccs.Bone objects. + * The Bone of Armature, it has bone data, display manager and transform data for armature. * @class - * @extends ccs.NodeRGBA + * @extends ccs.Node + * + * @param {String} [name] The name of the bone + * @example + * + * var bone = new ccs.Bone("head"); * * @property {ccs.BoneData} boneData - The bone data * @property {ccs.Armature} armature - The armature @@ -34,7 +40,6 @@ * @property {Array} childrenBone - <@readonly> All children bones * @property {ccs.Tween} tween - <@readonly> Tween * @property {ccs.FrameData} tweenData - <@readonly> The tween data - * @property {Boolean} transformDirty - Indicate whether the transform is dirty * @property {ccs.ColliderFilter} colliderFilter - The collider filter * @property {ccs.DisplayManager} displayManager - The displayManager * @property {Boolean} ignoreMovementBoneData - Indicate whether force the bone to show When CCArmature play a animation and there isn't a CCMovementBoneData of this bone in this CCMovementData. @@ -42,188 +47,162 @@ * @property {Boolean} blendDirty - Indicate whether the blend is dirty * */ -ccs.Bone = ccs.NodeRGBA.extend(/** @lends ccs.Bone# */{ - _boneData:null, - _armature:null, - _childArmature:null, - displayManager:null, - ignoreMovementBoneData:false, - _tween:null, - _tweenData:null, - name:"", - _childrenBone:null, - parentBone:null, - boneTransformDirty:false, - _worldTransform:null, - _blendFunc:0, - blendDirty:false, - _worldInfo:null, - _armatureParentBone:null, - _dataVersion:0, - _className:"Bone", - ctor:function () { - cc.NodeRGBA.prototype.ctor.call(this); - this._boneData = null; +ccs.Bone = ccs.Node.extend(/** @lends ccs.Bone# */{ + _boneData: null, + _armature: null, + _childArmature: null, + _displayManager: null, + ignoreMovementBoneData: false, + _tween: null, + _tweenData: null, + _parentBone: null, + _boneTransformDirty: false, + _worldTransform: null, + _blendFunc: null, + blendDirty: false, + _worldInfo: null, + _armatureParentBone: null, + _dataVersion: 0, + _className: "Bone", + + ctor: function (name) { + cc.Node.prototype.ctor.call(this); + this._tweenData = null; + this._parentBone = null; this._armature = null; this._childArmature = null; - this.displayManager = null; - this.ignoreMovementBoneData = false; + this._boneData = null; this._tween = null; - this._tweenData = null; - this.name = ""; - this._childrenBone = []; - this.parentBone = null; - this.boneTransformDirty = true; - this._worldTransform = cc.AffineTransformMake(1, 0, 0, 1, 0, 0); + this._displayManager = null; + this.ignoreMovementBoneData = false; + + this._worldTransform = cc.affineTransformMake(1, 0, 0, 1, 0, 0); + this._boneTransformDirty = true; this._blendFunc = new cc.BlendFunc(cc.BLEND_SRC, cc.BLEND_DST); this.blendDirty = false; - }, + this._worldInfo = null; - /** - * release objects - */ - release:function () { - CC_SAFE_RELEASE(this._tweenData); - for (var i = 0; i < this._childrenBone.length; i++) { - CC_SAFE_RELEASE(this._childrenBone[i]); - } - this._childrenBone = []; - CC_SAFE_RELEASE(this._tween); - CC_SAFE_RELEASE(this.displayManager); - CC_SAFE_RELEASE(this._boneData); - CC_SAFE_RELEASE(this._childArmature); + this._armatureParentBone = null; + this._dataVersion = 0; + + ccs.Bone.prototype.init.call(this, name); }, /** - * Initializes a CCBone with the specified name - * @param {String} name + * Initializes a ccs.Bone with the specified name + * @param {String} name bone name * @return {Boolean} */ - init:function (name) { - cc.NodeRGBA.prototype.init.call(this); - if (name) { - this.name = name; - } + init: function (name) { +// cc.Node.prototype.init.call(this); + if (name) + this._name = name; this._tweenData = new ccs.FrameData(); - this._tween = new ccs.Tween(); - this._tween.init(this); - this.displayManager = new ccs.DisplayManager(); - this.displayManager.init(this); + + this._tween = new ccs.Tween(this); + + this._displayManager = new ccs.DisplayManager(this); + this._worldInfo = new ccs.BaseData(); this._boneData = new ccs.BaseData(); + return true; }, /** - * set the boneData + * Sets the boneData to ccs.Bone. * @param {ccs.BoneData} boneData */ - setBoneData:function (boneData) { - if (!boneData) { - cc.log("boneData must not be null"); - return; - } - this._boneData = boneData; - this.name = this._boneData.name; - this.setLocalZOrder(this._boneData.zOrder); - this.displayManager.initDisplayList(boneData); + setBoneData: function (boneData) { + cc.assert(boneData, "_boneData must not be null"); + + if(this._boneData !== boneData) + this._boneData = boneData; + + this.setName(this._boneData.name); + this._localZOrder = this._boneData.zOrder; + this._displayManager.initDisplayList(boneData); }, /** - * boneData getter + * Returns boneData of ccs.Bone. * @return {ccs.BoneData} */ - getBoneData:function () { + getBoneData: function () { return this._boneData; }, /** - * set the armature + * Sets the armature reference to ccs.Bone. * @param {ccs.Armature} armature */ - setArmature:function (armature) { + setArmature: function (armature) { this._armature = armature; - if(armature){ + if (armature) { this._tween.setAnimation(this._armature.getAnimation()); this._dataVersion = this._armature.getArmatureData().dataVersion; this._armatureParentBone = this._armature.getParentBone(); - }else{ + } else this._armatureParentBone = null; - } }, /** - * armature getter + * Returns the armature reference of ccs.Bone. * @return {ccs.Armature} */ - getArmature:function () { + getArmature: function () { return this._armature; }, /** - * update worldTransform - * @param dt + * Updates worldTransform by tween data and updates display state + * @param {Number} delta */ - update:function (dt) { - var locParentBone = this.parentBone; - var locArmature = this._armature; - var locTweenData = this._tweenData; - var locWorldTransform = this._worldTransform; - var locWorldInfo = this._worldInfo; - var locArmatureParentBone = this._armatureParentBone; + update: function (delta) { + if (this._parentBone) + this._boneTransformDirty = this._boneTransformDirty || this._parentBone.isTransformDirty(); - if (locParentBone) { - this.boneTransformDirty = this.boneTransformDirty || locParentBone.isTransformDirty(); - } - if (locArmatureParentBone && !this.boneTransformDirty){ - this.boneTransformDirty = locArmatureParentBone.isTransformDirty(); - } - if (this.boneTransformDirty) { - if (this._dataVersion >= ccs.CONST_VERSION_COMBINED) { - var locBoneData = this._boneData; - locTweenData.x += locBoneData.x; - locTweenData.y += locBoneData.y; - locTweenData.skewX += locBoneData.skewX; - locTweenData.skewY += locBoneData.skewY; - locTweenData.scaleX += locBoneData.scaleX; - locTweenData.scaleY += locBoneData.scaleY; + if (this._armatureParentBone && !this._boneTransformDirty) + this._boneTransformDirty = this._armatureParentBone.isTransformDirty(); + if (this._boneTransformDirty){ + var locTweenData = this._tweenData; + if (this._dataVersion >= ccs.CONST_VERSION_COMBINED){ + ccs.TransformHelp.nodeConcat(locTweenData, this._boneData); locTweenData.scaleX -= 1; locTweenData.scaleY -= 1; } + var locWorldInfo = this._worldInfo; + locWorldInfo.copy(locTweenData); locWorldInfo.x = locTweenData.x + this._position.x; locWorldInfo.y = locTweenData.y + this._position.y; locWorldInfo.scaleX = locTweenData.scaleX * this._scaleX; locWorldInfo.scaleY = locTweenData.scaleY * this._scaleY; - locWorldInfo.skewX = locTweenData.skewX + this._skewX + this._rotationX; - locWorldInfo.skewY = locTweenData.skewY + this._skewY - this._rotationY; + locWorldInfo.skewX = locTweenData.skewX + this._skewX + cc.degreesToRadians(this._rotationX); + locWorldInfo.skewY = locTweenData.skewY + this._skewY - cc.degreesToRadians(this._rotationY); - if (this.parentBone) { - this.applyParentTransform(this.parentBone); - } + if(this._parentBone) + this._applyParentTransform(this._parentBone); else { - if (locArmatureParentBone) { - this.applyParentTransform(locArmatureParentBone); - } + if (this._armatureParentBone) + this._applyParentTransform(this._armatureParentBone); } - ccs.TransformHelp.nodeToMatrix(locWorldInfo, locWorldTransform); - - if (locArmatureParentBone) { - this._worldTransform = cc.AffineTransformConcat(locWorldTransform, locArmature.nodeToParentTransform()); - } + ccs.TransformHelp.nodeToMatrix(locWorldInfo, this._worldTransform); + if (this._armatureParentBone) + this._worldTransform = cc.affineTransformConcat(this._worldTransform, this._armature.getNodeToParentTransform()); //TODO TransformConcat } - ccs.DisplayFactory.updateDisplay(this, dt, this.boneTransformDirty || locArmature.getArmatureTransformDirty()); - var locChildrenBone = this._childrenBone; - for (var i = 0; i < locChildrenBone.length; i++) { - locChildrenBone[i].update(dt); + ccs.displayFactory.updateDisplay(this, delta, this._boneTransformDirty || this._armature.getArmatureTransformDirty()); + for(var i=0; i= ccs.CONST_VERSION_COMBINED) { - var zorder = this._tweenData.zOrder + this._boneData.zOrder; - this.setLocalZOrder(zorder); - } - else { + this.setLocalZOrder(this._tweenData.zOrder + this._boneData.zOrder); + } else { this.setLocalZOrder(this._tweenData.zOrder); } }, /** - * Add a child to this bone, and it will let this child call setParent(ccs.Bone) function to set self to it's parent + * Adds a child to this bone, and it will let this child call setParent(ccs.Bone) function to set self to it's parent * @param {ccs.Bone} child */ - addChildBone:function (child) { - if (!child) { - cc.log("Argument must be non-nil"); - return; - } - if (child.parentBone) { - cc.log("child already added. It can't be added again"); - return; - } - if (this._childrenBone.indexOf(child) < 0) { - this._childrenBone.push(child); + addChildBone: function (child) { + cc.assert(child, "Argument must be non-nil"); + cc.assert(!child.parentBone, "child already added. It can't be added again"); + + if (this._children.indexOf(child) < 0) { + this._children.push(child); child.setParentBone(this); } }, @@ -337,331 +283,361 @@ ccs.Bone = ccs.NodeRGBA.extend(/** @lends ccs.Bone# */{ * @param {ccs.Bone} bone * @param {Boolean} recursion */ - removeChildBone:function (bone, recursion) { - for (var i = 0; i < this._childrenBone.length; i++) { - if (this._childrenBone[i] == bone) { - if (recursion) { - var ccbones = bone._childrenBone; - for (var j = 0; j < ccbones.length; j++) { - bone.removeChildBone(ccbones[j], recursion); - } + removeChildBone: function (bone, recursion) { + if (this._children.length > 0 && this._children.getIndex(bone) !== -1 ) { + if(recursion) { + var ccbones = bone._children; + for(var i=0; i * Set IgnoreMovementBoneData to true, then this bone will also show. * @param {Boolean} bool */ - setIgnoreMovementBoneData:function (bool) { - this.ignoreMovementBoneData = bool; + setIgnoreMovementBoneData: function (bool) { + this._ignoreMovementBoneData = bool; }, /** - * ignoreMovementBoneData getter - * @return {Boolean} + * Returns whether is ignore movement bone data. + * @returns {Boolean} */ - getIgnoreMovementBoneData:function () { - return this.ignoreMovementBoneData; + isIgnoreMovementBoneData: function(){ + return this._ignoreMovementBoneData; }, /** - * tweenData getter + * Returns the blendFunc of ccs.Bone. + * @return {cc.BlendFunc} + */ + getBlendFunc: function () { + return new cc.BlendFunc(this._blendFunc.src, this._blendFunc.dst); + }, + + /** + * Sets blend dirty flag + * @param {Boolean} dirty + */ + setBlendDirty: function (dirty) { + this._blendDirty = dirty; + }, + + /** + * Returns the blend dirty flag whether is dirty. + * @returns {Boolean|*|ccs.Bone._blendDirty} + */ + isBlendDirty: function () { + return this._blendDirty; + }, + + /** + * Returns the tweenData of ccs.Bone. * @return {ccs.FrameData} */ - getTweenData:function () { + getTweenData: function () { return this._tweenData; }, /** - * name setter - * @param {String} name + * Returns the world information of ccs.Bone. + * @returns {ccs.BaseData} */ - setName:function (name) { - this.name = name; + getWorldInfo: function(){ + return this._worldInfo; }, /** - * name getter - * @return {String} + * Returns the children of ccs.Bone + * @return {Array} + * @deprecated since v3.0, please use getChildren instead. */ - getName:function () { - return this.name; + getChildrenBone: function () { + return this._children; }, /** - * BlendFunc setter - * @param {cc.BlendFunc} blendFunc + * Returns the worldTransform of ccs.Bone. + * @return {cc.AffineTransform} + * @deprecated since v3.0, please use getNodeToArmatureTransform instead. */ - setBlendFunc:function (blendFunc) { - if (this._blendFunc.src != blendFunc.src || this._blendFunc.dst != blendFunc.dst) { - this._blendFunc = blendFunc; - this.blendDirty = true; - } + nodeToArmatureTransform: function () { + return this.getNodeToArmatureTransform(); }, /** - * blendType getter - * @return {cc.BlendFunc} + * @deprecated + * Returns the world affine transform matrix. The matrix is in Pixels. + * @returns {cc.AffineTransform} + */ + nodeToWorldTransform: function () { + return this.getNodeToWorldTransform(); + }, + + /** + * Returns the collider body list in this bone. + * @returns {Array|null} + * @deprecated since v3.0, please use getColliderDetector to get a delector, and calls its getColliderBodyList instead. */ - getBlendFunc:function () { - return this._blendFunc; + getColliderBodyList: function () { + var detector = this.getColliderDetector(); + if(detector) + return detector.getColliderBodyList(); + return null; }, - setBlendDirty:function(dirty){ - this.blendDirty = dirty; + /** + * Returns whether is ignore movement bone data. + * @return {Boolean} + * @deprecated since v3.0, please isIgnoreMovementBoneData instead. + */ + getIgnoreMovementBoneData: function () { + return this.isIgnoreMovementBoneData(); }, - isBlendDirty:function(){ - return this.blendDirty; + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new ccs.Bone.CanvasRenderCmd(this); + else + return new ccs.Bone.WebGLRenderCmd(this); } }); -window._p = ccs.Bone.prototype; +var _p = ccs.Bone.prototype; // Extended properties /** @expose */ @@ -686,20 +662,52 @@ cc.defineGetterSetter(_p, "tweenData", _p.getTweenData); _p.colliderFilter; cc.defineGetterSetter(_p, "colliderFilter", _p.getColliderFilter, _p.setColliderFilter); -delete window._p; +_p = null; /** - * allocates and initializes a bone. - * @constructs + * Allocates and initializes a bone. * @return {ccs.Bone} - * @example - * // example - * var bone = ccs.Bone.create(); + * @deprecated since v3.1, please use new construction instead */ ccs.Bone.create = function (name) { - var bone = new ccs.Bone(); - if (bone && bone.init(name)) { - return bone; + return new ccs.Bone(name); +}; + +ccs.Bone.RenderCmd = { + _updateColor: function(){ + var node = this._node; + var display = node._displayManager.getDisplayRenderNode(); + if (display !== null) { + var displayCmd = display._renderCmd; + display.setColor(cc.color( node._tweenData.r, node._tweenData.g, node._tweenData.g)); + display.setOpacity(node._tweenData.a); + displayCmd._syncDisplayColor(this._displayedColor); + displayCmd._syncDisplayOpacity(this._displayedOpacity); + displayCmd._updateColor(); + } } - return null; -}; \ No newline at end of file +}; + +(function(){ + ccs.Bone.CanvasRenderCmd = function(renderable){ + cc.Node.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = ccs.Bone.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + cc.inject(ccs.Bone.RenderCmd, proto); + proto.constructor = ccs.Bone.CanvasRenderCmd; +})(); + +(function(){ + if(!cc.Node.WebGLRenderCmd) + return; + ccs.Bone.WebGLRenderCmd = function(renderable){ + cc.Node.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + }; + + var proto = ccs.Bone.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + cc.inject(ccs.Bone.RenderCmd, proto); + proto.constructor = ccs.Bone.WebGLRenderCmd; +})(); diff --git a/extensions/cocostudio/armature/animation/CCArmatureAnimation.js b/extensions/cocostudio/armature/animation/CCArmatureAnimation.js index cbc9ab9086..870ba7ed0f 100644 --- a/extensions/cocostudio/armature/animation/CCArmatureAnimation.js +++ b/extensions/cocostudio/armature/animation/CCArmatureAnimation.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,8 @@ ****************************************************************************/ /** - * movement event type + * movement event type enum + * @constant * @type {Object} */ ccs.MovementEventType = { @@ -31,41 +33,60 @@ ccs.MovementEventType = { complete: 1, loopComplete: 2 }; + /** - * Base class for cc.MovementEvent objects. + * The animation event class, it has the callback, target and arguments. + * @deprecated since v3.0. * @class * @extends ccs.Class */ ccs.AnimationEvent = ccs.Class.extend(/** @lends ccs.AnimationEvent# */{ - _arguments:null, - _callFunc:null, - _selectorTarget:null, - ctor:function (target, callFunc, data) { + _arguments: null, + _callFunc: null, + _selectorTarget: null, + + /** + * Constructor of ccs.AnimationEvent + * @param {function} callFunc + * @param {object} target + * @param {object} [data] + */ + ctor: function (callFunc,target, data) { this._data = data; this._callFunc = callFunc; this._selectorTarget = target; }, - call:function () { - if (this._callFunc) { + call: function () { + if (this._callFunc) this._callFunc.apply(this._selectorTarget, this._arguments); - } }, - setArguments:function (args) { + setArguments: function (args) { this._arguments = args; } }); + /** - * movement event + * The movement event class for Armature. * @constructor + * + * @property {ccs.Armature} armature - The armature reference of movement event. + * @property {Number} movementType - The type of movement. + * @property {String} movementID - The ID of movement. */ ccs.MovementEvent = function () { this.armature = null; - this.movementType = ""; + this.movementType = ccs.MovementEventType.start; this.movementID = ""; }; + /** - * frame event + * The frame event class for Armature. * @constructor + * + * @property {ccs.Bone} bone - The bone reference of frame event. + * @property {String} frameEventName - The name of frame event. + * @property {Number} originFrameIndex - The index of origin frame. + * @property {Number} currentFrameIndex - The index of current frame. */ ccs.FrameEvent = function () { this.bone = null; @@ -73,126 +94,147 @@ ccs.FrameEvent = function () { this.originFrameIndex = 0; this.currentFrameIndex = 0; }; + /** - * Base class for ccs.ArmatureAnimation objects. + * The Animation class for Armature, it plays armature animation, and controls speed scale and manages animation frame. * @class * @extends ccs.ProcessBase - * + * + * @param {ccs.Armature} [armature] The armature + * * @property {ccs.AnimationData} animationData - Animation data * @property {Object} userObject - User custom object * @property {Boolean} ignoreFrameEvent - Indicate whether the frame event is ignored * @property {Number} speedScale - Animation play speed scale * @property {Number} animationScale - Animation play speed scale - * */ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# */{ - animationData:null, - _movementData:null, - _armature:null, - _movementID:"", - _prevFrameIndex:0, - _toIndex:0, - _tweenList:null, - _frameEvent:null, - _movementEvent:null, - _speedScale:1, - ignoreFrameEvent:false, - _frameEventQueue:null, - _movementEventQueue:null, - userObject:null, + _animationData: null, + _movementData: null, + _armature: null, + _movementID: "", + _toIndex: 0, + _tweenList: null, + _speedScale: 1, + _ignoreFrameEvent: false, + _frameEventQueue: null, + _movementEventQueue: null, _movementList: null, _onMovementList: false, _movementListLoop: false, _movementIndex: 0, - ctor:function () { + _movementListDurationTo: -1, + + _movementEventCallFunc: null, + _frameEventCallFunc: null, + _movementEventTarget: null, + _frameEventTarget:null, + _movementEventListener: null, + _frameEventListener: null, + + ctor: function (armature) { ccs.ProcessBase.prototype.ctor.call(this); - this.animationData = null; - this._movementData = null; - this._movementID = ""; - this._armature = null; - this._prevFrameIndex = 0; - this._toIndex = 0; + this._tweenList = []; - this._frameEvent = null; - this._movementEvent = null; - this._speedScale = 1; - this.ignoreFrameEvent = false; + this._movementList = []; this._frameEventQueue = []; this._movementEventQueue = []; - this.userObject = null; - this._movementList = []; - this._onMovementList = false; - this._movementListLoop = false; - this._movementIndex = 0; + this._armature = null; + + armature && ccs.ArmatureAnimation.prototype.init.call(this, armature); }, /** - * init with a CCArmature + * Initializes with an armature object * @param {ccs.Armature} armature * @return {Boolean} */ - init:function (armature) { + init: function (armature) { this._armature = armature; - this._tweenList = []; + this._tweenList.length = 0; return true; }, - pause:function () { - for (var i = 0; i < this._tweenList.length; i++) { - this._tweenList[i].pause(); - } + + /** + * Pauses armature animation. + */ + pause: function () { + var locTweenList = this._tweenList; + for (var i = 0; i < locTweenList.length; i++) + locTweenList[i].pause(); ccs.ProcessBase.prototype.pause.call(this); }, - resume:function () { - for (var i = 0; i < this._tweenList.length; i++) { - this._tweenList[i].resume(); - } + + /** + * Resumes armature animation. + */ + resume: function () { + var locTweenList = this._tweenList; + for (var i = 0; i < locTweenList.length; i++) + locTweenList[i].resume(); ccs.ProcessBase.prototype.resume.call(this); }, - stop:function () { - for (var i = 0; i < this._tweenList.length; i++) { - this._tweenList[i].stop(); - } - this._tweenList = []; + /** + * Stops armature animation. + */ + stop: function () { + var locTweenList = this._tweenList; + for (var i = 0; i < locTweenList.length; i++) + locTweenList[i].stop(); + locTweenList.length = 0; ccs.ProcessBase.prototype.stop.call(this); }, /** - * scale animation play speed + * Sets animation play speed scale. + * @deprecated since v3.0, please use setSpeedScale instead. + * @param {Number} animationScale + */ + setAnimationScale: function (animationScale) { + this.setSpeedScale(animationScale); + }, + + /** + * Returns animation play speed scale. + * @deprecated since v3.0, please use getSpeedScale instead. + * @returns {Number} + */ + getAnimationScale: function () { + return this.getSpeedScale(); + }, + + /** + * Sets animation play speed scale. * @param {Number} speedScale */ - setSpeedScale:function (speedScale) { - if (speedScale == this._speedScale) { + setSpeedScale: function (speedScale) { + if (speedScale === this._speedScale) return; - } this._speedScale = speedScale; this._processScale = !this._movementData ? this._speedScale : this._speedScale * this._movementData.scale; var dict = this._armature.getBoneDic(); for (var key in dict) { var bone = dict[key]; bone.getTween().setProcessScale(this._processScale); - if (bone.getChildArmature()) { - bone.getChildArmature().getAnimation().setProcessScale(this._processScale); - } + if (bone.getChildArmature()) + bone.getChildArmature().getAnimation().setSpeedScale(this._processScale); } }, - getSpeedScale:function(){ + /** + * Returns animation play speed scale. + * @returns {Number} + */ + getSpeedScale: function () { return this._speedScale; }, - getAnimationScale:function(){ - return this.getSpeedScale(); - }, - setAnimationScale:function(animationScale){ - return this.setSpeedScale(animationScale); - }, - /** * play animation by animation name. * @param {String} animationName The animation name you want to play * @param {Number} [durationTo=-1] - * he frames between two animation changing-over.It's meaning is changing to this animation need how many frames + * the frames between two animation changing-over.It's meaning is changing to this animation need how many frames * -1 : use the value from CCMovementData get from flash design panel * @param {Number} [loop=-1] * Whether the animation is loop. @@ -204,76 +246,57 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# * armature.getAnimation().play("run",-1,1);//loop play * armature.getAnimation().play("run",-1,0);//not loop play */ - play:function (animationName, durationTo, loop) { - if (this.animationData == null) { - cc.log("this.animationData can not be null"); - return; - } - this._movementData = this.animationData.getMovement(animationName); - if (this._movementData == null) { - cc.log("this._movementData can not be null"); - return; - } - if (durationTo === undefined) { - durationTo = -1; - } + play: function (animationName, durationTo, loop) { + cc.assert(this._animationData, "this.animationData can not be null"); - if (loop === undefined) { - loop = -1; - } + this._movementData = this._animationData.getMovement(animationName); + cc.assert(this._movementData, "this._movementData can not be null"); - var locMovementData = this._movementData; - //Get key frame count - this._rawDuration = locMovementData.duration; + durationTo = (durationTo === undefined) ? -1 : durationTo; + loop = (loop === undefined) ? -1 : loop; + + //! Get key frame count + this._rawDuration = this._movementData.duration; this._movementID = animationName; - this._processScale = this._speedScale * locMovementData.scale; - //Further processing parameters - durationTo = (durationTo == -1) ? locMovementData.durationTo : durationTo; - var durationTween = locMovementData.durationTween; - durationTween = (durationTween == 0) ? this._rawDuration : durationTween;//todo - var tweenEasing = locMovementData.tweenEasing; - - if (loop < 0) { - loop = locMovementData.loop; - } else { - loop = Boolean(loop); - } + this._processScale = this._speedScale * this._movementData.scale; + //! Further processing parameters + durationTo = (durationTo === -1) ? this._movementData.durationTo : durationTo; + var durationTween = this._movementData.durationTween === 0 ? this._rawDuration : this._movementData.durationTween; + + var tweenEasing = this._movementData.tweenEasing; + //loop = (!loop || loop < 0) ? this._movementData.loop : loop; + loop = (loop < 0) ? this._movementData.loop : loop; this._onMovementList = false; - ccs.ProcessBase.prototype.play.call(this, durationTo, tweenEasing); - if (this._rawDuration == 0) { + ccs.ProcessBase.prototype.play.call(this, durationTo, durationTween, loop, tweenEasing); + + if (this._rawDuration === 0) this._loopType = ccs.ANIMATION_TYPE_SINGLE_FRAME; - } else { - if (loop) { - this._loopType = ccs.ANIMATION_TYPE_TO_LOOP_FRONT; - } - else { - this._loopType = ccs.ANIMATION_TYPE_NO_LOOP; - } + this._loopType = loop ? ccs.ANIMATION_TYPE_TO_LOOP_FRONT : ccs.ANIMATION_TYPE_NO_LOOP; this._durationTween = durationTween; } - this._tweenList = []; + this._tweenList.length = 0; + + var movementBoneData, map = this._armature.getBoneDic(); + for(var element in map) { + var bone = map[element]; + movementBoneData = this._movementData.movBoneDataDic[bone.getName()]; - var movementBoneData; - var dict = this._armature.getBoneDic(); - for (var key in dict) { - var bone = dict[key]; - movementBoneData = locMovementData.getMovementBoneData(bone.getName()); var tween = bone.getTween(); - if (movementBoneData && movementBoneData.frameList.length > 0) { + if(movementBoneData && movementBoneData.frameList.length > 0) { this._tweenList.push(tween); - movementBoneData.duration = locMovementData.duration; + movementBoneData.duration = this._movementData.duration; tween.play(movementBoneData, durationTo, durationTween, loop, tweenEasing); - tween.setProcessScale(this._processScale); - if (bone.getChildArmature()) { - bone.getChildArmature().getAnimation().setProcessScale(this._processScale); - } + + if (bone.getChildArmature()) + bone.getChildArmature().getAnimation().setSpeedScale(this._processScale); } else { - if (!bone.getIgnoreMovementBoneData()) { + if(!bone.isIgnoreMovementBoneData()){ + //! this bone is not include in this movement, so hide it bone.getDisplayManager().changeDisplayWithIndex(-1, false); tween.stop(); } @@ -283,57 +306,91 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# }, /** - * play with names + * Plays animation with index, the other param is the same to play. + * @param {Number} animationIndex + * @param {Number} durationTo + * @param {Number} durationTween + * @param {Number} loop + * @param {Number} [tweenEasing] + * @deprecated since v3.0, please use playWithIndex instead. + */ + playByIndex: function (animationIndex, durationTo, durationTween, loop, tweenEasing) { + cc.log("playByIndex is deprecated. Use playWithIndex instead."); + this.playWithIndex(animationIndex, durationTo, loop); + }, + + /** + * Plays animation with index, the other param is the same to play. + * @param {Number|Array} animationIndex + * @param {Number} durationTo + * @param {Number} loop + */ + playWithIndex: function (animationIndex, durationTo, loop) { + var movName = this._animationData.movementNames; + cc.assert((animationIndex > -1) && (animationIndex < movName.length)); + + var animationName = movName[animationIndex]; + this.play(animationName, durationTo, loop); + }, + + /** + * Plays animation with names * @param {Array} movementNames * @param {Number} durationTo * @param {Boolean} loop */ playWithNames: function (movementNames, durationTo, loop) { - this._movementList = []; + durationTo = (durationTo === undefined) ? -1 : durationTo; + loop = (loop === undefined) ? true : loop; + + this._movementListLoop = loop; + this._movementListDurationTo = durationTo; + this._onMovementList = true; + this._movementIndex = 0; + if(movementNames instanceof Array) + this._movementList = movementNames; + else + this._movementList.length = 0; + this.updateMovementList(); + }, + + /** + * Plays animation by indexes + * @param {Array} movementIndexes + * @param {Number} durationTo + * @param {Boolean} loop + */ + playWithIndexes: function (movementIndexes, durationTo, loop) { + durationTo = (durationTo === undefined) ? -1 : durationTo; + loop = (loop === undefined) ? true : loop; + + this._movementList.length = 0; this._movementListLoop = loop; + this._movementListDurationTo = durationTo; this._onMovementList = true; this._movementIndex = 0; - for (var i = 0; i < movementNames.length; i++) { - this._movementList.push({name: movementNames[i], durationTo: durationTo}); + var movName = this._animationData.movementNames; + + for (var i = 0; i < movementIndexes.length; i++) { + var name = movName[movementIndexes[i]]; + this._movementList.push(name); } this.updateMovementList(); }, - updateMovementList: function () { - if (this._onMovementList) { - if (this._movementListLoop) { - var movementObj = this._movementList[this._movementIndex]; - this.play(movementObj.name, movementObj.durationTo,-1,0); - this._movementIndex++; - if (this._movementIndex >= this._movementList.length) { - this._movementIndex = 0; - } - } - else { - if (this._movementIndex < this._movementList.length) { - var movementObj = this._movementList[this._movementIndex]; - this.play(movementObj.name, movementObj.durationTo,-1,0); - this._movementIndex++; - } - else { - this._onMovementList = false; - } - } - this._onMovementList = true; - } - }, - /** - * Go to specified frame and play current movement. - * You need first switch to the movement you want to play, then call this function. - * - * example : playByIndex(0); - * gotoAndPlay(0); - * playByIndex(1); - * gotoAndPlay(0); - * gotoAndPlay(15); + *

    + * Goes to specified frame and plays current movement.
    + * You need first switch to the movement you want to play, then call this function.
    + *
    + * example : playByIndex(0);
    + * gotoAndPlay(0);
    + * playByIndex(1);
    + * gotoAndPlay(0);
    + * gotoAndPlay(15);
    + *

    * @param {Number} frameIndex */ gotoAndPlay: function (frameIndex) { @@ -342,8 +399,8 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# return; } - var ignoreFrameEvent = this.ignoreFrameEvent; - this.ignoreFrameEvent = true; + var ignoreFrameEvent = this._ignoreFrameEvent; + this._ignoreFrameEvent = true; this._isPlaying = true; this._isComplete = this._isPause = false; @@ -351,16 +408,15 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# this._currentPercent = this._curFrameIndex / (this._movementData.duration - 1); this._currentFrame = this._nextFrameIndex * this._currentPercent; - for (var i = 0; i < this._tweenList.length; i++) { - var tween = this._tweenList[i]; - tween.gotoAndPlay(frameIndex); - } + var locTweenList = this._tweenList; + for (var i = 0; i < locTweenList.length; i++) + locTweenList[i].gotoAndPlay(frameIndex); this._armature.update(0); - this.ignoreFrameEvent = ignoreFrameEvent; + this._ignoreFrameEvent = ignoreFrameEvent; }, /** - * Go to specified frame and pause current movement. + * Goes to specified frame and pauses current movement. * @param {Number} frameIndex */ gotoAndPause: function (frameIndex) { @@ -369,97 +425,49 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# }, /** - * Play animation with index, the other param is the same to play. - * @param {Number||Array} animationIndex - * @param {Number} durationTo - * @param {Number} durationTween - * @param {Number} loop - * @param {Number} tweenEasing - */ - playWithIndex:function (animationIndex, durationTo, durationTween, loop, tweenEasing) { - if (typeof durationTo == "undefined") { - durationTo = -1; - } - if (typeof loop == "undefined") { - loop = -1; - } - var moveNames = this.animationData.movementNames; - if (animationIndex < -1 || animationIndex >= moveNames.length) { - return; - } - var animationName = moveNames[animationIndex]; - this.play(animationName, durationTo,-1, loop, 0); - }, - - /** - * Play animation with index, the o ther param is the same to play. - * @param {Number} animationIndex - * @param {Number} durationTo - * @param {Number} durationTween - * @param {Number} loop - * @param {Number} tweenEasing - */ - playByIndex:function(animationIndex, durationTo, durationTween, loop, tweenEasing){ - cc.log("playByIndex is deprecated. Use playWithIndex instead."); - this.playWithIndex(animationIndex, durationTo, durationTween, loop, tweenEasing); - }, - - /** - * play by indexes - * @param movementIndexes - * @param {Number} durationTo - * @param {Boolean} loop + * Returns the length of armature's movements + * @return {Number} */ - playWithIndexes: function (movementIndexes, durationTo, loop) { - this._movementList = []; - this._movementListLoop = loop; - this._onMovementList = true; - this._movementIndex = 0; - - var movName = this.animationData.movementNames; - - for (var i = 0; i < movementIndexes.length; i++) { - var name = movName[movementIndexes[i]]; - this._movementList.push({name: name, durationTo: durationTo}); - } - - this.updateMovementList(); + getMovementCount: function () { + return this._animationData.getMovementCount(); }, /** - * get movement count - * @return {Number} + * Updates the state of ccs.Tween list, calls frame event's callback and calls movement event's callback. + * @param {Number} dt */ - getMovementCount:function () { - return this.animationData.getMovementCount(); - }, + update: function (dt) { + ccs.ProcessBase.prototype.update.call(this, dt); - update:function (dt) { - if(ccs.ProcessBase.prototype.update.call(this, dt)){ - for (var i = 0; i < this._tweenList.length; i++) { - this._tweenList[i].update(dt); - } - } + var locTweenList = this._tweenList; + for (var i = 0; i < locTweenList.length; i++) + locTweenList[i].update(dt); - var frameEvents = this._frameEventQueue; + var frameEvents = this._frameEventQueue, event; while (frameEvents.length > 0) { - var frameEvent = frameEvents.shift(); - this.ignoreFrameEvent = true; - this.callFrameEvent([frameEvent.bone, frameEvent.frameEventName, frameEvent.originFrameIndex, frameEvent.currentFrameIndex]); - this.ignoreFrameEvent = false; + event = frameEvents.shift(); + this._ignoreFrameEvent = true; + if(this._frameEventCallFunc) + this._frameEventCallFunc.call(this._frameEventTarget, event.bone, event.frameEventName, event.originFrameIndex, event.currentFrameIndex); + if(this._frameEventListener) + this._frameEventListener(event.bone, event.frameEventName, event.originFrameIndex, event.currentFrameIndex); + this._ignoreFrameEvent = false; } var movementEvents = this._movementEventQueue; while (movementEvents.length > 0) { - var movEvent = movementEvents.shift(); - this.callMovementEvent([movEvent.armature, movEvent.movementType, movEvent.movementID]); + event = movementEvents.shift(); + if(this._movementEventCallFunc) + this._movementEventCallFunc.call(this._movementEventTarget, event.armature, event.movementType, event.movementID); + if (this._movementEventListener) + this._movementEventListener(event.armature, event.movementType, event.movementID); } }, /** - * update will call this handler, you can handle your logic here + * Updates will call this handler, you can handle your logic here */ - updateHandler:function () { + updateHandler: function () { //TODO set it to protected in v3.1 var locCurrentPercent = this._currentPercent; if (locCurrentPercent >= 1) { switch (this._loopType) { @@ -472,18 +480,21 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# this.movementEvent(this._armature, ccs.MovementEventType.start, this._movementID); break; } + break; case ccs.ANIMATION_TYPE_MAX: case ccs.ANIMATION_TYPE_SINGLE_FRAME: locCurrentPercent = 1; this._isComplete = true; this._isPlaying = false; + this.movementEvent(this._armature, ccs.MovementEventType.complete, this._movementID); + this.updateMovementList(); break; case ccs.ANIMATION_TYPE_TO_LOOP_FRONT: this._loopType = ccs.ANIMATION_TYPE_LOOP_FRONT; locCurrentPercent = ccs.fmodf(locCurrentPercent, 1); - this._currentFrame = this._nextFrameIndex == 0 ? 0 : ccs.fmodf(this._currentFrame, this._nextFrameIndex); + this._currentFrame = this._nextFrameIndex === 0 ? 0 : ccs.fmodf(this._currentFrame, this._nextFrameIndex); this._nextFrameIndex = this._durationTween > 0 ? this._durationTween : 1; this.movementEvent(this, ccs.MovementEventType.start, this._movementID); break; @@ -499,7 +510,7 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# }, /** - * Get current movementID + * Returns the Id of current movement * @returns {String} */ getCurrentMovementID: function () { @@ -509,63 +520,50 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# }, /** - * connect a event - * @param {Object} target + * Sets movement event callback to animation. * @param {function} callFunc + * @param {Object} target */ - setMovementEventCallFunc:function (callFunc, target) { - this._movementEvent = new ccs.AnimationEvent(target, callFunc); - }, - - /** - * call event - * @param {Array} args - */ - callMovementEvent:function (args) { - if (this._movementEvent) { - this._movementEvent.setArguments(args); - this._movementEvent.call(); + setMovementEventCallFunc: function (callFunc, target) { + if(arguments.length === 1){ + this._movementEventListener = callFunc; + }else if(arguments.length === 2){ + this._movementEventTarget = target; + this._movementEventCallFunc = callFunc; } }, /** - * connect a event - * @param {Object} target + * Sets frame event callback to animation. * @param {function} callFunc + * @param {Object} target */ - setFrameEventCallFunc:function (callFunc, target) { - this._frameEvent = new ccs.AnimationEvent(target, callFunc); + setFrameEventCallFunc: function (callFunc, target) { + if(arguments.length === 1){ + this._frameEventListener = callFunc; + }else if(arguments.length === 2){ + this._frameEventTarget = target; + this._frameEventCallFunc = callFunc; + } }, /** - * call event - * @param {Array} args + * Sets user object to animation. + * @param {Object} userObject */ - callFrameEvent:function (args) { - if (this._frameEvent) { - this._frameEvent.setArguments(args); - this._frameEvent.call(); - } - }, - - movementEvent:function(armature, movementType, movementID){ - if (this._movementEvent) { - var event = new ccs.MovementEvent(); - event.armature = armature; - event.movementType = movementType; - event.movementID = movementID; - this._movementEventQueue.push(event); - } + setUserObject: function (userObject) { + this._userObject = userObject; }, /** + * Emits a frame event * @param {ccs.Bone} bone * @param {String} frameEventName * @param {Number} originFrameIndex * @param {Number} currentFrameIndex */ - frameEvent:function(bone, frameEventName, originFrameIndex, currentFrameIndex){ - if (this._frameEvent) { + frameEvent: function (bone, frameEventName, originFrameIndex, currentFrameIndex) { + if ((this._frameEventTarget && this._frameEventCallFunc) || this._frameEventListener) { var frameEvent = new ccs.FrameEvent(); frameEvent.bone = bone; frameEvent.frameEventName = frameEventName; @@ -574,56 +572,82 @@ ccs.ArmatureAnimation = ccs.ProcessBase.extend(/** @lends ccs.ArmatureAnimation# this._frameEventQueue.push(frameEvent); } }, - + /** - * animationData setter - * @param {ccs.AnimationData} aniData + * Emits a movement event + * @param {ccs.Armature} armature + * @param {Number} movementType + * @param {String} movementID */ - setAnimationData:function (aniData) { - this.animationData = aniData; + movementEvent: function (armature, movementType, movementID) { + if ((this._movementEventTarget && this._movementEventCallFunc) || this._movementEventListener) { + var event = new ccs.MovementEvent(); + event.armature = armature; + event.movementType = movementType; + event.movementID = movementID; + this._movementEventQueue.push(event); + } }, /** - * animationData getter - * @return {ccs.AnimationData} + * Updates movement list. */ - getAnimationData:function () { - return this.animationData; + updateMovementList: function () { + if (this._onMovementList) { + var movementObj, locMovementList = this._movementList; + if (this._movementListLoop) { + movementObj = locMovementList[this._movementIndex]; + this.play(movementObj, movementObj.durationTo, 0); + this._movementIndex++; + if (this._movementIndex >= locMovementList.length) + this._movementIndex = 0; + } else { + if (this._movementIndex < locMovementList.length) { + movementObj = locMovementList[this._movementIndex]; + this.play(movementObj, movementObj.durationTo, 0); + this._movementIndex++; + } else + this._onMovementList = false; + } + this._onMovementList = true; + } }, + /** - * userObject setter - * @param {Object} userObject + * Sets animation data to animation. + * @param {ccs.AnimationData} data */ - setUserObject:function (userObject) { - this.userObject = userObject; + setAnimationData: function (data) { + if(this._animationData !== data) + this._animationData = data; }, /** - * userObject getter - * @return {Object} + * Returns animation data of animation. + * @return {ccs.AnimationData} */ - getUserObject:function () { - return this.userObject; + getAnimationData: function () { + return this._animationData; }, /** - * Determines if the frame event is ignored - * @returns {boolean} + * Returns the user object of animation. + * @return {Object} */ - isIgnoreFrameEvent:function(){ - return this.ignoreFrameEvent; + getUserObject: function () { + return this._userObject; }, /** - * Sets whether the frame event is ignored - * @param {Boolean} bool + * Determines if the frame event is ignored + * @returns {boolean} */ - setIgnoreFrameEvent:function(bool){ - this.ignoreFrameEvent = bool; + isIgnoreFrameEvent: function () { + return this._ignoreFrameEvent; } }); -window._p = ccs.ArmatureAnimation.prototype; +var _p = ccs.ArmatureAnimation.prototype; // Extended properties /** @expose */ @@ -633,20 +657,13 @@ cc.defineGetterSetter(_p, "speedScale", _p.getSpeedScale, _p.setSpeedScale); _p.animationScale; cc.defineGetterSetter(_p, "animationScale", _p.getAnimationScale, _p.setAnimationScale); -delete window._p; +_p = null; /** - * allocates and initializes a ArmatureAnimation. - * @constructs + * Allocates and initializes a ArmatureAnimation. * @return {ccs.ArmatureAnimation} - * @example - * // example - * var animation = ccs.ArmatureAnimation.create(); + * @deprecated since v3.1, please use new construction instead */ ccs.ArmatureAnimation.create = function (armature) { - var animation = new ccs.ArmatureAnimation(); - if (animation && animation.init(armature)) { - return animation; - } - return null; -}; \ No newline at end of file + return new ccs.ArmatureAnimation(armature); +}; diff --git a/extensions/cocostudio/armature/animation/CCProcessBase.js b/extensions/cocostudio/armature/animation/CCProcessBase.js index c63f1b7ab7..a4707d3854 100644 --- a/extensions/cocostudio/armature/animation/CCProcessBase.js +++ b/extensions/cocostudio/armature/animation/CCProcessBase.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,53 +23,52 @@ THE SOFTWARE. ****************************************************************************/ - //animation type /** - * the animation just have one frame + * The animation just have one frame * @constant * @type {number} */ ccs.ANIMATION_TYPE_SINGLE_FRAME = -4; /** - * the animation isn't loop + * The animation isn't loop * @constant * @type {number} */ ccs.ANIMATION_TYPE_NO_LOOP = -3; /** - * the animation to loop from front + * The animation to loop from front * @constant * @type {number} */ ccs.ANIMATION_TYPE_TO_LOOP_FRONT = -2; /** - * the animation to loop from back + * The animation to loop from back * @constant * @type {number} */ ccs.ANIMATION_TYPE_TO_LOOP_BACK = -1; /** - * the animation loop from front + * The animation loop from front * @constant * @type {number} */ ccs.ANIMATION_TYPE_LOOP_FRONT = 0; /** - * the animation loop from back + * The animation loop from back * @constant * @type {number} */ ccs.ANIMATION_TYPE_LOOP_BACK = 1; /** - * the animation max + * The animation max * @constant * @type {number} */ ccs.ANIMATION_TYPE_MAX = 2; /** - * Base class for ccs.ProcessBase objects. + * The Base Process class for Cocostudio. * @class * @extends ccs.Class * @@ -84,22 +84,26 @@ ccs.ANIMATION_TYPE_MAX = 2; * @property {Boolean} playing - <@readonly> Indicate whether the process is playing */ ccs.ProcessBase = ccs.Class.extend(/** @lends ccs.ProcessBase# */{ - processScale:1, - _isComplete:true, - _isPause:true, - _isPlaying:false, - _currentPercent:0.0, - _rawDuration:0, - _loopType:0, - _tweenEasing:0, - animationInternal:null, - _currentFrame:0, - _durationTween:0, - _nextFrameIndex:0, - _curFrameIndex:null, - _isLoopBack:false, - ctor:function () { - this.processScale = 1; + _processScale: 1, + _isComplete: true, + _isPause: true, + _isPlaying: false, + _currentPercent: 0.0, + _rawDuration: 0, + _loopType: 0, + _tweenEasing: 0, + animationInternal: null, + _currentFrame: 0, + _durationTween: 0, + _nextFrameIndex: 0, + _curFrameIndex: null, + _isLoopBack: false, + + /** + * Constructor of ccs.ProcessBase + */ + ctor: function () { + this._processScale = 1; this._isComplete = true; this._isPause = true; this._isPlaying = false; @@ -108,71 +112,96 @@ ccs.ProcessBase = ccs.Class.extend(/** @lends ccs.ProcessBase# */{ this._durationTween = 0; this._rawDuration = 0; this._loopType = ccs.ANIMATION_TYPE_LOOP_BACK; - this._tweenEasing = ccs.TweenType.linear; - this.animationInternal = 1/60; + this._tweenEasing = ccs.TweenType.LINEAR; + this.animationInternal = 1 / 60; this._curFrameIndex = 0; this._durationTween = 0; this._isLoopBack = false; }, /** - * Pause the Process + * Pauses the Process */ - pause:function () { + pause: function () { this._isPause = true; this._isPlaying = false; }, /** - * Resume the Process + * Resumes the Process */ - resume:function () { + resume: function () { this._isPause = false; this._isPlaying = true; }, /** - * Stop the Process + * Stops the Process */ - stop:function () { + stop: function () { this._isComplete = true; this._isPlaying = false; }, /** - * Play the Process - * @param {Number} durationTo - * @param {ccs.TweenType} tweenEasing + * Plays animation by animation name. + * @param {Number} durationTo The frames between two animation changing-over. + * It's meaning is changing to this animation need how many frames + * -1 : use the value from MovementData get from flash design panel + * @param {Number} durationTween The frame count you want to play in the game. + * if _durationTween is 80, then the animation will played 80 frames in a loop + * -1 : use the value from MovementData get from flash design panel + * @param {Number} loop Whether the animation is loop + * loop < 0 : use the value from MovementData get from flash design panel + * loop = 0 : this animation is not loop + * loop > 0 : this animation is loop + * @param {Number} tweenEasing Tween easing is used for calculate easing effect + * TWEEN_EASING_MAX : use the value from MovementData get from flash design panel + * -1 : fade out + * 0 : line + * 1 : fade in + * 2 : fade in and out */ - play:function (durationTo, tweenEasing) { + play: function (durationTo, durationTween, loop, tweenEasing) { this._isComplete = false; this._isPause = false; this._isPlaying = true; this._currentFrame = 0; + /* + * Set m_iTotalFrames to durationTo, it is used for change tween between two animation. + * When changing end, m_iTotalFrames will be set to _durationTween + */ this._nextFrameIndex = durationTo; this._tweenEasing = tweenEasing; }, - update:function (dt) { - if (this._isComplete || this._isPause) { - return false; - } - if (this._rawDuration <= 0) { - return false; - } - var locNextFrameIndex = this._nextFrameIndex; + /** + * Update process' state. + * @param {Number} dt + */ + update: function (dt) { + if (this._isComplete || this._isPause) + return; + + /* + * Fileter the m_iDuration <=0 and dt >1 + * If dt>1, generally speaking the reason is the device is stuck. + */ + if (this._rawDuration <= 0 || dt > 1) + return; + + var locNextFrameIndex = this._nextFrameIndex === undefined ? 0 : this._nextFrameIndex; var locCurrentFrame = this._currentFrame; if (locNextFrameIndex <= 0) { this._currentPercent = 1; locCurrentFrame = 0; - }else{ + } else { /* * update currentFrame, every update add the frame passed. * dt/this.animationInternal determine it is not a frame animation. If frame speed changed, it will not make our * animation speed slower or quicker. */ - locCurrentFrame += this.processScale * (dt / this.animationInternal); - + locCurrentFrame += this._processScale * (dt / this.animationInternal); this._currentPercent = locCurrentFrame / locNextFrameIndex; /* @@ -181,134 +210,131 @@ ccs.ProcessBase = ccs.Class.extend(/** @lends ccs.ProcessBase# */{ */ locCurrentFrame = ccs.fmodf(locCurrentFrame, locNextFrameIndex); } - this._currentFrame = locCurrentFrame + this._currentFrame = locCurrentFrame; this.updateHandler(); - return true; }, /** - * update will call this handler, you can handle your logic here - */ - updateHandler:function () { - //override - }, - - /** - * goto frame + * Goes to specified frame by frameIndex. * @param {Number} frameIndex */ - gotoFrame:function (frameIndex) { + gotoFrame: function (frameIndex) { var locLoopType = this._loopType; - if (locLoopType == ccs.ANIMATION_TYPE_NO_LOOP) { + if (locLoopType === ccs.ANIMATION_TYPE_NO_LOOP) locLoopType = ccs.ANIMATION_TYPE_MAX; - } - else if (locLoopType == ccs.ANIMATION_TYPE_TO_LOOP_FRONT) { + else if (locLoopType === ccs.ANIMATION_TYPE_TO_LOOP_FRONT) locLoopType = ccs.ANIMATION_TYPE_LOOP_FRONT; - } this._loopType = locLoopType; this._curFrameIndex = frameIndex; this._nextFrameIndex = this._durationTween; }, /** - * get currentFrameIndex + * Returns the index of current frame. * @return {Number} */ - getCurrentFrameIndex:function () { - this._curFrameIndex = (this._rawDuration-1) * this._currentPercent; + getCurrentFrameIndex: function () { + this._curFrameIndex = (this._rawDuration - 1) * this._currentPercent; return this._curFrameIndex; }, /** - * whether the animation is pause + * Updates will call this handler, you can handle your logic here + */ + updateHandler: function () { + //override + }, + + /** + * Returns whether the animation is pause * @returns {boolean} */ - isPause:function () { + isPause: function () { return this._isPause; }, /** - * whether the animation is complete + * Returns whether the animation is complete * @returns {boolean} */ - isComplete:function () { + isComplete: function () { return this._isComplete; }, /** - * current percent getter + * Returns current percent of ccs.ProcessBase * @returns {number} */ - getCurrentPercent:function () { + getCurrentPercent: function () { return this._currentPercent; }, /** - * rawDuration getter + * Returns the raw duration of ccs.ProcessBase * @returns {number} */ - getRawDuration:function () { + getRawDuration: function () { return this._rawDuration; }, /** - * loop type getter + * Returns loop type of ccs.ProcessBase * @returns {number} */ - getLoop:function () { + getLoop: function () { return this._loopType; }, /** - * tween easing getter + * Returns tween easing of ccs.ProcessBase * @returns {number} */ - getTweenEasing:function () { + getTweenEasing: function () { return this._tweenEasing; }, /** - * animationInternal getter + * Returns animation interval of ccs.ProcessBase * @returns {number} */ - getAnimationInternal:function () { + getAnimationInternal: function () { //TODO rename getAnimationInternal to getAnimationInterval in v3.1 return this.animationInternal; }, /** - * animationInternal setter + * Sets animation interval to ccs.ProcessBase. * @param animationInternal */ - setAnimationInternal:function(animationInternal){ + setAnimationInternal: function (animationInternal) { this.animationInternal = animationInternal; }, /** - * process scale getter + * Returns process scale * @returns {number} */ - getProcessScale:function () { - return this.processScale; + getProcessScale: function () { + return this._processScale; }, /** - * process scale setter + * Sets process scale * @param processScale */ - setProcessScale:function (processScale) { - this.processScale = processScale; + setProcessScale: function (processScale) { + this._processScale = processScale; }, /** - * whether the animation is playing + * Returns whether the animation is playing * @returns {boolean} */ - isPlaying:function () { + isPlaying: function () { return this._isPlaying; } }); -window._p = ccs.ProcessBase.prototype; +var _p = ccs.ProcessBase.prototype; // Extended properties /** @expose */ @@ -336,4 +362,4 @@ cc.defineGetterSetter(_p, "tweenEasing", _p.getTweenEasing); _p.playing; cc.defineGetterSetter(_p, "playing", _p.isPlaying); -delete window._p; +_p = null; diff --git a/extensions/cocostudio/armature/animation/CCTween.js b/extensions/cocostudio/armature/animation/CCTween.js index c42c2e71a3..5706d1d595 100644 --- a/extensions/cocostudio/armature/animation/CCTween.js +++ b/extensions/cocostudio/armature/animation/CCTween.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,10 +24,12 @@ ****************************************************************************/ /** - * Base class for ccs.Tween objects. + * The tween class for Armature. * @class * @extends ccs.ProcessBase * + * @param {ccs.Bone} The bone to be animated + * * @property {ccs.ArmatureAnimation} animation - The animation */ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ @@ -41,25 +44,18 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ _totalDuration:0, _toIndex:0, _fromIndex:0, - animation:null, + _animation:null, _passLastFrame:false, - ctor:function () { + + ctor:function (bone) { ccs.ProcessBase.prototype.ctor.call(this); - this._tweenData = null; - this._to = null; - this._from = null; - this._between = null; - this._bone = null; - this._movementBoneData = null; - this._frameTweenEasing = ccs.TweenType.linear; - this._toIndex = 0; - this._fromIndex = 0; - this.animation = null; - this._passLastFrame = false; + this._frameTweenEasing = ccs.TweenType.LINEAR; + + ccs.Tween.prototype.init.call(this, bone); }, /** - * init with a CCBone + * initializes a ccs.Tween with a CCBone * @param {ccs.Bone} bone * @return {Boolean} */ @@ -70,13 +66,15 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ this._bone = bone; this._tweenData = this._bone.getTweenData(); this._tweenData.displayIndex = -1; - var armature = bone.getArmature(); - if (armature) this.animation = armature.getAnimation(); + + this._animation = (this._bone !== null && this._bone.getArmature() !== null) ? + this._bone.getArmature().getAnimation() : + null; return true; }, /** - * Start the Process + * Plays the tween. * @param {ccs.MovementBoneData} movementBoneData * @param {Number} durationTo * @param {Number} durationTween @@ -84,21 +82,18 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ * @param {ccs.TweenType} tweenEasing */ play:function (movementBoneData, durationTo, durationTween, loop, tweenEasing) { - ccs.ProcessBase.prototype.play.call(this, durationTo, tweenEasing); - - if(loop){ - this._loopType = ccs.ANIMATION_TYPE_TO_LOOP_FRONT; - }else{ - this._loopType = ccs.ANIMATION_TYPE_NO_LOOP; - } + ccs.ProcessBase.prototype.play.call(this, durationTo, durationTween, loop, tweenEasing); + this._loopType = (loop)?ccs.ANIMATION_TYPE_TO_LOOP_FRONT:ccs.ANIMATION_TYPE_NO_LOOP; this._totalDuration = 0; this._betweenDuration = 0; this._fromIndex = this._toIndex = 0; - var difMovement = movementBoneData != this._movementBoneData; - this._movementBoneData = movementBoneData; + var difMovement = movementBoneData !== this._movementBoneData; + + this.setMovementBoneData(movementBoneData); this._rawDuration = this._movementBoneData.duration; + var nextKeyFrame = this._movementBoneData.getFrameData(0); this._tweenData.displayIndex = nextKeyFrame.displayIndex; @@ -108,22 +103,20 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ this._tweenData.scaleY += 1; } - if (this._rawDuration == 0 || this._movementBoneData.frameList.length == 1) { + if (this._rawDuration === 0) { this._loopType = ccs.ANIMATION_TYPE_SINGLE_FRAME; - if (durationTo == 0) { + if (durationTo === 0) this.setBetween(nextKeyFrame, nextKeyFrame); - } else { + else this.setBetween(this._tweenData, nextKeyFrame); - } - this._frameTweenEasing = ccs.TweenType.linear; + this._frameTweenEasing = ccs.TweenType.LINEAR; } else if (this._movementBoneData.frameList.length > 1) { this._durationTween = durationTween * this._movementBoneData.scale; - if (loop && this._movementBoneData.delay != 0) { + if (loop && this._movementBoneData.delay !== 0) this.setBetween(this._tweenData, this.tweenNodeTo(this.updateFrameData(1 - this._movementBoneData.delay), this._between)); - } else { - if (!difMovement || durationTo == 0) + if (!difMovement || durationTo === 0) this.setBetween(nextKeyFrame, nextKeyFrame); else this.setBetween(this._tweenData, nextKeyFrame); @@ -132,17 +125,28 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ this.tweenNodeTo(0); }, + /** + * Goes to specified frame and plays frame. + * @param {Number} frameIndex + */ gotoAndPlay: function (frameIndex) { ccs.ProcessBase.prototype.gotoFrame.call(this, frameIndex); + this._totalDuration = 0; this._betweenDuration = 0; this._fromIndex = this._toIndex = 0; + this._isPlaying = true; this._isComplete = this._isPause = false; + this._currentPercent = this._curFrameIndex / (this._rawDuration-1); this._currentFrame = this._nextFrameIndex * this._currentPercent; }, + /** + * Goes to specified frame and pauses frame. + * @param {Number} frameIndex + */ gotoAndPause: function (frameIndex) { this.gotoAndPlay(frameIndex); this.pause(); @@ -152,7 +156,7 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ * update will call this handler, you can handle your logic here */ updateHandler:function () { - var locCurrentPercent = this._currentPercent; + var locCurrentPercent = this._currentPercent == null ? 1 : this._currentPercent; var locLoopType = this._loopType; if (locCurrentPercent >= 1) { switch (locLoopType) { @@ -163,19 +167,16 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ break; case ccs.ANIMATION_TYPE_NO_LOOP: locLoopType = ccs.ANIMATION_TYPE_MAX; - if (this._durationTween <= 0) { + if (this._durationTween <= 0) locCurrentPercent = 1; - } - else { + else locCurrentPercent = (locCurrentPercent - 1) * this._nextFrameIndex / this._durationTween; - } if (locCurrentPercent >= 1) { locCurrentPercent = 1; this._isComplete = true; this._isPlaying = false; break; - } - else { + } else { this._nextFrameIndex = this._durationTween; this._currentFrame = locCurrentPercent * this._nextFrameIndex; this._totalDuration = 0; @@ -186,10 +187,10 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ case ccs.ANIMATION_TYPE_TO_LOOP_FRONT: locLoopType = ccs.ANIMATION_TYPE_LOOP_FRONT; this._nextFrameIndex = this._durationTween > 0 ? this._durationTween : 1; - if (this._movementBoneData.delay != 0) { + + if (this._movementBoneData.delay !== 0) { this._currentFrame = (1 - this._movementBoneData.delay) * this._nextFrameIndex; locCurrentPercent = this._currentFrame / this._nextFrameIndex; - } else { locCurrentPercent = 0; this._currentFrame = 0; @@ -206,39 +207,32 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ break; default: this._currentFrame = ccs.fmodf(this._currentFrame, this._nextFrameIndex); - this._totalDuration = 0; - this._betweenDuration = 0; break; } } - if (locCurrentPercent < 1 && locLoopType < ccs.ANIMATION_TYPE_TO_LOOP_BACK) { + if (locCurrentPercent < 1 && locLoopType < ccs.ANIMATION_TYPE_TO_LOOP_BACK) locCurrentPercent = Math.sin(locCurrentPercent * cc.PI / 2); - } this._currentPercent = locCurrentPercent; this._loopType = locLoopType; - if (locLoopType > ccs.ANIMATION_TYPE_TO_LOOP_BACK) { + if (locLoopType > ccs.ANIMATION_TYPE_TO_LOOP_BACK) locCurrentPercent = this.updateFrameData(locCurrentPercent); - } - if (this._frameTweenEasing != ccs.TweenType.tweenEasingMax) { + if (this._frameTweenEasing !== ccs.TweenType.TWEEN_EASING_MAX) this.tweenNodeTo(locCurrentPercent); - } }, /** * Calculate the between value of _from and _to, and give it to between frame data * @param {ccs.FrameData} from * @param {ccs.FrameData} to - * @param {Boolean} limit + * @param {Boolean} [limit=true] */ - setBetween:function (from, to, limit) { - if (typeof limit == "undefined") { + setBetween:function (from, to, limit) { //TODO set tweenColorTo to protected in v3.1 + if(limit === undefined) limit = true; - } - do - { + do { if (from.displayIndex < 0 && to.displayIndex >= 0) { this._from.copy(to); this._between.subtract(to, to, limit); @@ -263,24 +257,28 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ * Update display index and process the key frame event when arrived a key frame * @param {ccs.FrameData} keyFrameData */ - arriveKeyFrame:function (keyFrameData) { + arriveKeyFrame:function (keyFrameData) { //TODO set tweenColorTo to protected in v3.1 if (keyFrameData) { var locBone = this._bone; - var displayIndex = keyFrameData.displayIndex; var displayManager = locBone.getDisplayManager(); - if (!displayManager.getForceChangeDisplay()) { + + //! Change bone's display + var displayIndex = keyFrameData.displayIndex; + + if (!displayManager.getForceChangeDisplay()) displayManager.changeDisplayWithIndex(displayIndex, false); - var locRenderNode = displayManager.getDisplayRenderNode(); - if(locRenderNode) - locRenderNode.setBlendFunc(keyFrameData.blendFunc); - } + + //! Update bone zorder, bone's zorder is determined by frame zorder and bone zorder this._tweenData.zOrder = keyFrameData.zOrder; locBone.updateZOrder(); + + //! Update blend type + this._bone.setBlendFunc(keyFrameData.blendFunc); + var childAramture = locBone.getChildArmature(); if (childAramture) { - if (keyFrameData.movement != "") { + if (keyFrameData.movement !== "") childAramture.getAnimation().play(keyFrameData.movement); - } } } }, @@ -288,18 +286,17 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ /** * According to the percent to calculate current CCFrameData with tween effect * @param {Number} percent - * @param {ccs.FrameData} node + * @param {ccs.FrameData} [node] * @return {ccs.FrameData} */ - tweenNodeTo:function (percent, node) { - if (!node) { + tweenNodeTo:function (percent, node) { //TODO set tweenColorTo to protected in v3.1 + if (!node) node = this._tweenData; - } + var locFrom = this._from; var locBetween = this._between; - if (!locFrom.isTween){ + if (!locFrom.isTween) percent = 0; - } node.x = locFrom.x + percent * locBetween.x; node.y = locFrom.y + percent * locBetween.y; node.scaleX = locFrom.scaleX + percent * locBetween.scaleX; @@ -314,7 +311,12 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ return node; }, - tweenColorTo:function(percent,node){ + /** + * According to the percent to calculate current color with tween effect + * @param {Number} percent + * @param {ccs.FrameData} node + */ + tweenColorTo:function(percent,node){ //TODO set tweenColorTo to protected in v3.1 var locFrom = this._from; var locBetween = this._between; node.a = locFrom.a + percent * locBetween.a; @@ -329,11 +331,12 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ * @param {Number} currentPercent * @return {Number} */ - updateFrameData:function (currentPercent) { - if (currentPercent > 1 && this._movementBoneData.delay != 0) { + updateFrameData:function (currentPercent) { //TODO set tweenColorTo to protected in v3.1 + if (currentPercent > 1 && this._movementBoneData.delay !== 0) currentPercent = ccs.fmodf(currentPercent,1); - } + var playedTime = (this._rawDuration-1) * currentPercent; + var from, to; var locTotalDuration = this._totalDuration,locBetweenDuration = this._betweenDuration, locToIndex = this._toIndex; // if play to current frame's front or back, then find current frame again @@ -342,100 +345,104 @@ ccs.Tween = ccs.ProcessBase.extend(/** @lends ccs.Tween# */{ * get frame length, if this._toIndex >= _length, then set this._toIndex to 0, start anew. * this._toIndex is next index will play */ - var length = this._movementBoneData.frameList.length; var frames = this._movementBoneData.frameList; + var length = frames.length; + if (playedTime < frames[0].frameID){ from = to = frames[0]; this.setBetween(from, to); - return currentPercent; + return this._currentPercent; } - else if (playedTime >= frames[length - 1].frameID) { + + if (playedTime >= frames[length - 1].frameID) { + // If _passLastFrame is true and playedTime >= frames[length - 1]->frameID, then do not need to go on. if (this._passLastFrame) { from = to = frames[length - 1]; this.setBetween(from, to); - return currentPercent; + return this._currentPercent; } this._passLastFrame = true; - } else { + } else this._passLastFrame = false; - } do { this._fromIndex = locToIndex; from = frames[this._fromIndex]; locTotalDuration = from.frameID; + locToIndex = this._fromIndex + 1; - if (locToIndex >= length) { + if (locToIndex >= length) locToIndex = 0; - } to = frames[locToIndex]; //! Guaranteed to trigger frame event - if(from.event&& !this.animation.isIgnoreFrameEvent()){ - this.animation.frameEvent(this._bone, from.event,from.frameID, playedTime); - } + if(from.strEvent && !this._animation.isIgnoreFrameEvent()) + this._animation.frameEvent(this._bone, from.strEvent,from.frameID, playedTime); - if (playedTime == from.frameID|| (this._passLastFrame && this._fromIndex == length-1)){ + if (playedTime === from.frameID|| (this._passLastFrame && this._fromIndex === length-1)) break; - } - } - while (playedTime < from.frameID || playedTime >= to.frameID); + } while (playedTime < from.frameID || playedTime >= to.frameID); locBetweenDuration = to.frameID - from.frameID; this._frameTweenEasing = from.tweenEasing; this.setBetween(from, to, false); + this._totalDuration = locTotalDuration; this._betweenDuration = locBetweenDuration; this._toIndex = locToIndex; } - - currentPercent = locBetweenDuration == 0 ? 0 : (playedTime - locTotalDuration) / locBetweenDuration; + currentPercent = locBetweenDuration === 0 ? 0 : (playedTime - this._totalDuration) / this._betweenDuration; /* * if frame tween easing equal to TWEEN_EASING_MAX, then it will not do tween. */ - var tweenType = (this._frameTweenEasing != ccs.TweenType.linear) ? this._frameTweenEasing : this._tweenEasing; - if (tweenType != ccs.TweenType.tweenEasingMax&&tweenType != ccs.TweenType.linear&& !this._passLastFrame) { + var tweenType = (this._frameTweenEasing !== ccs.TweenType.LINEAR) ? this._frameTweenEasing : this._tweenEasing; + if (tweenType !== ccs.TweenType.TWEEN_EASING_MAX && tweenType !== ccs.TweenType.LINEAR && !this._passLastFrame) { currentPercent = ccs.TweenFunction.tweenTo(currentPercent, tweenType, this._from.easingParams); } return currentPercent; }, /** - * animation setter + * Sets Armature animation to ccs.Tween. * @param {ccs.ArmatureAnimation} animation */ setAnimation:function (animation) { - this.animation = animation; + this._animation = animation; }, /** - * animation getter + * Returns Armature animation of ccs.Tween. * @return {ccs.ArmatureAnimation} */ getAnimation:function () { - return this.animation; + return this._animation; }, - release:function () { - this._from = null; - this._between = null; + /** + * Sets movement bone data to ccs.Tween. + * @param data + */ + setMovementBoneData: function(data){ + this._movementBoneData = data; } }); +var _p = ccs.Tween.prototype; + +// Extended properties +/** @expose */ +_p.animation; +cc.defineGetterSetter(_p, "animation", _p.getAnimation, _p.setAnimation); + +_p = null; + /** - * allocates and initializes a ArmatureAnimation. - * @constructs + * Allocates and initializes a ArmatureAnimation. * @param {ccs.Bone} bone - * @return {ccs.ArmatureAnimation} - * @example - * // example - * var animation = ccs.ArmatureAnimation.create(); + * @return {ccs.Tween} + * @deprecated since v3.1, please use new construction instead */ ccs.Tween.create = function (bone) { - var tween = new ccs.Tween(); - if (tween && tween.init(bone)) { - return tween; - } - return null; + return new ccs.Tween(bone); }; diff --git a/extensions/cocostudio/armature/datas/CCDatas.js b/extensions/cocostudio/armature/datas/CCDatas.js index a4680f4b24..6aa958b36a 100644 --- a/extensions/cocostudio/armature/datas/CCDatas.js +++ b/extensions/cocostudio/armature/datas/CCDatas.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -121,17 +122,50 @@ ccs.BLEND_TYPE_ALPHA = 12; */ ccs.BLEND_TYPE_ERASE = 13; - //DisplayType +/** + * The Sprite flag of display render type. + * @constant + * @type Number + */ ccs.DISPLAY_TYPE_SPRITE = 0; +/** + * The Armature flag of display render type. + * @constant + * @type Number + */ ccs.DISPLAY_TYPE_ARMATURE = 1; +/** + * The Particle flag of display render type. + * @constant + * @type Number + */ ccs.DISPLAY_TYPE_PARTICLE = 2; ccs.DISPLAY_TYPE_MAX = 3; /** - * Base class for ccs.BaseData objects. + *

    + * The base data class for Armature. it contains position, zOrder, skew, scale, color datas.
    + * x y skewX skewY scaleX scaleY used to calculate transform matrix
    + * skewX, skewY can have rotation effect
    + * To get more matrix information, you can have a look at this pape : http://www.senocular.com/flash/tutorials/transformmatrix/
    + *

    * @class * @extends ccs.Class + * + * @property {Number} x - x + * @property {Number} y - y + * @property {Number} zOrder - zOrder + * @property {Number} skewX - skewX + * @property {Number} skewY - skewY + * @property {Number} scaleX - scaleX + * @property {Number} scaleY - scaleY + * @property {Number} tweenRotate - tween Rotate + * @property {Number} isUseColorInfo - is Use Color Info + * @property {Number} r - r of color + * @property {Number} g - g of color + * @property {Number} b - b of color + * @property {Number} a - a of color */ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ x:0, @@ -141,13 +175,16 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ skewY:0, scaleX:1, scaleY:1, - tweenRotate:0, - isUseColorInfo:false, + tweenRotate:0, //! SkewX, SkewY, and TweenRotate effect the rotation + isUseColorInfo:false, //! Whether or not this frame have the color changed Info r:255, g:255, b:255, a:255, + /** + * Construction of ccs.BaseData + */ ctor:function () { this.x = 0; this.y = 0; @@ -164,20 +201,23 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ this.a = 255; }, - /** * Copy data from node + * @function * @param {ccs.BaseData} node */ copy:function (node) { this.x = node.x; this.y = node.y; this.zOrder = node.zOrder; + this.scaleX = node.scaleX; this.scaleY = node.scaleY; this.skewX = node.skewX; this.skewY = node.skewY; + this.tweenRotate = node.tweenRotate; + this.isUseColorInfo = node.isUseColorInfo; this.r = node.r; this.g = node.g; @@ -186,7 +226,8 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ }, /** - * color setter + * Sets color to base data. + * @function * @param {cc.Color} color */ setColor:function(color){ @@ -197,7 +238,8 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ }, /** - * color getter + * Returns the color of ccs.BaseData + * @function * @returns {cc.Color} */ getColor:function(){ @@ -206,6 +248,7 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ /** * Calculate two baseData's between value(to - from) and set to self + * @function * @param {ccs.BaseData} from * @param {ccs.BaseData} to * @param {Boolean} limit @@ -230,40 +273,44 @@ ccs.BaseData = ccs.Class.extend(/** @lends ccs.BaseData# */{ } if (limit) { - if (this.skewX > cc.PI) { - this.skewX -= ccs.M_PI_X_2; - } - if (this.skewX < -cc.PI) { - this.skewX += ccs.M_PI_X_2; - } - if (this.skewY > cc.PI) { - this.skewY -= ccs.M_PI_X_2; - } - if (this.skewY < -cc.PI) { - this.skewY += ccs.M_PI_X_2; - } + if (this.skewX > ccs.M_PI) + this.skewX -= ccs.DOUBLE_PI; + if (this.skewX < -ccs.M_PI) + this.skewX += ccs.DOUBLE_PI; + if (this.skewY > ccs.M_PI) + this.skewY -= ccs.DOUBLE_PI; + if (this.skewY < -ccs.M_PI) + this.skewY += ccs.DOUBLE_PI; } if (to.tweenRotate) { - this.skewX += to.tweenRotate * ccs.M_PI_X_2; - this.skewY -= to.tweenRotate * ccs.M_PI_X_2; + this.skewX += to.tweenRotate * ccs.PI * 2; + this.skewY -= to.tweenRotate * ccs.PI * 2; } } }); /** - * Base class for ccs.DisplayData objects. + * The class use for save display data. * @class * @extends ccs.Class + * + * @property {Number} displayType - the display type + * @property {String} displayName - the display name */ ccs.DisplayData = ccs.Class.extend(/** @lends ccs.DisplayData# */{ - displayType:ccs.DISPLAY_TYPE_MAX, - displayName:"", - ctor:function () { + displayType: ccs.DISPLAY_TYPE_MAX, + displayName: "", + + /** + * Construction of ccs.DisplayData + */ + ctor: function () { this.displayType = ccs.DISPLAY_TYPE_MAX; }, /** - * change display name to texture type + * Changes display name to texture type + * @function * @param {String} displayName * @returns {String} */ @@ -272,13 +319,14 @@ ccs.DisplayData = ccs.Class.extend(/** @lends ccs.DisplayData# */{ var textureName = displayName; var startPos = textureName.lastIndexOf("."); - if (startPos != -1) { + if (startPos !== -1) textureName = textureName.substring(0, startPos); - } return textureName; }, + /** * copy data + * @function * @param {ccs.DisplayData} displayData */ copy:function (displayData) { @@ -288,18 +336,25 @@ ccs.DisplayData = ccs.Class.extend(/** @lends ccs.DisplayData# */{ }); /** - * Base class for ccs.SpriteDisplayData objects. + * The sprite display data class. * @class * @extends ccs.DisplayData + * + * @property {ccs.BaseData} skinData - the skin data */ ccs.SpriteDisplayData = ccs.DisplayData.extend(/** @lends ccs.SpriteDisplayData# */{ skinData:null, + + /** + * Construction of ccs.SpriteDisplayData + */ ctor:function () { this.skinData = new ccs.BaseData(); this.displayType = ccs.DISPLAY_TYPE_SPRITE; }, /** * copy data + * @function * @param {ccs.SpriteDisplayData} displayData */ copy:function (displayData) { @@ -309,12 +364,14 @@ ccs.SpriteDisplayData = ccs.DisplayData.extend(/** @lends ccs.SpriteDisplayData# }); /** - * Base class for ccs.ArmatureDisplayData objects. - * @class + * The armature display data class + * @class ccs.ArmatureDisplayData * @extends ccs.DisplayData */ ccs.ArmatureDisplayData = ccs.DisplayData.extend(/** @lends ccs.ArmatureDisplayData# */{ - displayName:"", + /** + * Construction of ccs.ArmatureDisplayData + */ ctor:function () { this.displayName = ""; this.displayType = ccs.DISPLAY_TYPE_ARMATURE; @@ -322,38 +379,60 @@ ccs.ArmatureDisplayData = ccs.DisplayData.extend(/** @lends ccs.ArmatureDisplayD }); /** - * Base class for ccs.ParticleDisplayData objects. - * @class + * The particle display data class. + * @class ccs.ParticleDisplayData * @extends ccs.DisplayData */ ccs.ParticleDisplayData = ccs.DisplayData.extend(/** @lends ccs.ParticleDisplayData# */{ + /** + * Construction of ccs.ParticleDisplayData + */ ctor:function () { this.displayType = ccs.DISPLAY_TYPE_PARTICLE; } }); /** - * Base class for ccs.BoneData objects. - * @class + *

    + * BoneData used to init a Bone.
    + * BoneData keeps a DisplayData list, a Bone can have many display to change.
    + * The display information saved in the DisplayData
    + *

    + * @class ccs.BoneData * @extends ccs.BaseData + * + * @property {Array} displayDataList - the display data list + * @property {String} name - the name of Bone + * @property {String} parentName - the parent name of bone + * @property {cc.AffineTransform} boneDataTransform - the bone transform data */ ccs.BoneData = ccs.BaseData.extend(/** @lends ccs.BoneData# */{ - displayDataList:null, - name:"", - parentName:"", - boneDataTransform:null, - ctor:function () { + displayDataList: null, + name: "", + parentName: "", + boneDataTransform: null, + + /** + * Construction of ccs.BoneData + */ + ctor: function () { this.displayDataList = []; this.name = ""; this.parentName = ""; this.boneDataTransform = null; - }, - init:function () { + /** + * Initializes a ccs.BoneData + * @returns {boolean} + */ + init: function () { + this.displayDataList.length = 0; + return true; }, /** - * add display data + * Adds display data to list + * @function * @param {ccs.DisplayData} displayData */ addDisplayData:function (displayData) { @@ -361,7 +440,8 @@ ccs.BoneData = ccs.BaseData.extend(/** @lends ccs.BoneData# */{ }, /** - * get display data + * Returns display data with index. + * @function * @param {Number} index * @returns {ccs.DisplayData} */ @@ -371,38 +451,58 @@ ccs.BoneData = ccs.BaseData.extend(/** @lends ccs.BoneData# */{ }); /** - * Base class for ccs.ArmatureData objects. - * @class + *

    + * ArmatureData saved the Armature name and BoneData needed for the CCBones in this Armature
    + * When we create a Armature, we need to get each Bone's BoneData as it's init information.
    + * So we can get a BoneData from the Dictionary saved in the ArmatureData.
    + *

    + * @class ccs.ArmatureData * @extends ccs.Class + * + * @property {Object} boneDataDic - the bone data dictionary + * @property {String} name - the name of armature data + * @property {Number} dataVersion - the data version of armature data */ ccs.ArmatureData = ccs.Class.extend(/** @lends ccs.ArmatureData# */{ boneDataDic:null, name:"", dataVersion:0.1, + + /** + * Construction of ccs.ArmatureData + */ ctor:function () { this.boneDataDic = {}; this.name = ""; this.dataVersion = 0.1; }, + + /** + * Initializes a ccs.ArmatureData + * @returns {boolean} + */ init:function () { return true; }, + /** - * add bone data + * Adds bone data to dictionary * @param {ccs.BoneData} boneData */ addBoneData:function (boneData) { this.boneDataDic[boneData.name] = boneData; }, + /** - * get bone datas + * Gets bone data dictionary * @returns {Object} */ getBoneDataDic:function () { return this.boneDataDic; }, /** - * get bone data by bone name + * Gets bone data by bone name + * @function * @param {String} boneName * @returns {ccs.BoneData} */ @@ -412,9 +512,22 @@ ccs.ArmatureData = ccs.Class.extend(/** @lends ccs.ArmatureData# */{ }); /** - * Base class for ccs.FrameData objects. - * @class + * FrameData saved the frame data needed for armature animation in this Armature. + * @class ccs.FrameData * @extends ccs.BaseData + * + * @property {Number} duration - the duration of frame + * @property {Number} tweenEasing - the easing type of frame + * @property {Number} easingParamNumber - the count of easing parameters. + * @property {Object} easingParams - the dictionary of easing parameters. + * @property {Number} displayIndex - the display renderer index. + * @property {String} movement - the movement name. + * @property {String} event - the event name + * @property {String} sound - the sound path. + * @property {String} soundEffect - the sound effect path. + * @property {Object} blendFunc - the blendFunc of frame. + * @property {Number} frameID - the frame ID of frame + * @property {Boolean} isTween - the flag which frame whether is tween. */ ccs.FrameData = ccs.BaseData.extend(/** @lends ccs.FrameData# */{ duration:0, @@ -426,13 +539,17 @@ ccs.FrameData = ccs.BaseData.extend(/** @lends ccs.FrameData# */{ event:"", sound:"", soundEffect:"", - blendFunc:0, + blendFunc:null, frameID:0, isTween:true, + + /** + * Construction of ccs.FrameData. + */ ctor:function () { ccs.BaseData.prototype.ctor.call(this); this.duration = 1; - this.tweenEasing = ccs.TweenType.linear; + this.tweenEasing = ccs.TweenType.LINEAR; this.easingParamNumber = 0; this.easingParams = []; this.displayIndex = 0; @@ -447,35 +564,45 @@ ccs.FrameData = ccs.BaseData.extend(/** @lends ccs.FrameData# */{ /** * copy data + * @function * @param frameData */ copy:function (frameData) { ccs.BaseData.prototype.copy.call(this, frameData); this.duration = frameData.duration; - this.tweenEasing = frameData.tweenEasing; this.displayIndex = frameData.displayIndex; - this.movement = frameData.movement; - this.event = frameData.event; - this.sound = frameData.sound; - this.soundEffect = frameData.soundEffect; - this.blendFunc = frameData.blendFunc; - this.isTween = frameData.isTween; + this.tweenEasing = frameData.tweenEasing; this.easingParamNumber = frameData.easingParamNumber; - this.easingParams = []; - if (this.easingParamNumber != 0) { - for (var i = 0; i + * The animation data information of Cocos Armature. It include all movement information for the Armature.
    + * The struct is AnimationData -> MovementData -> MovementBoneData -> FrameData
    + * -> MovementFrameData
    + *

    + * @class ccs.AnimationData * @extends ccs.Class */ -ccs.AnimationData = ccs.Class.extend(/** @lends ccs.AnimationData# */{ - moveDataDic:null, - movementNames:null, - name:"", - ctor:function () { - this.moveDataDic = {}; - this.movementNames = []; - }, - /** - * add movement data - * @param {ccs.MovementData} moveData - */ - addMovement:function (moveData) { - this.moveDataDic[moveData.name] = moveData; - this.movementNames.push(moveData.name); - }, - /** - * get movement data - * @param {String} moveName - * @returns {ccs.MovementData} - */ - getMovement:function (moveName) { - return this.moveDataDic[moveName]; - }, - /** - * - * @returns {Number} - */ - getMovementCount:function () { - return Object.keys(this.moveDataDic).length; - } -}); +ccs.AnimationData = function(){ + this.movementDataDic = {}; + this.movementNames = []; + this.name = ""; +}; + +/** + * adds movement data to the movement data dictionary + * @param {ccs.MovementData} moveData + */ +ccs.AnimationData.prototype.addMovement = function(moveData){ + this.movementDataDic[moveData.name] = moveData; + this.movementNames.push(moveData.name); +}; + +/** + * gets movement data from movement data dictionary + * @param {String} moveName + * @returns {ccs.MovementData} + */ +ccs.AnimationData.prototype.getMovement = function(moveName){ + return this.movementDataDic[moveName]; +}; + +/** + * gets the count of movement data dictionary + * @returns {Number} + */ +ccs.AnimationData.prototype.getMovementCount = function(){ + return Object.keys(this.movementDataDic).length; +}; /** * contour vertex + * @class ccs.ContourVertex2 * @param {Number} x * @param {Number} y * @constructor @@ -603,70 +750,58 @@ ccs.ContourVertex2 = function (x, y) { }; /** - * Base class for ccs.ContourData objects. - * @class - * @extends ccs.Class + * The Contour data information of Cocos Armature. + * @class ccs.ContourData + * @constructor */ -ccs.ContourData = ccs.Class.extend({ - vertexList:null, - ctor:function () { - this.vertexList = []; - }, +ccs.ContourData = function(){ + this.vertexList = []; +}; - init:function () { - this.vertexList = []; - return true; - }, +ccs.ContourData.prototype.init = function(){ + this.vertexList.length = 0; + return true; +}; - /** - * add vertex - * @param {cc.Point} p - */ - addVertex: function (p) { - var v = ccs.ContourVertex2(p.x, p.y); - this.vertexList.push(v); - } -}); +/** + * add a vertex object to vertex list + * @param {cc.Point} p + */ +ccs.ContourData.prototype.addVertex = function(p){ + //var v = new ccs.ContourVertex2(p.x, p.y); //ccs.ContourVertex2 is same as cc.Point, so we needn't create a ccs.ContourVertex2 object + this.vertexList.push(p); +}; /** - * Base class for ccs.TextureData objects. - * @class - * @extends ccs.Class + * The texture data information of Cocos Armature + * @class ccs.TextureData */ -ccs.TextureData = ccs.Class.extend(/** @lends ccs.TextureData# */{ - height:0, - width:0, - pivotX:0, - pivotY:0, - name:"", - contourDataList:null, - ctor:function () { - this.height = 0; - this.width = 0; - this.pivotX = 0.5; - this.pivotY = 0.5; - this.name = ""; - this.contourDataList = []; - }, +ccs.TextureData = function(){ + this.height = 0; + this.width = 0; + this.pivotX = 0.5; + this.pivotY = 0.5; + this.name = ""; + this.contourDataList = []; +}; - init:function () { - this.contourDataList = []; - }, +ccs.TextureData.prototype.init = function(){ + this.contourDataList.length = 0; +}; - /** - * set contourData - * @param {ccs.ContourData} contourData - */ - addContourData:function (contourData) { - this.contourDataList.push(contourData); - }, +/** + * Adds a contourData to contourDataList + * @param {ccs.ContourData} contourData + */ +ccs.TextureData.prototype.addContourData = function(contourData){ + this.contourDataList.push(contourData); +}; - /** - * get contourData - * @param {Number} index - * @returns {ccs.ContourData} - */ - getContourData:function (index) { - return this.contourDataList[index]; - } -}); +/** + * gets a contourData from contourDataList by index + * @param {Number} index + * @returns {ccs.ContourData} + */ +ccs.TextureData.prototype.getContourData = function(index){ + return this.contourDataList[index]; +}; diff --git a/extensions/cocostudio/armature/display/CCBatchNode.js b/extensions/cocostudio/armature/display/CCBatchNode.js index ad8307b5f7..f20c238850 100644 --- a/extensions/cocostudio/armature/display/CCBatchNode.js +++ b/extensions/cocostudio/armature/display/CCBatchNode.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,12 +23,21 @@ THE SOFTWARE. ****************************************************************************/ -cc.BatchNode = cc.Node.extend({ +/** + * A batchNode to Armature + * @class ccs.BatchNode + * @extends cc.Node + */ +ccs.BatchNode = cc.Node.extend(/** @lends ccs.BatchNode# */{ _atlas:null, _className:"BatchNode", + ctor:function () { this._atlas = null; + + ccs.BatchNode.prototype.init.call(this); }, + init:function () { var ret = cc.Node.prototype.init.call(this); this.setShaderProgram(cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURE_UCOLOR)); @@ -36,36 +46,52 @@ cc.BatchNode = cc.Node.extend({ addChild:function (child, zOrder, tag) { cc.Node.prototype.addChild.call(this, child, zOrder, tag); - if (child instanceof cc.Armature) { + if (child instanceof cc.Armature){ child.setBatchNode(this); } }, - visit:function () { + removeChild: function(child, cleanup){ + if (child instanceof cc.Armature) + child.setBatchNode(null); + cc.Node.prototype.removeChild.call(this, child, cleanup); + }, + + visit:function (renderer, parentTransform, parentTransformUpdated) { // quick return if not visible. children won't be drawn. - if (!this._visible) { + if (!this._visible) return; - } - this.kmGLPushMatrix(); - if (this.grid && this.grid.isActive()) { + + var dirty = parentTransformUpdated || this._transformUpdated; + if(dirty) + this._modelViewTransform = this.transform(parentTransform); + this._transformUpdated = false; + + // IMPORTANT: + // To ease the migration to v3.0, we still support the kmGL stack, + // but it is deprecated and your code should not rely on it + cc.kmGLPushMatrixWitMat4(this._stackMatrix); + + if (this.grid && this.grid.isActive()) this.grid.beforeDraw(); - } - this.transform(); + this.sortAllChildren(); - this.draw(); - // reset for next frame - this.arrivalOrder = 0; - if (this.grid && this.grid.isActive()) { + this.draw(renderer, this._modelViewTransform, dirty); + + if (this.grid && this.grid.isActive()) this.grid.afterDraw(this); - } - this.kmGLPopMatrix(); + + cc.kmGLPopMatrix(); }, - draw:function (ctx) { - cc.nodeDrawSetup(this); + draw:function (renderer, transform, transformUpdated) { + var locChildren = this._children; + if(locChildren.length === 0) + return; + var child = null; - for (var i = 0; i < this._children.length; i++) { - child = this._children[i]; + for (var i = 0, len = locChildren.length; i < len; i++) { + child = locChildren[i]; child.visit(); if (child instanceof cc.Armature) { this._atlas = child.getTextureAtlas(); @@ -77,10 +103,12 @@ cc.BatchNode = cc.Node.extend({ } } }); -cc.BatchNode.create = function () { - var batchNode = new cc.BatchNode(); - if (batchNode && batchNode.init()) { - return batchNode; - } - return null; + +/** + * + * @returns {ccs.BatchNode} + * @deprecated since v3.1, please use new construction instead + */ +ccs.BatchNode.create = function () { + return new ccs.BatchNode(); }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/display/CCDecorativeDisplay.js b/extensions/cocostudio/armature/display/CCDecorativeDisplay.js index 2a537eccda..f7a7c3d4bf 100644 --- a/extensions/cocostudio/armature/display/CCDecorativeDisplay.js +++ b/extensions/cocostudio/armature/display/CCDecorativeDisplay.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,35 +24,45 @@ ****************************************************************************/ /** - * Base class for ccs.DecorativeDisplay + * Decorative a display node for Cocos Armature * @class * @extends ccs.Class */ ccs.DecorativeDisplay = ccs.Class.extend(/** @lends ccs.DecorativeDisplay# */{ - _display:null, - _colliderDetector:null, - _displayData:null, + _display: null, + _colliderDetector: null, + _displayData: null, ctor:function () { this._display = null; this._colliderDetector = null; this._displayData = null; + + //ccs.DecorativeDisplay.prototype.init.call(this); }, + /** + * Initializes a ccs.DecorativeDisplay + * @returns {boolean} + */ init:function () { return true; }, /** - * display setter + * Sets display node to decorative * @param {cc.Node} display */ setDisplay:function (display) { + if(display._parent){ + display._parent.removeChild(display); + delete display._parent; + } this._display = display; }, /** - * display getter + * Returns the display node * @returns {cc.Node} */ getDisplay:function () { @@ -59,7 +70,7 @@ ccs.DecorativeDisplay = ccs.Class.extend(/** @lends ccs.DecorativeDisplay# */{ }, /** - * colliderDetector setter + * Sets collide detector * @param {ccs.ColliderDetector} colliderDetector */ setColliderDetector:function (colliderDetector) { @@ -67,7 +78,7 @@ ccs.DecorativeDisplay = ccs.Class.extend(/** @lends ccs.DecorativeDisplay# */{ }, /** - * colliderDetector getter + * Returns collide detector * @returns {ccs.ColliderDetector} */ getColliderDetector:function () { @@ -75,7 +86,7 @@ ccs.DecorativeDisplay = ccs.Class.extend(/** @lends ccs.DecorativeDisplay# */{ }, /** - * display data setter + * Sets display data * @param {ccs.DisplayData} displayData */ setDisplayData:function (displayData) { @@ -83,35 +94,25 @@ ccs.DecorativeDisplay = ccs.Class.extend(/** @lends ccs.DecorativeDisplay# */{ }, /** - * display data getter + * Returns display data * @returns {ccs.DisplayData} */ getDisplayData:function () { return this._displayData; }, + release:function () { - CC_SAFE_RELEASE(this._display); this._display = null; - CC_SAFE_RELEASE(this._displayData); this._displayData = null; - CC_SAFE_RELEASE(this._colliderDetector); this._colliderDetector = null; } - }); /** - * allocates and initializes a decorative display. - * @constructs + * Allocates and initializes a decorative display. * @return {ccs.DecorativeDisplay} - * @example - * // example - * var display = ccs.DecorativeDisplay.create(); + * @deprecated since v3.1, please use new construction instead */ ccs.DecorativeDisplay.create = function () { - var decorativeDisplay = new ccs.DecorativeDisplay(); - if (decorativeDisplay && decorativeDisplay.init()) { - return decorativeDisplay; - } - return null; + return new ccs.DecorativeDisplay(); }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/display/CCDisplayFactory.js b/extensions/cocostudio/armature/display/CCDisplayFactory.js index a898315dc8..da8f8601df 100644 --- a/extensions/cocostudio/armature/display/CCDisplayFactory.js +++ b/extensions/cocostudio/armature/display/CCDisplayFactory.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,181 +26,192 @@ /** * @ignore */ -ccs.DisplayFactory = ccs.DisplayFactory || ccs.Class.extend({}); -ccs.DisplayFactory.addDisplay = function (bone, decoDisplay, displayData) { - switch (displayData.displayType) { - case ccs.DISPLAY_TYPE_SPRITE: - this.addSpriteDisplay(bone, decoDisplay, displayData); - break; - case ccs.DISPLAY_TYPE_PARTICLE: - this.addParticleDisplay(bone, decoDisplay, displayData); - break; - case ccs.DISPLAY_TYPE_ARMATURE: - this.addArmatureDisplay(bone, decoDisplay, displayData); - break; - default: - break; - } -}; -ccs.DisplayFactory.createDisplay = function (bone, decoDisplay) { - switch (decoDisplay.getDisplayData().displayType) { - case ccs.DISPLAY_TYPE_SPRITE: - this.createSpriteDisplay(bone, decoDisplay); - break; - case ccs.DISPLAY_TYPE_PARTICLE: - this.createParticleDisplay(bone, decoDisplay); - break; - case ccs.DISPLAY_TYPE_ARMATURE: - this.createArmatureDisplay(bone, decoDisplay); - break; - default: - break; - } -}; -ccs.DisplayFactory._helpTransform = {a:1, b:0, c:0, d:1, tx:0, ty:0}; -ccs.DisplayFactory.updateDisplay = function (bone,dt, dirty) { - var display = bone.getDisplayRenderNode(); - if(!display) - return; - - switch (bone.getDisplayRenderNodeType()) { - case ccs.DISPLAY_TYPE_SPRITE: - if (dirty){ - display.updateArmatureTransform(); - } - break; - case ccs.DISPLAY_TYPE_PARTICLE: - this.updateParticleDisplay(bone, display, dt); - break; - case ccs.DISPLAY_TYPE_ARMATURE: - this.updateArmatureDisplay(bone, display, dt); - break; - default: - display.setAdditionalTransform(bone.nodeToArmatureTransform()); - break; - } +ccs.displayFactory = { + addDisplay: function (bone, decoDisplay, displayData) { + switch (displayData.displayType) { + case ccs.DISPLAY_TYPE_SPRITE: + this.addSpriteDisplay(bone, decoDisplay, displayData); + break; + case ccs.DISPLAY_TYPE_PARTICLE: + this.addParticleDisplay(bone, decoDisplay, displayData); + break; + case ccs.DISPLAY_TYPE_ARMATURE: + this.addArmatureDisplay(bone, decoDisplay, displayData); + break; + default: + break; + } + }, - if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { - if (dirty) { - var decoDisplay = bone.getDisplayManager().getCurrentDecorativeDisplay(); - var detector = decoDisplay.getColliderDetector(); - if (detector) { - var node = decoDisplay.getDisplay(); - var displayTransform = node.nodeToParentTransform(); - var helpTransform = this._helpTransform; - helpTransform.a = displayTransform.a; - helpTransform.b = displayTransform.b; - helpTransform.c = displayTransform.c; - helpTransform.d = displayTransform.d; - helpTransform.tx = displayTransform.tx; - helpTransform.ty = displayTransform.ty; - var anchorPoint = node.getAnchorPointInPoints(); - anchorPoint = cc.PointApplyAffineTransform(anchorPoint, helpTransform); - helpTransform.tx = anchorPoint.x; - helpTransform.ty = anchorPoint.y; - var t = cc.AffineTransformConcat(helpTransform, bone.getArmature().nodeToParentTransform()); - detector.updateTransform(t); + createDisplay: function (bone, decoDisplay) { + switch (decoDisplay.getDisplayData().displayType) { + case ccs.DISPLAY_TYPE_SPRITE: + this.createSpriteDisplay(bone, decoDisplay); + break; + case ccs.DISPLAY_TYPE_PARTICLE: + this.createParticleDisplay(bone, decoDisplay); + break; + case ccs.DISPLAY_TYPE_ARMATURE: + this.createArmatureDisplay(bone, decoDisplay); + break; + default: + break; + } + }, + + _helpTransform: {a:1, b:0, c:0, d:1, tx:0, ty:0}, + updateDisplay: function (bone,dt, dirty) { + var display = bone.getDisplayRenderNode(); + if(!display) + return; + + switch (bone.getDisplayRenderNodeType()) { + case ccs.DISPLAY_TYPE_SPRITE: + if (dirty) + display.updateArmatureTransform(); + break; + case ccs.DISPLAY_TYPE_PARTICLE: + this.updateParticleDisplay(bone, display, dt); + break; + case ccs.DISPLAY_TYPE_ARMATURE: + this.updateArmatureDisplay(bone, display, dt); + break; + default: + var transform = bone.getNodeToArmatureTransform(); + display.setAdditionalTransform(transform); + break; + } + if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { + if (dirty) { + var decoDisplay = bone.getDisplayManager().getCurrentDecorativeDisplay(); + var detector = decoDisplay.getColliderDetector(); + if (detector) { + var node = decoDisplay.getDisplay(); + var displayTransform = node.getNodeToParentTransform(); + var helpTransform = this._helpTransform; + helpTransform.a = displayTransform.a; + helpTransform.b = displayTransform.b; + helpTransform.c = displayTransform.c; + helpTransform.d = displayTransform.d; + helpTransform.tx = displayTransform.tx; + helpTransform.ty = displayTransform.ty; + var anchorPoint = cc.pointApplyAffineTransform(node.getAnchorPointInPoints(), helpTransform); + helpTransform.tx = anchorPoint.x; + helpTransform.ty = anchorPoint.y; + var t = cc.affineTransformConcat(helpTransform, bone.getArmature().getNodeToParentTransform()); + detector.updateTransform(t); + } } } - } + }, -}; -ccs.DisplayFactory.addSpriteDisplay = function (bone, decoDisplay, displayData) { - var sdp = new ccs.SpriteDisplayData(); - sdp.copy(displayData); - decoDisplay.setDisplayData(sdp); - this.createSpriteDisplay(bone, decoDisplay); -}; - -ccs.DisplayFactory.createSpriteDisplay = function (bone, decoDisplay) { - var skin = null; - var displayData = decoDisplay.getDisplayData(); - //! remove .xxx - var textureName = displayData.displayName; - var startPos = textureName.lastIndexOf("."); - if (startPos != -1) { - textureName = textureName.substring(0, startPos); - } - //! create display - if (textureName == "") { - skin = ccs.Skin.create(); - } - else { - skin = ccs.Skin.createWithSpriteFrameName(textureName + ".png"); - } - decoDisplay.setDisplay(skin); - skin.setBone(bone); - this.initSpriteDisplay(bone, decoDisplay, displayData.displayName, skin); - var armature = bone.getArmature(); - if (armature) { - if (armature.getArmatureData().dataVersion >= ccs.CONST_VERSION_COMBINED) - skin.setSkinData(displayData.skinData); + addSpriteDisplay: function (bone, decoDisplay, displayData) { + var sdp = new ccs.SpriteDisplayData(); + sdp.copy(displayData); + decoDisplay.setDisplayData(sdp); + this.createSpriteDisplay(bone, decoDisplay); + }, + + createSpriteDisplay: function (bone, decoDisplay) { + var skin = null; + var displayData = decoDisplay.getDisplayData(); + //! remove .xxx + var textureName = displayData.displayName; + var startPos = textureName.lastIndexOf("."); + if (startPos !== -1) + textureName = textureName.substring(0, startPos); + //! create display + if (textureName === "") + skin = new ccs.Skin(); else - skin.setSkinData(bone.getBoneData()); - } + skin = new ccs.Skin("#" + textureName + ".png"); + decoDisplay.setDisplay(skin); -}; + skin.setBone(bone); + this.initSpriteDisplay(bone, decoDisplay, displayData.displayName, skin); -ccs.DisplayFactory.initSpriteDisplay = function(bone, decoDisplay, displayName, skin){ - var textureName = displayName; - var startPos = textureName.lastIndexOf("."); - if (startPos != -1) { - textureName = textureName.substring(0, startPos); - } - var textureData = ccs.armatureDataManager.getTextureData(textureName); - if (textureData) { - //! Init display anchorPoint, every Texture have a anchor point - skin.setAnchorPoint(textureData.pivotX, textureData.pivotY); - } - if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { - if (textureData && textureData.contourDataList.length > 0) { - var colliderDetector = ccs.ColliderDetector.create(bone); - colliderDetector.addContourDataList(textureData.contourDataList); - decoDisplay.setColliderDetector(colliderDetector); + var armature = bone.getArmature(); + if (armature) { + if (armature.getArmatureData().dataVersion >= ccs.CONST_VERSION_COMBINED) + skin.setSkinData(displayData.skinData); + else + skin.setSkinData(bone.boneData); } + }, + + initSpriteDisplay: function (bone, decoDisplay, displayName, skin) { + //! remove .xxx + var textureName = displayName; + var startPos = textureName.lastIndexOf("."); + + if (startPos !== -1) + textureName = textureName.substring(0, startPos); + + var textureData = ccs.armatureDataManager.getTextureData(textureName); + if (textureData) { + //! Init display anchorPoint, every Texture have a anchor point + skin.setAnchorPoint(cc.p(textureData.pivotX, textureData.pivotY)); + } + + if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { + if (textureData && textureData.contourDataList.length > 0) { + //! create ContourSprite + var colliderDetector = new ccs.ColliderDetector(bone); + colliderDetector.addContourDataList(textureData.contourDataList); + decoDisplay.setColliderDetector(colliderDetector); + } + } + }, + + addArmatureDisplay: function (bone, decoDisplay, displayData) { + var adp = new ccs.ArmatureDisplayData(); + adp.copy(displayData); + decoDisplay.setDisplayData(adp); + + this.createArmatureDisplay(bone, decoDisplay); + }, + + createArmatureDisplay: function (bone, decoDisplay) { + var displayData = decoDisplay.getDisplayData(); + var armature = new ccs.Armature(displayData.displayName, bone); + decoDisplay.setDisplay(armature); + }, + + updateArmatureDisplay: function (bone, armature, dt) { + if (armature) { + armature.sortAllChildren(); + armature.update(dt); + } + }, + + addParticleDisplay: function (bone, decoDisplay, displayData) { + var adp = new ccs.ParticleDisplayData(); + adp.copy(displayData); + decoDisplay.setDisplayData(adp); + this.createParticleDisplay(bone, decoDisplay); + }, + + createParticleDisplay: function (bone, decoDisplay) { + var displayData = decoDisplay.getDisplayData(); + var system = new cc.ParticleSystem(displayData.displayName); + + system.removeFromParent(); + system.cleanup(); + + var armature = bone.getArmature(); + if (armature) + system.setParent(bone.getArmature()); + + decoDisplay.setDisplay(system); + }, + + updateParticleDisplay: function (bone, particleSystem, dt) { + var node = new ccs.BaseData(); + ccs.TransformHelp.matrixToNode(bone.nodeToArmatureTransform(), node); + particleSystem.setPosition(node.x, node.y); + particleSystem.setScaleX(node.scaleX); + particleSystem.setScaleY(node.scaleY); + particleSystem.update(dt); } -}; - -ccs.DisplayFactory.addArmatureDisplay = function (bone, decoDisplay, displayData) { - var adp = new ccs.ArmatureDisplayData(); - adp.copy(displayData); - decoDisplay.setDisplayData(adp); - - this.createArmatureDisplay(bone, decoDisplay); -}; -ccs.DisplayFactory.createArmatureDisplay = function (bone, decoDisplay) { - var displayData = decoDisplay.getDisplayData(); - var armature = ccs.Armature.create(displayData.displayName, bone); - decoDisplay.setDisplay(armature); -}; -ccs.DisplayFactory.updateArmatureDisplay = function (bone, armature, dt) { - if (armature) { - armature.sortAllChildren(); - armature.update(dt); - } -}; - -ccs.DisplayFactory.addParticleDisplay = function (bone, decoDisplay, displayData) { - var adp = new ccs.ParticleDisplayData(); - adp.copy(displayData); - decoDisplay.setDisplayData(adp); - this.createParticleDisplay(bone, decoDisplay); -}; -ccs.DisplayFactory.createParticleDisplay = function (bone, decoDisplay) { - var displayData = decoDisplay.getDisplayData(); - var system = cc.ParticleSystem.create(displayData.displayName); - var armature = bone.getArmature(); - if (armature) { - system.setParent(bone.getArmature()); - } - decoDisplay.setDisplay(system); -}; -ccs.DisplayFactory.updateParticleDisplay = function (bone, particleSystem, dt) { - var node = new ccs.BaseData(); - ccs.TransformHelp.matrixToNode(bone.nodeToArmatureTransform(), node); - particleSystem.setPosition(node.x, node.y); - particleSystem.setScaleX(node.scaleX); - particleSystem.setScaleY(node.scaleY); - particleSystem.update(dt); -}; +}; \ No newline at end of file diff --git a/extensions/cocostudio/armature/display/CCDisplayManager.js b/extensions/cocostudio/armature/display/CCDisplayManager.js index e49855c9e5..5ea12a0fe7 100644 --- a/extensions/cocostudio/armature/display/CCDisplayManager.js +++ b/extensions/cocostudio/armature/display/CCDisplayManager.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,54 +24,117 @@ ****************************************************************************/ /** - * The display manager of CocoStudio - * @Class + * The display manager for CocoStudio Armature bone. + * @Class ccs.DisplayManager * @extend cc.Class + * + * @param {ccs.Bone} bone The bone for the display manager */ -ccs.DisplayManager = ccs.Class.extend(/** @lends cc.DisplayManager */{ +ccs.DisplayManager = ccs.Class.extend(/** @lends ccs.DisplayManager */{ _decoDisplayList:null, _currentDecoDisplay:null, _displayRenderNode:null, - _displayIndex:-1, + _displayIndex: null, _forceChangeDisplay:false, _bone:null, _visible:true, _displayType: null, - ctor:function () { + + ctor:function (bone) { this._decoDisplayList = []; this._currentDecoDisplay = null; this._displayRenderNode = null; - this._displayIndex = -1; + this._displayIndex = null; this._forceChangeDisplay = false; this._bone = null; this._visible = true; this._displayType = ccs.DISPLAY_TYPE_MAX; + + bone && ccs.DisplayManager.prototype.init.call(this, bone); }, + /** + * Initializes a ccs.DisplayManager. + * @param bone + * @returns {boolean} + */ init:function (bone) { this._bone = bone; this.initDisplayList(bone.getBoneData()); return true; }, - addDisplay: function (displayData, index) { - var decoDisplay = null; - if (index >= 0 && index < this._decoDisplayList.length) { - decoDisplay = this._decoDisplayList[index]; - } - else { - decoDisplay = ccs.DecorativeDisplay.create(); - this._decoDisplayList.push(decoDisplay); + /** + *

    + * Add display and use _DisplayData init the display.
    + * If index already have a display, then replace it.
    + * If index is current display index, then also change display to _index
    + *

    + * @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 + * @param {Number} index the index of the display you want to replace or add to. -1 : append display from back + */ + addDisplay: function (display, index) { + var decoDisplay, locDisplayList = this._decoDisplayList; + if( (index >= 0) && (index < locDisplayList.length) ) + decoDisplay = locDisplayList[index]; + else{ + decoDisplay = new ccs.DecorativeDisplay(); + locDisplayList.push(decoDisplay); } - if(displayData instanceof ccs.DisplayData){ - ccs.DisplayFactory.addDisplay(this._bone, decoDisplay, displayData); - }else{ - this._addDisplayOther(decoDisplay,displayData); + if(display instanceof ccs.DisplayData){ + ccs.displayFactory.addDisplay(this._bone, decoDisplay, display); + //! if changed display index is current display index, then change current display to the new display + if(index === this._displayIndex) { + this._displayIndex = -1; + this.changeDisplayWithIndex(index, false); + } + return; } + var displayData = null; + if (display instanceof ccs.Skin) { + display.setBone(this._bone); + displayData = new ccs.SpriteDisplayData(); + ccs.displayFactory.initSpriteDisplay(this._bone, decoDisplay, display.getDisplayName(), display); + + var spriteDisplayData = decoDisplay.getDisplayData(); + if (spriteDisplayData instanceof ccs.SpriteDisplayData) { + display.setSkinData(spriteDisplayData.skinData); + displayData.skinData = spriteDisplayData.skinData; + } else { + var find = false; + for (var i = locDisplayList.length - 2; i >= 0; i--) { + var dd = locDisplayList[i]; + var sdd = dd.getDisplayData(); + if (sdd instanceof ccs.SpriteDisplayData) { + find = true; + display.setSkinData(sdd.skinData); + displayData.skinData = sdd.skinData; + break; + } + } + if (!find) + display.setSkinData(new ccs.BaseData()); + } + } else if (display instanceof cc.ParticleSystem){ + displayData = new ccs.ParticleDisplayData(); + display.removeFromParent(); + display.cleanup(); + var armature = this._bone.getArmature(); + if (armature) + display.setParent(armature); + } else if(display instanceof ccs.Armature) { + displayData = new ccs.ArmatureDisplayData(); + displayData.displayName = display.getName(); + display.setParentBone(this._bone); + } else + displayData = new ccs.DisplayData(); + decoDisplay.setDisplay(display); + decoDisplay.setDisplayData(displayData); + //! if changed display index is current display index, then change current display to the new display - if (index == this._displayIndex) { + if(index === this._displayIndex) { this._displayIndex = -1; this.changeDisplayWithIndex(index, false); } @@ -83,7 +147,7 @@ ccs.DisplayManager = ccs.Class.extend(/** @lends cc.DisplayManager */{ skin.setBone(this._bone); displayData = new ccs.SpriteDisplayData(); displayData.displayName = skin.getDisplayName(); - ccs.DisplayFactory.initSpriteDisplay(this._bone, decoDisplay, skin.getDisplayName(), skin); + ccs.displayFactory.initSpriteDisplay(this._bone, decoDisplay, skin.getDisplayName(), skin); var spriteDisplayData = decoDisplay.getDisplayData(); if (spriteDisplayData instanceof ccs.SpriteDisplayData) skin.setSkinData(spriteDisplayData.skinData); @@ -122,210 +186,258 @@ ccs.DisplayManager = ccs.Class.extend(/** @lends cc.DisplayManager */{ decoDisplay.setDisplayData(displayData); }, + /** + * Removes display node from list. + * @param {Number} index + */ removeDisplay:function (index) { this._decoDisplayList.splice(index, 1); - if (index == this._displayIndex) { + if (index === this._displayIndex) { this.setCurrentDecorativeDisplay(null); + this._displayIndex = -1; } }, + /** + * Returns the display node list. + * @returns {Array} + */ getDecorativeDisplayList:function(){ return this._decoDisplayList; }, + /** + *

    + * Change display by index. You can just use this method to change display in the display list.
    + * The display list is just used for this bone, and it is the displays you may use in every frame.
    + * Note : if index is the same with prev index, the method will not effect
    + *

    + * @param {Number} index The index of the display you want to change + * @param {Boolean} 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. + */ changeDisplayWithIndex:function (index, force) { if (index >= this._decoDisplayList.length) { cc.log("the index value is out of range"); return; } - this._forceChangeDisplay = force; - //this._displayIndex == -1, it means you want to hide you display - if (index < 0) { - this._displayIndex = index; - if (this._displayRenderNode) { - this._displayRenderNode.removeFromParent(true); - this.setCurrentDecorativeDisplay(null); - this._displayRenderNode = null; - } - return; - } - //if index is equal to current display index,then do nothing - if (this._displayIndex == index) { + if (this._displayIndex === index) return; - } + this._displayIndex = index; - var decoDisplay = this._decoDisplayList[this._displayIndex]; - if(!decoDisplay){ + //! If displayIndex < 0, it means you want to hide you display + if (index < 0) { + if(this._displayRenderNode) { + this._displayRenderNode.removeFromParent(true); + this.setCurrentDecorativeDisplay(null); + } return; } - this.setCurrentDecorativeDisplay(decoDisplay); + this.setCurrentDecorativeDisplay(this._decoDisplayList[index]); }, + /** + * Change display by name. @see changeDisplayWithIndex. + * @param {String} name + * @param {Boolean} force + */ changeDisplayWithName: function (name, force) { - for (var i = 0; i < this._decoDisplayList.length; i++) { - if (this._decoDisplayList[i].getDisplayData().displayName == name) { + var locDisplayList = this._decoDisplayList; + for (var i = 0; i < locDisplayList.length; i++) { + if (locDisplayList[i].getDisplayData().displayName === name) { this.changeDisplayWithIndex(i, force); break; } } }, + /** + * Sets current decorative display. + * @param {ccs.DecorativeDisplay} decoDisplay + */ setCurrentDecorativeDisplay:function (decoDisplay) { var locCurrentDecoDisplay = this._currentDecoDisplay; if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { - if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector()) { + if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector()) locCurrentDecoDisplay.getColliderDetector().setActive(false); - } } this._currentDecoDisplay = decoDisplay; locCurrentDecoDisplay = this._currentDecoDisplay; if (ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT || ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { - if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector()) { + if (locCurrentDecoDisplay && locCurrentDecoDisplay.getColliderDetector()) locCurrentDecoDisplay.getColliderDetector().setActive(true); - } } - var displayRenderNode = locCurrentDecoDisplay == null ? null : locCurrentDecoDisplay.getDisplay(); - if (this._displayRenderNode) { - if (this._displayRenderNode instanceof ccs.Armature) { - this._bone.setChildArmature(null); - } - this._displayRenderNode.removeFromParent(true); - this._displayRenderNode = null; - } + var displayRenderNode = (!locCurrentDecoDisplay) ? null : locCurrentDecoDisplay.getDisplay(); + var locRenderNode = this._displayRenderNode, locBone = this._bone; + if (locRenderNode) { + if (locRenderNode instanceof ccs.Armature) + locBone.setChildArmature(null); + locRenderNode.removeFromParent(true); + } this._displayRenderNode = displayRenderNode; if (displayRenderNode) { if (displayRenderNode instanceof ccs.Armature) { this._bone.setChildArmature(displayRenderNode); - }else if(displayRenderNode instanceof cc.ParticleSystem) { - displayRenderNode.resetSystem(); + displayRenderNode.setParentBone(this._bone); + } else if (displayRenderNode instanceof cc.ParticleSystem) { + if (displayRenderNode instanceof ccs.Armature) { + locBone.setChildArmature(displayRenderNode); + displayRenderNode.setParentBone(locBone); + } else if (displayRenderNode instanceof cc.ParticleSystem) + displayRenderNode.resetSystem(); } - if (displayRenderNode.RGBAProtocol) { - displayRenderNode.setColor(this._bone.getDisplayedColor()); - displayRenderNode.setOpacity(this._bone.getDisplayedOpacity()); - } - displayRenderNode.retain(); + + displayRenderNode.setColor(locBone.getDisplayedColor()); + displayRenderNode.setOpacity(locBone.getDisplayedOpacity()); + + this._displayRenderNode.setVisible(this._visible); this._displayType = this._currentDecoDisplay.getDisplayData().displayType; - //todo - //this._displayRenderNode.setVisible(this._visible); - }else{ + }else this._displayType = ccs.DISPLAY_TYPE_MAX; - } + + + cc.renderer.childrenOrderDirty = true; }, + /** + * Returns the current display render node. + * @returns {cc.Node} + */ getDisplayRenderNode:function () { return this._displayRenderNode; }, + /** + * Returns the type of display render node. + * @returns {Number} + */ getDisplayRenderNodeType:function(){ return this._displayType; }, + /** + * Returns the index of display render node. + * @returns {Number} + */ getCurrentDisplayIndex:function () { return this._displayIndex; }, + /** + * Returns the current decorative display + * @returns {ccs.DecorativeDisplay} + */ getCurrentDecorativeDisplay:function () { return this._currentDecoDisplay; }, + /** + * Gets a decorative display by index. + * @param index + * @returns {ccs.DecorativeDisplay} + */ getDecorativeDisplayByIndex:function (index) { return this._decoDisplayList[index]; }, + /** + *

    + * Use BoneData to init the display list. + * If display is a sprite, and it have texture info in the TextureData, then use TextureData to init the display node's anchor point + * If the display is a Armature, then create a new Armature + *

    + * @param {ccs.BoneData} boneData + */ initDisplayList:function (boneData) { - this._decoDisplayList = []; - if (!boneData) { + this._decoDisplayList.length = 0; + if (!boneData) return; - } - var displayList = boneData.displayDataList; + var displayList = boneData.displayDataList, decoList = this._decoDisplayList, locBone = this._bone; for (var i = 0; i < displayList.length; i++) { var displayData = displayList[i]; - var decoDisplay = ccs.DecorativeDisplay.create(); + var decoDisplay = new ccs.DecorativeDisplay(); decoDisplay.setDisplayData(displayData); - - ccs.DisplayFactory.createDisplay(this._bone, decoDisplay); - - this._decoDisplayList.push(decoDisplay); + ccs.displayFactory.createDisplay(locBone, decoDisplay); + decoList.push(decoDisplay); } }, + /** + * Check if the position is inside the bone. + * @param {cc.Point|Number} point + * @param {Number} [y] + * @returns {boolean} + */ containPoint: function (point, y) { - var p = cc.p(0, 0); - if (y === undefined) { - p.x = point.x; - p.y = point.y; - } else { - p.x = point; - p.y = y; - } - if (!this._visible || this._displayIndex < 0) { + if (!this._visible || this._displayIndex < 0) return false; - } - var ret = false; - switch (this._currentDecoDisplay.getDisplayData().displayType) { - case ccs.DISPLAY_TYPE_SPRITE: - /* - * First we first check if the point is in the sprite content rect. If false, then we continue to check - * the contour point. If this step is also false, then we can say the bone not contain this point. - * - */ - var outPoint = cc.p(0, 0); - var sprite = this._currentDecoDisplay.getDisplay(); - sprite = sprite.getChildByTag(0); - ret = ccs.SPRITE_CONTAIN_POINT_WITH_RETURN(sprite, p, outPoint); - break; - default: - break; + if (y !== undefined) + point = cc.p(point, y); + + if(this._currentDecoDisplay.getDisplayData().displayType === ccs.DISPLAY_TYPE_SPRITE){ + /* + * First we first check if the point is in the sprite content rect. If false, then we continue to check + * the contour point. If this step is also false, then we can say the bone not contain this point. + * + */ + var sprite = this._currentDecoDisplay.getDisplay(); + sprite = sprite.getChildByTag(0); + return ccs.SPRITE_CONTAIN_POINT_WITH_RETURN(sprite, point); } - return ret; + return false; }, + /** + *

    + * Sets whether the display is visible
    + * The default value is true, a node is default to visible + *

    + * @param {boolean} visible + */ setVisible:function (visible) { - if (!this._displayRenderNode) { + if (!this._displayRenderNode) return; - } this._visible = visible; this._displayRenderNode.setVisible(visible); }, + /** + * Determines if the display is visible + * @returns {boolean} true if the node is visible, false if the node is hidden. + */ isVisible:function () { return this._visible; }, getContentSize:function () { - if (!this._displayRenderNode) { - return cc.size(0, 0); - } + if (!this._displayRenderNode) + return cc.size(0, 0); return this._displayRenderNode.getContentSize(); }, getBoundingBox:function () { - if (!this._displayRenderNode) { + if (!this._displayRenderNode) return cc.rect(0, 0, 0, 0); - } return this._displayRenderNode.getBoundingBox(); }, getAnchorPoint:function () { - if (!this._displayRenderNode) { + if (!this._displayRenderNode) return cc.p(0, 0); - } return this._displayRenderNode.getAnchorPoint(); }, getAnchorPointInPoints:function () { - if (!this._displayRenderNode) { + if (!this._displayRenderNode) return cc.p(0, 0); - } return this._displayRenderNode.getAnchorPointInPoints(); }, @@ -334,19 +446,20 @@ ccs.DisplayManager = ccs.Class.extend(/** @lends cc.DisplayManager */{ }, release:function () { - this._decoDisplayList = []; + this._decoDisplayList = null; if (this._displayRenderNode) { this._displayRenderNode.removeFromParent(true); this._displayRenderNode = null; } } - }); +/** + * Allocates and initializes a display manager with ccs.Bone. + * @param {ccs.Bone} bone + * @returns {ccs.DisplayManager} + * @deprecated since v3.1, please use new construction instead + */ ccs.DisplayManager.create = function (bone) { - var displayManager = new ccs.DisplayManager(); - if (displayManager && displayManager.init(bone)) { - return displayManager; - } - return null; + return new ccs.DisplayManager(bone); }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/display/CCSkin.js b/extensions/cocostudio/armature/display/CCSkin.js index cbcbb98e1e..933b790e07 100644 --- a/extensions/cocostudio/armature/display/CCSkin.js +++ b/extensions/cocostudio/armature/display/CCSkin.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,50 +24,91 @@ ****************************************************************************/ /** - * Base class for ccs.Skin + * ccs.Bone uses ccs.Skin to displays on screen. * @class * @extends ccs.Sprite * + * @param {String} [fileName] + * @param {cc.Rect} [rect] + * * @property {Object} skinData - The data of the skin * @property {ccs.Bone} bone - The bone of the skin * @property {String} displayName - <@readonly> The displayed name of skin * */ ccs.Skin = ccs.Sprite.extend(/** @lends ccs.Skin# */{ - _skinData:null, - bone:null, - _skinTransform:null, - _displayName:"", - _armature:null, - _className:"Skin", - ctor:function () { + _skinData: null, + bone: null, + _skinTransform: null, + _displayName: "", + _armature: null, + _className: "Skin", + + ctor: function (fileName, rect) { cc.Sprite.prototype.ctor.call(this); this._skinData = null; this.bone = null; this._displayName = ""; - this._skinTransform = cc.AffineTransformIdentity(); + this._skinTransform = cc.affineTransformIdentity(); this._armature = null; + + if (fileName == null || fileName === "") { + ccs.Skin.prototype.init.call(this); + } else { + if(fileName[0] === "#"){ + ccs.Skin.prototype.initWithSpriteFrameName.call(this, fileName.substr(1)); + } else { + ccs.Skin.prototype.initWithFile.call(this, fileName, rect); + } + } }, - initWithSpriteFrameName:function(spriteFrameName){ - var ret = cc.Sprite.prototype.initWithSpriteFrameName.call(this,spriteFrameName); + + /** + * Initializes with sprite frame name + * @param {String} spriteFrameName + * @returns {Boolean} + */ + initWithSpriteFrameName: function (spriteFrameName) { + if(spriteFrameName === "") + return false; + var pFrame = cc.spriteFrameCache.getSpriteFrame(spriteFrameName); + var ret = true; + if(pFrame) + this.initWithSpriteFrame(pFrame); + else{ + cc.log("Can't find CCSpriteFrame with %s. Please check your .plist file", spriteFrameName); + ret = false; + } this._displayName = spriteFrameName; return ret; }, - initWithFile:function(fileName){ - var ret = cc.Sprite.prototype.initWithFile.call(this,fileName); + + /** + * Initializes with texture file name. + * @param {String} fileName + * @param {cc.Rect} rect + * @returns {Boolean} + */ + initWithFile: function (fileName, rect) { + var ret = rect ? cc.Sprite.prototype.initWithFile.call(this, fileName, rect) + : cc.Sprite.prototype.initWithFile.call(this, fileName); this._displayName = fileName; return ret; }, - setSkinData:function (skinData) { - this._skinData = skinData; + /** + * Sets skin data to ccs.Skin. + * @param {ccs.BaseData} skinData + */ + setSkinData: function (skinData) { + this._skinData = skinData; this.setScaleX(skinData.scaleX); this.setScaleY(skinData.scaleY); - this.setRotationX(cc.radiansToDegress(skinData.skewX)); - this.setRotationY(cc.radiansToDegress(-skinData.skewY)); + this.setRotationX(cc.radiansToDegrees(skinData.skewX)); + this.setRotationY(cc.radiansToDegrees(-skinData.skewY)); this.setPosition(skinData.x, skinData.y); - var localTransform = this.nodeToParentTransform(); + var localTransform = this.getNodeToParentTransform ? this.getNodeToParentTransform() : this.nodeToParentTransform(); var skinTransform = this._skinTransform; skinTransform.a = localTransform.a; skinTransform.b = localTransform.b; @@ -77,71 +119,69 @@ ccs.Skin = ccs.Sprite.extend(/** @lends ccs.Skin# */{ this.updateArmatureTransform(); }, - getSkinData:function () { + /** + * Returns skin date of ccs.Skin. + * @returns {ccs.BaseData} + */ + getSkinData: function () { return this._skinData; }, - setBone:function (bone) { - this.bone = bone; + /** + * Updates armature skin's transform with skin transform and bone's transform. + */ + updateArmatureTransform: function () { + this._renderCmd.updateArmatureTransform(); }, - getBone:function () { - return this.bone; + /** + * Returns skin's world transform. + * @returns {cc.AffineTransform} + */ + getNodeToWorldTransform: function(){ + return this._renderCmd.getNodeToWorldTransform(); }, - updateArmatureTransform:function () { - this._transform = cc.AffineTransformConcat(this._skinTransform, this.bone.nodeToArmatureTransform()); - var locTransform = this._transform; - var locArmature = this._armature; - if (locArmature && locArmature.getBatchNode()) { - this._transform = cc.AffineTransformConcat(locTransform, locArmature.nodeToParentTransform()); - } - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - locTransform = this._transform - locTransform.b *= -1; - locTransform.c *= -1; - var tempB = locTransform.b; - locTransform.b = locTransform.c; - locTransform.c = tempB; - } + getNodeToWorldTransformAR: function(){ + return this._renderCmd.getNodeToWorldTransformAR(); }, - /** returns a "local" axis aligned bounding box of the node.
    - * The returned box is relative only to its parent. - * @return {cc.Rect} + + /** + * Sets the bone reference to ccs.Skin. + * @param bone */ - getBoundingBox:function () { - var rect = cc.rect(0, 0, this._contentSize.width, this._contentSize.height); - var transForm = this.nodeToParentTransform(); - return cc.RectApplyAffineTransform(rect, transForm); + setBone: function (bone) { + this.bone = bone; + var armature = this.bone.getArmature(); + if(armature) + this._armature = armature; + }, + + /** + * Returns the bone reference of ccs.Skin. + * @returns {null} + */ + getBone: function () { + return this.bone; }, /** * display name getter * @returns {String} */ - getDisplayName:function(){ + getDisplayName: function () { return this._displayName; }, - nodeToWorldTransform: function () { - return cc.AffineTransformConcat(this._transform, this.bone.getArmature().nodeToWorldTransform()); - }, - - - nodeToWorldTransformAR: function () { - var displayTransform = this._transform; - var anchorPoint = this._anchorPointInPoints; - - anchorPoint = cc.PointApplyAffineTransform(anchorPoint, displayTransform); - displayTransform.tx = anchorPoint.x; - displayTransform.ty = anchorPoint.y; - - return cc.AffineTransformConcat(displayTransform, this.bone.getArmature().nodeToWorldTransform()); + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new ccs.Skin.CanvasRenderCmd(this); + else + return new ccs.Skin.WebGLRenderCmd(this); } }); -ccs.Skin.prototype.nodeToParentTransform = cc.Node.prototype._nodeToParentTransformForWebGL; -window._p = ccs.Skin.prototype; +var _p = ccs.Skin.prototype; // Extended properties /** @expose */ @@ -151,42 +191,25 @@ cc.defineGetterSetter(_p, "skinData", _p.getSkinData, _p.setSkinData); _p.displayName; cc.defineGetterSetter(_p, "displayName", _p.getDisplayName); -delete window._p; +_p = null; /** * allocates and initializes a skin. - * @param {String} fileName - * @param {cc.Rect} rect + * @param {String} [fileName] fileName or sprite frame name + * @param {cc.Rect} [rect] * @returns {ccs.Skin} - * @example - * // example - * var skin = ccs.Skin.create("res/test.png",cc.rect(0,0,50,50)); + * @deprecated since v3.1, please use new construction instead */ ccs.Skin.create = function (fileName, rect) { - var argnum = arguments.length; - var sprite = new ccs.Skin(); - if (argnum === 0) { - if (sprite.init()) - return sprite; - } else { - if (sprite && sprite.initWithFile(fileName, rect)) - return sprite; - } - return null; + return new ccs.Skin(fileName, rect); }; /** * allocates and initializes a skin. - * @param {String} pszSpriteFrameName + * @param {String} spriteFrameName * @returns {ccs.Skin} - * @example - * // example - * var skin = ccs.Skin.createWithSpriteFrameName("test.png"); + * @deprecated since v3.1, please use new construction instead */ -ccs.Skin.createWithSpriteFrameName = function (pszSpriteFrameName) { - var skin = new ccs.Skin(); - if (skin && skin.initWithSpriteFrameName(pszSpriteFrameName)) { - return skin; - } - return null; +ccs.Skin.createWithSpriteFrameName = function (spriteFrameName) { + return new ccs.Skin("#" + spriteFrameName); }; diff --git a/extensions/cocostudio/armature/display/CCSkinCanvasRenderCmd.js b/extensions/cocostudio/armature/display/CCSkinCanvasRenderCmd.js new file mode 100644 index 0000000000..83504f8b14 --- /dev/null +++ b/extensions/cocostudio/armature/display/CCSkinCanvasRenderCmd.js @@ -0,0 +1,58 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + ccs.Skin.RenderCmd = { + updateArmatureTransform: function () { + var node = this._node; + this._transform = cc.affineTransformConcat( + node._skinTransform, + node.bone.getNodeToArmatureTransform() + ); + this._dirtyFlag = this._dirtyFlag & cc.Node._dirtyFlags.transformDirty ^ this._dirtyFlag; + }, + + getNodeToWorldTransform: function () { + return cc.affineTransformConcat(this._transform, this._node.bone.getArmature().getNodeToWorldTransform()); + }, + + getNodeToWorldTransformAR: function () { + var displayTransform = this._transform, node = this._node; + this._anchorPointInPoints = cc.pointApplyAffineTransform(this._anchorPointInPoints, displayTransform); + displayTransform.tx = this._anchorPointInPoints.x; + displayTransform.ty = this._anchorPointInPoints.y; + return cc.affineTransformConcat(displayTransform, node.bone.getArmature().getNodeToWorldTransform()); + } + }; + + ccs.Skin.CanvasRenderCmd = function(renderable){ + cc.Sprite.CanvasRenderCmd.call(this, renderable); + this._needDraw = true; + }; + + var proto = ccs.Skin.CanvasRenderCmd.prototype = Object.create(cc.Sprite.CanvasRenderCmd.prototype); + cc.inject(ccs.Skin.RenderCmd, proto); + proto.constructor = ccs.Skin.CanvasRenderCmd; +})(); diff --git a/extensions/cocostudio/armature/display/CCSkinWebGLRenderCmd.js b/extensions/cocostudio/armature/display/CCSkinWebGLRenderCmd.js new file mode 100644 index 0000000000..f541aa1058 --- /dev/null +++ b/extensions/cocostudio/armature/display/CCSkinWebGLRenderCmd.js @@ -0,0 +1,146 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + ccs.Skin.WebGLRenderCmd = function(renderable){ + cc.Sprite.WebGLRenderCmd.call(this, renderable); + }; + + var proto = ccs.Skin.WebGLRenderCmd.prototype = Object.create(cc.Sprite.WebGLRenderCmd.prototype); + cc.inject(ccs.Skin.RenderCmd, proto); + proto.constructor = ccs.Skin.WebGLRenderCmd; + + proto.updateTransform = function(){ + var node = this._node; + var locQuad = this._quad; + // If it is not visible, or one of its ancestors is not visible, then do nothing: + if( !node._visible) + locQuad.br.vertices = locQuad.tl.vertices = locQuad.tr.vertices = locQuad.bl.vertices = {x: 0, y: 0, z: 0}; + else { + // + // calculate the Quad based on the Affine Matrix + // + var transform = this.getNodeToParentTransform(); //this._transform; + var size = node._rect; + + var x1 = node._offsetPosition.x, y1 = node._offsetPosition.y; + + var x2 = x1 + size.width, y2 = y1 + size.height; + var x = transform.tx, y = transform.ty; + + var cr = transform.a, sr = transform.b; + var cr2 = transform.d, sr2 = -transform.c; + var ax = x1 * cr - y1 * sr2 + x; + var ay = x1 * sr + y1 * cr2 + y; + + var bx = x2 * cr - y1 * sr2 + x; + var by = x2 * sr + y1 * cr2 + y; + + var cx = x2 * cr - y2 * sr2 + x; + var cy = x2 * sr + y2 * cr2 + y; + + var dx = x1 * cr - y2 * sr2 + x; + var dy = x1 * sr + y2 * cr2 + y; + + var locVertexZ = node._vertexZ; + if(!cc.SPRITEBATCHNODE_RENDER_SUBPIXEL) { + ax = 0 | ax; + ay = 0 | ay; + bx = 0 | bx; + by = 0 | by; + cx = 0 | cx; + cy = 0 | cy; + dx = 0 | dx; + dy = 0 | dy; + } + this.SET_VERTEX3F(locQuad.bl.vertices,ax, ay,locVertexZ); + this.SET_VERTEX3F(locQuad.br.vertices,bx, by,locVertexZ); + this.SET_VERTEX3F(locQuad.tl.vertices,dx, dy,locVertexZ); + this.SET_VERTEX3F(locQuad.tr.vertices,cx, cy,locVertexZ); + } + + // MARMALADE CHANGE: ADDED CHECK FOR nullptr, TO PERMIT SPRITES WITH NO BATCH NODE / TEXTURE ATLAS + if (node.textureAtlas) + node.textureAtlas.updateQuad(locQuad, node.textureAtlas.getTotalQuads()); + this._quadDirty = true; + }; + + proto.SET_VERTEX3F = function(_v_, _x_, _y_, _z_){ + (_v_).x = (_x_); + (_v_).y = (_y_); + (_v_).z = (_z_); + }; + + proto.rendering = function(ctx){ + var node = this._node; + if (!node._textureLoaded) + return; + + var gl = ctx || cc._renderContext, locTexture = node._texture; + if (locTexture && locTexture._textureLoaded) { + this._shaderProgram.use(); + this._shaderProgram.setUniformForModelViewAndProjectionMatrixWithMat4(); + + cc.glBlendFunc(node._blendFunc.src, node._blendFunc.dst); + //optimize performance for javascript + cc.glBindTexture2DN(0, locTexture); // = cc.glBindTexture2D(locTexture); + cc.glEnableVertexAttribs(cc.VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); + + gl.bindBuffer(gl.ARRAY_BUFFER, this._quadWebBuffer); + if (this._quadDirty) { + gl.bufferData(gl.ARRAY_BUFFER, this._quad.arrayBuffer, gl.DYNAMIC_DRAW); + this._quadDirty = false; + } + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0); //cc.VERTEX_ATTRIB_POSITION + gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, 24, 12); //cc.VERTEX_ATTRIB_COLOR + gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 24, 16); //cc.VERTEX_ATTRIB_TEX_COORDS + + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + } + + cc.g_NumberOfDraws++; + if (cc.SPRITE_DEBUG_DRAW === 0 && !node._showNode) + return; + + if (cc.SPRITE_DEBUG_DRAW === 1 || node._showNode) { + // draw bounding box + var locQuad = this._quad; + var verticesG1 = [ + cc.p(locQuad.tl.vertices.x, locQuad.tl.vertices.y), + cc.p(locQuad.bl.vertices.x, locQuad.bl.vertices.y), + cc.p(locQuad.br.vertices.x, locQuad.br.vertices.y), + cc.p(locQuad.tr.vertices.x, locQuad.tr.vertices.y) + ]; + cc._drawingUtil.drawPoly(verticesG1, 4, true); + } else if (cc.SPRITE_DEBUG_DRAW === 2) { + // draw texture box + var drawRectG2 = node.getTextureRect(); + var offsetPixG2 = node.getOffsetPosition(); + var verticesG2 = [cc.p(offsetPixG2.x, offsetPixG2.y), cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y), + cc.p(offsetPixG2.x + drawRectG2.width, offsetPixG2.y + drawRectG2.height), cc.p(offsetPixG2.x, offsetPixG2.y + drawRectG2.height)]; + cc._drawingUtil.drawPoly(verticesG2, 4, true); + } // CC_SPRITE_DEBUG_DRAW + }; +})(); \ No newline at end of file diff --git a/extensions/cocostudio/armature/physics/CCColliderDetector.js b/extensions/cocostudio/armature/physics/CCColliderDetector.js index 1451482c34..dccbe5882d 100644 --- a/extensions/cocostudio/armature/physics/CCColliderDetector.js +++ b/extensions/cocostudio/armature/physics/CCColliderDetector.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -26,6 +27,7 @@ * @ignore */ ccs.PT_RATIO = 32; + /** * Base class for ccs.ColliderFilter * @class @@ -34,15 +36,30 @@ ccs.PT_RATIO = 32; ccs.ColliderFilter = ccs.Class.extend(/** @lends ccs.ColliderFilter# */{ _collisionType: 0, _group: 0, + _categoryBits: 0, + _groupIndex: 0, + _maskBits: 0, + ctor: function (collisionType, group) { this._collisionType = collisionType || 0; this._group = group || 0; }, + updateShape: function (shape) { - shape.collision_type = this._collisionType; - shape.group = this._group; + if(shape instanceof cp.Shape){ + shape.collision_type = this._collisionType; + shape.group = this._group; + }else if(shape instanceof Box2D.b2FilterData){ + var filter = new Box2D.b2FilterData(); + filter.categoryBits = this._categoryBits; + filter.groupIndex = this._groupIndex; + filter.maskBits = this._maskBits; + + shape.SetFilterData(filter); + } } }); + /** * Base class for ccs.ColliderBody * @class @@ -56,13 +73,13 @@ ccs.ColliderFilter = ccs.Class.extend(/** @lends ccs.ColliderFilter# */{ ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{ shape: null, coutourData: null, - colliderFilter:null, - _calculatedVertexList:null, + colliderFilter: null, + _calculatedVertexList: null, ctor: function (contourData) { this.shape = null; this.coutourData = contourData; this.colliderFilter = new ccs.ColliderFilter(); - if(ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX){ + if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { this._calculatedVertexList = []; } }, @@ -76,19 +93,27 @@ ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{ }, /** - * contourData setter - * @param {ccs.ContourData} contourData + * colliderFilter setter + * @param {ccs.ColliderFilter} colliderFilter */ - setContourData: function (contourData) { - this.coutourData = contourData; + setColliderFilter: function (colliderFilter) { + this.colliderFilter = colliderFilter; }, /** - * shape setter - * @return {ccs.Shape} + * get calculated vertex list + * @returns {Array} */ - getShape: function () { - return this.shape; + getCalculatedVertexList: function () { + return this._calculatedVertexList; + }, + + setB2Fixture: function(fixture){ + this._fixture = fixture; + }, + + getB2Fixture: function(){ + return this._fixture; }, /** @@ -100,27 +125,27 @@ ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{ }, /** - * colliderFilter getter - * @returns {ccs.ColliderFilter} + * shape setter + * @return {ccs.Shape} */ - getColliderFilter: function () { - return this.colliderFilter; + getShape: function () { + return this.shape; }, /** - * colliderFilter setter - * @param {ccs.ColliderFilter} colliderFilter + * contourData setter + * @param {ccs.ContourData} contourData */ - setColliderFilter: function (colliderFilter) { - this.colliderFilter = colliderFilter; + setContourData: function (contourData) { + this.coutourData = contourData; }, /** - * get calculated vertex list - * @returns {Array} + * colliderFilter getter + * @returns {ccs.ColliderFilter} */ - getCalculatedVertexList:function(){ - return this._calculatedVertexList; + getColliderFilter: function () { + return this.colliderFilter; } }); @@ -129,6 +154,8 @@ ccs.ColliderBody = ccs.Class.extend(/** @lends ccs.ColliderBody# */{ * @class * @extends ccs.Class * + * @param {ccs.Bone} [bone] + * * @property {ccs.ColliderFilter} colliderFilter - The collider filter of the collider detector * @property {Boolean} active - Indicate whether the collider detector is active * @property {Object} body - The collider body @@ -139,15 +166,19 @@ ccs.ColliderDetector = ccs.Class.extend(/** @lends ccs.ColliderDetector# */{ _body: null, _active: false, _filter: null, - ctor: function () { + helpPoint: cc.p(0, 0), + + ctor: function (bone) { this._colliderBodyList = []; this._bone = null; this._body = null; this._active = false; this._filter = null; + + ccs.ColliderDetector.prototype.init.call(this, bone); }, init: function (bone) { - this._colliderBodyList = []; + this._colliderBodyList.length = 0; if (bone) this._bone = bone; this._filter = new ccs.ColliderFilter(); @@ -161,6 +192,7 @@ ccs.ColliderDetector = ccs.Class.extend(/** @lends ccs.ColliderDetector# */{ addContourData: function (contourData) { var colliderBody = new ccs.ColliderBody(contourData); this._colliderBodyList.push(colliderBody); + if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { var calculatedVertexList = colliderBody.getCalculatedVertexList(); var vertexList = contourData.vertexList; @@ -186,51 +218,29 @@ ccs.ColliderDetector = ccs.Class.extend(/** @lends ccs.ColliderDetector# */{ * @param contourData */ removeContourData: function (contourData) { - var locColliderBodyList = this._colliderBodyList; - for (var i = 0; i < locColliderBodyList.length; i++) { - if(locColliderBodyList[i].getContourData()==contourData){ - locColliderBodyList.splice(i, 1); - return; - } + var eraseList = [], i, locBodyList = this._colliderBodyList; + for (i = 0; i < locBodyList.length; i++) { + var body = locBodyList[i]; + if (body && body.getContourData() === contourData) + eraseList.push(body); } + + for (i=0; igetB2Fixture()->GetShape(); shape = colliderBody.getShape(); } + var vs = contourData.vertexList; var cvs = colliderBody.getCalculatedVertexList(); + for (var j = 0; j < vs.length; j++) { locHelpPoint.x = vs[j].x; locHelpPoint.y = vs[j].y; - locHelpPoint = cc.PointApplyAffineTransform(locHelpPoint, t); - if (shape) { - shape.verts[j * 2] = locHelpPoint.x; - shape.verts[j * 2 + 1] = locHelpPoint.y; - } + locHelpPoint = cc.pointApplyAffineTransform(locHelpPoint, t); + if (ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX) { - var v = cc.p(0, 0); + var v = cc.p(0, 0); v.x = locHelpPoint.x; v.y = locHelpPoint.y; cvs[j] = v; } + + if (shape) { + shape.verts[j * 2] = locHelpPoint.x; + shape.verts[j * 2 + 1] = locHelpPoint.y; + } } if (shape) { - for (var j = 0; j < vs.length; j++) { + for (var j = 0; j < vs.length; j++) { var b = shape.verts[(j + 1) % shape.verts.length]; var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[j]))); - shape.axes[j].n = n; - shape.axes[j].d = cp.v.dot(n, shape.verts[j]); + + if(shape.planes){ + shape.planes[j].n = n; + shape.planes[j].d = cp.v.dot(n, shape.verts[j]); + } +// var b = shape.verts[(i + 1) % shape.numVerts]; +// var n = cp.v.normalize(cp.v.perp(cp.v.sub(b, shape.verts[i]))); +// +// shape.planes[i].n = n; +// shape.planes[i].d = cp.v.dot(n, shape.verts[i]); } } } }, - getBody: function () { - return this._body; - }, + setBody: function (body) { this._body = body; - var colliderBody; - for (var i = 0; i < this._colliderBodyList.length; i++) { - colliderBody = this._colliderBodyList[i]; - var contourData = colliderBody.getContourData(); - var verts = []; + var colliderBody, locBodyList = this._colliderBodyList; + for (var i = 0; i < locBodyList.length; i++) { + colliderBody = locBodyList[i]; + var contourData = colliderBody.getContourData(), verts = []; var vs = contourData.vertexList; - for (var i = 0; i < vs.length; i++) { - var v = vs[i]; + for (var j = 0; j < vs.length; j++) { + var v = vs[j]; verts.push(v.x); verts.push(v.y); } var shape = new cp.PolyShape(this._body, verts, cp.vzero); shape.sensor = true; shape.data = this._bone; - if (this._active){ + if (this._active) this._body.space.addShape(shape); - } colliderBody.setShape(shape); colliderBody.getColliderFilter().updateShape(shape); } + }, + + getBody: function () { + return this._body; } }); -window._p = ccs.ColliderDetector.prototype; +var _p = ccs.ColliderDetector.prototype; // Extended properties /** @expose */ @@ -340,12 +390,8 @@ cc.defineGetterSetter(_p, "active", _p.getActive, _p.setActive); _p.body; cc.defineGetterSetter(_p, "body", _p.getBody, _p.setBody); -delete window._p; +_p = null; ccs.ColliderDetector.create = function (bone) { - var colliderDetector = new ccs.ColliderDetector(); - if (colliderDetector && colliderDetector.init(bone)) { - return colliderDetector; - } - return null; + return new ccs.ColliderDetector(bone); }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/utils/CCArmatureDataManager.js b/extensions/cocostudio/armature/utils/CCArmatureDataManager.js index 25be4680d6..89f06fb2d0 100644 --- a/extensions/cocostudio/armature/utils/CCArmatureDataManager.js +++ b/extensions/cocostudio/armature/utils/CCArmatureDataManager.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * RelativeData + * RelativeData uses to save plist files, armature files, animations and textures for armature data manager. * @constructor */ ccs.RelativeData = function(){ @@ -34,108 +35,97 @@ ccs.RelativeData = function(){ }; /** - * @namespace Format and manage armature configuration and armature animation + * ccs.armatureDataManager is a singleton object which format and manage armature configuration and armature animation + * @class + * @name ccs.armatureDataManager */ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ _animationDatas: {}, - _armarureDatas: {}, + _armatureDatas: {}, _textureDatas: {}, _autoLoadSpriteFile: false, _relativeDatas: {}, + s_sharedArmatureDataManager: null, + /** - * remove armature cache data by configFilePath + * Removes armature cache data by configFilePath * @param {String} configFilePath */ removeArmatureFileInfo:function(configFilePath){ var data = this.getRelativeData(configFilePath); - for (var i = 0; i < data.armatures.length; i++) { - var obj = data.armatures[i]; - this.removeArmatureData(obj); - } - for (var i = 0; i < data.animations.length; i++) { - var obj = data.animations[i]; - this.removeAnimationData(obj); - } - for (var i = 0; i < data.textures.length; i++) { - var obj = data.textures[i]; - this.removeTextureData(obj); + if(data){ + var i, obj; + for (i = 0; i < data.armatures.length; i++) { + obj = data.armatures[i]; + this.removeArmatureData(obj); + } + for ( i = 0; i < data.animations.length; i++) { + obj = data.animations[i]; + this.removeAnimationData(obj); + } + for ( i = 0; i < data.textures.length; i++) { + obj = data.textures[i]; + this.removeTextureData(obj); + } + for ( i = 0; i < data.plistFiles.length; i++) { + obj = data.plistFiles[i]; + cc.spriteFrameCache.removeSpriteFramesFromFile(obj); + } + delete this._relativeDatas[configFilePath]; + ccs.dataReaderHelper.removeConfigFile(configFilePath); } - for (var i = 0; i < data.plistFiles.length; i++) { - var obj = data.plistFiles[i]; - cc.spriteFrameCache.removeSpriteFramesFromFile(obj); - } - delete this._relativeDatas[configFilePath]; - ccs.dataReaderHelper.removeConfigFile(configFilePath); }, /** - * Add armature data + * Adds armature data * @param {string} id The id of the armature data * @param {ccs.ArmatureData} armatureData */ addArmatureData:function (id, armatureData, configFilePath) { - if (this._armarureDatas) { - var data = this.getRelativeData(configFilePath); + var data = this.getRelativeData(configFilePath); + if (data){ data.armatures.push(id); - this._armarureDatas[id] = armatureData; } + this._armatureDatas[id] = armatureData; }, /** - * remove armature data - * @param {string} id - */ - removeArmatureData:function(id){ - if (this._armarureDatas[id]) - delete this._armarureDatas[id]; - }, - - /** - * get armatureData by id + * Gets armatureData by id * @param {String} id * @return {ccs.ArmatureData} */ getArmatureData:function (id) { var armatureData = null; - if (this._armarureDatas) { - armatureData = this._armarureDatas[id]; + if (this._armatureDatas) { + armatureData = this._armatureDatas[id]; } return armatureData; }, /** - * get armatureDatas - * @return {Object} + * Removes armature data from armature data manager. + * @param {string} id */ - getArmatureDatas:function () { - return this._armarureDatas; + removeArmatureData:function(id){ + if (this._armatureDatas[id]) + delete this._armatureDatas[id]; }, /** - * add animation data + * Adds animation data to armature data manager. * @param {String} id * @param {ccs.AnimationData} animationData */ addAnimationData:function (id, animationData, configFilePath) { - if (this._animationDatas) { - var data = this.getRelativeData(configFilePath); + var data = this.getRelativeData(configFilePath); + if(data) data.animations.push(id); - this._animationDatas[id] = animationData; - } - }, - - /** - * remove animation data - * @param {string} id - */ - removeAnimationData:function(id){ - if (this._animationDatas[id]) - delete this._animationDatas[id]; + this._animationDatas[id] = animationData; }, /** - * get animationData by id + * Gets animationData by id * @param {String} id * @return {ccs.AnimationData} */ @@ -148,37 +138,29 @@ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ }, /** - * get animationDatas - * @return {Object} + * Removes animation data + * @param {string} id */ - getAnimationDatas:function () { - return this._animationDatas; + removeAnimationData:function(id){ + if (this._animationDatas[id]) + delete this._animationDatas[id]; }, /** - * add texture data + * Adds texture data to Armature data manager. * @param {String} id * @param {ccs.TextureData} textureData */ addTextureData:function (id, textureData, configFilePath) { - if (this._textureDatas) { - var data = this.getRelativeData(configFilePath); + var data = this.getRelativeData(configFilePath); + if (data) { data.textures.push(id); - this._textureDatas[id] = textureData; } + this._textureDatas[id] = textureData; }, /** - * remove texture data - * @param {string} id - */ - removeTextureData:function(id){ - if (this._textureDatas[id]) - delete this._textureDatas[id]; - }, - - /** - * get textureData by id + * Gets textureData by id * @param {String} id * @return {ccs.TextureData} */ @@ -191,15 +173,16 @@ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ }, /** - * get textureDatas - * @return {Object} + * Removes texture data by id + * @param {string} id */ - getTextureDatas:function () { - return this._textureDatas; + removeTextureData:function(id){ + if (this._textureDatas[id]) + delete this._textureDatas[id]; }, /** - * Add ArmatureFileInfo, it is managed by CCArmatureDataManager. + * Adds ArmatureFileInfo, it is managed by CCArmatureDataManager. * @param {String} imagePath * @param {String} plistPath * @param {String} configFilePath @@ -211,68 +194,108 @@ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ */ addArmatureFileInfo:function (/*imagePath, plistPath, configFilePath*/) { var imagePath, plistPath, configFilePath; - var isLoadSpriteFrame = false; - if (arguments.length == 1) { - configFilePath = arguments[0]; - isLoadSpriteFrame = true; - this.addRelativeData(configFilePath); - } else if (arguments.length == 3){ - imagePath = arguments[0]; - plistPath = arguments[1]; - configFilePath = arguments[2]; - this.addRelativeData(configFilePath); - this.addSpriteFrameFromFile(plistPath, imagePath, configFilePath); + switch(arguments.length){ + case 1: + configFilePath = arguments[0]; + + this.addRelativeData(configFilePath); + + this._autoLoadSpriteFile = true; + ccs.dataReaderHelper.addDataFromFile(configFilePath); + break; + case 3: + imagePath = arguments[0]; + plistPath = arguments[1]; + configFilePath = arguments[2]; + + this.addRelativeData(configFilePath); + + this._autoLoadSpriteFile = false; + ccs.dataReaderHelper.addDataFromFile(configFilePath); + this.addSpriteFrameFromFile(plistPath, imagePath); } - ccs.dataReaderHelper.addDataFromFile(configFilePath,isLoadSpriteFrame); }, /** - * Add ArmatureFileInfo, it is managed by CCArmatureDataManager. + * Adds ArmatureFileInfo, it is managed by CCArmatureDataManager. * @param {String} imagePath * @param {String} plistPath * @param {String} configFilePath + * @param {Function} selector * @param {Object} target - * @param {Function} configFilePath */ - addArmatureFileInfoAsync:function (/*imagePath, plistPath, configFilePath, target, selector*/) { + addArmatureFileInfoAsync:function (/*imagePath, plistPath, configFilePath, selector, target*/) { var imagePath, plistPath, configFilePath, target, selector; - var isLoadSpriteFrame = false; - if (arguments.length == 3) { - configFilePath = arguments[0]; - selector = arguments[1]; - target = arguments[2]; - isLoadSpriteFrame = true; - this.addRelativeData(configFilePath); - } else if (arguments.length == 5){ - imagePath = arguments[0]; - plistPath = arguments[1]; - configFilePath = arguments[2]; - selector = arguments[3]; - target = arguments[4]; - this.addRelativeData(configFilePath); - this.addSpriteFrameFromFile(plistPath, imagePath, configFilePath); - } - ccs.dataReaderHelper.addDataFromFileAsync(configFilePath,target,selector,isLoadSpriteFrame); + switch(arguments.length){ + case 3: + configFilePath = arguments[0]; + target = arguments[2]; + selector = arguments[1]; + this.addRelativeData(configFilePath); + this._autoLoadSpriteFile = true; + ccs.dataReaderHelper.addDataFromFileAsync("", "", configFilePath, selector,target); + break; + case 5: + imagePath = arguments[0]; + plistPath = arguments[1]; + configFilePath = arguments[2]; + target = arguments[4]; + selector = arguments[3]; + this.addRelativeData(configFilePath); + this._autoLoadSpriteFile = false; + ccs.dataReaderHelper.addDataFromFileAsync(imagePath, plistPath, configFilePath, selector, target); + this.addSpriteFrameFromFile(plistPath, imagePath); + } }, /** * Add sprite frame to CCSpriteFrameCache, it will save display name and it's relative image name * @param {String} plistPath * @param {String} imagePath + * @param {String} configFilePath */ addSpriteFrameFromFile:function (plistPath, imagePath, configFilePath) { var data = this.getRelativeData(configFilePath); - data.plistFiles.push(plistPath); + if(data) + data.plistFiles.push(plistPath); ccs.spriteFrameCacheHelper.addSpriteFrameFromFile(plistPath, imagePath); }, + /** + * Returns whether or not need auto load sprite file + * @returns {boolean} + */ isAutoLoadSpriteFile:function(){ return this._autoLoadSpriteFile; }, /** - * add RelativeData + * Returns armature Data of Armature data manager. + * @return {Object} + */ + getArmatureDatas:function () { + return this._armatureDatas; + }, + + /** + * Returns animation data of Armature data manager. + * @return {Object} + */ + getAnimationDatas:function () { + return this._animationDatas; + }, + + /** + * Returns texture data of Armature data manager. + * @return {Object} + */ + getTextureDatas:function () { + return this._textureDatas; + }, + + /** + * Adds Relative data of Armature data manager. * @param {String} configFilePath */ addRelativeData: function (configFilePath) { @@ -281,7 +304,7 @@ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ }, /** - * get RelativeData + * Gets RelativeData of Armature data manager. * @param {String} configFilePath * @returns {ccs.RelativeData} */ @@ -289,14 +312,14 @@ ccs.armatureDataManager = /** @lends ccs.armatureDataManager# */{ return this._relativeDatas[configFilePath]; }, - /** - * Clear data - */ - clear: function() { + /** + * Clear data + */ + clear: function() { this._animationDatas = {}; - this._armarureDatas = {}; + this._armatureDatas = {}; this._textureDatas = {}; ccs.spriteFrameCacheHelper.clear(); ccs.dataReaderHelper.clear(); - } + } }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/utils/CCArmatureDefine.js b/extensions/cocostudio/armature/utils/CCArmatureDefine.js index de82c45931..a7db1b9203 100644 --- a/extensions/cocostudio/armature/utils/CCArmatureDefine.js +++ b/extensions/cocostudio/armature/utils/CCArmatureDefine.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -35,6 +36,10 @@ ccs.AUTO_ADD_SPRITE_FRAME_NAME_PREFIX = false; ccs.ENABLE_PHYSICS_CHIPMUNK_DETECT = false; ccs.ENABLE_PHYSICS_SAVE_CALCULATED_VERTEX = false; +/** + * Returns the version of Armature. + * @returns {string} + */ ccs.armatureVersion = function(){ return "v1.1.0.0"; }; diff --git a/extensions/cocostudio/armature/utils/CCDataReaderHelper.js b/extensions/cocostudio/armature/utils/CCDataReaderHelper.js index e072c1cc2d..e23fad1aa4 100644 --- a/extensions/cocostudio/armature/utils/CCDataReaderHelper.js +++ b/extensions/cocostudio/armature/utils/CCDataReaderHelper.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -29,7 +30,6 @@ ccs.CONST_VERSION = "version"; ccs.CONST_VERSION_2_0 = 2.0; ccs.CONST_VERSION_COMBINED = 0.3; -ccs.CONST_SKELETON = "skeleton"; ccs.CONST_ARMATURES = "armatures"; ccs.CONST_ARMATURE = "armature"; ccs.CONST_BONE = "b"; @@ -43,6 +43,8 @@ ccs.CONST_FRAME = "f"; ccs.CONST_TEXTURE_ATLAS = "TextureAtlas"; ccs.CONST_SUB_TEXTURE = "SubTexture"; +ccs.CONST_SKELETON = "skeleton"; + ccs.CONST_A_NAME = "name"; ccs.CONST_A_DURATION = "dr"; ccs.CONST_A_FRAME_INDEX = "fi"; @@ -53,8 +55,6 @@ ccs.CONST_A_MOVEMENT_SCALE = "sc"; ccs.CONST_A_MOVEMENT_DELAY = "dl"; ccs.CONST_A_DISPLAY_INDEX = "dI"; -ccs.CONST_A_VERT = "vert"; -ccs.CONST_A_FRAG = "frag"; ccs.CONST_A_PLIST = "plist"; ccs.CONST_A_PARENT = "parent"; @@ -67,14 +67,11 @@ ccs.CONST_A_EVENT = "evt"; ccs.CONST_A_SOUND = "sd"; ccs.CONST_A_SOUND_EFFECT = "sdE"; ccs.CONST_A_TWEEN_EASING = "twE"; -ccs.CONST_A_TWEEN_ROTATION = "twR"; ccs.CONST_A_EASING_PARAM = "twEP"; +ccs.CONST_A_TWEEN_ROTATE = "twR"; ccs.CONST_A_IS_ARMATURE = "isArmature"; ccs.CONST_A_DISPLAY_TYPE = "displayType"; ccs.CONST_A_MOVEMENT = "mov"; -ccs.CONST_A_BLEND_TYPE = "bd"; -ccs.CONST_A_BLEND_SRC = "bd_src"; -ccs.CONST_A_BLEND_DST = "bd_dst"; ccs.CONST_A_X = "x"; ccs.CONST_A_Y = "y"; @@ -90,6 +87,10 @@ ccs.CONST_A_PIVOT_Y = "pY"; ccs.CONST_A_COCOS2D_PIVOT_X = "cocos2d_pX"; ccs.CONST_A_COCOS2D_PIVOT_Y = "cocos2d_pY"; +ccs.CONST_A_BLEND_TYPE = "bd"; +ccs.CONST_A_BLEND_SRC = "bd_src"; +ccs.CONST_A_BLEND_DST = "bd_dst"; + ccs.CONST_A_ALPHA = "a"; ccs.CONST_A_RED = "r"; ccs.CONST_A_GREEN = "g"; @@ -100,20 +101,14 @@ ccs.CONST_A_GREEN_OFFSET = "gM"; ccs.CONST_A_BLUE_OFFSET = "bM"; ccs.CONST_A_COLOR_TRANSFORM = "colorTransform"; ccs.CONST_A_TWEEN_FRAME = "tweenFrame"; -ccs.CONST_A_ROTATION = "rotation"; -ccs.CONST_A_USE_COLOR_INFO = "uci"; ccs.CONST_CONTOUR = "con"; ccs.CONST_CONTOUR_VERTEX = "con_vt"; -ccs.CONST_MOVEMENT_EVENT_FRAME = "movementEventFrame"; -ccs.CONST_SOUND_FRAME = "soundFrame"; - ccs.CONST_FL_NAN = "NaN"; ccs.CONST_FRAME_DATA = "frame_data"; ccs.CONST_MOVEMENT_BONE_DATA = "mov_bone_data"; -ccs.CONST_MOVEMENT_FRAME_DATA = "mov_frame_data"; ccs.CONST_MOVEMENT_DATA = "mov_data"; ccs.CONST_ANIMATION_DATA = "animation_data"; ccs.CONST_DISPLAY_DATA = "display_data"; @@ -143,16 +138,28 @@ ccs.DataInfo = function () { }; /** - * @namespace CocoStudio data reader helper + * ccs.dataReaderHelper is a singleton object for reading CocoStudio data + * @class + * @name ccs.dataReaderHelper */ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ + ConfigType: { + DragonBone_XML: 0, + CocoStudio_JSON: 1, + CocoStudio_Binary: 2 + }, + _configFileList: [], _flashToolVersion: ccs.CONST_VERSION_2_0, - _cocoStudioVersion: ccs.CONST_VERSION_COMBINED, +// _cocoStudioVersion: ccs.CONST_VERSION_COMBINED, _positionReadScale: 1, _asyncRefCount: 0, _asyncRefTotalCount: 0, + _dataQueue: null, + + //LoadData don't need + setPositionReadScale: function (scale) { this._positionReadScale = scale; }, @@ -161,125 +168,147 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return this._positionReadScale; }, - clear: function () { - this._configFileList = []; - this._asyncRefCount = 0; - this._asyncRefTotalCount = 0; - }, - - addDataFromFile: function (filePath, isLoadSpriteFrame) { - if (this._configFileList.indexOf(filePath) != -1) { + /** + * Add armature data from file. + * @param {String} filePath + */ + addDataFromFile: function (filePath) { + /* + * Check if file is already added to ArmatureDataManager, if then return. + */ + if (this._configFileList.indexOf(filePath) !== -1) return; - } this._configFileList.push(filePath); - this._initBaseFilePath(filePath); + //! find the base file path + var basefilePath = this._initBaseFilePath(filePath); + + // Read content from file + // Here the reader into the next process var str = cc.path.extname(filePath).toLowerCase(); var dataInfo = new ccs.DataInfo(); dataInfo.filename = filePath; - dataInfo.basefilePath = this._initBaseFilePath(filePath); - if (str == ".xml") { - this.addDataFromXML(filePath, dataInfo); - } - else if (str == ".json" || str == ".exportjson") { - this.addDataFromJson(filePath, dataInfo, isLoadSpriteFrame); - } + dataInfo.basefilePath = basefilePath; + if (str === ".xml") + ccs.dataReaderHelper.addDataFromXML(filePath, dataInfo); + else if (str === ".json" || str === ".exportjson") + ccs.dataReaderHelper.addDataFromJson(filePath, dataInfo); + else if(str === ".csb") + ccs.dataReaderHelper.addDataFromBinaryCache(filePath, dataInfo); }, - addDataFromFileAsync: function (filePath, target, selector, isLoadSpriteFrame) { - if (this._configFileList.indexOf(filePath) != -1) { + /** + * Adds data from file with Async. + * @param {String} imagePath + * @param {String} plistPath + * @param {String} filePath + * @param {function} selector + * @param {Object} [target] + */ + addDataFromFileAsync: function (imagePath, plistPath, filePath, selector, target) { + /* + * Check if file is already added to ArmatureDataManager, if then return. + */ + if (this._configFileList.indexOf(filePath) !== -1) { if (target && selector) { - if (this._asyncRefTotalCount == 0 && this._asyncRefCount == 0) - this._asyncCallBack(target, selector, 1); + if (this._asyncRefTotalCount === 0 && this._asyncRefCount === 0) + this._asyncCallBack(selector,target, 1); else - this._asyncCallBack(target, selector, (this._asyncRefTotalCount - this._asyncRefCount) / this._asyncRefTotalCount); + this._asyncCallBack(selector, target, (this._asyncRefTotalCount - this._asyncRefCount) / this._asyncRefTotalCount); } return; } +// this._configFileList.push(filePath); + + //! find the base file path +// var basefilePath = this._initBaseFilePath(filePath); + this._asyncRefTotalCount++; this._asyncRefCount++; var self = this; var fun = function () { - self.addDataFromFile(filePath, isLoadSpriteFrame); + self.addDataFromFile(filePath); self._asyncRefCount--; - self._asyncCallBack(target, selector, (self._asyncRefTotalCount - self._asyncRefCount) / self._asyncRefTotalCount); + self._asyncCallBack(selector,target, (self._asyncRefTotalCount - self._asyncRefCount) / self._asyncRefTotalCount); }; - cc.director.getScheduler().scheduleCallbackForTarget(this, fun, 0.1, false); + cc.director.getScheduler().schedule(fun, this, 0.1, false, 0, false, "armatrueDataHelper"); }, - _asyncCallBack: function (target, selector, percent) { - if (target && (typeof(selector) == "string")) { - target[selector](percent); - } else if (target && (typeof(selector) == "function")) { - selector.call(target, percent); - } - }, /** - * find the base file path - * @param filePath - * @returns {String} - * @private + * Removes config file from config file list. + * @param {String} configFile */ - _initBaseFilePath: function (filePath) { - var path = filePath; - var pos = path.lastIndexOf("/"); - if (pos > -1) - path = path.substr(0, pos + 1); - else - path = ""; - return path; - }, - - addDataFromXML: function (xml, dataInfo) { - /* - * Need to get the full path of the xml file, or the Tiny XML can't find the xml at IOS - */ - var xmlStr = cc.loader.getRes(xml); - if (!xmlStr) throw "Please load the resource first : " + xml; - var skeletonXML = cc.saxParser.parse(xmlStr); - var skeleton = skeletonXML.documentElement; - if (skeleton) { - this.addDataFromCache(skeleton, dataInfo); + removeConfigFile: function (configFile) { +// cc.arrayRemoveObject(this._configFileList, configFile); + var locFileList = this._configFileList; + var len = locFileList.length; + var it = locFileList[len]; + for (var i = 0;i " + ccs.CONST_ARMATURES + " > " + ccs.CONST_ARMATURE + ""); - var armatureDataManager = ccs.armatureDataManager; - for (var i = 0; i < armaturesXML.length; i++) { + var armatureDataManager = ccs.armatureDataManager, i; + for (i = 0; i < armaturesXML.length; i++) { var armatureData = this.decodeArmature(armaturesXML[i], dataInfo); armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename); } + /* + * Begin decode animation data from xml + */ var animationsXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_ANIMATIONS + " > " + ccs.CONST_ANIMATION + ""); - for (var i = 0; i < animationsXML.length; i++) { + for (i = 0; i < animationsXML.length; i++) { var animationData = this.decodeAnimation(animationsXML[i], dataInfo); armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename); } var texturesXML = skeleton.querySelectorAll(ccs.CONST_SKELETON + " > " + ccs.CONST_TEXTURE_ATLAS + " > " + ccs.CONST_SUB_TEXTURE + ""); - for (var i = 0; i < texturesXML.length; i++) { + for (i = 0; i < texturesXML.length; i++) { var textureData = this.decodeTexture(texturesXML[i], dataInfo); armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename); } - skeleton = null; }, + /** + * decode xml armature data. + * @param {XMLDocument} armatureXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.ArmatureData} + */ decodeArmature: function (armatureXML, dataInfo) { - var name = armatureXML.getAttribute(ccs.CONST_A_NAME); var armatureData = new ccs.ArmatureData(); - armatureData.name = name; + armatureData.init(); + armatureData.name = armatureXML.getAttribute(ccs.CONST_A_NAME); var bonesXML = armatureXML.querySelectorAll(ccs.CONST_ARMATURE + " > " + ccs.CONST_BONE); for (var i = 0; i < bonesXML.length; i++) { + /* + * If this bone have parent, then get the parent bone xml + */ var boneXML = bonesXML[i]; var parentName = boneXML.getAttribute(ccs.CONST_A_PARENT); var parentXML = null; @@ -299,39 +328,97 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return armatureData; }, - decodeBone: function (boneXML, parentXML, dataInfo) { + /** + * decode json armature data. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.ArmatureData} + */ + decodeArmatureFromJSON: function (json, dataInfo) { + var armatureData = new ccs.ArmatureData(); + armatureData.init(); - var name = boneXML.getAttribute(ccs.CONST_A_NAME); - if (name == "") { - return; + var name = json[ccs.CONST_A_NAME]; + if (name) { + armatureData.name = name; + } + + dataInfo.cocoStudioVersion = armatureData.dataVersion = json[ccs.CONST_VERSION] || 0.1; + + var boneDataList = json[ccs.CONST_BONE_DATA]; + for (var i = 0; i < boneDataList.length; i++) { + var boneData = this.decodeBoneFromJson(boneDataList[i], dataInfo); + armatureData.addBoneData(boneData); } + return armatureData; + }, + + /** + * decode xml bone data. + * @param {XMLDocument} boneXML + * @param {XMLDocument} parentXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.BoneData} + */ + decodeBone: function (boneXML, parentXML, dataInfo) { var boneData = new ccs.BoneData(); - boneData.name = name; + boneData.init(); + + boneData.name = boneXML.getAttribute(ccs.CONST_A_NAME); boneData.parentName = boneXML.getAttribute(ccs.CONST_A_PARENT) || ""; + boneData.zOrder = parseInt(boneXML.getAttribute(ccs.CONST_A_Z)) || 0; var displaysXML = boneXML.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_DISPLAY); - - var displayXML; for (var i = 0; i < displaysXML.length; i++) { - displayXML = displaysXML[i]; + var displayXML = displaysXML[i]; var displayData = this.decodeBoneDisplay(displayXML, dataInfo); boneData.addDisplayData(displayData); } return boneData; }, + + /** + * decode json bone data. + * @param {Object} json json bone data. + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.BoneData} + */ + decodeBoneFromJson: function (json, dataInfo) { + var boneData = new ccs.BoneData(); + boneData.init(); + + this.decodeNodeFromJson(boneData, json, dataInfo); + + boneData.name = json[ccs.CONST_A_NAME] || ""; + + boneData.parentName = json[ccs.CONST_A_PARENT] || ""; + var displayDataList = json[ccs.CONST_DISPLAY_DATA] || []; + for (var i = 0; i < displayDataList.length; i++) { + var locDisplayData = this.decodeBoneDisplayFromJson(displayDataList[i], dataInfo); + boneData.addDisplayData(locDisplayData); + } + return boneData; + }, + + /** + * decode xml display data of bone + * @param {XMLDocument} displayXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.DisplayData} + */ decodeBoneDisplay: function (displayXML, dataInfo) { var isArmature = parseFloat(displayXML.getAttribute(ccs.CONST_A_IS_ARMATURE)) || 0; var displayData = null; - if (isArmature == 1) { + if (isArmature === 1) { displayData = new ccs.ArmatureDisplayData(); displayData.displayType = ccs.DISPLAY_TYPE_ARMATURE; - } - else { + } else { displayData = new ccs.SpriteDisplayData(); displayData.displayType = ccs.DISPLAY_TYPE_SPRITE; } + var displayName = displayXML.getAttribute(ccs.CONST_A_NAME) || ""; if (displayName) { displayData.displayName = displayName; @@ -339,15 +426,81 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return displayData; }, + /** + * Decodes json display data of bone. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.DisplayData} + */ + decodeBoneDisplayFromJson: function (json, dataInfo) { + var displayType = json[ccs.CONST_A_DISPLAY_TYPE] || ccs.DISPLAY_TYPE_SPRITE; + var displayData = null; + + switch (displayType) { + case ccs.DISPLAY_TYPE_SPRITE: + displayData = new ccs.SpriteDisplayData(); + + var name = json[ccs.CONST_A_NAME]; + if(name != null){ + displayData.displayName = name; + } + + var dicArray = json[ccs.CONST_SKIN_DATA] || []; + var dic = dicArray[0]; + if (dic) { + var skinData = displayData.skinData; + skinData.x = dic[ccs.CONST_A_X] * this._positionReadScale; + skinData.y = dic[ccs.CONST_A_Y] * this._positionReadScale; + skinData.scaleX = dic[ccs.CONST_A_SCALE_X] == null ? 1 : dic[ccs.CONST_A_SCALE_X]; + skinData.scaleY = dic[ccs.CONST_A_SCALE_Y] == null ? 1 : dic[ccs.CONST_A_SCALE_Y]; + skinData.skewX = dic[ccs.CONST_A_SKEW_X] == null ? 1 : dic[ccs.CONST_A_SKEW_X]; + skinData.skewY = dic[ccs.CONST_A_SKEW_Y] == null ? 1 : dic[ccs.CONST_A_SKEW_Y]; + + skinData.x *= dataInfo.contentScale; + skinData.y *= dataInfo.contentScale; + } + break; + case ccs.DISPLAY_TYPE_ARMATURE: + displayData = new ccs.ArmatureDisplayData(); + var name = json[ccs.CONST_A_NAME]; + if(name != null){ + displayData.displayName = json[ccs.CONST_A_NAME]; + } + break; + case ccs.DISPLAY_TYPE_PARTICLE: + displayData = new ccs.ParticleDisplayData(); + var plist = json[ccs.CONST_A_PLIST]; + if(plist != null){ + if(dataInfo.asyncStruct){ + displayData.displayName = dataInfo.asyncStruct.basefilePath + plist; + }else{ + displayData.displayName = dataInfo.basefilePath + plist; + } + } + break; + default: + displayData = new ccs.SpriteDisplayData(); + break; + } + displayData.displayType = displayType; + return displayData; + }, + /** + * Decodes xml animation data. + * @param {XMLDocument} animationXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.AnimationData} + */ decodeAnimation: function (animationXML, dataInfo) { - var name = animationXML.getAttribute(ccs.CONST_A_NAME); var aniData = new ccs.AnimationData(); + var name = animationXML.getAttribute(ccs.CONST_A_NAME); var armatureData = ccs.armatureDataManager.getArmatureData(name); aniData.name = name; var movementsXML = animationXML.querySelectorAll(ccs.CONST_ANIMATION + " > " + ccs.CONST_MOVEMENT); var movementXML = null; + for (var i = 0; i < movementsXML.length; i++) { movementXML = movementsXML[i]; var movementData = this.decodeMovement(movementXML, armatureData, dataInfo); @@ -356,20 +509,48 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return aniData; }, + /** + * Decodes animation json data. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.AnimationData} + */ + decodeAnimationFromJson: function (json, dataInfo) { + var aniData = new ccs.AnimationData(); + var name = json[ccs.CONST_A_NAME]; + if(name){ + aniData.name = json[ccs.CONST_A_NAME]; + } + + var movementDataList = json[ccs.CONST_MOVEMENT_DATA] || []; + for (var i = 0; i < movementDataList.length; i++) { + var locMovementData = this.decodeMovementFromJson(movementDataList[i], dataInfo); + aniData.addMovement(locMovementData); + } + return aniData; + }, + + /** + * Decodes xml movement data. + * @param {XMLDocument} movementXML + * @param {ccs.ArmatureData} armatureData + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.MovementData} + */ decodeMovement: function (movementXML, armatureData, dataInfo) { - var movName = movementXML.getAttribute(ccs.CONST_A_NAME); var movementData = new ccs.MovementData(); - movementData.name = movName; - var duration, durationTo, durationTween, loop = 0, tweenEasing = 0; + movementData.name = movementXML.getAttribute(ccs.CONST_A_NAME); - duration = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION)) || 0; - movementData.duration = duration; + var duration, durationTo, durationTween, loop, tweenEasing = 0; - durationTo = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TO)) || 0; - movementData.durationTo = durationTo; + duration = movementXML.getAttribute(ccs.CONST_A_DURATION); + movementData.duration = duration == null ? 0 : parseFloat(duration); - durationTween = parseFloat(movementXML.getAttribute(ccs.CONST_A_DURATION_TWEEN)) || 0; - movementData.durationTween = durationTween; + durationTo = movementXML.getAttribute(ccs.CONST_A_DURATION_TO); + movementData.durationTo = durationTo == null ? 0 : parseFloat(durationTo); + + durationTween = movementXML.getAttribute(ccs.CONST_A_DURATION_TWEEN); + movementData.durationTween = durationTween == null ? 0 : parseFloat(durationTween); loop = movementXML.getAttribute(ccs.CONST_A_LOOP); movementData.loop = loop ? Boolean(parseFloat(loop)) : true; @@ -377,11 +558,10 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ var easing = movementXML.getAttribute(ccs.CONST_A_TWEEN_EASING); if (easing) { if (easing != ccs.CONST_FL_NAN) { - tweenEasing = parseFloat(easing) || 0; - movementData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing; - } else { - movementData.tweenEasing = ccs.TweenType.linear; - } + tweenEasing = easing == null ? 0 : parseFloat(easing); + movementData.tweenEasing = tweenEasing === 2 ? ccs.TweenType.SINE_EASEINOUT : tweenEasing; + } else + movementData.tweenEasing = ccs.TweenType.LINEAR; } var movBonesXml = movementXML.querySelectorAll(ccs.CONST_MOVEMENT + " > " + ccs.CONST_BONE); @@ -390,20 +570,18 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ movBoneXml = movBonesXml[i]; var boneName = movBoneXml.getAttribute(ccs.CONST_A_NAME); - if (movementData.getMovementBoneData(boneName)) { + if (movementData.getMovementBoneData(boneName)) continue; - } var boneData = armatureData.getBoneData(boneName); var parentName = boneData.parentName; var parentXML = null; - if (parentName != "") { + if (parentName !== "") { for (var j = 0; j < movBonesXml.length; j++) { parentXML = movBonesXml[j]; - if (parentName == parentXML.getAttribute(ccs.CONST_A_NAME)) { + if (parentName === parentXML.getAttribute(ccs.CONST_A_NAME)) break; - } } } var moveBoneData = this.decodeMovementBone(movBoneXml, parentXML, boneData, dataInfo); @@ -412,47 +590,86 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return movementData; }, + /** + * Decodes json movement data. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.MovementData} + */ + decodeMovementFromJson: function (json, dataInfo) { + var movementData = new ccs.MovementData(); + + movementData.loop = json[ccs.CONST_A_LOOP] == null ? false : json[ccs.CONST_A_LOOP]; + movementData.durationTween = json[ccs.CONST_A_DURATION_TWEEN] || 0; + movementData.durationTo = json[ccs.CONST_A_DURATION_TO] || 0; + movementData.duration = json[ccs.CONST_A_DURATION] || 0; + + if(json[ccs.CONST_A_DURATION] == null){ + movementData.scale = 1; + }else{ + movementData.scale = json[ccs.CONST_A_MOVEMENT_SCALE] == null ? 1 : json[ccs.CONST_A_MOVEMENT_SCALE]; + } + + movementData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] == null ? ccs.TweenType.LINEAR : json[ccs.CONST_A_TWEEN_EASING]; + var name = json[ccs.CONST_A_NAME]; + if(name) + movementData.name = name; + + var movementBoneList = json[ccs.CONST_MOVEMENT_BONE_DATA] || []; + for (var i = 0; i < movementBoneList.length; i++) { + var locMovementBoneData = this.decodeMovementBoneFromJson(movementBoneList[i], dataInfo); + movementData.addMovementBoneData(locMovementBoneData); + } + return movementData; + }, + + /** + * Decodes xml data of bone's movement. + * @param {XMLDocument} movBoneXml + * @param {XMLDocument} parentXml + * @param {ccs.BoneData} boneData + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.MovementBoneData} + */ decodeMovementBone: function (movBoneXml, parentXml, boneData, dataInfo) { var movBoneData = new ccs.MovementBoneData(); - var scale, delay; + movBoneData.init(); + var scale, delay; if (movBoneXml) { scale = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_SCALE)) || 0; movBoneData.scale = scale; delay = parseFloat(movBoneXml.getAttribute(ccs.CONST_A_MOVEMENT_DELAY)) || 0; - if (delay > 0) { + if (delay > 0) delay -= 1; - } movBoneData.delay = delay; } - var length = 0; - var parentTotalDuration = 0; - var currentDuration = 0; - var parentFrameXML = null; - var parentXMLList = []; + var length = 0, parentTotalDuration = 0,currentDuration = 0; + var parentFrameXML = null,parentXMLList = []; - //* get the parent frame xml list, we need get the origin data + /* + * get the parent frame xml list, we need get the origin data + */ if (parentXml != null) { var parentFramesXML = parentXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME); - for (var i = 0; i < parentFramesXML.length; i++) { + for (var i = 0; i < parentFramesXML.length; i++) parentXMLList.push(parentFramesXML[i]); - } length = parentXMLList.length; } + movBoneData.name = movBoneXml.getAttribute(ccs.CONST_A_NAME); - var totalDuration = 0; - - var name = movBoneXml.getAttribute(ccs.CONST_A_NAME); - movBoneData.name = name; var framesXML = movBoneXml.querySelectorAll(ccs.CONST_BONE + " > " + ccs.CONST_FRAME); - var j = 0; + + var j = 0, totalDuration = 0; for (var ii = 0; ii < framesXML.length; ii++) { var frameXML = framesXML[ii]; if (parentXml) { - //* in this loop we get the corresponding parent frame xml + /* + * in this loop we get the corresponding parent frame xml + */ while (j < length && (parentFrameXML ? (totalDuration < parentTotalDuration || totalDuration >= parentTotalDuration + currentDuration) : true)) { parentFrameXML = parentXMLList[j]; parentTotalDuration += currentDuration; @@ -460,16 +677,15 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ j++; } } - var frameData = this.decodeFrame(frameXML, parentFrameXML, boneData, dataInfo); - movBoneData.addFrameData(frameData); - frameData.frameID = totalDuration; - totalDuration += frameData.duration; + var boneFrameData = this.decodeFrame(frameXML, parentFrameXML, boneData, dataInfo); + movBoneData.addFrameData(boneFrameData); + boneFrameData.frameID = totalDuration; + totalDuration += boneFrameData.duration; movBoneData.duration = totalDuration; } //Change rotation range from (-180 -- 180) to (-infinity -- infinity) - var frames = movBoneData.frameList; - var pi = Math.PI; + var frames = movBoneData.frameList, pi = Math.PI; for (var i = frames.length - 1; i >= 0; i--) { if (i > 0) { var difSkewX = frames[i].skewX - frames[i - 1].skewX; @@ -485,130 +701,220 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ } } - if (movBoneData.frameList.length > 0) { - var frameData = new ccs.FrameData(); - frameData.copy(movBoneData.frameList[movBoneData.frameList.length - 1]); - frameData.frameID = movBoneData.duration; - movBoneData.addFrameData(frameData); - } + var frameData = new ccs.FrameData(); + frameData.copy(movBoneData.frameList[movBoneData.frameList.length - 1]); + frameData.frameID = movBoneData.duration; + movBoneData.addFrameData(frameData); return movBoneData; }, - decodeFrame: function (frameXML, parentFrameXml, boneData, dataInfo) { - var frameData = new ccs.FrameData(); - frameData.movement = frameXML.getAttribute(ccs.CONST_A_MOVEMENT) || ""; - frameData.event = frameXML.getAttribute(ccs.CONST_A_EVENT) || ""; - frameData.blendType = parseInt(frameXML.getAttribute(ccs.CONST_A_BLEND_TYPE)) || ccs.BLEND_TYPE_NORMAL; - - var blendFunc = frameData.blendFunc; - switch (frameData.blendType) { - case ccs.BLEND_TYPE_NORMAL: - blendFunc.src = cc.BLEND_SRC; - blendFunc.dst = cc.BLEND_DST; - break; - case ccs.BLEND_TYPE_ADD: - blendFunc.src = cc.SRC_ALPHA; - blendFunc.dst = cc.ONE; - break; - case ccs.BLEND_TYPE_MULTIPLY: - blendFunc.src = cc.ONE_MINUS_SRC_ALPHA; - blendFunc.dst = cc.ONE_MINUS_DST_COLOR; - break; - case ccs.BLEND_TYPE_SCREEN: - blendFunc.src = cc.ONE; - blendFunc.dst = cc.ONE_MINUS_DST_COLOR; - break; - default: - break; - } - - frameData.sound = frameXML.getAttribute(ccs.CONST_A_SOUND) || ""; - frameData.soundEffect = frameXML.getAttribute(ccs.CONST_A_SOUND_EFFECT) || ""; - - var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME); - if(isTween == null) - isTween = true; - frameData.isTween = Boolean(isTween); - - if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) { - frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0; - frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0; - } - else { - frameData.x = parseFloat(frameXML.getAttribute(ccs.CONST_A_X)) || 0; - frameData.y = -parseFloat(frameXML.getAttribute(ccs.CONST_A_Y)) || 0; - } - frameData.x *= this._positionReadScale; - frameData.y *= this._positionReadScale; - frameData.scaleX = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_X)) || 0; - frameData.scaleY = parseFloat(frameXML.getAttribute(ccs.CONST_A_SCALE_Y)) || 0; - frameData.skewX = cc.degreesToRadians(parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_X)) || 0); - frameData.skewY = cc.degreesToRadians(-parseFloat(frameXML.getAttribute(ccs.CONST_A_SKEW_Y)) || 0); - frameData.duration = parseFloat(frameXML.getAttribute(ccs.CONST_A_DURATION)) || 0; - frameData.displayIndex = parseFloat(frameXML.getAttribute(ccs.CONST_A_DISPLAY_INDEX)) || 0; - frameData.zOrder = parseFloat(frameXML.getAttribute(ccs.CONST_A_Z)) || 0; - frameData.tweenRotate = parseFloat(frameXML.getAttribute(ccs.CONST_A_TWEEN_ROTATION)) || 0; - - var colorTransformXMLList = frameXML.querySelectorAll(ccs.CONST_FRAME + " > " + ccs.CONST_A_COLOR_TRANSFORM); - if (colorTransformXMLList.length > 0) { - var colorTransformXML = colorTransformXMLList[0]; - var alpha = 0, red = 0, green = 0, blue = 0; - var alphaOffset = 0, redOffset = 0, greenOffset = 0, blueOffset = 100; - - alpha = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_ALPHA)) || alpha; - red = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_RED)) || red; - green = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_GREEN)) || green; - blue = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_BLUE)) || blue; - - var str_alphaOffset = colorTransformXML.getAttribute(ccs.CONST_A_ALPHA_OFFSET); - if (str_alphaOffset) { - alphaOffset = parseFloat(str_alphaOffset); - } - var str_redOffset = colorTransformXML.getAttribute(ccs.CONST_A_RED_OFFSET); - if (str_redOffset) { - redOffset = parseFloat(str_redOffset); - } - var str_greenOffset = colorTransformXML.getAttribute(ccs.CONST_A_GREEN_OFFSET); - if (str_redOffset) { - greenOffset = parseFloat(str_greenOffset); - } - var str_blueOffset = colorTransformXML.getAttribute(ccs.CONST_A_BLUE_OFFSET); - if (str_blueOffset) { - blueOffset = parseFloat(str_blueOffset); - } - frameData.a = 2.55 * alphaOffset + alpha; - frameData.r = 2.55 * redOffset + red; - frameData.g = 2.55 * greenOffset + green; - frameData.b = 2.55 * blueOffset + blue; + /** + * Decodes json data of bone's movement. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.MovementBoneData} + */ + decodeMovementBoneFromJson: function (json, dataInfo) { + var movementBoneData = new ccs.MovementBoneData(); + movementBoneData.init(); + movementBoneData.delay = json[ccs.CONST_A_MOVEMENT_DELAY] || 0; - frameData.isUseColorInfo = true; - } - if (frameData.displayIndex == -1) { - frameData.a = 0; - } + var name = json[ccs.CONST_A_NAME]; + if(name) + movementBoneData.name = name; + + var framesData = json[ccs.CONST_FRAME_DATA] || []; + var length = framesData.length; + for (var i = 0; i < length; i++) { + var dic = json[ccs.CONST_FRAME_DATA][i]; + var frameData = this.decodeFrameFromJson(dic, dataInfo); + movementBoneData.addFrameData(frameData); - var tweenEasing = frameXML.getAttribute(ccs.CONST_A_TWEEN_EASING); - if (tweenEasing) { - if (tweenEasing != ccs.CONST_FL_NAN) { - frameData.tweenEasing = tweenEasing == 2 ? ccs.TweenType.sineEaseInOut : tweenEasing; - } else { - frameData.tweenEasing = ccs.TweenType.linear; + if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED){ + frameData.frameID = movementBoneData.duration; + movementBoneData.duration += frameData.duration; } } - if (parentFrameXml) { - //* recalculate frame data from parent frame data, use for translate matrix - var helpNode = new ccs.BaseData(); - if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) { - helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_X)) || 0; - helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_Y)) || 0; + if (dataInfo.cocoStudioVersion < ccs.VERSION_CHANGE_ROTATION_RANGE) { + //! Change rotation range from (-180 -- 180) to (-infinity -- infinity) + var frames = movementBoneData.frameList; + var pi = Math.PI; + for (var i = frames.length - 1; i >= 0; i--) { + if (i > 0) { + var difSkewX = frames[i].skewX - frames[i - 1].skewX; + var difSkewY = frames[i].skewY - frames[i - 1].skewY; + + if (difSkewX < -pi || difSkewX > pi) { + frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi; + } + + if (difSkewY < -pi || difSkewY > pi) { + frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi; + } + } } - else { - helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_X)) || 0; - helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_Y)) || 0; + } + + if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) { + if (movementBoneData.frameList.length > 0) { + var frameData = new ccs.FrameData(); + frameData.copy(movementBoneData.frameList[movementBoneData.frameList.length - 1]); + movementBoneData.addFrameData(frameData); + frameData.frameID = movementBoneData.duration; + } + } + return movementBoneData; + }, + + /** + * Decodes xml data of frame. + * @param {XMLDocument} frameXML + * @param {XMLDocument} parentFrameXml + * @param {ccs.BoneData} boneData + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.FrameData} + */ + decodeFrame: function (frameXML, parentFrameXml, boneData, dataInfo) { + var x = 0, y = 0, scale_x = 0, scale_y = 0, skew_x = 0, skew_y = 0, tweenRotate = 0; + var duration = 0, displayIndex = 0, zOrder = 0, tweenEasing = 0, blendType = 0; + + var frameData = new ccs.FrameData(); + frameData.strMovement = frameXML.getAttribute(ccs.CONST_A_MOVEMENT) || ""; + frameData.movement = frameData.strMovement; + frameData.strEvent = frameXML.getAttribute(ccs.CONST_A_EVENT) || ""; + frameData.event = frameData.strEvent; + frameData.strSound = frameXML.getAttribute(ccs.CONST_A_SOUND) || ""; + frameData.sound = frameData.strSound; + frameData.strSoundEffect = frameXML.getAttribute(ccs.CONST_A_SOUND_EFFECT) || ""; + frameData.soundEffect = frameData.strSoundEffect; + + var isTween = frameXML.getAttribute(ccs.CONST_A_TWEEN_FRAME); + frameData.isTween = !(isTween != undefined && isTween === "false"); + + if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) { + x = frameXML.getAttribute(ccs.CONST_A_COCOS2DX_X); + if(x){ + frameData.x = parseFloat(x); + frameData.x *= this._positionReadScale; } - helpNode.skewX = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_X)) || 0; - helpNode.skewY = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_Y)) || 0; + y = frameXML.getAttribute(ccs.CONST_A_COCOS2DX_Y); + if(y){ + frameData.y = -parseFloat(y); + frameData.y *= this._positionReadScale; + } + } else { + x = frameXML.getAttribute(ccs.CONST_A_X); + if(x) { + frameData.x = parseFloat(x); + frameData.x *= this._positionReadScale; + } + y = frameXML.getAttribute(ccs.CONST_A_Y); + if(y) { + frameData.y = -parseFloat(y); + frameData.y *= this._positionReadScale; + } + } + + scale_x = frameXML.getAttribute(ccs.CONST_A_SCALE_X); + if( scale_x != null ) + frameData.scaleX = parseFloat(scale_x); + scale_y = frameXML.getAttribute(ccs.CONST_A_SCALE_Y); + if( scale_y != null ) + frameData.scaleY = parseFloat(scale_y); + skew_x = frameXML.getAttribute(ccs.CONST_A_SKEW_X); + if( skew_x != null ) + frameData.skewX = cc.degreesToRadians(parseFloat(skew_x)); + skew_y = frameXML.getAttribute(ccs.CONST_A_SKEW_Y); + if( skew_y != null ) + frameData.skewY = cc.degreesToRadians(-parseFloat(skew_y)); + + duration = frameXML.getAttribute(ccs.CONST_A_DURATION); + if( duration != null ) + frameData.duration = parseFloat(duration); + displayIndex = frameXML.getAttribute(ccs.CONST_A_DISPLAY_INDEX); + if( displayIndex != null ) + frameData.displayIndex = parseFloat(displayIndex); + zOrder = frameXML.getAttribute(ccs.CONST_A_Z); + if( zOrder != null ) + frameData.zOrder = parseInt(zOrder); + tweenRotate = frameXML.getAttribute(ccs.CONST_A_TWEEN_ROTATE); + if( tweenRotate != null ) + frameData.tweenRotate = parseFloat(tweenRotate); + + blendType = frameXML.getAttribute(ccs.CONST_A_BLEND_TYPE); + if ( blendType != null ) { + var blendFunc = frameData.blendFunc; + switch (blendType) { + case ccs.BLEND_TYPE_NORMAL: + blendFunc.src = cc.BLEND_SRC; + blendFunc.dst = cc.BLEND_DST; + break; + case ccs.BLEND_TYPE_ADD: + blendFunc.src = cc.SRC_ALPHA; + blendFunc.dst = cc.ONE; + break; + case ccs.BLEND_TYPE_MULTIPLY: + blendFunc.src = cc.DST_COLOR; + blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + break; + case ccs.BLEND_TYPE_SCREEN: + blendFunc.src = cc.ONE; + blendFunc.dst = cc.ONE_MINUS_DST_COLOR; + break; + default: + frameData.blendFunc.src = cc.BLEND_SRC; + frameData.blendFunc.dst = cc.BLEND_DST; + break; + } + } + + var colorTransformXML = frameXML.querySelectorAll(ccs.CONST_FRAME + " > " + ccs.CONST_A_COLOR_TRANSFORM); + if (colorTransformXML && colorTransformXML.length > 0) { + colorTransformXML = colorTransformXML[0]; + var alpha, red, green, blue; + var alphaOffset, redOffset, greenOffset, blueOffset; + + alpha = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_ALPHA)) || 0; + red = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_RED)) || 0; + green = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_GREEN)) || 0; + blue = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_BLUE)) || 0; + + alphaOffset = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_ALPHA_OFFSET)) || 0; + redOffset = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_RED_OFFSET)) || 0; + greenOffset = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_GREEN_OFFSET)) || 0; + blueOffset = parseFloat(colorTransformXML.getAttribute(ccs.CONST_A_BLUE_OFFSET)) || 0; + + frameData.a = 2.55 * alphaOffset + alpha; + frameData.r = 2.55 * redOffset + red; + frameData.g = 2.55 * greenOffset + green; + frameData.b = 2.55 * blueOffset + blue; + + frameData.isUseColorInfo = true; + } + + var _easing = frameXML.getAttribute(ccs.CONST_A_TWEEN_EASING); + if(_easing != null) { + if(_easing != ccs.CONST_FL_NAN){ + tweenEasing = frameXML.getAttribute(ccs.CONST_A_TWEEN_EASING); + if( tweenEasing ) + frameData.tweenEasing = (tweenEasing === 2) ? ccs.TweenType.SINE_EASEINOUT : tweenEasing; + } else + frameData.tweenEasing = ccs.TweenType.LINEAR; + } + + if (parentFrameXml) { + //* recalculate frame data from parent frame data, use for translate matrix + var helpNode = new ccs.BaseData(); + if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) { + helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_X)); + helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_COCOS2DX_Y)); + } else { + helpNode.x = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_X)); + helpNode.y = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_Y)); + } + helpNode.skewX = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_X)); + helpNode.skewY = parseFloat(parentFrameXml.getAttribute(ccs.CONST_A_SKEW_Y)); helpNode.y = -helpNode.y; helpNode.skewX = cc.degreesToRadians(helpNode.skewX); @@ -618,22 +924,70 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ return frameData; }, + /** + * Decodes json data of frame. + * @param {Object} json + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.FrameData} + */ + decodeFrameFromJson: function (json, dataInfo) { + var frameData = new ccs.FrameData(); + + this.decodeNodeFromJson(frameData, json, dataInfo); + + frameData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.LINEAR; + frameData.displayIndex = json[ccs.CONST_A_DISPLAY_INDEX]; + var bd_src = json[ccs.CONST_A_BLEND_SRC] == null ? cc.BLEND_SRC : json[ccs.CONST_A_BLEND_SRC]; + var bd_dst = json[ccs.CONST_A_BLEND_DST] == null ? cc.BLEND_DST : json[ccs.CONST_A_BLEND_DST]; + frameData.blendFunc.src = bd_src; + frameData.blendFunc.dst = bd_dst; + frameData.isTween = json[ccs.CONST_A_TWEEN_FRAME] == null ? true : json[ccs.CONST_A_TWEEN_FRAME]; + + var event = json[ccs.CONST_A_EVENT]; + if(event != null){ + frameData.strEvent = event; + frameData.event = event; + } + + if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) + frameData.duration = json[ccs.CONST_A_DURATION] == null ? 1 : json[ccs.CONST_A_DURATION]; + else + frameData.frameID = json[ccs.CONST_A_FRAME_INDEX]; + + var twEPs = json[ccs.CONST_A_EASING_PARAM] || []; + for (var i = 0; i < twEPs.length; i++) { + frameData.easingParams[i] = twEPs[i]; + } + + return frameData; + }, + + /** + * Decodes xml data of texture + * @param {XMLDocument} textureXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.TextureData} + */ decodeTexture: function (textureXML, dataInfo) { var textureData = new ccs.TextureData(); + textureData.init(); + if (textureXML.getAttribute(ccs.CONST_A_NAME)) { textureData.name = textureXML.getAttribute(ccs.CONST_A_NAME); } - var px, py, width, height = 0; + + var px, py; + if (dataInfo.flashToolVersion >= ccs.CONST_VERSION_2_0) { px = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_X)) || 0; py = parseFloat(textureXML.getAttribute(ccs.CONST_A_COCOS2D_PIVOT_Y)) || 0; - } - else { + } else { px = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_X)) || 0; py = parseFloat(textureXML.getAttribute(ccs.CONST_A_PIVOT_Y)) || 0; } - width = parseFloat(textureXML.getAttribute(ccs.CONST_A_WIDTH)) || 0; - height = parseFloat(textureXML.getAttribute(ccs.CONST_A_HEIGHT)) || 0; + + var width = parseFloat(textureXML.getAttribute(ccs.CONST_A_WIDTH)) || 0; + var height = parseFloat(textureXML.getAttribute(ccs.CONST_A_HEIGHT)) || 0; var anchorPointX = px / width; var anchorPointY = (height - py) / height; @@ -643,13 +997,46 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ var contoursXML = textureXML.querySelectorAll(ccs.CONST_SUB_TEXTURE + " > " + ccs.CONST_CONTOUR); for (var i = 0; i < contoursXML.length; i++) { - this.decodeContour(contoursXML[i], dataInfo); + textureData.addContourData(this.decodeContour(contoursXML[i], dataInfo)); + } + return textureData; + }, + + /** + * Decodes json data of Texture. + * @param json + * @returns {ccs.TextureData} + */ + decodeTextureFromJson: function (json) { + var textureData = new ccs.TextureData(); + textureData.init(); + + var name = json[ccs.CONST_A_NAME]; + if(name != null) + textureData.name = name; + + textureData.width = json[ccs.CONST_A_WIDTH] || 0; + textureData.height = json[ccs.CONST_A_HEIGHT] || 0; + textureData.pivotX = json[ccs.CONST_A_PIVOT_X] || 0; + textureData.pivotY = json[ccs.CONST_A_PIVOT_Y] || 0; + + var contourDataList = json[ccs.CONST_CONTOUR_DATA] || []; + for (var i = 0; i < contourDataList.length; i++) { + textureData.contourDataList.push(this.decodeContourFromJson(contourDataList[i])); } return textureData; }, + /** + * Decodes xml data of contour. + * @param {XMLDocument} contourXML + * @param {ccs.DataInfo} dataInfo + * @returns {ccs.ContourData} + */ decodeContour: function (contourXML, dataInfo) { var contourData = new ccs.ContourData(); + contourData.init(); + var vertexDatasXML = contourXML.querySelectorAll(ccs.CONST_CONTOUR + " > " + ccs.CONST_CONTOUR_VERTEX); var vertexDataXML; for (var i = 0; i < vertexDatasXML.length; i++) { @@ -657,44 +1044,73 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ var vertex = cc.p(0, 0); vertex.x = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_X)) || 0; vertex.y = parseFloat(vertexDataXML.getAttribute(ccs.CONST_A_Y)) || 0; - //vertex.y = - vertex.y;//todo + + vertex.y = - vertex.y; contourData.vertexList.push(vertex); } return contourData; - }, - addDataFromJson: function (filePath, dataInfo, isLoadSpriteFrame) { - var fileContent = cc.loader.getRes(filePath); - this.addDataFromJsonCache(fileContent, dataInfo, isLoadSpriteFrame); + /** + * Decodes json data of contour. + * @param {Object} json + * @returns {ccs.ContourData} + */ + decodeContourFromJson: function (json) { + var contourData = new ccs.ContourData(); + contourData.init(); + + var vertexPointList = json[ccs.CONST_VERTEX_POINT] || []; + var len = vertexPointList.length; + for (var i = 0; i < len; i++) { + var dic = vertexPointList[i]; + var vertex = cc.p(0, 0); + vertex.x = dic[ccs.CONST_A_X] || 0; + vertex.y = dic[ccs.CONST_A_Y] || 0; + contourData.vertexList.push(vertex); + } + return contourData; }, - addDataFromJsonCache: function (dic, dataInfo, isLoadSpriteFrame) { - dataInfo.contentScale = dic[ccs.CONST_CONTENT_SCALE] || 1; - var armatureDataArr = dic[ccs.CONST_ARMATURE_DATA] || []; + + /** + * Adds json armature data to armature data manager. + * @param {Object} dic json armature data + * @param {ccs.DataInfo} dataInfo + */ + addDataFromJsonCache: function (dic, dataInfo) { + dataInfo.contentScale = dic[ccs.CONST_CONTENT_SCALE] == null ? 1 : dic[ccs.CONST_CONTENT_SCALE]; + + // Decode armatures + var armatureDataArr = dic[ccs.CONST_ARMATURE_DATA] || [], i; var armatureData; - for (var i = 0; i < armatureDataArr.length; i++) { + for (i = 0; i < armatureDataArr.length; i++) { armatureData = this.decodeArmatureFromJSON(armatureDataArr[i], dataInfo); ccs.armatureDataManager.addArmatureData(armatureData.name, armatureData, dataInfo.filename); } + // Decode animations var animationDataArr = dic[ccs.CONST_ANIMATION_DATA] || []; var animationData; - for (var i = 0; i < animationDataArr.length; i++) { + for (i = 0; i < animationDataArr.length; i++) { animationData = this.decodeAnimationFromJson(animationDataArr[i], dataInfo); ccs.armatureDataManager.addAnimationData(animationData.name, animationData, dataInfo.filename); } + // Decode textures var textureDataArr = dic[ccs.CONST_TEXTURE_DATA] || []; var textureData; - for (var i = 0; i < textureDataArr.length; i++) { + for (i = 0; i < textureDataArr.length; i++) { textureData = this.decodeTextureFromJson(textureDataArr[i], dataInfo); ccs.armatureDataManager.addTextureData(textureData.name, textureData, dataInfo.filename); } - if (isLoadSpriteFrame) { + // Auto load sprite file + var autoLoad = dataInfo.asyncStruct == null ? ccs.armatureDataManager.isAutoLoadSpriteFile() : dataInfo.asyncStruct.autoLoadSpriteFile; +// if (isLoadSpriteFrame) { + if (autoLoad) { var configFiles = dic[ccs.CONST_CONFIG_FILE_PATH] || []; var locFilePath, locPos, locPlistPath, locImagePath; - for (var i = 0; i < configFiles.length; i++) { + for (i = 0; i < configFiles.length; i++) { locFilePath = configFiles[i]; locPos = locFilePath.lastIndexOf("."); locFilePath = locFilePath.substring(0, locPos); @@ -708,256 +1124,100 @@ ccs.dataReaderHelper = /** @lends ccs.dataReaderHelper# */{ animationData = null; }, - decodeArmatureFromJSON: function (json, dataInfo) { - var armatureData = new ccs.ArmatureData(); - - var name = json[ccs.CONST_A_NAME]; - if (name) { - armatureData.name = name; - } - - dataInfo.cocoStudioVersion = armatureData.dataVersion = json[ccs.CONST_VERSION] || 0.1; - - var boneDataList = json[ccs.CONST_BONE_DATA]; - for (var i = 0; i < boneDataList.length; i++) { - armatureData.addBoneData(this.decodeBoneFromJson(boneDataList[i], dataInfo)); - } - return armatureData; - }, - - decodeBoneFromJson: function (json, dataInfo) { - var boneData = new ccs.BoneData(); - this.decodeNodeFromJson(boneData, json, dataInfo); - boneData.name = json[ccs.CONST_A_NAME] || ""; - boneData.parentName = json[ccs.CONST_A_PARENT] || ""; - var displayDataList = json[ccs.CONST_DISPLAY_DATA] || []; - for (var i = 0; i < displayDataList.length; i++) { - var locDisplayData = this.decodeBoneDisplayFromJson(displayDataList[i], dataInfo); - boneData.addDisplayData(locDisplayData); - } - return boneData; - }, - - decodeBoneDisplayFromJson: function (json, dataInfo) { - var displayType = json[ccs.CONST_A_DISPLAY_TYPE] || ccs.DISPLAY_TYPE_SPRITE; - var displayData = null; - switch (displayType) { - case ccs.DISPLAY_TYPE_SPRITE: - displayData = new ccs.SpriteDisplayData(); - displayData.displayName = json[ccs.CONST_A_NAME] || ""; - - var dicArray = json[ccs.CONST_SKIN_DATA] || []; - var dic = dicArray[0]; - if (dic) { - var skinData = displayData.skinData; - skinData.x = (dic[ccs.CONST_A_X] || 0) * this._positionReadScale; - skinData.y = (dic[ccs.CONST_A_Y] || 0) * this._positionReadScale; - if (dic[ccs.CONST_A_SCALE_X] !== undefined) { - skinData.scaleX = dic[ccs.CONST_A_SCALE_X]; - } - if (dic[ccs.CONST_A_SCALE_Y] !== undefined) { - skinData.scaleY = dic[ccs.CONST_A_SCALE_Y]; - } - skinData.skewX = dic[ccs.CONST_A_SKEW_X] || 0; - skinData.skewY = dic[ccs.CONST_A_SKEW_Y] || 0; - - skinData.x *= dataInfo.contentScale; - skinData.y *= dataInfo.contentScale; - dic = null; - } - break; - case ccs.DISPLAY_TYPE_ARMATURE: - displayData = new ccs.ArmatureDisplayData(); - displayData.displayName = json[ccs.CONST_A_NAME] || ""; - break; - case ccs.DISPLAY_TYPE_PARTICLE: - displayData = new ccs.ParticleDisplayData(); - displayData.displayName = dataInfo.basefilePath + json[ccs.CONST_A_PLIST] || ""; - break; - default: - displayData = new ccs.SpriteDisplayData(); - break; - } - - displayData.displayType = displayType; - - return displayData; - }, - - decodeAnimationFromJson: function (json, dataInfo) { - var aniData = new ccs.AnimationData(); - aniData.name = json[ccs.CONST_A_NAME] || ""; - var movementDataList = json[ccs.CONST_MOVEMENT_DATA] || []; - for (var i = 0; i < movementDataList.length; i++) { - var locMovementData = this.decodeMovementFromJson(movementDataList[i], dataInfo); - aniData.addMovement(locMovementData); - } - return aniData; - }, - - decodeMovementFromJson: function (json, dataInfo) { - var movementData = new ccs.MovementData(); - - movementData.loop = json[ccs.CONST_A_LOOP] || false; - movementData.durationTween = json[ccs.CONST_A_DURATION_TWEEN] || 0; - movementData.durationTo = json[ccs.CONST_A_DURATION_TO] || 0; - movementData.duration = json[ccs.CONST_A_DURATION] || 0; - if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) { - movementData.scale = json[ccs.CONST_A_MOVEMENT_SCALE] - } - movementData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear; - movementData.name = json[ccs.CONST_A_NAME] || ""; - - var movementBoneList = json[ccs.CONST_MOVEMENT_BONE_DATA] || []; - for (var i = 0; i < movementBoneList.length; i++) { - var locMovementBoneData = this.decodeMovementBoneFromJson(movementBoneList[i], dataInfo); - movementData.addMovementBoneData(locMovementBoneData); - } - return movementData; - }, - - decodeMovementBoneFromJson: function (json, dataInfo) { - var movementBoneData = new ccs.MovementBoneData(); - movementBoneData.delay = json[ccs.CONST_A_MOVEMENT_DELAY] || 0; - if (json[ccs.CONST_A_MOVEMENT_SCALE] !== undefined) { - movementBoneData.scale = json[ccs.CONST_A_MOVEMENT_SCALE]; - } - - movementBoneData.name = json[ccs.CONST_A_NAME] || ""; - var frameDataList = json[ccs.CONST_FRAME_DATA] || []; - for (var i = 0; i < frameDataList.length; i++) { - var frameData = this.decodeFrameFromJson(frameDataList[i], dataInfo); - movementBoneData.addFrameData(frameData); - if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) { - frameData.frameID = movementBoneData.duration; - movementBoneData.duration += frameData.duration; - } - } + /** + * Decodes json data of node. + * @param node + * @param json + * @param dataInfo + */ + decodeNodeFromJson: function (node, json, dataInfo) { + node.x = json[ccs.CONST_A_X] * this._positionReadScale; + node.y = json[ccs.CONST_A_Y] * this._positionReadScale; - if (dataInfo.cocoStudioVersion < ccs.VERSION_CHANGE_ROTATION_RANGE) { - //! Change rotation range from (-180 -- 180) to (-infinity -- infinity) - var frames = movementBoneData.frameList; - var pi = Math.PI; - for (var i = frames.length - 1; i >= 0; i--) { - if (i > 0) { - var difSkewX = frames[i].skewX - frames[i - 1].skewX; - var difSkewY = frames[i].skewY - frames[i - 1].skewY; + node.x *= dataInfo.contentScale; + node.y *= dataInfo.contentScale; - if (difSkewX < -pi || difSkewX > pi) { - frames[i - 1].skewX = difSkewX < 0 ? frames[i - 1].skewX - 2 * pi : frames[i - 1].skewX + 2 * pi; - } + node.zOrder = json[ccs.CONST_A_Z]; - if (difSkewY < -pi || difSkewY > pi) { - frames[i - 1].skewY = difSkewY < 0 ? frames[i - 1].skewY - 2 * pi : frames[i - 1].skewY + 2 * pi; - } - } + node.skewX = json[ccs.CONST_A_SKEW_X] || 0; + node.skewY = json[ccs.CONST_A_SKEW_Y] || 0; + node.scaleX = json[ccs.CONST_A_SCALE_X] == null ? 1 : json[ccs.CONST_A_SCALE_X]; + node.scaleY = json[ccs.CONST_A_SCALE_Y] == null ? 1 : json[ccs.CONST_A_SCALE_Y]; + + var colorDic; + if (dataInfo.cocoStudioVersion < ccs.VERSION_COLOR_READING) { + colorDic = json[0]; + if (colorDic){ + node.a = colorDic[ccs.CONST_A_ALPHA] == null ? 255 : colorDic[ccs.CONST_A_ALPHA]; + node.r = colorDic[ccs.CONST_A_RED] == null ? 255 : colorDic[ccs.CONST_A_RED]; + node.g = colorDic[ccs.CONST_A_GREEN] == null ? 255 : colorDic[ccs.CONST_A_GREEN]; + node.b = colorDic[ccs.CONST_A_BLUE] == null ? 255 : colorDic[ccs.CONST_A_BLUE]; + node.isUseColorInfo = true; } - } - - if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) { - if (movementBoneData.frameList.length > 0) { - var frameData = new ccs.FrameData(); - frameData.copy(movementBoneData.frameList[movementBoneData.frameList.length - 1]); - movementBoneData.addFrameData(frameData); - frameData.frameID = movementBoneData.duration; + } else { + colorDic = json[ccs.CONST_COLOR_INFO] || null; + if (colorDic){ + node.a = colorDic[ccs.CONST_A_ALPHA] == null ? 255 : colorDic[ccs.CONST_A_ALPHA]; + node.r = colorDic[ccs.CONST_A_RED] == null ? 255 : colorDic[ccs.CONST_A_RED]; + node.g = colorDic[ccs.CONST_A_GREEN] == null ? 255 : colorDic[ccs.CONST_A_GREEN]; + node.b = colorDic[ccs.CONST_A_BLUE] == null ? 255 : colorDic[ccs.CONST_A_BLUE]; + node.isUseColorInfo = true; } } - return movementBoneData; }, - decodeFrameFromJson: function (json, dataInfo) { - var frameData = new ccs.FrameData(); - this.decodeNodeFromJson(frameData, json, dataInfo); - frameData.duration = json[ccs.CONST_A_DURATION] || 0; - frameData.tweenEasing = json[ccs.CONST_A_TWEEN_EASING] || ccs.TweenType.linear; - frameData.displayIndex = json[ccs.CONST_A_DISPLAY_INDEX] || 0; - - var bd_src = json[ccs.CONST_A_BLEND_SRC] || cc.BLEND_SRC; - var bd_dst = json[ccs.CONST_A_BLEND_DST] || cc.BLEND_DST; - frameData.blendFunc.src = bd_src; - frameData.blendFunc.dst = bd_dst; - - frameData.event = json[ccs.CONST_A_EVENT] || null; - if (json[ccs.CONST_A_TWEEN_FRAME] !== undefined) { - frameData.isTween = json[ccs.CONST_A_TWEEN_FRAME] - } - if (dataInfo.cocoStudioVersion < ccs.CONST_VERSION_COMBINED) - frameData.duration = json[ccs.CONST_A_DURATION] || 0; - else - frameData.frameID = json[ccs.CONST_A_FRAME_INDEX] || 0; - - var twEPs = json[ccs.CONST_A_EASING_PARAM] || []; - for (var i = 0; i < twEPs.length; i++) { - var twEP = twEPs[i]; - frameData.easingParams[i] = twEP; - } - - return frameData; + clear: function () { + this._configFileList = []; + this._asyncRefCount = 0; + this._asyncRefTotalCount = 0; }, - decodeTextureFromJson: function (json) { - var textureData = new ccs.TextureData(); - textureData.name = json[ccs.CONST_A_NAME] || ""; - textureData.width = json[ccs.CONST_A_WIDTH] || 0; - textureData.height = json[ccs.CONST_A_HEIGHT] || 0; - textureData.pivotX = json[ccs.CONST_A_PIVOT_X] || 0; - textureData.pivotY = json[ccs.CONST_A_PIVOT_Y] || 0; - - var contourDataList = json[ccs.CONST_CONTOUR_DATA] || []; - for (var i = 0; i < contourDataList.length; i++) { - var locContourData = this.decodeContourFromJson(contourDataList[i]); - textureData.contourDataList.push(locContourData); - } - return textureData; + _asyncCallBack: function (selector, target, percent) { + if(selector && cc.isFunction(selector)) + selector.call(target, percent); + if(target && selector && typeof selector === 'string') + target[selector](percent); }, - - decodeContourFromJson: function (json) { - var contourData = new ccs.ContourData(); - var vertexPointList = json[ccs.CONST_VERTEX_POINT] || []; - for (var i = 0; i < vertexPointList.length; i++) { - var dic = vertexPointList[i]; - var vertex = cc.p(0, 0); - vertex.x = dic[ccs.CONST_A_X] || 0; - vertex.y = dic[ccs.CONST_A_Y] || 0; - contourData.vertexList.push(vertex); - } - return contourData; + /** + * find the base file path + * @param filePath + * @returns {String} + * @private + */ + _initBaseFilePath: function (filePath) { + var path = filePath; + var pos = path.lastIndexOf("/"); + if (pos > -1) + path = path.substr(0, pos + 1); + else + path = ""; + return path; }, - decodeNodeFromJson: function (node, json, dataInfo) { - node.x = json[ccs.CONST_A_X] || 0; - node.y = json[ccs.CONST_A_Y] || 0; - - node.x *= dataInfo.contentScale; - node.y *= dataInfo.contentScale; - - node.zOrder = json[ccs.CONST_A_Z] || 0; - - node.skewX = json[ccs.CONST_A_SKEW_X] || 0; - node.skewY = json[ccs.CONST_A_SKEW_Y] || 0; - if (json[ccs.CONST_A_SCALE_X] !== undefined) { - node.scaleX = json[ccs.CONST_A_SCALE_X]; - } - if (json[ccs.CONST_A_SCALE_Y] !== undefined) { - node.scaleY = json[ccs.CONST_A_SCALE_Y]; - } - - var colorDic = json[ccs.CONST_COLOR_INFO] || null; - if (colorDic) { - //compatible old version - if (dataInfo.cocoStudioVersion < ccs.VERSION_COLOR_READING) { - colorDic = colorDic[0]; - } - node.a = colorDic[ccs.CONST_A_ALPHA]; - node.r = colorDic[ccs.CONST_A_RED]; - node.g = colorDic[ccs.CONST_A_GREEN]; - node.b = colorDic[ccs.CONST_A_BLUE]; - node.isUseColorInfo = true; - delete colorDic; - } + /** + * Adds xml armature data to armature data manager. + * @param {XMLDocument} xml + * @param {ccs.DataInfo} dataInfo + */ + addDataFromXML: function (xml, dataInfo) { + /* + * Need to get the full path of the xml file, or the Tiny XML can't find the xml at IOS + */ + var xmlStr = cc.loader.getRes(xml); + if (!xmlStr) throw "Please load the resource first : " + xml; + var skeletonXML = cc.saxParser.parse(xmlStr); + var skeleton = skeletonXML.documentElement; + if (skeleton) + this.addDataFromCache(skeleton, dataInfo); }, - removeConfigFile: function (configFile) { - cc.arrayRemoveObject(this._configFileList, configFile); + /** + * Adds json armature data to armature data manager. + * @param {String} filePath + * @param {ccs.DataInfo} dataInfo + */ + addDataFromJson: function (filePath, dataInfo) { + var fileContent = cc.loader.getRes(filePath); + this.addDataFromJsonCache(fileContent, dataInfo); } }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/utils/CCSpriteFrameCacheHelper.js b/extensions/cocostudio/armature/utils/CCSpriteFrameCacheHelper.js index c79a854a80..a0496e96a7 100644 --- a/extensions/cocostudio/armature/utils/CCSpriteFrameCacheHelper.js +++ b/extensions/cocostudio/armature/utils/CCSpriteFrameCacheHelper.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,29 +24,43 @@ ****************************************************************************/ /** - * @namespace

    - * The sprite frame cache helper + * ccs.spriteFrameCacheHelper is a singleton object, it's a sprite frame cache helper + * @class + * @name ccs.spriteFrameCacheHelper */ -ccs.spriteFrameCacheHelper = /** @lends cc.spriteFrameCacheHelper# */ { +ccs.spriteFrameCacheHelper = /** @lends ccs.spriteFrameCacheHelper# */ { _textureAtlasDic:{}, _imagePaths:[], + /** + * Adds sprite frame from file + * @param plistPath + * @param imagePath + */ addSpriteFrameFromFile:function (plistPath, imagePath) { cc.spriteFrameCache.addSpriteFrames(plistPath, imagePath); }, - getTexureAtlasWithTexture:function (texture) { + /** + * Returns texture atlas with texture. + * @param texture + * @returns {*} + */ + getTextureAtlasWithTexture:function (texture) { //todo return null; var textureName = texture.getName(); var atlas = this._textureAtlasDic[textureName]; if (atlas == null) { - atlas = cc.TextureAtlas.create(texture, 20); + atlas = new cc.TextureAtlas(texture, 20); this._textureAtlasDic[textureName] = atlas; } return atlas; }, + /** + * Clear the sprite frame cache's data. + */ clear: function () { this._textureAtlasDic = {}; this._imagePaths = []; diff --git a/extensions/cocostudio/armature/utils/CCTransformHelp.js b/extensions/cocostudio/armature/utils/CCTransformHelp.js index d2430c2b10..0d6228d5cd 100644 --- a/extensions/cocostudio/armature/utils/CCTransformHelp.js +++ b/extensions/cocostudio/armature/utils/CCTransformHelp.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,38 +24,86 @@ ****************************************************************************/ /** - * @ignore + * use to calculate the matrix of node from parent node + * @class ccs.TransformHelp + * @extend ccs.Class */ ccs.TransformHelp = ccs.TransformHelp || ccs.Class.extend({}); -ccs.TransformHelp.helpMatrix1 = cc.AffineTransformMake(1, 0, 0, 1, 0, 0); -ccs.TransformHelp.helpMatrix2 = cc.AffineTransformMake(1, 0, 0, 1, 0, 0); +ccs.TransformHelp.helpMatrix1 = cc.affineTransformMake(1, 0, 0, 1, 0, 0); +ccs.TransformHelp.helpMatrix2 = cc.affineTransformMake(1, 0, 0, 1, 0, 0); ccs.TransformHelp.helpPoint1 = cc.p(0, 0); ccs.TransformHelp.helpPoint2 = cc.p(0, 0); +ccs.TransformHelp.helpParentNode = {}; /** + * Calculate a BaseData's transform matrix from parent node. * @function + * @static * @param {ccs.BaseData} bone - * @return {cc.AffineTransform} * Constructor */ -ccs.TransformHelp.transformFromParent = function (bone, parentBone) { +ccs.TransformHelp.transformFromParent = function (bone, parentNode) { this.nodeToMatrix(bone, this.helpMatrix1); - this.nodeToMatrix(parentBone, this.helpMatrix2); + this.nodeToMatrix(parentNode, this.helpMatrix2); - this.helpMatrix2 = cc.AffineTransformInvert(this.helpMatrix2); - this.helpMatrix1 = cc.AffineTransformConcat(this.helpMatrix1, this.helpMatrix2); + this.helpMatrix2 = cc.affineTransformInvert(this.helpMatrix2); + this.helpMatrix1 = cc.affineTransformConcat(this.helpMatrix1, this.helpMatrix2); this.matrixToNode(this.helpMatrix1, bone); }; +ccs.TransformHelp.transformToParent = function(node, parentNode){ + this.nodeToMatrix(node, this.helpMatrix1); + this.nodeToMatrix(parentNode, this.helpMatrix2); + + this.helpMatrix1 = cc.affineTransformConcat(this.helpMatrix1, this.helpMatrix2); + + this.matrixToNode(this.helpMatrix1, node); +}; + +ccs.TransformHelp.transformFromParentWithoutScale = function(node, parentNode){ +// this.helpParentNode.copy(&parentNode); + + for(var p in parentNode){ + this.helpParentNode[p] = parentNode[p]; + } + this.helpParentNode.scaleX = 1; + this.helpParentNode.scaleY = 1; + + this.nodeToMatrix(node, this.helpMatrix1); + this.nodeToMatrix(this.helpParentNode, this.helpMatrix2); + + this.helpMatrix2 = cc.affineTransformInvert(this.helpMatrix2); + this.helpMatrix1 = cc.affineTransformConcat(this.helpMatrix1, this.helpMatrix2); + + this.matrixToNode(this.helpMatrix1, node); +}; + +ccs.TransformHelp.transformToParentWithoutScale = function(node, parentNode){ + for(var p in parentNode){ + this.helpParentNode[p] = parentNode[p]; + } + this.helpParentNode.scaleX = 1; + this.helpParentNode.scaleY = 1; + + this.nodeToMatrix(node, this.helpMatrix1); + this.nodeToMatrix(this.helpParentNode, this.helpMatrix2); + + this.helpMatrix1 = cc.affineTransformConcat(this.helpMatrix1, this.helpMatrix2); + + this.matrixToNode(this.helpMatrix1, node); + +}; + /** * @function + * @static * @param {ccs.BaseData} node * @param {cc.AffineTransform} matrix */ ccs.TransformHelp.nodeToMatrix = function (node, matrix) { - if (node.skewX == -node.skewY) { + if (node.skewX === -node.skewY) { var sine = Math.sin(node.skewX); var cosine = Math.cos(node.skewX); matrix.a = node.scaleX * cosine; @@ -65,7 +114,7 @@ ccs.TransformHelp.nodeToMatrix = function (node, matrix) { matrix.a = node.scaleX * Math.cos(node.skewY); matrix.b = node.scaleX * Math.sin(node.skewY); matrix.c = node.scaleY * Math.sin(node.skewX); - matrix.d = node.scaleY * Math.cos(node.skewY); + matrix.d = node.scaleY * Math.cos(node.skewX); } matrix.tx = node.x; matrix.ty = node.y; @@ -73,6 +122,7 @@ ccs.TransformHelp.nodeToMatrix = function (node, matrix) { /** * @function + * @static * @param {cc.AffineTransform} matrix * @param {ccs.BaseData} node */ @@ -83,13 +133,13 @@ ccs.TransformHelp.matrixToNode = function (matrix, node) { */ this.helpPoint1.x = 0; this.helpPoint1.y = 1; - this.helpPoint1 = cc.PointApplyAffineTransform(this.helpPoint1, matrix); + this.helpPoint1 = cc.pointApplyAffineTransform(this.helpPoint1, matrix); this.helpPoint1.x -= matrix.tx; this.helpPoint1.y -= matrix.ty; this.helpPoint2.x = 1; this.helpPoint2.y = 0; - this.helpPoint2 = cc.PointApplyAffineTransform(this.helpPoint2, matrix); + this.helpPoint2 = cc.pointApplyAffineTransform(this.helpPoint2, matrix); this.helpPoint2.x -= matrix.tx; this.helpPoint2.y -= matrix.ty; @@ -104,6 +154,7 @@ ccs.TransformHelp.matrixToNode = function (matrix, node) { /** * @function + * @static * @param {ccs.BaseData} target * @param {ccs.BaseData} source */ @@ -118,6 +169,7 @@ ccs.TransformHelp.nodeConcat = function (target, source) { /** * @function + * @static * @param {ccs.BaseData} target * @param {ccs.BaseData} source */ diff --git a/extensions/cocostudio/armature/utils/CCTweenFunction.js b/extensions/cocostudio/armature/utils/CCTweenFunction.js index 15a71cc16f..7ced7fad96 100644 --- a/extensions/cocostudio/armature/utils/CCTweenFunction.js +++ b/extensions/cocostudio/armature/utils/CCTweenFunction.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -27,165 +28,177 @@ * @type Object */ ccs.TweenType = { - customEasing: -1, - linear: 0, + CUSTOM_EASING: -1, + LINEAR: 0, - sineEaseIn: 1, - sineEaseOut: 2, - sineEaseInOut: 3, + SINE_EASEIN: 1, + SINE_EASEOUT: 2, + SINE_EASEINOUT: 3, - quadEaseIn: 4, - quadEaseOut: 5, - quadEaseInOut: 6, + QUAD_EASEIN: 4, + QUAD_EASEOUT: 5, + QUAD_EASEINOUT: 6, - cubicEaseIn: 7, - cubicEaseOut: 8, - cubicEaseInOut: 9, + CUBIC_EASEIN: 7, + CUBIC_EASEOUT: 8, + CUBIC_EASEINOUT: 9, - quartEaseIn: 10, - quartEaseOut: 11, - quartEaseInOut: 12, + QUART_EASEIN: 10, + QUART_EASEOUT: 11, + QUART_EASEINOUT: 12, - quintEaseIn: 13, - quintEaseOut: 14, - quintEaseInOut: 15, + QUINT_EASEIN: 13, + QUINT_EASEOUT: 14, + QUINT_EASEINOUT: 15, - expoEaseIn: 16, - expoEaseOut: 17, - expoEaseInOut: 18, + EXPO_EASEIN: 16, + EXPO_EASEOUT: 17, + EXPO_EASEINOUT: 18, - circEaseIn: 19, - eircEaseOut: 20, - circEaseInOut: 21, + CIRC_EASEIN: 19, + CIRC_EASEOUT: 20, + CIRC_EASEINOUT: 21, - elasticEaseIn: 22, - elasticEaseOut: 23, - elasticEaseInOut: 24, + ELASTIC_EASEIN: 22, + ELASTIC_EASEOUT: 23, + ELASTIC_EASEINOUT: 24, - backEaseIn: 25, - backEaseOut: 26, - backEaseInOut: 27, + BACK_EASEIN: 25, + BACK_EASEOUT: 26, + BACK_EASEINOUT: 27, - bounceEaseIn: 28, - bounceEaseOut: 29, - bounceEaseInOut: 30, + BOUNCE_EASEIN: 28, + BOUNCE_EASEOUT: 29, + BOUNCE_EASEINOUT: 30, - tweenEasingMax: 10000 + TWEEN_EASING_MAX: 10000 }; ccs.TweenFunction = ccs.TweenFunction || ccs.Class.extend({}); -ccs.M_PI_X_2 = Math.PI * 2; -ccs.M_PI_2 = Math.PI / 2; +ccs.DOUBLE_PI = ccs.M_PI_X_2 = Math.PI * 2; +ccs.HALF_PI = ccs.M_PI_2 = Math.PI / 2; ccs.M_PI = Math.PI; ccs.TweenFunction.tweenTo = function (time, type, easingParam) { var delta = 0; switch (type) { - case ccs.TweenType.customEasing: + case ccs.TweenType.CUSTOM_EASING: delta = this.customEase(time, easingParam); break; - case ccs.TweenType.linear: + case ccs.TweenType.LINEAR: delta = this.linear(time); break; - case ccs.TweenType.sineEaseIn: + case ccs.TweenType.SINE_EASEIN: delta = this.sineEaseIn(time); break; - case ccs.TweenType.sineEaseOut: + case ccs.TweenType.SINE_EASEOUT: delta = this.sineEaseOut(time); break; - case ccs.TweenType.sineEaseInOut: + case ccs.TweenType.SINE_EASEINOUT: delta = this.sineEaseInOut(time); break; - case ccs.TweenType.quadEaseIn: + case ccs.TweenType.QUAD_EASEIN: delta = this.quadEaseIn(time); break; - case ccs.TweenType.quadEaseOut: + case ccs.TweenType.QUAD_EASEOUT: delta = this.quadEaseOut(time); break; - case ccs.TweenType.quadEaseInOut: + case ccs.TweenType.QUAD_EASEINOUT: delta = this.quadEaseInOut(time); break; - case ccs.TweenType.cubicEaseIn: + case ccs.TweenType.CUBIC_EASEIN: delta = this.cubicEaseIn(time); break; - case ccs.TweenType.cubicEaseOut: + case ccs.TweenType.CUBIC_EASEOUT: delta = this.cubicEaseOut(time); break; - case ccs.TweenType.cubicEaseInOut: + case ccs.TweenType.CUBIC_EASEINOUT: delta = this.cubicEaseInOut(time); break; - case ccs.TweenType.quartEaseIn: + case ccs.TweenType.QUART_EASEIN: delta = this.quartEaseIn(time); break; - case ccs.TweenType.quartEaseOut: + case ccs.TweenType.QUART_EASEOUT: delta = this.quartEaseOut(time); break; - case ccs.TweenType.quartEaseInOut: + case ccs.TweenType.QUART_EASEINOUT: delta = this.quartEaseInOut(time); break; - case ccs.TweenType.quintEaseIn: + case ccs.TweenType.QUINT_EASEIN: delta = this.quintEaseIn(time); break; - case ccs.TweenType.quintEaseOut: + case ccs.TweenType.QUINT_EASEOUT: delta = this.quintEaseOut(time); break; - case ccs.TweenType.quintEaseInOut: + case ccs.TweenType.QUINT_EASEINOUT: delta = this.quintEaseInOut(time); break; - case ccs.TweenType.expoEaseIn: + case ccs.TweenType.EXPO_EASEIN: delta = this.expoEaseIn(time); break; - case ccs.TweenType.expoEaseOut: + case ccs.TweenType.EXPO_EASEOUT: delta = this.expoEaseOut(time); break; - case ccs.TweenType.expoEaseInOut: + case ccs.TweenType.EXPO_EASEINOUT: delta = this.expoEaseInOut(time); break; - case ccs.TweenType.circEaseIn: + case ccs.TweenType.CIRC_EASEIN: delta = this.circEaseIn(time); break; - case ccs.TweenType.eircEaseOut: + case ccs.TweenType.CIRC_EASEOUT: delta = this.circEaseOut(time); break; - case ccs.TweenType.circEaseInOut: + case ccs.TweenType.CIRC_EASEINOUT: delta = this.circEaseInOut(time); break; - case ccs.TweenType.elasticEaseIn: - delta = this.elasticEaseIn(time, easingParam); + case ccs.TweenType.ELASTIC_EASEIN: + var period = 0.3; + if(null != easingParam && easingParam.length > 0){ + period = easingParam[0]; + } + delta = this.elasticEaseIn(time, period); break; - case ccs.TweenType.elasticEaseOut: - delta = this.elasticEaseOut(time, easingParam); + case ccs.TweenType.ELASTIC_EASEOUT: + var period = 0.3; + if(null != easingParam && easingParam.length > 0){ + period = easingParam[0]; + } + delta = this.elasticEaseOut(time, period); break; - case ccs.TweenType.elasticEaseInOut: - delta = this.elasticEaseInOut(time, easingParam); + case ccs.TweenType.ELASTIC_EASEINOUT: + var period = 0.3; + if(null != easingParam && easingParam.length > 0){ + period = easingParam[0]; + } + delta = this.elasticEaseInOut(time, period); break; - case ccs.TweenType.backEaseIn: + case ccs.TweenType.BACK_EASEIN: delta = this.backEaseIn(time); break; - case ccs.TweenType.backEaseOut: + case ccs.TweenType.BACK_EASEOUT: delta = this.backEaseOut(time); break; - case ccs.TweenType.backEaseInOut: + case ccs.TweenType.BACK_EASEINOUT: delta = this.backEaseInOut(time); break; - case ccs.TweenType.bounceEaseIn: + case ccs.TweenType.BOUNCE_EASEIN: delta = this.bounceEaseIn(time); break; - case ccs.TweenType.bounceEaseOut: + case ccs.TweenType.BOUNCE_EASEOUT: delta = this.bounceEaseOut(time); break; - case ccs.TweenType.bounceEaseInOut: + case ccs.TweenType.BOUNCE_EASEINOUT: delta = this.bounceEaseInOut(time); break; @@ -206,10 +219,10 @@ ccs.TweenFunction.linear = function (time) { // Sine Ease ccs.TweenFunction.sineEaseIn = function (time) { - return -1 * Math.cos(time * ccs.M_PI_2) + 1; + return -1 * Math.cos(time * ccs.HALF_PI) + 1; }; ccs.TweenFunction.sineEaseOut = function (time) { - return Math.sin(time * ccs.M_PI_2); + return Math.sin(time * ccs.HALF_PI); }; ccs.TweenFunction.sineEaseInOut = function (time) { return -0.5 * (Math.cos(ccs.M_PI * time) - 1); @@ -285,10 +298,10 @@ ccs.TweenFunction.quintEaseInOut = function (time) { // Expo Ease ccs.TweenFunction.expoEaseIn = function (time) { - return time == 0 ? 0 : Math.pow(2, 10 * (time - 1)) - 0.001; + return time === 0 ? 0 : Math.pow(2, 10 * (time - 1)) - 0.001; }; ccs.TweenFunction.expoEaseOut = function (time) { - return time == 1 ? 1 : (-Math.pow(2, -10 * time) + 1); + return time === 1 ? 1 : (-Math.pow(2, -10 * time) + 1); }; ccs.TweenFunction.expoEaseInOut = function (time) { time /= 0.5; @@ -329,13 +342,13 @@ ccs.TweenFunction.elasticEaseIn = function (time, easingParam) { } var newT = 0; - if (time == 0 || time == 1) { + if (time === 0 || time === 1) { newT = time; } else { var s = period / 4; time = time - 1; - newT = -Math.pow(2, 10 * time) * Math.sin((time - s) * ccs.M_PI_X_2 / period); + newT = -Math.pow(2, 10 * time) * Math.sin((time - s) * ccs.DOUBLE_PI / period); } return newT; @@ -348,12 +361,12 @@ ccs.TweenFunction.elasticEaseOut = function (time, easingParam) { } var newT = 0; - if (time == 0 || time == 1) { + if (time === 0 || time === 1) { newT = time; } else { var s = period / 4; - newT = Math.pow(2, -10 * time) * Math.sin((time - s) * ccs.M_PI_X_2 / period) + 1; + newT = Math.pow(2, -10 * time) * Math.sin((time - s) * ccs.DOUBLE_PI / period) + 1; } return newT; @@ -366,7 +379,7 @@ ccs.TweenFunction.elasticEaseInOut = function (time, easingParam) { } var newT = 0; - if (time == 0 || time == 1) { + if (time === 0 || time === 1) { newT = time; } else { @@ -379,10 +392,9 @@ ccs.TweenFunction.elasticEaseInOut = function (time, easingParam) { time = time - 1; if (time < 0) { - newT = -0.5 * Math.pow(2, 10 * time) * Math.sin((time - s) * ccs.M_PI_X_2 / period); - } - else { - newT = Math.pow(2, -10 * time) * Math.sin((time - s) * ccs.M_PI_X_2 / period) * 0.5 + 1; + newT = -0.5 * Math.pow(2, 10 * time) * Math.sin((time - s) * ccs.DOUBLE_PI / period); + } else { + newT = Math.pow(2, -10 * time) * Math.sin((time - s) * ccs.DOUBLE_PI / period) * 0.5 + 1; } } return newT; @@ -442,8 +454,7 @@ ccs.TweenFunction.bounceEaseInOut = function (time) { if (time < 0.5) { time = time * 2; newT = (1 - ccs.bounceTime(1 - time)) * 0.5; - } - else { + } else { newT = ccs.bounceTime(time * 2 - 1) * 0.5 + 0.5; } @@ -458,4 +469,33 @@ ccs.TweenFunction.customEase = function (time, easingParam) { return easingParam[1] * tt * tt * tt + 3 * easingParam[3] * time * tt * tt + 3 * easingParam[5] * time * time * tt + easingParam[7] * time * time * time; } return time; +}; + +ccs.TweenFunction.easeIn = function(time, rate){ + return Math.pow(time, rate); +}; + +ccs.TweenFunction.easeOut = function(time, rate){ + return Math.pow(time, 1 / rate); +}; + +ccs.TweenFunction.easeInOut = function(time, rate){ + time *= 2; + if(time < 1){ + return 0.5 * Math.pow(time, rate); + }else{ + return 1 - 0.5 * Math.pow(2 - time, rate); + } +}; + +ccs.TweenFunction.quadraticIn = function(time){ + return Math.pow(time, 2); +}; + +ccs.TweenFunction.quadraticOut = function(time){ + return -time * (time - 2); +}; + +ccs.TweenFunction.bezieratFunction = function(a, b, c, d, t){ + return (Math.pow(1-t,3) * a + 3*t*(Math.pow(1-t,2))*b + 3*Math.pow(t,2)*(1-t)*c + Math.pow(t,3)*d ); }; \ No newline at end of file diff --git a/extensions/cocostudio/armature/utils/CCUtilMath.js b/extensions/cocostudio/armature/utils/CCUtilMath.js index b960b05754..082ec35b12 100644 --- a/extensions/cocostudio/armature/utils/CCUtilMath.js +++ b/extensions/cocostudio/armature/utils/CCUtilMath.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -36,13 +37,13 @@ var CC_SAFE_RELEASE = function (obj) { }; ccs.isSpriteContainPoint = function (sprite, point, outPoint) { - var p = cc.p(0, 0); + var p = sprite.convertToNodeSpace(point); if (outPoint) { - p = sprite.convertToNodeSpace(point); + outPoint.x = p.x; + outPoint.y = p.y; } var s = sprite.getContentSize(); - var r = cc.rect(0, 0, s.width, s.height); - return cc.rectContainsPoint(r, p); + return cc.rectContainsPoint(cc.rect(0, 0, s.width, s.height), p); }; ccs.SPRITE_CONTAIN_POINT = ccs.isSpriteContainPoint; ccs.SPRITE_CONTAIN_POINT_WITH_RETURN = ccs.isSpriteContainPoint; diff --git a/extensions/cocostudio/components/CCComAttribute.js b/extensions/cocostudio/components/CCComAttribute.js index 0b91d17cbe..0575b9334d 100644 --- a/extensions/cocostudio/components/CCComAttribute.js +++ b/extensions/cocostudio/components/CCComAttribute.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,26 +24,36 @@ ****************************************************************************/ /** - * Base class for ccs.ComAttribute + * The attribute component for Cocostudio. * @class * @extends ccs.Component */ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ _jsonDict: null, _filePath: "", + + /** + * Construction of ccs.ComAttribute + */ ctor: function () { cc.Component.prototype.ctor.call(this); this._jsonDict = {}; this._filePath = ""; this._name = "CCComAttribute"; + ccs.ComAttribute.prototype.init.call(this); }, + + /** + * Initializes a ccs.ComAttribute + * @returns {boolean} + */ init: function () { this._jsonDict = {}; return true; }, /** - * Set int attribute + * Sets int attribute * @param {String} key * @param {number} value */ @@ -55,7 +66,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Set double attribute + * Sets double attribute * @param {String} key * @param {number} value */ @@ -68,7 +79,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Set float attribute + * Sets float attribute * @param {String} key * @param {number} value */ @@ -81,7 +92,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Set boolean attribute + * Sets boolean attribute * @param {String} key * @param {Boolean} value */ @@ -94,7 +105,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Set string attribute + * Sets string attribute * @param {String} key * @param {Boolean} value */ @@ -107,7 +118,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Set object attribute + * Sets object attribute * @param {String} key * @param {Object} value */ @@ -120,7 +131,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get int value from attribute + * Returns int value from attribute * @param {String} key * @returns {Number} */ @@ -130,7 +141,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get double value from attribute + * Returns double value from attribute * @param {String} key * @returns {Number} */ @@ -140,7 +151,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get float value from attribute + * Returns float value from attribute * @param {String} key * @returns {Number} */ @@ -150,7 +161,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get boolean value from attribute + * Returns boolean value from attribute * @param {String} key * @returns {Boolean} */ @@ -160,7 +171,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get string value from attribute + * Returns string value from attribute * @param {String} key * @returns {String} */ @@ -170,7 +181,7 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * Get object value from attribute + * Returns object value from attribute * @param {String} key * @returns {Object} */ @@ -179,25 +190,21 @@ ccs.ComAttribute = ccs.Component.extend(/** @lends ccs.ComAttribute# */{ }, /** - * - * @param path + * Parses json file. + * @param filename */ - parse:function(path){ - this._jsonDict = cc.loader.getRes(path); + parse:function(filename){ + this._jsonDict = cc.loader.getRes(filename); } }); /** * allocates and initializes a ComAttribute. - * @constructs + * @deprecated since v3.0, please use new construction instead. * @return {ccs.ComAttribute} * @example * // example * var com = ccs.ComAttribute.create(); */ ccs.ComAttribute.create = function () { - var com = new ccs.ComAttribute(); - if (com && com.init()) { - return com; - } - return null; + return new ccs.ComAttribute(); }; \ No newline at end of file diff --git a/extensions/cocostudio/components/CCComAudio.js b/extensions/cocostudio/components/CCComAudio.js index a3868a7c78..0b15af0b9a 100644 --- a/extensions/cocostudio/components/CCComAudio.js +++ b/extensions/cocostudio/components/CCComAudio.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,29 +24,43 @@ ****************************************************************************/ /** - * Base class for ccs.ComAudio + * The audio component for Cocostudio. * @class * @extends ccs.Component */ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ _filePath: "", _loop: false, + + /** + * Construction of ccs.ComAudio + */ ctor: function () { cc.Component.prototype.ctor.call(this); this._name = "Audio"; + ccs.ComAudio.prototype.init.call(this); }, + + /** + * Initializes a ccs.ComAudio. + * @returns {boolean} + */ init: function () { return true; }, - onEnter: function () { - }, - + /** + * The callback calls when a audio component enter stage. + * @override + */ onExit: function () { this.stopBackgroundMusic(true); this.stopAllEffects(); }, + /** + * Stops all audios. + */ end: function () { cc.audioEngine.end(); }, @@ -60,8 +75,8 @@ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ /** * Play background music - * @param {String} pszFilePath - * @param {Boolean} loop + * @param {String} [pszFilePath] + * @param {Boolean} [loop] */ playBackgroundMusic: function (pszFilePath, loop) { if(pszFilePath){ @@ -150,16 +165,15 @@ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ /** * Play sound effect. - * @param {String} pszFilePath - * @param {Boolean} loop + * @param {String} [pszFilePath] + * @param {Boolean} [loop] * @returns {Boolean} */ playEffect: function (pszFilePath, loop) { - if (pszFilePath) { + if (pszFilePath) return cc.audioEngine.playEffect(pszFilePath, loop); - } else { + else return cc.audioEngine.playEffect(this._filePath, this._loop); - } }, /** @@ -234,7 +248,7 @@ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ }, /** - * Set loop + * Sets audio component whether plays loop * @param {Boolean} loop */ setLoop: function (loop) { @@ -242,7 +256,7 @@ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ }, /** - * File path Getter + * Returns the file path of audio component. * @returns {string} */ getFile: function () { @@ -250,25 +264,22 @@ ccs.ComAudio = ccs.Component.extend(/** @lends ccs.ComAudio# */{ }, /** - * Whether is loop + * Returns audio component whether plays loop * @returns {boolean} */ isLoop: function () { return this._loop; } }); + /** * allocates and initializes a ComAudio. - * @constructs + * @deprecated since v3.0, please use new construction instead. * @return {ccs.ComAudio} * @example * // example * var com = ccs.ComAudio.create(); */ ccs.ComAudio.create = function () { - var com = new ccs.ComAudio(); - if (com && com.init()) { - return com; - } - return null; + return new ccs.ComAudio(); }; \ No newline at end of file diff --git a/extensions/cocostudio/components/CCComController.js b/extensions/cocostudio/components/CCComController.js index 1f2c7ead72..cdd85eeb94 100644 --- a/extensions/cocostudio/components/CCComController.js +++ b/extensions/cocostudio/components/CCComController.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,32 +24,31 @@ ****************************************************************************/ /** - * Base class for ccs.ComController + * The controller component for Cocostudio. * @class * @extends ccs.Component */ ccs.ComController = ccs.Component.extend(/** @lends ccs.ComController# */{ + /** + * Construction of ccs.ComController. + */ ctor: function () { cc.Component.prototype.ctor.call(this); this._name = "ComController"; - }, - init: function () { - return true; + ccs.ComController.prototype.init.call(this); }, + /** + * The callback calls when controller component enter stage. + * @override + */ onEnter: function () { - - }, - - onExit: function () { - - }, - - update: function (dt) { + if (this._owner !== null) + this._owner.scheduleUpdate(); }, /** - * Enabled getter + * Returns controller component whether is enabled * @returns {Boolean} */ isEnabled: function () { @@ -56,25 +56,21 @@ ccs.ComController = ccs.Component.extend(/** @lends ccs.ComController# */{ }, /** - * Enabled setter + * Sets controller component whether is enabled * @param {Boolean} bool */ setEnabled: function (bool) { - this._enabled = b; + this._enabled = bool; } }); /** - * allocates and initializes a ComController. - * @constructs + * Allocates and initializes a ComController. + * @deprecated since v3.0, please use new construction instead. * @return {ccs.ComController} * @example * // example * var com = ccs.ComController.create(); */ ccs.ComController.create = function () { - var com = new ccs.ComController(); - if (com && com.init()) { - return com; - } - return null; + return new ccs.ComController(); }; \ No newline at end of file diff --git a/extensions/cocostudio/components/CCComRender.js b/extensions/cocostudio/components/CCComRender.js index 5626d03ba8..960e096a11 100644 --- a/extensions/cocostudio/components/CCComRender.js +++ b/extensions/cocostudio/components/CCComRender.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,24 +24,36 @@ ****************************************************************************/ /** - * Base class for ccs.ComRender + * The render component for Cocostudio. * @class * @extends ccs.Component */ ccs.ComRender = ccs.Component.extend(/** @lends ccs.ComRender# */{ _render: null, + /** + * Construction of ccs.ComRender + * @param {cc.Node} node + * @param {String} comName + */ ctor: function (node, comName) { cc.Component.prototype.ctor.call(this); this._render = node; this._name = comName; + this.isRenderer = true; + ccs.ComRender.prototype.init.call(this); }, + /** + * The callback calls when a render component enter stage. + */ onEnter: function () { - if (this._owner) { + if (this._owner) this._owner.addChild(this._render); - } }, + /** + * The callback calls when a render component exit stage. + */ onExit: function () { if (this._owner) { this._owner.removeChild(this._render, true); @@ -49,7 +62,7 @@ ccs.ComRender = ccs.Component.extend(/** @lends ccs.ComRender# */{ }, /** - * Node getter + * Returns a render node * @returns {cc.Node} */ getNode: function () { @@ -57,25 +70,22 @@ ccs.ComRender = ccs.Component.extend(/** @lends ccs.ComRender# */{ }, /** - * Node setter + * Sets a render node to component. * @param {cc.Node} node */ setNode: function (node) { this._render = node; } }); + /** * allocates and initializes a ComRender. - * @constructs + * @deprecated since v3.0, please use new construction instead. * @return {ccs.ComRender} * @example * // example * var com = ccs.ComRender.create(); */ ccs.ComRender.create = function (node, comName) { - var com = new ccs.ComRender(node, comName); - if (com && com.init()) { - return com; - } - return null; + return new ccs.ComRender(node, comName); }; diff --git a/extensions/cocostudio/components/CCComponent.js b/extensions/cocostudio/components/CCComponent.js index e444b2da0e..5084a9744a 100644 --- a/extensions/cocostudio/components/CCComponent.js +++ b/extensions/cocostudio/components/CCComponent.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -32,57 +33,103 @@ cc.Component = cc.Class.extend(/** @lends cc.Component# */{ _name: "", _enabled: true, + /** + * Construction of cc.Component + */ ctor:function(){ this._owner = null; this._name = ""; this._enabled = true; }, + /** + * Initializes a cc.Component. + * @returns {boolean} + */ init:function(){ return true; }, + /** + * The callback when a component enter stage. + */ onEnter:function(){ - }, + /** + * The callback when a component exit stage. + */ onExit:function(){ - }, + /** + * The callback per every frame if it schedules update. + * @param delta + */ update:function(delta){ - }, + /** + * Serialize a component object. + * @param reader + */ serialize:function( reader){ - }, + /** + * Returns component whether is enabled. + * @returns {boolean} + */ isEnabled:function(){ return this._enabled; }, + /** + * Sets component whether is enabled. + * @param enable + */ setEnabled:function(enable){ this._enabled = enable; }, + /** + * Returns the name of cc.Component. + * @returns {string} + */ getName:function(){ return this._name; } , + /** + * Sets the name to cc.Component. + * @param {String} name + */ setName:function(name){ this._name = name; } , + /** + * Sets the owner to cc.Component. + * @param owner + */ setOwner:function(owner){ this._owner = owner; }, + /** + * Returns the owner of cc.Component. + * @returns {*} + */ getOwner:function(){ return this._owner; } }); +/** + * Allocates and initializes a component. + * @deprecated since v3.0, please use new construction instead. + * @return {cc.Component} + */ cc.Component.create = function(){ return new cc.Component(); }; diff --git a/extensions/cocostudio/components/CCComponentContainer.js b/extensions/cocostudio/components/CCComponentContainer.js index 470561f3ed..c82103e7ee 100644 --- a/extensions/cocostudio/components/CCComponentContainer.js +++ b/extensions/cocostudio/components/CCComponentContainer.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -23,7 +24,7 @@ ****************************************************************************/ /** - * The container of cc.Component + * The component container for Cocostudio, it has some components. * @class * @extends cc.Class */ @@ -31,18 +32,35 @@ cc.ComponentContainer = cc.Class.extend(/** @lends cc.ComponentContainer# */{ _components:null, _owner:null, + /** + * Construction of cc.ComponentContainer + * @param node + */ ctor:function(node){ this._components = null; this._owner = node; }, + /** + * Gets component by name. + * @param name + * @returns {*} + */ getComponent:function(name){ if(!name) throw "cc.ComponentContainer.getComponent(): name should be non-null"; name = name.trim(); + if(!this._components){ + this._components = {}; + } return this._components[name]; }, + /** + * Adds a component to container + * @param {cc.Component} component + * @returns {boolean} + */ add:function(component){ if(!component) throw "cc.ComponentContainer.add(): component should be non-null"; @@ -67,8 +85,8 @@ cc.ComponentContainer = cc.Class.extend(/** @lends cc.ComponentContainer# */{ }, /** - * - * @param {String|cc.Component} name + * Removes component from container by name or component object. + * @param {String|cc.Component} name component name or component object. * @returns {boolean} */ remove:function(name){ @@ -76,16 +94,16 @@ cc.ComponentContainer = cc.Class.extend(/** @lends cc.ComponentContainer# */{ throw "cc.ComponentContainer.remove(): name should be non-null"; if(!this._components) return false; - if(name instanceof cc.Component){ + if(name instanceof cc.Component) return this._removeByComponent(name); - }else{ + else { name = name.trim(); return this._removeByComponent(this._components[name]); } }, _removeByComponent:function(component){ - if(component) + if(!component) return false; component.onExit(); component.setOwner(null); @@ -93,10 +111,12 @@ cc.ComponentContainer = cc.Class.extend(/** @lends cc.ComponentContainer# */{ return true; }, + /** + * Removes all components of container. + */ removeAll:function(){ if(!this._components) return; - var locComponents = this._components; for(var selKey in locComponents){ var selComponent = locComponents[selKey]; @@ -112,24 +132,27 @@ cc.ComponentContainer = cc.Class.extend(/** @lends cc.ComponentContainer# */{ this._components = {}; }, + /** + * Visit callback by director. it calls every frame. + * @param {Number} delta + */ visit:function(delta){ if(!this._components) return; var locComponents = this._components; - for(var selKey in locComponents){ + for(var selKey in locComponents) locComponents[selKey].update(delta); - } }, - isEmpty:function(){ - if(!this._components) + /** + * Returns the container whether is empty. + * @returns {boolean} + */ + isEmpty: function () { + if (!this._components) return true; - - for(var selkey in this._components){ - return false; - } - return true; + return this._components.length === 0; } }); diff --git a/extensions/cocostudio/loader/load.js b/extensions/cocostudio/loader/load.js new file mode 100644 index 0000000000..751ee53918 --- /dev/null +++ b/extensions/cocostudio/loader/load.js @@ -0,0 +1,223 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +ccs._load = (function(){ + + /** + * load file + * @param {String} file + * @param {String} [type=] - ccui|node|action + * @param {String} [path=] - Resource search path + * @returns {*} + */ + var load = function(file, type, path){ + + var json = cc.loader.getRes(file); + + if(!json) + return cc.log("%s does not exist", file); + var ext = extname(file).toLocaleLowerCase(); + if(ext !== "json" && ext !== "exportjson") + return cc.log("%s load error, must be json file", file); + + var parse; + if(!type){ + if(json["widgetTree"]) + parse = parser["ccui"]; + else if(json["nodeTree"]) + parse = parser["timeline"]; + else if(json["Content"] && json["Content"]["Content"]) + parse = parser["timeline"]; + else if(json["gameobjects"]) + parse = parser["scene"]; + }else{ + parse = parser[type]; + } + + if(!parse){ + cc.log("Can't find the parser : %s", file); + return new cc.Node(); + } + var version = json["version"] || json["Version"]; + if(!version && json["armature_data"]){ + cc.warn("%s is armature. please use:", file); + cc.warn(" ccs.armatureDataManager.addArmatureFileInfoAsync(%s);", file); + cc.warn(" var armature = new ccs.Armature('name');"); + return new cc.Node(); + } + var currentParser = getParser(parse, version); + if(!currentParser){ + cc.log("Can't find the parser : %s", file); + return new cc.Node(); + } + + return currentParser.parse(file, json, path) || null; + }; + + var parser = { + "ccui": {}, + "timeline": {}, + "action": {}, + "scene": {} + }; + + load.registerParser = function(name, version, target){ + if(!name || !version || !target) + return cc.log("register parser error"); + if(!parser[name]) + parser[name] = {}; + parser[name][version] = target; + }; + + load.getParser = function(name, version){ + if(name && version) + return parser[name] ? parser[name][version] : undefined; + if(name) + return parser[name]; + return parser; + }; + + //Gets the file extension + var extname = function(fileName){ + var arr = fileName.match(extnameReg); + return ( arr && arr[1] ) ? arr[1] : null; + }; + var extnameReg = /\.([^\.]+)$/; + + + var parserReg = /([^\.](\.\*)?)*$/; + var getParser = function(parser, version){ + if(parser[version]) + return parser[version]; + else if(version === "*") + return null; + else + return getParser(parser, version.replace(parserReg, "*")); + }; + + return load; + +})(); + +ccs._parser = cc.Class.extend({ + + ctor: function(){ + this.parsers = {}; + }, + + _dirnameReg: /\S*\//, + _dirname: function(path){ + var arr = path.match(this._dirnameReg); + return (arr && arr[0]) ? arr[0] : ""; + }, + + getClass: function(json){ + return json["classname"]; + }, + + getNodeJson: function(json){ + return json["widgetTree"]; + }, + + parse: function(file, json){ + var resourcePath = this._dirname(file); + this.pretreatment(json, resourcePath); + var node = this.parseNode(this.getNodeJson(json), resourcePath, file); + node && this.deferred(json, resourcePath, node, file); + return node; + }, + + pretreatment: function(json, resourcePath, file){}, + + deferred: function(json, resourcePath, node, file){}, + + parseNode: function(json, resourcePath){ + var parser = this.parsers[this.getClass(json)]; + var widget = null; + if(parser) + widget = parser.call(this, json, resourcePath); + else + cc.log("Can't find the parser : %s", this.getClass(json)); + + return widget; + }, + + registerParser: function(widget, parse){ + this.parsers[widget] = parse; + } +}); + +/** + * Analysis of studio JSON file + * The incoming file name, parse out the corresponding object + * Temporary support file list: + * ui 1.* + * node 1.* - 2.* + * action 1.* - 2.* + * scene 0.* - 1.* + * @param {String} file + * @param {String} [path=] Resource path + * @returns {{node: cc.Node, action: cc.Action}} + */ +ccs.load = function(file, path){ + var object = { + node: null, + action: null + }; + + object.node = ccs._load(file, null, path); + object.action = ccs._load(file, "action", path); + if(object.action && object.action.tag === -1 && object.node) + object.action.tag = object.node.tag; + return object; +}; + +//Forward compatible interface + +ccs.actionTimelineCache = { + + + //@deprecated This function will be deprecated sooner or later please use ccs.load + /** + * Create Timeline Action + * @param file + * @returns {*} + */ + createAction: function(file){ + return ccs._load(file, "action"); + } +}; + +ccs.csLoader = { + + //@deprecated This function will be deprecated sooner or later please use ccs.load + /** + * Create Timeline Node + * @param file + * @returns {*} + */ + createNode: function(file){ + return ccs._load(file); + } +}; diff --git a/extensions/cocostudio/loader/parsers/action-1.x.js b/extensions/cocostudio/loader/parsers/action-1.x.js new file mode 100644 index 0000000000..6bcebf2734 --- /dev/null +++ b/extensions/cocostudio/loader/parsers/action-1.x.js @@ -0,0 +1,238 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var cache = {}; + + var Parser = baseParser.extend({ + + getNodeJson: function(json){ + return json["action"]; + }, + + parseNode: function(json, resourcePath, file){ + if(!json) + return null; + if(cache[file]) + return cache[file].clone(); + + var self = this, + action = new ccs.ActionTimeline(); + + action.setDuration(json["duration"]); + action.setTimeSpeed(json["speed"] || 1); + //The process of analysis + var timelines = json["timelines"]; + timelines.forEach(function(timeline){ + var parser = self.parsers[timeline["frameType"]]; + var frame; + if(parser) + frame = parser.call(self, timeline, resourcePath); + else + cc.log("parser does not exist : %s", timeline["frameType"]); + if(frame) + action.addTimeline(frame); + + if(timeline["frameType"] === "ColorFrame"){ + action.addTimeline( + self.parsers["AlphaFrame"].call(self, timeline, resourcePath) + ); + } + }); + + cache[file] = action; + cache[file].retain(); + return action.clone(); + } + + }); + + var parser = new Parser(); + + var frameList = [ + { + name: "PositionFrame", + handle: function(options){ + var frame = new ccs.PositionFrame(); + var x = options["x"]; + var y = options["y"]; + frame.setPosition(cc.p(x,y)); + return frame; + } + }, + { + name: "VisibleFrame", + handle: function(options){ + var frame = new ccs.VisibleFrame(); + var visible = options["value"]; + frame.setVisible(visible); + return frame; + } + }, + { + name: "ScaleFrame", + handle: function(options){ + var frame = new ccs.ScaleFrame(); + var scalex = options["x"]; + var scaley = options["y"]; + frame.setScaleX(scalex); + frame.setScaleY(scaley); + return frame; + } + }, + { + name: "RotationFrame", + handle: function(options){ + var frame = new ccs.RotationFrame(); + var rotation = options["rotation"]; + frame.setRotation(rotation); + return frame; + } + }, + { + name: "SkewFrame", + handle: function(options){ + var frame = new ccs.SkewFrame(); + var skewx = options["x"]; + var skewy = options["y"]; + frame.setSkewX(skewx); + frame.setSkewY(skewy); + return frame; + } + }, + { + name: "RotationSkewFrame", + handle: function(options){ + var frame = new ccs.RotationSkewFrame(); + var skewx = options["x"]; + var skewy = options["y"]; + frame.setSkewX(skewx); + frame.setSkewY(skewy); + return frame; + } + }, + { + name: "AnchorFrame", + handle: function(options){ + var frame = new ccs.AnchorPointFrame(); + var anchorx = options["x"]; + var anchory = options["y"]; + frame.setAnchorPoint(cc.p(anchorx, anchory)); + return frame; + } + }, + { + name: "InnerActionFrame", + handle: function(options){ + var frame = new ccs.InnerActionFrame(); + var type = options["innerActionType"]; + var startFrame = options["startFrame"]; + frame.setInnerActionType(type); + frame.setStartFrameIndex(startFrame); + return frame; + } + }, + { + name: "ColorFrame", + handle: function(options){ + var frame = new ccs.ColorFrame(); + var red = options["red"]; + var green = options["green"]; + var blue = options["blue"]; + frame.setColor(cc.color(red, green, blue)); + var alphaFrame = new ccs.AlphaFrame(); + var alpha = options["alpha"]; + alphaFrame.setAlpha(alpha); + return frame; + } + }, + { + name: "AlphaFrame", + handle: function(options){ + var frame = new ccs.AlphaFrame(); + var alpha = options["alpha"]; + frame.setAlpha(alpha); + return frame; + } + }, + { + name: "TextureFrame", + handle: function(options){ + var frame = new ccs.TextureFrame(); + var texture = options["value"]; + if(texture != null) { + var path = texture; + var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path); + if(spriteFrame == null){ + var jsonPath = ccs.csLoader.getJsonPath(); + path = jsonPath + texture; + } + frame.setTextureName(path); + } + return frame; + } + }, + { + name: "EventFrame", + handle: function(options){ + var frame = new ccs.EventFrame(); + var evnt = options["value"]; + if(evnt != null) + frame.setEvent(evnt); + return frame; + } + }, + { + name: "ZOrderFrame", + handle: function(options){ + var frame = new ccs.ZOrderFrame(); + var zorder = options["value"]; + frame.setZOrder(zorder); + return frame; + } + } + ]; + + frameList.forEach(function(item){ + parser.registerParser(item.name, function(options, resourcePath){ + var timeline = new ccs.Timeline(); + timeline.setActionTag(options["actionTag"]); + + var frames = options["frames"]; + if(frames && frames.length){ + frames.forEach(function(frameData){ + var frame = item.handle(frameData); + frame.setFrameIndex(frameData["frameIndex"]); + frame.setTween(frameData["tween"]); + timeline.addFrame(frame); + }); + } + return timeline; + }); + }); + + load.registerParser("action", "*", parser); + +})(ccs._load, ccs._parser); diff --git a/extensions/cocostudio/loader/parsers/action-2.x.js b/extensions/cocostudio/loader/parsers/action-2.x.js new file mode 100644 index 0000000000..3329106e25 --- /dev/null +++ b/extensions/cocostudio/loader/parsers/action-2.x.js @@ -0,0 +1,285 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var cache = {}; + + var Parser = baseParser.extend({ + + getNodeJson: function(json){ + return json["Content"]["Content"]["Animation"]; + }, + + parseNode: function(json, resourcePath, file){ + if(!json) + return null; + if(cache[file]) + return cache[file].clone(); + + var self = this, + action = new ccs.ActionTimeline(); + + action.setDuration(json["Duration"]); + action.setTimeSpeed(json["Speed"] || 1); + + //The process of analysis + var timelines = json["Timelines"]; + timelines.forEach(function(timeline){ + var parser = self.parsers[timeline["Property"]]; + var frame; + if(parser) + frame = parser.call(self, timeline, resourcePath); + else + cc.log("parser does not exist : %s", timeline["Property"]); + if(frame) + action.addTimeline(frame); + }); + + cache[file] = action; + cache[file].retain(); + return action.clone(); + }, + + deferred: function(json, resourcePath, action, file){ + var animationlist = json["Content"]["Content"]["AnimationList"]; + var length = animationlist ? animationlist.length : 0; + for (var i = 0; i < length; i++){ + var animationdata = animationlist[i]; + var info = { name: null, startIndex: null, endIndex: null }; + info.name = animationdata["Name"]; + info.startIndex = animationdata["StartIndex"]; + info.endIndex = animationdata["EndIndex"]; + action.addAnimationInfo(info); + } + } + + }); + var parser = new Parser(); + + var frameList = [ + { + name: "Position", + handle: function(options){ + var frame = new ccs.PositionFrame(); + var x = options["X"]; + var y = options["Y"]; + frame.setPosition(cc.p(x,y)); + return frame; + } + }, + { + name: "VisibleForFrame", + handle: function(options){ + var frame = new ccs.VisibleFrame(); + var visible = options["Value"]; + frame.setVisible(visible); + return frame; + } + }, + { + name: "Scale", + handle: function(options){ + var frame = new ccs.ScaleFrame(); + var scalex = options["X"]; + var scaley = options["Y"]; + frame.setScaleX(scalex); + frame.setScaleY(scaley); + return frame; + } + }, + { + name: "Rotation", + handle: function(options){ + var frame = new ccs.RotationFrame(); + var rotation = options["Rotation"]; + frame.setRotation(rotation); + return frame; + } + }, + { + name: "Skew", + handle: function(options){ + var frame = new ccs.SkewFrame(); + var skewx = options["X"]; + var skewy = options["Y"]; + frame.setSkewX(skewx); + frame.setSkewY(skewy); + return frame; + } + }, + { + name: "RotationSkew", + handle: function(options){ + var frame = new ccs.RotationSkewFrame(); + var skewx = options["X"]; + var skewy = options["Y"]; + frame.setSkewX(skewx); + frame.setSkewY(skewy); + return frame; + } + }, + { + name: "Anchor", + handle: function(options){ + var frame = new ccs.AnchorPointFrame(); + var anchorx = options["X"]; + var anchory = options["Y"]; + frame.setAnchorPoint(cc.p(anchorx, anchory)); + return frame; + } + }, + { + name: "InnerAction", + handle: function(options){ + var frame = new ccs.InnerActionFrame(); + var type = options["InnerActionType"]; + var startFrame = options["StartFrame"]; + frame.setInnerActionType(type); + frame.setStartFrameIndex(startFrame); + return frame; + } + }, + { + name: "CColor", + handle: function(options){ + var frame = new ccs.ColorFrame(); + var color = options["Color"]; + if(!color) color = {}; + color["R"] = color["R"] || 255; + color["G"] = color["G"] || 255; + color["B"] = color["B"] || 255; + frame.setColor(cc.color(color["R"], color["G"], color["B"])); + return frame; + } + }, + { + name: "Alpha", + handle: function(options){ + var frame = new ccs.AlphaFrame(); + var alpha = options["Value"]; + frame.setAlpha(alpha); + return frame; + } + }, + { + name: "FileData", + handle: function(options, resourcePath){ + var frame = new ccs.TextureFrame(); + var texture = options["TextureFile"]; + if(texture != null) { + var path = texture["Path"]; + var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path); + if(spriteFrame == null){ + path = resourcePath + path; + } + frame.setTextureName(path); + } + return frame; + } + }, + { + name: "FrameEvent", + handle: function(options){ + var frame = new ccs.EventFrame(); + var evnt = options["Value"]; + if(evnt != null) + frame.setEvent(evnt); + return frame; + } + }, + { + name: "ZOrder", + handle: function(options){ + var frame = new ccs.ZOrderFrame(); + var zorder = options["Value"]; + frame.setZOrder(zorder); + return frame; + } + }, + { + name: "ActionValue", + handle: function (options) { + + var frame = new ccs.InnerActionFrame(); + var innerActionType = options["InnerActionType"]; + + var currentAnimationFrame = options["CurrentAniamtionName"]; + + var singleFrameIndex = options["SingleFrameIndex"]; + + var frameIndex = options["FrameIndex"]; + if(frameIndex !== undefined) + frame.setFrameIndex(frameIndex); + + frame.setInnerActionType(ccs.InnerActionType[innerActionType]); + frame.setSingleFrameIndex(singleFrameIndex); + + frame.setEnterWithName(true); + if (currentAnimationFrame) + frame.setAnimationName(currentAnimationFrame); + + return frame; + } + } + ]; + + var loadEasingDataWithFlatBuffers = function(frame, options){ + var type = options["Type"]; + frame.setTweenType(type); + var points = options["Points"]; + if(points){ + points = points.map(function(p){ + return cc.p(p["X"], p["Y"]); + }); + frame.setEasingParams(points); + } + }; + + frameList.forEach(function(item){ + parser.registerParser(item.name, function(options, resourcePath){ + var timeline = new ccs.Timeline(); + timeline.setActionTag(options["ActionTag"]); + + var frames = options["Frames"]; + if(frames && frames.length){ + frames.forEach(function(frameData){ + var frame = item.handle(frameData, resourcePath); + frame.setFrameIndex(frameData["FrameIndex"]); + var tween = frameData["Tween"] != null ? frameData["Tween"] : true; + frame.setTween(tween); + //https://github.com/cocos2d/cocos2d-x/pull/11388/files + var easingData = frameData["EasingData"]; + if(easingData) + loadEasingDataWithFlatBuffers(frame, easingData); + timeline.addFrame(frame); + }); + } + return timeline; + }); + }); + + load.registerParser("action", "2.*", parser); + +})(ccs._load, ccs._parser); diff --git a/extensions/cocostudio/loader/parsers/compatible.js b/extensions/cocostudio/loader/parsers/compatible.js new file mode 100644 index 0000000000..caa681d4fc --- /dev/null +++ b/extensions/cocostudio/loader/parsers/compatible.js @@ -0,0 +1,251 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + + +/* + This file is for compatibility compatibility with older versions of GUIReader and SceneReader + todo: deprecated all + */ + +(function(){ + + ccs.uiReader = { + + _fileDesignSizes: {}, + + //@deprecated This function will be deprecated sooner or later please use ccs.load + /** + * Create CCUI Node + * @param file + * @returns {*} + */ + widgetFromJsonFile: function(file){ + var json = cc.loader.getRes(file); + if(json) + this._fileDesignSizes[file] = cc.size(json["designWidth"]||0, json["designHeight"]||0); + + var version = json["Version"] || json["version"]; + var versionNum = ccs.uiReader.getVersionInteger(version); + if(!version || versionNum >= 1700){ + cc.warn("Not supported file types, Please try use the ccs.load"); + return null; + } + return ccs._load(file, "ccui"); + }, + + //@deprecated This function will be deprecated sooner or later please use parser.registerParser + /** + * Register a custom Widget reader + * @param classType + * @param ins + * @param object + * @param callback + * @deprecated This function will be deprecated sooner or later please use parser.registerParser + */ + registerTypeAndCallBack: function(classType, ins, object, callback){ + var parser = ccs._load.getParser("ccui")["*"]; + var func = callback.bind(object); + parser.registerParser(classType, function(options, resourcePath){ + var widget = new ins(); + var uiOptions = options["options"]; + object.setPropsFromJsonDictionary && object.setPropsFromJsonDictionary(widget, uiOptions); + this.generalAttributes(widget, uiOptions); + var customProperty = uiOptions["customProperty"]; + if(customProperty) + customProperty = JSON.parse(customProperty); + else + customProperty = {}; + func(classType, widget, customProperty); + this.colorAttributes(widget, uiOptions); + this.anchorPointAttributes(widget, uiOptions); + this.parseChild.call(this, widget, options, resourcePath); + return widget; + }); + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Gets the version number by version string. + * @param {String} version version string. + * @returns {Number} + */ + getVersionInteger: function(version){ + if(!version || typeof version !== "string") return 0; + var arr = version.split("."); + if (arr.length !== 4) + return 0; + var num = 0; + arr.forEach(function(n, i){ + num += n * Math.pow(10, 3 - i); + }); + return num; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * stores the designSize of UI file. + * @param {String} fileName + * @param {cc.Size} size + */ + storeFileDesignSize: function (fileName, size) { + this._fileDesignSizes[fileName] = size; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Gets the design size by filename. + * @param {String} fileName + * @returns {cc.Size} + */ + getFileDesignSize: function (fileName) { + return this._fileDesignSizes[fileName]; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Returns the file path + * @returns {string} + */ + getFilePath: function(){ + return this._filePath; + }, + + //@deprecated This function will be deprecated sooner or later + setFilePath: function(path){ + this._filePath = path; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Returns the parsed object map. (analytic function) + * @returns {Object} + */ + getParseObjectMap: function(){ + return ccs._load.getParser("ccui")["*"]["parsers"]; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Returns the parsed callback map. (analytic function) + * @returns {*} + */ + getParseCallBackMap: function(){ + return ccs._load.getParser("ccui")["*"]["parsers"]; + }, + + //@deprecated This function will be deprecated sooner or later + clear: function(){} + }; + + var parser = ccs._load.getParser("ccui")["*"]; + ccs.imageViewReader = {setPropsFromJsonDictionary: parser.ImageViewAttributes}; + ccs.buttonReader = {setPropsFromJsonDictionary: parser.ButtonAttributes}; + ccs.checkBoxReader = {setPropsFromJsonDictionary: parser.CheckBoxAttributes}; + ccs.labelAtlasReader = {setPropsFromJsonDictionary: parser.TextAtlasAttributes}; + ccs.labelBMFontReader= {setPropsFromJsonDictionary: parser.TextBMFontAttributes}; + ccs.labelReader = {setPropsFromJsonDictionary: parser.TextAttributes}; + ccs.layoutReader = {setPropsFromJsonDictionary: parser.LayoutAttributes}; + ccs.listViewReader = {setPropsFromJsonDictionary: parser.ListViewAttributes}; + ccs.loadingBarReader = {setPropsFromJsonDictionary: parser.LoadingBarAttributes}; + ccs.pageViewReader = {setPropsFromJsonDictionary: parser.PageViewAttributes}; + ccs.scrollViewReader = {setPropsFromJsonDictionary: parser.ScrollViewAttributes}; + ccs.sliderReader = {setPropsFromJsonDictionary: parser.SliderAttributes}; + ccs.textFieldReader = {setPropsFromJsonDictionary: parser.TextFieldAttributes}; +})(); + +(function(){ + ccs.sceneReader = { + + _node: null, + + //@deprecated This function will be deprecated sooner or later please use ccs.load + /** + * Create Scene Node + * @param file + * @returns {*} + */ + createNodeWithSceneFile: function(file){ + var node = ccs._load(file, "scene"); + this._node = node; + return node; + }, + + /** + * Get a node by tag. + * @param {Number} tag + * @returns {cc.Node|null} + */ + getNodeByTag: function(tag){ + if (this._node == null) + return null; + if (this._node.getTag() === tag) + return this._node; + return this._nodeByTag(this._node, tag); + }, + + _nodeByTag: function (parent, tag) { + if (parent == null) + return null; + var retNode = null; + var children = parent.getChildren(); + for (var i = 0; i < children.length; i++) { + var child = children[i]; + if (child && child.getTag() === tag) { + retNode = child; + break; + } else { + retNode = this._nodeByTag(child, tag); + if (retNode) + break; + } + } + return retNode; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Returns the version of ccs.SceneReader. + * @returns {string} + */ + version: function(){ + return "*"; + }, + + //@deprecated This function will be deprecated sooner or later + /** + * Sets the listener to reader. + * Cannot use + */ + setTarget: function(){}, + + //@deprecated This function will be deprecated sooner or later + /** + * Clear all triggers and stops all sounds. + */ + clear: function(){ + ccs.triggerManager.removeAll(); + cc.audioEngine.end(); + } + }; +})(); \ No newline at end of file diff --git a/extensions/cocostudio/loader/parsers/scene-1.x.js b/extensions/cocostudio/loader/parsers/scene-1.x.js new file mode 100644 index 0000000000..04569cb17f --- /dev/null +++ b/extensions/cocostudio/loader/parsers/scene-1.x.js @@ -0,0 +1,262 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var Parser = baseParser.extend({ + + getNodeJson: function(json){ + return json; + }, + + parseNode: function(json, resourcePath){ + var parser = this.parsers[this.getClass(json)]; + var node = null; + if(parser) + node = parser.call(this, json, resourcePath); + else + cc.log("Can't find the parser : %s", this.getClass(json)); + + return node; + }, + + deferred: function(json, resourcePath, node, file){ + ccs.triggerManager.parse(json["Triggers"]||[]); + if(ccs.sceneReader) + ccs.sceneReader._node = node; + }, + + setPropertyFromJsonDict: function(node, json){ + var x = (cc.isUndefined(json["x"]))?0:json["x"]; + var y = (cc.isUndefined(json["y"]))?0:json["y"]; + node.setPosition(x, y); + + var bVisible = Boolean((cc.isUndefined(json["visible"]))?1:json["visible"]); + node.setVisible(bVisible); + + var nTag = (cc.isUndefined(json["objecttag"]))?-1:json["objecttag"]; + node.setTag(nTag); + + var nZorder = (cc.isUndefined(json["zorder"]))?0:json["zorder"]; + node.setLocalZOrder(nZorder); + + var fScaleX = (cc.isUndefined(json["scalex"]))?1:json["scalex"]; + var fScaleY = (cc.isUndefined(json["scaley"]))?1:json["scaley"]; + node.setScaleX(fScaleX); + node.setScaleY(fScaleY); + + var fRotationZ = (cc.isUndefined(json["rotation"]))?0:json["rotation"]; + node.setRotation(fRotationZ); + + var sName = json["name"] || ""; + node.setName(sName); + } + + }); + + var parser = new Parser(); + + parser.parseChild = function(node, objects, resourcePath){ + for (var i = 0; i < objects.length; i++) { + var child, + options = objects[i]; + if(options) + child = this.parseNode(options, resourcePath); + if(child) + node.addChild(child); + } + }; + + var componentsParser = { + "CCSprite": function(node, component, resourcePath){ + var child = new cc.Sprite(); + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0) + child.setTexture(path); + else if(type === 1){ + var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path); + child.setSpriteFrame(spriteFrame); + } + }); + var render = new ccs.ComRender(child, "CCSprite"); + node.addComponent(render); + return render; + }, + "CCTMXTiledMap": function(node, component, resourcePath){ + var child = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0) + child = new cc.TMXTiledMap(path); + }); + var render = new ccs.ComRender(child, "CCTMXTiledMap"); + node.addComponent(render); + return render; + }, + "CCParticleSystemQuad": function(node, component, resourcePath){ + var child = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0) + child = new cc.ParticleSystem(path); + else + cc.log("unknown resourcetype on CCParticleSystemQuad!"); + child.setPosition(0, 0); + }); + var render = new ccs.ComRender(child, "CCParticleSystemQuad"); + node.addComponent(render); + return render; + }, + "CCArmature": function(node, component, resourcePath){ + var child = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0){ + var jsonDict = cc.loader.getRes(path); + if (!jsonDict) cc.log("Please load the resource [%s] first!", path); + var armature_data = jsonDict["armature_data"]; + var subData = armature_data[0]; + var name = subData["name"]; + ccs.armatureDataManager.addArmatureFileInfo(path); + child = new ccs.Armature(name); + } + }); + if(child){ + var render = new ccs.ComRender(child, "CCArmature"); + node.addComponent(render); + var actionName = component["selectedactionname"]; + if (actionName && child.getAnimation()) + child.getAnimation().play(actionName); + + return render; + } + + }, + "CCComAudio": function(node, component, resourcePath){ + var audio = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0){ + audio = new ccs.ComAudio(); + audio.preloadEffect(path); + var name = component["name"]; + if(name) + audio.setName(name); + node.addComponent(audio); + } + }); + }, + "CCComAttribute": function(node, component, resourcePath){ + var attribute = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0){ + attribute = new ccs.ComAttribute(); + if (path !== "") + attribute.parse(path); + node.addComponent(attribute); + }else + cc.log("unknown resourcetype on CCComAttribute!"); + }); + return attribute; + }, + "CCBackgroundAudio": function(node, component, resourcePath){ + var audio = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + if(type === 0){ + audio = new ccs.ComAudio(); + audio.preloadBackgroundMusic(path); + audio.setFile(path);var bLoop = Boolean(component["loop"] || 0); + audio.setLoop(bLoop); + var name = component["name"]; + if(name) + audio.setName(name); + node.addComponent(audio); + audio.playBackgroundMusic(path, bLoop); + } + }); + }, + "GUIComponent": function(node, component, resourcePath){ + var widget = null; + loadTexture(component["fileData"], resourcePath, function(path, type){ + widget = ccs._load(path, "ccui"); + }); + var render = new ccs.ComRender(widget, "GUIComponent"); + node.addComponent(render); + return render; + }, + "CCScene": function(){} + }; + var loadedPlist = {}; + var loadTexture = function(json, resourcePath, cb){ + if(json != null){ + var path = json["path"]; + var type = json["resourceType"]; + var plist = json["plist"]; + if(!path) + return; + if(plist){ + if(cc.loader.getRes(resourcePath + plist)){ + loadedPlist[resourcePath + plist] = true; + cc.spriteFrameCache.addSpriteFrames(resourcePath + plist); + }else{ + if(!loadedPlist[resourcePath + plist]) + cc.log("%s need to be preloaded", resourcePath + plist); + } + } + if(type !== 0) + cb(path, type); + else + cb(resourcePath + path, type); + } + }; + + parser.parseComponents = function(node, json, resourcePath){ + if(!node || !json) + return; + json.forEach(function(component){ + var parser = componentsParser[component["classname"]]; + var render = null; + if(parser) + render = parser(node, component, resourcePath); + else + cc.log("Can't find the component parser : %s", component["classname"]); + var name = component["name"]; + if(render && name){ + render.setName(name); + } + }); + }; + + parser.registerParser("CCNode", function(options, resourcePath){ + var node = new cc.Node(); + this.setPropertyFromJsonDict(node, options); + this.parseChild.call(this, node, options["gameobjects"], resourcePath); + this.parseComponents(node, options["components"], resourcePath); + var size = options["CanvasSize"]; + if (size) + node.setContentSize(cc.size(size["_width"], size["_height"])); + + return node; + }); + + load.registerParser("scene", "*", parser); + + +})(ccs._load, ccs._parser); diff --git a/extensions/cocostudio/loader/parsers/timelineParser-1.x.js b/extensions/cocostudio/loader/parsers/timelineParser-1.x.js new file mode 100644 index 0000000000..c9c3efbab5 --- /dev/null +++ b/extensions/cocostudio/loader/parsers/timelineParser-1.x.js @@ -0,0 +1,292 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var loadedPlist = {}; + + var Parser = baseParser.extend({ + + getNodeJson: function(json){ + return json["nodeTree"]; + }, + + addSpriteFrame: function(plists, pngs, resourcePath){ + if(!plists || !pngs || plists.length !== pngs.length) + return; + for (var i = 0; i < plists.length; i++) { + var plist = resourcePath + plists[i]; + if(!cc.loader.getRes(plist) && !loadedPlist[plist]) + cc.log("%s need to be preloaded", plist); + else + loadedPlist[plist] = true; + cc.spriteFrameCache.addSpriteFrames( + plist, + resourcePath + pngs[i] + ); + } + }, + + pretreatment: function(json, resourcePath, file){ + this.addSpriteFrame(json["textures"], json["texturesPng"], resourcePath); + } + + }); + var parser = new Parser(); + + parser.generalAttributes = function(node, options){ + var width = options["width"] !=null ? options["width"] : 0; + var height = options["height"] !=null ? options["height"] : 0; + var x = options["x"] !=null ? options["x"] : 0; + var y = options["y"] !=null ? options["y"] : 0; + var scalex = options["scaleX"] !=null ? options["scaleX"] : 1; + var scaley = options["scaleY"] !=null ? options["scaleY"] : 1; + var rotation = options["rotation"] !=null ? options["rotation"] : 0; + var rotationSkewX = options["rotationSkewX"]!=null ? options["rotationSkewX"] : 0; + var rotationSkewY = options["rotationSkewY"]!=null ? options["rotationSkewY"] : 0; + var skewx = options["skewX"] !=null ? options["skewX"] : 0; + var skewy = options["skewY"] !=null ? options["skewY"] : 0; + var anchorx = options["anchorPointX"] !=null ? options["anchorPointX"] : 0.5; + var anchory = options["anchorPointY"] !=null ? options["anchorPointY"] : 0.5; + var alpha = options["opacity"] !=null ? options["opacity"] : 255; + var red = options["colorR"] !=null ? options["colorR"] : 255; + var green = options["colorG"] !=null ? options["colorG"] : 255; + var blue = options["colorB"] !=null ? options["colorB"] : 255; + var zorder = options["colorR"] !=null ? options["colorR"] : 0; + var tag = options["tag"] !=null ? options["tag"] : 0; + var actionTag = options["actionTag"] !=null ? options["actionTag"] : 0; + var visible = options["visible"] !=null ? options["visible"] : true; + + if(x != 0 || y != 0) + node.setPosition(cc.p(x, y)); + if(scalex != 1) + node.setScaleX(scalex); + if(scaley != 1) + node.setScaleY(scaley); + if (rotation != 0) + node.setRotation(rotation); + if(rotationSkewX != 0) + node.setRotationX(rotationSkewX); + if(rotationSkewY != 0) + node.setRotationY(rotationSkewY); + if(skewx != 0) + node.setSkewX(skewx); + if(skewy != 0) + node.setSkewY(skewy); + if(anchorx != 0.5 || anchory != 0.5) + node.setAnchorPoint(cc.p(anchorx, anchory)); + if(width != 0 || height != 0) + node.setContentSize(cc.size(width, height)); + if(zorder != 0) + node.setLocalZOrder(zorder); + if(visible != true) + node.setVisible(visible); + + if(alpha != 255) + { + node.setOpacity(alpha); + } + if(red != 255 || green != 255 || blue != 255) + { + node.setColor(cc.color(red, green, blue)); + } + + + node.setTag(tag); + node.setUserObject(new ccs.ActionTimelineData(actionTag)); + }; + + parser.parseComponent = function(node, options){ + if(!options) return; + for (var i = 0; i < options.length; ++i){ + var dic = options[i]; + var component = this.loadComponent(dic); + if (component){ + node.addComponent(component); + } + } + }; + + parser.parseChild = function(parse, widget, options, resourcePath){ + var children = options["children"]; + for (var i = 0; i < children.length; i++) { + var child = this.parseNode(children[i], resourcePath); + if(child){ + if(widget instanceof ccui.PageView){ + if(child instanceof ccui.Layout) + widget.addPage(child); + } else { + if(widget instanceof ccui.ListView){ + if(child instanceof ccui.Widget) + widget.pushBackCustomItem(child); + } else { + if(!(widget instanceof ccui.Layout) && child instanceof ccui.Widget) { + if(child.getPositionType() === ccui.Widget.POSITION_PERCENT) { + var position = child.getPositionPercent(); + var anchor = widget.getAnchorPoint(); + child.setPositionPercent(cc.p(position.x + anchor.x, position.y + anchor.y)); + } + //To make up for the studio positioning error problem + var AnchorPointIn = widget.getAnchorPointInPoints(); + child.setPosition(cc.p(child.getPositionX() + AnchorPointIn.x, child.getPositionY() + AnchorPointIn.y)); + } + widget.addChild(child); + } + } + } + } + }; + + parser.initNode = function(options){ + var node = new cc.Node(); + this.generalAttributes(node, options); + return node; + }; + parser.initSubGraph = function(options){ + var filePath = options["fileName"]; + + var node; + if (filePath && "" !== filePath){ + node = this.createNode(filePath); + }else{ + node = new ccs.Node(); + } + this.generalAttributes(node, options); + return node; + }; + parser.initSprite = function(options, resourcePath){ + var path = options["fileName"]; + var sprite; + if(path != null){ + var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path); + if(!spriteFrame){ + path = resourcePath + path; + sprite = new ccs.Sprite(path); + }else{ + sprite = ccs.Sprite.createWithSpriteFrame(spriteFrame); + } + + if(!sprite){ + sprite = new cc.Sprite(); + cc.log("filePath is empty. Create a sprite with no texture"); + } + }else{ + sprite = new ccs.Sprite(); + } + this.generalAttributes(sprite, options); + var flipX = options["flipX"]; + var flipY = options["flipY"]; + + if(flipX != false) + sprite.setFlippedX(flipX); + if(flipY != false) + sprite.setFlippedY(flipY); + return sprite; + }; + parser.initParticle = function(options, resourcePath){ + var filePath = options["plistFile"]; + var num = options["tmxFile"]; + var particle = new cc.ParticleSystemQuad(filePath); + particle.setTotalParticles(num); + this.generalAttributes(particle, options); + return particle; + }; + parser.initTMXTiledMap = function(options, resourcePath){ + var tmxFile = options["tmxFile"]; + var tmxString = options["tmxString"]; + //todo check path and resourcePath + var path = options["resourcePath"]; + + var tmx = null; + if (tmxFile && "" !== tmxFile){ + tmx = new cc.TMXTiledMap(tmxFile); + }else if (tmxString && "" !== tmxString && path && "" !== path){ + tmx = new cc.TMXTiledMap(tmxString, path); + } + return tmx; + }; + var uiParser = load.getParser("ccui")["*"]; + parser.initWidget = function(options, resourcePath){ + var type = options["classname"]; + + var parser = uiParser.parsers[type]; + if(!parser) + return cc.log("%s parser is not found", type); + + var node = parser.call(uiParser, options, resourcePath); + if(node){ + var rotationSkewX = options["rotationSkewX"]; + var rotationSkewY = options["rotationSkewY"]; + var skewx = options["skewX"]; + var skewy = options["skewY"]; + if(rotationSkewX != 0) + node.setRotationX(rotationSkewX); + if(rotationSkewY != 0) + node.setRotationY(rotationSkewY); + if(skewx != 0) + node.setSkewX(skewx); + if(skewy != 0) + node.setSkewY(skewy); + + var actionTag = options["actionTag"]; + node.setUserObject(new ccs.ActionTimelineData(actionTag)); + } + return node; + }; + + var register = [ + {name: "Node", handle: parser.initNode}, + {name: "SubGraph", handle: parser.initSubGraph}, + {name: "Sprite", handle: parser.initSprite}, + {name: "Particle", handle: parser.initParticle}, + {name: "TMXTiledMap", handle: parser.initTMXTiledMap}, + + {name: "Widget", handle: parser.initWidget}, + {name: "Panel", handle: parser.initWidget}, + {name: "Button", handle: parser.initWidget}, + {name: "CheckBox", handle: parser.initWidget}, + {name: "ImageView", handle: parser.initWidget}, + {name: "LabelAtlas", handle: parser.initWidget}, + {name: "LabelBMFont", handle: parser.initWidget}, + {name: "Label", handle: parser.initWidget}, + {name: "ListView", handle: parser.initWidget}, + {name: "LoadingBar", handle: parser.initWidget}, + {name: "PageView", handle: parser.initWidget}, + {name: "ScrollView", handle: parser.initWidget}, + {name: "Slider", handle: parser.initWidget}, + {name: "TextField", handle: parser.initWidget} + ]; + + register.forEach(function(item){ + parser.registerParser(item.name, function(options, parse, resourcePath){ + var node = item.handle.call(this, options["options"]); + this.parseComponent(node, options["components"]); + this.parseChild(parse, node, options, resourcePath); + return node; + }); + }); + + load.registerParser("timeline", "*", parser); + +})(ccs._load, ccs._parser); diff --git a/extensions/cocostudio/loader/parsers/timelineParser-2.x.js b/extensions/cocostudio/loader/parsers/timelineParser-2.x.js new file mode 100644 index 0000000000..e5644ccada --- /dev/null +++ b/extensions/cocostudio/loader/parsers/timelineParser-2.x.js @@ -0,0 +1,1321 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var DEBUG = false; + + var Parser = baseParser.extend({ + + parse: function(file, json, path){ + var resourcePath; + if(path !== undefined) + resourcePath = path; + else + resourcePath = this._dirname(file); + this.pretreatment(json, resourcePath, file); + var node = this.parseNode(this.getNodeJson(json), resourcePath); + this.deferred(json, resourcePath, node, file); + return node; + }, + + getNodeJson: function(json){ + return json["Content"]["Content"]["ObjectData"]; + }, + + getClass: function(json){ + return json["ctype"]; + } + + }); + var parser = new Parser(); + + + var getParam = function(value, dValue){ + if(value === undefined) + return dValue; + else + return value; + }; + + ////////// + // NODE // + ////////// + + parser.generalAttributes = function(node, json){ + if(json["Name"] != null) + node.setName(json["Name"]); + + var position = json["Position"]; + if(position != null && (position["X"] != null || position["Y"] != null)) + node.setPosition(cc.p(position["X"]||0, position["Y"]||0)); + + var scale = json["Scale"]; + if(scale != null){ + if(scale["ScaleX"] != null) + node.setScaleX(scale["ScaleX"]); + if(scale["ScaleY"] != null) + node.setScaleY(scale["ScaleY"]); + } + + var rotationSkewX = json["RotationSkewX"]; + if (rotationSkewX != null) + node.setRotationX(rotationSkewX); + + var rotationSkewY = json["RotationSkewY"]; + if (json["RotationSkewY"] != null) + node.setRotationY(rotationSkewY); + + + var anchor = json["AnchorPoint"]; + if(anchor != null){ + if(anchor["ScaleX"] == null) + anchor["ScaleX"] = 0; + if(anchor["ScaleY"] == null) + anchor["ScaleY"] = 0; + if(anchor["ScaleX"] != 0.5 || anchor["ScaleY"] != 0.5) + node.setAnchorPoint(cc.p(anchor["ScaleX"], anchor["ScaleY"])); + } + + if (json["ZOrder"] != null) + node.setLocalZOrder(json["ZOrder"]); + + var visible = getParam(json["VisibleForFrame"], true); + node.setVisible(visible); + + setContentSize(node, json["Size"]); + + if (json["Alpha"] != null) + node.setOpacity(json["Alpha"]); + + node.setTag(json["Tag"] || 0); + + var actionTag = json["ActionTag"] || 0; + var extensionData = new ccs.ObjectExtensionData(); + var customProperty = json["UserData"]; + if(customProperty !== undefined) + extensionData.setCustomProperty(customProperty); + extensionData.setActionTag(actionTag); + node.setUserObject(extensionData); + + node.setCascadeColorEnabled(true); + node.setCascadeOpacityEnabled(true); + }; + + parser.parseChild = function(node, children, resourcePath){ + if(!node || !children) return; + for (var i = 0; i < children.length; i++) { + var child = this.parseNode(children[i], resourcePath); + if(child){ + if(node instanceof ccui.PageView){ + if(child instanceof ccui.Layout) + node.addPage(child); + } else { + if(node instanceof ccui.ListView){ + if(child instanceof ccui.Widget) + node.pushBackCustomItem(child); + } else { + if(!(node instanceof ccui.Layout) && child instanceof ccui.Widget) { + if(child.getPositionType() === ccui.Widget.POSITION_PERCENT) { + var position = child.getPositionPercent(); + var anchor = node.getAnchorPoint(); + child.setPositionPercent(cc.p(position.x + anchor.x, position.y + anchor.y)); + } + } + node.addChild(child); + } + } + } + } + }; + + /** + * SingleNode + * @param json + * @returns {cc.Node} + */ + parser.initSingleNode = function(json){ + var node = new cc.Node(); + + this.generalAttributes(node, json); + + return node; + }; + + /** + * Sprite + * @param json + * @param resourcePath + * @returns {cc.Sprite} + */ + parser.initSprite = function(json, resourcePath){ + var node = new cc.Sprite(); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + if(type === 0) + node.setTexture(path); + else if(type === 1){ + var spriteFrame = cc.spriteFrameCache.getSpriteFrame(path); + node.setSpriteFrame(spriteFrame); + } + }); + + var blendData = json["BlendFunc"]; + if(json["BlendFunc"]) { + var blendFunc = cc.BlendFunc.ALPHA_PREMULTIPLIED; + if (blendData["Src"] !== undefined) + blendFunc.src = blendData["Src"]; + if (blendData["Dst"] !== undefined) + blendFunc.dst = blendData["Dst"]; + node.setBlendFunc(blendFunc); + } + + if(json["FlipX"]) + node.setFlippedX(true); + if(json["FlipY"]) + node.setFlippedY(true); + + this.generalAttributes(node, json); + var color = json["CColor"]; + if(color != null) + node.setColor(getColor(color)); + + return node; + }; + + /** + * Particle + * @param json + * @param resourcePath + * @returns {*} + */ + parser.initParticle = function(json, resourcePath){ + var node, + self = this; + loadTexture(json["FileData"], resourcePath, function(path, type){ + if(!cc.loader.getRes(path)) + cc.log("%s need to be preloaded", path); + node = new cc.ParticleSystem(path); + self.generalAttributes(node, json); + node.setPositionType(cc.ParticleSystem.TYPE_GROUPED); + !cc.sys.isNative && node.setDrawMode(cc.ParticleSystem.TEXTURE_MODE); + + var blendData = json["BlendFunc"]; + if(json["BlendFunc"]){ + var blendFunc = cc.BlendFunc.ALPHA_PREMULTIPLIED; + if(blendData["Src"] !== undefined) + blendFunc.src = blendData["Src"]; + if(blendData["Dst"] !== undefined) + blendFunc.dst = blendData["Dst"]; + node.setBlendFunc(blendFunc); + } + }); + return node; + }; + + + //////////// + // WIDGET // + //////////// + + parser.widgetAttributes = function (widget, json, enableContent) { + widget.setCascadeColorEnabled(true); + widget.setCascadeOpacityEnabled(true); + + widget.setUnifySizeEnabled(false); + //widget.setLayoutComponentEnabled(true); + widget.ignoreContentAdaptWithSize(false); + !enableContent && setContentSize(widget, json["Size"]); + + var name = json["Name"]; + if (name) + widget.setName(name); + + var actionTag = json["ActionTag"] || 0; + widget.setActionTag(actionTag); + var extensionData = new ccs.ObjectExtensionData(); + var customProperty = json["UserData"]; + if(customProperty !== undefined) + extensionData.setCustomProperty(customProperty); + extensionData.setActionTag(actionTag); + widget.setUserObject(extensionData); + + var rotationSkewX = json["RotationSkewX"]; + if (rotationSkewX) + widget.setRotationX(rotationSkewX); + + var rotationSkewY = json["RotationSkewY"]; + if (rotationSkewY) + widget.setRotationY(rotationSkewY); + + //var rotation = json["Rotation"]; + + var flipX = json["FlipX"]; + if (flipX) + widget.setFlippedX(true); + + var flipY = json["FlipY"]; + if (flipY) + widget.setFlippedY(true); + + var zOrder = json["zOrder"]; + if (zOrder != null) + widget.setLocalZOrder(zOrder); + + //var visible = json["Visible"]; + + var visible = getParam(json["VisibleForFrame"], true); + widget.setVisible(visible); + + var alpha = json["Alpha"]; + if (alpha != null) + widget.setOpacity(alpha); + + widget.setTag(json["Tag"] || 0); + + var touchEnabled = json["TouchEnable"] || false; + widget.setTouchEnabled(touchEnabled); + + // -- var frameEvent = json["FrameEvent"]; + + var callBackType = json["CallBackType"]; + if (callBackType != null) + widget.setCallbackType(callBackType); + + var callBackName = json["CallBackName"]; + if (callBackName) + widget.setCallbackName(callBackName); + + var position = json["Position"]; + if (position != null) + widget.setPosition(position["X"] || 0, position["Y"] || 0); + + var scale = json["Scale"]; + if (scale != null) { + var scaleX = getParam(scale["ScaleX"], 1); + var scaleY = getParam(scale["ScaleY"], 1); + widget.setScaleX(scaleX); + widget.setScaleY(scaleY); + } + + var anchorPoint = json["AnchorPoint"]; + if (anchorPoint != null) + widget.setAnchorPoint(anchorPoint["ScaleX"] || 0, anchorPoint["ScaleY"] || 0); + + var color = json["CColor"]; + if (color != null) + widget.setColor(getColor(color)); + + var layoutComponent = ccui.LayoutComponent.bindLayoutComponent(widget); + if(!layoutComponent) + return; + + var positionXPercentEnabled = json["PositionPercentXEnable"] || false; + var positionYPercentEnabled = json["PositionPercentYEnable"] || false; + var positionXPercent = 0, + positionYPercent = 0, + PrePosition = json["PrePosition"]; + if (PrePosition != null) { + positionXPercent = PrePosition["X"] || 0; + positionYPercent = PrePosition["Y"] || 0; + } + var sizeXPercentEnable = json["PercentWidthEnable"] || false; + var sizeYPercentEnable = json["PercentHeightEnable"] || false; + var sizeXPercent = 0, + sizeYPercent = 0, + PreSize = json["PreSize"]; + if (PrePosition != null) { + sizeXPercent = PreSize["X"] || 0; + sizeYPercent = PreSize["Y"] || 0; + } + var stretchHorizontalEnabled = json["StretchWidthEnable"] || false; + var stretchVerticalEnabled = json["StretchHeightEnable"] || false; + var horizontalEdge = json["HorizontalEdge"];// = ccui.LayoutComponent.horizontalEdge.LEFT; + var verticalEdge = json["VerticalEdge"]; // = ccui.LayoutComponent.verticalEdge.TOP; + var leftMargin = json["LeftMargin"] || 0; + var rightMargin = json["RightMargin"] || 0; + var topMargin = json["TopMargin"] || 0; + var bottomMargin = json["BottomMargin"] || 0; + + layoutComponent.setPositionPercentXEnabled(positionXPercentEnabled); + layoutComponent.setPositionPercentYEnabled(positionYPercentEnabled); + layoutComponent.setPositionPercentX(positionXPercent); + layoutComponent.setPositionPercentY(positionYPercent); + layoutComponent.setPercentWidthEnabled(sizeXPercentEnable); + layoutComponent.setPercentHeightEnabled(sizeYPercentEnable); + layoutComponent.setPercentWidth(sizeXPercent); + layoutComponent.setPercentHeight(sizeYPercent); + layoutComponent.setStretchWidthEnabled(stretchHorizontalEnabled); + layoutComponent.setStretchHeightEnabled(stretchVerticalEnabled); + + var horizontalEdgeType = ccui.LayoutComponent.horizontalEdge.NONE; + if (horizontalEdge === "LeftEdge") { + horizontalEdgeType = ccui.LayoutComponent.horizontalEdge.LEFT; + } else if (horizontalEdge === "RightEdge") { + horizontalEdgeType = ccui.LayoutComponent.horizontalEdge.RIGHT; + } else if (horizontalEdge === "BothEdge") { + horizontalEdgeType = ccui.LayoutComponent.horizontalEdge.CENTER; + } + layoutComponent.setHorizontalEdge(horizontalEdgeType); + + var verticalEdgeType = ccui.LayoutComponent.verticalEdge.NONE; + if (verticalEdge === "TopEdge") { + verticalEdgeType = ccui.LayoutComponent.verticalEdge.TOP; + } else if (verticalEdge === "BottomEdge") { + verticalEdgeType = ccui.LayoutComponent.verticalEdge.BOTTOM; + } else if (verticalEdge === "BothEdge") { + verticalEdgeType = ccui.LayoutComponent.verticalEdge.CENTER; + } + layoutComponent.setVerticalEdge(verticalEdgeType); + + layoutComponent.setTopMargin(topMargin); + layoutComponent.setBottomMargin(bottomMargin); + layoutComponent.setLeftMargin(leftMargin); + layoutComponent.setRightMargin(rightMargin); + + layoutComponent.setVerticalEdge(verticalEdgeType); + + layoutComponent.setTopMargin(topMargin); + layoutComponent.setBottomMargin(bottomMargin); + layoutComponent.setLeftMargin(leftMargin); + layoutComponent.setRightMargin(rightMargin); + }; + + var setLayoutBackground = function(layout, single, first, end){ + if( layout.getBackGroundColorType() === 2 ){ + first = first || {}; + end = end || {}; + layout.setBackGroundColor(getColor(first), getColor(end)); + }else{ + single = single || {}; + layout.setBackGroundColor(getColor(single)); + } + }; + + var setLayoutBackgroundVector = function(widget, vector){ + var x = vector["ScaleX"] || 0; + var y = vector["ScaleY"] || 0; + widget.setBackGroundColorVector(cc.p(x, y)); + }; + + /** + * Layout + * @param json + * @param resourcePath + * @returns {ccui.Layout} + */ + parser.initPanel = function(json, resourcePath){ + var widget = new ccui.Layout(); + + this.widgetAttributes(widget, json); + + var clipEnabled = json["ClipAble"]; + if(clipEnabled != null) + widget.setClippingEnabled(clipEnabled); + + var colorType = getParam(json["ComboBoxIndex"], 0); + widget.setBackGroundColorType(colorType); + + var bgColorOpacity = getParam(json["BackColorAlpha"], 255); + if(bgColorOpacity != null) + widget.setBackGroundColorOpacity(bgColorOpacity); + + var backGroundScale9Enabled = json["Scale9Enable"]; + if(backGroundScale9Enabled != null) + widget.setBackGroundImageScale9Enabled(backGroundScale9Enabled); + + var opacity = getParam(json["Alpha"], 255); + widget.setOpacity(opacity); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + widget.setBackGroundImage(path, type); + }); + + if(backGroundScale9Enabled){ + var scale9OriginX = json["Scale9OriginX"] || 0; + var scale9OriginY = json["Scale9OriginY"] || 0; + + var scale9Width = json["Scale9Width"] || 0; + var scale9Height = json["Scale9Height"] || 0; + + widget.setBackGroundImageCapInsets(cc.rect( + scale9OriginX, scale9OriginY, scale9Width, scale9Height + )); + + setContentSize(widget, json["Size"]); + }else{ + if (!widget.isIgnoreContentAdaptWithSize()){ + setContentSize(widget, json["Size"]); + } + + } + + setLayoutBackground(widget, json["SingleColor"], json["FirstColor"], json["EndColor"]); + setLayoutBackgroundVector(widget, json["ColorVector"]); + + return widget; + }; + + /** + * Text + * @param json + * @param resourcePath + */ + parser.initText = function(json, resourcePath){ + + var widget = new ccui.Text(); + + var touchScaleEnabled = json["TouchScaleChangeAble"]; + if(touchScaleEnabled != null) + widget.setTouchScaleChangeEnabled(touchScaleEnabled); + + var text = json["LabelText"]; + if(text != null) + widget.setString(text); + + var fontSize = json["FontSize"]; + if(fontSize != null) + widget.setFontSize(fontSize); + + var fontName = json["FontName"]; + if(fontName != null) + widget.setFontName(fontName); + + var areaWidth = json["AreaWidth"]; + var areaHeight = json["areaHeight"]; + if(areaWidth && areaHeight) + widget.setTextAreaSize(cc.size(areaWidth, areaHeight)); + + var h_alignment = json["HorizontalAlignmentType"] || "HT_Left"; + switch(h_alignment){ + case "HT_Right": + h_alignment = 2; break; + case "HT_Center": + h_alignment = 1; break; + case "HT_Left": + default: + h_alignment = 0; + } + widget.setTextHorizontalAlignment(h_alignment); + + var v_alignment = json["VerticalAlignmentType"] || "VT_Top"; + switch(v_alignment){ + case "VT_Bottom": + v_alignment = 2; break; + case "VT_Center": + v_alignment = 1; break; + case "VT_Top": + default: + v_alignment = 0; + } + widget.setTextVerticalAlignment(v_alignment); + + var fontResource = json["FontResource"]; + if(fontResource != null){ + var path = fontResource["Path"]; + //resoutceType = fontResource["Type"]; + if(path != null){ + if (cc.sys.isNative) { + fontName = cc.path.join(cc.loader.resPath, resourcePath, path); + } else { + fontName = path.match(/([^\/]+)\.ttf/); + fontName = fontName ? fontName[1] : ""; + } + widget.setFontName(fontName); + } + } + + if(json["OutlineEnabled"] && json["OutlineColor"] && widget.enableOutline) + widget.enableOutline(getColor(json["OutlineColor"]), getParam(json["OutlineSize"], 1)); + + if(json["ShadowEnabled"] && json["ShadowColor"] && widget.enableShadow) + widget.enableShadow( + getColor(json["ShadowColor"]), + cc.size(getParam(json["ShadowOffsetX"], 2), getParam(json["ShadowOffsetY"], -2)), + json["ShadowBlurRadius"] || 0 + ); + + var isCustomSize = json["IsCustomSize"]; + if(isCustomSize != null) + widget.ignoreContentAdaptWithSize(!isCustomSize); + + widget.setUnifySizeEnabled(false); + + this.widgetAttributes(widget, json, widget.isIgnoreContentAdaptWithSize()); + + return widget; + + }; + + /** + * Button + * @param json + * @param resourcePath + */ + parser.initButton = function(json, resourcePath){ + + var widget = new ccui.Button(); + + loadTexture(json["NormalFileData"], resourcePath, function(path, type){ + widget.loadTextureNormal(path, type); + }); + loadTexture(json["PressedFileData"], resourcePath, function(path, type){ + widget.loadTexturePressed(path, type); + }); + loadTexture(json["DisabledFileData"], resourcePath, function(path, type){ + widget.loadTextureDisabled(path, type); + }); + + var scale9Enabled = getParam(json["Scale9Enable"], false); + if(scale9Enabled) { + widget.setScale9Enabled(scale9Enabled); + } + + var text = json["ButtonText"]; + if(text != null) + widget.setTitleText(text); + + var fontSize = json["FontSize"]; + if(fontSize != null) + widget.setTitleFontSize(fontSize); + + var fontName = json["FontName"]; + if(fontName != null) + widget.setTitleFontName(fontName); + + var textColor = json["TextColor"]; + if(textColor != null) + widget.setTitleColor(getColor(textColor)); + + var displaystate = getParam(json["DisplayState"], true); + widget.setBright(displaystate); + widget.setEnabled(displaystate); + + var fontResource = json["FontResource"]; + if(fontResource != null){ + var path = fontResource["Path"]; + //resoutceType = fontResource["Type"]; + if(path != null){ + if (cc.sys.isNative) { + fontName = cc.path.join(cc.loader.resPath, resourcePath, path); + } else { + fontName = path.match(/([^\/]+)\.ttf/); + fontName = fontName ? fontName[1] : ""; + } + widget.setTitleFontName(fontName); + } + } + + var label = widget.getTitleRenderer(); + if(label && json["ShadowEnabled"] && json["ShadowColor"] && label.enableShadow){ + label.enableShadow( + getColor(json["ShadowColor"]), + cc.size(getParam(json["ShadowOffsetX"], 2), getParam(json["ShadowOffsetY"], -2)), + json["ShadowBlurRadius"] || 0 + ); + } + if(label && json["OutlineEnabled"] && json["OutlineColor"] && label.enableStroke) + label.enableStroke(getColor(json["OutlineColor"]), getParam(json["OutlineSize"], 1)); + + this.widgetAttributes(widget, json); + + if(scale9Enabled) { + widget.setUnifySizeEnabled(false); + widget.ignoreContentAdaptWithSize(false); + var capInsets = cc.rect( + json["Scale9OriginX"] || 0, + json["Scale9OriginY"] || 0, + json["Scale9Width"] || 0, + json["Scale9Height"] || 0 + ); + widget.setCapInsets(capInsets); + + } + + setContentSize(widget, json["Size"]); + + return widget; + + }; + + /** + * CheckBox + * @param json + * @param resourcePath + */ + parser.initCheckBox = function(json, resourcePath){ + + var widget = new ccui.CheckBox(); + + this.widgetAttributes(widget, json); + + var dataList = [ + {name: "NormalBackFileData", handle: widget.loadTextureBackGround}, + {name: "PressedBackFileData", handle: widget.loadTextureBackGroundSelected}, + {name: "NodeNormalFileData", handle: widget.loadTextureFrontCross}, + {name: "DisableBackFileData", handle: widget.loadTextureBackGroundDisabled}, + {name: "NodeDisableFileData", handle: widget.loadTextureFrontCrossDisabled} + ]; + + dataList.forEach(function(item){ + loadTexture(json[item.name], resourcePath, function(path, type){ + item.handle.call(widget, path, type); + }); + }); + + var selectedState = getParam(json["CheckedState"], false); + widget.setSelected(selectedState); + + var displaystate = getParam(json["DisplayState"], true); + widget.setBright(displaystate); + widget.setEnabled(displaystate); + + return widget; + }; + + /** + * ScrollView + * @param json + * @param resourcePath + */ + parser.initScrollView = function(json, resourcePath){ + var widget = new ccui.ScrollView(); + + this.widgetAttributes(widget, json); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + widget.setBackGroundImage(path, type); + }); + + var clipEnabled = json["ClipAble"]; + widget.setClippingEnabled(clipEnabled); + + var colorType = getParam(json["ComboBoxIndex"], 0); + widget.setBackGroundColorType(colorType); + + var bgColorOpacity = json["BackColorAlpha"]; + if(bgColorOpacity != null) + widget.setBackGroundColorOpacity(bgColorOpacity); + + var backGroundScale9Enabled = json["Scale9Enable"]; + if(backGroundScale9Enabled){ + widget.setBackGroundImageScale9Enabled(true); + + + var scale9OriginX = json["Scale9OriginX"] || 0; + var scale9OriginY = json["Scale9OriginY"] || 0; + var scale9Width = json["Scale9Width"] || 0; + var scale9Height = json["Scale9Height"] || 0; + widget.setBackGroundImageCapInsets(cc.rect( + scale9OriginX, scale9OriginY, scale9Width, scale9Height + )); + setContentSize(widget, json["Size"]); + }else if(!widget.isIgnoreContentAdaptWithSize()){ + setContentSize(widget, json["Size"]); + } + + setLayoutBackground(widget, json["SingleColor"], json["FirstColor"], json["EndColor"]); + setLayoutBackgroundVector(widget, json["ColorVector"]); + + var innerNodeSize = json["InnerNodeSize"]; + var innerSize = cc.size( + innerNodeSize["Width"] || 0, + innerNodeSize["Height"] || 0 + ); + widget.setInnerContainerSize(innerSize); + + var direction = 0; + if(json["ScrollDirectionType"] === "Vertical") direction = 1; + if(json["ScrollDirectionType"] === "Horizontal") direction = 2; + if(json["ScrollDirectionType"] === "Vertical_Horizontal") direction = 3; + widget.setDirection(direction); + + var bounceEnabled = getParam(json["IsBounceEnabled"], false); + widget.setBounceEnabled(bounceEnabled); + + return widget; + }; + + /** + * ImageView + * @param json + * @param resourcePath + */ + parser.initImageView = function(json, resourcePath){ + + var widget = new ccui.ImageView(); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + widget.loadTexture(path, type); + }); + loadTexture(json["ImageFileData"], resourcePath, function(path, type){ + widget.loadTexture(path, type); + }); + + var scale9Enabled = json["Scale9Enable"]; + if(scale9Enabled){ + widget.setScale9Enabled(true); + widget.setUnifySizeEnabled(false); + widget.ignoreContentAdaptWithSize(false); + + var scale9OriginX = json["Scale9OriginX"] || 0; + var scale9OriginY = json["Scale9OriginY"] || 0; + var scale9Width = json["Scale9Width"] || 0; + var scale9Height = json["Scale9Height"] || 0; + widget.setCapInsets(cc.rect( + scale9OriginX , + scale9OriginY, + scale9Width, + scale9Height + )); + } else + setContentSize(widget, json["Size"]); + + this.widgetAttributes(widget, json); + + return widget; + }; + + /** + * LoadingBar + * @param json + * @param resourcePath + * @returns {ccui.LoadingBar} + */ + parser.initLoadingBar = function(json, resourcePath){ + + var widget = new ccui.LoadingBar(); + + this.widgetAttributes(widget, json); + + loadTexture(json["ImageFileData"], resourcePath, function(path, type){ + widget.loadTexture(path, type); + }); + + var direction = json["ProgressType"] === "Right_To_Left" ? 1 : 0; + widget.setDirection(direction); + + var percent = getParam(json["ProgressInfo"], 80); + if(percent != null) + widget.setPercent(percent); + + return widget; + + }; + + /** + * Slider + * @param json + * @param resourcePath + */ + parser.initSlider = function(json, resourcePath){ + + var widget = new ccui.Slider(); + var loader = cc.loader; + + this.widgetAttributes(widget, json); + + var textureList = [ + {name: "BackGroundData", handle: widget.loadBarTexture}, + {name: "BallNormalData", handle: widget.loadSlidBallTextureNormal}, + {name: "BallPressedData", handle: widget.loadSlidBallTexturePressed}, + {name: "BallDisabledData", handle: widget.loadSlidBallTextureDisabled}, + {name: "ProgressBarData", handle: widget.loadProgressBarTexture} + ]; + textureList.forEach(function(item){ + loadTexture(json[item.name], resourcePath, function(path, type){ + if(type === 0 && !loader.getRes(path)) + cc.log("%s need to be preloaded", path); + item.handle.call(widget, path, type); + }); + }); + + var percent = json["PercentInfo"] || 0; + widget.setPercent(percent); + + var displaystate = getParam(json["DisplayState"], true); + widget.setBright(displaystate); + widget.setEnabled(displaystate); + + return widget; + }; + + /** + * PageView + * @param json + * @param resourcePath + */ + parser.initPageView = function(json, resourcePath){ + + var widget = new ccui.PageView(); + + this.widgetAttributes(widget, json); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + widget.setBackGroundImage(path, type); + }); + + var clipEnabled = json["ClipAble"] || false; + widget.setClippingEnabled(clipEnabled); + + var backGroundScale9Enabled = json["Scale9Enable"]; + if(backGroundScale9Enabled){ + widget.setBackGroundImageScale9Enabled(true); + + var scale9OriginX = json["Scale9OriginX"] || 0; + var scale9OriginY = json["Scale9OriginY"] || 0; + var scale9Width = json["Scale9Width"] || 0; + var scale9Height = json["Scale9Height"] || 0; + widget.setBackGroundImageCapInsets(cc.rect( + scale9OriginX, + scale9OriginY, + scale9Width, + scale9Height + )); + } + + var colorType = getParam(json["ComboBoxIndex"], 0); + widget.setBackGroundColorType(colorType); + + setLayoutBackground(widget, json["SingleColor"], json["FirstColor"], json["EndColor"]); + setLayoutBackgroundVector(widget, json["ColorVector"]); + + var bgColorOpacity = json["BackColorAlpha"]; + if(bgColorOpacity != null) + widget.setBackGroundColorOpacity(bgColorOpacity); + + setContentSize(widget, json["Size"]); + + return widget; + + }; + + /** + * ListView + * @param json + * @param resourcePath + * @returns {ccui.ListView} + */ + parser.initListView = function(json, resourcePath){ + + var widget = new ccui.ListView(); + + this.widgetAttributes(widget, json); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + widget.setBackGroundImage(path, type); + }); + + var clipEnabled = json["ClipAble"] || false; + widget.setClippingEnabled(clipEnabled); + + var colorType = getParam(json["ComboBoxIndex"], 0); + widget.setBackGroundColorType(colorType); + + var bgColorOpacity = getParam(json["BackColorAlpha"], 255); + var backGroundScale9Enabled = json["Scale9Enable"]; + if(backGroundScale9Enabled){ + widget.setBackGroundImageScale9Enabled(true); + + var scale9OriginX = json["Scale9OriginX"] || 0; + var scale9OriginY = json["Scale9OriginY"] || 0; + var scale9Width = json["Scale9Width"] || 0; + var scale9Height = json["Scale9Height"] || 0; + widget.setBackGroundImageCapInsets(cc.rect( + scale9OriginX, + scale9OriginY, + scale9Width, + scale9Height + )); + } + + var directionType = getParam(json["DirectionType"], ccui.ListView.DIR_HORIZONTAL); + var verticalType = getParam(json["VerticalType"], "Align_Left"); + var horizontalType = getParam(json["HorizontalType"], "Align_Top"); + if(!directionType){ + widget.setDirection(ccui.ScrollView.DIR_HORIZONTAL); + if(verticalType === "Align_Bottom") + widget.setGravity(ccui.ListView.GRAVITY_BOTTOM); + else if(verticalType === "Align_VerticalCenter") + widget.setGravity(ccui.ListView.GRAVITY_CENTER_VERTICAL); + else + widget.setGravity(ccui.ListView.GRAVITY_TOP); + }else if(directionType === "Vertical"){ + widget.setDirection(ccui.ScrollView.DIR_VERTICAL); + if (horizontalType === "") + widget.setGravity(ccui.ListView.GRAVITY_LEFT); + else if (horizontalType === "Align_Right") + widget.setGravity(ccui.ListView.GRAVITY_RIGHT); + else if (horizontalType === "Align_HorizontalCenter") + widget.setGravity(ccui.ListView.GRAVITY_CENTER_HORIZONTAL); + } + + + var bounceEnabled = getParam(json["IsBounceEnabled"], false); + widget.setBounceEnabled(bounceEnabled); + + var itemMargin = json["ItemMargin"] || 0; + widget.setItemsMargin(itemMargin); + + var innerSize = json["InnerNodeSize"]; + //Width + if(innerSize != null) + widget.setInnerContainerSize(cc.size(innerSize["Widget"]||0, innerSize["Height"]||0)); + + setLayoutBackground(widget, json["SingleColor"], json["FirstColor"], json["EndColor"]); + setLayoutBackgroundVector(widget, json["ColorVector"]); + + if(bgColorOpacity != null) + widget.setBackGroundColorOpacity(bgColorOpacity); + + setContentSize(widget, json["Size"]); + + return widget; + }; + + /** + * TextAtlas + * @param json + * @param resourcePath + * @returns {ccui.TextAtlas} + */ + parser.initTextAtlas = function(json, resourcePath){ + + var widget = new ccui.TextAtlas(); + + var stringValue = json["LabelText"]; + var itemWidth = json["CharWidth"]; + var itemHeight = json["CharHeight"]; + + var startCharMap = json["StartChar"]; + + loadTexture(json["LabelAtlasFileImage_CNB"], resourcePath, function(path, type){ + if(!cc.loader.getRes(path)) + cc.log("%s need to be preloaded", path); + if(type === 0){ + widget.setProperty(stringValue, path, itemWidth, itemHeight, startCharMap); + } + }); + this.widgetAttributes(widget, json); + + return widget; + }; + + /** + * TextBMFont + * @param json + * @param resourcePath + * @returns {ccui.TextBMFont} + */ + parser.initTextBMFont = function(json, resourcePath){ + + var widget = new ccui.TextBMFont(); + this.widgetAttributes(widget, json); + + var text = json["LabelText"]; + widget.setString(text); + + loadTexture(json["LabelBMFontFile_CNB"], resourcePath, function(path, type){ + if(!cc.loader.getRes(path)) + cc.log("%s need to be pre loaded", path); + widget.setFntFile(path); + }); + widget.ignoreContentAdaptWithSize(true); + return widget; + }; + + /** + * TextField + * @param json + * @param resourcePath + * @returns {ccui.TextField} + */ + parser.initTextField = function(json, resourcePath){ + var widget = new ccui.TextField(); + + var passwordEnabled = json["PasswordEnable"]; + if(passwordEnabled){ + widget.setPasswordEnabled(true); + var passwordStyleText = json["PasswordStyleText"] || "*"; + widget.setPasswordStyleText(passwordStyleText); + } + + var placeHolder = json["PlaceHolderText"]; + if(placeHolder != null) + widget.setPlaceHolder(placeHolder); + + var fontSize = json["FontSize"]; + if(fontSize != null) + widget.setFontSize(fontSize); + + var fontName = json["FontName"]; + if(fontName != null) + widget.setFontName(fontName); + + var maxLengthEnabled = json["MaxLengthEnable"]; + if(maxLengthEnabled){ + widget.setMaxLengthEnabled(true); + var maxLength = json["MaxLengthText"] || 0; + widget.setMaxLength(maxLength); + } + + //var isCustomSize = json["IsCustomSize"]; + this.widgetAttributes(widget, json); + + var text = json["LabelText"]; + if(text != null) + widget.setString(text); + + var fontResource = json["FontResource"]; + if(fontResource != null){ + var path = fontResource["Path"]; + //resoutceType = fontResource["Type"]; + if(path != null){ + if (cc.sys.isNative) { + fontName = cc.path.join(cc.loader.resPath, resourcePath, path); + } else { + fontName = path.match(/([^\/]+)\.ttf/); + fontName = fontName ? fontName[1] : ""; + } + widget.setFontName(fontName); + } + } + + widget.setUnifySizeEnabled(false); + widget.ignoreContentAdaptWithSize(false); + + var color = json["CColor"]; + if(color != null) + widget.setTextColor(getColor(color)); + + if (!widget.isIgnoreContentAdaptWithSize()){ + setContentSize(widget, json["Size"]); + if (cc.sys.isNative) + widget.getVirtualRenderer().setLineBreakWithoutSpace(true); + } + + + return widget; + + }; + + /** + * SimpleAudio + * @param json + * @param resourcePath + */ + parser.initSimpleAudio = function(json, resourcePath){ + + var loop = json["Loop"] || false; + var volume = json["Volume"] || 0; + cc.audioEngine.setMusicVolume(volume); + //var name = json["Name"]; + var resPath = ""; + if(cc.loader.resPath) + resPath = (cc.loader.resPath + "/").replace(/\/\/$/, "/"); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + cc.loader.load(path, function(){ + cc.audioEngine.playMusic(resPath + path, loop); + }); + }); + + }; + + /** + * GameMap + * @param json + * @param resourcePath + * @returns {*} + */ + parser.initGameMap = function(json, resourcePath){ + + var node = null; + + loadTexture(json["FileData"], resourcePath, function(path, type){ + if(type === 0) + node = new cc.TMXTiledMap(path); + + parser.generalAttributes(node, json); + }); + + return node; + }; + + /** + * ProjectNode + * @param json + * @param resourcePath + * @returns {*} + */ + parser.initProjectNode = function(json, resourcePath){ + var projectFile = json["FileData"]; + if(projectFile != null && projectFile["Path"]){ + var file = resourcePath + projectFile["Path"]; + if(cc.loader.getRes(file)){ + var obj = ccs.load(file, resourcePath); + parser.generalAttributes(obj.node, json); + if(obj.action && obj.node){ + obj.action.tag = obj.node.tag; + var InnerActionSpeed = json["InnerActionSpeed"]; + if(InnerActionSpeed !== undefined) + obj.action.setTimeSpeed(InnerActionSpeed); + obj.node.runAction(obj.action); + obj.action.gotoFrameAndPause(0); + } + return obj.node; + } else + cc.log("%s need to be preloaded", file); + } + }; + + var getFileName = function(name){ + if(!name) return ""; + var arr = name.match(/([^\/]+)\.[^\/]+$/); + if(arr && arr[1]) + return arr[1]; + else + return ""; + }; + + /** + * Armature + * @param json + * @param resourcePath + */ + parser.initArmature = function(json, resourcePath){ + + var node = new ccs.Armature(); + + var isLoop = json["IsLoop"]; + + var isAutoPlay = json["IsAutoPlay"]; + + var currentAnimationName = json["CurrentAnimationName"]; + + parser.generalAttributes(node, json); + + loadTexture(json["FileData"], resourcePath, function(path, type){ + var plists, pngs; + var armJson = cc.loader.getRes(path); + if(!armJson) + cc.log("%s need to be preloaded", path); + else{ + plists = armJson["config_file_path"]; + pngs = armJson["config_png_path"]; + plists.forEach(function(plist, index){ + if(pngs[index]) + cc.spriteFrameCache.addSpriteFrames(plist, pngs[index]); + }); + } + ccs.armatureDataManager.addArmatureFileInfo(path); + node.init(getFileName(path)); + if(isAutoPlay) + node.getAnimation().play(currentAnimationName, -1, isLoop); + + }); + return node; + }; + + var loadedPlist = {}; + var loadTexture = function(json, resourcePath, cb){ + if(json != null){ + var path = json["Path"]; + var type; + if(json["Type"] === "Default" || json["Type"] === "Normal") + type = 0; + else + type = 1; + var plist = json["Plist"]; + if(plist){ + if(cc.loader.getRes(resourcePath + plist)){ + loadedPlist[resourcePath + plist] = true; + cc.spriteFrameCache.addSpriteFrames(resourcePath + plist); + }else{ + if(!loadedPlist[resourcePath + plist]) + cc.log("%s need to be preloaded", resourcePath + plist); + } + } + if(type !== 0) + cb(path, type); + else + cb(resourcePath + path, type); + } + }; + + var getColor = function(json){ + if(!json) return; + var r = json["R"] != null ? json["R"] : 255; + var g = json["G"] != null ? json["G"] : 255; + var b = json["B"] != null ? json["B"] : 255; + var a = json["A"] != null ? json["A"] : 255; + return cc.color(r, g, b, a); + }; + + var setContentSize = function(node, size){ + var x = size["X"] || 0; + var y = size["Y"] || 0; + if(size) + node.setContentSize(cc.size(x, y)); + }; + + var register = [ + {name: "SingleNodeObjectData", handle: parser.initSingleNode}, + {name: "NodeObjectData", handle: parser.initSingleNode}, + {name: "LayerObjectData", handle: parser.initSingleNode}, + {name: "SpriteObjectData", handle: parser.initSprite}, + {name: "ParticleObjectData", handle: parser.initParticle}, + {name: "PanelObjectData", handle: parser.initPanel}, + {name: "TextObjectData", handle: parser.initText}, + {name: "ButtonObjectData", handle: parser.initButton}, + {name: "CheckBoxObjectData", handle: parser.initCheckBox}, + {name: "ScrollViewObjectData", handle: parser.initScrollView}, + {name: "ImageViewObjectData", handle: parser.initImageView}, + {name: "LoadingBarObjectData", handle: parser.initLoadingBar}, + {name: "SliderObjectData", handle: parser.initSlider}, + {name: "PageViewObjectData", handle: parser.initPageView}, + {name: "ListViewObjectData", handle: parser.initListView}, + {name: "TextAtlasObjectData", handle: parser.initTextAtlas}, + {name: "TextBMFontObjectData", handle: parser.initTextBMFont}, + {name: "TextFieldObjectData", handle: parser.initTextField}, + {name: "SimpleAudioObjectData", handle: parser.initSimpleAudio}, + {name: "GameMapObjectData", handle: parser.initGameMap}, + {name: "ProjectNodeObjectData", handle: parser.initProjectNode}, + {name: "ArmatureNodeObjectData", handle: parser.initArmature} + ]; + + register.forEach(function(item){ + parser.registerParser(item.name, function(options, resourcePath){ + var node = item.handle.call(this, options, resourcePath); + this.parseChild(node, options["Children"], resourcePath); + DEBUG && node && (node.__parserName = item.name); + return node; + }); + }); + + + load.registerParser("timeline", "2.*", parser); + + +})(ccs._load, ccs._parser); diff --git a/extensions/cocostudio/loader/parsers/uiParser-1.x.js b/extensions/cocostudio/loader/parsers/uiParser-1.x.js new file mode 100644 index 0000000000..c14763e875 --- /dev/null +++ b/extensions/cocostudio/loader/parsers/uiParser-1.x.js @@ -0,0 +1,698 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(load, baseParser){ + + var Parser = baseParser.extend({ + + addSpriteFrame: function(textures, resourcePath){ + if(!textures) return; + for (var i = 0; i < textures.length; i++) { + cc.spriteFrameCache.addSpriteFrames(resourcePath + textures[i]); + } + }, + + pretreatment: function(json, resourcePath){ + this.addSpriteFrame(json["textures"], resourcePath); + }, + + deferred: function(json, resourcePath, node, file){ + if(node){ + ccs.actionManager.initWithDictionary(file, json["animation"], node); + node.setContentSize(cc.size(json["designWidth"], json["designHeight"])); + } + } + + }); + var parser = new Parser(); + + + parser.generalAttributes = function(widget, options){ + var ignoreSizeExsit = options["ignoreSize"]; + if(ignoreSizeExsit != null) + widget.ignoreContentAdaptWithSize(ignoreSizeExsit); + + if (options["sizeType"]) + { + widget.setSizeType(options["sizeType"]); + } + + if (options["positionType"]) + { + widget.setPositionType(options["positionType"]); + } + + widget.setSizePercent(cc.p(options["sizePercentX"], options["sizePercentY"])); + widget.setPositionPercent(cc.p(options["positionPercentX"], options["positionPercentY"])); + + /* adapt screen */ + var w = 0, h = 0; + var adaptScreen = options["adaptScreen"]; + if (adaptScreen) { + var screenSize = cc.director.getWinSize(); + w = screenSize.width; + h = screenSize.height; + } else { + w = options["width"]; + h = options["height"]; + } + widget.setContentSize(w, h); + + widget.setTag(options["tag"]); + widget.setActionTag(options["actiontag"]); + widget.setTouchEnabled(options["touchAble"]); + var name = options["name"]; + var widgetName = name ? name : "default"; + widget.setName(widgetName); + + var x = options["x"]; + var y = options["y"]; + widget.setPosition(x, y); + + var sx = options["scaleX"]!=null ? options["scaleX"] : 1; + widget.setScaleX(sx); + + var sy = options["scaleY"]!=null ? options["scaleY"] : 1; + widget.setScaleY(sy); + + var rt = options["rotation"] || 0; + widget.setRotation(rt); + + var vb = options["visible"] || false; + if(vb != null) + widget.setVisible(vb); + widget.setLocalZOrder(options["ZOrder"]); + + var layout = options["layoutParameter"]; + if(layout != null){ + var layoutParameterDic = options["layoutParameter"]; + var paramType = layoutParameterDic["type"]; + var parameter = null; + + switch(paramType){ + case 0: + break; + case 1: + parameter = new ccui.LinearLayoutParameter(); + var gravity = layoutParameterDic["gravity"]; + parameter.setGravity(gravity); + break; + case 2: + parameter = new ccui.RelativeLayoutParameter(); + var rParameter = parameter; + var relativeName = layoutParameterDic["relativeName"]; + rParameter.setRelativeName(relativeName); + var relativeToName = layoutParameterDic["relativeToName"]; + rParameter.setRelativeToWidgetName(relativeToName); + var align = layoutParameterDic["align"]; + rParameter.setAlign(align); + break; + default: + break; + } + if(parameter != null){ + var mgl = layoutParameterDic["marginLeft"]||0; + var mgt = layoutParameterDic["marginTop"]||0; + var mgr = layoutParameterDic["marginRight"]||0; + var mgb = layoutParameterDic["marginDown"]||0; + parameter.setMargin(mgl, mgt, mgr, mgb); + widget.setLayoutParameter(parameter); + } + } + }; + + parser.colorAttributes = function(widget, options){ + var op = options["opacity"]; + if(op != null) + widget.setOpacity(op); + var colorR = options["colorR"]; + var colorG = options["colorG"]; + var colorB = options["colorB"]; + widget.setColor(cc.color((colorR == null) ? 255 : colorR, (colorG == null) ? 255 : colorG, (colorB == null) ? 255 : colorB)); + + widget.setFlippedX(options["flipX"]); + widget.setFlippedY(options["flipY"]); + }; + + parser.anchorPointAttributes = function(widget, options){ + var isAnchorPointXExists = options["anchorPointX"]; + var anchorPointXInFile; + if (isAnchorPointXExists != null) + anchorPointXInFile = options["anchorPointX"]; + else + anchorPointXInFile = widget.getAnchorPoint().x; + + var isAnchorPointYExists = options["anchorPointY"]; + var anchorPointYInFile; + if (isAnchorPointYExists != null) + anchorPointYInFile = options["anchorPointY"]; + else + anchorPointYInFile = widget.getAnchorPoint().y; + + if (isAnchorPointXExists != null || isAnchorPointYExists != null) + widget.setAnchorPoint(cc.p(anchorPointXInFile, anchorPointYInFile)); + }; + + parser.parseChild = function(widget, options, resourcePath){ + var children = options["children"]; + for (var i = 0; i < children.length; i++) { + var child = this.parseNode(children[i], resourcePath); + if(child){ + if(widget instanceof ccui.PageView) + widget.addPage(child); + else { + if(widget instanceof ccui.ListView){ + widget.pushBackCustomItem(child); + } else { + if(!(widget instanceof ccui.Layout)) { + if(child.getPositionType() === ccui.Widget.POSITION_PERCENT) { + var position = child.getPositionPercent(); + var anchor = widget.getAnchorPoint(); + child.setPositionPercent(cc.p(position.x + anchor.x, position.y + anchor.y)); + } + var AnchorPointIn = widget.getAnchorPointInPoints(); + child.setPosition(cc.p(child.getPositionX() + AnchorPointIn.x, child.getPositionY() + AnchorPointIn.y)); + } + widget.addChild(child); + } + } + } + } + }; + + var getPath = function(res, type, path, cb){ + if(path){ + if(type === 0) + cb(res + path, type); + else + cb(path, type); + } + }; + + /** + * Panel parser (UILayout) + */ + parser.LayoutAttributes = function(widget, options, resourcePath){ + var w = 0, h = 0; + var adaptScreen = options["adaptScreen"]; + if (adaptScreen){ + var screenSize = cc.director.getWinSize(); + w = screenSize.width; + h = screenSize.height; + }else{ + w = options["width"]; + h = options["height"]; + } + widget.setSize(cc.size(w, h)); + + widget.setClippingEnabled(options["clipAble"]); + + var backGroundScale9Enable = options["backGroundScale9Enable"]; + widget.setBackGroundImageScale9Enabled(backGroundScale9Enable); + var cr = options["bgColorR"]; + var cg = options["bgColorG"]; + var cb = options["bgColorB"]; + + var scr = options["bgStartColorR"]; + var scg = options["bgStartColorG"]; + var scb = options["bgStartColorB"]; + + var ecr = options["bgEndColorR"]; + var ecg = options["bgEndColorG"]; + var ecb = options["bgEndColorB"]; + + var bgcv1 = options["vectorX"]; + var bgcv2 = options["vectorY"]; + widget.setBackGroundColorVector(cc.p(bgcv1, bgcv2)); + + var co = options["bgColorOpacity"]; + + var colorType = options["colorType"]; + widget.setBackGroundColorType(colorType/*ui.LayoutBackGroundColorType(colorType)*/); + widget.setBackGroundColor(cc.color(scr, scg, scb), cc.color(ecr, ecg, ecb)); + widget.setBackGroundColor(cc.color(cr, cg, cb)); + widget.setBackGroundColorOpacity(co); + + + var imageFileNameDic = options["backGroundImageData"]; + if(imageFileNameDic){ + getPath(resourcePath, imageFileNameDic["resourceType"], imageFileNameDic["path"], function(path, type){ + widget.setBackGroundImage(path, type); + }); + } + + if (backGroundScale9Enable){ + var cx = options["capInsetsX"]; + var cy = options["capInsetsY"]; + var cw = options["capInsetsWidth"]; + var ch = options["capInsetsHeight"]; + widget.setBackGroundImageCapInsets(cc.rect(cx, cy, cw, ch)); + } + if (options["layoutType"]) + { + widget.setLayoutType(options["layoutType"]); + } + }; + /** + * Button parser (UIButton) + */ + parser.ButtonAttributes = function(widget, options, resourcePath){ + var button = widget; + var scale9Enable = options["scale9Enable"]; + button.setScale9Enabled(scale9Enable); + + var normalDic = options["normalData"]; + getPath(resourcePath, normalDic["resourceType"], normalDic["path"], function(path, type){ + button.loadTextureNormal(path, type); + }); + var pressedDic = options["pressedData"]; + getPath(resourcePath, pressedDic["resourceType"], pressedDic["path"], function(path, type){ + button.loadTexturePressed(path, type); + }); + var disabledDic = options["disabledData"]; + getPath(resourcePath, disabledDic["resourceType"], disabledDic["path"], function(path, type){ + button.loadTextureDisabled(path, type); + }); + if (scale9Enable) { + var cx = options["capInsetsX"]; + var cy = options["capInsetsY"]; + var cw = options["capInsetsWidth"]; + var ch = options["capInsetsHeight"]; + + button.setCapInsets(cc.rect(cx, cy, cw, ch)); + var sw = options["scale9Width"]; + var sh = options["scale9Height"]; + if (sw != null && sh != null) + button.setSize(cc.size(sw, sh)); + } + var text = options["text"]; + if (text != null) + button.setTitleText(text); + + var cr = options["textColorR"]; + var cg = options["textColorG"]; + var cb = options["textColorB"]; + var cri = cr!==null?options["textColorR"]:255; + var cgi = cg!==null?options["textColorG"]:255; + var cbi = cb!==null?options["textColorB"]:255; + + button.setTitleColor(cc.color(cri,cgi,cbi)); + var fs = options["fontSize"]; + if (fs != null) + button.setTitleFontSize(options["fontSize"]); + var fn = options["fontName"]; + if (fn) + button.setTitleFontName(options["fontName"]); + }; + /** + * CheckBox parser (UICheckBox) + */ + parser.CheckBoxAttributes = function(widget, options, resourcePath){ + //load background image + var backGroundDic = options["backGroundBoxData"]; + getPath(resourcePath, backGroundDic["resourceType"], backGroundDic["path"], function(path, type){ + widget.loadTextureBackGround(path, type); + }); + + //load background selected image + var backGroundSelectedDic = options["backGroundBoxSelectedData"]; + getPath( + resourcePath, + backGroundSelectedDic["resourceType"] || backGroundDic["resourceType"], + backGroundSelectedDic["path"] || backGroundDic["path"], + function(path, type){ + widget.loadTextureBackGroundSelected(path, type); + }); + + //load frontCross image + var frontCrossDic = options["frontCrossData"]; + getPath(resourcePath, frontCrossDic["resourceType"], frontCrossDic["path"], function(path, type){ + widget.loadTextureFrontCross(path, type); + }); + + //load backGroundBoxDisabledData + var backGroundDisabledDic = options["backGroundBoxDisabledData"]; + getPath( + resourcePath, + backGroundDisabledDic["resourceType"] || frontCrossDic["resourceType"], + backGroundDisabledDic["path"] || frontCrossDic["path"], + function(path, type){ + widget.loadTextureBackGroundDisabled(path, type); + }); + + ///load frontCrossDisabledData + var frontCrossDisabledDic = options["frontCrossDisabledData"]; + getPath(resourcePath, frontCrossDisabledDic["resourceType"], frontCrossDisabledDic["path"], function(path, type){ + widget.loadTextureFrontCrossDisabled(path, type); + }); + + if (options["selectedState"]) + widget.setSelected(options["selectedState"]); + }; + /** + * ImageView parser (UIImageView) + */ + parser.ImageViewAttributes = function(widget, options, resourcePath){ + var imageFileNameDic = options["fileNameData"] + getPath(resourcePath, imageFileNameDic["resourceType"], imageFileNameDic["path"], function(path, type){ + widget.loadTexture(path, type); + }); + + var scale9EnableExist = options["scale9Enable"]; + var scale9Enable = false; + if (scale9EnableExist){ + scale9Enable = options["scale9Enable"]; + } + widget.setScale9Enabled(scale9Enable); + + if (scale9Enable){ + var sw = options["scale9Width"]; + var sh = options["scale9Height"]; + if (sw && sh) + { + var swf = options["scale9Width"]; + var shf = options["scale9Height"]; + widget.setSize(cc.size(swf, shf)); + } + + var cx = options["capInsetsX"]; + var cy = options["capInsetsY"]; + var cw = options["capInsetsWidth"]; + var ch = options["capInsetsHeight"]; + + widget.setCapInsets(cc.rect(cx, cy, cw, ch)); + + } + }; + /** + * TextAtlas parser (UITextAtlas) + */ + parser.TextAtlasAttributes = function(widget, options, resourcePath){ + var sv = options["stringValue"]; + var cmf = options["charMapFileData"]; // || options["charMapFile"]; + var iw = options["itemWidth"]; + var ih = options["itemHeight"]; + var scm = options["startCharMap"]; + if (sv != null && cmf && iw != null && ih != null && scm != null){ + var cmftDic = options["charMapFileData"]; + var cmfType = cmftDic["resourceType"]; + switch (cmfType){ + case 0: + var tp_c = resourcePath; + var cmfPath = cmftDic["path"]; + var cmf_tp = tp_c + cmfPath; + widget.setProperty(sv, cmf_tp, iw, ih, scm); + break; + case 1: + cc.log("Wrong res type of LabelAtlas!"); + break; + default: + break; + } + } + }; + /** + * TextBMFont parser (UITextBMFont) + */ + parser.TextBMFontAttributes = function(widget, options, resourcePath){ + var cmftDic = options["fileNameData"]; + var cmfType = cmftDic["resourceType"]; + switch (cmfType) { + case 0: + var tp_c = resourcePath; + var cmfPath = cmftDic["path"]; + var cmf_tp = tp_c + cmfPath; + widget.setFntFile(cmf_tp); + break; + case 1: + cc.log("Wrong res type of LabelAtlas!"); + break; + default: + break; + } + + var text = options["text"]; + widget.setString(text); + }; + /** + * Text parser (UIText) + */ + var regTTF = /\.ttf$/; + parser.TextAttributes = function(widget, options, resourcePath){ + var touchScaleChangeAble = options["touchScaleEnable"]; + widget.setTouchScaleChangeEnabled(touchScaleChangeAble); + var text = options["text"]; + widget.setString(text); + var fs = options["fontSize"]; + if (fs != null){ + widget.setFontSize(options["fontSize"]); + } + var fn = options["fontName"]; + if (fn != null){ + if(cc.sys.isNative){ + if(regTTF.test(fn)){ + widget.setFontName(cc.path.join(cc.loader.resPath, resourcePath, fn)); + }else{ + widget.setFontName(fn); + } + }else{ + widget.setFontName(fn.replace(regTTF, '')); + } + } + var aw = options["areaWidth"]; + var ah = options["areaHeight"]; + if (aw != null && ah != null){ + var size = cc.size(options["areaWidth"], options["areaHeight"]); + widget.setTextAreaSize(size); + } + var ha = options["hAlignment"]; + if (ha != null){ + widget.setTextHorizontalAlignment(options["hAlignment"]); + } + var va = options["vAlignment"]; + if (va != null){ + widget.setTextVerticalAlignment(options["vAlignment"]); + } + }; + /** + * ListView parser (UIListView) + */ + parser.ListViewAttributes = function(widget, options, resoutcePath){ + parser.ScrollViewAttributes(widget, options,resoutcePath); + var direction = options["direction"]; + widget.setDirection(direction); + var gravity = options["gravity"]; + widget.setGravity(gravity); + var itemMargin = options["itemMargin"]; + widget.setItemsMargin(itemMargin); + }; + /** + * LoadingBar parser (UILoadingBar) + */ + parser.LoadingBarAttributes = function(widget, options, resourcePath){ + var imageFileNameDic = options["textureData"]; + getPath(resourcePath, imageFileNameDic["resourceType"], imageFileNameDic["path"], function(path, type){ + widget.loadTexture(path, type); + }); + + var scale9Enable = options["scale9Enable"]; + widget.setScale9Enabled(scale9Enable); + + if (scale9Enable){ + var cx = options["capInsetsX"]; + var cy = options["capInsetsY"]; + var cw = options["capInsetsWidth"]; + var ch = options["capInsetsHeight"]; + + widget.setCapInsets(cc.rect(cx, cy, cw, ch)); + + var width = options["width"]; + var height = options["height"]; + widget.setSize(cc.size(width, height)); + } + + widget.setDirection(options["direction"]); + widget.setPercent(options["percent"]); + }; + /** + * PageView parser (UIPageView) + */ + parser.PageViewAttributes = parser.LayoutAttributes; + /** + * ScrollView parser (UIScrollView) + */ + parser.ScrollViewAttributes = function(widget, options, resoutcePath){ + parser.LayoutAttributes(widget, options,resoutcePath); + var innerWidth = options["innerWidth"]!=null ? options["innerWidth"] : 200; + var innerHeight = options["innerHeight"]!=null ? options["innerHeight"] : 200; + widget.setInnerContainerSize(cc.size(innerWidth, innerHeight)); + + var direction = options["direction"]!=null ? options["direction"] : 1; + widget.setDirection(direction); + widget.setBounceEnabled(options["bounceEnable"]); + }; + /** + * Slider parser (UISlider) + */ + parser.SliderAttributes = function(widget, options, resourcePath){ + + var slider = widget; + + var barTextureScale9Enable = options["scale9Enable"]; + slider.setScale9Enabled(barTextureScale9Enable); + var bt = options["barFileName"]; + var barLength = options["length"]; + + var imageFileNameDic = options["barFileNameData"]; + var imageFileType = imageFileNameDic["resourceType"]; + var imageFileName = imageFileNameDic["path"]; + + if(bt != null){ + if(barTextureScale9Enable){ + getPath(resourcePath, imageFileType, imageFileName, function(path, type){ + slider.loadBarTexture(path, type); + }); + slider.setSize(cc.size(barLength, slider.getContentSize().height)); + } + }else{ + getPath(resourcePath, imageFileType, imageFileName, function(path, type){ + slider.loadBarTexture(path, type); + }); + } + + var normalDic = options["ballNormalData"]; + getPath(resourcePath, normalDic["resourceType"], normalDic["path"], function(path, type){ + slider.loadSlidBallTextureNormal(path, type); + }); + + var pressedDic = options["ballPressedData"]; + getPath( + resourcePath, + pressedDic["resourceType"] || normalDic["resourceType"], + pressedDic["path"] || normalDic["path"], + function(path, type){ + slider.loadSlidBallTexturePressed(path, type); + }); + + var disabledDic = options["ballDisabledData"]; + getPath(resourcePath, disabledDic["resourceType"], disabledDic["path"], function(path, type){ + slider.loadSlidBallTextureDisabled(path, type); + }); + + var progressBarDic = options["progressBarData"]; + getPath(resourcePath, progressBarDic["resourceType"], progressBarDic["path"], function(path, type){ + slider.loadProgressBarTexture(path, type); + }); + }; + /** + * TextField parser (UITextField) + */ + parser.TextFieldAttributes = function(widget, options, resourcePath){ + var ph = options["placeHolder"]; + if(ph) + widget.setPlaceHolder(ph); + widget.setString(options["text"]||""); + var fs = options["fontSize1"]; + if(fs) + widget.setFontSize(fs); + var fn = options["fontName"]; + if (fn != null){ + if(cc.sys.isNative){ + if(regTTF.test(fn)){ + widget.setFontName(cc.path.join(cc.loader.resPath, resourcePath, fn)); + }else{ + widget.setFontName(fn); + } + }else{ + widget.setFontName(fn.replace(regTTF, '')); + } + } + var tsw = options["touchSizeWidth"]; + var tsh = options["touchSizeHeight"]; + if(tsw!=null && tsh!=null) + widget.setTouchSize(tsw, tsh); + + var dw = options["width"]; + var dh = options["height"]; + if(dw > 0 || dh > 0){ + //textField.setSize(cc.size(dw, dh)); + } + var maxLengthEnable = options["maxLengthEnable"]; + widget.setMaxLengthEnabled(maxLengthEnable); + + if(maxLengthEnable){ + var maxLength = options["maxLength"]; + widget.setMaxLength(maxLength); + } + var passwordEnable = options["passwordEnable"]; + widget.setPasswordEnabled(passwordEnable); + if(passwordEnable) + widget.setPasswordStyleText(options["passwordStyleText"]); + + var aw = options["areaWidth"]; + var ah = options["areaHeight"]; + if(aw && ah){ + var size = cc.size(aw, ah); + widget.setTextAreaSize(size); + } + var ha = options["hAlignment"]; + if(ha) + widget.setTextHorizontalAlignment(ha); + var va = options["vAlignment"]; + if(va) + widget.setTextVerticalAlignment(va); + }; + + var register = [ + {name: "Panel", object: ccui.Layout, handle: parser.LayoutAttributes}, + {name: "Button", object: ccui.Button, handle: parser.ButtonAttributes}, + {name: "CheckBox", object: ccui.CheckBox, handle: parser.CheckBoxAttributes}, + {name: "ImageView", object: ccui.ImageView, handle: parser.ImageViewAttributes}, + {name: "LabelAtlas", object: ccui.TextAtlas, handle: parser.TextAtlasAttributes}, + {name: "LabelBMFont", object: ccui.TextBMFont, handle: parser.TextBMFontAttributes}, + {name: "Label", object: ccui.Text, handle: parser.TextAttributes}, + {name: "ListView", object: ccui.ListView, handle: parser.ListViewAttributes}, + {name: "LoadingBar", object: ccui.LoadingBar, handle: parser.LoadingBarAttributes}, + {name: "PageView", object: ccui.PageView, handle: parser.PageViewAttributes}, + {name: "ScrollView", object: ccui.ScrollView, handle: parser.ScrollViewAttributes}, + {name: "Slider", object: ccui.Slider, handle: parser.SliderAttributes}, + {name: "TextField", object: ccui.TextField, handle: parser.TextFieldAttributes} + ]; + + register.forEach(function(item){ + parser.registerParser(item.name, function(options, resourcePath){ + var widget = new item.object; + var uiOptions = options["options"]; + parser.generalAttributes(widget, uiOptions); + item.handle(widget, uiOptions, resourcePath); + parser.colorAttributes(widget, uiOptions); + parser.anchorPointAttributes(widget, uiOptions); + parser.parseChild.call(this, widget, options, resourcePath); + return widget; + }); + }); + + load.registerParser("ccui", "*", parser); + +})(ccs._load, ccs._parser); \ No newline at end of file diff --git a/extensions/cocostudio/reader/GUIReader.js b/extensions/cocostudio/reader/GUIReader.js deleted file mode 100644 index 37e4847d48..0000000000 --- a/extensions/cocostudio/reader/GUIReader.js +++ /dev/null @@ -1,1594 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -/** - * @namespace Base object for ccs.uiReader - */ -ccs.uiReader = /** @lends ccs.uiReader# */{ - _filePath: "", - _olderVersion: false, - _fileDesignSizes: {}, - - /** - * get version - * @param {String} str - * @returns {Number} - */ - getVersionInteger: function (str) { - if(!str) - return 0; - var strVersion = str; - var versionLength = strVersion.length; - if (versionLength < 7) { - return 0; - } - var pos = strVersion.indexOf("."); - var t = strVersion.substr(0, pos); - strVersion = strVersion.substr(pos + 1, versionLength - 1); - - pos = strVersion.indexOf("."); - var h = strVersion.substr(0, pos); - strVersion = strVersion.substr(pos + 1, versionLength - 1); - - pos = strVersion.indexOf("."); - var te = strVersion.substr(0, pos); - strVersion = strVersion.substr(pos + 1, versionLength - 1); - - pos = strVersion.indexOf("."); - var s; - if (pos == -1) { - s = strVersion; - } else { - s = strVersion.substr(0, pos); - } - - var it = parseInt(t); - var ih = parseInt(h); - var ite = parseInt(te); - var is = parseInt(s); - - var version = it * 1000 + ih * 100 + ite * 10 + is; - return version; - }, - - /** - * store file designSize - * @param {String} fileName - * @param {cc.Size} size - */ - storeFileDesignSize: function (fileName, size) { - this._fileDesignSizes[fileName] = size; - }, - - /** - * - * @param {String} fileName - * @returns {cc.Size} - */ - getFileDesignSize: function (fileName) { - return this._fileDesignSizes[fileName]; - }, - - /** - * create uiWidget from a josn file that exported by cocostudio UI editor - * @param {String} fileName - * @returns {ccui.Widget} - */ - widgetFromJsonFile: function (fileName) { - var jsonDict = cc.loader.getRes(fileName); - if(!jsonDict) throw "Please load the resource first : " + fileName; - - var tempFilePath = cc.path.dirname(fileName); - this._filePath = tempFilePath == "" ? tempFilePath : tempFilePath + "/"; - - var fileVersion = jsonDict["version"]; - var pReader, widget; - var versionInteger = this.getVersionInteger(fileVersion); - if (fileVersion) { - if (versionInteger < 250) { - pReader = new ccs.WidgetPropertiesReader0250(); - widget = pReader.createWidget(jsonDict, this._filePath, fileName); - } else { - pReader = new ccs.WidgetPropertiesReader0300(); - widget = pReader.createWidget(jsonDict, this._filePath, fileName); - } - } else { - pReader = new ccs.WidgetPropertiesReader0250(); - widget = pReader.createWidget(jsonDict, this._filePath, fileName); - } - - if (!fileVersion || versionInteger < 250) { - this._olderVersion = true; - } - jsonDict = null; - return widget; - }, - - /** - * Clear data: Release all actions. - */ - clear: function () { - this._filePath = ""; - this._olderVersion = false; - this._fileDesignSizes = {}; - } -}; - - -ccs.WidgetPropertiesReader = ccs.Class.extend({ - _filePath: "", - createWidget: function (jsonDict, fullPath, fileName) { - }, - widgetFromJsonDictionary: function (data) { - } -}); -ccs.WidgetPropertiesReader0250 = ccs.WidgetPropertiesReader.extend({ - createWidget: function (jsonDict, fullPath, fileName) { - this._filePath = fullPath == "" ? fullPath : cc.path.join(fullPath, "/"); - var textures = jsonDict["textures"]; - for (var i = 0; i < textures.length; i++) { - var file = textures[i]; - var tp = fullPath; - tp += file; - cc.spriteFrameCache.addSpriteFrames(tp); - } - var fileDesignWidth = jsonDict["designWidth"]; - var fileDesignHeight = jsonDict["designHeight"]; - if (fileDesignWidth <= 0 || fileDesignHeight <= 0) { - cc.log("Read design size error!"); - var winSize = cc.director.getWinSize(); - ccs.uiReader.storeFileDesignSize(fileName, winSize); - } - else { - ccs.uiReader.storeFileDesignSize(fileName, cc.size(fileDesignWidth, fileDesignHeight)); - } - var widgetTree = jsonDict["widgetTree"]; - var widget = this.widgetFromJsonDictionary(widgetTree); - - var size = widget.getContentSize(); - if (size.width == 0 && size.height == 0) { - widget.setSize(cc.size(fileDesignWidth, fileDesignHeight)); - } - - var actions = jsonDict["animation"]; - var rootWidget = widget; - ccs.actionManager.initWithDictionary(fileName, actions, rootWidget); - - widgetTree = null; - actions = null; - return widget; - }, - widgetFromJsonDictionary: function (data) { - var widget = null; - var classname = data["classname"]; - var uiOptions = data["options"]; - if (classname == "Button") { - widget = ccui.Button.create(); - this.setPropsForButtonFromJsonDictionary(widget, uiOptions); - } - else if (classname == "CheckBox") { - widget = ccui.CheckBox.create(); - this.setPropsForCheckBoxFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Label") { - widget = ccui.Text.create(); - this.setPropsForLabelFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LabelAtlas") { - widget = ccui.TextAtlas.create(); - this.setPropsForLabelAtlasFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LoadingBar") { - widget = ccui.LoadingBar.create(); - this.setPropsForLoadingBarFromJsonDictionary(widget, uiOptions); - } else if (classname == "ScrollView") { - widget = ccui.ScrollView.create(); - this.setPropsForScrollViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextArea") { - widget = ccui.Text.create(); - this.setPropsForLabelFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextButton") { - widget = ccui.Button.create(); - this.setPropsForButtonFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextField") { - widget = ccui.TextField.create(); - this.setPropsForTextFieldFromJsonDictionary(widget, uiOptions); - } - else if (classname == "ImageView") { - widget = ccui.ImageView.create(); - this.setPropsForImageViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Panel") { - widget = ccui.Layout.create(); - this.setPropsForLayoutFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Slider") { - widget = ccui.Slider.create(); - this.setPropsForSliderFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LabelBMFont") { - widget = ccui.TextBMFont.create(); - this.setPropsForLabelBMFontFromJsonDictionary(widget, uiOptions); - } - else if (classname == "DragPanel") { - widget = ccui.ScrollView.create(); - this.setPropsForScrollViewFromJsonDictionary(widget, uiOptions); - } - var children = data["children"]; - for (var i = 0; i < children.length; i++) { - var subData = children[i]; - var child = this.widgetFromJsonDictionary(subData); - if (child) { - widget.addChild(child); - } - subData = null; - } - - uiOptions = null; - return widget; - }, - - - setPropsForWidgetFromJsonDictionary: function (widget, options) { - if (options["ignoreSize"] !== undefined) { - widget.ignoreContentAdaptWithSize(options["ignoreSize"]); - } - - var w = options["width"]; - var h = options["height"]; - widget.setSize(cc.size(w, h)); - - widget.setTag(options["tag"]); - widget.setActionTag(options["actiontag"]); - widget.setTouchEnabled(options["touchAble"]); - var name = options["name"]; - var widgetName = name ? name : "default"; - widget.setName(widgetName); - var x = options["x"]; - var y = options["y"]; - widget.setPosition(x, y); - if (options["scaleX"] !== undefined) { - widget.setScaleX(options["scaleX"]); - } - if (options["scaleY"] !== undefined) { - widget.setScaleY(options["scaleY"]); - } - if (options["rotation"] !== undefined) { - widget.setRotation(options["rotation"]); - } - if (options["visible"] !== undefined) { - widget.setVisible(options["visible"]); - } - - var z = options["ZOrder"]; - widget.setLocalZOrder(z); - }, - - setColorPropsForWidgetFromJsonDictionary: function (widget, options) { - if (options["opacity"] !== undefined) { - widget.setOpacity(options["opacity"]); - } - var colorR = options["colorR"] !== undefined ? options["colorR"] : 255; - var colorG = options["colorG"] !== undefined ? options["colorG"] : 255; - var colorB = options["colorB"] !== undefined ? options["colorB"] : 255; - widget.setColor(cc.color(colorR, colorG, colorB)); - var apx = options["anchorPointX"] !== undefined ? options["anchorPointX"] : ((widget.getWidgetType() == ccui.Widget.TYPE_WIDGET) ? 0.5 : 0); - var apy = options["anchorPointY"] !== undefined ? options["anchorPointY"] : ((widget.getWidgetType() == ccui.Widget.TYPE_WIDGET) ? 0.5 : 0); - widget.setAnchorPoint(apx, apy); - var flipX = options["flipX"]; - var flipY = options["flipY"]; - widget.setFlippedX(flipX); - widget.setFlippedY(flipY); - }, - - setPropsForButtonFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var button = widget; - var scale9Enable = options["scale9Enable"]; - button.setScale9Enabled(scale9Enable); - - var normalFileName = options["normal"]; - var pressedFileName = options["pressed"]; - var disabledFileName = options["disabled"]; - - var normalFileName_tp = normalFileName ? this._filePath + normalFileName : null; - var pressedFileName_tp = pressedFileName ? this._filePath + pressedFileName : null; - var disabledFileName_tp = disabledFileName ? this._filePath + disabledFileName : null; - var useMergedTexture = options["useMergedTexture"]; - if (scale9Enable) { - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - - if (useMergedTexture) { - button.loadTextures(normalFileName, pressedFileName, disabledFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - button.loadTextures(normalFileName_tp, pressedFileName_tp, disabledFileName_tp); - } - //button.setCapInsets(cc.rect(cx, cy, cw, ch)); - if (options["scale9Width"] !== undefined && options["scale9Height"] !== undefined) { - var swf = options["scale9Width"]; - var shf = options["scale9Height"]; - button.setSize(cc.size(swf, shf)); - } - } - else { - if (useMergedTexture) { - button.loadTextures(normalFileName, pressedFileName, disabledFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - button.loadTextures(normalFileName_tp, pressedFileName_tp, disabledFileName_tp); - } - } - if (options["text"] !== undefined) { - var text = options["text"] || ""; - if (text) - button.setTitleText(text); - } - if (options["fontSize"] !== undefined) { - button.setTitleFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - button.setTitleFontName(options["fontName"]); - } - var cr = options["textColorR"] !== undefined ? options["textColorR"] : 255; - var cg = options["textColorG"] !== undefined ? options["textColorG"] : 255; - var cb = options["textColorB"] !== undefined ? options["textColorB"] : 255; - var tc = cc.color(cr, cg, cb); - button.setTitleColor(tc); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForCheckBoxFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var checkBox = widget; - var backGroundFileName = options["backGroundBox"]; - var backGroundSelectedFileName = options["backGroundBoxSelected"]; - var frontCrossFileName = options["frontCross"]; - var backGroundDisabledFileName = options["backGroundBoxDisabled"]; - var frontCrossDisabledFileName = options["frontCrossDisabled"]; - - var locFilePath = this._filePath; - - var backGroundFileName_tp = backGroundFileName ? locFilePath + backGroundFileName : null; - var backGroundSelectedFileName_tp = backGroundSelectedFileName ? locFilePath + backGroundSelectedFileName : null; - var frontCrossFileName_tp = frontCrossFileName ? locFilePath + frontCrossFileName : null; - var backGroundDisabledFileName_tp = backGroundDisabledFileName ? locFilePath + backGroundDisabledFileName : null; - var frontCrossDisabledFileName_tp = frontCrossDisabledFileName ? locFilePath + frontCrossDisabledFileName : null; - var useMergedTexture = options["useMergedTexture"]; - - if (useMergedTexture) { - checkBox.loadTextures(backGroundFileName, backGroundSelectedFileName, frontCrossFileName, backGroundDisabledFileName, frontCrossDisabledFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - checkBox.loadTextures(backGroundFileName_tp, backGroundSelectedFileName_tp, frontCrossFileName_tp, backGroundDisabledFileName_tp, frontCrossDisabledFileName_tp); - } - - checkBox.setSelectedState(options["selectedState"] || false); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForImageViewFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - - var imageView = widget; - var imageFileName = options["fileName"]; - var scale9Enable = options["scale9Enable"] || false; - imageView.setScale9Enabled(scale9Enable); - - var tp_i = this._filePath; - var imageFileName_tp = null; - if (imageFileName) { - imageFileName_tp = tp_i + imageFileName; - } - - var useMergedTexture = options["useMergedTexture"]; - if (scale9Enable) { - if (useMergedTexture) { - imageView.loadTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - imageView.loadTexture(imageFileName_tp); - } - - if (options["scale9Width"] !== undefined && options["scale9Height"] !== undefined) { - var swf = options["scale9Width"]; - var shf = options["scale9Height"]; - imageView.setSize(cc.size(swf, shf)); - } - - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - imageView.setCapInsets(cc.rect(cx, cy, cw, ch)); - - } - else { - if (useMergedTexture) { - imageView.loadTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - imageView.loadTexture(imageFileName_tp); - } - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLabelFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var label = widget; - var touchScaleChangeAble = options["touchScaleEnable"]; - label.setTouchScaleChangeEnabled(touchScaleChangeAble); - var text = options["text"]; - label.setText(text); - if (options["fontSize"] !== undefined) { - label.setFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - label.setFontName(options["fontName"]); - } - if (options["areaWidth"] !== undefined && options["areaHeight"] !== undefined) { - var size = cc.size(options["areaWidth"], options["areaHeight"]); - label.setTextAreaSize(size); - } - if (options["hAlignment"]) { - label.setTextHorizontalAlignment(options["hAlignment"]); - } - if (options["vAlignment"]) { - label.setTextVerticalAlignment(options["vAlignment"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLabelAtlasFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var labelAtlas = widget; - var sv = (options["stringValue"] !== undefined); - var cmf = (options["charMapFile"] !== undefined); - var iw = (options["itemWidth"] !== undefined); - var ih = (options["itemHeight"] !== undefined); - var scm = (options["startCharMap"] !== undefined); - if (sv && cmf && iw && ih && scm && options["charMapFile"]) { - var cmft = options["charMapFile"]; - var cmf_tp = this._filePath + cmft; - - labelAtlas.setProperty(options["stringValue"], cmf_tp, options["itemWidth"], options["itemHeight"], options["startCharMap"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLayoutFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var containerWidget = widget; - if (!(containerWidget instanceof ccui.ScrollView) && !(containerWidget instanceof ccui.ListView)) { - containerWidget.setClippingEnabled(options["clipAble"]); - } - var panel = widget; - var backGroundScale9Enable = options["backGroundScale9Enable"]; - panel.setBackGroundImageScale9Enabled(backGroundScale9Enable); - var cr = options["bgColorR"]; - var cg = options["bgColorG"]; - var cb = options["bgColorB"]; - - var scr = options["bgStartColorR"]; - var scg = options["bgStartColorG"]; - var scb = options["bgStartColorB"]; - - var ecr = options["bgEndColorR"]; - var ecg = options["bgEndColorG"]; - var ecb = options["bgEndColorB"]; - - var bgcv1 = options["vectorX"]; - var bgcv2 = options["vectorY"]; - panel.setBackGroundColorVector(cc.p(bgcv1, bgcv2)); - - var co = options["bgColorOpacity"]; - - var colorType = options["colorType"]; - panel.setBackGroundColorType(colorType); - panel.setBackGroundColor(cc.color(scr, scg, scb), cc.color(ecr, ecg, ecb)); - panel.setBackGroundColor(cc.color(cr, cg, cb)); - panel.setBackGroundColorOpacity(co); - - var imageFileName = options["backGroundImage"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - var useMergedTexture = options["useMergedTexture"]; - if (useMergedTexture) { - panel.setBackGroundImage(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - panel.setBackGroundImage(imageFileName_tp); - } - if (backGroundScale9Enable) { - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - panel.setBackGroundImageCapInsets(cc.rect(cx, cy, cw, ch)); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - - setPropsForScrollViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - var scrollView = widget; - var innerWidth = options["innerWidth"]; - var innerHeight = options["innerHeight"]; - scrollView.setInnerContainerSize(cc.size(innerWidth, innerHeight)); - var direction = options["direction"]; - scrollView.setDirection(direction); - scrollView.setBounceEnabled(options["bounceEnable"]); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForContainerWidgetFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var containerWidget = widget; - if (containerWidget instanceof ccui.ScrollView || - containerWidget instanceof ccui.ListView) { - containerWidget.setClippingEnabled(options["clipAble"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForSliderFromJsonDictionary: function (widget, options) { - - this.setPropsForWidgetFromJsonDictionary(widget, options); - var slider = widget; - - var barTextureScale9Enable = options["barTextureScale9Enable"] || false; - slider.setScale9Enabled(barTextureScale9Enable); - var barLength = options["length"]; - var useMergedTexture = options["useMergedTexture"]; - var bt = (options["barFileName"] !== undefined); - if (bt) { - if (barTextureScale9Enable) { - var imageFileName = options["barFileName"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - if (useMergedTexture) { - slider.loadBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - slider.loadBarTexture(imageFileName_tp); - } - slider.setSize(cc.size(barLength, slider.getContentSize().height)); - } - else { - var imageFileName = options["barFileName"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - if (useMergedTexture) { - slider.loadBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - slider.loadBarTexture(imageFileName_tp); - } - } - } - - var normalFileName = options["ballNormal"]; - var pressedFileName = options["ballPressed"]; - var disabledFileName = options["ballDisabled"]; - - var normalFileName_tp = normalFileName ? this._filePath + normalFileName : null; - var pressedFileName_tp = pressedFileName ? this._filePath + pressedFileName : null; - var disabledFileName_tp = disabledFileName ? this._filePath + disabledFileName : null; - if (useMergedTexture) { - slider.loadSlidBallTextures(normalFileName, pressedFileName, disabledFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - slider.loadSlidBallTextures(normalFileName_tp, pressedFileName_tp, disabledFileName_tp); - } - slider.setPercent(options["percent"]); - - var imageFileName = options["progressBarFileName"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - if (useMergedTexture) { - slider.loadProgressBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - slider.loadProgressBarTexture(imageFileName_tp); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForTextAreaFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var textArea = widget; - textArea.setText(options["text"]); - if (options["fontSize"] !== undefined) { - textArea.setFontSize(options["fontSize"]); - } - var cr = options["colorR"] - var cg = options["colorG"]; - var cb = options["colorB"]; - textArea.setColor(cc.color(cr, cg, cb)); - textArea.setFontName(options["fontName"]); - if (options["areaWidth"] !== undefined && options["areaHeight"] !== undefined) { - var size = cc.size(options["areaWidth"], options["areaHeight"]); - textArea.setTextAreaSize(size); - } - if (options["hAlignment"]) { - textArea.setTextHorizontalAlignment(options["hAlignment"]); - } - if (options["vAlignment"]) { - textArea.setTextVerticalAlignment(options["vAlignment"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForTextButtonFromJsonDictionary: function (widget, options) { - this.setPropsForButtonFromJsonDictionary(widget, options); - - var textButton = widget; - textButton.setTitleText(options["text"] || ""); - var cri = options["textColorR"] !== undefined ? options["textColorR"] : 255; - var cgi = options["textColorG"] !== undefined ? options["textColorG"] : 255; - var cbi = options["textColorB"] !== undefined ? options["textColorB"] : 255; - textButton.setTitleColor(cc.color(cri, cgi, cbi)); - if (options["fontSize"] !== undefined) { - textButton.setTitleFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - textButton.setTitleFontName(options["fontName"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForTextFieldFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var textField = widget; - if (options["placeHolder"] !== undefined) { - textField.setPlaceHolder(options["placeHolder"]); - } - textField.setText(options["text"]); - if (options["fontSize"] !== undefined) { - textField.setFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - textField.setFontName(options["fontName"]); - } - if (options["touchSizeWidth"] !== undefined && options["touchSizeHeight"] !== undefined) { - textField.setTouchSize(cc.size(options["touchSizeWidth"], options["touchSizeHeight"])); - } - - var dw = options["width"]; - var dh = options["height"]; - if (dw > 0.0 || dh > 0.0) { - //textField.setSize(CCSizeMake(dw, dh)); - } - var maxLengthEnable = options["maxLengthEnable"]; - textField.setMaxLengthEnabled(maxLengthEnable); - - if (maxLengthEnable) { - var maxLength = options["maxLength"]; - textField.setMaxLength(maxLength); - } - var passwordEnable = options["passwordEnable"]; - textField.setPasswordEnabled(passwordEnable); - if (passwordEnable) { - textField.setPasswordStyleText(options["passwordStyleText"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLoadingBarFromJsonDictionary: function (widget, options) { - - this.setPropsForWidgetFromJsonDictionary(widget, options); - var loadingBar = widget; - var useMergedTexture = options["useMergedTexture"]; - var imageFileName = options["texture"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - if (useMergedTexture) { - loadingBar.loadTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - } - else { - loadingBar.loadTexture(imageFileName_tp); - } - loadingBar.setDirection(options["direction"]); - loadingBar.setPercent(options["percent"]); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForListViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - }, - - setPropsForPageViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - }, - - setPropsForLabelBMFontFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var labelBMFont = widget; - var cmft = options["fileName"]; - var cmf_tp = this._filePath + cmft; - labelBMFont.setFntFile(cmf_tp); - var text = options["text"]; - labelBMFont.setText(text); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - } -}); - -ccs.WidgetPropertiesReader0300 = ccs.WidgetPropertiesReader.extend({ - createWidget: function (jsonDict, fullPath, fileName) { - this._filePath = fullPath == "" ? fullPath : cc.path.join(fullPath, "/"); - var textures = jsonDict["textures"]; - for (var i = 0; i < textures.length; i++) { - var file = textures[i]; - var tp = fullPath; - tp += file; - cc.spriteFrameCache.addSpriteFrames(tp); - } - var fileDesignWidth = jsonDict["designWidth"]; - var fileDesignHeight = jsonDict["designHeight"]; - if (fileDesignWidth <= 0 || fileDesignHeight <= 0) { - cc.log("Read design size error!"); - var winSize = cc.director.getWinSize(); - ccs.uiReader.storeFileDesignSize(fileName, winSize); - } - else { - ccs.uiReader.storeFileDesignSize(fileName, cc.size(fileDesignWidth, fileDesignHeight)); - } - var widgetTree = jsonDict["widgetTree"]; - var widget = this.widgetFromJsonDictionary(widgetTree); - - var size = widget.getContentSize(); - if (size.width == 0 && size.height == 0) { - widget.setSize(cc.size(fileDesignWidth, fileDesignHeight)); - } - - var actions = jsonDict["animation"]; - var rootWidget = widget; - ccs.actionManager.initWithDictionary(fileName, actions, rootWidget); - - widgetTree = null; - actions = null; - return widget; - }, - widgetFromJsonDictionary: function (data) { - var widget = null; - var classname = data["classname"]; - var uiOptions = data["options"]; - if (classname == "Button") { - widget = ccui.Button.create(); - this.setPropsForButtonFromJsonDictionary(widget, uiOptions); - } - else if (classname == "CheckBox") { - widget = ccui.CheckBox.create(); - this.setPropsForCheckBoxFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Label") { - widget = ccui.Text.create(); - this.setPropsForLabelFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LabelAtlas") { - widget = ccui.TextAtlas.create(); - this.setPropsForLabelAtlasFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LoadingBar") { - widget = ccui.LoadingBar.create(); - this.setPropsForLoadingBarFromJsonDictionary(widget, uiOptions); - } else if (classname == "ScrollView") { - widget = ccui.ScrollView.create(); - this.setPropsForScrollViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextArea") { - widget = ccui.Text.create(); - this.setPropsForLabelFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextButton") { - widget = ccui.Button.create(); - this.setPropsForButtonFromJsonDictionary(widget, uiOptions); - } - else if (classname == "TextField") { - widget = ccui.TextField.create(); - this.setPropsForTextFieldFromJsonDictionary(widget, uiOptions); - } - else if (classname == "ImageView") { - widget = ccui.ImageView.create(); - this.setPropsForImageViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Panel") { - widget = ccui.Layout.create(); - this.setPropsForLayoutFromJsonDictionary(widget, uiOptions); - } - else if (classname == "Slider") { - widget = ccui.Slider.create(); - this.setPropsForSliderFromJsonDictionary(widget, uiOptions); - } - else if (classname == "LabelBMFont") { - widget = ccui.TextBMFont.create(); - this.setPropsForLabelBMFontFromJsonDictionary(widget, uiOptions); - } - else if (classname == "DragPanel") { - widget = ccui.ScrollView.create(); - this.setPropsForScrollViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "ListView") { - widget = ccui.ListView.create(); - this.setPropsForListViewFromJsonDictionary(widget, uiOptions); - } - else if (classname == "PageView") { - widget = ccui.PageView.create(); - this.setPropsForPageViewFromJsonDictionary(widget, uiOptions); - } - var children = data["children"]; - for (var i = 0; i < children.length; i++) { - var subData = children[i]; - var child = this.widgetFromJsonDictionary(subData); - if (child) { - if (widget instanceof ccui.PageView && child instanceof ccui.Layout) { - widget.addPage(child); - } else if (widget instanceof ccui.ListView) { - widget.pushBackCustomItem(child); - } else { - widget.addChild(child); - } - } - subData = null; - } - - uiOptions = null; - return widget; - }, - - - setPropsForWidgetFromJsonDictionary: function (widget, options) { - var name = options["name"]; - var widgetName = name ? name : "default"; - widget.setName(widgetName); - - if (options["ignoreSize"] !== undefined) { - widget.ignoreContentAdaptWithSize(options["ignoreSize"]); - } - widget.setSizeType(options["sizeType"]); - widget.setPositionType(options["positionType"]); - - widget.setSizePercent(cc.p(options["sizePercentX"], options["sizePercentY"])); - widget.setPositionPercent(cc.p(options["positionPercentX"], options["positionPercentY"])); - - var w = options["width"]; - var h = options["height"]; - widget.setSize(cc.size(w, h)); - - widget.setTag(options["tag"]); - widget.setActionTag(options["actiontag"]); - widget.setTouchEnabled(options["touchAble"]); - - var x = options["x"]; - var y = options["y"]; - widget.setPosition(x, y); - if (options["scaleX"] !== undefined) { - widget.setScaleX(options["scaleX"]); - } - if (options["scaleY"] !== undefined) { - widget.setScaleY(options["scaleY"]); - } - if (options["rotation"] !== undefined) { - widget.setRotation(options["rotation"]); - } - if (options["visible"] !== undefined) { - widget.setVisible(options["visible"]); - } - - widget.setLocalZOrder(options["ZOrder"]); - var layoutParameterDic = options["layoutParameter"]; - if (layoutParameterDic) { - var paramType = layoutParameterDic["type"]; - var parameter; - switch (paramType) { - case 0: - break; - case 1: - parameter = ccui.LinearLayoutParameter.create(); - var gravity = layoutParameterDic["gravity"]; - parameter.setGravity(gravity); - break; - case 2: - parameter = ccui.RelativeLayoutParameter.create(); - var relativeName = layoutParameterDic["relativeName"]; - parameter.setRelativeName(relativeName); - var relativeToName = layoutParameterDic["relativeToName"]; - parameter.setRelativeToWidgetName(relativeToName); - parameter.setAlign(layoutParameterDic["align"]); - break; - default: - break; - } - var mgl = layoutParameterDic["marginLeft"]; - var mgt = layoutParameterDic["marginTop"]; - var mgr = layoutParameterDic["marginRight"]; - var mgb = layoutParameterDic["marginDown"]; - parameter.setMargin(new ccui.Margin(mgl, mgt, mgr, mgb)); - widget.setLayoutParameter(parameter); - } - }, - - setColorPropsForWidgetFromJsonDictionary: function (widget, options) { - if (options["opacity"] !== undefined) { - widget.setOpacity(options["opacity"]); - } - var colorR = options["colorR"] !== undefined ? options["colorR"] : 255; - var colorG = options["colorG"] !== undefined ? options["colorG"] : 255; - var colorB = options["colorB"] !== undefined ? options["colorB"] : 255; - widget.setColor(cc.color(colorR, colorG, colorB)); - var apx = options["anchorPointX"] !== undefined ? options["anchorPointX"] : ((widget.getWidgetType() == ccui.Widget.TYPE_WIDGET) ? 0.5 : 0); - var apy = options["anchorPointY"] !== undefined ? options["anchorPointY"] : ((widget.getWidgetType() == ccui.Widget.TYPE_WIDGET) ? 0.5 : 0); - widget.setAnchorPoint(apx, apy); - var flipX = options["flipX"]; - var flipY = options["flipY"]; - widget.setFlippedX(flipX); - widget.setFlippedY(flipY); - }, - - setPropsForButtonFromJsonDictionary: function (widget, options) { - - - this.setPropsForWidgetFromJsonDictionary(widget, options); - var button = widget; - var scale9Enable = options["scale9Enable"]; - button.setScale9Enabled(scale9Enable); - - var normalDic = options["normalData"]; - var normalType = normalDic["resourceType"]; - switch (normalType) { - case 0: - var normalFileName = normalDic["path"]; - var normalFileName_tp = normalFileName ? this._filePath + normalFileName : null; - button.loadTextureNormal(normalFileName_tp); - break; - case 1: - var normalFileName = normalDic["path"]; - button.loadTextureNormal(normalFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - normalDic = null; - var pressedDic = options["pressedData"]; - var pressedType = pressedDic["resourceType"]; - switch (pressedType) { - case 0: - var pressedFileName = pressedDic["path"]; - var pressedFileName_tp = pressedFileName ? this._filePath + pressedFileName : null; - button.loadTexturePressed(pressedFileName_tp); - break; - case 1: - var pressedFileName = pressedDic["path"]; - button.loadTexturePressed(pressedFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - pressedDic = null; - var disabledDic = options["disabledData"]; - var disabledType = disabledDic["resourceType"]; - switch (disabledType) { - case 0: - var disabledFileName = disabledDic["path"]; - var disabledFileName_tp = disabledFileName ? this._filePath + disabledFileName : null; - button.loadTextureDisabled(disabledFileName_tp); - break; - case 1: - var disabledFileName = disabledDic["path"]; - button.loadTextureDisabled(disabledFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - disabledDic = null; - if (scale9Enable) { - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - - button.setCapInsets(cc.rect(cx, cy, cw, ch)); - if (options["scale9Width"] !== undefined && options["scale9Height"] !== undefined) { - var swf = options["scale9Width"]; - var shf = options["scale9Height"]; - button.setSize(cc.size(swf, shf)); - } - } - if (options["text"] !== undefined) { - var text = options["text"] || ""; - if (text) - button.setTitleText(text); - } - if (options["fontSize"] !== undefined) { - button.setTitleFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - button.setTitleFontName(options["fontName"]); - } - var cr = options["textColorR"] !== undefined ? options["textColorR"] : 255; - var cg = options["textColorG"] !== undefined ? options["textColorG"] : 255; - var cb = options["textColorB"] !== undefined ? options["textColorB"] : 255; - var tc = cc.color(cr, cg, cb); - button.setTitleColor(tc); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForCheckBoxFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var checkBox = widget; - var backGroundDic = options["backGroundBoxData"]; - var backGroundType = backGroundDic["resourceType"]; - switch (backGroundType) { - case 0: - var backGroundFileName = backGroundDic["path"]; - var backGroundFileName_tp = backGroundFileName ? this._filePath + backGroundFileName : null; - checkBox.loadTextureBackGround(backGroundFileName_tp); - break; - case 1: - var backGroundFileName = backGroundDic["path"]; - checkBox.loadTextureBackGround(backGroundFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - backGroundDic = null; - var backGroundSelectedDic = options["backGroundBoxSelectedData"]; - var backGroundSelectedType = backGroundSelectedDic["resourceType"]; - switch (backGroundSelectedType) { - case 0: - var backGroundSelectedFileName = backGroundSelectedDic["path"]; - var backGroundSelectedFileName_tp = backGroundSelectedFileName ? this._filePath + backGroundSelectedFileName : null; - checkBox.loadTextureBackGroundSelected(backGroundSelectedFileName_tp); - break; - case 1: - var backGroundSelectedFileName = backGroundSelectedDic["path"]; - checkBox.loadTextureBackGroundSelected(backGroundSelectedFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - backGroundSelectedDic = null; - - var frontCrossDic = options["frontCrossData"]; - var frontCrossType = frontCrossDic["resourceType"]; - switch (frontCrossType) { - case 0: - var frontCrossFileName = frontCrossDic["path"]; - var frontCrossFileName_tp = frontCrossFileName ? this._filePath + frontCrossFileName : null; - checkBox.loadTextureFrontCross(frontCrossFileName_tp); - break; - case 1: - var frontCrossFileName = frontCrossDic["path"]; - checkBox.loadTextureFrontCross(frontCrossFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - frontCrossDic = null; - - var backGroundDisabledDic = options["backGroundBoxDisabledData"]; - var backGroundDisabledType = backGroundDisabledDic["resourceType"]; - switch (backGroundDisabledType) { - case 0: - var backGroundDisabledFileName = backGroundDisabledDic["path"]; - var backGroundDisabledFileName_tp = backGroundDisabledFileName ? this._filePath + backGroundDisabledFileName : null; - checkBox.loadTextureBackGroundDisabled(backGroundDisabledFileName_tp); - break; - case 1: - var backGroundDisabledFileName = backGroundDisabledDic["path"]; - checkBox.loadTextureBackGroundDisabled(backGroundDisabledFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - backGroundDisabledDic = null; - - var frontCrossDisabledDic = options["frontCrossDisabledData"]; - var frontCrossDisabledType = frontCrossDisabledDic["resourceType"]; - switch (frontCrossDisabledType) { - case 0: - var frontCrossDisabledFileName = options["path"]; - var frontCrossDisabledFileName_tp = frontCrossDisabledFileName ? this._filePath + frontCrossDisabledFileName : null; - checkBox.loadTextureFrontCrossDisabled(frontCrossDisabledFileName_tp); - break; - case 1: - var frontCrossDisabledFileName = options["path"]; - checkBox.loadTextureFrontCrossDisabled(frontCrossDisabledFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - frontCrossDisabledDic = null; - - var selectedState = options["selectedState"] || false; - widget.setSelectedState(selectedState); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForImageViewFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - - var imageView = widget; - - var imageFileNameDic = options["fileNameData"]; - var imageFileNameType = imageFileNameDic["resourceType"]; - switch (imageFileNameType) { - case 0: - var tp_i = this._filePath; - var imageFileName = imageFileNameDic["path"]; - var imageFileName_tp = null; - if (imageFileName) { - imageFileName_tp = tp_i + imageFileName; - imageView.loadTexture(imageFileName_tp); - } - break; - case 1: - var imageFileName = imageFileNameDic["path"]; - imageView.loadTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - imageFileNameDic = null; - - var scale9Enable = options["scale9Enable"] || false; - imageView.setScale9Enabled(scale9Enable); - - if (scale9Enable) { - if (options["scale9Width"] !== undefined && options["scale9Height"] !== undefined) { - var swf = options["scale9Width"]; - var shf = options["scale9Height"]; - imageView.setSize(cc.size(swf, shf)); - } - - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - - imageView.setCapInsets(cc.rect(cx, cy, cw, ch)); - - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLabelFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var label = widget; - var touchScaleChangeAble = options["touchScaleEnable"]; - label.setTouchScaleChangeEnabled(touchScaleChangeAble); - var text = options["text"]; - label.setText(text); - if (options["fontSize"] !== undefined) { - label.setFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - label.setFontName(options["fontName"]); - } - if (options["areaWidth"] !== undefined && options["areaHeight"] !== undefined) { - var size = cc.size(options["areaWidth"], options["areaHeight"]); - label.setTextAreaSize(size); - } - if (options["hAlignment"]) { - label.setTextHorizontalAlignment(options["hAlignment"]); - } - if (options["vAlignment"]) { - label.setTextVerticalAlignment(options["vAlignment"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLabelAtlasFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var labelAtlas = widget; - var sv = (options["stringValue"] !== undefined); - var cmf = (options["charMapFile"] !== undefined); - var iw = (options["itemWidth"] !== undefined); - var ih = (options["itemHeight"] !== undefined); - var scm = (options["startCharMap"] !== undefined); - if (sv && cmf && iw && ih && scm) { - - var cmftDic = options["charMapFileData"]; - var cmfType = cmftDic["resourceType"]; - switch (cmfType) { - case 0: - var cmfPath = cmftDic["path"]; - var cmf_tp = this._filePath + cmfPath; - labelAtlas.setProperty(options["stringValue"], cmf_tp, options["itemWidth"], options["itemHeight"], options["startCharMap"]); - break; - case 1: - cc.log("Wrong res type of LabelAtlas!"); - break; - default: - break; - } - cmftDic = null; - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLayoutFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var panel = widget; - if (!(panel instanceof ccui.ScrollView) && !(panel instanceof ccui.ListView)) { - panel.setClippingEnabled(options["clipAble"]); - } - var backGroundScale9Enable = options["backGroundScale9Enable"]; - panel.setBackGroundImageScale9Enabled(backGroundScale9Enable); - var cr = options["bgColorR"]; - var cg = options["bgColorG"]; - var cb = options["bgColorB"]; - - var scr = options["bgStartColorR"]; - var scg = options["bgStartColorG"] - var scb = options["bgStartColorB"]; - - var ecr = options["bgEndColorR"]; - var ecg = options["bgEndColorG"]; - var ecb = options["bgEndColorB"]; - - var bgcv1 = options["vectorX"]; - var bgcv2 = options["vectorY"]; - panel.setBackGroundColorVector(cc.p(bgcv1, bgcv2)); - - var co = options["bgColorOpacity"]; - - var colorType = options["colorType"]; - panel.setBackGroundColorType(colorType); - panel.setBackGroundColor(cc.color(scr, scg, scb), cc.color(ecr, ecg, ecb)); - panel.setBackGroundColor(cc.color(cr, cg, cb)); - panel.setBackGroundColorOpacity(co); - - - var imageFileNameDic = options["backGroundImageData"] || {}; - var imageFileNameType = imageFileNameDic["resourceType"]; - switch (imageFileNameType) { - case 0: - var imageFileName = imageFileNameDic["path"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - panel.setBackGroundImage(imageFileName_tp); - break; - case 1: - var imageFileName = imageFileNameDic["path"]; - panel.setBackGroundImage(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - imageFileNameDic = null; - - if (backGroundScale9Enable) { - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - panel.setBackGroundImageCapInsets(cc.rect(cx, cy, cw, ch)); - } - panel.setLayoutType(options["layoutType"]); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - - setPropsForScrollViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - var scrollView = widget; - var innerWidth = options["innerWidth"]; - var innerHeight = options["innerHeight"]; - scrollView.setInnerContainerSize(cc.size(innerWidth, innerHeight)); - var direction = options["direction"]; - scrollView.setDirection(direction); - scrollView.setBounceEnabled(options["bounceEnable"]); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForSliderFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var slider = widget; - - var barTextureScale9Enable = options["barTextureScale9Enable"] || false; - slider.setScale9Enabled(barTextureScale9Enable); - var barLength = options["length"]; - var bt = (options["barFileName"] !== undefined); - if (bt) { - if (barTextureScale9Enable) { - var imageFileNameDic = options["barFileNameData"]; - var imageFileType = imageFileNameDic["resourceType"]; - switch (imageFileType) { - case 0: - var imageFileName = imageFileNameDic["path"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - slider.loadBarTexture(imageFileName_tp); - break; - case 1: - var imageFileName = imageFileNameDic["path"]; - slider.loadBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - - slider.setSize(cc.size(barLength, slider.getContentSize().height)); - imageFileNameDic = null; - } - else { - var imageFileNameDic = options["barFileNameData"]; - var imageFileType = imageFileNameDic["resourceType"]; - switch (imageFileType) { - case 0: - var imageFileName = imageFileNameDic["path"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - slider.loadBarTexture(imageFileName_tp); - break; - case 1: - var imageFileName = imageFileNameDic["path"]; - slider.loadBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - imageFileNameDic = null; - } - } - - var normalDic = options["ballNormalData"]; - var normalType = normalDic["resourceType"]; - switch (normalType) { - case 0: - var normalFileName = normalDic["path"]; - var normalFileName_tp = normalFileName ? this._filePath + normalFileName : null; - slider.loadSlidBallTextureNormal(normalFileName_tp); - break; - case 1: - var normalFileName = normalDic["path"]; - slider.loadSlidBallTextureNormal(normalFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - normalDic = null; - - var pressedDic = options["ballPressedData"]; - var pressedType = pressedDic["resourceType"]; - switch (pressedType) { - case 0: - var pressedFileName = pressedDic["path"]; - var pressedFileName_tp = pressedFileName ? this._filePath + pressedFileName : null; - slider.loadSlidBallTexturePressed(pressedFileName_tp); - break; - case 1: - var pressedFileName = pressedDic["path"]; - slider.loadSlidBallTexturePressed(pressedFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - pressedDic = null; - - var disabledDic = options["ballDisabledData"]; - var disabledType = disabledDic["resourceType"]; - switch (disabledType) { - case 0: - var disabledFileName = disabledDic["path"]; - var disabledFileName_tp = disabledFileName ? this._filePath + disabledFileName : null; - slider.loadSlidBallTextureDisabled(disabledFileName_tp); - break; - case 1: - var disabledFileName = disabledDic["path"]; - slider.loadSlidBallTextureDisabled(disabledFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - disabledDic = null; - - var progressBarDic = options["progressBarData"]; - var progressBarType = progressBarDic["resourceType"]; - switch (progressBarType) { - case 0: - var imageFileName = progressBarDic["path"]; - var imageFileName_tp = imageFileName ? this._filePath + imageFileName : null; - slider.loadProgressBarTexture(imageFileName_tp); - break; - case 1: - var imageFileName = progressBarDic["path"]; - slider.loadProgressBarTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - - slider.setPercent(options["percent"]); - }, - - setPropsForTextAreaFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var textArea = widget; - textArea.setText(options["text"]); - if (options["fontSize"] !== undefined) { - textArea.setFontSize(options["fontSize"]); - } - var cr = options["colorR"] - var cg = options["colorG"]; - var cb = options["colorB"]; - textArea.setColor(cc.color(cr, cg, cb)); - textArea.setFontName(options["fontName"]); - if (options["areaWidth"] !== undefined && options["areaHeight"] !== undefined) { - var size = cc.size(options["areaWidth"], options["areaHeight"]); - textArea.setTextAreaSize(size); - } - if (options["hAlignment"]) { - textArea.setTextHorizontalAlignment(options["hAlignment"]); - } - if (options["vAlignment"]) { - textArea.setTextVerticalAlignment(options["vAlignment"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForTextButtonFromJsonDictionary: function (widget, options) { - this.setPropsForButtonFromJsonDictionary(widget, options); - - var textButton = widget; - textButton.setTitleText(options["text"] || ""); - var cri = options["textColorR"] !== undefined ? options["textColorR"] : 255; - var cgi = options["textColorG"] !== undefined ? options["textColorG"] : 255; - var cbi = options["textColorB"] !== undefined ? options["textColorB"] : 255; - textButton.setTitleColor(cc.color(cri, cgi, cbi)); - if (options["fontSize"] !== undefined) { - textButton.setTitleFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - textButton.setTitleFontName(options["fontName"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForTextFieldFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var textField = widget; - if (options["placeHolder"] !== undefined) { - textField.setPlaceHolder(options["placeHolder"]); - } - textField.setText(options["text"]); - if (options["fontSize"] !== undefined) { - textField.setFontSize(options["fontSize"]); - } - if (options["fontName"] !== undefined) { - textField.setFontName(options["fontName"]); - } - if (options["touchSizeWidth"] !== undefined && options["touchSizeHeight"] !== undefined) { - textField.setTouchSize(cc.size(options["touchSizeWidth"], options["touchSizeHeight"])); - } - - var dw = options["width"]; - var dh = options["height"]; - if (dw > 0.0 || dh > 0.0) { - //textField.setSize(CCSizeMake(dw, dh)); - } - var maxLengthEnable = options["maxLengthEnable"]; - textField.setMaxLengthEnabled(maxLengthEnable); - - if (maxLengthEnable) { - var maxLength = options["maxLength"]; - textField.setMaxLength(maxLength); - } - var passwordEnable = options["passwordEnable"]; - textField.setPasswordEnabled(passwordEnable); - if (passwordEnable) { - textField.setPasswordStyleText(options["passwordStyleText"]); - } - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - }, - - setPropsForLoadingBarFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - var loadingBar = widget; - - var imageFileNameDic = options["textureData"]; - var imageFileNameType = imageFileNameDic["resourceType"]; - switch (imageFileNameType) { - case 0: - var tp_i = this._filePath; - var imageFileName = imageFileNameDic["path"]; - var imageFileName_tp = null; - if (imageFileName) { - imageFileName_tp = tp_i + imageFileName; - loadingBar.loadTexture(imageFileName_tp); - } - break; - case 1: - var imageFileName = imageFileNameDic["path"]; - loadingBar.loadTexture(imageFileName, ccui.Widget.PLIST_TEXTURE); - break; - default: - break; - } - imageFileNameDic = null; - - var scale9Enable = options["scale9Enable"]; - loadingBar.setScale9Enabled(scale9Enable); - - if (scale9Enable) { - var cx = options["capInsetsX"]; - var cy = options["capInsetsY"]; - var cw = options["capInsetsWidth"]; - var ch = options["capInsetsHeight"]; - - loadingBar.setCapInsets(cc.rect(cx, cy, cw, ch)); - - var width = options["width"]; - var height = options["height"]; - loadingBar.setSize(cc.size(width, height)); - } - - loadingBar.setDirection(options["direction"]); - loadingBar.setPercent(options["percent"]); - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - - }, - - setPropsForListViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - var innerWidth = options["innerWidth"] || 0; - var innerHeight = options["innerHeight"] || 0; - widget.setInnerContainerSize(cc.size(innerWidth, innerHeight)); - widget.setDirection(options["direction"] || 0); - widget.setGravity(options["gravity"] || 0); - widget.setItemsMargin(options["itemMargin"] || 0); - }, - - setPropsForPageViewFromJsonDictionary: function (widget, options) { - this.setPropsForLayoutFromJsonDictionary(widget, options); - }, - - setPropsForLabelBMFontFromJsonDictionary: function (widget, options) { - this.setPropsForWidgetFromJsonDictionary(widget, options); - - var labelBMFont = widget; - - var cmftDic = options["fileNameData"]; - var cmfType = cmftDic["resourceType"]; - switch (cmfType) { - case 0: - var cmfPath = cmftDic["path"]; - var cmf_tp = this._filePath + cmfPath; - labelBMFont.setFntFile(cmf_tp); - break; - case 1: - cc.log("Wrong res type of LabelAtlas!"); - break; - default: - break; - } - cmftDic = null; - - var text = options["text"]; - labelBMFont.setText(text); - - this.setColorPropsForWidgetFromJsonDictionary(widget, options); - } -}); diff --git a/extensions/cocostudio/reader/SceneReader.js b/extensions/cocostudio/reader/SceneReader.js deleted file mode 100644 index 2d73b83801..0000000000 --- a/extensions/cocostudio/reader/SceneReader.js +++ /dev/null @@ -1,342 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -/** - * @namespace Base singleton object for ccs.sceneReader - */ -ccs.sceneReader = /** @lends ccs.sceneReader# */{ - _baseBath:"", - _listener:null, - _selector:null, - _node: null, - - /** - * create node with json file that exported by CocoStudio scene editor - * @param pszFileName - * @returns {cc.Node} - */ - createNodeWithSceneFile: function (pszFileName) { - this._baseBath = cc.path.dirname(pszFileName); - var jsonDict = cc.loader.getRes(pszFileName); - - if (!jsonDict) throw "Please load the resource first : " + pszFileName; - - this._node = this.createObject(jsonDict, null); - ccs.triggerManager.parse(jsonDict["Triggers"]||[]); - return this._node; - }, - - /** - * create object from data - * @param {Object} inputFiles - * @param {cc.Node} parenet - * @returns {cc.Node} - */ - createObject: function (inputFiles, parenet) { - var className = inputFiles["classname"]; - if (className == "CCNode") { - var gb = null; - if (!parenet) { - gb = cc.Node.create(); - } - else { - gb = cc.Node.create(); - parenet.addChild(gb); - } - - this.setPropertyFromJsonDict(gb, inputFiles); - - var components = inputFiles["components"]; - for (var i = 0; i < components.length; i++) { - var subDict = components[i]; - if (!subDict) { - break; - } - var className = subDict["classname"]; - var comName = subDict["name"]; - - var fileData = subDict["fileData"]; - var path = "", plistFile = ""; - var resType = 0; - if (fileData != null) { - if(fileData["resourceType"] !== undefined){ - resType = fileData["resourceType"] - }else{ - resType =-1; - } - - path = cc.path.join(this._baseBath, fileData["path"]); - plistFile = fileData["plistFile"]; - } - - var pathExtname = cc.path.extname(path); - - if (className == "CCSprite") { - var sprite = null; - - if (resType == 0) { - if (pathExtname != ".png") continue; - sprite = cc.Sprite.create(path); - } - else if (resType == 1) { - if (pathExtname != ".plist") continue; - - plistFile = cc.path.join(this._baseBath, plistFile); - var pngFile = cc.path.changeExtname(plistFile, ".png"); - cc.spriteFrameCache.addSpriteFrames(plistFile, pngFile); - sprite = cc.Sprite.create("#" + fileData["path"]); - } - else { - continue; - } - - var render = ccs.ComRender.create(sprite, "CCSprite"); - if (comName != null) { - render.setName(comName); - } - - gb.addComponent(render); - this._callSelector(sprite, subDict); - } - else if (className == "CCTMXTiledMap") { - var tmx = null; - if (resType == 0) { - if (pathExtname != ".tmx") continue; - tmx = cc.TMXTiledMap.create(path); - } - else { - continue; - } - - var render = ccs.ComRender.create(tmx, "CCTMXTiledMap"); - if (comName != null) { - render.setName(comName); - } - gb.addComponent(render); - this._callSelector(tmx, subDict); - } - else if (className == "CCParticleSystemQuad") { - if (pathExtname != ".plist") continue; - - var particle = null; - if (resType == 0) { - particle = cc.ParticleSystem.create(path); - } - else { - cc.log("unknown resourcetype on CCParticleSystemQuad!"); - continue; - } - - particle.setPosition(0, 0); - var render = ccs.ComRender.create(particle, "CCParticleSystemQuad"); - if (comName != null) { - render.setName(comName); - } - gb.addComponent(render); - this._callSelector(particle, subDict); - } - else if (className == "CCArmature") { - if (resType != 0) { - continue; - } - var jsonDict = cc.loader.getRes(path); - if (!jsonDict) cc.log("Please load the resource [%s] first!", path); - var armature_data = jsonDict["armature_data"]; - var subData = armature_data[0]; - var name = subData["name"]; - - ccs.armatureDataManager.addArmatureFileInfo(path); - - var armature = ccs.Armature.create(name); - var render = ccs.ComRender.create(armature, "CCArmature"); - if (comName != null) { - render.setName(comName); - } - gb.addComponent(render); - - var actionName = subDict["selectedactionname"]; - if (actionName && armature.getAnimation()) { - armature.getAnimation().play(actionName); - } - jsonDict = null; - subData = null; - this._callSelector(armature, subDict); - } - else if (className == "CCComAudio") { - var audio = null; - if (resType == 0) { - audio = ccs.ComAudio.create(); - } - else { - continue; - } - audio.preloadEffect(path); - if (comName) { - audio.setName(comName); - } - gb.addComponent(audio); - this._callSelector(audio, subDict); - } - else if (className == "CCComAttribute") { - var attribute = null; - if (resType == 0) { - attribute = ccs.ComAttribute.create(); - if (path != "") attribute.parse(path); - } - else { - cc.log("unknown resourcetype on CCComAttribute!"); - continue; - } - if (comName) { - attribute.setName(comName); - } - gb.addComponent(attribute); - this._callSelector(attribute, subDict); - } - else if (className == "CCBackgroundAudio") { - if(!pathExtname) continue; - if(resType!=0) continue; - - var audio = ccs.ComAudio.create(); - audio.preloadBackgroundMusic(path); - audio.setFile(path); - var bLoop = Boolean(subDict["loop"] || 0); - audio.setLoop(bLoop); - if (comName) { - audio.setName(comName); - } - gb.addComponent(audio); - audio.playBackgroundMusic(path, bLoop); - this._callSelector(audio, subDict); - } - else if (className == "GUIComponent") { - var widget = ccs.uiReader.widgetFromJsonFile(path); - var render = ccs.ComRender.create(widget, "GUIComponent"); - if (comName != null) { - render.setName(comName); - } - gb.addComponent(render); - this._callSelector(audio, subDict); - } - subDict = null; - } - var gameobjects = inputFiles["gameobjects"]; - for (var i = 0; i < gameobjects.length; i++) { - var subDict = gameobjects[i]; - if (!subDict) { - break; - } - this.createObject(subDict, gb); - subDict = null; - } - - return gb; - } - - return null; - }, - - - nodeByTag: function (parent, tag) { - if (parent == null) { - return null; - } - var retNode = null; - var children = parent.getChildren(); - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - if (child && child.getTag() == tag) { - retNode = child; - break; - } - else { - retNode = this.nodeByTag(child, tag); - if (retNode) { - break; - } - } - } - return retNode; - }, - - getNodeByTag: function (tag) { - if (this._node == null) { - return null; - } - if (this._node.getTag() == tag) { - return this._node; - } - return this.nodeByTag(this._node, tag); - }, - - /** - * set property - * @param {cc.Node} node - * @param {Object} dict - */ - setPropertyFromJsonDict: function (node, dict) { - var x = (typeof dict["x"] === 'undefined')?0:dict["x"]; - var y = (typeof dict["y"] === 'undefined')?0:dict["y"]; - node.setPosition(x, y); - - var bVisible = Boolean((typeof dict["visible"] === 'undefined')?1:dict["visible"]); - node.setVisible(bVisible); - - var nTag = (typeof dict["objecttag"] === 'undefined')?-1:dict["objecttag"]; - node.setTag(nTag); - - var nZorder = (typeof dict["zorder"] === 'undefined')?0:dict["zorder"]; - node.setLocalZOrder(nZorder); - - var fScaleX = (typeof dict["scalex"] === 'undefined')?1:dict["scalex"]; - var fScaleY = (typeof dict["scaley"] === 'undefined')?1:dict["scaley"]; - node.setScaleX(fScaleX); - node.setScaleY(fScaleY); - - var fRotationZ = (typeof dict["rotation"] === 'undefined')?0:dict["rotation"]; - node.setRotation(fRotationZ); - }, - setTarget : function(selector,listener){ - this._listener = listener; - this._selector = selector; - }, - _callSelector:function(obj,subDict){ - if(this._selector){ - this._selector.call(this._listener,obj,subDict); - } - }, - - version: function () { - return "1.2.0.0"; - }, - - /** - * Clear data - */ - clear: function () { - ccs.triggerManager.removeAll(); - cc.audioEngine.end(); - } -}; \ No newline at end of file diff --git a/extensions/cocostudio/timeline/ActionTimeline.js b/extensions/cocostudio/timeline/ActionTimeline.js new file mode 100644 index 0000000000..d458bb958b --- /dev/null +++ b/extensions/cocostudio/timeline/ActionTimeline.js @@ -0,0 +1,509 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + + +/** + * ActionTimelineData + * @name ccs.ActionTimelineData + * @extend ccs.Class + * @class + * + */ +ccs.ActionTimelineData = ccs.Class.extend({ + + _actionTag: 0, + + ctor: function(actionTag){ + this._init(actionTag); + }, + + _init: function(actionTag){ + this._actionTag = actionTag; + return true; + }, + + /** + * Set the action tag. + * @param {number} actionTag + */ + setActionTag: function(actionTag){ + this._actionTag = actionTag; + }, + + /** + * Gets the action tag. + */ + getActionTag: function(){ + return this._actionTag; + } + +}); + +ccs.ObjectExtensionData = ccs.Class.extend({ + + _customProperty: null, + _timelineData: null, + + ctor: function(){ + this._timelineData = new ccs.ActionTimelineData(0); + return true; + }, + + setActionTag: function(actionTag){ + this._timelineData.setActionTag(actionTag); + }, + + getActionTag: function(){ + return this._timelineData.getActionTag(); + } +}); + +ccs.ObjectExtensionData.create = function(){ + return new ccs.ObjectExtensionData(); +}; + +/** + * Create new ActionTimelineData. + * + * @deprecated v3.0, please use new ccs.ActionTimelineData() instead. + * + * @name ccs.ActionTimelineData.create + * @function + * @param actionTag + * @returns {ccs.ActionTimelineData} + */ +ccs.ActionTimelineData.create = function(actionTag){ + return new ccs.ActionTimelineData(actionTag); +}; + + +/** + * ActionTimeline + * @class + * @extend cc.Action + * + * @property gotoFrameAndPlay + * @property gotoFrameAndPause + */ +ccs.ActionTimeline = cc.Action.extend({ + + _timelineMap: null, + _timelineList: null, + _duration: 0, + _time: null, + _timeSpeed: 1, + _frameInternal: 1/60, + _playing: false, + _currentFrame: 0, + _startFrame: 0, + _endFrame: 0, + _loop: null, + _frameEventListener: null, + _animationInfos: null, + + ctor: function(){ + cc.Action.prototype.ctor.call(this); + this._timelineMap = {}; + this._timelineList = []; + this._animationInfos = {}; + this.init(); + }, + + _gotoFrame: function(frameIndex){ + var size = this._timelineList.length; + for(var i = 0; i < size; i++) + { + this._timelineList[i]._gotoFrame(frameIndex); + } + }, + + _stepToFrame: function(frameIndex){ + var size = this._timelineList.length; + for(var i = 0; i < size; i++){ + this._timelineList[i]._stepToFrame(frameIndex); + } + }, + + //emit frame event, call it when enter a frame + _emitFrameEvent: function(frame){ + if(this._frameEventListener){ + this._frameEventListener(frame); + } + }, + + init: function(){ + return true; + }, + + /** + * Goto the specified frame index, and start playing from this index. + * @param startIndex The animation will play from this index. + * @param [endIndex=] The animation will end at this index. + * @param [currentFrameIndex=] set current frame index. + * @param [loop=] Whether or not the animation need loop. + */ + gotoFrameAndPlay: function(startIndex, endIndex, currentFrameIndex, loop){ + //Consolidation parameters + var i = 0, + argLen = arguments.length; + var num = [], + bool; + for(i; i= this._startFrame && frameIndex <= this._endFrame){ + this._currentFrame = frameIndex; + this._time = this._currentFrame * this._frameInternal; + }else{ + cc.log("frame index is not between start frame and end frame"); + } + + }, + + /** + * Get current frame. + * @returns {number} + */ + getCurrentFrame: function(){ + return this._currentFrame; + }, + + /** + * add Timeline to ActionTimeline + * @param {ccs.Timeline} timeline + */ + addTimeline: function(timeline){ + var tag = timeline.getActionTag(); + if (!this._timelineMap[tag]) { + this._timelineMap[tag] = []; + } + + if (!this._timelineMap[tag].some(function(item){ + if(item === timeline) + return true; + })) { + this._timelineList.push(timeline); + this._timelineMap[tag].push(timeline); + timeline.setActionTimeline(this); + } + + }, + + /** + * remove Timeline to ActionTimeline + * @param {ccs.Timeline} timeline + */ + removeTimeline: function(timeline){ + var tag = timeline.getActionTag(); + if (this._timelineMap[tag]) { + if(this._timelineMap[tag].some(function(item){ + if(item === timeline) + return true; + })) { + cc.arrayRemoveObject(this._timelineMap[tag], timeline); + cc.arrayRemoveObject(this._timelineList, timeline); + timeline.setActionTimeline(null); + } + } + }, + + /** + * Gets the timeline list + * @returns {array | null} + */ + getTimelines: function(){ + return this._timelineList; + }, + + /** + * Set the Frame event + * @param {function} listener + */ + setFrameEventCallFunc: function(listener){ + this._frameEventListener = listener; + }, + + /** + * remove event + */ + clearFrameEventCallFunc: function(){ + this._frameEventListener = null; + }, + + /** + * Clone this timeline + * @returns {ccs.ActionTimeline} + */ + clone: function(){ + var newAction = new ccs.ActionTimeline(); + newAction.setDuration(this._duration); + newAction.setTimeSpeed(this._timeSpeed); + + for (var a in this._timelineMap){ + var timelines = this._timelineMap[a]; + for(var b in timelines) + { + var timeline = timelines[b]; + var newTimeline = timeline.clone(); + newAction.addTimeline(newTimeline); + } + } + + return newAction; + + }, + + /** + * Reverse is not defined; + * @returns {null} + */ + reverse: function(){ + return null; + }, + + /** + * Stepping of this time line. + * @param {number} delta + */ + step: function(delta){ + if (!this._playing || this._timelineMap.length === 0 || this._duration === 0) + { + return; + } + + this._time += delta * this._timeSpeed; + this._currentFrame = this._time / this._frameInternal | 0; + + this._stepToFrame(this._currentFrame); + + if(this._time > this._endFrame * this._frameInternal){ + this._playing = this._loop; + if(!this._playing) + this._time = this._endFrame * this._frameInternal; + else + this.gotoFrameAndPlay(this._startFrame, this._endFrame, this._loop); + } + + }, + + _foreachNodeDescendant: function(parent, callback){ + callback(parent); + + var children = parent.getChildren(); + for (var i=0; i= this._frames[0].getFrameIndex()) + needEnterFrame = true; + + from = to = this._frames[0]; + this._currentKeyFrameIndex = 0; + this._betweenDuration = this._frames[0].getFrameIndex(); + break; + } + else if(frameIndex >= this._frames[length - 1].getFrameIndex()) + { + from = to = this._frames[length - 1]; + this._currentKeyFrameIndex = this._frames[length - 1].getFrameIndex(); + this._betweenDuration = 0; + break; + } + + var target = -1; + var low = 0, + high = length - 1, + mid = 0; + while(low <= high){ + mid = Math.ceil(( low + high )/2); + if(frameIndex >= this._frames[mid].getFrameIndex() && frameIndex < this._frames[mid + 1].getFrameIndex()) + { + target = mid; + break; + } + if(this._frames[mid].getFrameIndex()>frameIndex) + high = mid - 1; + else + low = mid + 1; + } + + from = this._frames[target]; + to = this._frames[target+1]; + + if(target === 0 && this._currentKeyFrameIndex < from.getFrameIndex()) + needEnterFrame = true; + + this._currentKeyFrameIndex = from.getFrameIndex(); + this._betweenDuration = to.getFrameIndex() - from.getFrameIndex(); + } while (0); + + if(needEnterFrame || this._currentKeyFrame != from) { + this._currentKeyFrame = from; + this._currentKeyFrame.onEnter(to); + } + + }, + + _updateCurrentKeyFrame: function(frameIndex){ + //! If play to current frame's front or back, then find current frame again + if (frameIndex < this._currentKeyFrameIndex || frameIndex >= this._currentKeyFrameIndex + this._betweenDuration) + { + var from = null; + var to = null; + + do + { + var length = this._frames.length; + + if (frameIndex < this._frames[0].getFrameIndex()) + { + from = to = this._frames[0]; + this._currentKeyFrameIndex = 0; + this._betweenDuration = this._frames[0].getFrameIndex(); + break; + } + else if(frameIndex >= this._frames[length - 1].getFrameIndex()) + { + from = to = this._frames[length - 1]; + this._currentKeyFrameIndex = this._frames[length - 1].getFrameIndex(); + this._betweenDuration = 0; + break; + } + + do{ + this._fromIndex = this._toIndex; + from = this._frames[this._fromIndex]; + this._currentKeyFrameIndex = from.getFrameIndex(); + + this._toIndex = this._fromIndex + 1; + if (this._toIndex >= length) + { + this._toIndex = 0; + } + + to = this._frames[this._toIndex]; + + if (frameIndex === from.getFrameIndex()) + { + break; + } + }while (frameIndex < from.getFrameIndex() || frameIndex >= to.getFrameIndex()); + + this._betweenDuration = to.getFrameIndex() - from.getFrameIndex(); + + } while (0); + + this._currentKeyFrame = from; + this._currentKeyFrame.onEnter(to); + } + } + +}); + +/** + * Create the Timeline + * + * @deprecated v3.0, please use new ccs.Timeline() instead. + * @returns {ccs.Timeline} + */ +ccs.Timeline.create = function(){ + return new ccs.Timeline(); +}; \ No newline at end of file diff --git a/extensions/cocostudio/trigger/ObjectFactory.js b/extensions/cocostudio/trigger/ObjectFactory.js index be74b1a0f6..c2bc197c82 100644 --- a/extensions/cocostudio/trigger/ObjectFactory.js +++ b/extensions/cocostudio/trigger/ObjectFactory.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,24 +23,62 @@ THE SOFTWARE. ****************************************************************************/ -ccs.objectFactory = { +/** + * The singleton object that creating object factory, it creates object with class name, and manager the type mapping. + * @class + * @name ccs.objectFactory + */ +ccs.objectFactory = /** @lends ccs.objectFactory# */{ _typeMap: {}, - destroyInstance: function () { - this._instance = null; - }, - + /** + * Creates object with class name. if the the class name without register in type map, it returns null. + * @param {String} className + * @returns {*} + */ createObject: function (className) { var o = null; var t = this._typeMap[className]; if (t) { - o = new t._fun(); + if(cc.isFunction(t._fun)) + o = new t._fun(); + else + o = t._fun; } return o; }, + /** + * Registers class type in type map. + * @param {ccs.TInfo} t + */ registerType: function (t) { this._typeMap[t._className] = t; + }, + + /** + * Creates ccui widget object. + * @param {String} name widget name + * @returns {ccui.Widget|null} + */ + createGUI: function(name){ + var object = null; + if(name === "Panel") + name = "Layout"; + else if(name === "TextArea") + name = "Label"; + else if(name === "TextButton") + name = "Button"; + + var t = this._typeMap[name]; + if(t && t._fun) + object = t._fun; + + return object; + }, + + removeAll: function(){ + this._typeMap = {}; } }; diff --git a/extensions/cocostudio/trigger/TriggerBase.js b/extensions/cocostudio/trigger/TriggerBase.js index b8f4f68482..4c773e4476 100644 --- a/extensions/cocostudio/trigger/TriggerBase.js +++ b/extensions/cocostudio/trigger/TriggerBase.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,19 +23,27 @@ THE SOFTWARE. ****************************************************************************/ +/** + * Sends event by trigger manager. + * @function + * @param {Number} event + */ ccs.sendEvent = function (event) { var triggerObjArr = ccs.triggerManager.get(event); - if (triggerObjArr == null) { + if (triggerObjArr == null) return; - } for (var i = 0; i < triggerObjArr.length; i++) { var triObj = triggerObjArr[i]; - if (triObj != null && triObj.detect()) { + if (triObj != null && triObj.detect()) triObj.done(); - } } }; +/** + * Registers a trigger class to objectFactory type map. + * @param {String} className + * @param {function} func + */ ccs.registerTriggerClass = function (className, func) { new ccs.TInfo(className, func); }; \ No newline at end of file diff --git a/extensions/cocostudio/trigger/TriggerMng.js b/extensions/cocostudio/trigger/TriggerMng.js index 988e27893d..e0167a1ab6 100644 --- a/extensions/cocostudio/trigger/TriggerMng.js +++ b/extensions/cocostudio/trigger/TriggerMng.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,20 +23,24 @@ THE SOFTWARE. ****************************************************************************/ -ccs.triggerManager = { +/** + * The trigger manager of Cocostudio + * @class + * @name ccs.triggerManager + */ +ccs.triggerManager = /** @lends ccs.triggerManager# */{ _eventTriggers: {}, _triggerObjs: {}, _movementDispatches: [], - destroyInstance: function () { - this.removeAll(); - this._instance = null; - }, - + /** + * Parses the triggers. + * @param {Array} triggers + */ parse: function (triggers) { for (var i = 0; i < triggers.length; ++i) { var subDict = triggers[i]; - var triggerObj = ccs.TriggerObj.create(); + var triggerObj = new ccs.TriggerObj(); triggerObj.serialize(subDict); var events = triggerObj.getEvents(); for (var j = 0; j < events.length; j++) { @@ -46,25 +51,42 @@ ccs.triggerManager = { } }, + /** + * Returns the event triggers by event id. + * @param {Number} event + * @returns {Array} + */ get: function (event) { return this._eventTriggers[event]; }, + /** + * Returns the trigger object by id + * @param {Number} id + * @returns {ccs.TriggerObj} + */ getTriggerObj: function (id) { return this._triggerObjs[id]; }, + /** + * Adds event and trigger object to trigger manager. + * @param event + * @param triggerObj + */ add: function (event, triggerObj) { var eventTriggers = this._eventTriggers[event]; - if (!eventTriggers) { + if (!eventTriggers) eventTriggers = []; - } - if (eventTriggers.indexOf(triggerObj) == -1) { + if (eventTriggers.indexOf(triggerObj) === -1) { eventTriggers.push(triggerObj); this._eventTriggers[event] = eventTriggers; } }, + /** + * Removes all event triggers from manager. + */ removeAll: function () { for (var key in this._eventTriggers) { var triObjArr = this._eventTriggers[key]; @@ -76,20 +98,25 @@ ccs.triggerManager = { this._eventTriggers = {}; }, + /** + * Removes event object from trigger manager. + * @param {*} event + * @param {*} Obj + * @returns {Boolean} + */ remove: function (event, Obj) { - if (Obj) { + if (Obj) return this._removeObj(event, Obj); - } + var bRet = false; - do - { + do { var triObjects = this._eventTriggers[event]; - if (!triObjects) break; + if (!triObjects) + break; for (var i = 0; i < triObjects.length; i++) { var triObject = triObjects[i]; - if (triObject) { + if (triObject) triObject.removeAll(); - } } delete this._eventTriggers[event]; bRet = true; @@ -116,11 +143,15 @@ ccs.triggerManager = { return bRet; }, + /** + * Removes trigger object from manager + * @param {Number} id + * @returns {boolean} + */ removeTriggerObj: function (id) { var obj = this.getTriggerObj(id); - if (!obj) { + if (!obj) return false; - } var events = obj.getEvents(); for (var i = 0; i < events.length; i++) { var event = events[i]; @@ -128,18 +159,28 @@ ccs.triggerManager = { } return true; }, + + /** + * Returns the event triggers whether is empty. + * @returns {boolean} + */ isEmpty: function () { return !this._eventTriggers || this._eventTriggers.length <= 0; }, + /** + * Adds an armature movement callback to manager. + * @param {ccs.Armature} armature + * @param {function} callFunc + * @param {Object} target + */ addArmatureMovementCallBack: function (armature, callFunc, target) { - if (armature == null || target == null || callFunc == null) { + if (armature == null || target == null || callFunc == null) return; - } var locAmd, hasADD = false; for (var i = 0; i < this._movementDispatches.length; i++) { locAmd = this._movementDispatches[i]; - if (locAmd && locAmd[0] == armature) { + if (locAmd && locAmd[0] === armature) { locAmd.addAnimationEventCallBack(callFunc, target); hasADD = true; } @@ -152,48 +193,77 @@ ccs.triggerManager = { } }, + /** + * Removes armature movement callback from manager. + * @param {ccs.Armature} armature + * @param {Object} target + * @param {function} callFunc + */ removeArmatureMovementCallBack: function (armature, target, callFunc) { - if (armature == null || target == null || callFunc == null) { + if (armature == null || target == null || callFunc == null) return; - } var locAmd; for (var i = 0; i < this._movementDispatches.length; i++) { locAmd = this._movementDispatches[i]; - if (locAmd && locAmd[0] == armature) { + if (locAmd && locAmd[0] === armature) locAmd.removeAnimationEventCallBack(callFunc, target); - } } }, + /** + * Removes an armature's all movement callbacks. + * @param {ccs.Armature} armature + */ removeArmatureAllMovementCallBack: function (armature) { - if (armature == null) { + if (armature == null) return; - } var locAmd; for (var i = 0; i < this._movementDispatches.length; i++) { locAmd = this._movementDispatches[i]; - if (locAmd && locAmd[0] == armature) { + if (locAmd && locAmd[0] === armature) { this._movementDispatches.splice(i, 1); break; } } }, + /** + * Removes all armature movement callbacks from ccs.triggerManager. + */ removeAllArmatureMovementCallBack: function () { - this._movementDispatches = []; + this._movementDispatches.length = 0; }, + /** + * Returns the version of ccs.triggerManager + * @returns {string} + */ version: function () { return "1.2.0.0"; } }; -ccs.ArmatureMovementDispatcher = ccs.Class.extend({ +/** + * The armature movement dispatcher for trigger manager. + * @class + * @extends ccs.Class + */ +ccs.ArmatureMovementDispatcher = ccs.Class.extend(/** @lends ccs.ArmatureMovementDispatcher# */{ _mapEventAnimation: null, + + /** + * Constructor of ArmatureMovementDispatcher. + */ ctor: function () { this._mapEventAnimation = []; }, + /** + * Calls armature movement events. + * @param {ccs.Armature} armature + * @param {Number} movementType + * @param {String} movementID + */ animationEvent: function (armature, movementType, movementID) { var locEventAni, locTarget, locFunc; for (var i = 0; i < this._mapEventAnimation.length; i++) { @@ -205,15 +275,25 @@ ccs.ArmatureMovementDispatcher = ccs.Class.extend({ } }, + /** + * Adds animation event callback to event animation list + * @param {function} callFunc + * @param {Object|null} [target] + */ addAnimationEventCallBack: function (callFunc, target) { this._mapEventAnimation.push([target, callFunc]); }, + /** + * Removes animation event callback from trigger manager. + * @param {function} callFunc + * @param {Object|null} [target] + */ removeAnimationEventCallBack: function (callFunc, target) { var locEventAni; for (var i = 0; i < this._mapEventAnimation.length; i++) { locEventAni = this._mapEventAnimation[i]; - if (locEventAni[0] == target) { + if (locEventAni[0] === target) { this._mapEventAnimation.splice(i, 1); } } diff --git a/extensions/cocostudio/trigger/TriggerObj.js b/extensions/cocostudio/trigger/TriggerObj.js index e0b19d2634..6a8e3c1226 100644 --- a/extensions/cocostudio/trigger/TriggerObj.js +++ b/extensions/cocostudio/trigger/TriggerObj.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2013 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -22,46 +23,94 @@ THE SOFTWARE. ****************************************************************************/ -ccs.BaseTriggerCondition = ccs.Class.extend({ +/** + * The base class of trigger condition. + * @class + * @extends ccs.Class + */ +ccs.BaseTriggerCondition = ccs.Class.extend(/** @lends ccs.BaseTriggerCondition# */{ + /** + * Construction of ccs.BaseTriggerCondition + */ ctor:function(){ - }, + /** + * initializes a BaseTriggerCondition class. + * @returns {boolean} + */ init: function () { return true; }, + /** + * Detects trigger condition + * @returns {boolean} + */ detect: function () { return true; }, + /** + * Serialize a BaseTriggerCondition object. + * @param jsonVal + */ serialize: function (jsonVal) { }, + /** + * Removes all condition + */ removeAll: function () { } }); -ccs.BaseTriggerAction = ccs.Class.extend({ - ctor:function(){ +/** + * The base class of trigger action + * @class + * @extends ccs.Class + */ +ccs.BaseTriggerAction = ccs.Class.extend(/** @lends ccs.BaseTriggerAction# */{ + /** + * Construction of ccs.BaseTriggerAction + */ + ctor:function(){ }, + /** + * Initializes a BaseTriggerAction object. + * @returns {boolean} + */ init: function () { return true; }, + /** + * Sets the action to done. + */ done: function () { - }, + /** + * Serializes a ccs.BaseTriggerAction object. + * @param jsonVal + */ serialize: function (jsonVal) { }, + /** + * Removes all actions. + */ removeAll: function () { } }); -ccs.TriggerObj = ccs.Class.extend({ +/** + * The trigger object of Cocostudio. + * @class + * @extends ccs.Class + */ +ccs.TriggerObj = ccs.Class.extend(/** @lends ccs.TriggerObj# */{ _cons: null, _acts: null, _id: 0, @@ -71,8 +120,14 @@ ccs.TriggerObj = ccs.Class.extend({ ctor: function () { this._id = 0; this._enable = true; + + ccs.TriggerObj.prototype.init.call(this); }, + /** + * Initializes a ccs.TriggerObj + * @returns {boolean} + */ init: function () { this._cons = []; this._acts = []; @@ -80,34 +135,41 @@ ccs.TriggerObj = ccs.Class.extend({ return true; }, + /** + * Detects trigger's conditions. + * @returns {boolean} + */ detect: function () { - if (!this._enable || this._cons.length == 0) { + if (!this._enable || this._cons.length === 0) { return true; } var ret = true; var obj = null; for (var i = 0; i < this._cons.length; i++) { obj = this._cons[i]; - if (obj && obj.detect) { + if (obj && obj.detect) ret = ret && obj.detect(); - } } return ret; }, + /** + * Sets trigger's actions to done. + */ done: function () { - if (!this._enable || this._acts.length == 0) { + if (!this._enable || this._acts.length === 0) return; - } var obj; for (var i = 0; i < this._acts.length; i++) { obj = this._acts[i]; - if (obj && obj.done) { + if (obj && obj.done) obj.done(); - } } }, + /** + * Removes all condition and actions from ccs.TriggerObj. + */ removeAll: function () { var obj = null; for (var i = 0; i < this._cons.length; i++) { @@ -124,6 +186,10 @@ ccs.TriggerObj = ccs.Class.extend({ this._acts = []; }, + /** + * Serializes ccs.TriggerObj + * @param jsonVal + */ serialize: function (jsonVal) { this._id = jsonVal["id"] || 0; var conditions = jsonVal["conditions"] || []; @@ -167,22 +233,31 @@ ccs.TriggerObj = ccs.Class.extend({ } }, + /** + * Returns the id of ccs.TriggerObj. + * @returns {number} + */ getId: function () { return this._id; }, + /** + * Sets enable value. + * @param {Boolean} enable + */ setEnable: function (enable) { this._enable = enable; }, + /** + * Returns the events of ccs.TriggerObj. + * @returns {null|Array} + */ getEvents: function () { return this._vInt; } }); ccs.TriggerObj.create = function () { - var ret = new ccs.TriggerObj(); - if (ret.init()) - return ret; - return null; + return new ccs.TriggerObj(); }; \ No newline at end of file diff --git a/extensions/editbox/CCEditBox.js b/extensions/editbox/CCEditBox.js index f460c290d4..4c68eb84c2 100644 --- a/extensions/editbox/CCEditBox.js +++ b/extensions/editbox/CCEditBox.js @@ -1,5 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2012 James Chen http://www.cocos2d-x.org @@ -144,6 +145,10 @@ cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_SENTENCE = 3; */ cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_ALL_CHARACTERS = 4; +/** + * @class + * @extends cc.Class + */ cc.EditBoxDelegate = cc.Class.extend({ /** * This method is called when an edit box gains focus after keyboard is shown. @@ -222,19 +227,23 @@ cc.EditBox = cc.ControlButton.extend({ _placeholderFontSize: 14, _tooltip: false, - _className:"EditBox", + _className: "EditBox", /** - * * Constructor. - * */ - ctor: function (boxSize) { + * constructor of cc.EditBox + * @param {cc.Size} size + * @param {cc.Scale9Sprite} normal9SpriteBg + * @param {cc.Scale9Sprite} press9SpriteBg + * @param {cc.Scale9Sprite} disabled9SpriteBg + */ + ctor: function (size, normal9SpriteBg, press9SpriteBg, disabled9SpriteBg) { cc.ControlButton.prototype.ctor.call(this); this._textColor = cc.color.WHITE; this._placeholderColor = cc.color.GRAY; - this.setContentSize(boxSize); + this.setContentSize(size); var tmpDOMSprite = this._domInputSprite = new cc.Sprite(); - tmpDOMSprite.draw = function(){ }; //redefine draw function + tmpDOMSprite.draw = function () {}; //redefine draw function this.addChild(tmpDOMSprite); var selfPointer = this; var tmpEdTxt = this._edTxt = cc.newElement("input"); @@ -248,7 +257,9 @@ cc.EditBox = cc.ControlButton.extend({ tmpEdTxt.style.height = "100%"; tmpEdTxt.style.active = 0; tmpEdTxt.style.outline = "medium"; - + tmpEdTxt.style.padding = "0"; + var onCanvasClick = function() { tmpEdTxt.blur();}; + // TODO the event listener will be remove when EditBox removes from parent. cc._addEventListener(tmpEdTxt, "input", function () { if (selfPointer._delegate && selfPointer._delegate.editBoxTextChanged) @@ -262,36 +273,50 @@ cc.EditBox = cc.ControlButton.extend({ } }); cc._addEventListener(tmpEdTxt, "focus", function () { - if (this.value == selfPointer._placeholderText) { + if (this.value === selfPointer._placeholderText) { this.value = ""; - this.style.fontSize = selfPointer._edFontSize + "px" ; + this.style.fontSize = selfPointer._edFontSize + "px"; this.style.color = cc.colorToHex(selfPointer._textColor); + if (selfPointer._editBoxInputFlag === cc.EDITBOX_INPUT_FLAG_PASSWORD) + selfPointer._edTxt.type = "password"; + else + selfPointer._edTxt.type = "text"; } if (selfPointer._delegate && selfPointer._delegate.editBoxEditingDidBegin) selfPointer._delegate.editBoxEditingDidBegin(selfPointer); + cc._addEventListener(cc._canvas, "click", onCanvasClick); }); cc._addEventListener(tmpEdTxt, "blur", function () { - if (this.value == "") { + if (this.value === "") { this.value = selfPointer._placeholderText; - this.style.fontSize = selfPointer._placeholderFontSize + "px" ; + this.style.fontSize = selfPointer._placeholderFontSize + "px"; this.style.color = cc.colorToHex(selfPointer._placeholderColor); + selfPointer._edTxt.type = "text"; } if (selfPointer._delegate && selfPointer._delegate.editBoxEditingDidEnd) selfPointer._delegate.editBoxEditingDidEnd(selfPointer); if (selfPointer._delegate && selfPointer._delegate.editBoxReturn) selfPointer._delegate.editBoxReturn(selfPointer); + cc._canvas.removeEventListener('click', onCanvasClick); }); cc.DOM.convert(tmpDOMSprite); tmpDOMSprite.dom.appendChild(tmpEdTxt); tmpDOMSprite.dom.showTooltipDiv = false; - tmpDOMSprite.dom.style.width = (boxSize.width - 6) +"px"; - tmpDOMSprite.dom.style.height = (boxSize.height - 6) +"px"; + tmpDOMSprite.dom.style.width = (size.width - 6) + "px"; + tmpDOMSprite.dom.style.height = (size.height - 6) + "px"; //this._domInputSprite.dom.style.borderWidth = "1px"; //this._domInputSprite.dom.style.borderStyle = "solid"; //this._domInputSprite.dom.style.borderRadius = "8px"; tmpDOMSprite.canvas.remove(); + + if (this.initWithSizeAndBackgroundSprite(size, normal9SpriteBg)) { + if (press9SpriteBg) + this.setBackgroundSpriteForState(press9SpriteBg, cc.CONTROL_STATE_HIGHLIGHTED); + if (disabled9SpriteBg) + this.setBackgroundSpriteForState(disabled9SpriteBg, cc.CONTROL_STATE_DISABLED); + } }, /** @@ -305,20 +330,20 @@ cc.EditBox = cc.ControlButton.extend({ this._setFontToEditBox(); }, - _setFont: function (fontStyle) { - var res = cc.LabelTTF._fontStyleRE.exec(fontStyle); - if(res) { - this._edFontSize = parseInt(res[1]); - this._edFontName = res[2]; - this._setFontToEditBox(); - } - }, + _setFont: function (fontStyle) { + var res = cc.LabelTTF._fontStyleRE.exec(fontStyle); + if (res) { + this._edFontSize = parseInt(res[1]); + this._edFontName = res[2]; + this._setFontToEditBox(); + } + }, /** * set fontName * @param {String} fontName */ - setFontName: function(fontName){ + setFontName: function (fontName) { this._edFontName = fontName; this._setFontToEditBox(); }, @@ -327,30 +352,49 @@ cc.EditBox = cc.ControlButton.extend({ * set fontSize * @param {Number} fontSize */ - setFontSize: function(fontSize){ + setFontSize: function (fontSize) { this._edFontSize = fontSize; this._setFontToEditBox(); }, _setFontToEditBox: function () { - if (this._edTxt.value != this._placeholderText){ + if (this._edTxt.value !== this._placeholderText) { this._edTxt.style.fontFamily = this._edFontName; - this._edTxt.style.fontSize = this._edFontSize+"px"; + this._edTxt.style.fontSize = this._edFontSize + "px"; + if (this._editBoxInputFlag === cc.EDITBOX_INPUT_FLAG_PASSWORD) + this._edTxt.type = "password"; + else + this._edTxt.type = "text"; } }, /** * Set the text entered in the edit box. + * @deprecated * @param {string} text The given text. */ setText: function (text) { + cc.log("Please use the setString"); + this.setString(text); + }, + + /** + * Set the text entered in the edit box. + * @param {string} text The given text. + */ + setString: function (text) { if (text != null) { - if (text == "") { + if (text === "") { this._edTxt.value = this._placeholderText; this._edTxt.style.color = cc.colorToHex(this._placeholderColor); + this._edTxt.type = "text"; } else { this._edTxt.value = text; this._edTxt.style.color = cc.colorToHex(this._textColor); + if (this._editBoxInputFlag === cc.EDITBOX_INPUT_FLAG_PASSWORD) + this._edTxt.type = "password"; + else + this._edTxt.type = "text"; } } }, @@ -361,7 +405,7 @@ cc.EditBox = cc.ControlButton.extend({ */ setFontColor: function (color) { this._textColor = color; - if (this._edTxt.value != this._placeholderText) { + if (this._edTxt.value !== this._placeholderText) { this._edTxt.style.color = cc.colorToHex(color); } }, @@ -396,7 +440,7 @@ cc.EditBox = cc.ControlButton.extend({ if (text != null) { var oldPlaceholderText = this._placeholderText; this._placeholderText = text; - if (this._edTxt.value == oldPlaceholderText) { + if (this._edTxt.value === oldPlaceholderText) { this._edTxt.value = text; this._edTxt.style.color = cc.colorToHex(this._placeholderColor); this._setPlaceholderFontToEditText(); @@ -414,14 +458,14 @@ cc.EditBox = cc.ControlButton.extend({ this._placeholderFontSize = fontSize; this._setPlaceholderFontToEditText(); }, - _setPlaceholderFont: function (fontStyle) { - var res = cc.LabelTTF._fontStyleRE.exec(fontStyle); - if(res) { - this._placeholderFontName = res[2]; - this._placeholderFontSize = parseInt(res[1]); - this._setPlaceholderFontToEditText(); - } - }, + _setPlaceholderFont: function (fontStyle) { + var res = cc.LabelTTF._fontStyleRE.exec(fontStyle); + if (res) { + this._placeholderFontName = res[2]; + this._placeholderFontSize = parseInt(res[1]); + this._setPlaceholderFontToEditText(); + } + }, /** * Set the placeholder's fontName. @@ -442,9 +486,10 @@ cc.EditBox = cc.ControlButton.extend({ }, _setPlaceholderFontToEditText: function () { - if (this._edTxt.value == this._placeholderText){ + if (this._edTxt.value === this._placeholderText) { this._edTxt.style.fontFamily = this._placeholderFontName; this._edTxt.style.fontSize = this._placeholderFontSize + "px"; + this._edTxt.type = "text"; } }, @@ -454,7 +499,7 @@ cc.EditBox = cc.ControlButton.extend({ */ setPlaceholderFontColor: function (color) { this._placeholderColor = color; - if (this._edTxt.value == this._placeholderText) { + if (this._edTxt.value === this._placeholderText) { this._edTxt.style.color = cc.colorToHex(color); } }, @@ -466,7 +511,7 @@ cc.EditBox = cc.ControlButton.extend({ */ setInputFlag: function (inputFlag) { this._editBoxInputFlag = inputFlag; - if (inputFlag == cc.EDITBOX_INPUT_FLAG_PASSWORD) + if ((this._edTxt.value !== this._placeholderText) && (inputFlag === cc.EDITBOX_INPUT_FLAG_PASSWORD)) this._edTxt.type = "password"; else this._edTxt.type = "text"; @@ -474,9 +519,21 @@ cc.EditBox = cc.ControlButton.extend({ /** * Gets the input string of the edit box. + * @deprecated * @return {string} */ getText: function () { + cc.log("Please use the getString"); + return this._edTxt.value; + }, + + /** + * Gets the input string of the edit box. + * @return {string} + */ + getString: function () { + if(this._edTxt.value === this._placeholderText) + return ""; return this._edTxt.value; }, @@ -488,12 +545,12 @@ cc.EditBox = cc.ControlButton.extend({ initWithSizeAndBackgroundSprite: function (size, normal9SpriteBg) { if (this.initWithBackgroundSprite(normal9SpriteBg)) { this._domInputSprite.x = 3; - this._domInputSprite.y = 3; + this._domInputSprite.y = 3; this.setZoomOnTouchDown(false); this.setPreferredSize(size); this.x = 0; - this.y = 0; + this.y = 0; this._addTargetWithActionForControlEvent(this, this.touchDownAction, cc.CONTROL_EVENT_TOUCH_UP_INSIDE); return true; } @@ -503,6 +560,7 @@ cc.EditBox = cc.ControlButton.extend({ /* override functions */ /** * Set the delegate for edit box. + * @param {cc.EditBoxDelegate} delegate */ setDelegate: function (delegate) { this._delegate = delegate; @@ -563,7 +621,11 @@ cc.EditBox = cc.ControlButton.extend({ //this._editBoxImpl.openKeyboard(); }, - //HTML5 Only + /** + * @warning HTML5 Only + * @param {cc.Size} size + * @param {cc.color} bgColor + */ initWithBackgroundColor: function (size, bgColor) { this._edWidth = size.width; this.dom.style.width = this._edWidth.toString() + "px"; @@ -573,7 +635,7 @@ cc.EditBox = cc.ControlButton.extend({ } }); -window._p = cc.EditBox.prototype; +var _p = cc.EditBox.prototype; // Extended properties /** @expose */ @@ -590,7 +652,7 @@ _p.fontColor; cc.defineGetterSetter(_p, "fontColor", null, _p.setFontColor); /** @expose */ _p.string; -cc.defineGetterSetter(_p, "string", _p.getText, _p.setText); +cc.defineGetterSetter(_p, "string", _p.getString, _p.setString); /** @expose */ _p.maxLength; cc.defineGetterSetter(_p, "maxLength", _p.getMaxLength, _p.setMaxLength); @@ -622,31 +684,31 @@ cc.defineGetterSetter(_p, "inputMode", null, _p.setInputMode); _p.returnType; cc.defineGetterSetter(_p, "returnType", null, _p.setReturnType); -delete window._p; +_p = null; +/** + * get the rect of a node in world coordinate frame + * @function + * @param {cc.Node} node + * @return {cc.Rect} + */ cc.EditBox.getRect = function (node) { var contentSize = node.getContentSize(); var rect = cc.rect(0, 0, contentSize.width, contentSize.height); - return cc.RectApplyAffineTransform(rect, node.nodeToWorldTransform()); + return cc.rectApplyAffineTransform(rect, node.getNodeToWorldTransform()); }; /** * create a edit box with size and background-color or + * @deprecated since v3.0, please use new cc.EditBox(size, normal9SpriteBg, press9SpriteBg, disabled9SpriteBg) instead * @param {cc.Size} size * @param {cc.Scale9Sprite } normal9SpriteBg * @param {cc.Scale9Sprite } [press9SpriteBg] * @param {cc.Scale9Sprite } [disabled9SpriteBg] + * @return {cc.EditBox} */ cc.EditBox.create = function (size, normal9SpriteBg, press9SpriteBg, disabled9SpriteBg) { - var edbox = new cc.EditBox(size); - if (edbox.initWithSizeAndBackgroundSprite(size, normal9SpriteBg)) { - if (press9SpriteBg) - edbox.setBackgroundSpriteForState(press9SpriteBg, cc.CONTROL_STATE_HIGHLIGHTED); - - if (disabled9SpriteBg) - edbox.setBackgroundSpriteForState(disabled9SpriteBg, cc.CONTROL_STATE_DISABLED); - } - return edbox; + return new cc.EditBox(size, normal9SpriteBg, press9SpriteBg, disabled9SpriteBg); }; diff --git a/extensions/editbox/CCdomNode.js b/extensions/editbox/CCdomNode.js index 641c1ecd95..25085855eb 100644 --- a/extensions/editbox/CCdomNode.js +++ b/extensions/editbox/CCdomNode.js @@ -1,7 +1,6 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -25,8 +24,8 @@ ****************************************************************************/ /** * the DOM object - * @class - * @type {Object} + * @namespace + * @name cc.DOM */ cc.DOM = {}; @@ -49,7 +48,7 @@ cc.DOM._addMethods = function (node) { cc.defineGetterSetter(node, "anchorY", node._getAnchorY, node._setAnchorY); cc.defineGetterSetter(node, "scale", node.getScale, node.setScale); cc.defineGetterSetter(node, "scaleX", node.getScaleX, node.setScaleX); - cc.defineGetterSetter(node, "scaleY", node.getScaleY, node.getScaleY); + cc.defineGetterSetter(node, "scaleY", node.getScaleY, node.setScaleY); cc.defineGetterSetter(node, "rotation", node.getRotation, node.setRotation); cc.defineGetterSetter(node, "skewX", node.getSkewX, node.setSkewX); cc.defineGetterSetter(node, "skewY", node.getSkewY, node.setSkewY); @@ -138,6 +137,8 @@ cc.DOM.methods = /** @lends cc.DOM# */{ * @param {Number} [y] The anchor point.y of node. */ setAnchorPoint:function (point, y) { + var cmd = this._renderCmd; + var locAnchorPoint = this._anchorPoint; if (y === undefined) { locAnchorPoint.x = point.x; @@ -146,7 +147,7 @@ cc.DOM.methods = /** @lends cc.DOM# */{ locAnchorPoint.x = point; locAnchorPoint.y = y; } - var locAPP = this._anchorPointInPoints, locSize = this._contentSize; + var locAPP = cmd._anchorPointInPoints, locSize = this._contentSize; locAPP.x = locSize.width * locAnchorPoint.x; locAPP.y = locSize.height * locAnchorPoint.y; @@ -167,12 +168,13 @@ cc.DOM.methods = /** @lends cc.DOM# */{ */ _setAnchorX:function (x) { var locAnchorPoint = this._anchorPoint; + var cmd = this._renderCmd; if (x === locAnchorPoint.x) return; locAnchorPoint.x = x; - var locAPP = this._anchorPointInPoints, locSize = this._contentSize; + var locAPP = cmd._anchorPointInPoints, locSize = this._contentSize; locAPP.x = locSize.width * locAnchorPoint.x; this.dom.style[cc.$.pfx + 'TransformOrigin'] = '' + locAPP.x + 'px ' + -locAPP.y + 'px'; @@ -191,12 +193,13 @@ cc.DOM.methods = /** @lends cc.DOM# */{ */ _setAnchorY:function (y) { var locAnchorPoint = this._anchorPoint; + var cmd = this._renderCmd; if (y === locAnchorPoint.y) return; locAnchorPoint.y = y; - var locAPP = this._anchorPointInPoints, locSize = this._contentSize; + var locAPP = cmd._anchorPointInPoints, locSize = this._contentSize; locAPP.y = locSize.height * locAnchorPoint.y; this.dom.style[cc.$.pfx + 'TransformOrigin'] = '' + locAPP.x + 'px ' + -locAPP.y + 'px'; @@ -215,6 +218,8 @@ cc.DOM.methods = /** @lends cc.DOM# */{ * @param {Number} [height] The untransformed size's height of the node. */ setContentSize:function (size, height) { + var cmd = this._renderCmd; + var locContentSize = this._contentSize; if (height === undefined) { locContentSize.width = size.width; @@ -223,7 +228,7 @@ cc.DOM.methods = /** @lends cc.DOM# */{ locContentSize.width = size; locContentSize.height = height; } - var locAPP = this._anchorPointInPoints, locAnchorPoint = this._anchorPoint; + var locAPP = cmd._anchorPointInPoints, locAnchorPoint = this._anchorPoint; locAPP.x = locContentSize.width * locAnchorPoint.x; locAPP.y = locContentSize.height * locAnchorPoint.y; this.dom.width = locContentSize.width; @@ -243,11 +248,12 @@ cc.DOM.methods = /** @lends cc.DOM# */{ */ _setWidth:function (width) { var locContentSize = this._contentSize; + var cmd = this._renderCmd; if (width === locContentSize.width) return; locContentSize.width = width; - var locAPP = this._anchorPointInPoints, locAnchorPoint = this._anchorPoint; + var locAPP = cmd._anchorPointInPoints, locAnchorPoint = this._anchorPoint; locAPP.x = locContentSize.width * locAnchorPoint.x; this.dom.width = locContentSize.width; this.anchorX = locAnchorPoint.x; @@ -264,11 +270,12 @@ cc.DOM.methods = /** @lends cc.DOM# */{ */ _setHeight:function (height) { var locContentSize = this._contentSize; + var cmd = this._renderCmd; if (height === locContentSize.height) return; locContentSize.height = height; - var locAPP = this._anchorPointInPoints, locAnchorPoint = this._anchorPoint; + var locAPP = cmd._anchorPointInPoints, locAnchorPoint = this._anchorPoint; locAPP.y = locContentSize.height * locAnchorPoint.y; this.dom.height = locContentSize.height; this.anchorY = locAnchorPoint.y; @@ -284,15 +291,10 @@ cc.DOM.methods = /** @lends cc.DOM# */{ * @param {Number} newRotation */ setRotation:function (newRotation) { - if (this._rotation == newRotation) + if (this._rotation === newRotation) return; - //save dirty region when before change - //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); this._rotationX = this._rotationY = newRotation; - this._rotationRadiansX = this._rotationX * (Math.PI / 180); - this._rotationRadiansY = this._rotationY * (Math.PI / 180); - this.setNodeDirty(); this.dom.rotate(newRotation); }, @@ -358,7 +360,11 @@ cc.DOM.methods = /** @lends cc.DOM# */{ //if dom does not have parent, but node has no parent and its running if (this.dom && !this.dom.parentNode) { if (!this.getParent()) { - this.dom.appendTo(cc.container); + if(this.dom.id === ""){ + cc.DOM._createEGLViewDiv(this); + }else{ + this.dom.appendTo(cc.container); + } } else { cc.DOM.parentDOM(this); } @@ -388,7 +394,7 @@ cc.DOM.methods = /** @lends cc.DOM# */{ this.unscheduleAllCallbacks(); // timers - this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.cleanup); + this._arrayMakeObjectsPerformSelector(this._children, cc.Node._stateCallbackType.cleanup); if (this.dom) { this.dom.remove(); } @@ -420,13 +426,13 @@ cc.DOM.methods = /** @lends cc.DOM# */{ }; cc.DOM._resetEGLViewDiv = function(){ - var eglViewDiv = cc.$("#EGLViewDiv"); - if(eglViewDiv){ - var eglViewer = cc.view; - var designSize = eglViewer.getDesignResolutionSize(); - var viewPortRect = eglViewer.getViewPortRect(); - var screenSize = eglViewer.getFrameSize(); - var pixelRatio = eglViewer.getDevicePixelRatio(); + var div = cc.$("#EGLViewDiv"); + if(div){ + var view = cc.view; + var designSize = view.getDesignResolutionSize(); + var viewPortRect = view.getViewPortRect(); + var screenSize = view.getFrameSize(); + var pixelRatio = view.getDevicePixelRatio(); var designSizeWidth = designSize.width, designSizeHeight = designSize.height; if((designSize.width === 0) && (designSize.height === 0)){ designSizeWidth = screenSize.width; @@ -438,15 +444,21 @@ cc.DOM._resetEGLViewDiv = function(){ viewPortWidth = screenSize.width; } - eglViewDiv.style.position = 'absolute'; + div.style.position = 'absolute'; //x.dom.style.display='block'; - eglViewDiv.style.width = designSizeWidth + "px"; - eglViewDiv.style.maxHeight = designSizeHeight + "px"; - eglViewDiv.style.margin = 0; - - eglViewDiv.resize(eglViewer.getScaleX()/pixelRatio, eglViewer.getScaleY()/pixelRatio); - eglViewDiv.style.left = (viewPortWidth - designSizeWidth) / 2 + "px"; - eglViewDiv.style.bottom = "0px"; + div.style.width = designSizeWidth + "px"; + div.style.maxHeight = designSizeHeight + "px"; + div.style.margin = 0; + + div.resize(view.getScaleX()/pixelRatio, view.getScaleY()/pixelRatio); + if (view.getResolutionPolicy() === view._rpNoBorder) { + div.style.left = (view.getFrameSize().width - designSizeWidth)/2 + "px"; + div.style.bottom = (view.getFrameSize().height - designSizeHeight*view.getScaleY()/pixelRatio)/2 + "px"; + } + else { + div.style.left = (designSizeWidth*view.getScaleX()/pixelRatio - designSizeWidth) / 2 + "px"; + div.style.bottom = "0px"; + } } }; @@ -479,41 +491,54 @@ cc.DOM.parentDOM = function (x) { if (eglViewDiv) { p.dom.appendTo(eglViewDiv); } else { - eglViewDiv = cc.$new("div"); - eglViewDiv.id = "EGLViewDiv"; - - var eglViewer = cc.view; - var designSize = eglViewer.getDesignResolutionSize(); - var viewPortRect = eglViewer.getViewPortRect(); - var screenSize = eglViewer.getFrameSize(); - var pixelRatio = eglViewer.getDevicePixelRatio(); - var designSizeWidth = designSize.width, designSizeHeight = designSize.height; - if ((designSize.width === 0) && (designSize.height === 0)) { - designSizeWidth = screenSize.width; - designSizeHeight = screenSize.height; - } + cc.DOM._createEGLViewDiv(p); + } + } + } + return true; +}; - var viewPortWidth = viewPortRect.width/pixelRatio; - if ((viewPortRect.width === 0) && (viewPortRect.height === 0)) { - viewPortWidth = screenSize.width; - } +cc.DOM._createEGLViewDiv = function(p){ + var div = cc.$("#EGLViewDiv"); + if(!div){ + div = cc.$new("div"); + div.id = "EGLViewDiv"; + } - eglViewDiv.style.position = 'absolute'; - //x.dom.style.display='block'; - eglViewDiv.style.width = designSizeWidth + "px"; - eglViewDiv.style.maxHeight = designSizeHeight + "px"; - eglViewDiv.style.margin = 0; + var view = cc.view; + var designSize = view.getDesignResolutionSize(); + var viewPortRect = view.getViewPortRect(); + var screenSize = view.getFrameSize(); + var pixelRatio = view.getDevicePixelRatio(); + var designSizeWidth = designSize.width, designSizeHeight = designSize.height; + if ((designSize.width === 0) && (designSize.height === 0)) { + designSizeWidth = screenSize.width; + designSizeHeight = screenSize.height; + } - eglViewDiv.resize(eglViewer.getScaleX()/pixelRatio, eglViewer.getScaleY()/pixelRatio); - eglViewDiv.style.left = (viewPortWidth - designSizeWidth) / 2 + "px"; - eglViewDiv.style.bottom = "0px"; + var viewPortWidth = viewPortRect.width/pixelRatio; + if ((viewPortRect.width === 0) && (viewPortRect.height === 0)) { + viewPortWidth = screenSize.width; + } - p.dom.appendTo(eglViewDiv); - eglViewDiv.appendTo(cc.container); - } - } + div.style.position = 'absolute'; + //x.dom.style.display='block'; + div.style.width = designSizeWidth + "px"; + div.style.maxHeight = designSizeHeight + "px"; + div.style.margin = 0; + + div.resize(view.getScaleX()/pixelRatio, view.getScaleY()/pixelRatio); + if (view.getResolutionPolicy() === view._rpNoBorder) { + div.style.left = (screenSize.width - designSizeWidth)/2 + "px"; + div.style.bottom = (screenSize.height - designSizeHeight*view.getScaleY()/pixelRatio)/2 + "px"; } - return true; + else { + div.style.left = (designSizeWidth*view.getScaleX()/pixelRatio - designSizeWidth) / 2 + "px"; + div.style.bottom = "0px"; + } + + p.dom.appendTo(div); + div.appendTo(cc.container); }; /** @@ -523,19 +548,15 @@ cc.DOM.parentDOM = function (x) { */ cc.DOM.setTransform = function (x) { if (x.ctx) { - /* x.ctx.save(); - x.ctx.setTransform(1,0,0,1,0,0); - x.ctx.clearRect(0,0,x.canvas.width, x.canvas.height); - x.ctx.restore();*/ x.ctx.translate(x.getAnchorPointInPoints().x, x.getAnchorPointInPoints().y); if (x.isSprite) { var tmp = x._children; x._children = []; - cc.Sprite.prototype.visit.call(x, x.ctx); + cc.Sprite.prototype.visit.call(x); x._children = tmp; } else { - cc.Sprite.prototype.visit.call(x, x.ctx); + cc.Sprite.prototype.visit.call(x); } } if (x.dom) { @@ -599,7 +620,7 @@ cc.DOM.placeHolder = function (x) { * It currently only supports cc.Sprite and cc.MenuItem * @function * @param {cc.Sprite|cc.MenuItem|Array} nodeObject - * * @example + * @example * // example * cc.DOM.convert(Sprite1, Sprite2, Menuitem); * @@ -611,7 +632,7 @@ cc.DOM.convert = function (nodeObject) { if (arguments.length > 1) { cc.DOM.convert(arguments); return; - } else if (arguments.length == 1 && !arguments[0].length) { + } else if (arguments.length === 1 && !arguments[0].length) { cc.DOM.convert([arguments[0]]); return; } diff --git a/extensions/gui/control-extension/CCControl.js b/extensions/gui/control-extension/CCControl.js index 23c583d98d..2ff72a7ee7 100644 --- a/extensions/gui/control-extension/CCControl.js +++ b/extensions/gui/control-extension/CCControl.js @@ -1,6 +1,7 @@ /** - * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * Copyright 2011 Yannick Loriot. * http://yannickloriot.com * @@ -22,8 +23,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * - * - * converted to Javascript / cocos2d-x by Angus C */ /** Number of kinds of control event. */ @@ -56,56 +55,56 @@ cc.CONTROL_STATE_INITIAL = 1 << 3; * certain events occur. * To use the CCControl you have to subclass it. * @class - * @extends cc.LayerRGBA + * @extends cc.Layer * * @property {Number} state - <@readonly> The current control state: cc.CONTROL_STATE_NORMAL | cc.CONTROL_STATE_HIGHLIGHTED | cc.CONTROL_STATE_DISABLED | cc.CONTROL_STATE_SELECTED | cc.CONTROL_STATE_INITIAL * @property {Boolean} enabled - Indicate whether the control node is enbaled * @property {Boolean} selected - Indicate whether the control node is selected * @property {Boolean} highlighted - Indicate whether the control node is highlighted */ -cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ - _isOpacityModifyRGB:false, - _hasVisibleParents:false, +cc.Control = cc.Layer.extend(/** @lends cc.Control# */{ + _isOpacityModifyRGB: false, + _hasVisibleParents: false, _touchListener: null, - _className:"Control", + _className: "Control", - isOpacityModifyRGB:function () { + isOpacityModifyRGB: function () { return this._isOpacityModifyRGB; }, - setOpacityModifyRGB:function (opacityModifyRGB) { + setOpacityModifyRGB: function (opacityModifyRGB) { this._isOpacityModifyRGB = opacityModifyRGB; var children = this.getChildren(); for (var i = 0, len = children.length; i < len; i++) { var selNode = children[i]; - if (selNode && selNode.RGBAProtocol) + if (selNode) selNode.setOpacityModifyRGB(opacityModifyRGB); } }, /** The current control state constant. */ - _state:cc.CONTROL_STATE_NORMAL, - getState:function () { + _state: cc.CONTROL_STATE_NORMAL, + getState: function () { return this._state; }, - _enabled:false, - _selected:false, - _highlighted:false, + _enabled: false, + _selected: false, + _highlighted: false, - _dispatchTable:null, + _dispatchTable: null, /** * Tells whether the control is enabled * @param {Boolean} enabled */ - setEnabled:function (enabled) { + setEnabled: function (enabled) { this._enabled = enabled; - this._state = enabled ? cc.CONTROL_STATE_NORMAL:cc.CONTROL_STATE_DISABLED; + this._state = enabled ? cc.CONTROL_STATE_NORMAL : cc.CONTROL_STATE_DISABLED; this.needsLayout(); }, - isEnabled:function () { + isEnabled: function () { return this._enabled; }, @@ -113,11 +112,11 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * A Boolean value that determines the control selected state. * @param {Boolean} selected */ - setSelected:function (selected) { + setSelected: function (selected) { this._selected = selected; this.needsLayout(); }, - isSelected:function () { + isSelected: function () { return this._selected; }, @@ -125,15 +124,15 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * A Boolean value that determines whether the control is highlighted. * @param {Boolean} highlighted */ - setHighlighted:function (highlighted) { + setHighlighted: function (highlighted) { this._highlighted = highlighted; this.needsLayout(); }, - isHighlighted:function () { + isHighlighted: function () { return this._highlighted; }, - hasVisibleParents:function () { + hasVisibleParents: function () { var parent = this.getParent(); for (var c = parent; c != null; c = c.getParent()) { if (!c.isVisible()) @@ -142,14 +141,14 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ return true; }, - ctor:function () { - cc.LayerRGBA.prototype.ctor.call(this); + ctor: function () { + cc.Layer.prototype.ctor.call(this); this._dispatchTable = {}; this._color = cc.color.WHITE; }, - init:function () { - if (cc.LayerRGBA.prototype.init.call(this)) { + init: function () { + if (cc.Layer.prototype.init.call(this)) { // Initialise instance variables this._state = cc.CONTROL_STATE_NORMAL; this._enabled = true; @@ -157,15 +156,16 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ this._highlighted = false; var listener = cc.EventListener.create({ - event: cc.EventListener.TOUCH_ONE_BY_ONE + event: cc.EventListener.TOUCH_ONE_BY_ONE, + swallowTouches: true }); - if(this.onTouchBegan) + if (this.onTouchBegan) listener.onTouchBegan = this.onTouchBegan.bind(this); - if(this.onTouchMoved) + if (this.onTouchMoved) listener.onTouchMoved = this.onTouchMoved.bind(this); - if(this.onTouchEnded) + if (this.onTouchEnded) listener.onTouchEnded = this.onTouchEnded.bind(this); - if(this.onTouchCancelled) + if (this.onTouchCancelled) listener.onTouchCancelled = this.onTouchCancelled.bind(this); this._touchListener = listener; return true; @@ -173,9 +173,9 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ return false; }, - onEnter: function(){ + onEnter: function () { var locListener = this._touchListener; - if(!locListener._isRegistered()) + if (!locListener._isRegistered()) cc.eventManager.addListener(locListener, this); cc.Node.prototype.onEnter.call(this); }, @@ -185,7 +185,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * which action messages are sent. See "CCControlEvent" for bitmask constants. * @param {Number} controlEvents A bitmask whose set flags specify the control events for */ - sendActionsForControlEvents:function (controlEvents) { + sendActionsForControlEvents: function (controlEvents) { // For each control events for (var i = 0, len = cc.CONTROL_EVENT_TOTAL_NUMBER; i < len; i++) { // If the given controlEvents bitmask contains the curent event @@ -212,7 +212,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param {function} action A selector identifying an action message. It cannot be NULL. * @param {Number} controlEvents A bitmask specifying the control events for which the action message is sent. See "CCControlEvent" for bitmask constants. */ - addTargetWithActionForControlEvents:function (target, action, controlEvents) { + addTargetWithActionForControlEvents: function (target, action, controlEvents) { // For each control events for (var i = 0, len = cc.CONTROL_EVENT_TOTAL_NUMBER; i < len; i++) { // If the given controlEvents bit mask contains the current event @@ -228,7 +228,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param {function} action A selector identifying an action message. Pass NULL to remove all action messages paired with target. * @param {Number} controlEvents A bitmask specifying the control events associated with target and action. See "CCControlEvent" for bitmask constants. */ - removeTargetWithActionForControlEvents:function (target, action, controlEvents) { + removeTargetWithActionForControlEvents: function (target, action, controlEvents) { // For each control events for (var i = 0, len = cc.CONTROL_EVENT_TOTAL_NUMBER; i < len; i++) { // If the given controlEvents bitmask contains the current event @@ -242,7 +242,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * control space coordinates. * @param {cc.Touch} touch A CCTouch object that represents a touch. */ - getTouchLocation:function (touch) { + getTouchLocation: function (touch) { var touchLocation = touch.getLocation(); // Get the touch position return this.convertToNodeSpace(touchLocation); // Convert to the node space of this class }, @@ -253,7 +253,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param {cc.Touch} touch A cc.Touch object that represents a touch. * @return {Boolean} YES whether a touch is inside the receiver's rect. */ - isTouchInside:function (touch) { + isTouchInside: function (touch) { var touchLocation = touch.getLocation(); // Get the touch position touchLocation = this.getParent().convertToNodeSpace(touchLocation); return cc.rectContainsPoint(this.getBoundingBox(), touchLocation); @@ -271,7 +271,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * * @return {cc.Invocation} an CCInvocation object able to construct messages using a given target-action pair. */ - _invocationWithTargetAndActionForControlEvent:function (target, action, controlEvent) { + _invocationWithTargetAndActionForControlEvent: function (target, action, controlEvent) { return null; }, @@ -281,7 +281,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param {Number} controlEvent A control events for which the action message is sent. See "CCControlEvent" for constants. * @return {cc.Invocation} the cc.Invocation list for the given control event. */ - _dispatchListforControlEvent:function (controlEvent) { + _dispatchListforControlEvent: function (controlEvent) { controlEvent = controlEvent.toString(); // If the invocation list does not exist for the dispatch table, we create it if (!this._dispatchTable[controlEvent]) @@ -302,7 +302,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param controlEvent A control event for which the action message is sent. * See "CCControlEvent" for constants. */ - _addTargetWithActionForControlEvent:function (target, action, controlEvent) { + _addTargetWithActionForControlEvent: function (target, action, controlEvent) { // Create the invocation object var invocation = new cc.Invocation(target, action, controlEvent); @@ -318,7 +318,7 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ * @param {function} action A selector identifying an action message. Pass NULL to remove all action messages paired with target. * @param {Number} controlEvent A control event for which the action message is sent. See "CCControlEvent" for constants. */ - _removeTargetWithActionForControlEvent:function (target, action, controlEvent) { + _removeTargetWithActionForControlEvent: function (target, action, controlEvent) { // Retrieve all invocations for the given control event // var eventInvocationList = this._dispatchListforControlEvent(controlEvent); @@ -331,18 +331,18 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ eventInvocationList.length = 0; } else { //normally we would use a predicate, but this won't work here. Have to do it manually - for (var i = 0; i < eventInvocationList.length; ) { + for (var i = 0; i < eventInvocationList.length;) { var invocation = eventInvocationList[i]; var shouldBeRemoved = true; if (target) - shouldBeRemoved = (target == invocation.getTarget()); + shouldBeRemoved = (target === invocation.getTarget()); if (action) - shouldBeRemoved = (shouldBeRemoved && (action == invocation.getAction())); + shouldBeRemoved = (shouldBeRemoved && (action === invocation.getAction())); // Remove the corresponding invocation object if (shouldBeRemoved) cc.arrayRemoveObject(eventInvocationList, invocation); else - i ++; + i++; } } }, @@ -350,11 +350,11 @@ cc.Control = cc.LayerRGBA.extend(/** @lends cc.Control# */{ /** * Updates the control layout using its current internal state. */ - needsLayout:function () { + needsLayout: function () { } }); -window._p = cc.Control.prototype; +var _p = cc.Control.prototype; // Extended properties /** @expose */ @@ -370,7 +370,7 @@ cc.defineGetterSetter(_p, "selected", _p.isSelected, _p.setSelected); _p.highlighted; cc.defineGetterSetter(_p, "highlighted", _p.isHighlighted, _p.setHighlighted); -delete window._p; +_p = null; cc.Control.create = function () { var retControl = new cc.Control(); diff --git a/extensions/gui/control-extension/CCControlButton.js b/extensions/gui/control-extension/CCControlButton.js index 19c451fe9c..068a649ff8 100644 --- a/extensions/gui/control-extension/CCControlButton.js +++ b/extensions/gui/control-extension/CCControlButton.js @@ -1,7 +1,9 @@ /** * CCControlButton.m * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * Copyright 2011 Yannick Loriot. * http://yannickloriot.com * @@ -40,27 +42,27 @@ cc.CONTROL_ZOOM_ACTION_TAG = 0xCCCB0001; * @property {Boolean} labelAnchor - The anchor point for the label of the control button */ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ - _doesAdjustBackgroundImage:false, - zoomOnTouchDown:false, + _doesAdjustBackgroundImage: false, + zoomOnTouchDown: false, _preferredSize: null, _labelAnchorPoint: null, _currentTitle: null, _currentTitleColor: null, - _titleLabel:null, - _backgroundSprite:null, - _opacity:0, - _isPushed:false, - _titleDispatchTable:null, - _titleColorDispatchTable:null, - _titleLabelDispatchTable:null, - _backgroundSpriteDispatchTable:null, - _parentInited:false, - - _marginV:0, - _marginH:0, - _className:"ControlButton", - - ctor:function () { + _titleLabel: null, + _backgroundSprite: null, + _opacity: 0, + _isPushed: false, + _titleDispatchTable: null, + _titleColorDispatchTable: null, + _titleLabelDispatchTable: null, + _backgroundSpriteDispatchTable: null, + _parentInited: false, + + _marginV: 0, + _marginH: 0, + _className: "ControlButton", + + ctor: function (label, backgroundSprite, fontSize) { cc.Control.prototype.ctor.call(this); this._preferredSize = cc.size(0, 0); this._labelAnchorPoint = cc.p(0, 0); @@ -70,20 +72,29 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ this._titleColorDispatchTable = {}; this._titleLabelDispatchTable = {}; this._backgroundSpriteDispatchTable = {}; + + if(fontSize != undefined) + this.initWithTitleAndFontNameAndFontSize(label, backgroundSprite, fontSize); + else if(backgroundSprite != undefined) + this.initWithLabelAndBackgroundSprite(label, backgroundSprite); + else if(label != undefined) + this.initWithBackgroundSprite(label); + else + this.init(); }, - init:function () { - return this.initWithLabelAndBackgroundSprite(cc.LabelTTF.create("", "Arial", 12), cc.Scale9Sprite.create()); + init: function () { + return this.initWithLabelAndBackgroundSprite(new cc.LabelTTF("", "Arial", 12), new cc.Scale9Sprite()); }, - needsLayout:function () { + needsLayout: function () { if (!this._parentInited) { return; } // Hide the background and the label - if(this._titleLabel) + if (this._titleLabel) this._titleLabel.setVisible(false); - if(this._backgroundSprite) + if (this._backgroundSprite) this._backgroundSprite.setVisible(false); // Update anchor of all labels @@ -100,22 +111,22 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ var label = this._titleLabel; if (label && label.setString) label.setString(this._currentTitle); - if (label && label.RGBAProtocol) + if (label) label.setColor(this._currentTitleColor); var locContentSize = this.getContentSize(); - if(label) + if (label) label.setPosition(locContentSize.width / 2, locContentSize.height / 2); // Update the background sprite this._backgroundSprite = this.getBackgroundSpriteForState(locState); var locBackgroundSprite = this._backgroundSprite; - if(locBackgroundSprite) + if (locBackgroundSprite) locBackgroundSprite.setPosition(locContentSize.width / 2, locContentSize.height / 2); // Get the title label size var titleLabelSize = cc.size(0, 0); - if(label){ + if (label) { var boundingBox = label.getBoundingBox(); titleLabelSize.width = boundingBox.width; titleLabelSize.height = boundingBox.height; @@ -123,11 +134,11 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ // Adjust the background image if necessary if (this._doesAdjustBackgroundImage) { // Add the margins - if(locBackgroundSprite) + if (locBackgroundSprite) locBackgroundSprite.setContentSize(titleLabelSize.width + this._marginH * 2, titleLabelSize.height + this._marginV * 2); } else { //TODO: should this also have margins if one of the preferred sizes is relaxed? - if(locBackgroundSprite){ + if (locBackgroundSprite) { var preferredSize = locBackgroundSprite.getPreferredSize(); preferredSize = cc.size(preferredSize.width, preferredSize.height); if (preferredSize.width <= 0) @@ -140,25 +151,25 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ } // Set the content size - var rectTitle = label? label.getBoundingBox():cc.rect(0,0,0,0); - var rectBackground = locBackgroundSprite? locBackgroundSprite.getBoundingBox():cc.rect(0,0,0,0); + var rectTitle = label ? label.getBoundingBox() : cc.rect(0, 0, 0, 0); + var rectBackground = locBackgroundSprite ? locBackgroundSprite.getBoundingBox() : cc.rect(0, 0, 0, 0); var maxRect = cc.rectUnion(rectTitle, rectBackground); this.setContentSize(maxRect.width, maxRect.height); locContentSize = this.getContentSize(); - if(label){ + if (label) { label.setPosition(locContentSize.width / 2, locContentSize.height / 2); label.setVisible(true); } - if(locBackgroundSprite){ + if (locBackgroundSprite) { locBackgroundSprite.setPosition(locContentSize.width / 2, locContentSize.height / 2); locBackgroundSprite.setVisible(true); } }, - initWithLabelAndBackgroundSprite:function (label, backgroundSprite) { - if(!label || !label.RGBAProtocol) + initWithLabelAndBackgroundSprite: function (label, backgroundSprite) { + if (!label) throw "cc.ControlButton.initWithLabelAndBackgroundSprite(): label should be non-null"; - if(!backgroundSprite) + if (!backgroundSprite) throw "cc.ControlButton.initWithLabelAndBackgroundSprite(): backgroundSprite should be non-null"; if (cc.Control.prototype.init.call(this, true)) { this._parentInited = true; @@ -176,7 +187,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ // Adjust the background image by default this.setAdjustBackgroundImage(true); - this.setPreferredSize(cc.size(0,0)); + this.setPreferredSize(cc.size(0, 0)); // Zooming button by default this.zoomOnTouchDown = true; @@ -219,13 +230,13 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ return false; }, - initWithTitleAndFontNameAndFontSize:function (title, fontName, fontSize) { - var label = cc.LabelTTF.create(title, fontName, fontSize); - return this.initWithLabelAndBackgroundSprite(label, cc.Scale9Sprite.create()); + initWithTitleAndFontNameAndFontSize: function (title, fontName, fontSize) { + var label = new cc.LabelTTF(title, fontName, fontSize); + return this.initWithLabelAndBackgroundSprite(label, new cc.Scale9Sprite()); }, - initWithBackgroundSprite:function (sprite) { - var label = cc.LabelTTF.create("", "Arial", 30);// + initWithBackgroundSprite: function (sprite) { + var label = new cc.LabelTTF("", "Arial", 30);// return this.initWithLabelAndBackgroundSprite(label, sprite); }, @@ -233,30 +244,30 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * Adjust the background image. YES by default. If the property is set to NO, the background will use the prefered size of the background image. * @return {Boolean} */ - doesAdjustBackgroundImage:function () { + doesAdjustBackgroundImage: function () { return this._doesAdjustBackgroundImage; }, - setAdjustBackgroundImage:function (adjustBackgroundImage) { + setAdjustBackgroundImage: function (adjustBackgroundImage) { this._doesAdjustBackgroundImage = adjustBackgroundImage; this.needsLayout(); }, /** Adjust the button zooming on touchdown. Default value is YES. */ - getZoomOnTouchDown:function () { + getZoomOnTouchDown: function () { return this.zoomOnTouchDown; }, - setZoomOnTouchDown:function (zoomOnTouchDown) { + setZoomOnTouchDown: function (zoomOnTouchDown) { return this.zoomOnTouchDown = zoomOnTouchDown; }, /** The prefered size of the button, if label is larger it will be expanded. */ - getPreferredSize:function () { + getPreferredSize: function () { return this._preferredSize; }, - setPreferredSize:function (size) { + setPreferredSize: function (size) { if (size.width === 0 && size.height === 0) { this._doesAdjustBackgroundImage = true; } else { @@ -269,12 +280,12 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ this.needsLayout(); }, - getLabelAnchorPoint:function () { + getLabelAnchorPoint: function () { return this._labelAnchorPoint; }, - setLabelAnchorPoint:function (labelAnchorPoint) { + setLabelAnchorPoint: function (labelAnchorPoint) { this._labelAnchorPoint = labelAnchorPoint; - if(this._titleLabel) + if (this._titleLabel) this._titleLabel.setAnchorPoint(labelAnchorPoint); }, @@ -282,59 +293,59 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * The current title that is displayed on the button. * @return {string} */ - _getCurrentTitle:function () { + _getCurrentTitle: function () { return this._currentTitle; }, /** The current color used to display the title. */ - _getCurrentTitleColor:function () { + _getCurrentTitleColor: function () { return this._currentTitleColor; }, /* Override setter to affect a background sprite too */ - getOpacity:function () { + getOpacity: function () { return this._opacity; }, - setOpacity:function (opacity) { + setOpacity: function (opacity) { // XXX fixed me if not correct cc.Control.prototype.setOpacity.call(this, opacity); /*this._opacity = opacity; - var controlChildren = this.getChildren(); - for (var i = 0; i < controlChildren.length; i++) { - var selChild = controlChildren[i]; - if (selChild && selChild.RGBAProtocol) - selChild.setOpacity(opacity); - }*/ + var controlChildren = this.getChildren(); + for (var i = 0; i < controlChildren.length; i++) { + var selChild = controlChildren[i]; + if (selChild) + selChild.setOpacity(opacity); + }*/ var locTable = this._backgroundSpriteDispatchTable; for (var itemKey in locTable) locTable[itemKey].setOpacity(opacity); }, - setColor:function(color){ - cc.Control.prototype.setColor.call(this,color); + setColor: function (color) { + cc.Control.prototype.setColor.call(this, color); var locTable = this._backgroundSpriteDispatchTable; - for(var key in locTable) + for (var key in locTable) locTable[key].setColor(color); }, - getColor:function(){ + getColor: function () { var locRealColor = this._realColor; return cc.color(locRealColor.r, locRealColor.g, locRealColor.b, locRealColor.a); }, /** Flag to know if the button is currently pushed. */ - isPushed:function () { + isPushed: function () { return this._isPushed; }, /* Define the button margin for Top/Bottom edge */ - _getVerticalMargin:function () { + _getVerticalMargin: function () { return this._marginV; }, /* Define the button margin for Left/Right edge */ - _getHorizontalOrigin:function () { + _getHorizontalOrigin: function () { return this._marginH; }, @@ -343,40 +354,40 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Number} marginH * @param {Number} marginV */ - setMargins:function (marginH, marginV) { + setMargins: function (marginH, marginV) { this._marginV = marginV; this._marginH = marginH; this.needsLayout(); }, - setEnabled:function (enabled) { + setEnabled: function (enabled) { cc.Control.prototype.setEnabled.call(this, enabled); this.needsLayout(); }, - setSelected:function (enabled) { + setSelected: function (enabled) { cc.Control.prototype.setSelected.call(this, enabled); this.needsLayout(); }, - setHighlighted:function (enabled) { - this._state = enabled?cc.CONTROL_STATE_HIGHLIGHTED:cc.CONTROL_STATE_NORMAL; + setHighlighted: function (enabled) { + this._state = enabled ? cc.CONTROL_STATE_HIGHLIGHTED : cc.CONTROL_STATE_NORMAL; cc.Control.prototype.setHighlighted.call(this, enabled); var action = this.getActionByTag(cc.CONTROL_ZOOM_ACTION_TAG); if (action) this.stopAction(action); - this.needsLayout(); + //this.needsLayout();// needn't if (this.zoomOnTouchDown) { var scaleValue = (this.isHighlighted() && this.isEnabled() && !this.isSelected()) ? 1.1 : 1.0; - var zoomAction = cc.ScaleTo.create(0.05, scaleValue); + var zoomAction = cc.scaleTo(0.05, scaleValue); zoomAction.setTag(cc.CONTROL_ZOOM_ACTION_TAG); this.runAction(zoomAction); } }, - onTouchBegan:function (touch, event) { - if (!this.isTouchInside(touch) || !this.isEnabled()|| !this.isVisible()||!this.hasVisibleParents()) + onTouchBegan: function (touch, event) { + if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible() || !this.hasVisibleParents()) return false; this._isPushed = true; @@ -385,7 +396,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ return true; }, - onTouchMoved:function (touch, event) { + onTouchMoved: function (touch, event) { if (!this._enabled || !this._isPushed || this._selected) { if (this._highlighted) this.setHighlighted(false); @@ -405,7 +416,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DRAG_OUTSIDE); } }, - onTouchEnded:function (touch, event) { + onTouchEnded: function (touch, event) { this._isPushed = false; this.setHighlighted(false); @@ -416,7 +427,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ } }, - onTouchCancelled:function (touch, event) { + onTouchCancelled: function (touch, event) { this._isPushed = false; this.setHighlighted(false); this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_CANCEL); @@ -428,7 +439,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Number} state The state that uses the title. Possible values are described in "CCControlState". * @return {string} The title for the specified state. */ - getTitleForState:function (state) { + getTitleForState: function (state) { var locTable = this._titleDispatchTable; if (locTable) { if (locTable[state]) @@ -446,11 +457,11 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {string} title The title string to use for the specified state. * @param {Number} state The state that uses the specified title. The values are described in "CCControlState". */ - setTitleForState:function (title, state) { + setTitleForState: function (title, state) { this._titleDispatchTable[state] = title || ""; // If the current state if equal to the given state we update the layout - if (this.getState() == state) + if (this.getState() === state) this.needsLayout(); }, @@ -476,12 +487,12 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {cc.Color} color The color of the title to use for the specified state. * @param {Number} state The state that uses the specified color. The values are described in "CCControlState". */ - setTitleColorForState:function (color, state) { + setTitleColorForState: function (color, state) { //ccColor3B* colorValue=&color; this._titleColorDispatchTable[state] = color; // If the current state if equal to the given state we update the layout - if (this.getState() == state) + if (this.getState() === state) this.needsLayout(); }, @@ -491,7 +502,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param state The state that uses the title label. Possible values are described in "CCControlState". * @return {cc.Node} the title label used for a state. */ - getTitleLabelForState:function (state) { + getTitleLabelForState: function (state) { var locTable = this._titleLabelDispatchTable; if (locTable[state]) return locTable[state]; @@ -506,7 +517,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {cc.Node} titleLabel The title label to use for the specified state. * @param {Number} state The state that uses the specified title. The values are described in "CCControlState". */ - setTitleLabelForState:function (titleLabel, state) { + setTitleLabelForState: function (titleLabel, state) { var locTable = this._titleLabelDispatchTable; if (locTable[state]) { var previousLabel = locTable[state]; @@ -520,7 +531,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ this.addChild(titleLabel, 1); // If the current state if equal to the given state we update the layout - if (this.getState() == state) + if (this.getState() === state) this.needsLayout(); }, @@ -529,11 +540,11 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {string} fntFile * @param {Number} state */ - setTitleTTFForState:function (fntFile, state) { + setTitleTTFForState: function (fntFile, state) { var title = this.getTitleForState(state); if (!title) title = ""; - this.setTitleLabelForState(cc.LabelTTF.create(title, fntFile, 12), state); + this.setTitleLabelForState(new cc.LabelTTF(title, fntFile, 12), state); }, /** @@ -541,7 +552,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Number} state * @returns {string} */ - getTitleTTFForState:function (state) { + getTitleTTFForState: function (state) { var labelTTF = this.getTitleLabelForState(state); if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) { return labelTTF.getFontName(); @@ -554,7 +565,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Number} size * @param {Number} state */ - setTitleTTFSizeForState:function (size, state) { + setTitleTTFSizeForState: function (size, state) { var labelTTF = this.getTitleLabelForState(state); if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) { labelTTF.setFontSize(size); @@ -566,7 +577,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Number} state * @returns {Number} */ - getTitleTTFSizeForState:function (state) { + getTitleTTFSizeForState: function (state) { var labelTTF = this.getTitleLabelForState(state); if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) { return labelTTF.getFontSize(); @@ -579,14 +590,14 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {string} fntFile The name of the font to change to * @param {Number} state The state that uses the specified fntFile. The values are described in "CCControlState". */ - setTitleBMFontForState:function (fntFile, state) { + setTitleBMFontForState: function (fntFile, state) { var title = this.getTitleForState(state); if (!title) title = ""; - this.setTitleLabelForState(cc.LabelBMFont.create(title, fntFile), state); + this.setTitleLabelForState(new cc.LabelBMFont(title, fntFile), state); }, - getTitleBMFontForState:function (state) { + getTitleBMFontForState: function (state) { var labelBMFont = this.getTitleLabelForState(state); if ((labelBMFont != null) && (labelBMFont instanceof cc.LabelBMFont)) { return labelBMFont.getFntFile(); @@ -599,7 +610,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * * @param {Number} state The state that uses the background sprite. Possible values are described in "CCControlState". */ - getBackgroundSpriteForState:function (state) { + getBackgroundSpriteForState: function (state) { var locTable = this._backgroundSpriteDispatchTable; if (locTable[state]) { return locTable[state]; @@ -613,7 +624,7 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {Scale9Sprite} sprite The background sprite to use for the specified state. * @param {Number} state The state that uses the specified image. The values are described in "CCControlState". */ - setBackgroundSpriteForState:function (sprite, state) { + setBackgroundSpriteForState: function (sprite, state) { var locTable = this._backgroundSpriteDispatchTable; if (locTable[state]) { var previousSprite = locTable[state]; @@ -642,13 +653,13 @@ cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{ * @param {SpriteFrame} spriteFrame The background spriteFrame to use for the specified state. * @param {Number} state The state that uses the specified image. The values are described in "CCControlState". */ - setBackgroundSpriteFrameForState:function (spriteFrame, state) { + setBackgroundSpriteFrameForState: function (spriteFrame, state) { var sprite = cc.Scale9Sprite.createWithSpriteFrame(spriteFrame); this.setBackgroundSpriteForState(sprite, state); } }); -window._p = cc.ControlButton.prototype; +var _p = cc.ControlButton.prototype; // Extended properties /** @expose */ @@ -661,27 +672,17 @@ cc.defineGetterSetter(_p, "preferredSize", _p.getPreferredSize, _p.setPreferredS _p.labelAnchor; cc.defineGetterSetter(_p, "labelAnchor", _p.getLabelAnchorPoint, _p.setLabelAnchorPoint); -delete window._p; +_p = null; -cc.ControlButton.create = function(label, backgroundSprite) { - var controlButton; - if (arguments.length == 0) { - controlButton = new cc.ControlButton(); - if (controlButton && controlButton.init()) { - return controlButton; - } - return null; - } else if (arguments.length == 1) { - controlButton = new cc.ControlButton(); - controlButton.initWithBackgroundSprite(arguments[0]); - } else if (arguments.length == 2) { - controlButton = new cc.ControlButton(); - controlButton.initWithLabelAndBackgroundSprite(label, backgroundSprite); - } else if (arguments.length == 3) { - controlButton = new cc.ControlButton(); - controlButton.initWithTitleAndFontNameAndFontSize(arguments[0], arguments[1], arguments[2]); - } - return controlButton; +/** + * @deprecated + * @param label + * @param backgroundSprite + * @param fontSize + * @returns {ControlButton} + */ +cc.ControlButton.create = function (label, backgroundSprite, fontSize) { + return new cc.ControlButton(label, backgroundSprite, fontSize); }; diff --git a/extensions/gui/control-extension/CCControlColourPicker.js b/extensions/gui/control-extension/CCControlColourPicker.js index d74cbf30d4..6cdfd6bcc8 100644 --- a/extensions/gui/control-extension/CCControlColourPicker.js +++ b/extensions/gui/control-extension/CCControlColourPicker.js @@ -1,6 +1,8 @@ /** * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Copyright 2012 Stewart Hamilton-Arrandale. * http://creativewax.co.uk @@ -24,10 +26,8 @@ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THE SOFTWARE. * * - * - * converted to Javascript / cocos2d-x by Angus C */ /** @@ -44,6 +44,10 @@ cc.ControlColourPicker = cc.Control.extend(/** @lends cc.ControlColourPicker# */ _background:null, _className:"ControlColourPicker", + ctor:function () { + cc.Control.prototype.ctor.call(this); + this.init(); + }, hueSliderValueChanged:function (sender, controlEvent) { this._hsv.h = sender.getHue(); @@ -92,7 +96,7 @@ cc.ControlColourPicker = cc.Control.extend(/** @lends cc.ControlColourPicker# */ cc.spriteFrameCache.addSpriteFrames(res.CCControlColourPickerSpriteSheet_plist); // Create the sprite batch node - var spriteSheet = cc.SpriteBatchNode.create(res.CCControlColourPickerSpriteSheet_png); + var spriteSheet = new cc.SpriteBatchNode(res.CCControlColourPickerSpriteSheet_png); this.addChild(spriteSheet); /*// MIPMAP @@ -115,8 +119,8 @@ cc.ControlColourPicker = cc.Control.extend(/** @lends cc.ControlColourPicker# */ var hueShift = 8; var colourShift = 28; - this._huePicker = cc.ControlHuePicker.create(spriteSheet, cc.p(backgroundPointZero.x + hueShift, backgroundPointZero.y + hueShift)); - this._colourPicker = cc.ControlSaturationBrightnessPicker.create(spriteSheet, cc.p(backgroundPointZero.x + colourShift, backgroundPointZero.y + colourShift)); + this._huePicker = new cc.ControlHuePicker(spriteSheet, cc.p(backgroundPointZero.x + hueShift, backgroundPointZero.y + hueShift)); + this._colourPicker = new cc.ControlSaturationBrightnessPicker(spriteSheet, cc.p(backgroundPointZero.x + colourShift, backgroundPointZero.y + colourShift)); // Setup events this._huePicker.addTargetWithActionForControlEvents(this, this.hueSliderValueChanged, cc.CONTROL_EVENT_VALUECHANGED); @@ -147,7 +151,7 @@ cc.ControlColourPicker = cc.Control.extend(/** @lends cc.ControlColourPicker# */ }, setEnabled:function (enabled) { cc.Control.prototype.setEnabled.call(this, enabled); - if (this._huePicker != null) { + if (this._huePicker !== null) { this._huePicker.setEnabled(enabled); } if (this._colourPicker) { @@ -160,19 +164,21 @@ cc.ControlColourPicker = cc.Control.extend(/** @lends cc.ControlColourPicker# */ } }); -window._p = cc.ControlColourPicker.prototype; +var _p = cc.ControlColourPicker.prototype; // Extended properties /** @expose */ _p.background; cc.defineGetterSetter(_p, "background", _p.getBackground); -delete window._p; +_p = null; +/** + * @deprecated + * @returns {ControlColourPicker} + */ cc.ControlColourPicker.create = function () { - var pRet = new cc.ControlColourPicker(); - pRet.init(); - return pRet; + return new cc.ControlColourPicker(); }; // compatible with NPM diff --git a/extensions/gui/control-extension/CCControlHuePicker.js b/extensions/gui/control-extension/CCControlHuePicker.js index b0f4a38646..9c002740f4 100644 --- a/extensions/gui/control-extension/CCControlHuePicker.js +++ b/extensions/gui/control-extension/CCControlHuePicker.js @@ -1,6 +1,8 @@ /** * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Copyright 2012 Stewart Hamilton-Arrandale. * http://creativewax.co.uk @@ -49,6 +51,16 @@ cc.ControlHuePicker = cc.Control.extend(/** @lends cc.ControlHuePicker# */{ _startPos:null, _className:"ControlHuePicker", + /** + * The constructor of cc.ControlHuePicker + * @param {cc.Node} target + * @param {cc.Point} pos position + */ + ctor:function(target, pos) { + cc.Control.prototype.ctor.call(this); + pos && this.initWithTargetAndPos(target, pos); + }, + //maunally put in the setters getHue:function () { return this._hue; @@ -133,7 +145,7 @@ cc.ControlHuePicker = cc.Control.extend(/** @lends cc.ControlHuePicker# */{ // Update angle by using the direction of the location var angle = Math.atan2(dy, dx); - var angleDeg = cc.radiansToDegress(angle) + 180.0; + var angleDeg = cc.radiansToDegrees(angle) + 180.0; // use the position / slider width to determin the percentage the dragger is at this.setHue(angleDeg); @@ -174,7 +186,7 @@ cc.ControlHuePicker = cc.Control.extend(/** @lends cc.ControlHuePicker# */{ } }); -window._p = cc.ControlHuePicker.prototype; +var _p = cc.ControlHuePicker.prototype; // Extended properties /** @expose */ @@ -193,10 +205,14 @@ cc.defineGetterSetter(_p, "slider", _p.getSlider); _p.startPos; cc.defineGetterSetter(_p, "startPos", _p.getStartPos); -delete window._p; +_p = null; +/** + * @deprecated + * @param target + * @param pos + * @returns {ControlHuePicker} + */ cc.ControlHuePicker.create = function (target, pos) { - var pRet = new cc.ControlHuePicker(); - pRet.initWithTargetAndPos(target, pos); - return pRet; + return new cc.ControlHuePicker(target, pos); }; \ No newline at end of file diff --git a/extensions/gui/control-extension/CCControlPotentiometer.js b/extensions/gui/control-extension/CCControlPotentiometer.js index 134aaf8303..7c035efd5c 100644 --- a/extensions/gui/control-extension/CCControlPotentiometer.js +++ b/extensions/gui/control-extension/CCControlPotentiometer.js @@ -1,5 +1,8 @@ /** - * Copyright (c) 2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. + * * http://www.cocos2d-x.org * * Copyright 2012 Yannick Loriot. All rights reserved. @@ -51,6 +54,21 @@ cc.ControlPotentiometer = cc.Control.extend(/** @lends cc.ControlPotentiometer# _maximumValue:1, _className:"ControlPotentiometer", + ctor:function (backgroundFile, progressFile, thumbFile) { + cc.Control.prototype.ctor.call(this); + if (thumbFile != undefined) { + // Prepare track for potentiometer + var backgroundSprite = new cc.Sprite(backgroundFile); + + // Prepare thumb for potentiometer + var thumbSprite = new cc.Sprite(thumbFile); + + // Prepare progress for potentiometer + var progressTimer = new cc.ProgressTimer(new cc.Sprite(progressFile)); + this.initWithTrackSprite_ProgressTimer_ThumbSprite(backgroundSprite, progressTimer, thumbSprite); + } + }, + /** * * @param {cc.Sprite} trackSprite @@ -81,7 +99,7 @@ cc.ControlPotentiometer = cc.Control.extend(/** @lends cc.ControlPotentiometer# setEnabled:function (enabled) { this.setEnabled(enabled); - if (this._thumbSprite != NULL) { + if (this._thumbSprite !== null) { this._thumbSprite.setOpacity((enabled) ? 255 : 128); } }, @@ -246,7 +264,7 @@ cc.ControlPotentiometer = cc.Control.extend(/** @lends cc.ControlPotentiometer# } }); -window._p = cc.ControlPotentiometer.prototype; +var _p = cc.ControlPotentiometer.prototype; // Extended properties /** @expose */ @@ -268,22 +286,15 @@ cc.defineGetterSetter(_p, "thumbSprite", _p.getThumbSprite, _p.setThumbSprite); _p.prevLocation; cc.defineGetterSetter(_p, "prevLocation", _p.getPreviousLocation, _p.setPreviousLocation); -delete window._p; +_p = null; +/** + * @deprecated + * @param backgroundFile + * @param progressFile + * @param thumbFile + * @returns {ControlPotentiometer} + */ cc.ControlPotentiometer.create = function (backgroundFile, progressFile, thumbFile) { - var pRet = new cc.ControlPotentiometer(); - if (pRet) { - // Prepare track for potentiometer - var backgroundSprite = cc.Sprite.create(backgroundFile); - - // Prepare thumb for potentiometer - var thumbSprite = cc.Sprite.create(thumbFile); - - // Prepare progress for potentiometer - var progressTimer = cc.ProgressTimer.create(cc.Sprite.create(progressFile)); - if (pRet.initWithTrackSprite_ProgressTimer_ThumbSprite(backgroundSprite, progressTimer, thumbSprite)) { - return pRet; - } - } - return null; + return new cc.ControlPotentiometer(backgroundFile, progressFile, thumbFile); }; \ No newline at end of file diff --git a/extensions/gui/control-extension/CCControlSaturationBrightnessPicker.js b/extensions/gui/control-extension/CCControlSaturationBrightnessPicker.js index 174e6417f4..a9045c43d0 100644 --- a/extensions/gui/control-extension/CCControlSaturationBrightnessPicker.js +++ b/extensions/gui/control-extension/CCControlSaturationBrightnessPicker.js @@ -1,6 +1,8 @@ /** * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Copyright 2012 Stewart Hamilton-Arrandale. * http://creativewax.co.uk @@ -57,6 +59,15 @@ cc.ControlSaturationBrightnessPicker = cc.Control.extend(/** @lends cc.ControlSa _boxSize:0, _className:"ControlSaturationBrightnessPicker", + /** + * The constructor of cc.ControlSaturationBrightnessPicker + * @param {cc.Node} target + * @param {cc.Point} pos position + */ + ctor:function (target, pos) { + cc.Control.prototype.ctor.call(this); + pos && this.initWithTargetAndPos(target, pos); + }, getSaturation:function () { return this._saturation; }, @@ -208,7 +219,7 @@ cc.ControlSaturationBrightnessPicker = cc.Control.extend(/** @lends cc.ControlSa } }); -window._p = cc.ControlSaturationBrightnessPicker.prototype; +var _p = cc.ControlSaturationBrightnessPicker.prototype; // Extended properties /** @expose */ @@ -233,10 +244,14 @@ cc.defineGetterSetter(_p, "slider", _p.getSlider); _p.startPos; cc.defineGetterSetter(_p, "startPos", _p.getStartPos); -delete window._p; +_p = null; +/** + * Creates a cc.ControlSaturationBrightnessPicker + * @param {cc.Node} target + * @param {cc.Point} pos position + * @returns {ControlSaturationBrightnessPicker} + */ cc.ControlSaturationBrightnessPicker.create = function (target, pos) { - var pRet = new cc.ControlSaturationBrightnessPicker(); - pRet.initWithTargetAndPos(target, pos); - return pRet; + return new cc.ControlSaturationBrightnessPicker(target, pos); }; \ No newline at end of file diff --git a/extensions/gui/control-extension/CCControlSlider.js b/extensions/gui/control-extension/CCControlSlider.js index 80eab4418a..e4a757b3c8 100644 --- a/extensions/gui/control-extension/CCControlSlider.js +++ b/extensions/gui/control-extension/CCControlSlider.js @@ -1,6 +1,8 @@ /** * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Copyright 2011 Yannick Loriot. All rights reserved. * http://yannickloriot.com @@ -59,6 +61,22 @@ cc.ControlSlider = cc.Control.extend(/** @lends cc.ControlSlider# */{ _backgroundSprite:null, _className:"ControlSlider", + ctor:function (bgFile, progressFile, thumbFile) { + cc.Control.prototype.ctor.call(this); + if (thumbFile != undefined) { + // Prepare background for slider + var bgSprite = new cc.Sprite(bgFile); + + // Prepare progress for slider + var progressSprite = new cc.Sprite(progressFile); + + // Prepare thumb (menuItem) for slider + var thumbSprite = new cc.Sprite(thumbFile); + + this.initWithSprites(bgSprite, progressSprite, thumbSprite); + } + }, + getValue:function () { return this._value; }, @@ -191,7 +209,7 @@ cc.ControlSlider = cc.Control.extend(/** @lends cc.ControlSlider# */{ sliderBegan:function (location) { this.setSelected(true); - this.getThumbSprite().setColor(cc.color.GRAY); + this._thumbSprite.setColor(cc.color.GRAY); this.setValue(this.valueForLocation(location)); }, sliderMoved:function (location) { @@ -240,6 +258,7 @@ cc.ControlSlider = cc.Control.extend(/** @lends cc.ControlSlider# */{ var textureRect = this._progressSprite.getTextureRect(); textureRect = cc.rect(textureRect.x, textureRect.y, this._thumbSprite.getPositionX(), textureRect.height); this._progressSprite.setTextureRect(textureRect, this._progressSprite.isTextureRectRotated()); + this._thumbSprite._renderCmd.transform(this._renderCmd); }, /** Returns the value for the given location. */ valueForLocation:function (location) { @@ -248,7 +267,7 @@ cc.ControlSlider = cc.Control.extend(/** @lends cc.ControlSlider# */{ } }); -window._p = cc.ControlSlider.prototype; +var _p = cc.ControlSlider.prototype; // Extended properties /** @expose */ @@ -276,28 +295,14 @@ cc.defineGetterSetter(_p, "progressSprite", _p.getProgressSprite); _p.backgroundSprite; cc.defineGetterSetter(_p, "backgroundSprite", _p.getBackgroundSprite); -delete window._p; +_p = null; /** * Creates a slider with a given background sprite and a progress bar and a * thumb item. - * - * @see initWithBackgroundSprite:progressSprite:thumbMenuItem: + * @deprecated + * @see cc.ControlSlider */ cc.ControlSlider.create = function (bgFile, progressFile, thumbFile) { - if (typeof(bgFile) == "string") { - // Prepare background for slider - bgFile = cc.Sprite.create(bgFile); - - // Prepare progress for slider - progressFile = cc.Sprite.create(progressFile); - - // Prepare thumb (menuItem) for slider - thumbFile = cc.Sprite.create(thumbFile); - } - - var pRet = new cc.ControlSlider(); - pRet.initWithSprites(bgFile, progressFile, thumbFile); - return pRet; - + return new cc.ControlSlider(bgFile, progressFile, thumbFile); }; \ No newline at end of file diff --git a/extensions/gui/control-extension/CCControlStepper.js b/extensions/gui/control-extension/CCControlStepper.js index a8d4ddbba3..5dbc5e5d63 100644 --- a/extensions/gui/control-extension/CCControlStepper.js +++ b/extensions/gui/control-extension/CCControlStepper.js @@ -1,5 +1,8 @@ /** - * Copyright (c) 2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. + * * http://www.cocos2d-x.org * * Copyright 2012 Yannick Loriot. All rights reserved. @@ -69,7 +72,7 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ _touchedPart:cc.CONTROL_STEPPER_PARTNONE, _autorepeatCount:0, _className:"ControlStepper", - ctor:function () { + ctor:function (minusSprite, plusSprite) { cc.Control.prototype.ctor.call(this); this._minusSprite = null; this._plusSprite = null; @@ -85,6 +88,9 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ this._touchInsideFlag = false; this._touchedPart = cc.CONTROL_STEPPER_PARTNONE; this._autorepeatCount = 0; + + plusSprite && this.initWithMinusSpriteAndPlusSprite(minusSprite, plusSprite); + }, initWithMinusSpriteAndPlusSprite:function (minusSprite, plusSprite) { @@ -109,7 +115,7 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ this._minusSprite.setPosition(minusSprite.getContentSize().width / 2, minusSprite.getContentSize().height / 2); this.addChild(this._minusSprite); - this.setMinusLabel(cc.LabelTTF.create("-", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER)); + this.setMinusLabel(new cc.LabelTTF("-", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER)); this._minusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_DISABLED); this._minusLabel.setPosition(this._minusSprite.getContentSize().width / 2, this._minusSprite.getContentSize().height / 2); this._minusSprite.addChild(this._minusLabel); @@ -120,7 +126,7 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ minusSprite.getContentSize().height / 2); this.addChild(this._plusSprite); - this.setPlusLabel(cc.LabelTTF.create("+", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER)); + this.setPlusLabel(new cc.LabelTTF("+", cc.CONTROL_STEPPER_LABELFONT, 40, cc.size(40, 40), cc.TEXT_ALIGNMENT_CENTER, cc.VERTICAL_TEXT_ALIGNMENT_CENTER)); this._plusLabel.setColor(cc.CONTROL_STEPPER_LABELCOLOR_ENABLED); this._plusLabel.setPosition(this._plusSprite.getContentSize().width / 2, this._plusSprite.getContentSize().height / 2); this._plusSprite.addChild(this._plusLabel); @@ -204,8 +210,8 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ this._value = value; if (!this._wraps) { - this._minusLabel.setColor((value == this._minimumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED); - this._plusLabel.setColor((value == this._maximumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED); + this._minusLabel.setColor((value === this._minimumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED); + this._plusLabel.setColor((value === this._maximumValue) ? cc.CONTROL_STEPPER_LABELCOLOR_DISABLED : cc.CONTROL_STEPPER_LABELCOLOR_ENABLED); } if (send) { @@ -226,12 +232,12 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ update:function (dt) { this._autorepeatCount++; - if ((this._autorepeatCount < cc.AUTOREPEAT_INCREASETIME_INCREMENT) && (this._autorepeatCount % 3) != 0) + if ((this._autorepeatCount < cc.AUTOREPEAT_INCREASETIME_INCREMENT) && (this._autorepeatCount % 3) !== 0) return; - if (this._touchedPart == cc.CONTROL_STEPPER_PARTMINUS) { + if (this._touchedPart === cc.CONTROL_STEPPER_PARTMINUS) { this.setValueWithSendingEvent(this._value - this._stepValue, this._continuous); - } else if (this._touchedPart == cc.CONTROL_STEPPER_PARTPLUS) { + } else if (this._touchedPart === cc.CONTROL_STEPPER_PARTPLUS) { this.setValueWithSendingEvent(this._value + this._stepValue, this._continuous); } }, @@ -337,7 +343,7 @@ cc.ControlStepper = cc.Control.extend(/** @lends cc.ControlStepper# */{ } }); -window._p = cc.ControlStepper.prototype; +var _p = cc.ControlStepper.prototype; // Extedned properties /** @expose */ @@ -371,12 +377,14 @@ cc.defineGetterSetter(_p, "minusLabel", _p.getMinusLabel, _p.setMinusLabel); _p.plusLabel; cc.defineGetterSetter(_p, "plusLabel", _p.getPlusLabel, _p.setPlusLabel); -delete window._p; +_p = null; +/** + * Creates a cc.ControlStepper + * @param {cc.Sprite} minusSprite + * @param {cc.Sprite} plusSprite + * @returns {ControlStepper} + */ cc.ControlStepper.create = function (minusSprite, plusSprite) { - var pRet = new cc.ControlStepper(); - if (pRet && pRet.initWithMinusSpriteAndPlusSprite(minusSprite, plusSprite)) { - return pRet; - } - return null; + return new cc.ControlStepper(minusSprite, plusSprite); }; \ No newline at end of file diff --git a/extensions/gui/control-extension/CCControlSwitch.js b/extensions/gui/control-extension/CCControlSwitch.js index d5900cb547..1321dcb12c 100644 --- a/extensions/gui/control-extension/CCControlSwitch.js +++ b/extensions/gui/control-extension/CCControlSwitch.js @@ -1,6 +1,8 @@ /** * - * Copyright (c) 2010-2012 cocos2d-x.org + * Copyright (c) 2008-2010 Ricardo Quesada + * Copyright (c) 2011-2012 cocos2d-x.org + * Copyright (c) 2013-2014 Chukong Technologies Inc. * * Copyright 2011 Yannick Loriot. All rights reserved. * http://yannickloriot.com @@ -27,7 +29,7 @@ /** * CCControlSwitch: Switch control ui component * @class - * @extend cc.Control + * @extends cc.Control */ cc.ControlSwitch = cc.Control.extend(/** @lends cc.ControlSwitch# */{ /** Sprite which represents the view. */ @@ -38,8 +40,10 @@ cc.ControlSwitch = cc.Control.extend(/** @lends cc.ControlSwitch# */{ /** A Boolean value that determines the off/on state of the switch. */ _on:false, _className:"ControlSwitch", - ctor:function () { + ctor:function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) { cc.Control.prototype.ctor.call(this); + + offLabel && this.initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel); }, /** Creates a switch with a mask sprite, on/off sprites for on/off states, a thumb sprite and an on/off labels. */ @@ -73,7 +77,7 @@ cc.ControlSwitch = cc.Control.extend(/** @lends cc.ControlSwitch# */{ this._on = isOn; var xPosition = (this._on) ? this._switchSprite.getOnPosition() : this._switchSprite.getOffPosition(); if(animated){ - this._switchSprite.runAction(cc.ActionTween.create(0.2, "sliderXPosition", this._switchSprite.getSliderXPosition(),xPosition)); + this._switchSprite.runAction(new cc.ActionTween(0.2, "sliderXPosition", this._switchSprite.getSliderXPosition(),xPosition)); }else{ this._switchSprite.setSliderXPosition(xPosition); } @@ -152,19 +156,17 @@ cc.ControlSwitch = cc.Control.extend(/** @lends cc.ControlSwitch# */{ } }); -/** Creates a switch with a mask sprite, on/off sprites for on/off states and a thumb sprite. */ +/** Creates a switch with a mask sprite, on/off sprites for on/off states and a thumb sprite. + * @deprecated + */ cc.ControlSwitch.create = function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) { - var pRet = new cc.ControlSwitch(); - if (pRet && pRet.initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel)) { - return pRet; - } - return null; + return new cc.ControlSwitch(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel); }; /** * ControlSwitchSprite: Sprite switch control ui component * @class - * @extend cc.Sprite + * @extends cc.Sprite * * @property {Number} sliderX - Slider's x position * @property {cc.Point} onPos - The position of slider when switch is on @@ -213,7 +215,8 @@ cc.ControlSwitchSprite = cc.Sprite.extend({ }, initWithMaskSprite:function (maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel) { - if (cc.Sprite.prototype.initWithTexture.call(this, maskSprite.getTexture())) { + if (cc.Sprite.prototype.init.call(this)) { + this.setSpriteFrame(maskSprite.displayFrame()); // Sets the default values this._onPosition = 0; this._offPosition = -onSprite.getContentSize().width + thumbSprite.getContentSize().width / 2; @@ -231,14 +234,17 @@ cc.ControlSwitchSprite = cc.Sprite.extend({ this._stencil.setPosition(0, 0); // Init clipper for mask - this._clipper = cc.ClippingNode.create(); + this._clipper = new cc.ClippingNode(); this._clipper.setAnchorPoint(0.5, 0.5); this._clipper.setPosition(maskSize.width / 2, maskSize.height / 2); this._clipper.setStencil(this._stencil); - this._backRT = cc.RenderTexture.create(maskSize.width, maskSize.height); - this._clipper.addChild(this._backRT.getSprite()); this.addChild(this._clipper); + this._clipper.addChild(onSprite); + this._clipper.addChild(offSprite); + this._clipper.addChild(onLabel); + this._clipper.addChild(offLabel); + this.addChild(this._thumbSprite); this.needsLayout(); @@ -248,35 +254,32 @@ cc.ControlSwitchSprite = cc.Sprite.extend({ }, needsLayout:function () { - this._onSprite.setPosition(this._onSprite.getContentSize().width / 2 + this._sliderXPosition, - this._onSprite.getContentSize().height / 2); - this._offSprite.setPosition(this._onSprite.getContentSize().width + this._offSprite.getContentSize().width / 2 + this._sliderXPosition, - this._offSprite.getContentSize().height / 2); + var maskSize = this._maskSize; + this._onSprite.setPosition( + this._onSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2, + this._onSprite.getContentSize().height / 2 - maskSize.height / 2 + ); + this._offSprite.setPosition( + this._onSprite.getContentSize().width + this._offSprite.getContentSize().width / 2 + this._sliderXPosition - maskSize.width / 2, + this._offSprite.getContentSize().height / 2 - maskSize.height / 2 + ); if (this._onLabel) { - this._onLabel.setPosition(this._onSprite.getPositionX() - this._thumbSprite.getContentSize().width / 6, - this._onSprite.getContentSize().height / 2); + this._onLabel.setPosition( + this._onSprite.getPositionX() - this._thumbSprite.getContentSize().width / 6, + this._onSprite.getContentSize().height / 2 - maskSize.height / 2 + ); } if (this._offLabel) { - this._offLabel.setPosition(this._offSprite.getPositionX() + this._thumbSprite.getContentSize().width / 6, - this._offSprite.getContentSize().height / 2); + this._offLabel.setPosition( + this._offSprite.getPositionX() + this._thumbSprite.getContentSize().width / 6, + this._offSprite.getContentSize().height / 2 - maskSize.height / 2 + ); } - this._thumbSprite.setPosition(this._onSprite.getContentSize().width + this._sliderXPosition, - this._maskSize.height / 2); - - this._backRT.begin(); - - this._onSprite.visit(); - this._offSprite.visit(); - - if (this._onLabel) - this._onLabel.visit(); - if (this._offLabel) - this._offLabel.visit(); - - this._backRT.end(); - - //this.setFlippedY(true); + this._thumbSprite.setPosition( + this._onSprite.getContentSize().width + this._sliderXPosition, + this._maskSize.height / 2 + ); }, setSliderXPosition:function (sliderXPosition) { @@ -305,8 +308,8 @@ cc.ControlSwitchSprite = cc.Sprite.extend({ }, updateTweenAction:function (value, key) { - cc.log("key = " + key + ", value = " + value); - this.setSliderXPosition(value); + if (key === "sliderXPosition") + this.setSliderXPosition(value); }, setOnPosition:function (onPosition) { @@ -380,7 +383,7 @@ cc.ControlSwitchSprite = cc.Sprite.extend({ } }); -window._p = cc.ControlSwitchSprite.prototype; +var _p = cc.ControlSwitchSprite.prototype; /** @expose */ _p.sliderX; @@ -419,4 +422,4 @@ cc.defineGetterSetter(_p, "onSideWidth", _p._getOnSideWidth); _p.offSideWidth; cc.defineGetterSetter(_p, "offSideWidth", _p._getOffSideWidth); -delete window._p; +_p = null; diff --git a/extensions/gui/control-extension/CCControlUtils.js b/extensions/gui/control-extension/CCControlUtils.js index 327e09790e..5e803bd56a 100644 --- a/extensions/gui/control-extension/CCControlUtils.js +++ b/extensions/gui/control-extension/CCControlUtils.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright 2012 Stewart Hamilton-Arrandale. http://creativewax.co.uk @@ -52,7 +54,7 @@ cc.HSV = function(h,s,v){ cc.ControlUtils = {}; cc.ControlUtils.addSpriteToTargetWithPosAndAnchor = function(spriteName,target,pos,anchor){ - var sprite =cc.Sprite.create("#" + spriteName); + var sprite = new cc.Sprite("#" + spriteName); if (!sprite) return null; diff --git a/extensions/gui/control-extension/CCInvocation.js b/extensions/gui/control-extension/CCInvocation.js index b3fff1f9a9..82b0189a9d 100644 --- a/extensions/gui/control-extension/CCInvocation.js +++ b/extensions/gui/control-extension/CCInvocation.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -52,7 +54,7 @@ cc.Invocation = cc.Class.extend(/** @lends cc.Invocation# */{ invoke:function(sender){ if (this._target && this._action) { - if (typeof(this._action) == "string") { + if (cc.isString(this._action)) { this._target[this._action](sender, this._controlEvent); } else{ this._action.call(this._target, sender, this._controlEvent); diff --git a/extensions/gui/control-extension/CCMenuPassive.js b/extensions/gui/control-extension/CCMenuPassive.js index ba0a3e831d..82a3fd32fe 100644 --- a/extensions/gui/control-extension/CCMenuPassive.js +++ b/extensions/gui/control-extension/CCMenuPassive.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. http://www.cocos2d-x.org @@ -46,10 +48,9 @@ cc.Spacer.horizontalSpacer = function (space) { /** * MenuPassive: The menu passive ui component * @class - * @extend cc.Layer + * @extends cc.Layer */ cc.MenuPassive = cc.Layer.extend(/** @lends cc.MenuPassive# */{ - RGBAProtocol:true, _color:null, _opacity:0, @@ -71,7 +72,7 @@ cc.MenuPassive = cc.Layer.extend(/** @lends cc.MenuPassive# */{ if (this._children && this._children.length > 0) { for (var i = 0; i < this._children.length; i++) { - if (this._children[i] && this._children[i].RGBAProtocol) { + if (this._children[i]) { this._children[i].setColor(color); } } @@ -91,7 +92,7 @@ cc.MenuPassive = cc.Layer.extend(/** @lends cc.MenuPassive# */{ if (this._children && this._children.length > 0) { for (var i = 0; i < this._children.length; i++) { - if (this._children[i] && this._children[i].RGBAProtocol) { + if (this._children[i]) { this._children[i].setOpacity(opacity); } } @@ -256,7 +257,7 @@ cc.MenuPassive = cc.Layer.extend(/** @lends cc.MenuPassive# */{ if (this._children && this._children.length > 0) { for (i = 0; i < this._children.length; i++) { if (this._children[i]) { - if (rowColumns == 0) { + if (rowColumns === 0) { rowColumns = rows[row]; w = winSize.width / (1 + rowColumns); x = w; diff --git a/extensions/gui/control-extension/CCScale9Sprite.js b/extensions/gui/control-extension/CCScale9Sprite.js index e8f51b157e..9e1fefa38a 100644 --- a/extensions/gui/control-extension/CCScale9Sprite.js +++ b/extensions/gui/control-extension/CCScale9Sprite.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2012 Neofect. All rights reserved. http://www.cocos2d-x.org @@ -25,19 +27,6 @@ Created by Jung Sang-Taik on 2012-03-16 ****************************************************************************/ -/** - * @ignore - */ -cc.POSITIONS_CENTRE = 0; -cc.POSITIONS_TOP = 1; -cc.POSITIONS_LEFT = 2; -cc.POSITIONS_RIGHT = 3; -cc.POSITIONS_BOTTOM = 4; -cc.POSITIONS_TOPRIGHT = 5; -cc.POSITIONS_TOPLEFT = 6; -cc.POSITIONS_BOTTOMRIGHT = 7; -cc.POSITIONS_BOTTOMLEFT = 8; - /** * A 9-slice sprite for cocos2d. * @@ -48,7 +37,7 @@ cc.POSITIONS_BOTTOMLEFT = 8; * * @see http://yannickloriot.com/library/ios/cccontrolextension/Classes/CCScale9Sprite.html * @class - * @extends cc.NodeRGBA + * @extends cc.Node * * @property {cc.Size} preferredSize - The preferred size of the 9-slice sprite * @property {cc.Rect} capInsets - The cap insets of the 9-slice sprite @@ -57,9 +46,7 @@ cc.POSITIONS_BOTTOMLEFT = 8; * @property {Number} insetRight - The right inset of the 9-slice sprite * @property {Number} insetBottom - The bottom inset of the 9-slice sprite */ -cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ - RGBAProtocol: true, - +cc.Scale9Sprite = cc.Node.extend(/** @lends cc.Scale9Sprite# */{ _spriteRect: null, _capInsetsInternal: null, _positionsAreDirty: false, @@ -75,7 +62,8 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ _bottom: null, _bottomRight: null, - _colorUnmodified: null, + _scale9Dirty: true, + _opacityModifyRGB: false, _originalSize: null, @@ -91,9 +79,12 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ _spritesGenerated: false, _spriteFrameRotated: false, _textureLoaded:false, - _loadedEventListeners: null, _className:"Scale9Sprite", + //v3.3 + _flippedX: false, + _flippedY: false, + /** * return texture is loaded * @returns {boolean} @@ -106,19 +97,10 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ * add texture loaded event listener * @param {Function} callback * @param {Object} target + * @deprecated since 3.1, please use addEventListener instead */ addLoadedEventListener:function(callback, target){ - this._loadedEventListeners.push({eventCallback:callback, eventTarget:target}); - }, - - _callLoadedEventCallbacks:function(){ - this._textureLoaded = true; - var locListeners = this._loadedEventListeners; - for(var i = 0, len = locListeners.length; i < len; i++){ - var selCallback = locListeners[i]; - selCallback.eventCallback.call(selCallback.eventTarget, this); - } - locListeners.length = 0; + this.addEventListener("load", callback, target); }, _updateCapInset: function () { @@ -128,11 +110,11 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ insets = cc.rect(0, 0, 0, 0); } else { insets = this._spriteFrameRotated ? cc.rect(locInsetBottom, locInsetLeft, - locSpriteRect.width - locInsetRight - locInsetLeft, - locSpriteRect.height - locInsetTop - locInsetBottom) : + locSpriteRect.width - locInsetRight - locInsetLeft, + locSpriteRect.height - locInsetTop - locInsetBottom) : cc.rect(locInsetLeft, locInsetTop, - locSpriteRect.width - locInsetLeft - locInsetRight, - locSpriteRect.height - locInsetTop - locInsetBottom); + locSpriteRect.width - locInsetLeft - locInsetRight, + locSpriteRect.height - locInsetTop - locInsetBottom); } this.setCapInsets(insets); }, @@ -153,27 +135,30 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ var sizableWidth = size.width - locTopLeftContentSize.width - locTopRight.getContentSize().width; var sizableHeight = size.height - locTopLeftContentSize.height - locBottomRight.getContentSize().height; + var horizontalScale = sizableWidth / locCenterContentSize.width; var verticalScale = sizableHeight / locCenterContentSize.height; + var rescaledWidth = locCenterContentSize.width * horizontalScale; var rescaledHeight = locCenterContentSize.height * verticalScale; var leftWidth = locBottomLeftContentSize.width; var bottomHeight = locBottomLeftContentSize.height; - if(cc._renderType == cc._RENDER_TYPE_WEBGL){ + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { //browser is in canvas mode, need to manually control rounding to prevent overlapping pixels var roundedRescaledWidth = Math.round(rescaledWidth); - if(rescaledWidth != roundedRescaledWidth) { + if (rescaledWidth !== roundedRescaledWidth) { rescaledWidth = roundedRescaledWidth; - horizontalScale = rescaledWidth/locCenterContentSize.width; + horizontalScale = rescaledWidth / locCenterContentSize.width; } var roundedRescaledHeight = Math.round(rescaledHeight); - if(rescaledHeight != roundedRescaledHeight) { + if (rescaledHeight !== roundedRescaledHeight) { rescaledHeight = roundedRescaledHeight; - verticalScale = rescaledHeight/locCenterContentSize.height; + verticalScale = rescaledHeight / locCenterContentSize.height; } } + locCenter.setScaleX(horizontalScale); locCenter.setScaleY(verticalScale); @@ -209,100 +194,112 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ locCenter.setPosition(leftWidth, bottomHeight); }, - ctor: function () { - cc.NodeRGBA.prototype.ctor.call(this); + /** + * Constructor function. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + * @function + * @param {string|cc.SpriteFrame} file file name of texture or a SpriteFrame + * @param {cc.Rect} rect + * @param {cc.Rect} capInsets + * @returns {Scale9Sprite} + */ + ctor: function (file, rect, capInsets) { + cc.Node.prototype.ctor.call(this); this._spriteRect = cc.rect(0, 0, 0, 0); this._capInsetsInternal = cc.rect(0, 0, 0, 0); - this._colorUnmodified = cc.color(255, 255, 255, 255); this._originalSize = cc.size(0, 0); this._preferredSize = cc.size(0, 0); - this._color = cc.color(255, 255, 255, 255); - this._opacity = 255; this._capInsets = cc.rect(0, 0, 0, 0); - this._loadedEventListeners = []; + + if(file != undefined){ + if(file instanceof cc.SpriteFrame) + this.initWithSpriteFrame(file, rect); + else{ + var frame = cc.spriteFrameCache.getSpriteFrame(file); + if(frame != null) + this.initWithSpriteFrame(frame, rect); + else + this.initWithFile(file, rect, capInsets); + } + }else{ + this.init(); + } + }, + + getSprite: function () { + return this._scale9Image; }, /** Original sprite's size. */ getOriginalSize: function () { - return this._originalSize; + return cc.size(this._originalSize); }, //if the preferredSize component is given as -1, it is ignored getPreferredSize: function () { - return this._preferredSize; - }, - _getPreferredWidth: function () { - return this._preferredSize.width; - }, - _getPreferredHeight: function () { - return this._preferredSize.height; - }, + return cc.size(this._preferredSize); + }, + _getPreferredWidth: function () { + return this._preferredSize.width; + }, + _getPreferredHeight: function () { + return this._preferredSize.height; + }, setPreferredSize: function (preferredSize) { this.setContentSize(preferredSize); this._preferredSize = preferredSize; + + if (this._positionsAreDirty) { + this._updatePositions(); + this._positionsAreDirty = false; + this._scale9Dirty = true; + } + }, + _setPreferredWidth: function (value) { + this._setWidth(value); + this._preferredSize.width = value; + }, + _setPreferredHeight: function (value) { + this._setHeight(value); + this._preferredSize.height = value; }, - _setPreferredWidth: function (value) { - this._setWidth(value); - this._preferredSize.width = value; - }, - _setPreferredHeight: function (value) { - this._setHeight(value); - this._preferredSize.height = value; - }, /** Opacity: conforms to CCRGBAProtocol protocol */ - getOpacity: function () { - return this._opacity; - }, setOpacity: function (opacity) { - if(!this._scale9Image){ + if(!this._scale9Image) return; - } - this._opacity = opacity; + cc.Node.prototype.setOpacity.call(this, opacity); var scaleChildren = this._scale9Image.getChildren(); for (var i = 0; i < scaleChildren.length; i++) { var selChild = scaleChildren[i]; - if (selChild && selChild.RGBAProtocol) + if (selChild) selChild.setOpacity(opacity); } - this._color.a = opacity; + this._scale9Dirty = true; }, /** Color: conforms to CCRGBAProtocol protocol */ - getColor: function () { - var locColor = this._color; - return cc.color(locColor.r, locColor.g, locColor.b, locColor.a); - }, setColor: function (color) { - if(!this._scale9Image){ + if(!this._scale9Image) return; - } - var locColor = this._color; - locColor.r = color.r; - locColor.g = color.g; - locColor.b = color.b; + cc.Node.prototype.setColor.call(this, color); var scaleChildren = this._scale9Image.getChildren(); for (var i = 0; i < scaleChildren.length; i++) { var selChild = scaleChildren[i]; - if (selChild && selChild.RGBAProtocol) + if (selChild) selChild.setColor(color); } - - if (color.a !== undefined && !color.a_undefined) { - this.setOpacity(color.a); - } + this._scale9Dirty = true; }, getCapInsets: function () { - return this._capInsets; + return cc.rect(this._capInsets); }, setCapInsets: function (capInsets) { - if(!this._scale9Image){ + if(!this._scale9Image) return; - } //backup the contentSize var contentSize = this._contentSize; var tempWidth = contentSize.width, tempHeight = contentSize.height; @@ -385,39 +382,46 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ * @param {Number} [height] The untransformed size's height of the Scale9Sprite. */ setContentSize: function (size, height) { - cc.Node.prototype.setContentSize.call(this, size, height); + cc.Node.prototype.setContentSize.call(this, size, height); this._positionsAreDirty = true; }, - _setWidth: function (value) { - cc.Node.prototype._setWidth.call(this, value); - this._positionsAreDirty = true; - }, - _setHeight: function (value) { - cc.Node.prototype._setHeight.call(this, value); - this._positionsAreDirty = true; - }, - visit: function (ctx) { - if (this._positionsAreDirty) { - this._updatePositions(); - this._positionsAreDirty = false; - } - cc.NodeRGBA.prototype.visit.call(this, ctx); + _setWidth: function (value) { + cc.Node.prototype._setWidth.call(this, value); + this._positionsAreDirty = true; }, + _setHeight: function (value) { + cc.Node.prototype._setHeight.call(this, value); + this._positionsAreDirty = true; + }, + + /** + * Initializes a cc.Scale9Sprite. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @returns {boolean} + */ init: function () { return this.initWithBatchNode(null, cc.rect(0, 0, 0, 0), false, cc.rect(0, 0, 0, 0)); }, + /** + * Initializes a 9-slice sprite with a SpriteBatchNode. + * @param {cc.SpriteBatchNode} batchNode + * @param {cc.Rect} rect + * @param {boolean|cc.Rect} rotated + * @param {cc.Rect} [capInsets] + * @returns {boolean} + */ initWithBatchNode: function (batchNode, rect, rotated, capInsets) { if (capInsets === undefined) { capInsets = rotated; rotated = false; } - if (batchNode) { + if (batchNode) this.updateWithBatchNode(batchNode, rect, rotated, capInsets); - } + this.setCascadeColorEnabled(true); + this.setCascadeOpacityEnabled(true); this.setAnchorPoint(0.5, 0.5); this._positionsAreDirty = true; return true; @@ -430,11 +434,10 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ * to resize the sprite will all it's 9-slice goodness intact. * It respects the anchorPoint too. * - * @param file The name of the texture file. - * @param rect The rectangle that describes the sub-part of the texture that - * is the whole image. If the shape is the whole texture, set this to the - * texture's full rect. - * @param capInsets The values to use for the cap insets. + * @param {String} file The name of the texture file. + * @param {cc.Rect} rect The rectangle that describes the sub-part of the texture that + * is the whole image. If the shape is the whole texture, set this to the texture's full rect. + * @param {cc.Rect} capInsets The values to use for the cap insets. */ initWithFile: function (file, rect, capInsets) { if (file instanceof cc.Rect) { @@ -449,32 +452,34 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ if(!file) throw "cc.Scale9Sprite.initWithFile(): file should be non-null"; - var texture = cc.textureCache.textureForKey(file); + var texture = cc.textureCache.getTextureForKey(file); if (!texture) { texture = cc.textureCache.addImage(file); - var locLoaded = texture.isLoaded(); - this._textureLoaded = locLoaded; - if(!locLoaded){ - texture.addLoadedEventListener(function(sender){ - // the texture is rotated on Canvas render mode, so isRotated always is false. - var preferredSize = this._preferredSize; - preferredSize = cc.size(preferredSize.width, preferredSize.height); - var size = sender.getContentSize(); - this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets); - this.setPreferredSize(preferredSize); - this._positionsAreDirty = true; - this._callLoadedEventCallbacks(); - }, this); - } } - return this.initWithBatchNode(cc.SpriteBatchNode.create(file, 9), rect, false, capInsets); + + var locLoaded = texture.isLoaded(); + this._textureLoaded = locLoaded; + if(!locLoaded){ + texture.addEventListener("load", function(sender){ + // the texture is rotated on Canvas render mode, so isRotated always is false. + var preferredSize = this._preferredSize, restorePreferredSize = (preferredSize.width !== 0 || preferredSize.height !== 0); + if(restorePreferredSize)preferredSize = cc.size(preferredSize.width, preferredSize.height); + var size = sender.getContentSize(); + this.updateWithBatchNode(this._scale9Image, cc.rect(0,0,size.width,size.height), false, this._capInsets); + if(restorePreferredSize)this.setPreferredSize(preferredSize); + this._positionsAreDirty = true; + this.dispatchEvent("load"); + }, this); + } + + return this.initWithBatchNode(new cc.SpriteBatchNode(file, 9), rect, false, capInsets); }, /** * Initializes a 9-slice sprite with an sprite frame and with the specified * cap insets. * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. + * to resize the sprite will all it's 9-slice goodness interact. * It respects the anchorPoint too. * * @param spriteFrame The sprite frame object. @@ -488,26 +493,26 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ var locLoaded = spriteFrame.textureLoaded(); this._textureLoaded = locLoaded; if(!locLoaded){ - spriteFrame.addLoadedEventListener(function(sender){ + spriteFrame.addEventListener("load", function(sender){ // the texture is rotated on Canvas render mode, so isRotated always is false. - var preferredSize = this._preferredSize; - preferredSize = cc.size(preferredSize.width, preferredSize.height); - this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType == cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); - this.setPreferredSize(preferredSize); + var preferredSize = this._preferredSize, restorePreferredSize = (preferredSize.width !== 0 || preferredSize.height !== 0); + if(restorePreferredSize)preferredSize = cc.size(preferredSize.width, preferredSize.height); + this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); + if(restorePreferredSize)this.setPreferredSize(preferredSize); this._positionsAreDirty = true; - this._callLoadedEventCallbacks(); + this.dispatchEvent("load"); },this); } - var batchNode = cc.SpriteBatchNode.create(spriteFrame.getTexture(), 9); + var batchNode = new cc.SpriteBatchNode(spriteFrame.getTexture(), 9); // the texture is rotated on Canvas render mode, so isRotated always is false. - return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType == cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), capInsets); + return this.initWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), capInsets); }, /** * Initializes a 9-slice sprite with an sprite frame name and with the specified * cap insets. * Once the sprite is created, you can then call its "setContentSize:" method - * to resize the sprite will all it's 9-slice goodness intract. + * to resize the sprite will all it's 9-slice goodness interact. * It respects the anchorPoint too. * * @param spriteFrameName The sprite frame name. @@ -533,26 +538,24 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ * cap insets of a sprite. In both cases, you get back a new image and the * original sprite remains untouched. * - * @param capInsets The values to use for the cap insets. + * @param {cc.Rect} capInsets The values to use for the cap insets. */ resizableSpriteWithCapInsets: function (capInsets) { var pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets)) { + if (pReturn && pReturn.initWithBatchNode(this._scale9Image, this._spriteRect, false, capInsets)) return pReturn; - } return null; }, /** sets the premultipliedAlphaOpacity property. If set to NO then opacity will be applied as: glColor(R,G,B,opacity); - If set to YES then oapcity will be applied as: glColor(opacity, opacity, opacity, opacity ); + If set to YES then opacity will be applied as: glColor(opacity, opacity, opacity, opacity ); Textures with premultiplied alpha will have this property by default on YES. Otherwise the default value is NO @since v0.8 */ setOpacityModifyRGB: function (value) { - if(!this._scale9Image){ + if(!this._scale9Image) return; - } this._opacityModifyRGB = value; var scaleChildren = this._scale9Image.getChildren(); if (scaleChildren) { @@ -568,6 +571,14 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ return this._opacityModifyRGB; }, + /** + * Update the scale9Sprite with a SpriteBatchNode. + * @param {cc.SpriteBatchNode} batchNode + * @param {cc.Rect} originalRect + * @param {boolean} rotated + * @param {cc.Rect} capInsets + * @returns {boolean} + */ updateWithBatchNode: function (batchNode, originalRect, rotated, capInsets) { var opacity = this.getOpacity(); var color = this.getColor(); @@ -576,21 +587,15 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ // Release old sprites this.removeAllChildren(true); - if (this._scale9Image != batchNode){ + if (this._scale9Image !== batchNode) this._scale9Image = batchNode; - } + + if(!this._scale9Image) + return false; + var tmpTexture = batchNode.getTexture(); var locLoaded = tmpTexture.isLoaded(); this._textureLoaded = locLoaded; - if(!locLoaded){ - tmpTexture.addLoadedEventListener(function(sender){ - this._positionsAreDirty = true; - this._callLoadedEventCallbacks(); - },this); - return; - } - var locScale9Image = this._scale9Image; - locScale9Image.removeAllChildren(true); //this._capInsets = capInsets; var locCapInsets = this._capInsets; @@ -598,6 +603,17 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ locCapInsets.y = capInsets.y; locCapInsets.width = capInsets.width; locCapInsets.height = capInsets.height; + + if(!locLoaded){ + tmpTexture.addEventListener("load", function(sender){ + this._positionsAreDirty = true; + this.dispatchEvent("load"); + },this); + return true; + } + var locScale9Image = this._scale9Image; + locScale9Image.removeAllChildren(true); + this._spriteFrameRotated = rotated; var selTexture = locScale9Image.getTexture(); @@ -633,8 +649,7 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ locCapInsetsInternal.width = capInsets.width; locCapInsetsInternal.height = capInsets.height; } - var w = rect.width; - var h = rect.height; + var w = rect.width, h = rect.height; // If there is no specified center region if (cc._rectEqualToZero(locCapInsetsInternal)) { @@ -645,29 +660,24 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ locCapInsetsInternal.height = h / 3; } - var left_w = locCapInsetsInternal.x; - var center_w = locCapInsetsInternal.width; - var right_w = w - (left_w + center_w); + var left_w = locCapInsetsInternal.x, center_w = locCapInsetsInternal.width, right_w = w - (left_w + center_w); - var top_h = locCapInsetsInternal.y; - var center_h = locCapInsetsInternal.height; - var bottom_h = h - (top_h + center_h); + var top_h = locCapInsetsInternal.y, center_h = locCapInsetsInternal.height, bottom_h = h - (top_h + center_h); // calculate rects // ... top row - var x = 0.0; - var y = 0.0; + var x = 0.0, y = 0.0; // top left - var lefttopbounds = cc.rect(x, y, left_w, top_h); + var lefttopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, top_h + 0.5 | 0); // top center x += left_w; - var centertopbounds = cc.rect(x, y, center_w, top_h); + var centertopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, top_h + 0.5 | 0); // top right x += center_w; - var righttopbounds = cc.rect(x, y, right_w, top_h); + var righttopbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, top_h + 0.5 | 0); // ... center row x = 0.0; @@ -675,15 +685,15 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ y += top_h; // center left - var leftcenterbounds = cc.rect(x, y, left_w, center_h); + var leftcenterbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, center_h + 0.5 | 0); // center center x += left_w; - var centerbounds = cc.rect(x, y, center_w, center_h); + var centerbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, center_h + 0.5 | 0); // center right x += center_w; - var rightcenterbounds = cc.rect(x, y, right_w, center_h); + var rightcenterbounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, center_h + 0.5 | 0); // ... bottom row x = 0.0; @@ -692,75 +702,75 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ y += center_h; // bottom left - var leftbottombounds = cc.rect(x, y, left_w, bottom_h); + var leftbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, left_w + 0.5 | 0, bottom_h + 0.5 | 0); // bottom center x += left_w; - var centerbottombounds = cc.rect(x, y, center_w, bottom_h); + var centerbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, center_w + 0.5 | 0, bottom_h + 0.5 | 0); // bottom right x += center_w; - var rightbottombounds = cc.rect(x, y, right_w, bottom_h); + var rightbottombounds = cc.rect(x + 0.5 | 0, y + 0.5 | 0, right_w + 0.5 | 0, bottom_h + 0.5 | 0); - var t = cc.AffineTransformMakeIdentity(); + var t = cc.affineTransformMakeIdentity(); if (!rotated) { // CCLog("!rotated"); - t = cc.AffineTransformTranslate(t, rect.x, rect.y); - - cc._RectApplyAffineTransformIn(centerbounds, t); - cc._RectApplyAffineTransformIn(rightbottombounds, t); - cc._RectApplyAffineTransformIn(leftbottombounds, t); - cc._RectApplyAffineTransformIn(righttopbounds, t); - cc._RectApplyAffineTransformIn(lefttopbounds, t); - cc._RectApplyAffineTransformIn(rightcenterbounds, t); - cc._RectApplyAffineTransformIn(leftcenterbounds, t); - cc._RectApplyAffineTransformIn(centerbottombounds, t); - cc._RectApplyAffineTransformIn(centertopbounds, t); + t = cc.affineTransformTranslate(t, rect.x, rect.y); + + cc._rectApplyAffineTransformIn(centerbounds, t); + cc._rectApplyAffineTransformIn(rightbottombounds, t); + cc._rectApplyAffineTransformIn(leftbottombounds, t); + cc._rectApplyAffineTransformIn(righttopbounds, t); + cc._rectApplyAffineTransformIn(lefttopbounds, t); + cc._rectApplyAffineTransformIn(rightcenterbounds, t); + cc._rectApplyAffineTransformIn(leftcenterbounds, t); + cc._rectApplyAffineTransformIn(centerbottombounds, t); + cc._rectApplyAffineTransformIn(centertopbounds, t); // Centre this._centre = new cc.Sprite(); this._centre.initWithTexture(selTexture, centerbounds); - locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); + locScale9Image.addChild(this._centre, 0, cc.Scale9Sprite.POSITIONS_CENTRE); // Top this._top = new cc.Sprite(); this._top.initWithTexture(selTexture, centertopbounds); - locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); + locScale9Image.addChild(this._top, 1, cc.Scale9Sprite.POSITIONS_TOP); // Bottom this._bottom = new cc.Sprite(); this._bottom.initWithTexture(selTexture, centerbottombounds); - locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); + locScale9Image.addChild(this._bottom, 1, cc.Scale9Sprite.POSITIONS_BOTTOM); // Left this._left = new cc.Sprite(); this._left.initWithTexture(selTexture, leftcenterbounds); - locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); + locScale9Image.addChild(this._left, 1, cc.Scale9Sprite.POSITIONS_LEFT); // Right this._right = new cc.Sprite(); this._right.initWithTexture(selTexture, rightcenterbounds); - locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); + locScale9Image.addChild(this._right, 1, cc.Scale9Sprite.POSITIONS_RIGHT); // Top left this._topLeft = new cc.Sprite(); this._topLeft.initWithTexture(selTexture, lefttopbounds); - locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); + locScale9Image.addChild(this._topLeft, 2, cc.Scale9Sprite.POSITIONS_TOPLEFT); // Top right this._topRight = new cc.Sprite(); this._topRight.initWithTexture(selTexture, righttopbounds); - locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); + locScale9Image.addChild(this._topRight, 2, cc.Scale9Sprite.POSITIONS_TOPRIGHT); // Bottom left this._bottomLeft = new cc.Sprite(); this._bottomLeft.initWithTexture(selTexture, leftbottombounds); - locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); + locScale9Image.addChild(this._bottomLeft, 2, cc.Scale9Sprite.POSITIONS_BOTTOMLEFT); // Bottom right this._bottomRight = new cc.Sprite(); this._bottomRight.initWithTexture(selTexture, rightbottombounds); - locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); + locScale9Image.addChild(this._bottomRight, 2, cc.Scale9Sprite.POSITIONS_BOTTOMRIGHT); } else { // set up transformation of coordinates // to handle the case where the sprite is stored rotated @@ -776,18 +786,18 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ var rotatedcenterbottombounds = centerbottombounds; var rotatedcentertopbounds = centertopbounds; - t = cc.AffineTransformTranslate(t, rect.height + rect.x, rect.y); - t = cc.AffineTransformRotate(t, 1.57079633); + t = cc.affineTransformTranslate(t, rect.height + rect.x, rect.y); + t = cc.affineTransformRotate(t, 1.57079633); - centerbounds = cc.RectApplyAffineTransform(centerbounds, t); - rightbottombounds = cc.RectApplyAffineTransform(rightbottombounds, t); - leftbottombounds = cc.RectApplyAffineTransform(leftbottombounds, t); - righttopbounds = cc.RectApplyAffineTransform(righttopbounds, t); - lefttopbounds = cc.RectApplyAffineTransform(lefttopbounds, t); - rightcenterbounds = cc.RectApplyAffineTransform(rightcenterbounds, t); - leftcenterbounds = cc.RectApplyAffineTransform(leftcenterbounds, t); - centerbottombounds = cc.RectApplyAffineTransform(centerbottombounds, t); - centertopbounds = cc.RectApplyAffineTransform(centertopbounds, t); + centerbounds = cc.rectApplyAffineTransform(centerbounds, t); + rightbottombounds = cc.rectApplyAffineTransform(rightbottombounds, t); + leftbottombounds = cc.rectApplyAffineTransform(leftbottombounds, t); + righttopbounds = cc.rectApplyAffineTransform(righttopbounds, t); + lefttopbounds = cc.rectApplyAffineTransform(lefttopbounds, t); + rightcenterbounds = cc.rectApplyAffineTransform(rightcenterbounds, t); + leftcenterbounds = cc.rectApplyAffineTransform(leftcenterbounds, t); + centerbottombounds = cc.rectApplyAffineTransform(centerbottombounds, t); + centertopbounds = cc.rectApplyAffineTransform(centertopbounds, t); rotatedcenterbounds.x = centerbounds.x; rotatedcenterbounds.y = centerbounds.y; @@ -819,90 +829,206 @@ cc.Scale9Sprite = cc.NodeRGBA.extend(/** @lends cc.Scale9Sprite# */{ // Centre this._centre = new cc.Sprite(); this._centre.initWithTexture(selTexture, rotatedcenterbounds, true); - locScale9Image.addChild(this._centre, 0, cc.POSITIONS_CENTRE); + locScale9Image.addChild(this._centre, 0, cc.Scale9Sprite.POSITIONS_CENTRE); // Top this._top = new cc.Sprite(); this._top.initWithTexture(selTexture, rotatedcentertopbounds, true); - locScale9Image.addChild(this._top, 1, cc.POSITIONS_TOP); + locScale9Image.addChild(this._top, 1, cc.Scale9Sprite.POSITIONS_TOP); // Bottom this._bottom = new cc.Sprite(); this._bottom.initWithTexture(selTexture, rotatedcenterbottombounds, true); - locScale9Image.addChild(this._bottom, 1, cc.POSITIONS_BOTTOM); + locScale9Image.addChild(this._bottom, 1, cc.Scale9Sprite.POSITIONS_BOTTOM); // Left this._left = new cc.Sprite(); this._left.initWithTexture(selTexture, rotatedleftcenterbounds, true); - locScale9Image.addChild(this._left, 1, cc.POSITIONS_LEFT); + locScale9Image.addChild(this._left, 1, cc.Scale9Sprite.POSITIONS_LEFT); // Right this._right = new cc.Sprite(); this._right.initWithTexture(selTexture, rotatedrightcenterbounds, true); - locScale9Image.addChild(this._right, 1, cc.POSITIONS_RIGHT); + locScale9Image.addChild(this._right, 1, cc.Scale9Sprite.POSITIONS_RIGHT); // Top left this._topLeft = new cc.Sprite(); this._topLeft.initWithTexture(selTexture, rotatedlefttopbounds, true); - locScale9Image.addChild(this._topLeft, 2, cc.POSITIONS_TOPLEFT); + locScale9Image.addChild(this._topLeft, 2, cc.Scale9Sprite.POSITIONS_TOPLEFT); // Top right this._topRight = new cc.Sprite(); this._topRight.initWithTexture(selTexture, rotatedrighttopbounds, true); - locScale9Image.addChild(this._topRight, 2, cc.POSITIONS_TOPRIGHT); + locScale9Image.addChild(this._topRight, 2, cc.Scale9Sprite.POSITIONS_TOPRIGHT); // Bottom left this._bottomLeft = new cc.Sprite(); this._bottomLeft.initWithTexture(selTexture, rotatedleftbottombounds, true); - locScale9Image.addChild(this._bottomLeft, 2, cc.POSITIONS_BOTTOMLEFT); + locScale9Image.addChild(this._bottomLeft, 2, cc.Scale9Sprite.POSITIONS_BOTTOMLEFT); // Bottom right this._bottomRight = new cc.Sprite(); this._bottomRight.initWithTexture(selTexture, rotatedrightbottombounds, true); - locScale9Image.addChild(this._bottomRight, 2, cc.POSITIONS_BOTTOMRIGHT); + locScale9Image.addChild(this._bottomRight, 2, cc.Scale9Sprite.POSITIONS_BOTTOMRIGHT); } - this.setContentSize(rect); - this.addChild(locScale9Image); + this.setContentSize(rect.width, rect.height); + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + this.addChild(locScale9Image); if (this._spritesGenerated) { // Restore color and opacity this.setOpacity(opacity); - if(color.r !== 255 || color.g !== 255 || color.b !== 255){ - this.setColor(color); - } + this.setColor(color); } this._spritesGenerated = true; return true; }, + /** + * set the sprite frame of cc.Scale9Sprite + * @param {cc.SpriteFrame} spriteFrame + */ setSpriteFrame: function (spriteFrame) { - var batchNode = cc.SpriteBatchNode.create(spriteFrame.getTexture(), 9); + var batchNode = new cc.SpriteBatchNode(spriteFrame.getTexture(), 9); // the texture is rotated on Canvas render mode, so isRotated always is false. var locLoaded = spriteFrame.textureLoaded(); this._textureLoaded = locLoaded; if(!locLoaded){ - spriteFrame.addLoadedEventListener(function(sender){ + spriteFrame.addEventListener("load", function(sender){ // the texture is rotated on Canvas render mode, so isRotated always is false. - var preferredSize = this._preferredSize; - preferredSize = cc.size(preferredSize.width, preferredSize.height); - this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType == cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); - this.setPreferredSize(preferredSize); + var preferredSize = this._preferredSize, restorePreferredSize = (preferredSize.width !== 0 || preferredSize.height !== 0); + if(restorePreferredSize)preferredSize = cc.size(preferredSize.width, preferredSize.height); + this.updateWithBatchNode(this._scale9Image, sender.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && sender.isRotated(), this._capInsets); + if(restorePreferredSize)this.setPreferredSize(preferredSize); this._positionsAreDirty = true; - this._callLoadedEventCallbacks(); + this.dispatchEvent("load"); },this); } - this.updateWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType == cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), cc.rect(0, 0, 0, 0)); + this.updateWithBatchNode(batchNode, spriteFrame.getRect(), cc._renderType === cc._RENDER_TYPE_WEBGL && spriteFrame.isRotated(), cc.rect(0, 0, 0, 0)); // Reset insets this._insetLeft = 0; this._insetTop = 0; this._insetRight = 0; this._insetBottom = 0; + }, + + //v3.3 + /** + * Sets cc.Scale9Sprite's state + * @since v3.3 + * @param {Number} state + */ + setState: function(state){ + this._renderCmd.setState(state); + }, + + //setScale9Enabled implement late + + /** + * Sets whether the widget should be flipped horizontally or not. + * @since v3.3 + * @param flippedX true if the widget should be flipped horizontally, false otherwise. + */ + setFlippedX: function(flippedX){ + var realScale = this.getScaleX(); + this._flippedX = flippedX; + this.setScaleX(realScale); + }, + + /** + *

    + * Returns the flag which indicates whether the widget is flipped horizontally or not.
    + *
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget->setScaleX(sprite->getScaleX() * -1);
    + *

    + * @since v3.3 + * @return {Boolean} true if the widget is flipped horizontally, false otherwise. + */ + isFlippedX: function(){ + return this._flippedX; + }, + + /** + * Sets whether the widget should be flipped vertically or not. + * @since v3.3 + * @param flippedY true if the widget should be flipped vertically, false otherwise. + */ + setFlippedY:function(flippedY){ + var realScale = this.getScaleY(); + this._flippedY = flippedY; + this.setScaleY(realScale); + }, + + /** + *

    + * Return the flag which indicates whether the widget is flipped vertically or not.
    + *
    + * It only flips the texture of the widget, and not the texture of the widget's children.
    + * Also, flipping the texture doesn't alter the anchorPoint.
    + * If you want to flip the anchorPoint too, and/or to flip the children too use:
    + * widget->setScaleY(widget->getScaleY() * -1);
    + *

    + * @since v3.3 + * @return {Boolean} true if the widget is flipped vertically, false otherwise. + */ + isFlippedY:function(){ + return this._flippedY; + }, + + setScaleX: function (scaleX) { + if (this._flippedX) + scaleX = scaleX * -1; + cc.Node.prototype.setScaleX.call(this, scaleX); + }, + + setScaleY: function (scaleY) { + if (this._flippedY) + scaleY = scaleY * -1; + cc.Node.prototype.setScaleY.call(this, scaleY); + }, + + setScale: function (scaleX, scaleY) { + if(scaleY === undefined) + scaleY = scaleX; + this.setScaleX(scaleX); + this.setScaleY(scaleY); + }, + + getScaleX: function () { + var originalScale = cc.Node.prototype.getScaleX.call(this); + if (this._flippedX) + originalScale = originalScale * -1.0; + return originalScale; + }, + + getScaleY: function () { + var originalScale = cc.Node.prototype.getScaleY.call(this); + if (this._flippedY) + originalScale = originalScale * -1.0; + return originalScale; + }, + + getScale: function () { + if(this.getScaleX() !== this.getScaleY()) + cc.log("Scale9Sprite#scale. ScaleX != ScaleY. Don't know which one to return"); + return this.getScaleX(); + }, + + _createRenderCmd: function(){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new cc.Scale9Sprite.CanvasRenderCmd(this); + else + return new cc.Scale9Sprite.WebGLRenderCmd(this); } }); -window._p = cc.Scale9Sprite.prototype; +var _p = cc.Scale9Sprite.prototype; +cc.EventHelper.prototype.apply(_p); // Extended properties /** @expose */ @@ -924,60 +1050,52 @@ cc.defineGetterSetter(_p, "insetRight", _p.getInsetRight, _p.setInsetRight); _p.insetBottom; cc.defineGetterSetter(_p, "insetBottom", _p.getInsetBottom, _p.setInsetBottom); -delete window._p; +_p = null; /** * Creates a 9-slice sprite with a texture file, a delimitation zone and * with the specified cap insets. - * - * @see initWithFile:rect:centerRegion: + * @deprecated + * @param {String|cc.SpriteFrame} file file name of texture or a cc.Sprite object + * @param {cc.Rect} rect the rect of the texture + * @param {cc.Rect} capInsets the cap insets of cc.Scale9Sprite + * @returns {cc.Scale9Sprite} */ cc.Scale9Sprite.create = function (file, rect, capInsets) { - var pReturn; - if (arguments.length === 2) { - if (typeof(file) == "string") { - pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithFile(file, rect)) { - return pReturn; - } - } else if (file instanceof cc.Rect) { - pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithFile(file, capInsets)) { - return pReturn; - } - } - } else if (arguments.length === 3) { - pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithFile(file, rect, capInsets)) { - return pReturn; - } - } else if (arguments.length === 1) { - pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithFile(file)) { - return pReturn; - } - } else if (arguments.length === 0) { - pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.init()) { - return pReturn; - } - } - return null; + return new cc.Scale9Sprite(file, rect, capInsets); }; +/** + * @deprecated + * @param spriteFrame + * @param capInsets + * @returns {cc.Scale9Sprite} + */ cc.Scale9Sprite.createWithSpriteFrame = function (spriteFrame, capInsets) { - var pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithSpriteFrame(spriteFrame, capInsets)) { - return pReturn; - } - return null; + return new cc.Scale9Sprite(spriteFrame, capInsets); }; +/** + * @deprecated + * @param spriteFrameName + * @param capInsets + * @returns {cc.Scale9Sprite} + */ cc.Scale9Sprite.createWithSpriteFrameName = function (spriteFrameName, capInsets) { - if(!spriteFrameName) - throw "cc.Scale9Sprite.createWithSpriteFrameName(): spriteFrameName should be non-null"; - var pReturn = new cc.Scale9Sprite(); - if (pReturn && pReturn.initWithSpriteFrameName(spriteFrameName, capInsets)) - return pReturn; - return null; + return new cc.Scale9Sprite(spriteFrameName, capInsets); }; + +/** + * @ignore + */ +cc.Scale9Sprite.POSITIONS_CENTRE = 0; +cc.Scale9Sprite.POSITIONS_TOP = 1; +cc.Scale9Sprite.POSITIONS_LEFT = 2; +cc.Scale9Sprite.POSITIONS_RIGHT = 3; +cc.Scale9Sprite.POSITIONS_BOTTOM = 4; +cc.Scale9Sprite.POSITIONS_TOPRIGHT = 5; +cc.Scale9Sprite.POSITIONS_TOPLEFT = 6; +cc.Scale9Sprite.POSITIONS_BOTTOMRIGHT = 7; + +cc.Scale9Sprite.state = {NORMAL: 0, GRAY: 1}; + diff --git a/extensions/gui/control-extension/CCScale9SpriteCanvasRenderCmd.js b/extensions/gui/control-extension/CCScale9SpriteCanvasRenderCmd.js new file mode 100644 index 0000000000..0c693d6f02 --- /dev/null +++ b/extensions/gui/control-extension/CCScale9SpriteCanvasRenderCmd.js @@ -0,0 +1,144 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function() { + cc.Scale9Sprite.CanvasRenderCmd = function (renderable) { + cc.Node.CanvasRenderCmd.call(this, renderable); + this._cachedParent = null; + this._cacheDirty = false; + this._state = cc.Scale9Sprite.state.NORMAL; + + var node = this._node; + var locCacheCanvas = this._cacheCanvas = cc.newElement('canvas'); + locCacheCanvas.width = 1; + locCacheCanvas.height = 1; + this._cacheContext = new cc.CanvasContextWrapper(locCacheCanvas.getContext("2d")); + var locTexture = this._cacheTexture = new cc.Texture2D(); + locTexture.initWithElement(locCacheCanvas); + locTexture.handleLoadedTexture(); + this._cacheSprite = new cc.Sprite(locTexture); + this._cacheSprite.setAnchorPoint(0,0); + node.addChild(this._cacheSprite); + }; + + var proto = cc.Scale9Sprite.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = cc.Scale9Sprite.CanvasRenderCmd; + + proto.visit = function(parentCmd){ + var node = this._node; + if(!node._visible) + return; + + if (node._positionsAreDirty) { + node._updatePositions(); + node._positionsAreDirty = false; + node._scale9Dirty = true; + } + node._scale9Dirty = false; + this._cacheScale9Sprite(); + + cc.Node.CanvasRenderCmd.prototype.visit.call(this, parentCmd); + }; + + proto.transform = function(parentCmd){ + var node = this._node; + cc.Node.CanvasRenderCmd.prototype.transform.call(this, parentCmd); + if (node._positionsAreDirty) { + node._updatePositions(); + node._positionsAreDirty = false; + node._scale9Dirty = true; + } + this._cacheScale9Sprite(); + + var children = node._children; + for(var i=0; i The current container's minimum offset * @property {cc.Point} maxOffset - <@readonly> The current container's maximum offset @@ -100,7 +102,13 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ _touchListener: null, _className:"ScrollView", - ctor:function () { + /** + * @contructor + * @param size + * @param container + * @returns {ScrollView} + */ + ctor:function (size, container) { cc.Layer.prototype.ctor.call(this); this._contentOffset = cc.p(0,0); this._maxInset = cc.p(0, 0); @@ -111,6 +119,12 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ this._viewSize = cc.size(0, 0); this._parentScissorRect = new cc.Rect(0,0,0,0); this._tmpViewRect = new cc.Rect(0,0,0,0); + + if(container != undefined) + this.initWithViewSize(size, container); + else + this.initWithViewSize(cc.size(200, 200), null); + }, init:function () { @@ -129,7 +143,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ this._container = container; if (!this._container) { - this._container = cc.Layer.create(); + this._container = new cc.Layer(); this._container.ignoreAnchorPointForPosition(false); this._container.setAnchorPoint(pZero); } @@ -194,9 +208,9 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ * @param {Number} dt animation duration */ setContentOffsetInDuration:function (offset, dt) { - var scroll = cc.MoveTo.create(dt, offset); - var expire = cc.CallFunc.create(this._stoppedAnimatedScroll, this); - this._container.runAction(cc.Sequence.create(scroll, expire)); + var scroll = cc.moveTo(dt, offset); + var expire = cc.callFunc(this._stoppedAnimatedScroll, this); + this._container.runAction(cc.sequence(scroll, expire)); this.schedule(this._performedAnimatedScroll); }, @@ -213,11 +227,11 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ } var locContainer = this._container; - if (locContainer.getScale() != scale) { + if (locContainer.getScale() !== scale) { var oldCenter, newCenter; var center; - if (this._touchLength == 0.0) { + if (this._touchLength === 0.0) { var locViewSize = this._viewSize; center = cc.p(locViewSize.width * 0.5, locViewSize.height * 0.5); center = this.convertToWorldSpace(center); @@ -248,8 +262,8 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ setZoomScaleInDuration:function (s, dt) { if (dt > 0) { var locScale = this._container.getScale(); - if (locScale != s) { - var scaleAction = cc.ActionTween.create(dt, "zoomScale", locScale, s); + if (locScale !== s) { + var scaleAction = cc.actionTween(dt, "zoomScale", locScale, s); this.runAction(scaleAction); } } else { @@ -300,6 +314,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ for (var i = 0; i < selChildren.length; i++) { selChildren[i].pause(); } + this._super(); }, /** @@ -311,6 +326,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ selChildren[i].resume(); } this._container.resume(); + this._super(); }, isDragging:function () { @@ -405,7 +421,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ this._scrollDistance.x = 0; this._scrollDistance.y = 0; this._touchLength = 0.0; - } else if (locTouches.length == 2) { + } else if (locTouches.length === 2) { this._touchPoint = cc.pMidpoint(this.convertTouchToNodeSpace(locTouches[0]), this.convertTouchToNodeSpace(locTouches[1])); this._touchLength = cc.pDistance(locContainer.convertTouchToNodeSpace(locTouches[0]), @@ -419,6 +435,8 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ if (!this.isVisible()) return; + this.setNodeDirty(); + if (this._touches.length === 1 && this._dragging) { // scrolling this._touchMoved = true; //var frameOriginal = this.getParent().convertToWorldSpace(this.getPosition()); @@ -496,7 +514,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ if (!this.isVisible()) return; - if (this._touches.length == 1 && this._touchMoved) + if (this._touches.length === 1 && this._touchMoved) this.schedule(this._deaccelerateScrolling); this._touches.length = 0; @@ -514,7 +532,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ }, setContentSize: function (size, height) { - if (this.getContainer() != null) { + if (this.getContainer() !== null) { if(height === undefined) this.getContainer().setContentSize(size); else @@ -524,14 +542,14 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ }, _setWidth: function (value) { var container = this.getContainer(); - if (container != null) { + if (container !== null) { container._setWidth(value); this.updateInset(); } }, _setHeight: function (value) { var container = this.getContainer(); - if (container != null) { + if (container !== null) { container._setHeight(value); this.updateInset(); } @@ -542,7 +560,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ }, updateInset:function () { - if (this.getContainer() != null) { + if (this.getContainer() !== null) { var locViewSize = this._viewSize; var tempOffset = this.maxContainerOffset(); this._maxInset.x = tempOffset.x + locViewSize.width * INSET_RATIO; @@ -564,79 +582,12 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ this._clippingToBounds = clippingToBounds; }, - visit:function (ctx) { + visit:function (parentCmd) { // quick return if not visible if (!this.isVisible()) return; - var context = ctx || cc._renderContext; - var i, locChildren = this._children, selChild, childrenLen; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - context.save(); - this.transform(context); - this._beforeDraw(context); - - if (locChildren && locChildren.length > 0) { - childrenLen = locChildren.length; - this.sortAllChildren(); - // draw children zOrder < 0 - for (i = 0; i < childrenLen; i++) { - selChild = locChildren[i]; - if (selChild && selChild._localZOrder < 0) - selChild.visit(context); - else - break; - } - - this.draw(context); // self draw - - // draw children zOrder >= 0 - for (; i < childrenLen; i++) - locChildren[i].visit(context); - } else{ - this.draw(context); // self draw - } - - this._afterDraw(); - - context.restore(); - } else { - cc.kmGLPushMatrix(); - var locGrid = this.grid; - if (locGrid && locGrid.isActive()) { - locGrid.beforeDraw(); - this.transformAncestors(); - } - - this.transform(context); - this._beforeDraw(context); - if (locChildren && locChildren.length > 0) { - childrenLen = locChildren.length; - // draw children zOrder < 0 - for (i = 0; i < childrenLen; i++) { - selChild = locChildren[i]; - if (selChild && selChild._localZOrder < 0) - selChild.visit(); - else - break; - } - - // this draw - this.draw(context); - - // draw children zOrder >= 0 - for (; i < childrenLen; i++) - locChildren[i].visit(); - } else{ - this.draw(context); - } - - this._afterDraw(context); - if (locGrid && locGrid.isActive()) - locGrid.afterDraw(this); - - cc.kmGLPopMatrix(); - } + this._renderCmd.visit(parentCmd); }, addChild:function (child, zOrder, tag) { @@ -646,9 +597,9 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ zOrder = zOrder || child.getLocalZOrder(); tag = tag || child.getTag(); - child.ignoreAnchorPointForPosition(false); - child.setAnchorPoint(0, 0); - if (this._container != child) { + //child.ignoreAnchorPointForPosition(false); + //child.setAnchorPoint(0, 0); + if (this._container !== child) { this._container.addChild(child, zOrder, tag); } else { cc.Layer.prototype.addChild.call(this, child, zOrder, tag); @@ -656,7 +607,7 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ }, isTouchEnabled: function(){ - return this._touchListener != null; + return this._touchListener !== null; }, setTouchEnabled:function (e) { @@ -712,12 +663,12 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ newX = Math.min(newX, max.x); } - if (locDirection == cc.SCROLLVIEW_DIRECTION_BOTH || locDirection == cc.SCROLLVIEW_DIRECTION_VERTICAL) { + if (locDirection === cc.SCROLLVIEW_DIRECTION_BOTH || locDirection === cc.SCROLLVIEW_DIRECTION_VERTICAL) { newY = Math.min(newY, max.y); newY = Math.max(newY, min.y); } - if (newY != oldPoint.y || newX != oldPoint.x) { + if (newY !== oldPoint.y || newX !== oldPoint.x) { this.setContentOffset(cc.p(newX, newY), animated); } }, @@ -758,8 +709,8 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ Math.abs(locScrollDistance.y) <= SCROLL_DEACCEL_DIST) || newY > maxInset.y || newY < minInset.y || newX > maxInset.x || newX < minInset.x || - newX == maxInset.x || newX == minInset.x || - newY == maxInset.y || newY == minInset.y) { + newX === maxInset.x || newX === minInset.x || + newY === maxInset.y || newY === minInset.y) { this.unschedule(this._deaccelerateScrolling); this._relocateContainer(true); } @@ -787,65 +738,6 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ } }, - /** - * clip this view so that outside of the visible bounds can be hidden. - */ - _beforeDraw:function (context) { - if (this._clippingToBounds) { - this._scissorRestored = false; - var frame = this._getViewRect(), locEGLViewer = cc.view; - - var scaleX = this.getScaleX(); - var scaleY = this.getScaleY(); - - var ctx = context || cc._renderContext; - if (cc._renderType === cc._RENDER_TYPE_CANVAS) { - var getWidth = (this._viewSize.width * scaleX) * locEGLViewer.getScaleX(); - var getHeight = (this._viewSize.height * scaleY) * locEGLViewer.getScaleY(); - var startX = 0; - var startY = 0; - - ctx.beginPath(); - ctx.rect(startX, startY, getWidth, -getHeight); - ctx.clip(); - ctx.closePath(); - } else { - var EGLViewer = cc.view; - if(EGLViewer.isScissorEnabled()){ - this._scissorRestored = true; - this._parentScissorRect = EGLViewer.getScissorRect(); - //set the intersection of m_tParentScissorRect and frame as the new scissor rect - if (cc.rectIntersection(frame, this._parentScissorRect)) { - var locPSRect = this._parentScissorRect; - var x = Math.max(frame.x, locPSRect.x); - var y = Math.max(frame.y, locPSRect.y); - var xx = Math.min(frame.x + frame.width, locPSRect.x + locPSRect.width); - var yy = Math.min(frame.y + frame.height, locPSRect.y + locPSRect.height); - EGLViewer.setScissorInPoints(x, y, xx - x, yy - y); - } - }else{ - ctx.enable(ctx.SCISSOR_TEST); - //clip - EGLViewer.setScissorInPoints(frame.x, frame.y, frame.width, frame.height); - } - } - } - }, - /** - * retract what's done in beforeDraw so that there's no side effect to - * other nodes. - */ - _afterDraw:function (context) { - if (this._clippingToBounds && cc._renderType === cc._RENDER_TYPE_WEBGL) { - if (this._scissorRestored) { //restore the parent's scissor rect - var rect = this._parentScissorRect; - cc.view.setScissorInPoints(rect.x, rect.y, rect.width, rect.height) - }else{ - var ctx = context || cc._renderContext; - ctx.disable(ctx.SCISSOR_TEST); - } - } - }, /** * Zoom handling */ @@ -882,10 +774,18 @@ cc.ScrollView = cc.Layer.extend(/** @lends cc.ScrollView# */{ locViewRect.width = locViewSize.width * scaleX; locViewRect.height = locViewSize.height * scaleY; return locViewRect; + }, + + _createRenderCmd: function(){ + if (cc._renderType === cc._RENDER_TYPE_CANVAS) { + return new cc.ScrollView.CanvasRenderCmd(this); + } else { + return new cc.ScrollView.WebGLRenderCmd(this); + } } }); -window._p = cc.ScrollView.prototype; +var _p = cc.ScrollView.prototype; // Extended properties /** @expose */ @@ -913,23 +813,15 @@ cc.defineGetterSetter(_p, "delegate", _p.getDelegate, _p.setDelegate); _p.clippingToBounds; cc.defineGetterSetter(_p, "clippingToBounds", _p.isClippingToBounds, _p.setClippingToBounds); -delete window._p; +_p = null; /** * Returns an autoreleased scroll view object. - * + * @deprecated * @param {cc.Size} size view size * @param {cc.Node} container parent object * @return {cc.ScrollView} scroll view object */ cc.ScrollView.create = function (size, container) { - var pRet = new cc.ScrollView(); - if (arguments.length == 2) { - if (pRet && pRet.initWithViewSize(size, container)) - return pRet; - } else { - if (pRet && pRet.init()) - return pRet; - } - return null; + return new cc.ScrollView(size, container); }; \ No newline at end of file diff --git a/extensions/gui/scrollview/CCScrollViewCanvasRenderCmd.js b/extensions/gui/scrollview/CCScrollViewCanvasRenderCmd.js new file mode 100644 index 0000000000..af61a5d5de --- /dev/null +++ b/extensions/gui/scrollview/CCScrollViewCanvasRenderCmd.js @@ -0,0 +1,79 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function() { + cc.ScrollView.CanvasRenderCmd = function(renderable){ + cc.Layer.CanvasRenderCmd.call(this, renderable); + this._needDraw = false; + + this.startCmd = new cc.CustomRenderCmd(this, this._startCmd); + this.endCmd = new cc.CustomRenderCmd(this, this._endCmd); + }; + + var proto = cc.ScrollView.CanvasRenderCmd.prototype = Object.create(cc.Layer.CanvasRenderCmd.prototype); + proto.constructor = cc.ScrollView.CanvasRenderCmd; + + proto._startCmd = function(ctx, scaleX, scaleY){ + var node = this._node; + var wrapper = ctx || cc._renderContext, context = wrapper.getContext(); + wrapper.save(); + + if (node._clippingToBounds) { + this._scissorRestored = false; + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + + var locScaleX = node.getScaleX(), locScaleY = node.getScaleY(); + + var getWidth = (node._viewSize.width * locScaleX) * scaleX; + var getHeight = (node._viewSize.height * locScaleY) * scaleY; + + context.beginPath(); + context.rect(0, 0, getWidth, -getHeight); + context.closePath(); + context.clip(); + } + }; + + proto._endCmd = function(wrapper){ + wrapper = wrapper || cc._renderContext; + wrapper.restore(); + }; + + proto.visit = function(parentCmd){ + var node = this._node; + var i, locChildren = node._children, childrenLen; + + this.transform(parentCmd); + cc.renderer.pushRenderCommand(this.startCmd); + + if (locChildren && locChildren.length > 0) { + childrenLen = locChildren.length; + node.sortAllChildren(); + for (i = 0; i < childrenLen; i++) { + locChildren[i]._renderCmd.visit(this); + } + } + cc.renderer.pushRenderCommand(this.endCmd); + }; +})(); \ No newline at end of file diff --git a/extensions/gui/scrollview/CCScrollViewWebGLRenderCmd.js b/extensions/gui/scrollview/CCScrollViewWebGLRenderCmd.js new file mode 100644 index 0000000000..cc26655fce --- /dev/null +++ b/extensions/gui/scrollview/CCScrollViewWebGLRenderCmd.js @@ -0,0 +1,108 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function() { + cc.ScrollView.WebGLRenderCmd = function(renderable){ + cc.Layer.WebGLRenderCmd.call(this, renderable); + this._needDraw = false; + + this.startCmd = new cc.CustomRenderCmd(this, this._startCmd); + this.endCmd = new cc.CustomRenderCmd(this, this._endCmd); + }; + + var proto = cc.ScrollView.WebGLRenderCmd.prototype = Object.create(cc.Layer.WebGLRenderCmd.prototype); + proto.constructor = cc.ScrollView.WebGLRenderCmd; + + proto._startCmd = function(){ + var node = this._node; + var EGLViewer = cc.view; + var frame = node._getViewRect(); + if(EGLViewer.isScissorEnabled()){ + node._scissorRestored = true; + node._parentScissorRect = EGLViewer.getScissorRect(); + //set the intersection of m_tParentScissorRect and frame as the new scissor rect + if (cc.rectIntersection(frame, node._parentScissorRect)) { + var locPSRect = node._parentScissorRect; + var x = Math.max(frame.x, locPSRect.x); + var y = Math.max(frame.y, locPSRect.y); + var xx = Math.min(frame.x + frame.width, locPSRect.x + locPSRect.width); + var yy = Math.min(frame.y + frame.height, locPSRect.y + locPSRect.height); + EGLViewer.setScissorInPoints(x, y, xx - x, yy - y); + } + }else{ + var ctx = cc._renderContext; + ctx.enable(ctx.SCISSOR_TEST); + //clip + EGLViewer.setScissorInPoints(frame.x, frame.y, frame.width, frame.height); + } + }; + + proto._endCmd = function(){ + var node = this._node; + if (node._scissorRestored) { //restore the parent's scissor rect + var rect = node._parentScissorRect; + cc.view.setScissorInPoints(rect.x, rect.y, rect.width, rect.height) + }else{ + var ctx = cc._renderContext; + ctx.disable(ctx.SCISSOR_TEST); + } + }; + + proto.visit = function(parendCmd){ + var node = this._node; + + var i, locChildren = node._children, selChild, childrenLen; + + cc.kmGLPushMatrix(); + + this.transform(parendCmd); + + if (node._clippingToBounds) { + cc.renderer.pushRenderCommand(this.startCmd); + } + + if (locChildren && locChildren.length > 0) { + childrenLen = locChildren.length; + // draw children zOrder < 0 + for (i = 0; i < childrenLen; i++) { + selChild = locChildren[i]; + if (selChild && selChild._localZOrder < 0) + selChild._renderCmd.visit(); + else + break; + } + + // draw children zOrder >= 0 + for (; i < childrenLen; i++) + locChildren[i]._renderCmd.visit(); + } + + if (node._clippingToBounds) { + cc.renderer.pushRenderCommand(this.endCmd); + } + + this._dirtyFlag = 0; + cc.kmGLPopMatrix(); + }; +})(); \ No newline at end of file diff --git a/extensions/gui/scrollview/CCSorting.js b/extensions/gui/scrollview/CCSorting.js index 96fe4b1493..8aaf500710 100644 --- a/extensions/gui/scrollview/CCSorting.js +++ b/extensions/gui/scrollview/CCSorting.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2010 Sangwoo Im http://www.cocos2d-x.org @@ -81,7 +83,8 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# * If the compare message does not result NSComparisonResult, sorting behavior * is not defined. It ignores duplicate entries and inserts next to it. * - * @param {object} addObject + * @function + * @param {Object} addObject Object to insert */ insertSortedObject:function (addObject) { if(!addObject) @@ -96,17 +99,18 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# * Removes an object with given key and value. If no object is found in array * with the key and value, no action is taken. * - * @param value to remove + * @function + * @param {Object} delObject Object to remove */ removeSortedObject:function (delObject) { - if (this.count() == 0) { + if (this.count() === 0) { return; } var idx = this.indexOfSortedObject(delObject); - if (idx < this.count() && idx != cc.INVALID_INDEX) { + if (idx < this.count() && idx !== cc.INVALID_INDEX) { var foundObj = this.objectAtIndex(idx); - if (foundObj.getObjectID() == delObject.getObjectID()) { + if (foundObj.getObjectID() === delObject.getObjectID()) { this.removeObjectAtIndex(idx); } } @@ -119,14 +123,15 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# * keep consistency of being sorted. If it is changed externally, it must be * sorted completely again. * - * @param value to set - * @param object the object which has the value + * @function + * @param {Number} tag Tag to set + * @param {Object} setObject The object which would be set */ setObjectID_ofSortedObject:function (tag, setObject) { var idx = this.indexOfSortedObject(setObject); - if (idx < this.count() && idx != cc.INVALID_INDEX) { + if (idx < this.count() && idx !== cc.INVALID_INDEX) { var foundObj = this.objectAtIndex(idx); - if (foundObj.getObjectID() == setObject.getObjectID()) { + if (foundObj.getObjectID() === setObject.getObjectID()) { this.removeObjectAtIndex(idx); foundObj.setObjectID(tag); this.insertSortedObject(foundObj); @@ -135,16 +140,16 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# }, objectWithObjectID:function (tag) { - if (this.count() == 0) { + if (this.count() === 0) { return null; } var foundObj = new cc.SortedObject(); foundObj.setObjectID(tag); var idx = this.indexOfSortedObject(foundObj); - if (idx < this.count() && idx != cc.INVALID_INDEX) { + if (idx < this.count() && idx !== cc.INVALID_INDEX) { foundObj = this.objectAtIndex(idx); - if (foundObj.getObjectID() != tag) + if (foundObj.getObjectID() !== tag) foundObj = null; } return foundObj; @@ -156,8 +161,9 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# * Returns an object with given key and value. If no object is found, * it returns nil. * - * @param value to locate object - * @return object found or nil. + * @function + * @param {Number} tag Tag to locate object + * @return {Object|null} */ getObjectWithObjectID:function (tag) { return null; @@ -171,8 +177,9 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# * would have been located. If object must be located at the end of array, * it returns the length of the array, which is out of bound. * - * @param value to locate object - * @return index of an object found + * @function + * @param {Number} idxObj Id to locate object + * @return {Number} index of an object found */ indexOfSortedObject:function (idxObj) { var idx = 0; @@ -186,7 +193,7 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# for (var i = 0; i < locObjectArr.length; i++) { var pSortableObj = locObjectArr[i]; var curObjectID = pSortableObj.getObjectID(); - if ((uOfSortObjectID == curObjectID) || + if ((uOfSortObjectID === curObjectID) || (uOfSortObjectID >= uPrevObjectID && uOfSortObjectID < curObjectID)) { break; } @@ -206,7 +213,7 @@ cc.ArrayForObjectSorting = cc.Class.extend(/** @lends cc.ArrayForObjectSorting# lastObject:function () { var locObjectArr = this._saveObjectArr; - if (locObjectArr.length == 0) + if (locObjectArr.length === 0) return null; return locObjectArr[locObjectArr.length - 1]; }, diff --git a/extensions/gui/scrollview/CCTableView.js b/extensions/gui/scrollview/CCTableView.js index a001a8a3b7..1c27563724 100644 --- a/extensions/gui/scrollview/CCTableView.js +++ b/extensions/gui/scrollview/CCTableView.js @@ -1,5 +1,7 @@ /**************************************************************************** - Copyright (c) 2012 cocos2d-x.org + Copyright (c) 2008-2010 Ricardo Quesada + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. Copyright (c) 2010 Sangwoo Im http://www.cocos2d-x.org @@ -41,7 +43,7 @@ cc.TABLEVIEW_FILL_BOTTOMUP = 1; * Abstract class for SWTableView cell node * @class * @abstract - * @extend cc.Node + * @extends cc.Node * * @property {Number} objectId - The index used internally by SWTableView and its subclasses */ @@ -74,13 +76,13 @@ cc.TableViewCell = cc.Node.extend(/** @lends cc.TableViewCell# */{ } }); -window._p = cc.TableViewCell.prototype; +var _p = cc.TableViewCell.prototype; /** @expose */ _p.objectId; cc.defineGetterSetter(_p, "objectId", _p.getObjectID, _p.setObjectID); -delete window._p; +_p = null; /** * Sole purpose of this delegate is to single touch event in this version. @@ -176,7 +178,7 @@ cc.TableViewDataSource = cc.Class.extend(/** @lends cc.TableViewDataSource# */{ * this is a very basic, minimal implementation to bring UITableView-like component into cocos2d world. * * @class - * @extend cc.ScrollView + * @extends cc.ScrollView * * @property {cc.TableViewDataSource} dataSource - The data source of the table view * @property {cc.TableViewDelegate} delegate - The event delegate of the table view @@ -193,10 +195,21 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ _cellsPositions:null, //vector with all cell positions _touchedCell:null, - ctor:function () { + /** + * The + * @param dataSource + * @param size + * @param container + */ + ctor:function (dataSource, size, container) { cc.ScrollView.prototype.ctor.call(this); this._oldDirection = cc.SCROLLVIEW_DIRECTION_NONE; this._cellsPositions = []; + + this.initWithViewSize(size, container); + this.setDataSource(dataSource); + this._updateCellPositions(); + this._updateContentSize(); }, __indexFromOffset:function (offset) { @@ -241,7 +254,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ locOffset.y = this.getContainer().getContentSize().height - locOffset.y; var index = this.__indexFromOffset(locOffset); - if (index != -1) { + if (index !== -1) { index = Math.max(0, index); if (index > maxIdx) index = cc.INVALID_INDEX; @@ -315,8 +328,8 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ this.setContentSize(size); - if (this._oldDirection != this._direction) { - if (this._direction == cc.SCROLLVIEW_DIRECTION_HORIZONTAL) { + if (this._oldDirection !== this._direction) { + if (this._direction === cc.SCROLLVIEW_DIRECTION_HORIZONTAL) { this.setContentOffset(cc.p(0, 0)); } else { this.setContentOffset(cc.p(0, this.minContainerOffset().y)); @@ -334,7 +347,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ cc.arrayRemoveObject(this._indices, cell.getIdx()); cell.reset(); - if (cell.getParent() == this.getContainer()) { + if (cell.getParent() === this.getContainer()) { this.getContainer().removeChild(cell, true); } }, @@ -346,12 +359,12 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ }, _addCellIfNecessary:function (cell) { - if (cell.getParent() != this.getContainer()) { + if (cell.getParent() !== this.getContainer()) { this.getContainer().addChild(cell); } this._cellsUsed.insertSortedObject(cell); var locIndices = this._indices, addIdx = cell.getIdx(); - if(locIndices.indexOf(addIdx) == -1){ + if(locIndices.indexOf(addIdx) === -1){ locIndices.push(addIdx); //sort locIndices.sort(function(a,b){return a-b;}); @@ -383,7 +396,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ * determines how cell is ordered and filled in the view. */ setVerticalFillOrder:function (fillOrder) { - if (this._vOrdering != fillOrder) { + if (this._vOrdering !== fillOrder) { this._vOrdering = fillOrder; if (this._cellsUsed.count() > 0) { this.reloadData(); @@ -415,7 +428,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ * @param idx index to find a cell */ updateCellAtIndex:function (idx) { - if (idx == cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) + if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) return; var cell = this.cellAtIndex(idx); @@ -433,7 +446,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ * @param idx location to insert */ insertCellAtIndex:function (idx) { - if (idx == cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) + if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) return; var newIdx, locCellsUsed = this._cellsUsed; @@ -461,7 +474,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ * @param idx index to find a cell */ removeCellAtIndex:function (idx) { - if (idx == cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) + if (idx === cc.INVALID_INDEX || idx > this._dataSource.numberOfCellsInTableView(this) - 1) return; var cell = this.cellAtIndex(idx); @@ -496,7 +509,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ locCellsFreed.addObject(cell); cell.reset(); - if (cell.getParent() == locContainer) + if (cell.getParent() === locContainer) locContainer.removeChild(cell, true); } @@ -532,7 +545,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ */ cellAtIndex:function (idx) { var i = this._indices.indexOf(idx); - if (i == -1) + if (i === -1) return null; return this._cellsUsed.objectWithObjectID(idx); }, @@ -543,7 +556,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ if (0 === countOfItems) return; - if (this._tableViewDelegate != null && this._tableViewDelegate.scrollViewDidScroll) + if (this._tableViewDelegate !== null && this._tableViewDelegate.scrollViewDidScroll) this._tableViewDelegate.scrollViewDidScroll(this); var idx = 0, locViewSize = this._viewSize, locContainer = this.getContainer(); @@ -598,7 +611,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ var locIndices = this._indices; for (var i = startIdx; i <= endIdx; i++) { - if (locIndices.indexOf(i) != -1) + if (locIndices.indexOf(i) !== -1) continue; this.updateCellAtIndex(i); } @@ -618,7 +631,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ bb.x = tmpOrigin.x; bb.y = tmpOrigin.y; var locTableViewDelegate = this._tableViewDelegate; - if (cc.rectContainsPoint(bb, touch.getLocation()) && locTableViewDelegate != null){ + if (cc.rectContainsPoint(bb, touch.getLocation()) && locTableViewDelegate !== null){ if(locTableViewDelegate.tableCellUnhighlight) locTableViewDelegate.tableCellUnhighlight(this, this._touchedCell); if(locTableViewDelegate.tableCellTouched) @@ -646,10 +659,10 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ else this._touchedCell = this.cellAtIndex(index); - if (this._touchedCell && this._tableViewDelegate != null && this._tableViewDelegate.tableCellHighlight) + if (this._touchedCell && this._tableViewDelegate !== null && this._tableViewDelegate.tableCellHighlight) this._tableViewDelegate.tableCellHighlight(this, this._touchedCell); } else if(this._touchedCell) { - if(this._tableViewDelegate != null && this._tableViewDelegate.tableCellUnhighlight) + if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight) this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell); this._touchedCell = null; } @@ -661,7 +674,7 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ cc.ScrollView.prototype.onTouchMoved.call(this, touch, event); if (this._touchedCell && this.isTouchMoved()) { - if(this._tableViewDelegate != null && this._tableViewDelegate.tableCellUnhighlight) + if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight) this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell); this._touchedCell = null; } @@ -671,14 +684,14 @@ cc.TableView = cc.ScrollView.extend(/** @lends cc.TableView# */{ cc.ScrollView.prototype.onTouchCancelled.call(this, touch, event); if (this._touchedCell) { - if(this._tableViewDelegate != null && this._tableViewDelegate.tableCellUnhighlight) + if(this._tableViewDelegate !== null && this._tableViewDelegate.tableCellUnhighlight) this._tableViewDelegate.tableCellUnhighlight(this, this._touchedCell); this._touchedCell = null; } } }); -window._p = cc.TableView.prototype; +var _p = cc.TableView.prototype; /** @expose */ _p.dataSource; @@ -690,21 +703,16 @@ cc.defineGetterSetter(_p, "delegate", _p.getDelegate, _p.setDelegate); _p.verticalFillOrder; cc.defineGetterSetter(_p, "verticalFillOrder", _p.getVerticalFillOrder, _p.setVerticalFillOrder); -delete window._p; +_p = null; /** * An initialized table view object - * + * @deprecated * @param {cc.TableViewDataSource} dataSource data source; * @param {cc.Size} size view size * @param {cc.Node} [container] parent object for cells * @return {cc.TableView} table view */ cc.TableView.create = function (dataSource, size, container) { - var table = new cc.TableView(); - table.initWithViewSize(size, container); - table.setDataSource(dataSource); - table._updateCellPositions(); - table._updateContentSize(); - return table; + return new cc.TableView(dataSource, size, container); }; diff --git a/extensions/pluginx/plugins/AnalyticsFlurry.js b/extensions/pluginx/plugins/AnalyticsFlurry.js deleted file mode 100755 index 6cf264ce52..0000000000 --- a/extensions/pluginx/plugins/AnalyticsFlurry.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - -Functions available from FlurryAgent v1.0.0: - -setAppVersion: function, -getFlurryAgentVersion: function, -setShowErrorInLogEnabled: function, -setDebugLogEnabled: function, -setSessionContinueSeconds: function, -setRequestInterval: function, -startSession: function, -endSession: function, -pauseSession: function, -logEvent: function, -endTimedEvent: function, -timedEvents: function, -logError: function, -logPurchase: function, -setUserId: function, -setAge: function, -setGender: function, -setLocation: function, -setEventLogging: function, -requestCallback: function - -*/ - -plugin.AnalyticsFlurry = cc.Class.extend({ - debug: false, - - /** - methods of InterfaceAnalytics protocol - */ - init: function () { - if (typeof FlurryAgent === 'undefined') { - cc.log("FlurryAgent unavailable. Please ensure that flurry.js has been pre-loaded."); - } - }, - - startSession: function(appKey){ - this.debugLog("Starting Flurry session"); - FlurryAgent.startSession(appKey); - }, - - stopSession: function(){ - this.debugLog("Ending Flurry session"); - FlurryAgent.endSession(); - }, - - setSessionContinueMillis: function(millis) { - var seconds = parseInt(millis / 1000); - this.debugLog("Setting Flurry session continue seconds to " + seconds + "s"); - FlurryAgent.setSessionContinueSeconds(seconds); - }, - - logError: function(errorId, message) { - this.debugLog("Logging Flurry error: " + errorId + ": " + message); - FlurryAgent.logError(errorId, message); - }, - - logEvent: function(eventId, params) { - this.debugLog("Logging Flurry event: " + eventId); - FlurryAgent.logEvent(eventId, params); - }, - - logTimedEventBegin: function(eventId) { - this.debugLog("Logging timed Flurry event: " + eventId); - FlurryAgent.logEvent(eventId, {}, true); - }, - - logTimedEventEnd: function(eventId) { - this.debugLog("Logging end of timed Flurry event: " + eventId); - FlurryAgent.endTimedEvent(eventId); - }, - - setCaptureUncaughtException: function(enabled) { - this.debugLog("Flurry setCaptureUncaughtException unavailable with HTML5"); - }, - - setDebugMode: function (debug) { - this.debug = (debug ? true : false); - FlurryAgent.setDebugLogEnabled(this.debug); - }, - - debugLog: function() { - if (this.debug) { - cc.log(arguments); - } - }, - - getSDKVersion: function () { - return FlurryAgent.getFlurryAgentVersion(); - }, - - getPluginVersion: function () { - return plugin.Version; - } -}); diff --git a/extensions/pluginx/plugins/SocialFacebook.js b/extensions/pluginx/plugins/SocialFacebook.js deleted file mode 100644 index a1e0aa22c1..0000000000 --- a/extensions/pluginx/plugins/SocialFacebook.js +++ /dev/null @@ -1,31 +0,0 @@ -plugin.SocialFacebook = cc.Class.extend({ - - /** - methods of protocol : InterfaceSocial - */ - init: function () { - this._shareInfo = { - 'url': window.location.href - }; - }, - configDeveloperInfo: function (cpInfo) { - //invalid on html5 - }, - share: function (shareInfo) { - var url = shareInfo["SharedURLPath"]; - if(url !== null){ - this._shareInfo.url = url; - } - - cc.openURL("http://www.facebook.com/sharer/sharer.php?u=" + url); - }, - setDebugMode: function (debug) { - //invalid on html5 - }, - getSDKVersion: function () { - return "unkown"; - }, - getPluginVersion: function () { - return plugin.Version; - } -}); \ No newline at end of file diff --git a/extensions/pluginx/plugins/SocialQQWeibo.js b/extensions/pluginx/plugins/SocialQQWeibo.js deleted file mode 100644 index b7405ddea6..0000000000 --- a/extensions/pluginx/plugins/SocialQQWeibo.js +++ /dev/null @@ -1,42 +0,0 @@ -plugin.SocialQQWeibo = cc.Class.extend({ - _shareInfo: null, - - /** - methods of protocol : InterfaceSocial - */ - init: function () { - this._shareInfo = { - 'appkey': 12345678, - 'title': "Hello, Cocos2d-html5!", - 'url': window.location.href, - 'pic': null - }; - }, - configDeveloperInfo: function (cpInfo) { - this._shareInfo.appkey = cpInfo["QQWeiboAppKey"]; - }, - share: function (shareInfo) { - this._shareInfo.title = shareInfo["SharedText"]; - this._shareInfo.pic = shareInfo["SharedImagePath"]; - - var urlstring = "", value; - for (var key in this._shareInfo) { - value = this._shareInfo[key]; - if (value !== null) { - urlstring += encodeURI(key + "=" + value) + "&"; - } - } - urlstring = urlstring.substr(0, urlstring.length - 1); - cc.openURL("http://share.v.t.qq.com/index.php?c=share&a=index&" + urlstring); - - }, - setDebugMode: function (debug) { - //invalid on html5 - }, - getSDKVersion: function () { - return "unkown"; - }, - getPluginVersion: function () { - return plugin.Version; - } -}); \ No newline at end of file diff --git a/extensions/pluginx/plugins/SocialQzone.js b/extensions/pluginx/plugins/SocialQzone.js deleted file mode 100644 index 160c4e3c97..0000000000 --- a/extensions/pluginx/plugins/SocialQzone.js +++ /dev/null @@ -1,45 +0,0 @@ -plugin.SocialQzone = cc.Class.extend({ - _shareInfo: null, - - /** - methods of protocol : InterfaceSocial - */ - init: function () { - this._shareInfo = { - 'desc': "Hello, Cocos2d-html5!", - 'url': window.location.href, - 'pics': null, - 'showcount':1 - }; - }, - configDeveloperInfo: function (cpInfo) { - //invalid on html5 - }, - share: function (shareInfo) { - this._shareInfo.desc = shareInfo["SharedText"]; - this._shareInfo.pics = shareInfo["SharedImagePath"]; - var url = shareInfo["SharedURLPath"]; - if(url !== null){ - this._shareInfo.url = url; - } - - var urlstring = "", value; - for (var key in this._shareInfo) { - value = this._shareInfo[key]; - if (value) { - urlstring += encodeURI(key + "=" + value) + "&"; - } - } - urlstring = urlstring.substr(0, urlstring.length - 1); - cc.openURL("http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?"+urlstring); - }, - setDebugMode: function (debug) { - //invalid on html5 - }, - getSDKVersion: function () { - return "unkown"; - }, - getPluginVersion: function () { - return plugin.Version; - } -}); \ No newline at end of file diff --git a/extensions/pluginx/plugins/SocialTwitter.js b/extensions/pluginx/plugins/SocialTwitter.js deleted file mode 100644 index 34c2a5af0d..0000000000 --- a/extensions/pluginx/plugins/SocialTwitter.js +++ /dev/null @@ -1,34 +0,0 @@ -plugin.SocialTwitter = cc.Class.extend({ - _shareInfo: null, - - /** - methods of protocol : InterfaceSocial - */ - init: function () { - this._shareInfo = { - 'appkey': 12345678, - 'title': "Hello, Cocos2d-html5!", - 'url': window.location.href, - 'pic': null - }; - }, - configDeveloperInfo: function (cpInfo) { - this._shareInfo.appkey = cpInfo["WeiboAppKey"]; - }, - share: function (shareInfo) { - this._shareInfo.title = shareInfo["SharedText"]; - this._shareInfo.pic = shareInfo["SharedImagePath"]; - - - cc.openURL("http://twitter.com/intent/tweet?text=" + this._shareInfo.title + " " + this._shareInfo.url); - }, - setDebugMode: function (debug) { - //invalid on html5 - }, - getSDKVersion: function () { - return "20130607"; - }, - getPluginVersion: function () { - return plugin.Version; - } -}); \ No newline at end of file diff --git a/extensions/pluginx/plugins/SocialWeibo.js b/extensions/pluginx/plugins/SocialWeibo.js deleted file mode 100644 index cfe01a2aea..0000000000 --- a/extensions/pluginx/plugins/SocialWeibo.js +++ /dev/null @@ -1,41 +0,0 @@ -plugin.SocialWeibo = cc.Class.extend({ - _shareInfo: null, - - /** - methods of protocol : InterfaceSocial - */ - init: function () { - this._shareInfo = { - 'appkey': 12345678, - 'title': "Hello, Cocos2d-html5!", - 'url': window.location.href, - 'pic': null - }; - }, - configDeveloperInfo: function (cpInfo) { - this._shareInfo.appkey = cpInfo["WeiboAppKey"]; - }, - share: function (shareInfo) { - this._shareInfo.title = shareInfo["SharedText"]; - this._shareInfo.pic = shareInfo["SharedImagePath"]; - - var urlstring = "?", value; - for (var key in this._shareInfo) { - value = this._shareInfo[key]; - if (value) { - urlstring += encodeURI(key + "=" + value) + "&"; - } - } - urlstring = urlstring.substr(0, urlstring.length - 1); - cc.openURL("http://v.t.sina.com.cn/share/share.php?" + urlstring); - }, - setDebugMode: function (debug) { - //invalid on html5 - }, - getSDKVersion: function () { - return "2.0"; - }, - getPluginVersion: function () { - return plugin.Version; - } -}); \ No newline at end of file diff --git a/extensions/pluginx/protocols/Config.js b/extensions/pluginx/protocols/Config.js deleted file mode 100644 index 94f63fc279..0000000000 --- a/extensions/pluginx/protocols/Config.js +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -/** - * @namespace - */ -var plugin = plugin || {}; - -plugin.Version = "0.2.0"; - -/** - * plugin param - * @type {Object} - */ -plugin.PluginParam = function(type, value){ - var paramType = plugin.PluginParam.ParamType,tmpValue; - switch(type){ - case paramType.TypeInt: - tmpValue = parseInt(value); - break; - case paramType.TypeFloat: - tmpValue = parseFloat(value); - break; - case paramType.TypeBool: - tmpValue = Boolean(value); - break; - case paramType.TypeString: - tmpValue = String(value); - break; - case paramType.TypeStringMap: - tmpValue = JSON.stringify(value); - break; - default: - tmpValue = value; - } - return tmpValue -}; - -plugin.PluginParam.ParamType = { - TypeInt:1, - TypeFloat:2, - TypeBool:3, - TypeString:4, - TypeStringMap:5 -}; - -plugin.PluginParam.AdsResultCode = { - AdsReceived:0, - FullScreenViewShown:1, - FullScreenViewDismissed:2, - PointsSpendSucceed:3, - PointsSpendFailed:4, - NetworkError:5, - UnknownError:6 -}; - -plugin.PluginParam.PayResultCode = { - PaySuccess:0, - PayFail:1, - PayCancel:2, - PayTimeOut:3 -}; - -plugin.PluginParam.ShareResultCode = { - ShareSuccess:0, - ShareFail:1, - ShareCancel:2, - ShareTimeOut:3 -}; diff --git a/extensions/pluginx/protocols/PluginFactory.js b/extensions/pluginx/protocols/PluginFactory.js deleted file mode 100644 index e56a4431f5..0000000000 --- a/extensions/pluginx/protocols/PluginFactory.js +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -plugin.PluginType = { - ADS:["AdSense"], - ANALYTICS:["AdsGoogle","AnalyticsFlurry"], - IAP:[""], - SOCIAL:["SocialTwitter","SocialFacebook","SocialQzone","SocialQQWeibo","SocialWeibo"] -}; - -/** - * Plugin Factory - * @extend cc.Class - * @class - */ -plugin.PluginFactory = cc.Class.extend({ - /** - * create the plugin by name - */ - createPlugin:function (name) { - if (name == null || name.length == 0) return null; - - var ret; - var obj = new plugin[name](); - obj.init(); - - switch (name) { - case plugin.PluginType.ADS[0]: - ret = new plugin.ProtocolAds(); - break; - case plugin.PluginType.ANALYTICS[0]: - case plugin.PluginType.ANALYTICS[1]: - ret = new plugin.ProtocolAnalytics(); - break; - case plugin.PluginType.IAP: - ret = new plugin.ProtocolIAP(); - break; - case plugin.PluginType.SOCIAL[0]: - case plugin.PluginType.SOCIAL[1]: - case plugin.PluginType.SOCIAL[2]: - case plugin.PluginType.SOCIAL[3]: - case plugin.PluginType.SOCIAL[4]: - ret = new plugin.ProtocolSocial(); - break; - default: - throw "Plugin " + name + " not implements a right protocol"; - - } - - if (ret !== null) { - ret.setPluginName(name); - plugin.PluginUtils.initPlugin(ret, obj, name); - } - return ret; - } -}); - -/** - * Get singleton of PluginFactory - */ -plugin.PluginFactory.getInstance = function () { - if (!this._instnace) { - this._instnace = new plugin.PluginFactory(); - } - return this._instnace; -}; - -/** - * Destory the instance of PluginFactory - */ -plugin.PluginFactory.purgeFactory = function () { - if (this._instnace) { - delete this._instnace; - } -}; diff --git a/extensions/pluginx/protocols/PluginManager.js b/extensions/pluginx/protocols/PluginManager.js deleted file mode 100644 index 5588384d9a..0000000000 --- a/extensions/pluginx/protocols/PluginManager.js +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -var plugin = plugin || {}; - -/** - * @class plugin.PluginManager - */ -plugin.PluginManager = cc.Class.extend({ - _pluginsMap:null, - - ctor:function(){ - this._pluginsMap = {}; - }, - /** - * unload the plugin by name - * @param {String} name - */ - unloadPlugin:function (name) { - if (name == null || name.length == 0) return; - if (this._pluginsMap[name]) { - delete this._pluginsMap[name]; - } - - }, - - /** - * load the plugin by name - * @param {String} name - * @return {plugin.PluginProtocol||null} - */ - loadPlugin:function (name) { - if (name == null || name.length == 0) return null; - - var tmpPlugin; - if (this._pluginsMap[name]) { - tmpPlugin = this._pluginsMap[name]; - } - else { - tmpPlugin = plugin.PluginFactory.getInstance().createPlugin(name); - this._pluginsMap[name] = tmpPlugin; - } - - return tmpPlugin; - } -}); - -/** - * Get singleton of PluginManager - * @return {plugin.PluginManager} - */ -plugin.PluginManager.getInstance = function () { - if (!this._instance) { - this._instance = new plugin.PluginManager(); - } - return this._instance; -}; - -/** - * Destory the instance of PluginManager - */ -plugin.PluginManager.end = function () { - if (this._instance != null) { - delete this._instance; - } -}; \ No newline at end of file diff --git a/extensions/pluginx/protocols/PluginProtocol.js b/extensions/pluginx/protocols/PluginProtocol.js deleted file mode 100644 index 5d3354dafd..0000000000 --- a/extensions/pluginx/protocols/PluginProtocol.js +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - - -/** - * @class PluginProtocol - */ -plugin.PluginProtocol = cc.Class.extend({ - _pluginName:null, - - setPluginName:function (name) { - this._pluginName = name; - }, - getPluginName:function () { - return this._pluginName; - }, - - /** - * plug-in info methods(name, version, SDK version) - */ - getPluginVersion:function () { - var verName; - - var data = plugin.PluginUtils.getPluginData(this); - if (data) { - var obj = data.obj; - verName = obj.getPluginVersion(); - } else { - throw "Plugin " + this.getPluginName() + " not right initilized"; - } - - return verName; - }, - - /** - * @method getSDKVersion - * @return A value converted from C/C++ "const char*" - */ - getSDKVersion:function () { - var verName; - - var data = plugin.PluginUtils.getPluginData(this); - if (data) { - var pOCObj = data.obj; - verName = pOCObj.getSDKVersion(); - } else { - throw ("Plugin "+this.getPluginName()+" not right initilized"); - } - - return verName; - }, - - /** - * switch debug plug-in on/off - * @param {Boolean} debug - */ - setDebugMode:function (debug) { - /*NSNumber* debug = [NSNumber numberWithBool:isDebugMode]; - plugin.PluginUtils.callOCFunctionWithName_oneParam(this, "setDebugMode", debug);*/ - - }, - - /** - * methods for reflections - */ - callFuncWithParam:function (funcName, param) { - }, - - callStringFuncWithParam:function (funcName, param) { - }, - - callIntFuncWithParam:function (funcName, param) { - }, - - callBoolFuncWithParam:function (funcName, param) { - }, - - callFloatFuncWithParam:function (funcName, param) { - } - -}); \ No newline at end of file diff --git a/extensions/pluginx/protocols/PluginUtils.js b/extensions/pluginx/protocols/PluginUtils.js deleted file mode 100644 index 5603d59a4a..0000000000 --- a/extensions/pluginx/protocols/PluginUtils.js +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -/** - * Open an URL address - * @function - */ -cc.openURL = function (url) { - if (this.isMobile) { - var size = cc.director.getWinSize(); - var w = size.width + "px"; - var h = size.height + "px"; - - var div = cc.$new("div"); - div.style.backgroundColor = "#ffffff"; - div.style.width = w; - div.style.height = h; - div.style.zindex = 1000; - div.style.position = 'absolute'; - div.style.top = 0 + 'px'; - div.style.left = 0 + 'px'; - div.id = "cocos2d-browser"; - - var iframe = cc.$new("iframe"); - iframe.src = url; - iframe.style.width = w; - iframe.style.height = h; - iframe.setAttribute("frameborder", "no"); - iframe.setAttribute("scrolling", "no"); - div.appendChild(iframe); - - iframe.onload = function () { - var close = document.createElement('img'); - //TODO need delete - close.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo5OERBMEM3OUQzRTMxMUUyODg2Q0RFNjU1QkU1RjlFQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo5OERBMEM3QUQzRTMxMUUyODg2Q0RFNjU1QkU1RjlFQSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjk4REEwQzc3RDNFMzExRTI4ODZDREU2NTVCRTVGOUVBIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjk4REEwQzc4RDNFMzExRTI4ODZDREU2NTVCRTVGOUVBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+NwBuoAAAA/tJREFUeNrEWF0sW3EUb6+28zFhbGadsBaNhazV+kpDYhFWKRGWbHvwFV5IvPiIFw9evElEPEiWSUgsIWoIglhmUomPxj6aKC0zKVJjtPU5o9j5J7dLdbf33jKc5Jfc3v+v5/+755x7/j1lMoiNBRDh4AO88HvO2m+ACbAC+AJQAyz2JCbBFyMBWQA/xv+3DUAXLuivudhcY4BMwCuAB+NqDPmNAnAAOsCZvQgk4BnjeiwEwAbM2YoQA14yrteQEANgDcML7gXjZgw9OAuJkADu3JAIb7Q/hr+GtCwuLs6LDq+iooLvhBAREhFEl11ZWRne0tIiIeNIpVKv4uJi4dTUVApNt0EY3ohILSIiwqO7u1sql8vD8vLyJJ2dnXH2HDabzczPz3/Y1taWzOfz78XExDxSq9Vyd3d3jMK9F2pWr6lEtLa2RmVnZ4tt7w0NDWlTU1OVtkK7urqSQ0NDzzW5hYWFjcTExAGDwXDkyD+VSkZ7e3tsWlpamP19mUwWplQqk9B1UlKST3NzczxE4K49D4mCiDwn24PyPMjIyHjs6urKIVpLSEgInp6eZsM6Kzw8nEvEMZvNBxC1BbI9KCMhkUgUy8vLRpL1QIFA4EcSyZmcnJzpS4mYnZ3dj46O7p2fn193xIGi/CeiFovlFIp5pqGhYZ5qD1qFiQxCjk1OTsqEQmEAFReloL+/X0sVAadFWE2n02VA+O+TcVZXV01QkO8ODw9P6fjEnO2zvb2936g4XC7XG4rWm65P2iL8/f05kN8nBQUFQkqnGMYcGBjIys3N5dLxjY7ydDrE6urqsNLSUqmbmxuH1tOBkMzMTIHRaNxSqVTmS4soKyvjFRUViTw9PV2dTR901WAOh7M/MjKyeeHCbGpqEhcWFkY5Wl9aWtpUKBRaONziSbsii/Xm5OTk7EIdU6/X7zpaW1xc/Al5HxkfH9/e2dk5rqmpeUrE6+vr06ADzpEIlI5kMjFwPhh5PB5DJBKdK7KDg4Oj2tpaVUdHxw/0eWxszIjyj8Jvy4N60FdVVX2Grnt4dkaowYJESAG3yaLR09Oz5uvrexwbGxuAR2erpKTkI6RqxW5DM6RnLT09PQQV5vDwsDYlJWUU+I4EIDMhEQLAA6q0DA4OrqMCg/c/qL6+XtXY2Kgn4sGJuavRaFbFYrFPeXn5FIj6ReFa64KnIpJOpaMK39vbM9XV1X13lF9kc3Nz+xMTEwZo89s03A4ycRE1N/RjF/WPKgyfDRU39Gu7w1qYyNYAtwDB1yhgGPDBfgzU4bMi7xoEjAI6iWZRdGMGH80Cr2goRlP5W8B7qwBHfw1YO6kEH4yC8EnJ5QKbnuDFh17nr4BPRP9P/BFgAHo7ZNgI9EbHAAAAAElFTkSuQmCC"; - div.appendChild(close); - close.style.zindex = 1000; - close.style.position = 'absolute'; - close.style.bottom = 10 + 'px'; - close.style.right = 10 + 'px'; - close.onclick = function () { - div.remove(); - } - }; - - var tag = document['ccConfig'].tag; - var parent = document.getElementById(tag).parentNode; - if (parent) { - parent.appendChild(div); - } - } else { - window.open(url); - } -}; - -plugin.PluginData = function (obj, className) { - this.obj = obj; - this.className = className; -}; - -plugin.PluginUtils = { - _objMap:{}, - _pluginMap:{}, - initPlugin: function (tmpPlugin, obj, className) { - var data = new plugin.PluginData(obj,className); - this.setPluginData(tmpPlugin, data); - }, - - getPluginData: function (keyObj) { - return this._objMap[keyObj._pluginName]; - }, - - setPluginData: function (plugin, data) { - this.erasePluginData(plugin); - this._objMap[data.className] = data; - this._pluginMap[data.className] = plugin; - }, - - erasePluginData: function (keyObj) { - var data = this._objMap[keyObj]; - if(data){ - var key = data.className; - - var pluginIt = this._pluginMap[key]; - if (pluginIt) - { - delete this._pluginMap[key]; - } - - delete this._objMap[keyObj] - } - }, - - getPluginPtr: function (obj) { - return this._pluginMap[obj.className]; - }, - - getObjFromParam: function (param) { - - }, - - createDictFromMap: function (paramMap) { - return paramMap; - }, - - /** - @brief method don't have return value - */ - callOCFunctionWithName_oneParam: function (tmpPlugin, funcName, param) { - - }, - callOCFunctionWithName: function (tmpPlugin, funcName) { - }, - - /** - @brief method return int value - */ - callOCIntFunctionWithName_oneParam: function (tmpPlugin, funcName, param) { - }, - callOCIntFunctionWithName: function (tmpPlugin, funcName) { - }, - - /** - @brief method return float value - */ - callOCFloatFunctionWithName_oneParam: function (tmpPlugin, funcName, param) { - }, - callOCFloatFunctionWithName: function (tmpPlugin, funcName) { - }, - - /** - @brief method return bool value - */ - callOCBoolFunctionWithName_oneParam: function (tmpPlugin, funcName, param) { - }, - callOCBoolFunctionWithName: function (tmpPlugin, funcName) { - }, - - /** - @brief method return string value - */ - callOCStringFunctionWithName_oneParam: function (tmpPlugin, funcName, param) { - }, - callOCStringFunctionWithName: function (tmpPlugin, funcName) { - }, - - callRetFunctionWithParam: function (tmpPlugin, funcName, param) { - }, - callRetFunction: function (tmpPlugin, funcName) { - } -}; \ No newline at end of file diff --git a/extensions/pluginx/protocols/ProtocolAds.js b/extensions/pluginx/protocols/ProtocolAds.js deleted file mode 100755 index 66784d00c9..0000000000 --- a/extensions/pluginx/protocols/ProtocolAds.js +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -plugin.AdsResultCode = { - AdsReceived: 0, - FullScreenViewShown: 1, - FullScreenViewDismissed: 2, - PointsSpendSucceed: 3, - PointsSpendFailed: 4, - NetworkError: 5, - UnknownError: 6 -}; - -plugin.AdsType = { - BannerAd: 0, - FullScreenAd: 1 -}; - -plugin.AdsPos = { - Center: 0, - Top: 1, - TopLeft: 2, - TopRight: 3, - Bottom: 4, - BottomLeft: 5, - BottomRight: 6 -}; - -plugin.AdsResultListener = cc.Class.extend({ - /** - @brief The advertisement request result - @param code The result code - @param msg The message - */ - onAdsResult: function (code, msg) { - }, - - /** - @brief Player get points from advertisement(For example: Tapjoy) - @param points The point number player has got. - @param pAdsPlugin The plugin which the player get points. Used to spend the points. - */ - onPlayerGetPoints: function (adsPlugin, points) { - } -}); - -/** - * @class ProtocolAds - */ -plugin.ProtocolAds = plugin.PluginProtocol.extend({ - /** - @brief config the application info - @param devInfo This parameter is the info of aplication, - different plugin have different format - @warning Must invoke this interface before other interfaces. - And invoked only once. - */ - configDeveloperInfo: function (devInfo) { - if (typeof devInfo !== 'object') { - cc.log("The devInfo is not an object for configDeveloperInfo() in " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.configDeveloperInfo(devInfo); - } - }, - - /** - @brief show adview - @param type The adview type need to show. - @param sizeEnum The size of the banner view. - (only used when type is kBannerAd) - In different plugin, it's have different mean. - Pay attention to the subclass definition - @param pos The position where the adview be shown. - (only used when type is kBannerAd) - */ - showAds: function (type, sizeEnum, pos) { - if (typeof type === 'undefined') { - cc.log("The type is empty for showAds() in " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.showAds(type, sizeEnum, pos); - } - }, - - /** - @brief Hide the adview - @param type The adview type need to hide. - */ - hideAds: function (type) { - plugin.PluginUtils.getPluginData(this).obj.hideAds(type); - }, - - /** - @brief Spend the points. - Use this method to notify server spend points. - @param points Need spend number of points - */ - spendPoints: function (points) { - if (typeof points === 'undefined') { - cc.log("Points is empty for spendPoints() in " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.spendPoints(points); - } - }, - - /** - @brief set the Ads listener - @param An instance of plugin.AdsResultListener - */ - setAdsListener: function (listener) { - if (typeof listener === 'undefined') { - cc.log("Listener is empty for setAdsListener() in " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.setAdsListener(listener); - } - }, - - /** - @brief set debug mode - @param enabled - */ - setDebugMode:function(enabled){ - plugin.PluginUtils.getPluginData(this).obj.setDebugMode(enabled ? true : false); - } -}); - diff --git a/extensions/pluginx/protocols/ProtocolAnalytics.js b/extensions/pluginx/protocols/ProtocolAnalytics.js deleted file mode 100755 index 1499dc1e66..0000000000 --- a/extensions/pluginx/protocols/ProtocolAnalytics.js +++ /dev/null @@ -1,132 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -/** - * @class ProtocolAnalytics - */ -plugin.ProtocolAnalytics = plugin.PluginProtocol.extend({ - - /** - * start analytics session - * @param {String} appKey - */ - startSession: function(appKey){ - if (typeof appKey !== 'string' || appKey.length === 0) { - cc.log("The app key is empty for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.startSession(appKey); - } - }, - - /** - @brief Stop a session. - @warning This interface only worked on android - */ - stopSession: function(){ - plugin.PluginUtils.getPluginData(this).obj.stopSession(); - }, - - /** - @brief Set the timeout for expiring a session. - @param millis In milliseconds as the unit of time. - */ - setSessionContinueMillis: function(millis) { - if (typeof millis !== 'number') { - cc.log("The parameter milliseconds is not a number for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.setSessionContinueMillis(millis); - } - }, - - /** - @brief log an error - @param errorId The identity of error - @param message Extern message for the error - */ - logError: function(errorId, message) { - if (typeof errorId === 'undefined' || typeof message === 'undefined') { - cc.log("The errorId or message is empty for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.logError(errorId, message); - } - }, - - /** - @brief log an event. - @param eventId The identity of event - @param paramMap Extern parameters of the event, use NULL if not needed. - */ - logEvent: function(eventId, params) { - if (typeof eventId === 'undefined') { - cc.log("The eventId is empty for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.logEvent(eventId, params); - } - }, - - /** - @brief Track an event begin. - @param eventId The identity of event - */ - logTimedEventBegin: function(eventId) { - if (typeof eventId === 'undefined') { - cc.log("The eventId is empty for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.logTimedEventBegin(eventId); - } - }, - - /** - @brief Track an event end. - @param eventId The identity of event - */ - logTimedEventEnd: function(eventId) { - if (typeof eventId === 'undefined') { - cc.log("The eventId is empty for " + this.getPluginName()); - } - else { - plugin.PluginUtils.getPluginData(this).obj.logTimedEventEnd(eventId); - } - }, - - /** - @brief Whether to catch uncaught exceptions to server. - */ - setCaptureUncaughtException: function(enabled) { - plugin.PluginUtils.getPluginData(this).obj.setCaptureUncaughtException(enabled); - }, - - /** - @brief Sets debug mode - @param enabled Boolean - */ - setDebugMode: function(enabled) { - plugin.PluginUtils.getPluginData(this).obj.setDebugMode(enabled); - } -}); diff --git a/extensions/pluginx/protocols/ProtocolSocial.js b/extensions/pluginx/protocols/ProtocolSocial.js deleted file mode 100644 index 1de0d75bea..0000000000 --- a/extensions/pluginx/protocols/ProtocolSocial.js +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** - Copyright (c) 2012+2013 cocos2d-x.org - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -plugin.ShareResultCode = { - Success: 0, - Fail: 1, - Cancel: 2, - TimeOut: 3 -}; - -plugin.ShareResultListener = cc.Class.extend({ - onShareResult: function (ret, msg) { - - } -}); - -/** - * @class ProtocolSocial - */ -plugin.ProtocolSocial = plugin.PluginProtocol.extend({ - - /** - * share result callback - * @param {Number} ret - * @param {String} msg - */ - onShareResult: function (ret, msg) { - if (this._listener) { - this._listener.onShareResult(ret, msg); - } - else { - cc.log("Share result listener of " + this.getPluginName() + " is null!"); - } - cc.log("Share result of " + this.getPluginName() + " is : " + ret + msg); - }, - - /** - * set the result listener - * @param {Function} listener The callback object for share result - */ - setResultListener: function (listener) { - this._listener = listener; - }, - - /** - * share information - * @param {Object} info The info of share, contains key: - * SharedText The text need to share - * SharedImagePath The full path of image file need to share (optinal) - * SharedURL url of the site - */ - share: function (info) { - if (Object.keys(info).length == 0) { - if (null != this._listener) { - this.onShareResult(plugin.ShareResultCode.Fail, "Share info error"); - } - cc.log("The Share info of " + this.getPluginName() + " is empty!"); - } - else { - var data = plugin.PluginUtils.getPluginData(this); - var obj = data.obj; - obj.share(info); - } - }, - - /** - * config the social developer info - * @param {Object} devInfo This parameter is the info of developer,different plugin have different format - */ - configDeveloperInfo: function (devInfo) { - if (Object.keys(devInfo).length == 0) { - cc.log("The developer info is empty for " + this.getPluginName()); - } - else { - var data = plugin.PluginUtils.getPluginData(this); - var obj = data.obj; - obj.configDeveloperInfo(devInfo); - } - }, - - setDebugMode:function(value){ - //invalid on html5 - } -}); diff --git a/extensions/pluginx/samples/HelloSocial/cocos2d.js b/extensions/pluginx/samples/HelloSocial/cocos2d.js deleted file mode 100644 index 85c3c6ac25..0000000000 --- a/extensions/pluginx/samples/HelloSocial/cocos2d.js +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ -(function () { - var d = document; - var c = { - COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug - box2d:false, - chipmunk:false, - showFPS:true, - loadExtension:false, - loadPluginx:true, - frameRate:60, - tag:'gameCanvas', //the dom element to run cocos2d on - engineDir:'../../../../cocos2d/', - //SingleEngineFile:'', - appFiles:[ - 'src/resource.js', - 'src/MySocialManager.js', - 'src/myApp.js'//add your own files in order here - ] - }; - - if(!d.createElement('canvas').getContext){ - var s = d.createElement('div'); - s.innerHTML = '

    Your browser does not support HTML5 canvas!

    ' + - '

    Google Chrome is a browser that combines a minimal design with sophisticated technology to make the web faster, safer, and easier.Click the logo to download.

    ' + - '
    '; - var p = d.getElementById(c.tag).parentNode; - p.style.background = 'none'; - p.style.border = 'none'; - p.insertBefore(s); - - d.body.style.background = '#ffffff'; - return; - } - - var fn; - window.addEventListener('DOMContentLoaded', fn = function() { - this.removeEventListener('DOMContentLoaded', fn, false); - //first load engine file if specified - var s = d.createElement('script'); - /*********Delete this section if you have packed all files into one*******/ - if (c.SingleEngineFile && !c.engineDir) { - s.src = c.SingleEngineFile; - } - else if (c.engineDir && !c.SingleEngineFile) { - s.src = c.engineDir + 'jsloader.js'; - } - else { - alert('You must specify either the single engine file OR the engine directory in "cocos2d.js"'); - } - /*********Delete this section if you have packed all files into one*******/ - - //s.src = 'myTemplate.js'; //IMPORTANT: Un-comment this line if you have packed all files into one - - d.body.appendChild(s); - document.ccConfig = c; - s.id = 'cocos2d-html5'; - //else if single file specified, load singlefile - }); -})(); diff --git a/extensions/pluginx/samples/HelloSocial/index.html b/extensions/pluginx/samples/HelloSocial/index.html deleted file mode 100644 index 6b4cece82c..0000000000 --- a/extensions/pluginx/samples/HelloSocial/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - Cocos2d-html5 Hello World test - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/extensions/pluginx/samples/HelloSocial/res/CloseNormal.png b/extensions/pluginx/samples/HelloSocial/res/CloseNormal.png deleted file mode 100755 index 8ff9369dc9..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/CloseNormal.png and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/CloseSelected.png b/extensions/pluginx/samples/HelloSocial/res/CloseSelected.png deleted file mode 100755 index f75c4179a5..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/CloseSelected.png and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/background.png b/extensions/pluginx/samples/HelloSocial/res/background.png deleted file mode 100755 index b2e4ae6ce8..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/background.png and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/facebook.gif b/extensions/pluginx/samples/HelloSocial/res/facebook.gif deleted file mode 100644 index 2e622c197d..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/facebook.gif and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/qqweibo.gif b/extensions/pluginx/samples/HelloSocial/res/qqweibo.gif deleted file mode 100644 index bf50564745..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/qqweibo.gif and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/qzone.gif b/extensions/pluginx/samples/HelloSocial/res/qzone.gif deleted file mode 100644 index 2b44da927b..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/qzone.gif and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/snweibo.gif b/extensions/pluginx/samples/HelloSocial/res/snweibo.gif deleted file mode 100644 index b6f19eabbb..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/snweibo.gif and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/res/twitter.gif b/extensions/pluginx/samples/HelloSocial/res/twitter.gif deleted file mode 100644 index 72b0f30838..0000000000 Binary files a/extensions/pluginx/samples/HelloSocial/res/twitter.gif and /dev/null differ diff --git a/extensions/pluginx/samples/HelloSocial/src/MySocialManager.js b/extensions/pluginx/samples/HelloSocial/src/MySocialManager.js deleted file mode 100644 index 44ef5c6c71..0000000000 --- a/extensions/pluginx/samples/HelloSocial/src/MySocialManager.js +++ /dev/null @@ -1,120 +0,0 @@ -var MyShareMode = { - NoneMode:0, - SNWeibo:1, - QQWeibo:2, - QZone:3, - Twitter:4, - Facebook:5 -}; - - -var MyShareResult = plugin.ShareResultListener.extend({ - onShareResult: function (ret, msg) { - var shareStatus = "Share " + (ret == plugin.ShareResultCode.Success) ? " Successed" : " Failed"; - cc.log(msg + shareStatus); - } -}); - -var MySocialManager = cc.Class.extend({ - _twitter:null, - _snweibo:null, - _qqweibo:null, - _qzone:null, - _facebook:null, - _listener:null, - ctor:function () { - window.test = this; - }, - unloadSocialPlugin:function () { - if (this._twitter) { - plugin.PluginManager.getInstance().unloadPlugin("SocialTwitter"); - this._twitter = null; - } - - if (this._weibo) { - plugin.PluginManager.getInstance().unloadPlugin("SocialWeibo"); - this._weibo = null; - } - }, - loadSocialPlugin:function () { - if (this._listener == null) { - this._listener = new MyShareResult(); - } - - this._snweibo = plugin.PluginManager.getInstance().loadPlugin("SocialWeibo"); - if (this._snweibo) { - var weiboInfo = {}; - weiboInfo["WeiboAppKey"] = "3787440247"; - - if (Object.keys(weiboInfo).length == 0) { - cc.log("Developer info is empty. PLZ fill your weibo info in weiboInfo"); - } - - this._snweibo.setDebugMode(true); - this._snweibo.configDeveloperInfo(weiboInfo); - this._snweibo.setResultListener(this._listener); - } - - this._qqweibo = plugin.PluginManager.getInstance().loadPlugin("SocialQQWeibo"); - if (this._qqweibo) { - var qqweiboInfo = {}; - qqweiboInfo["QQWeiboAppKey"] = "b3410a01f51da238afdc92ea6e2c267a"; - - if (Object.keys(qqweiboInfo).length == 0) { - cc.log("Developer info is empty. PLZ fill your weibo info in qqweiboInfo"); - } - - this._qqweibo.setDebugMode(true); - this._qqweibo.configDeveloperInfo(qqweiboInfo); - this._qqweibo.setResultListener(this._listener); - } - - this._qzone = plugin.PluginManager.getInstance().loadPlugin("SocialQzone"); - this._twitter = plugin.PluginManager.getInstance().loadPlugin("SocialTwitter"); - this._facebook = plugin.PluginManager.getInstance().loadPlugin("SocialFacebook"); - - window.test = this; - - }, - shareByMode:function (info, mode) { - var share = null; - switch (mode) { - case MyShareMode.SNWeibo: - share = this._snweibo; - break; - case MyShareMode.QQWeibo: - share = this._qqweibo; - break; - case MyShareMode.QZone: - share = this._qzone; - break; - case MyShareMode.Twitter: - share = this._twitter; - break; - case MyShareMode.Facebook: - share = this._facebook; - break; - default: - break; - } - - - if (share) { - share.share(info); - } - } -}); - -MySocialManager.getInstance = function () { - if (!this._instance) { - this._instance = new MySocialManager(); - } - return this._instance; -}; - -MySocialManager.purgeManager = function () { - if (this._instance) { - this._instance = null; - delete this._instance; - } -}; \ No newline at end of file diff --git a/extensions/pluginx/samples/HelloSocial/src/myApp.js b/extensions/pluginx/samples/HelloSocial/src/myApp.js deleted file mode 100644 index 80ce026207..0000000000 --- a/extensions/pluginx/samples/HelloSocial/src/myApp.js +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - -var TAG_SHARE_BY_SNWEIBO = 100; -var TAG_SHARE_BY_QQWEIBO = 101; -var TAG_SHARE_BY_QZONE = 102; -var TAG_SHARE_BY_TWWITER = 103; -var TAG_SHARE_BY_FACEBOOK = 104; - -var EventMenuItem = function (id, tag) { - this.id = id; - this.tag = tag; -}; - -var s_EventMenuItem = [ - new EventMenuItem(s_snweibo, TAG_SHARE_BY_SNWEIBO), - new EventMenuItem(s_qqweibo, TAG_SHARE_BY_QQWEIBO), - new EventMenuItem(s_qzone, TAG_SHARE_BY_QZONE), - new EventMenuItem(s_twitter, TAG_SHARE_BY_TWWITER), - new EventMenuItem(s_facebook, TAG_SHARE_BY_FACEBOOK) -]; - -var MyLayer = cc.Layer.extend({ - init: function () { - this._super(); - - - var size = cc.director.getVisibleSize(); - - var bg = cc.Sprite.create(s_Background); - bg.x = size.width / 2; - bg.y = size.height / 2; - this.addChild(bg); - - var eglView = cc.view; - var posBR = cc.p(eglView.getVisibleOrigin().x + eglView.getVisibleSize().width, eglView.getVisibleOrigin().y); - var posBC = cc.p(eglView.getVisibleOrigin().x + eglView.getVisibleSize().width / 2, eglView.getVisibleOrigin().y); - var posTL = cc.p(eglView.getVisibleOrigin().x, eglView.getVisibleOrigin().y + eglView.getVisibleSize().height); - - var closeItem = cc.MenuItemImage.create( - s_CloseNormal, - s_CloseSelected, - this.menuCloseCallback, - this); - closeItem.x = posBR.x - 20; - closeItem.y = posBR.y + 20; - - // create menu, it's an autorelease object - var pMenu = cc.Menu.create(closeItem); - pMenu.x = 0; - pMenu.y = 0; - this.addChild(pMenu, 1); - - var posStep = cc.p(150, -150); - var beginPos = cc.pAdd(posTL, cc.pMult(posStep, 0.5)); - var line = 0; - var row = 0; - for (var i = 0; i < s_EventMenuItem.length; i++) { - var menuItem = cc.MenuItemImage.create(s_EventMenuItem[i].id, s_EventMenuItem[i].id, - this.eventMenuCallback, this); - pMenu.addChild(menuItem, 0, s_EventMenuItem[i].tag); - - var pos = cc.pAdd(beginPos, cc.p(posStep.x * row, posStep.y * line)); - var itemSize = menuItem.getContentSize(); - if ((pos.x + itemSize.width / 2) > posBR.x) { - line += 1; - row = 0; - pos = cc.pAdd(beginPos, cc.p(posStep.x * row, posStep.y * line)); - } - row += 1; - menuItem.x = pos.x; - menuItem.y = pos.y; - } - - var label = cc.LabelTTF.create("Reload all plugins", "Arial", 24); - var menuItem = cc.MenuItemLabel.create(label, this.reloadPluginMenuCallback, this); - menuItem.setAnchorPoint(0.5, 0); - pMenu.addChild(menuItem, 0); - menuItem.x = posBC.x; - menuItem.y = posBC.y; - }, - //a selector callback - menuCloseCallback: function (sender) { - MySocialManager.getInstance().unloadSocialPlugin(); - MySocialManager.getInstance().loadSocialPlugin(); - }, - eventMenuCallback: function (sender) { - var info = {}; - info["SharedText"] = "Share message : HelloSocial!"; - info["SharedImagePath"] = "http://www.cocos2d-x.org/images/banner-left.png"; - info["SharedURLPath"] = "http://www.cocos2d-x.org"; - - var mode = sender.getTag() - TAG_SHARE_BY_SNWEIBO + 1; - MySocialManager.getInstance().shareByMode(info, mode); - }, - reloadPluginMenuCallback: function (sender) { - MySocialManager.purgeManager(); - } -}); - -var MyScene = cc.Scene.extend({ - onEnter: function () { - this._super(); - var layer = new MyLayer(); - this.addChild(layer); - layer.init(); - } -}); diff --git a/extensions/pluginx/samples/HelloSocial/src/resource.js b/extensions/pluginx/samples/HelloSocial/src/resource.js deleted file mode 100644 index e2b1500aa3..0000000000 --- a/extensions/pluginx/samples/HelloSocial/src/resource.js +++ /dev/null @@ -1,19 +0,0 @@ -var s_CloseNormal = "res/CloseNormal.png"; -var s_CloseSelected = "res/CloseSelected.png"; -var s_Background = "res/Background.png"; -var s_qzone = "res/qzone.gif"; -var s_snweibo = "res/snweibo.gif"; -var s_qqweibo = "res/qqweibo.gif"; -var s_facebook = "res/facebook.gif"; -var s_twitter = "res/twitter.gif"; - -var g_ressources = [ - {src:s_CloseNormal}, - {src:s_CloseSelected}, - {src:s_Background}, - {src:s_qzone}, - {src:s_facebook}, - {src:s_twitter}, - {src:s_qqweibo}, - {src:s_snweibo} -]; \ No newline at end of file diff --git a/extensions/spine/CCSkeleton.js b/extensions/spine/CCSkeleton.js new file mode 100644 index 0000000000..27e1ac1763 --- /dev/null +++ b/extensions/spine/CCSkeleton.js @@ -0,0 +1,407 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2014 Shengxiang Chen (Nero Chan) + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * The main namespace of Spine, all classes, functions, properties and constants of Spine are defined in this namespace + * @namespace + * @name sp + */ +var sp = sp || {}; + +/** + * The vertex index of spine. + * @constant + * @type {{X1: number, Y1: number, X2: number, Y2: number, X3: number, Y3: number, X4: number, Y4: number}} + */ +sp.VERTEX_INDEX = { + X1: 0, + Y1: 1, + X2: 2, + Y2: 3, + X3: 4, + Y3: 5, + X4: 6, + Y4: 7 +}; + +/** + * The attachment type of spine. It contains three type: REGION(0), BOUNDING_BOX(1), MESH(2) and SKINNED_MESH. + * @constant + * @type {{REGION: number, BOUNDING_BOX: number, REGION_SEQUENCE: number, MESH: number}} + */ +sp.ATTACHMENT_TYPE = { + REGION: 0, + BOUNDING_BOX: 1, + MESH: 2, + SKINNED_MESH:3 +}; + +/** + *

    + * The skeleton of Spine.
    + * Skeleton has a reference to a SkeletonData and stores the state for skeleton instance, + * which consists of the current pose's bone SRT, slot colors, and which slot attachments are visible.
    + * Multiple skeletons can use the same SkeletonData (which includes all animations, skins, and attachments).
    + *

    + * @class + * @extends cc.Node + */ +sp.Skeleton = cc.Node.extend(/** @lends sp.Skeleton# */{ + _skeleton: null, + _rootBone: null, + _timeScale: 1, + _debugSlots: false, + _debugBones: false, + _premultipliedAlpha: false, + _ownsSkeletonData: null, + _atlas: null, + _blendFunc: null, + + /** + * The constructor of sp.Skeleton. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. + */ + ctor:function(skeletonDataFile, atlasFile, scale){ + cc.Node.prototype.ctor.call(this); + this._blendFunc = {src: cc.BLEND_SRC, dst: cc.BLEND_DST}; + + if(arguments.length === 0) + this.init(); + else + this.initWithArgs(skeletonDataFile, atlasFile, scale); + }, + + _createRenderCmd:function () { + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new sp.Skeleton.CanvasRenderCmd(this); + else + return new sp.Skeleton.WebGLRenderCmd(this); + }, + + /** + * Initializes a sp.Skeleton. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + */ + init: function () { + cc.Node.prototype.init.call(this); + //this.setOpacityModifyRGB(true); + this._blendFunc.src = cc.ONE; + this._blendFunc.dst = cc.ONE_MINUS_SRC_ALPHA; + this.scheduleUpdate(); + }, + + /** + * Sets whether open debug slots. + * @param {boolean} enable true to open, false to close. + */ + setDebugSolots:function(enable){ + this._debugSlots = enable; + }, + + /** + * Sets whether open debug bones. + * @param {boolean} enable + */ + setDebugBones:function(enable){ + this._debugBones = enable; + }, + + /** + * Sets whether open debug slots. + * @param {boolean} enabled true to open, false to close. + */ + setDebugSlotsEnabled: function(enabled) { + this._debugSlots = enabled; + }, + + /** + * Gets whether open debug slots. + * @returns {boolean} true to open, false to close. + */ + getDebugSlotsEnabled: function() { + return this._debugSlots; + }, + + /** + * Sets whether open debug bones. + * @param {boolean} enabled + */ + setDebugBonesEnabled: function(enabled) { + this._debugBones = enabled; + }, + + /** + * Gets whether open debug bones. + * @returns {boolean} true to open, false to close. + */ + getDebugBonesEnabled: function() { + return this._debugBones; + }, + + /** + * Sets the time scale of sp.Skeleton. + * @param {Number} scale + */ + setTimeScale:function(scale){ + this._timeScale = scale; + }, + + getTimeScale: function(){ + return this._timeScale; + }, + + /** + * Initializes sp.Skeleton with Data. + * @param {spine.SkeletonData|String} skeletonDataFile + * @param {String|spine.Atlas|spine.SkeletonData} atlasFile atlas filename or atlas data or owns SkeletonData + * @param {Number} [scale] scale can be specified on the JSON or binary loader which will scale the bone positions, image sizes, and animation translations. + */ + initWithArgs: function (skeletonDataFile, atlasFile, scale) { + var argSkeletonFile = skeletonDataFile, argAtlasFile = atlasFile, + skeletonData, atlas, ownsSkeletonData; + + if (cc.isString(argSkeletonFile)) { + if (cc.isString(argAtlasFile)) { + var data = cc.loader.getRes(argAtlasFile); + sp._atlasLoader.setAtlasFile(argAtlasFile); + atlas = new spine.Atlas(data, sp._atlasLoader); + } else { + atlas = atlasFile; + } + scale = scale || 1 / cc.director.getContentScaleFactor(); + + var attachmentLoader = new spine.AtlasAttachmentLoader(atlas); + var skeletonJsonReader = new spine.SkeletonJson(attachmentLoader); + skeletonJsonReader.scale = scale; + + var skeletonJson = cc.loader.getRes(argSkeletonFile); + skeletonData = skeletonJsonReader.readSkeletonData(skeletonJson); + atlas.dispose(skeletonJsonReader); + ownsSkeletonData = true; + } else { + skeletonData = skeletonDataFile; + ownsSkeletonData = atlasFile; + } + this.setSkeletonData(skeletonData, ownsSkeletonData); + this.init(); + }, + + /** + * Returns the bounding box of sp.Skeleton. + * @returns {cc.Rect} + */ + getBoundingBox: function () { + var minX = cc.FLT_MAX, minY = cc.FLT_MAX, maxX = cc.FLT_MIN, maxY = cc.FLT_MIN; + var scaleX = this.getScaleX(), scaleY = this.getScaleY(), vertices = [], + slots = this._skeleton.slots, VERTEX = sp.VERTEX_INDEX; + + for (var i = 0, slotCount = slots.length; i < slotCount; ++i) { + var slot = slots[i]; + if (!slot.attachment || slot.attachment.type != sp.ATTACHMENT_TYPE.REGION) + continue; + var attachment = slot.attachment; + this._computeRegionAttachmentWorldVertices(attachment, slot.bone.skeleton.x, slot.bone.skeleton.y, slot.bone, vertices); + minX = Math.min(minX, vertices[VERTEX.X1] * scaleX, vertices[VERTEX.X4] * scaleX, vertices[VERTEX.X2] * scaleX, vertices[VERTEX.X3] * scaleX); + minY = Math.min(minY, vertices[VERTEX.Y1] * scaleY, vertices[VERTEX.Y4] * scaleY, vertices[VERTEX.Y2] * scaleY, vertices[VERTEX.Y3] * scaleY); + maxX = Math.max(maxX, vertices[VERTEX.X1] * scaleX, vertices[VERTEX.X4] * scaleX, vertices[VERTEX.X2] * scaleX, vertices[VERTEX.X3] * scaleX); + maxY = Math.max(maxY, vertices[VERTEX.Y1] * scaleY, vertices[VERTEX.Y4] * scaleY, vertices[VERTEX.Y2] * scaleY, vertices[VERTEX.Y3] * scaleY); + } + var position = this.getPosition(); + return cc.rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY); + }, + + _computeRegionAttachmentWorldVertices : function(self, x, y, bone, vertices){ + var offset = self.offset, vertexIndex = sp.VERTEX_INDEX; + x += bone.worldX; + y += bone.worldY; + vertices[vertexIndex.X1] = offset[vertexIndex.X1] * bone.m00 + offset[vertexIndex.Y1] * bone.m01 + x; + vertices[vertexIndex.Y1] = offset[vertexIndex.X1] * bone.m10 + offset[vertexIndex.Y1] * bone.m11 + y; + vertices[vertexIndex.X2] = offset[vertexIndex.X2] * bone.m00 + offset[vertexIndex.Y2] * bone.m01 + x; + vertices[vertexIndex.Y2] = offset[vertexIndex.X2] * bone.m10 + offset[vertexIndex.Y2] * bone.m11 + y; + vertices[vertexIndex.X3] = offset[vertexIndex.X3] * bone.m00 + offset[vertexIndex.Y3] * bone.m01 + x; + vertices[vertexIndex.Y3] = offset[vertexIndex.X3] * bone.m10 + offset[vertexIndex.Y3] * bone.m11 + y; + vertices[vertexIndex.X4] = offset[vertexIndex.X4] * bone.m00 + offset[vertexIndex.Y4] * bone.m01 + x; + vertices[vertexIndex.Y4] = offset[vertexIndex.X4] * bone.m10 + offset[vertexIndex.Y4] * bone.m11 + y; + }, + + /** + * Computes the world SRT from the local SRT for each bone. + */ + updateWorldTransform: function () { + this._skeleton.updateWorldTransform(); + }, + + /** + * Sets the bones and slots to the setup pose. + */ + setToSetupPose: function () { + this._skeleton.setToSetupPose(); + }, + + /** + * Sets the bones to the setup pose, using the values from the `BoneData` list in the `SkeletonData`. + */ + setBonesToSetupPose: function () { + this._skeleton.setBonesToSetupPose(); + }, + + /** + * Sets the slots to the setup pose, using the values from the `SlotData` list in the `SkeletonData`. + */ + setSlotsToSetupPose: function () { + this._skeleton.setSlotsToSetupPose(); + }, + + /** + * Finds a bone by name. This does a string comparison for every bone. + * @param {String} boneName + * @returns {spine.Bone} + */ + findBone: function (boneName) { + return this._skeleton.findBone(boneName); + }, + + /** + * Finds a slot by name. This does a string comparison for every slot. + * @param {String} slotName + * @returns {spine.Slot} + */ + findSlot: function (slotName) { + return this._skeleton.findSlot(slotName); + }, + + /** + * Finds a skin by name and makes it the active skin. This does a string comparison for every skin. Note that setting the skin does not change which attachments are visible. + * @param {string} skinName + * @returns {spine.Skin} + */ + setSkin: function (skinName) { + return this._skeleton.setSkinByName(skinName); + }, + + /** + * Returns the attachment for the slot and attachment name. The skeleton looks first in its skin, then in the skeleton data’s default skin. + * @param {String} slotName + * @param {String} attachmentName + * @returns {spine.RegionAttachment|spine.BoundingBoxAttachment} + */ + getAttachment: function (slotName, attachmentName) { + return this._skeleton.getAttachmentBySlotName(slotName, attachmentName); + }, + + /** + * Sets the attachment for the slot and attachment name. The skeleton looks first in its skin, then in the skeleton data’s default skin. + * @param {String} slotName + * @param {String} attachmentName + */ + setAttachment: function (slotName, attachmentName) { + this._skeleton.setAttachment(slotName, attachmentName); + }, + + /** + * Sets the premultiplied alpha value to sp.Skeleton. + * @param {Number} alpha + */ + setOpacityModifyRGB: function (alpha) { + this._premultipliedAlpha = alpha; + }, + + /** + * Returns whether to enable premultiplied alpha. + * @returns {boolean} + */ + isOpacityModifyRGB: function () { + return this._premultipliedAlpha; + }, + + /** + * Sets skeleton data to sp.Skeleton. + * @param {spine.SkeletonData} skeletonData + * @param {spine.SkeletonData} ownsSkeletonData + */ + setSkeletonData: function (skeletonData, ownsSkeletonData) { + if(skeletonData.width != null && skeletonData.height != null) + this.setContentSize(skeletonData.width / cc.director.getContentScaleFactor(), skeletonData.height / cc.director.getContentScaleFactor()); + + this._skeleton = new spine.Skeleton(skeletonData); + this._skeleton.updateWorldTransform(); + this._rootBone = this._skeleton.getRootBone(); + this._ownsSkeletonData = ownsSkeletonData; + + this._renderCmd._createChildFormSkeletonData(); + }, + + /** + * Return the renderer of attachment. + * @param {spine.RegionAttachment|spine.BoundingBoxAttachment} regionAttachment + * @returns {cc.Node} + */ + getTextureAtlas: function (regionAttachment) { + return regionAttachment.rendererObject.page.rendererObject; + }, + + /** + * Returns the blendFunc of sp.Skeleton. + * @returns {cc.BlendFunc} + */ + getBlendFunc: function () { + return this._blendFunc; + }, + + /** + * Sets the blendFunc of sp.Skeleton. + * @param {cc.BlendFunc|Number} src + * @param {Number} [dst] + */ + setBlendFunc: function (src, dst) { + var locBlendFunc = this._blendFunc; + if (dst === undefined) { + locBlendFunc.src = src.src; + locBlendFunc.dst = src.dst; + } else { + locBlendFunc.src = src; + locBlendFunc.dst = dst; + } + }, + + /** + * Update will be called automatically every frame if "scheduleUpdate" is called when the node is "live". + * @param {Number} dt Delta time since last update + */ + update: function (dt) { + this._skeleton.update(dt); + } +}); + +/** + * Creates a skeleton object. + * @deprecated since v3.0, please use new sp.Skeleton(skeletonDataFile, atlasFile, scale) instead. + * @param {spine.SkeletonData|String} skeletonDataFile + * @param {String|spine.Atlas|spine.SkeletonData} atlasFile atlas filename or atlas data or owns SkeletonData + * @param {Number} [scale] scale can be specified on the JSON or binary loader which will scale the bone positions, image sizes, and animation translations. + * @returns {sp.Skeleton} + */ +sp.Skeleton.create = function (skeletonDataFile, atlasFile/* or atlas*/, scale) { + return new sp.Skeleton(skeletonDataFile, atlasFile, scale); +}; \ No newline at end of file diff --git a/extensions/spine/CCSkeletonAnimation.js b/extensions/spine/CCSkeletonAnimation.js new file mode 100644 index 0000000000..f351d83c80 --- /dev/null +++ b/extensions/spine/CCSkeletonAnimation.js @@ -0,0 +1,348 @@ +/**************************************************************************** + Copyright (c) 2011-2012 cocos2d-x.org + Copyright (c) 2013-2014 Chukong Technologies Inc. + Copyright (c) 2014 Shengxiang Chen (Nero Chan) + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * @ignore + */ +sp._atlasPage_createTexture_webGL = function (self, path) { + var texture = cc.textureCache.addImage(path); + self.rendererObject = new cc.TextureAtlas(texture, 128); + self.width = texture.getPixelsWide(); + self.height = texture.getPixelsHigh(); +}; + +sp._atlasPage_createTexture_canvas = function(self, path) { + self._texture = cc.textureCache.addImage(path); +}; + +sp._atlasPage_disposeTexture = function (self) { + self.rendererObject.release(); +}; + +sp._atlasLoader = { + spAtlasFile:null, + setAtlasFile:function(spAtlasFile){ + this.spAtlasFile = spAtlasFile; + }, + load:function(page, line, spAtlas){ + var texturePath = cc.path.join(cc.path.dirname(this.spAtlasFile), line); + if (cc._renderType === cc._RENDER_TYPE_WEBGL) + sp._atlasPage_createTexture_webGL(page,texturePath); + else + sp._atlasPage_createTexture_canvas(page,texturePath); + }, + unload:function(obj){ + } +}; + +/** + * The event type of spine skeleton animation. It contains event types: START(0), END(1), COMPLETE(2), EVENT(3). + * @constant + * @type {{START: number, END: number, COMPLETE: number, EVENT: number}} + */ +sp.ANIMATION_EVENT_TYPE = { + START: 0, + END: 1, + COMPLETE: 2, + EVENT: 3 +}; + +sp.TrackEntryListeners = function(startListener, endListener, completeListener, eventListener){ + this.startListener = startListener || null; + this.endListener = endListener || null; + this.completeListener = completeListener || null; + this.eventListener = eventListener || null; +}; + +sp.TrackEntryListeners.getListeners = function(entry){ + if(!entry.rendererObject){ + entry.rendererObject = new sp.TrackEntryListeners(); + entry.listener = sp.trackEntryCallback; + } + return entry.rendererObject; +}; + +sp.trackEntryCallback = function(state, trackIndex, type, event, loopCount) { + state.rendererObject.onTrackEntryEvent(trackIndex, type, event, loopCount); +}; + +/** + * The skeleton animation of spine. It updates animation's state and skeleton's world transform. + * @class + * @extends sp.Skeleton + * @example + * var spineBoy = new sp.SkeletonAnimation('res/skeletons/spineboy.json', 'res/skeletons/spineboy.atlas'); + * this.addChild(spineBoy, 4); + */ +sp.SkeletonAnimation = sp.Skeleton.extend(/** @lends sp.SkeletonAnimation# */{ + _state: null, + _target: null, + _callback: null, + + _ownsAnimationStateData: false, + _startListener: null, + _endListener: null, + _completeListener: null, + _eventListener: null, + + /** + * Initializes a sp.SkeletonAnimation. please do not call this function by yourself, you should pass the parameters to constructor to initialize it. + * @override + */ + init: function () { + sp.Skeleton.prototype.init.call(this); + this._ownsAnimationStateData = true; + this.setAnimationStateData(new spine.AnimationStateData(this._skeleton.data)); + }, + + /** + * Sets animation state data to sp.SkeletonAnimation. + * @param {spine.AnimationStateData} stateData + */ + setAnimationStateData: function (stateData) { + var state = new spine.AnimationState(stateData); + state.rendererObject = this; + state.onStart = this._onAnimationStateStart.bind(this); + state.onComplete = this._onAnimationStateComplete.bind(this); + state.onEnd = this._onAnimationStateEnd.bind(this); + state.onEvent = this._onAnimationStateEvent.bind(this); + this._state = state; + }, + + /** + * Mix applies all keyframe values, interpolated for the specified time and mixed with the current values.
    + * @param {String} fromAnimation + * @param {String} toAnimation + * @param {Number} duration + */ + setMix: function (fromAnimation, toAnimation, duration) { + this._state.data.setMixByName(fromAnimation, toAnimation, duration); + }, + + /** + * Sets event listener of sp.SkeletonAnimation. + * @param {Object} target + * @param {Function} callback + */ + setAnimationListener: function (target, callback) { + this._target = target; + this._callback = callback; + }, + + /** + * Set the current animation. Any queued animations are cleared. + * @param {Number} trackIndex + * @param {String} name + * @param {Boolean} loop + * @returns {spine.TrackEntry|null} + */ + setAnimation: function (trackIndex, name, loop) { + var animation = this._skeleton.data.findAnimation(name); + if (!animation) { + cc.log("Spine: Animation not found: " + name); + return null; + } + return this._state.setAnimation(trackIndex, animation, loop); + }, + + /** + * Adds an animation to be played delay seconds after the current or last queued animation. + * @param {Number} trackIndex + * @param {String} name + * @param {Boolean} loop + * @param {Number} [delay=0] + * @returns {spine.TrackEntry|null} + */ + addAnimation: function (trackIndex, name, loop, delay) { + delay = delay == null ? 0 : delay; + var animation = this._skeleton.data.findAnimation(name); + if (!animation) { + cc.log("Spine: Animation not found:" + name); + return null; + } + return this._state.addAnimation(trackIndex, animation, loop, delay); + }, + + /** + * Returns track entry by trackIndex. + * @param trackIndex + * @returns {spine.TrackEntry|null} + */ + getCurrent: function (trackIndex) { + return this._state.getCurrent(trackIndex); + }, + + /** + * Clears all tracks of animation state. + */ + clearTracks: function () { + this._state.clearTracks(); + }, + + /** + * Clears track of animation state by trackIndex. + * @param {Number} trackIndex + */ + clearTrack: function (trackIndex) { + this._state.clearTrack(trackIndex); + }, + + /** + * Update will be called automatically every frame if "scheduleUpdate" is called when the node is "live". + * It updates animation's state and skeleton's world transform. + * @param {Number} dt Delta time since last update + * @override + */ + update: function (dt) { + this._super(dt); + dt *= this._timeScale; + this._state.update(dt); + this._state.apply(this._skeleton); + this._skeleton.updateWorldTransform(); + this._renderCmd._updateChild(); + }, + + /** + * Set the start event listener. + * @param {function} listener + */ + setStartListener: function(listener){ + this._startListener = listener; + }, + + /** + * Set the end event listener. + * @param {function} listener + */ + setEndListener: function(listener) { + this._endListener = listener; + }, + + setCompleteListener: function(listener) { + this._completeListener = listener; + }, + + setEventListener: function(listener){ + this._eventListener = listener; + }, + + setTrackStartListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).startListener = listener; + }, + + setTrackEndListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).endListener = listener; + }, + + setTrackCompleteListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).completeListener = listener; + }, + + setTrackEventListener: function(entry, listener){ + sp.TrackEntryListeners.getListeners(entry).eventListener = listener; + }, + + onTrackEntryEvent: function(traceIndex, type, event, loopCount){ + var entry = this._state.getCurrent(traceIndex); + if(!entry.rendererObject) + return; + var listeners = entry.rendererObject; + switch (type){ + case sp.ANIMATION_EVENT_TYPE.START: + if(listeners.startListener) + listeners.startListener(traceIndex); + break; + case sp.ANIMATION_EVENT_TYPE.END: + if(listeners.endListener) + listeners.endListener(traceIndex); + break; + case sp.ANIMATION_EVENT_TYPE.COMPLETE: + if(listeners.completeListener) + listeners.completeListener(traceIndex, loopCount); + break; + case sp.ANIMATION_EVENT_TYPE.EVENT: + if(listeners.eventListener) + listeners.eventListener(traceIndex, event); + break; + } + }, + + onAnimationStateEvent: function(trackIndex, type, event, loopCount) { + switch(type){ + case sp.ANIMATION_EVENT_TYPE.START: + if(this._startListener) + this._startListener(trackIndex); + break; + case sp.ANIMATION_EVENT_TYPE.END: + if(this._endListener) + this._endListener(trackIndex); + break; + case sp.ANIMATION_EVENT_TYPE.COMPLETE: + if(this._completeListener) + this._completeListener(trackIndex, loopCount); + break; + case sp.ANIMATION_EVENT_TYPE.EVENT: + if(this._eventListener) + this._eventListener(trackIndex, event); + break; + } + }, + + getState: function(){ + return this._state; + }, + + _onAnimationStateStart: function (trackIndex) { + this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.START, null, 0); + }, + _onAnimationStateEnd: function (trackIndex) { + this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.END, null, 0); + }, + _onAnimationStateComplete: function (trackIndex, count) { + this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.COMPLETE, null, count); + }, + _onAnimationStateEvent: function (trackIndex, event) { + this._animationStateCallback(trackIndex, sp.ANIMATION_EVENT_TYPE.EVENT, event, 0); + }, + _animationStateCallback: function (trackIndex, type, event, loopCount) { + this.onAnimationStateEvent(trackIndex, type, event, loopCount); + if (this._target && this._callback) { + this._callback.call(this._target, this, trackIndex, type, event, loopCount) + } + } +}); + +/** + * Creates a skeleton animation object. + * @deprecated since v3.0, please use new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale) instead. + * @param {spine.SkeletonData|String} skeletonDataFile + * @param {String|spine.Atlas|spine.SkeletonData} atlasFile atlas filename or atlas data or owns SkeletonData + * @param {Number} [scale] scale can be specified on the JSON or binary loader which will scale the bone positions, image sizes, and animation translations. + * @returns {sp.Skeleton} + */ +sp.SkeletonAnimation.create = function (skeletonDataFile, atlasFile/* or atlas*/, scale) { + return new sp.SkeletonAnimation(skeletonDataFile, atlasFile, scale); +}; \ No newline at end of file diff --git a/extensions/spine/CCSkeletonCanvasRenderCmd.js b/extensions/spine/CCSkeletonCanvasRenderCmd.js new file mode 100644 index 0000000000..1b4f873cd1 --- /dev/null +++ b/extensions/spine/CCSkeletonCanvasRenderCmd.js @@ -0,0 +1,213 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + sp.Skeleton.CanvasRenderCmd = function(renderableObject){ + cc.Node.CanvasRenderCmd.call(this, renderableObject); + this._needDraw = true; + }; + + var proto = sp.Skeleton.CanvasRenderCmd.prototype = Object.create(cc.Node.CanvasRenderCmd.prototype); + proto.constructor = sp.Skeleton.CanvasRenderCmd; + + proto.rendering = function (wrapper, scaleX, scaleY) { + var node = this._node, i, n, slot, slotNode; + wrapper = wrapper || cc._renderContext; + + var locSkeleton = node._skeleton, drawOrder = locSkeleton.drawOrder; + for(i = 0, n = drawOrder.length; i < n; i++){ + slot = drawOrder[i]; + slotNode = slot._slotNode; + if(slotNode._visible && slotNode._renderCmd && slot.currentSprite){ + slotNode._renderCmd.transform(this, true); + slot.currentSprite._renderCmd.rendering(wrapper, scaleX, scaleY); + slotNode._renderCmd._dirtyFlag = slot.currentSprite._renderCmd._dirtyFlag = 0; + } + } + + if (!node._debugSlots && !node._debugBones) + return; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + wrapper.setGlobalAlpha(1); + var attachment, drawingUtil = cc._drawingUtil; + if (node._debugSlots) { + // Slots. + drawingUtil.setDrawColor(0, 0, 255, 255); + drawingUtil.setLineWidth(1); + + var points = []; + for (i = 0, n = locSkeleton.slots.length; i < n; i++) { + slot = locSkeleton.drawOrder[i]; + if (!slot.attachment || slot.attachment.type != sp.ATTACHMENT_TYPE.REGION) + continue; + attachment = slot.attachment; + this._updateRegionAttachmentSlot(attachment, slot, points); + drawingUtil.drawPoly(points, 4, true); + } + } + + if (node._debugBones) { + // Bone lengths. + var bone; + drawingUtil.setLineWidth(2); + drawingUtil.setDrawColor(255, 0, 0, 255); + + for (i = 0, n = locSkeleton.bones.length; i < n; i++) { + bone = locSkeleton.bones[i]; + var x = bone.data.length * bone.m00 + bone.worldX; + var y = bone.data.length * bone.m10 + bone.worldY; + drawingUtil.drawLine( + {x: bone.worldX, y: bone.worldY}, + {x: x, y: y}); + } + + // Bone origins. + drawingUtil.setPointSize(4); + drawingUtil.setDrawColor(0, 0, 255, 255); // Root bone is blue. + + for (i = 0, n = locSkeleton.bones.length; i < n; i++) { + bone = locSkeleton.bones[i]; + drawingUtil.drawPoint({x: bone.worldX, y: bone.worldY}); + if (i === 0) + drawingUtil.setDrawColor(0, 255, 0, 255); + } + } + }; + + proto._updateRegionAttachmentSlot = function(attachment, slot, points) { + if(!points) + return; + + var vertices = {}, VERTEX = sp.VERTEX_INDEX, bone = slot.bone; + attachment.computeVertices(bone.skeleton.x, bone.skeleton.y, bone, vertices); + points.length = 0; + points.push(cc.p(vertices[VERTEX.X1], vertices[VERTEX.Y1])); + points.push(cc.p(vertices[VERTEX.X4], vertices[VERTEX.Y4])); + points.push(cc.p(vertices[VERTEX.X3], vertices[VERTEX.Y3])); + points.push(cc.p(vertices[VERTEX.X2], vertices[VERTEX.Y2])); + }; + + proto._createChildFormSkeletonData = function(){ + var node = this._node; + var locSkeleton = node._skeleton, spriteName, sprite; + for (var i = 0, n = locSkeleton.slots.length; i < n; i++) { + var slot = locSkeleton.slots[i], attachment = slot.attachment; + var slotNode = new cc.Node(); + slot._slotNode = slotNode; + + if(attachment instanceof spine.RegionAttachment){ + spriteName = attachment.rendererObject.name; + sprite = this._createSprite(slot, attachment); + slot.currentSprite = sprite; + slot.currentSpriteName = spriteName; + slotNode.addChild(sprite); + } else if(attachment instanceof spine.MeshAttachment){ + //todo for mesh + } + } + }; + + proto._createSprite = function(slot, attachment){ + var rendererObject = attachment.rendererObject; + var texture = rendererObject.page._texture; + var rect = new cc.Rect(rendererObject.x, rendererObject.y, rendererObject.width, rendererObject.height); + var sprite = new cc.Sprite(); + sprite.initWithTexture(rendererObject.page._texture, rect, rendererObject.rotate, false); + sprite._rect.width = attachment.width; + sprite._rect.height = attachment.height; + sprite.setContentSize(attachment.width, attachment.height); + sprite.setRotation(-attachment.rotation); + sprite.setScale(rendererObject.width / rendererObject.originalWidth * attachment.scaleX, + rendererObject.height / rendererObject.originalHeight * attachment.scaleY); + + slot.sprites = slot.sprites || {}; + slot.sprites[rendererObject.name] = sprite; + + return sprite; + }; + + proto._updateChild = function(){ + var locSkeleton = this._node._skeleton, slots = locSkeleton.slots; + var i, n, selSprite; + + var slot, attachment, slotNode; + for(i = 0, n = slots.length; i < n; i++){ + slot = slots[i]; + attachment = slot.attachment; + slotNode = slot._slotNode; + if(!attachment){ + slotNode.setVisible(false); + continue; + } + var type = attachment.type; + if (type === spine.AttachmentType.region){ + if(attachment.rendererObject){ + if(!slot.currentSpriteName || slot.currentSpriteName !== attachment.name){ + var spriteName = attachment.rendererObject.name; + if(slot.currentSprite !== undefined) + slot.currentSprite.setVisible(false); + slot.sprites = slot.sprites ||{}; + if(slot.sprites[spriteName] !== undefined) + slot.sprites[spriteName].setVisible(true); + else{ + var sprite = this._createSprite(slot, attachment); + slotNode.addChild(sprite); + } + slot.currentSprite = slot.sprites[spriteName]; + slot.currentSpriteName = spriteName; + } + } + var bone = slot.bone; + slotNode.setPosition(bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01, + bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11); + slotNode.setScale(bone.worldScaleX, bone.worldScaleY); + + //set the color and opacity + selSprite = slot.currentSprite; + selSprite._flippedX = bone.worldFlipX; + selSprite._flippedY = bone.worldFlipY; + if(selSprite._flippedY || selSprite._flippedX){ + slotNode.setRotation(bone.worldRotation); + selSprite.setRotation(attachment.rotation); + }else{ + slotNode.setRotation(-bone.worldRotation); + selSprite.setRotation(-attachment.rotation); + } + + //hack for sprite + selSprite._renderCmd._displayedOpacity = 0 | (locSkeleton.a * slot.a * 255); + var r = 0 | (locSkeleton.r * slot.r * 255), g = 0 | (locSkeleton.g * slot.g * 255), b = 0 | (locSkeleton.b * slot.b * 255); + selSprite.setColor(cc.color(r,g,b)); + selSprite._renderCmd._updateColor(); + } else if (type === spine.AttachmentType.skinnedmesh) { + //todo for mesh + } else { + slotNode.setVisible(false); + continue; + } + slotNode.setVisible(true); + } + }; +})(); \ No newline at end of file diff --git a/extensions/spine/CCSkeletonWebGLRenderCmd.js b/extensions/spine/CCSkeletonWebGLRenderCmd.js new file mode 100644 index 0000000000..ca0f14b613 --- /dev/null +++ b/extensions/spine/CCSkeletonWebGLRenderCmd.js @@ -0,0 +1,246 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +(function(){ + sp.Skeleton.WebGLRenderCmd = function (renderableObject) { + cc.Node.WebGLRenderCmd.call(this, renderableObject); + this._needDraw = true; + this.setShaderProgram(cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR)); + this._tmpQuad = new cc.V3F_C4B_T2F_Quad(); + }; + + var proto = sp.Skeleton.WebGLRenderCmd.prototype = Object.create(cc.Node.WebGLRenderCmd.prototype); + proto.constructor = sp.Skeleton.WebGLRenderCmd; + + proto.rendering = function (ctx) { + var node = this._node, tmpQuad = this._tmpQuad; + this._shaderProgram.use(); + this._shaderProgram._setUniformForMVPMatrixWithMat4(this._stackMatrix); +// cc.glBlendFunc(this._blendFunc.src, this._blendFunc.dst); + var color = node.getColor(), locSkeleton = node._skeleton; + locSkeleton.r = color.r / 255; + locSkeleton.g = color.g / 255; + locSkeleton.b = color.b / 255; + locSkeleton.a = node.getOpacity() / 255; + if (node._premultipliedAlpha) { + locSkeleton.r *= locSkeleton.a; + locSkeleton.g *= locSkeleton.a; + locSkeleton.b *= locSkeleton.a; + } + + var additive, textureAtlas, attachment, slot, i, n; + var locBlendFunc = node._blendFunc; + + //for (i = 0, n = locSkeleton.slots.length; i < n; i++) { + for (i = 0, n = locSkeleton.drawOrder.length; i < n; i++) { + slot = locSkeleton.drawOrder[i]; + if (!slot.attachment) + continue; + attachment = slot.attachment; + + switch(slot.attachment.type) { + case sp.ATTACHMENT_TYPE.REGION: + this._updateRegionAttachmentQuad(attachment, slot, tmpQuad, node._premultipliedAlpha); + break; + case sp.ATTACHMENT_TYPE.MESH: + this._updateMeshAttachmentQuad(attachment, slot, tmpQuad, node._premultipliedAlpha); + break; + case sp.ATTACHMENT_TYPE.SKINNED_MESH: + break; + default: + continue; + } + + var regionTextureAtlas = node.getTextureAtlas(attachment); + + if (slot.data.additiveBlending != additive) { + if (textureAtlas) { + textureAtlas.drawQuads(); + textureAtlas.removeAllQuads(); + } + additive = !additive; + cc.glBlendFunc(locBlendFunc.src, additive ? cc.ONE : locBlendFunc.dst); + } else if (regionTextureAtlas != textureAtlas && textureAtlas) { + textureAtlas.drawQuads(); + textureAtlas.removeAllQuads(); + } + textureAtlas = regionTextureAtlas; + + var quadCount = textureAtlas.getTotalQuads(); + if (textureAtlas.getCapacity() == quadCount) { + textureAtlas.drawQuads(); + textureAtlas.removeAllQuads(); + if (!textureAtlas.resizeCapacity(textureAtlas.getCapacity() * 2)) + return; + } + + textureAtlas.updateQuad(tmpQuad, quadCount); + } + + if (textureAtlas) { + textureAtlas.drawQuads(); + textureAtlas.removeAllQuads(); + } + + if (node._debugBones || node._debugSlots) { + cc.kmGLMatrixMode(cc.KM_GL_MODELVIEW); + //cc.kmGLPushMatrixWitMat4(this._stackMatrix); + cc.current_stack.stack.push(cc.current_stack.top); + cc.current_stack.top = this._stackMatrix; + var drawingUtil = cc._drawingUtil; + + if (node._debugSlots) { + // Slots. + drawingUtil.setDrawColor(0, 0, 255, 255); + drawingUtil.setLineWidth(1); + + for (i = 0, n = locSkeleton.slots.length; i < n; i++) { + slot = locSkeleton.drawOrder[i]; + if (!slot.attachment || slot.attachment.type != sp.ATTACHMENT_TYPE.REGION) + continue; + attachment = slot.attachment; + this._updateRegionAttachmentQuad(attachment, slot, tmpQuad); + + var points = []; + points.push(cc.p(tmpQuad.bl.vertices.x, tmpQuad.bl.vertices.y)); + points.push(cc.p(tmpQuad.br.vertices.x, tmpQuad.br.vertices.y)); + points.push(cc.p(tmpQuad.tr.vertices.x, tmpQuad.tr.vertices.y)); + points.push(cc.p(tmpQuad.tl.vertices.x, tmpQuad.tl.vertices.y)); + + drawingUtil.drawPoly(points, 4, true); + } + } + + if (node._debugBones) { + // Bone lengths. + var bone; + drawingUtil.setLineWidth(2); + drawingUtil.setDrawColor(255, 0, 0, 255); + + for (i = 0, n = locSkeleton.bones.length; i < n; i++) { + bone = locSkeleton.bones[i]; + var x = bone.data.length * bone.m00 + bone.worldX; + var y = bone.data.length * bone.m10 + bone.worldY; + drawingUtil.drawLine(cc.p(bone.worldX, bone.worldY), cc.p(x, y)); + } + + // Bone origins. + drawingUtil.setPointSize(4); + drawingUtil.setDrawColor(0, 0, 255, 255); // Root bone is blue. + + for (i = 0, n = locSkeleton.bones.length; i < n; i++) { + bone = locSkeleton.bones[i]; + drawingUtil.drawPoint(cc.p(bone.worldX, bone.worldY)); + if (i == 0) { + drawingUtil.setDrawColor(0, 255, 0, 255); + } + } + } + cc.kmGLPopMatrix(); + } + }; + + proto._createChildFormSkeletonData = function(){}; + + proto._updateChild = function(){}; + + proto._updateRegionAttachmentQuad = function(self, slot, quad, premultipliedAlpha) { + var vertices = {}; + self.computeVertices(slot.bone.skeleton.x, slot.bone.skeleton.y, slot.bone, vertices); + var r = slot.bone.skeleton.r * slot.r * 255; + var g = slot.bone.skeleton.g * slot.g * 255; + var b = slot.bone.skeleton.b * slot.b * 255; + var normalizedAlpha = slot.bone.skeleton.a * slot.a; + + if (premultipliedAlpha) { + r *= normalizedAlpha; + g *= normalizedAlpha; + b *= normalizedAlpha; + } + var a = normalizedAlpha * 255; + + quad.bl.colors.r = quad.tl.colors.r = quad.tr.colors.r = quad.br.colors.r = r; + quad.bl.colors.g = quad.tl.colors.g = quad.tr.colors.g = quad.br.colors.g = g; + quad.bl.colors.b = quad.tl.colors.b = quad.tr.colors.b = quad.br.colors.b = b; + quad.bl.colors.a = quad.tl.colors.a = quad.tr.colors.a = quad.br.colors.a = a; + + var VERTEX = sp.VERTEX_INDEX; + quad.bl.vertices.x = vertices[VERTEX.X1]; + quad.bl.vertices.y = vertices[VERTEX.Y1]; + quad.tl.vertices.x = vertices[VERTEX.X2]; + quad.tl.vertices.y = vertices[VERTEX.Y2]; + quad.tr.vertices.x = vertices[VERTEX.X3]; + quad.tr.vertices.y = vertices[VERTEX.Y3]; + quad.br.vertices.x = vertices[VERTEX.X4]; + quad.br.vertices.y = vertices[VERTEX.Y4]; + + quad.bl.texCoords.u = self.uvs[VERTEX.X1]; + quad.bl.texCoords.v = self.uvs[VERTEX.Y1]; + quad.tl.texCoords.u = self.uvs[VERTEX.X2]; + quad.tl.texCoords.v = self.uvs[VERTEX.Y2]; + quad.tr.texCoords.u = self.uvs[VERTEX.X3]; + quad.tr.texCoords.v = self.uvs[VERTEX.Y3]; + quad.br.texCoords.u = self.uvs[VERTEX.X4]; + quad.br.texCoords.v = self.uvs[VERTEX.Y4]; + }; + + proto._updateMeshAttachmentQuad = function(self, slot, quad, premultipliedAlpha) { + var vertices = {}; + self.computeWorldVertices(slot.bone.x, slot.bone.y, slot, vertices); + var r = slot.bone.skeleton.r * slot.r * 255; + var g = slot.bone.skeleton.g * slot.g * 255; + var b = slot.bone.skeleton.b * slot.b * 255; + var normalizedAlpha = slot.bone.skeleton.a * slot.a; + if (premultipliedAlpha) { + r *= normalizedAlpha; + g *= normalizedAlpha; + b *= normalizedAlpha; + } + var a = normalizedAlpha * 255; + + quad.bl.colors.r = quad.tl.colors.r = quad.tr.colors.r = quad.br.colors.r = r; + quad.bl.colors.g = quad.tl.colors.g = quad.tr.colors.g = quad.br.colors.g = g; + quad.bl.colors.b = quad.tl.colors.b = quad.tr.colors.b = quad.br.colors.b = b; + quad.bl.colors.a = quad.tl.colors.a = quad.tr.colors.a = quad.br.colors.a = a; + + var VERTEX = sp.VERTEX_INDEX; + quad.bl.vertices.x = vertices[VERTEX.X1]; + quad.bl.vertices.y = vertices[VERTEX.Y1]; + quad.tl.vertices.x = vertices[VERTEX.X2]; + quad.tl.vertices.y = vertices[VERTEX.Y2]; + quad.tr.vertices.x = vertices[VERTEX.X3]; + quad.tr.vertices.y = vertices[VERTEX.Y3]; + quad.br.vertices.x = vertices[VERTEX.X4]; + quad.br.vertices.y = vertices[VERTEX.Y4]; + + quad.bl.texCoords.u = self.uvs[VERTEX.X1]; + quad.bl.texCoords.v = self.uvs[VERTEX.Y1]; + quad.tl.texCoords.u = self.uvs[VERTEX.X2]; + quad.tl.texCoords.v = self.uvs[VERTEX.Y2]; + quad.tr.texCoords.u = self.uvs[VERTEX.X3]; + quad.tr.texCoords.v = self.uvs[VERTEX.Y3]; + quad.br.texCoords.u = self.uvs[VERTEX.X4]; + quad.br.texCoords.v = self.uvs[VERTEX.Y4]; + }; +})(); \ No newline at end of file diff --git a/extensions/spine/Spine.js b/extensions/spine/Spine.js new file mode 100644 index 0000000000..7a25bab80e --- /dev/null +++ b/extensions/spine/Spine.js @@ -0,0 +1,2628 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +var spine = { + radDeg: 180 / Math.PI, + degRad: Math.PI / 180, + temp: [], + Float32Array: (typeof(Float32Array) === 'undefined') ? Array : Float32Array, + Uint16Array: (typeof(Uint16Array) === 'undefined') ? Array : Uint16Array +}; + +spine.BoneData = function (name, parent) { + this.name = name; + this.parent = parent; +}; +spine.BoneData.prototype = { + length: 0, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + inheritScale: true, + inheritRotation: true, + flipX: false, flipY: false +}; + +spine.SlotData = function (name, boneData) { + this.name = name; + this.boneData = boneData; +}; +spine.SlotData.prototype = { + r: 1, g: 1, b: 1, a: 1, + attachmentName: null, + additiveBlending: false +}; + +spine.IkConstraintData = function (name) { + this.name = name; + this.bones = []; +}; +spine.IkConstraintData.prototype = { + target: null, + bendDirection: 1, + mix: 1 +}; + +spine.Bone = function (boneData, skeleton, parent) { + this.data = boneData; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); +}; +spine.Bone.yDown = false; +spine.Bone.prototype = { + x: 0, y: 0, + rotation: 0, rotationIK: 0, + scaleX: 1, scaleY: 1, + flipX: false, flipY: false, + m00: 0, m01: 0, worldX: 0, // a b x + m10: 0, m11: 0, worldY: 0, // c d y + worldRotation: 0, + worldScaleX: 1, worldScaleY: 1, + worldFlipX: false, worldFlipY: false, + updateWorldTransform: function () { + var parent = this.parent; + if (parent) { + this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; + this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; + if (this.data.inheritScale) { + this.worldScaleX = parent.worldScaleX * this.scaleX; + this.worldScaleY = parent.worldScaleY * this.scaleY; + } else { + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + } + this.worldRotation = this.data.inheritRotation ? (parent.worldRotation + this.rotationIK) : this.rotationIK; + this.worldFlipX = parent.worldFlipX != this.flipX; + this.worldFlipY = parent.worldFlipY != this.flipY; + } else { + var skeletonFlipX = this.skeleton.flipX, skeletonFlipY = this.skeleton.flipY; + this.worldX = skeletonFlipX ? -this.x : this.x; + this.worldY = (skeletonFlipY != spine.Bone.yDown) ? -this.y : this.y; + this.worldScaleX = this.scaleX; + this.worldScaleY = this.scaleY; + this.worldRotation = this.rotationIK; + this.worldFlipX = skeletonFlipX != this.flipX; + this.worldFlipY = skeletonFlipY != this.flipY; + } + var radians = this.worldRotation * spine.degRad; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + if (this.worldFlipX) { + this.m00 = -cos * this.worldScaleX; + this.m01 = sin * this.worldScaleY; + } else { + this.m00 = cos * this.worldScaleX; + this.m01 = -sin * this.worldScaleY; + } + if (this.worldFlipY != spine.Bone.yDown) { + this.m10 = -sin * this.worldScaleX; + this.m11 = -cos * this.worldScaleY; + } else { + this.m10 = sin * this.worldScaleX; + this.m11 = cos * this.worldScaleY; + } + }, + setToSetupPose: function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.rotationIK = this.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.flipX = data.flipX; + this.flipY = data.flipY; + }, + worldToLocal: function (world) { + var dx = world[0] - this.worldX, dy = world[1] - this.worldY; + var m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11; + if (this.worldFlipX != (this.worldFlipY != spine.Bone.yDown)) { + m00 = -m00; + m11 = -m11; + } + var invDet = 1 / (m00 * m11 - m01 * m10); + world[0] = dx * m00 * invDet - dy * m01 * invDet; + world[1] = dy * m11 * invDet - dx * m10 * invDet; + }, + localToWorld: function (local) { + var localX = local[0], localY = local[1]; + local[0] = localX * this.m00 + localY * this.m01 + this.worldX; + local[1] = localX * this.m10 + localY * this.m11 + this.worldY; + } +}; + +spine.Slot = function (slotData, bone) { + this.data = slotData; + this.bone = bone; + this.setToSetupPose(); +}; +spine.Slot.prototype = { + r: 1, g: 1, b: 1, a: 1, + _attachmentTime: 0, + attachment: null, + attachmentVertices: [], + setAttachment: function (attachment) { + this.attachment = attachment; + this._attachmentTime = this.bone.skeleton.time; + this.attachmentVertices.length = 0; + }, + setAttachmentTime: function (time) { + this._attachmentTime = this.bone.skeleton.time - time; + }, + getAttachmentTime: function () { + return this.bone.skeleton.time - this._attachmentTime; + }, + setToSetupPose: function () { + var data = this.data; + this.r = data.r; + this.g = data.g; + this.b = data.b; + this.a = data.a; + + var slotDatas = this.bone.skeleton.data.slots; + for (var i = 0, n = slotDatas.length; i < n; i++) { + if (slotDatas[i] == data) { + this.setAttachment(!data.attachmentName ? null : this.bone.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); + break; + } + } + } +}; + +spine.IkConstraint = function (data, skeleton) { + this.data = data; + this.mix = data.mix; + this.bendDirection = data.bendDirection; + + this.bones = []; + for (var i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); +}; +spine.IkConstraint.prototype = { + apply: function () { + var target = this.target; + var bones = this.bones; + switch (bones.length) { + case 1: + spine.IkConstraint.apply1(bones[0], target.worldX, target.worldY, this.mix); + break; + case 2: + spine.IkConstraint.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); + break; + } + } +}; +/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world + * coordinate system. */ +spine.IkConstraint.apply1 = function (bone, targetX, targetY, alpha) { + var parentRotation = (!bone.data.inheritRotation || !bone.parent) ? 0 : bone.parent.worldRotation; + var rotation = bone.rotation; + var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg; + if (bone.worldFlipX != (bone.worldFlipY != spine.Bone.yDown)) rotationIK = -rotationIK; + rotationIK -= parentRotation; + bone.rotationIK = rotation + (rotationIK - rotation) * alpha; +}; +/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The + * target is specified in the world coordinate system. + * @param child Any descendant bone of the parent. */ +spine.IkConstraint.apply2 = function (parent, child, targetX, targetY, bendDirection, alpha) { + var childRotation = child.rotation, parentRotation = parent.rotation; + if (!alpha) { + child.rotationIK = childRotation; + parent.rotationIK = parentRotation; + return; + } + var positionX, positionY, tempPosition = spine.temp; + var parentParent = parent.parent; + if (parentParent) { + tempPosition[0] = targetX; + tempPosition[1] = targetY; + parentParent.worldToLocal(tempPosition); + targetX = (tempPosition[0] - parent.x) * parentParent.worldScaleX; + targetY = (tempPosition[1] - parent.y) * parentParent.worldScaleY; + } else { + targetX -= parent.x; + targetY -= parent.y; + } + if (child.parent == parent) { + positionX = child.x; + positionY = child.y; + } else { + tempPosition[0] = child.x; + tempPosition[1] = child.y; + child.parent.localToWorld(tempPosition); + parent.worldToLocal(tempPosition); + positionX = tempPosition[0]; + positionY = tempPosition[1]; + } + var childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY; + var offset = Math.atan2(childY, childX); + var len1 = Math.sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX; + // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ + var cosDenom = 2 * len1 * len2; + if (cosDenom < 0.0001) { + child.rotationIK = childRotation + (Math.atan2(targetY, targetX) * spine.radDeg - parentRotation - childRotation) * alpha; + return; + } + var cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; + if (cos < -1) + cos = -1; + else if (cos > 1) + cos = 1; + var childAngle = Math.acos(cos) * bendDirection; + var adjacent = len1 + len2 * cos, opposite = len2 * Math.sin(childAngle); + var parentAngle = Math.atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); + var rotation = (parentAngle - offset) * spine.radDeg - parentRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) // + rotation += 360; + parent.rotationIK = parentRotation + rotation * alpha; + rotation = (childAngle + offset) * spine.radDeg - childRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) // + rotation += 360; + child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha; +}; + +spine.Skin = function (name) { + this.name = name; + this.attachments = {}; +}; +spine.Skin.prototype = { + addAttachment: function (slotIndex, name, attachment) { + this.attachments[slotIndex + ":" + name] = attachment; + }, + getAttachment: function (slotIndex, name) { + return this.attachments[slotIndex + ":" + name]; + }, + _attachAll: function (skeleton, oldSkin) { + for (var key in oldSkin.attachments) { + var colon = key.indexOf(":"); + var slotIndex = parseInt(key.substring(0, colon)); + var name = key.substring(colon + 1); + var slot = skeleton.slots[slotIndex]; + if (slot.attachment && slot.attachment.name == name) { + var attachment = this.getAttachment(slotIndex, name); + if (attachment) slot.setAttachment(attachment); + } + } + } +}; + +spine.Animation = function (name, timelines, duration) { + this.name = name; + this.timelines = timelines; + this.duration = duration; +}; +spine.Animation.prototype = { + apply: function (skeleton, lastTime, time, loop, events) { + if (loop && this.duration != 0) { + time %= this.duration; + lastTime %= this.duration; + } + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, 1); + }, + mix: function (skeleton, lastTime, time, loop, events, alpha) { + if (loop && this.duration != 0) { + time %= this.duration; + lastTime %= this.duration; + } + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha); + } +}; +spine.Animation.binarySearch = function (values, target, step) { + var low = 0; + var high = Math.floor(values.length / step) - 2; + if (!high) return step; + var current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } +}; +spine.Animation.binarySearch1 = function (values, target) { + var low = 0; + var high = values.length - 2; + if (!high) return 1; + var current = high >>> 1; + while (true) { + if (values[current + 1] <= target) + low = current + 1; + else + high = current; + if (low == high) return low + 1; + current = (low + high) >>> 1; + } +}; +spine.Animation.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; +}; + +spine.Curves = function (frameCount) { + this.curves = []; // type, x, y, ... + //this.curves.length = (frameCount - 1) * 19/*BEZIER_SIZE*/; +}; +spine.Curves.prototype = { + setLinear: function (frameIndex) { + this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 0/*LINEAR*/; + }, + setStepped: function (frameIndex) { + this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 1/*STEPPED*/; + }, + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { + var subdiv1 = 1 / 10/*BEZIER_SEGMENTS*/, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1; + var pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3; + var tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1; + var dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3; + var ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5; + var dddfx = tmp2x * pre5, dddfy = tmp2y * pre5; + + var i = frameIndex * 19/*BEZIER_SIZE*/; + var curves = this.curves; + curves[i++] = 2/*BEZIER*/; + + var x = dfx, y = dfy; + for (var n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + }, + getCurvePercent: function (frameIndex, percent) { + percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); + var curves = this.curves; + var i = frameIndex * 19/*BEZIER_SIZE*/; + var type = curves[i]; + if (type === 0/*LINEAR*/) return percent; + if (type == 1/*STEPPED*/) return 0; + i++; + var x = 0; + for (var start = i, n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + var prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[i - 2]; + prevY = curves[i - 1]; + } + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + var y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +}; + +spine.RotateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, angle, ... + this.frames.length = frameCount * 2; +}; +spine.RotateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, angle) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = angle; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 2]) { // Time is after last frame. + var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch(frames, time, 2); + var prevFrameValue = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*PREV_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); + + var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - prevFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (prevFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +}; + +spine.TranslateTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.TranslateTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch(frames, time, 3); + var prevFrameX = frames[frameIndex - 2]; + var prevFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent - bone.y) * alpha; + } +}; + +spine.ScaleTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, x, y, ... + this.frames.length = frameCount * 3; +}; +spine.ScaleTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, x, y) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = x; + this.frames[frameIndex + 2] = y; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX * frames[frames.length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * frames[frames.length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch(frames, time, 3); + var prevFrameX = frames[frameIndex - 2]; + var prevFrameY = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent) - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent) - bone.scaleY) * alpha; + } +}; + +spine.ColorTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, r, g, b, a, ... + this.frames.length = frameCount * 5; +}; +spine.ColorTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length / 5; + }, + setFrame: function (frameIndex, time, r, g, b, a) { + frameIndex *= 5; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = r; + this.frames[frameIndex + 2] = g; + this.frames[frameIndex + 3] = b; + this.frames[frameIndex + 4] = a; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var r, g, b, a; + if (time >= frames[frames.length - 5]) { + // Time is after last frame. + var i = frames.length - 1; + r = frames[i - 3]; + g = frames[i - 2]; + b = frames[i - 1]; + a = frames[i]; + } else { + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch(frames, time, 5); + var prevFrameR = frames[frameIndex - 4]; + var prevFrameG = frames[frameIndex - 3]; + var prevFrameB = frames[frameIndex - 2]; + var prevFrameA = frames[frameIndex - 1]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*PREV_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); + + r = prevFrameR + (frames[frameIndex + 1/*FRAME_R*/] - prevFrameR) * percent; + g = prevFrameG + (frames[frameIndex + 2/*FRAME_G*/] - prevFrameG) * percent; + b = prevFrameB + (frames[frameIndex + 3/*FRAME_B*/] - prevFrameB) * percent; + a = prevFrameA + (frames[frameIndex + 4/*FRAME_A*/] - prevFrameA) * percent; + } + var slot = skeleton.slots[this.slotIndex]; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +}; + +spine.AttachmentTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, ... + this.frames.length = frameCount; + this.attachmentNames = []; + this.attachmentNames.length = frameCount; +}; +spine.AttachmentTimeline.prototype = { + slotIndex: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) { + if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); + return; + } else if (lastTime > time) // + lastTime = -1; + + var frameIndex = time >= frames[frames.length - 1] ? frames.length - 1 : spine.Animation.binarySearch1(frames, time) - 1; + if (frames[frameIndex] < lastTime) return; + + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex].setAttachment( + !attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); + } +}; + +spine.EventTimeline = function (frameCount) { + this.frames = []; // time, ... + this.frames.length = frameCount; + this.events = []; + this.events.length = frameCount; +}; +spine.EventTimeline.prototype = { + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, event) { + this.frames[frameIndex] = time; + this.events[frameIndex] = event; + }, + /** Fires events for frames > lastTime and <= time. */ + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + if (!firedEvents) return; + + var frames = this.frames; + var frameCount = frames.length; + + if (lastTime > time) { // Fire events after last time for looped animations. + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (lastTime < frames[0]) + frameIndex = 0; + else { + frameIndex = spine.Animation.binarySearch1(frames, lastTime); + var frame = frames[frameIndex]; + while (frameIndex > 0) { // Fire multiple events with the same frame. + if (frames[frameIndex - 1] != frame) break; + frameIndex--; + } + } + var events = this.events; + for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++) + firedEvents.push(events[frameIndex]); + } +}; + +spine.DrawOrderTimeline = function (frameCount) { + this.frames = []; // time, ... + this.frames.length = frameCount; + this.drawOrders = []; + this.drawOrders.length = frameCount; +}; +spine.DrawOrderTimeline.prototype = { + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, drawOrder) { + this.frames[frameIndex] = time; + this.drawOrders[frameIndex] = drawOrder; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = spine.Animation.binarySearch1(frames, time) - 1; + + var drawOrder = skeleton.drawOrder; + var slots = skeleton.slots; + var drawOrderToSetupIndex = this.drawOrders[frameIndex]; + if (!drawOrderToSetupIndex) { + for (var i = 0, n = slots.length; i < n; i++) + drawOrder[i] = slots[i]; + } else { + for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = skeleton.slots[drawOrderToSetupIndex[i]]; + } + + } +}; + +spine.FfdTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; + this.frames.length = frameCount; + this.frameVertices = []; + this.frameVertices.length = frameCount; +}; +spine.FfdTimeline.prototype = { + slotIndex: 0, + attachment: 0, + getFrameCount: function () { + return this.frames.length; + }, + setFrame: function (frameIndex, time, vertices) { + this.frames[frameIndex] = time; + this.frameVertices[frameIndex] = vertices; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var slot = skeleton.slots[this.slotIndex]; + if (slot.attachment != this.attachment) return; + + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameVertices = this.frameVertices; + var vertexCount = frameVertices[0].length; + + var vertices = slot.attachmentVertices; + if (vertices.length != vertexCount) alpha = 1; + vertices.length = vertexCount; + + if (time >= frames[frames.length - 1]) { // Time is after last frame. + var lastVertices = frameVertices[frames.length - 1]; + if (alpha < 1) { + for (var i = 0; i < vertexCount; i++) + vertices[i] += (lastVertices[i] - vertices[i]) * alpha; + } else { + for (var i = 0; i < vertexCount; i++) + vertices[i] = lastVertices[i]; + } + return; + } + + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch1(frames, time); + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime); + percent = this.curves.getCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + var prevVertices = frameVertices[frameIndex - 1]; + var nextVertices = frameVertices[frameIndex]; + + if (alpha < 1) { + for (var i = 0; i < vertexCount; i++) { + var prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } + } else { + for (var i = 0; i < vertexCount; i++) { + var prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } +}; + +spine.IkConstraintTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, mix, bendDirection, ... + this.frames.length = frameCount * 3; +}; +spine.IkConstraintTimeline.prototype = { + ikConstraintIndex: 0, + getFrameCount: function () { + return this.frames.length / 3; + }, + setFrame: function (frameIndex, time, mix, bendDirection) { + frameIndex *= 3; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = mix; + this.frames[frameIndex + 2] = bendDirection; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var ikConstraint = skeleton.ikConstraints[this.ikConstraintIndex]; + + if (time >= frames[frames.length - 3]) { // Time is after last frame. + ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha; + ikConstraint.bendDirection = frames[frames.length - 1]; + return; + } + + // Interpolate between the previous frame and the current frame. + var frameIndex = spine.Animation.binarySearch(frames, time, 3); + var prevFrameMix = frames[frameIndex + -2/*PREV_FRAME_MIX*/]; + var frameTime = frames[frameIndex]; + var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); + percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); + + var mix = prevFrameMix + (frames[frameIndex + 1/*FRAME_MIX*/] - prevFrameMix) * percent; + ikConstraint.mix += (mix - ikConstraint.mix) * alpha; + ikConstraint.bendDirection = frames[frameIndex + -1/*PREV_FRAME_BEND_DIRECTION*/]; + } +}; + +spine.FlipXTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, flip, ... + this.frames.length = frameCount * 2; +}; +spine.FlipXTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, flip) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = flip ? 1 : 0; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) { + if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); + return; + } else if (lastTime > time) // + lastTime = -1; + var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; + if (frames[frameIndex] < lastTime) return; + skeleton.bones[this.boneIndex].flipX = frames[frameIndex + 1] != 0; + } +}; + +spine.FlipYTimeline = function (frameCount) { + this.curves = new spine.Curves(frameCount); + this.frames = []; // time, flip, ... + this.frames.length = frameCount * 2; +}; +spine.FlipYTimeline.prototype = { + boneIndex: 0, + getFrameCount: function () { + return this.frames.length / 2; + }, + setFrame: function (frameIndex, time, flip) { + frameIndex *= 2; + this.frames[frameIndex] = time; + this.frames[frameIndex + 1] = flip ? 1 : 0; + }, + apply: function (skeleton, lastTime, time, firedEvents, alpha) { + var frames = this.frames; + if (time < frames[0]) { + if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); + return; + } else if (lastTime > time) // + lastTime = -1; + var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; + if (frames[frameIndex] < lastTime) return; + skeleton.bones[this.boneIndex].flipY = frames[frameIndex + 1] != 0; + } +}; + +spine.SkeletonData = function () { + this.bones = []; + this.slots = []; + this.skins = []; + this.events = []; + this.animations = []; + this.ikConstraints = []; +}; +spine.SkeletonData.prototype = { + name: null, + defaultSkin: null, + width: 0, height: 0, + version: null, hash: null, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + if (slots[i].name == slotName) return slot[i]; + } + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + }, + /** @return May be null. */ + findSkin: function (skinName) { + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) + if (skins[i].name == skinName) return skins[i]; + return null; + }, + /** @return May be null. */ + findEvent: function (eventName) { + var events = this.events; + for (var i = 0, n = events.length; i < n; i++) + if (events[i].name == eventName) return events[i]; + return null; + }, + /** @return May be null. */ + findAnimation: function (animationName) { + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) + if (animations[i].name == animationName) return animations[i]; + return null; + }, + /** @return May be null. */ + findIkConstraint: function (ikConstraintName) { + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) + if (ikConstraints[i].name == ikConstraintName) return ikConstraints[i]; + return null; + } +}; + +spine.Skeleton = function (skeletonData) { + this.data = skeletonData; + + this.bones = []; + for (var i = 0, n = skeletonData.bones.length; i < n; i++) { + var boneData = skeletonData.bones[i]; + var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; + this.bones.push(new spine.Bone(boneData, this, parent)); + } + + this.slots = []; + this.drawOrder = []; + for (var i = 0, n = skeletonData.slots.length; i < n; i++) { + var slotData = skeletonData.slots[i]; + var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; + var slot = new spine.Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + + this.ikConstraints = []; + for (var i = 0, n = skeletonData.ikConstraints.length; i < n; i++) + this.ikConstraints.push(new spine.IkConstraint(skeletonData.ikConstraints[i], this)); + + this.boneCache = []; + this.updateCache(); +}; +spine.Skeleton.prototype = { + x: 0, y: 0, + skin: null, + r: 1, g: 1, b: 1, a: 1, + time: 0, + flipX: false, flipY: false, + /** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */ + updateCache: function () { + var ikConstraints = this.ikConstraints; + var ikConstraintsCount = ikConstraints.length; + + var arrayCount = ikConstraintsCount + 1; + var boneCache = this.boneCache; + if (boneCache.length > arrayCount) boneCache.length = arrayCount; + for (var i = 0, n = boneCache.length; i < n; i++) + boneCache[i].length = 0; + while (boneCache.length < arrayCount) + boneCache[boneCache.length] = []; + + var nonIkBones = boneCache[0]; + var bones = this.bones; + + outer: + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var current = bone; + do { + for (var ii = 0; ii < ikConstraintsCount; ii++) { + var ikConstraint = ikConstraints[ii]; + var parent = ikConstraint.bones[0]; + var child= ikConstraint.bones[ikConstraint.bones.length - 1]; + while (true) { + if (current == child) { + boneCache[ii].push(bone); + boneCache[ii + 1].push(bone); + continue outer; + } + if (child == parent) break; + child = child.parent; + } + } + current = current.parent; + } while (current); + nonIkBones[nonIkBones.length] = bone; + } + }, + /** Updates the world transform for each bone. */ + updateWorldTransform: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + bone.rotationIK = bone.rotation; + } + var i = 0, last = this.boneCache.length - 1; + while (true) { + var cacheBones = this.boneCache[i]; + for (var ii = 0, nn = cacheBones.length; ii < nn; ii++) + cacheBones[ii].updateWorldTransform(); + if (i == last) break; + this.ikConstraints[i].apply(); + i++; + } + }, + /** Sets the bones and slots to their setup pose values. */ + setToSetupPose: function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }, + setBonesToSetupPose: function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var ikConstraint = ikConstraints[i]; + ikConstraint.bendDirection = ikConstraint.data.bendDirection; + ikConstraint.mix = ikConstraint.data.mix; + } + }, + setSlotsToSetupPose: function () { + var slots = this.slots; + var drawOrder = this.drawOrder; + for (var i = 0, n = slots.length; i < n; i++) { + drawOrder[i] = slots[i]; + slots[i].setToSetupPose(i); + } + }, + /** @return May return null. */ + getRootBone: function () { + return this.bones.length ? this.bones[0] : null; + }, + /** @return May be null. */ + findBone: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return bones[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findBoneIndex: function (boneName) { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + }, + /** @return May be null. */ + findSlot: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return slots[i]; + return null; + }, + /** @return -1 if the bone was not found. */ + findSlotIndex: function (slotName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + }, + setSkinByName: function (skinName) { + var skin = this.data.findSkin(skinName); + if (!skin) throw "Skin not found: " + skinName; + this.setSkin(skin); + }, + /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}. + * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was + * no old skin, each slot's setup mode attachment is attached from the new skin. + * @param newSkin May be null. */ + setSkin: function (newSkin) { + if (newSkin) { + if (this.skin) + newSkin._attachAll(this, this.skin); + else { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + var name = slot.data.attachmentName; + if (name) { + var attachment = newSkin.getAttachment(i, name); + if (attachment) slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + }, + /** @return May be null. */ + getAttachmentBySlotName: function (slotName, attachmentName) { + return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); + }, + /** @return May be null. */ + getAttachmentBySlotIndex: function (slotIndex, attachmentName) { + if (this.skin) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }, + /** @param attachmentName May be null. */ + setAttachment: function (slotName, attachmentName) { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName) { + attachment = this.getAttachmentBySlotIndex(i, attachmentName); + if (!attachment) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; + } + slot.setAttachment(attachment); + return; + } + } + throw "Slot not found: " + slotName; + }, + /** @return May be null. */ + findIkConstraint: function (ikConstraintName) { + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) + if (ikConstraints[i].data.name == ikConstraintName) return ikConstraints[i]; + return null; + }, + update: function (delta) { + this.time += delta; + } +}; + +spine.EventData = function (name) { + this.name = name; +}; +spine.EventData.prototype = { + intValue: 0, + floatValue: 0, + stringValue: null +}; + +spine.Event = function (data) { + this.data = data; +}; +spine.Event.prototype = { + intValue: 0, + floatValue: 0, + stringValue: null +}; + +spine.AttachmentType = { + region: 0, + boundingbox: 1, + mesh: 2, + skinnedmesh: 3 +}; + +spine.RegionAttachment = function (name) { + this.name = name; + this.offset = []; + this.offset.length = 8; + this.uvs = []; + this.uvs.length = 8; +}; +spine.RegionAttachment.prototype = { + type: spine.AttachmentType.region, + x: 0, y: 0, + rotation: 0, + scaleX: 1, scaleY: 1, + width: 0, height: 0, + r: 1, g: 1, b: 1, a: 1, + path: null, + rendererObject: null, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + setUVs: function (u, v, u2, v2, rotate) { + var uvs = this.uvs; + if (rotate) { + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v2; + uvs[4/*X3*/] = u; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v; + uvs[0/*X1*/] = u2; + uvs[1/*Y1*/] = v2; + } else { + uvs[0/*X1*/] = u; + uvs[1/*Y1*/] = v2; + uvs[2/*X2*/] = u; + uvs[3/*Y2*/] = v; + uvs[4/*X3*/] = u2; + uvs[5/*Y3*/] = v; + uvs[6/*X4*/] = u2; + uvs[7/*Y4*/] = v2; + } + }, + updateOffset: function () { + var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; + var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; + var localX2 = localX + this.regionWidth * regionScaleX; + var localY2 = localY + this.regionHeight * regionScaleY; + var radians = this.rotation * spine.degRad; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[0/*X1*/] = localXCos - localYSin; + offset[1/*Y1*/] = localYCos + localXSin; + offset[2/*X2*/] = localXCos - localY2Sin; + offset[3/*Y2*/] = localY2Cos + localXSin; + offset[4/*X3*/] = localX2Cos - localY2Sin; + offset[5/*Y3*/] = localY2Cos + localX2Sin; + offset[6/*X4*/] = localX2Cos - localYSin; + offset[7/*Y4*/] = localYCos + localX2Sin; + }, + computeVertices: function (x, y, bone, vertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; + var offset = this.offset; + vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; + vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; + vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; + vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; + vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; + vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; + vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; + vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; + } +}; + +spine.MeshAttachment = function (name) { + this.name = name; +}; +spine.MeshAttachment.prototype = { + type: spine.AttachmentType.mesh, + vertices: null, + uvs: null, + regionUVs: null, + triangles: null, + hullLength: 0, + r: 1, g: 1, b: 1, a: 1, + path: null, + rendererObject: null, + regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + edges: null, + width: 0, height: 0, + updateUVs: function () { + var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; + var n = this.regionUVs.length; + if (!this.uvs || this.uvs.length != n) { + this.uvs = new spine.Float32Array(n); + } + if (this.regionRotate) { + for (var i = 0; i < n; i += 2) { + this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; + this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; + } + } else { + for (var i = 0; i < n; i += 2) { + this.uvs[i] = this.regionU + this.regionUVs[i] * width; + this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; + } + } + }, + computeWorldVertices: function (x, y, slot, worldVertices) { + var bone = slot.bone; + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; + var vertices = this.vertices; + var verticesCount = vertices.length; + if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices; + for (var i = 0; i < verticesCount; i += 2) { + var vx = vertices[i]; + var vy = vertices[i + 1]; + worldVertices[i] = vx * m00 + vy * m01 + x; + worldVertices[i + 1] = vx * m10 + vy * m11 + y; + } + } +}; + +spine.SkinnedMeshAttachment = function (name) { + this.name = name; +}; +spine.SkinnedMeshAttachment.prototype = { + type: spine.AttachmentType.skinnedmesh, + bones: null, + weights: null, + uvs: null, + regionUVs: null, + triangles: null, + hullLength: 0, + r: 1, g: 1, b: 1, a: 1, + path: null, + rendererObject: null, + regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, + regionOffsetX: 0, regionOffsetY: 0, + regionWidth: 0, regionHeight: 0, + regionOriginalWidth: 0, regionOriginalHeight: 0, + edges: null, + width: 0, height: 0, + updateUVs: function (u, v, u2, v2, rotate) { + var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; + var n = this.regionUVs.length; + if (!this.uvs || this.uvs.length != n) { + this.uvs = new spine.Float32Array(n); + } + if (this.regionRotate) { + for (var i = 0; i < n; i += 2) { + this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; + this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; + } + } else { + for (var i = 0; i < n; i += 2) { + this.uvs[i] = this.regionU + this.regionUVs[i] * width; + this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; + } + } + }, + computeWorldVertices: function (x, y, slot, worldVertices) { + var skeletonBones = slot.bone.skeleton.bones; + var weights = this.weights; + var bones = this.bones; + + var w = 0, v = 0, b = 0, f = 0, n = bones.length, nn; + var wx, wy, bone, vx, vy, weight; + if (!slot.attachmentVertices.length) { + for (; v < n; w += 2) { + wx = 0; + wy = 0; + nn = bones[v++] + v; + for (; v < nn; v++, b += 3) { + bone = skeletonBones[bones[v]]; + vx = weights[b]; + vy = weights[b + 1]; + weight = weights[b + 2]; + wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; + wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; + } + worldVertices[w] = wx + x; + worldVertices[w + 1] = wy + y; + } + } else { + var ffd = slot.attachmentVertices; + for (; v < n; w += 2) { + wx = 0; + wy = 0; + nn = bones[v++] + v; + for (; v < nn; v++, b += 3, f += 2) { + bone = skeletonBones[bones[v]]; + vx = weights[b] + ffd[f]; + vy = weights[b + 1] + ffd[f + 1]; + weight = weights[b + 2]; + wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; + wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; + } + worldVertices[w] = wx + x; + worldVertices[w + 1] = wy + y; + } + } + } +}; + +spine.BoundingBoxAttachment = function (name) { + this.name = name; + this.vertices = []; +}; +spine.BoundingBoxAttachment.prototype = { + type: spine.AttachmentType.boundingbox, + computeWorldVertices: function (x, y, bone, worldVertices) { + x += bone.worldX; + y += bone.worldY; + var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; + var vertices = this.vertices; + for (var i = 0, n = vertices.length; i < n; i += 2) { + var px = vertices[i]; + var py = vertices[i + 1]; + worldVertices[i] = px * m00 + py * m01 + x; + worldVertices[i + 1] = px * m10 + py * m11 + y; + } + } +}; + +spine.AnimationStateData = function (skeletonData) { + this.skeletonData = skeletonData; + this.animationToMixTime = {}; +}; +spine.AnimationStateData.prototype = { + defaultMix: 0, + setMixByName: function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (!from) throw "Animation not found: " + fromName; + var to = this.skeletonData.findAnimation(toName); + if (!to) throw "Animation not found: " + toName; + this.setMix(from, to, duration); + }, + setMix: function (from, to, duration) { + this.animationToMixTime[from.name + ":" + to.name] = duration; + }, + getMix: function (from, to) { + var key = from.name + ":" + to.name; + return this.animationToMixTime.hasOwnProperty(key) ? this.animationToMixTime[key] : this.defaultMix; + } +}; + +spine.TrackEntry = function () {}; +spine.TrackEntry.prototype = { + next: null, previous: null, + animation: null, + loop: false, + delay: 0, time: 0, lastTime: -1, endTime: 0, + timeScale: 1, + mixTime: 0, mixDuration: 0, mix: 1, + onStart: null, onEnd: null, onComplete: null, onEvent: null +}; + +spine.AnimationState = function (stateData) { + this.data = stateData; + this.tracks = []; + this.events = []; +}; +spine.AnimationState.prototype = { + onStart: null, + onEnd: null, + onComplete: null, + onEvent: null, + timeScale: 1, + update: function (delta) { + delta *= this.timeScale; + for (var i = 0; i < this.tracks.length; i++) { + var current = this.tracks[i]; + if (!current) continue; + + current.time += delta * current.timeScale; + if (current.previous) { + var previousDelta = delta * current.previous.timeScale; + current.previous.time += previousDelta; + current.mixTime += previousDelta; + } + + var next = current.next; + if (next) { + next.time = current.lastTime - next.delay; + if (next.time >= 0) this.setCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) this.clearTrack(i); + } + } + }, + apply: function (skeleton) { + for (var i = 0; i < this.tracks.length; i++) { + var current = this.tracks[i]; + if (!current) continue; + + this.events.length = 0; + + var time = current.time; + var lastTime = current.lastTime; + var endTime = current.endTime; + var loop = current.loop; + if (!loop && time > endTime) time = endTime; + + var previous = current.previous; + if (!previous) { + if (current.mix == 1) + current.animation.apply(skeleton, current.lastTime, time, loop, this.events); + else + current.animation.mix(skeleton, current.lastTime, time, loop, this.events, current.mix); + } else { + var previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); + + var alpha = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + current.previous = null; + } + current.animation.mix(skeleton, current.lastTime, time, loop, this.events, alpha); + } + + for (var ii = 0, nn = this.events.length; ii < nn; ii++) { + var event = this.events[ii]; + if (current.onEvent) current.onEvent(i, event); + if (this.onEvent) this.onEvent(i, event); + } + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + var count = Math.floor(time / endTime); + if (current.onComplete) current.onComplete(i, count); + if (this.onComplete) this.onComplete(i, count); + } + + current.lastTime = current.time; + } + }, + clearTracks: function () { + for (var i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + }, + clearTrack: function (trackIndex) { + if (trackIndex >= this.tracks.length) return; + var current = this.tracks[trackIndex]; + if (!current) return; + + if (current.onEnd) current.onEnd(trackIndex); + if (this.onEnd) this.onEnd(trackIndex); + + this.tracks[trackIndex] = null; + }, + _expandToIndex: function (index) { + if (index < this.tracks.length) return this.tracks[index]; + while (index >= this.tracks.length) + this.tracks.push(null); + return null; + }, + setCurrent: function (index, entry) { + var current = this._expandToIndex(index); + if (current) { + var previous = current.previous; + current.previous = null; + + if (current.onEnd) current.onEnd(index); + if (this.onEnd) this.onEnd(index); + + entry.mixDuration = this.data.getMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous && current.mixTime / current.mixDuration < 0.5) + entry.previous = previous; + else + entry.previous = current; + } + } + + this.tracks[index] = entry; + + if (entry.onStart) entry.onStart(index); + if (this.onStart) this.onStart(index); + }, + setAnimationByName: function (trackIndex, animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + return this.setAnimation(trackIndex, animation, loop); + }, + /** Set the current animation. Any queued animations are cleared. */ + setAnimation: function (trackIndex, animation, loop) { + var entry = new spine.TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + this.setCurrent(trackIndex, entry); + return entry; + }, + addAnimationByName: function (trackIndex, animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw "Animation not found: " + animationName; + return this.addAnimation(trackIndex, animation, loop, delay); + }, + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimation: function (trackIndex, animation, loop, delay) { + var entry = new spine.TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + + var last = this._expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + last.next = entry; + } else + this.tracks[trackIndex] = entry; + + if (delay <= 0) { + if (last) + delay += last.endTime - this.data.getMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + }, + /** May be null. */ + getCurrent: function (trackIndex) { + if (trackIndex >= this.tracks.length) return null; + return this.tracks[trackIndex]; + } +}; + +spine.SkeletonJson = function (attachmentLoader) { + this.attachmentLoader = attachmentLoader; +}; +spine.SkeletonJson.prototype = { + scale: 1, + readSkeletonData: function (root, name) { + var skeletonData = new spine.SkeletonData(); + skeletonData.name = name; + + // Skeleton. + var skeletonMap = root["skeleton"]; + if (skeletonMap) { + skeletonData.hash = skeletonMap["hash"]; + skeletonData.version = skeletonMap["spine"]; + skeletonData.width = skeletonMap["width"] || 0; + skeletonData.height = skeletonMap["height"] || 0; + } + + // Bones. + var bones = root["bones"]; + for (var i = 0, n = bones.length; i < n; i++) { + var boneMap = bones[i]; + var parent = null; + if (boneMap["parent"]) { + parent = skeletonData.findBone(boneMap["parent"]); + if (!parent) throw "Parent bone not found: " + boneMap["parent"]; + } + var boneData = new spine.BoneData(boneMap["name"], parent); + boneData.length = (boneMap["length"] || 0) * this.scale; + boneData.x = (boneMap["x"] || 0) * this.scale; + boneData.y = (boneMap["y"] || 0) * this.scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1; + boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1; + boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? boneMap["inheritScale"] : true; + boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? boneMap["inheritRotation"] : true; + skeletonData.bones.push(boneData); + } + + // IK constraints. + var ik = root["ik"]; + if (ik) { + for (var i = 0, n = ik.length; i < n; i++) { + var ikMap = ik[i]; + var ikConstraintData = new spine.IkConstraintData(ikMap["name"]); + + var bones = ikMap["bones"]; + for (var ii = 0, nn = bones.length; ii < nn; ii++) { + var bone = skeletonData.findBone(bones[ii]); + if (!bone) throw "IK bone not found: " + bones[ii]; + ikConstraintData.bones.push(bone); + } + + ikConstraintData.target = skeletonData.findBone(ikMap["target"]); + if (!ikConstraintData.target) throw "Target bone not found: " + ikMap["target"]; + + ikConstraintData.bendDirection = (!ikMap.hasOwnProperty("bendPositive") || ikMap["bendPositive"]) ? 1 : -1; + ikConstraintData.mix = ikMap.hasOwnProperty("mix") ? ikMap["mix"] : 1; + + skeletonData.ikConstraints.push(ikConstraintData); + } + } + + // Slots. + var slots = root["slots"]; + for (var i = 0, n = slots.length; i < n; i++) { + var slotMap = slots[i]; + var boneData = skeletonData.findBone(slotMap["bone"]); + if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; + var slotData = new spine.SlotData(slotMap["name"], boneData); + + var color = slotMap["color"]; + if (color) { + slotData.r = this.toColor(color, 0); + slotData.g = this.toColor(color, 1); + slotData.b = this.toColor(color, 2); + slotData.a = this.toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + slotData.additiveBlending = slotMap["additive"] && slotMap["additive"] == "true"; + + skeletonData.slots.push(slotData); + } + + // Skins. + var skins = root["skins"]; + for (var skinName in skins) { + if (!skins.hasOwnProperty(skinName)) continue; + var skinMap = skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + if (!skinMap.hasOwnProperty(slotName)) continue; + var slotIndex = skeletonData.findSlotIndex(slotName); + var slotEntry = skinMap[slotName]; + for (var attachmentName in slotEntry) { + if (!slotEntry.hasOwnProperty(attachmentName)) continue; + var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); + if (attachment) skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + + // Events. + var events = root["events"]; + for (var eventName in events) { + if (!events.hasOwnProperty(eventName)) continue; + var eventMap = events[eventName]; + var eventData = new spine.EventData(eventName); + eventData.intValue = eventMap["int"] || 0; + eventData.floatValue = eventMap["float"] || 0; + eventData.stringValue = eventMap["string"] || null; + skeletonData.events.push(eventData); + } + + // Animations. + var animations = root["animations"]; + for (var animationName in animations) { + if (!animations.hasOwnProperty(animationName)) continue; + this.readAnimation(animationName, animations[animationName], skeletonData); + } + + return skeletonData; + }, + readAttachment: function (skin, name, map) { + name = map["name"] || name; + + var type = spine.AttachmentType[map["type"] || "region"]; + var path = map["path"] || name; + + var scale = this.scale; + if (type == spine.AttachmentType.region) { + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (!region) return null; + region.path = path; + region.x = (map["x"] || 0) * scale; + region.y = (map["y"] || 0) * scale; + region.scaleX = map.hasOwnProperty("scaleX") ? map["scaleX"] : 1; + region.scaleY = map.hasOwnProperty("scaleY") ? map["scaleY"] : 1; + region.rotation = map["rotation"] || 0; + region.width = (map["width"] || 0) * scale; + region.height = (map["height"] || 0) * scale; + + var color = map["color"]; + if (color) { + region.r = this.toColor(color, 0); + region.g = this.toColor(color, 1); + region.b = this.toColor(color, 2); + region.a = this.toColor(color, 3); + } + + region.updateOffset(); + return region; + } else if (type == spine.AttachmentType.mesh) { + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (!mesh) return null; + mesh.path = path; + mesh.vertices = this.getFloatArray(map, "vertices", scale); + mesh.triangles = this.getIntArray(map, "triangles"); + mesh.regionUVs = this.getFloatArray(map, "uvs", 1); + mesh.updateUVs(); + + color = map["color"]; + if (color) { + mesh.r = this.toColor(color, 0); + mesh.g = this.toColor(color, 1); + mesh.b = this.toColor(color, 2); + mesh.a = this.toColor(color, 3); + } + + mesh.hullLength = (map["hull"] || 0) * 2; + if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); + mesh.width = (map["width"] || 0) * scale; + mesh.height = (map["height"] || 0) * scale; + return mesh; + } else if (type == spine.AttachmentType.skinnedmesh) { + var mesh = this.attachmentLoader.newSkinnedMeshAttachment(skin, name, path); + if (!mesh) return null; + mesh.path = path; + + var uvs = this.getFloatArray(map, "uvs", 1); + var vertices = this.getFloatArray(map, "vertices", 1); + var weights = []; + var bones = []; + for (var i = 0, n = vertices.length; i < n; ) { + var boneCount = vertices[i++] | 0; + bones[bones.length] = boneCount; + for (var nn = i + boneCount * 4; i < nn; ) { + bones[bones.length] = vertices[i]; + weights[weights.length] = vertices[i + 1] * scale; + weights[weights.length] = vertices[i + 2] * scale; + weights[weights.length] = vertices[i + 3]; + i += 4; + } + } + mesh.bones = bones; + mesh.weights = weights; + mesh.triangles = this.getIntArray(map, "triangles"); + mesh.regionUVs = uvs; + mesh.updateUVs(); + + color = map["color"]; + if (color) { + mesh.r = this.toColor(color, 0); + mesh.g = this.toColor(color, 1); + mesh.b = this.toColor(color, 2); + mesh.a = this.toColor(color, 3); + } + + mesh.hullLength = (map["hull"] || 0) * 2; + if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); + mesh.width = (map["width"] || 0) * scale; + mesh.height = (map["height"] || 0) * scale; + return mesh; + } else if (type == spine.AttachmentType.boundingbox) { + var attachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + var vertices = map["vertices"]; + for (var i = 0, n = vertices.length; i < n; i++) + attachment.vertices.push(vertices[i] * scale); + return attachment; + } + throw "Unknown attachment type: " + type; + }, + readAnimation: function (name, map, skeletonData) { + var timelines = []; + var duration = 0; + + var slots = map["slots"]; + for (var slotName in slots) { + if (!slots.hasOwnProperty(slotName)) continue; + var slotMap = slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + + for (var timelineName in slotMap) { + if (!slotMap.hasOwnProperty(timelineName)) continue; + var values = slotMap[timelineName]; + if (timelineName == "color") { + var timeline = new spine.ColorTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var color = valueMap["color"]; + var r = this.toColor(color, 0); + var g = this.toColor(color, 1); + var b = this.toColor(color, 2); + var a = this.toColor(color, 3); + timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + this.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); + + } else if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(values.length); + timeline.slotIndex = slotIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + + } else + throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; + } + } + + var bones = map["bones"]; + for (var boneName in bones) { + if (!bones.hasOwnProperty(boneName)) continue; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw "Bone not found: " + boneName; + var boneMap = bones[boneName]; + + for (var timelineName in boneMap) { + if (!boneMap.hasOwnProperty(timelineName)) continue; + var values = boneMap[timelineName]; + if (timelineName == "rotate") { + var timeline = new spine.RotateTimeline(values.length); + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + this.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + + } else if (timelineName == "translate" || timelineName == "scale") { + var timeline; + var timelineScale = 1; + if (timelineName == "scale") + timeline = new spine.ScaleTimeline(values.length); + else { + timeline = new spine.TranslateTimeline(values.length); + timelineScale = this.scale; + } + timeline.boneIndex = boneIndex; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var x = (valueMap["x"] || 0) * timelineScale; + var y = (valueMap["y"] || 0) * timelineScale; + timeline.setFrame(frameIndex, valueMap["time"], x, y); + this.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); + + } else if (timelineName == "flipX" || timelineName == "flipY") { + var x = timelineName == "flipX"; + var timeline = x ? new spine.FlipXTimeline(values.length) : new spine.FlipYTimeline(values.length); + timeline.boneIndex = boneIndex; + + var field = x ? "x" : "y"; + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + timeline.setFrame(frameIndex, valueMap["time"], valueMap[field] || false); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); + } else + throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; + } + } + + var ikMap = map["ik"]; + for (var ikConstraintName in ikMap) { + if (!ikMap.hasOwnProperty(ikConstraintName)) continue; + var ikConstraint = skeletonData.findIkConstraint(ikConstraintName); + var values = ikMap[ikConstraintName]; + var timeline = new spine.IkConstraintTimeline(values.length); + timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint); + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var mix = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; + var bendDirection = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; + timeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); + this.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]); + } + + var ffd = map["ffd"]; + for (var skinName in ffd) { + var skin = skeletonData.findSkin(skinName); + var slotMap = ffd[skinName]; + for (slotName in slotMap) { + var slotIndex = skeletonData.findSlotIndex(slotName); + var meshMap = slotMap[slotName]; + for (var meshName in meshMap) { + var values = meshMap[meshName]; + var timeline = new spine.FfdTimeline(values.length); + var attachment = skin.getAttachment(slotIndex, meshName); + if (!attachment) throw "FFD attachment not found: " + meshName; + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + var isMesh = attachment.type == spine.AttachmentType.mesh; + var vertexCount; + if (isMesh) + vertexCount = attachment.vertices.length; + else + vertexCount = attachment.weights.length / 3 * 2; + + var frameIndex = 0; + for (var i = 0, n = values.length; i < n; i++) { + var valueMap = values[i]; + var vertices; + if (!valueMap["vertices"]) { + if (isMesh) + vertices = attachment.vertices; + else { + vertices = []; + vertices.length = vertexCount; + } + } else { + var verticesValue = valueMap["vertices"]; + var vertices = []; + vertices.length = vertexCount; + var start = valueMap["offset"] || 0; + var nn = verticesValue.length; + if (this.scale == 1) { + for (var ii = 0; ii < nn; ii++) + vertices[ii + start] = verticesValue[ii]; + } else { + for (var ii = 0; ii < nn; ii++) + vertices[ii + start] = verticesValue[ii] * this.scale; + } + if (isMesh) { + var meshVertices = attachment.vertices; + for (var ii = 0, nn = vertices.length; ii < nn; ii++) + vertices[ii] += meshVertices[ii]; + } + } + + timeline.setFrame(frameIndex, valueMap["time"], vertices); + this.readCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines[timelines.length] = timeline; + duration = Math.max(duration, timeline.frames[timeline.frameCount - 1]); + } + } + } + + var drawOrderValues = map["drawOrder"]; + if (!drawOrderValues) drawOrderValues = map["draworder"]; + if (drawOrderValues) { + var timeline = new spine.DrawOrderTimeline(drawOrderValues.length); + var slotCount = skeletonData.slots.length; + var frameIndex = 0; + for (var i = 0, n = drawOrderValues.length; i < n; i++) { + var drawOrderMap = drawOrderValues[i]; + var drawOrder = null; + if (drawOrderMap["offsets"]) { + drawOrder = []; + drawOrder.length = slotCount; + for (var ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + var offsets = drawOrderMap["offsets"]; + var unchanged = []; + unchanged.length = slotCount - offsets.length; + var originalIndex = 0, unchangedIndex = 0; + for (var ii = 0, nn = offsets.length; ii < nn; ii++) { + var offsetMap = offsets[ii]; + var slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]); + if (slotIndex == -1) throw "Slot not found: " + offsetMap["slot"]; + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (var ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + + var events = map["events"]; + if (events) { + var timeline = new spine.EventTimeline(events.length); + var frameIndex = 0; + for (var i = 0, n = events.length; i < n; i++) { + var eventMap = events[i]; + var eventData = skeletonData.findEvent(eventMap["name"]); + if (!eventData) throw "Event not found: " + eventMap["name"]; + var event = new spine.Event(eventData); + event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; + event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; + event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; + timeline.setFrame(frameIndex++, eventMap["time"], event); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + }, + readCurve: function (timeline, frameIndex, valueMap) { + var curve = valueMap["curve"]; + if (!curve) + timeline.curves.setLinear(frameIndex); + else if (curve == "stepped") + timeline.curves.setStepped(frameIndex); + else if (curve instanceof Array) + timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); + }, + toColor: function (hexString, colorIndex) { + if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; + return parseInt(hexString.substring(colorIndex * 2, (colorIndex * 2) + 2), 16) / 255; + }, + getFloatArray: function (map, name, scale) { + var list = map[name]; + var values = new spine.Float32Array(list.length); + var i = 0, n = list.length; + if (scale == 1) { + for (; i < n; i++) + values[i] = list[i]; + } else { + for (; i < n; i++) + values[i] = list[i] * scale; + } + return values; + }, + getIntArray: function (map, name) { + var list = map[name]; + var values = new spine.Uint16Array(list.length); + for (var i = 0, n = list.length; i < n; i++) + values[i] = list[i] | 0; + return values; + } +}; + +spine.Atlas = function (atlasText, textureLoader) { + this.textureLoader = textureLoader; + this.pages = []; + this.regions = []; + + var reader = new spine.AtlasReader(atlasText); + var tuple = []; + tuple.length = 4; + var page = null; + while (true) { + var line = reader.readLine(); + if (line === null) break; + line = reader.trim(line); + if (!line.length) + page = null; + else if (!page) { + page = new spine.AtlasPage(); + page.name = line; + + if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + page.format = spine.Atlas.Format[tuple[0]]; + + reader.readTuple(tuple); + page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; + page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; + + var direction = reader.readValue(); + page.uWrap = spine.Atlas.TextureWrap.clampToEdge; + page.vWrap = spine.Atlas.TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "y") + page.vWrap = spine.Atlas.TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; + + textureLoader.load(page, line, this); + + this.pages.push(page); + + } else { + var region = new spine.AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + this.regions.push(region); + } + } +}; +spine.Atlas.prototype = { + findRegion: function (name) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + }, + dispose: function () { + var pages = this.pages; + for (var i = 0, n = pages.length; i < n; i++) + this.textureLoader.unload(pages[i].rendererObject); + }, + updateUVs: function (page) { + var regions = this.regions; + for (var i = 0, n = regions.length; i < n; i++) { + var region = regions[i]; + if (region.page != page) continue; + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.rotate) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + } + } +}; + +spine.Atlas.Format = { + alpha: 0, + intensity: 1, + luminanceAlpha: 2, + rgb565: 3, + rgba4444: 4, + rgb888: 5, + rgba8888: 6 +}; + +spine.Atlas.TextureFilter = { + nearest: 0, + linear: 1, + mipMap: 2, + mipMapNearestNearest: 3, + mipMapLinearNearest: 4, + mipMapNearestLinear: 5, + mipMapLinearLinear: 6 +}; + +spine.Atlas.TextureWrap = { + mirroredRepeat: 0, + clampToEdge: 1, + repeat: 2 +}; + +spine.AtlasPage = function () {}; +spine.AtlasPage.prototype = { + name: null, + format: null, + minFilter: null, + magFilter: null, + uWrap: null, + vWrap: null, + rendererObject: null, + width: 0, + height: 0 +}; + +spine.AtlasRegion = function () {}; +spine.AtlasRegion.prototype = { + page: null, + name: null, + x: 0, y: 0, + width: 0, height: 0, + u: 0, v: 0, u2: 0, v2: 0, + offsetX: 0, offsetY: 0, + originalWidth: 0, originalHeight: 0, + index: 0, + rotate: false, + splits: null, + pads: null +}; + +spine.AtlasReader = function (text) { + this.lines = text.split(/\r\n|\r|\n/); +}; +spine.AtlasReader.prototype = { + index: 0, + trim: function (value) { + return value.replace(/^\s+|\s+$/g, ""); + }, + readLine: function () { + if (this.index >= this.lines.length) return null; + return this.lines[this.index++]; + }, + readValue: function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + return this.trim(line.substring(colon + 1)); + }, + /** Returns the number of tuple values read (1, 2 or 4). */ + readTuple: function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) throw "Invalid line: " + line; + var i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) break; + tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = this.trim(line.substring(lastMatch)); + return i + 1; + } +}; + +spine.AtlasAttachmentLoader = function (atlas) { + this.atlas = atlas; +}; +spine.AtlasAttachmentLoader.prototype = { + newRegionAttachment: function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (!region) throw "Region not found in atlas: " + path + " (region attachment: " + name + ")"; + var attachment = new spine.RegionAttachment(name); + attachment.rendererObject = region; + attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + }, + newMeshAttachment: function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (!region) throw "Region not found in atlas: " + path + " (mesh attachment: " + name + ")"; + var attachment = new spine.MeshAttachment(name); + attachment.rendererObject = region; + attachment.regionU = region.u; + attachment.regionV = region.v; + attachment.regionU2 = region.u2; + attachment.regionV2 = region.v2; + attachment.regionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + }, + newSkinnedMeshAttachment: function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (!region) throw "Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"; + var attachment = new spine.SkinnedMeshAttachment(name); + attachment.rendererObject = region; + attachment.regionU = region.u; + attachment.regionV = region.v; + attachment.regionU2 = region.u2; + attachment.regionV2 = region.v2; + attachment.regionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + }, + newBoundingBoxAttachment: function (skin, name) { + return new spine.BoundingBoxAttachment(name); + } +}; + +spine.SkeletonBounds = function () { + this.polygonPool = []; + this.polygons = []; + this.boundingBoxes = []; +}; +spine.SkeletonBounds.prototype = { + minX: 0, minY: 0, maxX: 0, maxY: 0, + update: function (skeleton, updateAabb) { + var slots = skeleton.slots; + var slotCount = slots.length; + var x = skeleton.x, y = skeleton.y; + var boundingBoxes = this.boundingBoxes; + var polygonPool = this.polygonPool; + var polygons = this.polygons; + + boundingBoxes.length = 0; + for (var i = 0, n = polygons.length; i < n; i++) + polygonPool.push(polygons[i]); + polygons.length = 0; + + for (var i = 0; i < slotCount; i++) { + var slot = slots[i]; + var boundingBox = slot.attachment; + if (boundingBox.type != spine.AttachmentType.boundingbox) continue; + boundingBoxes.push(boundingBox); + + var poolCount = polygonPool.length, polygon; + if (poolCount > 0) { + polygon = polygonPool[poolCount - 1]; + polygonPool.splice(poolCount - 1, 1); + } else + polygon = []; + polygons.push(polygon); + + polygon.length = boundingBox.vertices.length; + boundingBox.computeWorldVertices(x, y, slot.bone, polygon); + } + + if (updateAabb) this.aabbCompute(); + }, + aabbCompute: function () { + var polygons = this.polygons; + var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; + for (var i = 0, n = polygons.length; i < n; i++) { + var vertices = polygons[i]; + for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { + var x = vertices[ii]; + var y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + }, + /** Returns true if the axis aligned bounding box contains the point. */ + aabbContainsPoint: function (x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + }, + /** Returns true if the axis aligned bounding box intersects the line segment. */ + aabbIntersectsSegment: function (x1, y1, x2, y2) { + var minX = this.minX, minY = this.minY, maxX = this.maxX, maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + var m = (y2 - y1) / (x2 - x1); + var y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + var x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + }, + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + aabbIntersectsSkeleton: function (bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + }, + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + containsPoint: function (x, y) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.polygonContainsPoint(polygons[i], x, y)) return this.boundingBoxes[i]; + return null; + }, + /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ + intersectsSegment: function (x1, y1, x2, y2) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return this.boundingBoxes[i]; + return null; + }, + /** Returns true if the polygon contains the point. */ + polygonContainsPoint: function (polygon, x, y) { + var nn = polygon.length; + var prevIndex = nn - 2; + var inside = false; + for (var ii = 0; ii < nn; ii += 2) { + var vertexY = polygon[ii + 1]; + var prevY = polygon[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + var vertexX = polygon[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + }, + /** Returns true if the polygon contains the line segment. */ + polygonIntersectsSegment: function (polygon, x1, y1, x2, y2) { + var nn = polygon.length; + var width12 = x1 - x2, height12 = y1 - y2; + var det1 = x1 * y2 - y1 * x2; + var x3 = polygon[nn - 2], y3 = polygon[nn - 1]; + for (var ii = 0; ii < nn; ii += 2) { + var x4 = polygon[ii], y4 = polygon[ii + 1]; + var det2 = x3 * y4 - y3 * x4; + var width34 = x3 - x4, height34 = y3 - y4; + var det3 = width12 * height34 - height12 * width34; + var x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + var y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + }, + getPolygon: function (attachment) { + var index = this.boundingBoxes.indexOf(attachment); + return index == -1 ? null : this.polygons[index]; + }, + getWidth: function () { + return this.maxX - this.minX; + }, + getHeight: function () { + return this.maxY - this.minY; + } +}; \ No newline at end of file diff --git a/external/chipmunk/chipmunk.js b/external/chipmunk/chipmunk.js old mode 100755 new mode 100644 index 38d0d8c191..3be84bfc61 --- a/external/chipmunk/chipmunk.js +++ b/external/chipmunk/chipmunk.js @@ -1,1318 +1,1502 @@ (function(){ - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - Object.create = Object.create || function(o) { - function F() {} - F.prototype = o; - return new F(); - }; - +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +Object.create = Object.create || function(o) { + function F() {} + F.prototype = o; + return new F(); +}; + //var VERSION = CP_VERSION_MAJOR + "." + CP_VERSION_MINOR + "." + CP_VERSION_RELEASE; - var cp; - if(typeof exports === 'undefined'){ - cp = {}; - if(typeof window === 'object'){ - window["cp"] = cp; - } - } else { - cp = exports; - } - - var assert = function(value, message) - { - if (!value) { - throw new Error('Assertion failed: ' + message); - } - }; - - var assertSoft = function(value, message) - { - if(!value && console && console.warn) { - console.warn("ASSERTION FAILED: " + message); - if(console.trace) { - console.trace(); - } - } - }; - - var mymin = function(a, b) - { - return a < b ? a : b; - }; - var mymax = function(a, b) - { - return a > b ? a : b; - }; - - var min, max; - if (typeof window === 'object' && window.navigator.userAgent.indexOf('Firefox') > -1){ - // On firefox, Math.min and Math.max are really fast: - // http://jsperf.com/math-vs-greater-than/8 - min = Math.min; - max = Math.max; - } else { - // On chrome and safari, Math.min / max are slooow. The ternery operator above is faster - // than the builtins because we only have to deal with 2 arguments that are always numbers. - min = mymin; - max = mymax; - } - - /* The hashpair function takes two numbers and returns a hash code for them. - * Required that hashPair(a, b) === hashPair(b, a). - * Chipmunk's hashPair function is defined as: - * #define CP_HASH_COEF (3344921057ul) - * #define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF) - * But thats not suitable in javascript because multiplying by a large number will make the number - * a large float. - * - * The result of hashPair is used as the key in objects, so it returns a string. - */ - var hashPair = function(a, b) - { - //assert(typeof(a) === 'number', "HashPair used on something not a number"); - return a < b ? a + ' ' + b : b + ' ' + a; - }; - - var deleteObjFromList = function(arr, obj) - { - for(var i=0; i b ? a : b; +}; + +var min, max; +if (typeof window === 'object' && window.navigator.userAgent.indexOf('Firefox') > -1){ + // On firefox, Math.min and Math.max are really fast: + // http://jsperf.com/math-vs-greater-than/8 + min = Math.min; + max = Math.max; +} else { + // On chrome and safari, Math.min / max are slooow. The ternery operator above is faster + // than the builtins because we only have to deal with 2 arguments that are always numbers. + min = mymin; + max = mymax; +} + +/* The hashpair function takes two numbers and returns a hash code for them. + * Required that hashPair(a, b) === hashPair(b, a). + * Chipmunk's hashPair function is defined as: + * #define CP_HASH_COEF (3344921057ul) + * #define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF) + * But thats not suitable in javascript because multiplying by a large number will make the number + * a large float. + * + * The result of hashPair is used as the key in objects, so it returns a string. + */ +var hashPair = function(a, b) +{ + //assert(typeof(a) === 'number', "HashPair used on something not a number"); + return a < b ? a + ' ' + b : b + ' ' + a; +}; + +var deleteObjFromList = function(arr, obj) +{ + for(var i=0; i> 1; + for(var i=1; i maxx || (x == maxx && y > maxy)){ + maxx = x; + maxy = y; + end = i; + } + } + return [start, end]; +}; + +var SWAP = function(arr, idx1, idx2) +{ + var tmp = arr[idx1*2]; + arr[idx1*2] = arr[idx2*2]; + arr[idx2*2] = tmp; + + tmp = arr[idx1*2+1]; + arr[idx1*2+1] = arr[idx2*2+1]; + arr[idx2*2+1] = tmp; +}; + +var QHullPartition = function(verts, offs, count, a, b, tol) +{ + if(count === 0) return 0; + + var max = 0; + var pivot = offs; + + var delta = vsub(b, a); + var valueTol = tol * vlength(delta); + + var head = offs; + for(var tail = offs+count-1; head <= tail;){ + var v = new Vect(verts[head * 2], verts[head * 2 + 1]); + var value = vcross(delta, vsub(v, a)); + if(value > valueTol){ + if(value > max){ + max = value; + pivot = head; + } + + head++; + } else { + SWAP(verts, head, tail); + tail--; + } + } + + // move the new pivot to the front if it's not already there. + if(pivot != offs) SWAP(verts, offs, pivot); + return head - offs; +}; + +var QHullReduce = function(tol, verts, offs, count, a, pivot, b, resultPos) +{ + if(count < 0){ + return 0; + } else if(count == 0) { + verts[resultPos*2] = pivot.x; + verts[resultPos*2+1] = pivot.y; + return 1; + } else { + var left_count = QHullPartition(verts, offs, count, a, pivot, tol); + var left = new Vect(verts[offs*2], verts[offs*2+1]); + var index = QHullReduce(tol, verts, offs + 1, left_count - 1, a, left, pivot, resultPos); + + var pivotPos = resultPos + index++; + verts[pivotPos*2] = pivot.x; + verts[pivotPos*2+1] = pivot.y; + + var right_count = QHullPartition(verts, offs + left_count, count - left_count, pivot, b, tol); + var right = new Vect(verts[(offs+left_count)*2], verts[(offs+left_count)*2+1]); + return index + QHullReduce(tol, verts, offs + left_count + 1, right_count - 1, pivot, right, b, resultPos + index); + } +}; + +// QuickHull seemed like a neat algorithm, and efficient-ish for large input sets. +// My implementation performs an in place reduction using the result array as scratch space. +// +// Pass an Array into result to put the result of the calculation there. Otherwise, pass null +// and the verts list will be edited in-place. +// +// Expects the verts to be described in the same way as cpPolyShape - which is to say, it should +// be a list of [x1,y1,x2,y2,x3,y3,...]. +// +// tolerance is in world coordinates. Eg, 2. +cp.convexHull = function(verts, result, tolerance) +{ + if(result){ + // Copy the line vertexes into the empty part of the result polyline to use as a scratch buffer. + for (var i = 0; i < verts.length; i++){ + result[i] = verts[i]; + } + } else { + // If a result array was not specified, reduce the input instead. + result = verts; + } + + // Degenerate case, all points are the same. + var indexes = loopIndexes(verts); + var start = indexes[0], end = indexes[1]; + if(start == end){ + //if(first) (*first) = 0; + result.length = 2; + return result; + } + + SWAP(result, 0, start); + SWAP(result, 1, end == 0 ? start : end); + + var a = new Vect(result[0], result[1]); + var b = new Vect(result[2], result[3]); + + var count = verts.length >> 1; + //if(first) (*first) = start; + var resultCount = QHullReduce(tolerance, result, 2, count - 2, a, b, a, 1) + 1; + result.length = resultCount*2; + + assertSoft(polyValidate(result), + "Internal error: cpConvexHull() and cpPolyValidate() did not agree." + + "Please report this error with as much info as you can."); + return result; +}; /// Clamp @c f to be between @c min and @c max. - var clamp = function(f, minv, maxv) - { - return min(max(f, minv), maxv); - }; +var clamp = function(f, minv, maxv) +{ + return min(max(f, minv), maxv); +}; /// Clamp @c f to be between 0 and 1. - var clamp01 = cp.clamp01 = function(f) - { - return max(0, min(f, 1)); - }; +var clamp01 = function(f) +{ + return max(0, min(f, 1)); +}; /// Linearly interpolate (or extrapolate) between @c f1 and @c f2 by @c t percent. - var lerp = function(f1, f2, t) - { - return f1*(1 - t) + f2*t; - }; +var lerp = function(f1, f2, t) +{ + return f1*(1 - t) + f2*t; +}; /// Linearly interpolate from @c f1 to @c f2 by no more than @c d. - var lerpconst = function(f1, f2, d) - { - return f1 + clamp(f2 - f1, -d, d); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +var lerpconst = function(f1, f2, d) +{ + return f1 + clamp(f2 - f1, -d, d); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ // I'm using an array tuple here because (at time of writing) its about 3x faster // than an object on firefox, and the same speed on chrome. - var numVects = 0; - - var traces = {}; +//var numVects = 0; - var Vect = cp.Vect = function(x, y) - { - this.x = x; - this.y = y; - numVects++; +var Vect = cp.Vect = function(x, y) +{ + this.x = x; + this.y = y; + //numVects++; // var s = new Error().stack; // traces[s] = traces[s] ? traces[s]+1 : 1; - }; +}; - cp.v = function (x,y) { return new Vect(x, y) }; +cp.v = function (x,y) { return new Vect(x, y) }; - var vzero = cp.vzero = new Vect(0,0); +var vzero = cp.vzero = new Vect(0,0); // The functions below *could* be rewritten to be instance methods on Vect. I don't // know how that would effect performance. For now, I'm keeping the JS similar to // the original C code. /// Vector dot product. - var vdot = cp.v.dot = function(v1, v2) - { - return v1.x*v2.x + v1.y*v2.y; - }; +var vdot = cp.v.dot = function(v1, v2) +{ + return v1.x*v2.x + v1.y*v2.y; +}; - var vdot2 = function(x1, y1, x2, y2) - { - return x1*x2 + y1*y2; - }; +var vdot2 = function(x1, y1, x2, y2) +{ + return x1*x2 + y1*y2; +}; /// Returns the length of v. - var vlength = cp.v.len = function(v) - { - return Math.sqrt(vdot(v, v)); - }; +var vlength = cp.v.len = function(v) +{ + return Math.sqrt(vdot(v, v)); +}; + +var vlength2 = cp.v.len2 = function(x, y) +{ + return Math.sqrt(x*x + y*y); +}; /// Check if two vectors are equal. (Be careful when comparing floating point numbers!) - var veql = cp.v.eql = function(v1, v2) - { - return (v1.x === v2.x && v1.y === v2.y); - }; +var veql = cp.v.eql = function(v1, v2) +{ + return (v1.x === v2.x && v1.y === v2.y); +}; /// Add two vectors - var vadd = cp.v.add = function(v1, v2) - { - return new Vect(v1.x + v2.x, v1.y + v2.y); - }; - - Vect.prototype.add = function(v2) - { - this.x += v2.x; - this.y += v2.y; - return this; - }; +var vadd = cp.v.add = function(v1, v2) +{ + return new Vect(v1.x + v2.x, v1.y + v2.y); +}; + +Vect.prototype.add = function(v2) +{ + this.x += v2.x; + this.y += v2.y; + return this; +}; /// Subtract two vectors. - var vsub = cp.v.sub = function(v1, v2) - { - return new Vect(v1.x - v2.x, v1.y - v2.y); - }; - - Vect.prototype.sub = function(v2) - { - this.x -= v2.x; - this.y -= v2.y; - return this; - }; +var vsub = cp.v.sub = function(v1, v2) +{ + return new Vect(v1.x - v2.x, v1.y - v2.y); +}; + +Vect.prototype.sub = function(v2) +{ + this.x -= v2.x; + this.y -= v2.y; + return this; +}; /// Negate a vector. - var vneg = cp.v.neg = function(v) - { - return new Vect(-v.x, -v.y); - }; - - Vect.prototype.neg = function() - { - this.x = -this.x; - this.y = -this.y; - return this; - }; +var vneg = cp.v.neg = function(v) +{ + return new Vect(-v.x, -v.y); +}; + +Vect.prototype.neg = function() +{ + this.x = -this.x; + this.y = -this.y; + return this; +}; /// Scalar multiplication. - var vmult = cp.v.mult = function(v, s) - { - return new Vect(v.x*s, v.y*s); - }; - - Vect.prototype.mult = function(s) - { - this.x *= s; - this.y *= s; - return this; - }; +var vmult = cp.v.mult = function(v, s) +{ + return new Vect(v.x*s, v.y*s); +}; + +Vect.prototype.mult = function(s) +{ + this.x *= s; + this.y *= s; + return this; +}; /// 2D vector cross product analog. /// The cross product of 2D vectors results in a 3D vector with only a z component. /// This function returns the magnitude of the z value. - var vcross = cp.v.cross = function(v1, v2) - { - return v1.x*v2.y - v1.y*v2.x; - }; +var vcross = cp.v.cross = function(v1, v2) +{ + return v1.x*v2.y - v1.y*v2.x; +}; - var vcross2 = function(x1, y1, x2, y2) - { - return x1*y2 - y1*x2; - }; +var vcross2 = function(x1, y1, x2, y2) +{ + return x1*y2 - y1*x2; +}; /// Returns a perpendicular vector. (90 degree rotation) - var vperp = cp.v.perp = function(v) - { - return new Vect(-v.y, v.x); - }; +var vperp = cp.v.perp = function(v) +{ + return new Vect(-v.y, v.x); +}; /// Returns a perpendicular vector. (-90 degree rotation) - var vpvrperp = cp.v.pvrperp = function(v) - { - return new Vect(v.y, -v.x); - }; +var vpvrperp = cp.v.pvrperp = function(v) +{ + return new Vect(v.y, -v.x); +}; /// Returns the vector projection of v1 onto v2. - var vproject = cp.v.project = function(v1, v2) - { - return vmult(v2, vdot(v1, v2)/vlengthsq(v2)); - }; +var vproject = cp.v.project = function(v1, v2) +{ + return vmult(v2, vdot(v1, v2)/vlengthsq(v2)); +}; - Vect.prototype.project = function(v2) - { - this.mult(vdot(this, v2) / vlengthsq(v2)); - return this; - }; +Vect.prototype.project = function(v2) +{ + this.mult(vdot(this, v2) / vlengthsq(v2)); + return this; +}; /// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector. - var vrotate = cp.v.rotate = function(v1, v2) - { - return new Vect(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); - }; - - Vect.prototype.rotate = function(v2) - { - this.x = this.x * v2.x - this.y * v2.y; - this.y = this.x * v2.y + this.y * v2.x; - return this; - }; +var vrotate = cp.v.rotate = function(v1, v2) +{ + return new Vect(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); +}; + +Vect.prototype.rotate = function(v2) +{ + this.x = this.x * v2.x - this.y * v2.y; + this.y = this.x * v2.y + this.y * v2.x; + return this; +}; /// Inverse of vrotate(). - var vunrotate = cp.v.unrotate = function(v1, v2) - { - return new Vect(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); - }; +var vunrotate = cp.v.unrotate = function(v1, v2) +{ + return new Vect(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); +}; /// Returns the squared length of v. Faster than vlength() when you only need to compare lengths. - var vlengthsq = cp.v.lengthsq = function(v) - { - return vdot(v, v); - }; +var vlengthsq = cp.v.lengthsq = function(v) +{ + return vdot(v, v); +}; + +var vlengthsq2 = cp.v.lengthsq2 = function(x, y) +{ + return x*x + y*y; +}; /// Linearly interpolate between v1 and v2. - var vlerp = cp.v.lerp = function(v1, v2, t) - { - return vadd(vmult(v1, 1 - t), vmult(v2, t)); - }; +var vlerp = cp.v.lerp = function(v1, v2, t) +{ + return vadd(vmult(v1, 1 - t), vmult(v2, t)); +}; /// Returns a normalized copy of v. - var vnormalize = cp.v.normalize = function(v) - { - return vmult(v, 1/vlength(v)); - }; +var vnormalize = cp.v.normalize = function(v) +{ + return vmult(v, 1/vlength(v)); +}; /// Returns a normalized copy of v or vzero if v was already vzero. Protects against divide by zero errors. - var vnormalize_safe = cp.v.normalize_safe = function(v) - { - return (v.x === 0 && v.y === 0 ? vzero : vnormalize(v)); - }; +var vnormalize_safe = cp.v.normalize_safe = function(v) +{ + return (v.x === 0 && v.y === 0 ? vzero : vnormalize(v)); +}; /// Clamp v to length len. - var vclamp = cp.v.clamp = function(v, len) - { - return (vdot(v,v) > len*len) ? vmult(vnormalize(v), len) : v; - }; +var vclamp = cp.v.clamp = function(v, len) +{ + return (vdot(v,v) > len*len) ? vmult(vnormalize(v), len) : v; +}; /// Linearly interpolate between v1 towards v2 by distance d. - var vlerpconst = cp.v.lerpconst = function(v1, v2, d) - { - return vadd(v1, vclamp(vsub(v2, v1), d)); - }; +var vlerpconst = cp.v.lerpconst = function(v1, v2, d) +{ + return vadd(v1, vclamp(vsub(v2, v1), d)); +}; /// Returns the distance between v1 and v2. - var vdist = cp.v.dist = function(v1, v2) - { - return vlength(vsub(v1, v2)); - }; +var vdist = cp.v.dist = function(v1, v2) +{ + return vlength(vsub(v1, v2)); +}; /// Returns the squared distance between v1 and v2. Faster than vdist() when you only need to compare distances. - var vdistsq = cp.v.distsq = function(v1, v2) - { - return vlengthsq(vsub(v1, v2)); - }; +var vdistsq = cp.v.distsq = function(v1, v2) +{ + return vlengthsq(vsub(v1, v2)); +}; /// Returns true if the distance between v1 and v2 is less than dist. - var vnear = cp.v.near = function(v1, v2, dist) - { - return vdistsq(v1, v2) < dist*dist; - }; +var vnear = cp.v.near = function(v1, v2, dist) +{ + return vdistsq(v1, v2) < dist*dist; +}; /// Spherical linearly interpolate between v1 and v2. - var vslerp = cp.v.slerp = function(v1, v2, t) - { - var omega = Math.acos(vdot(v1, v2)); - - if(omega) { - var denom = 1/Math.sin(omega); - return vadd(vmult(v1, Math.sin((1 - t)*omega)*denom), vmult(v2, Math.sin(t*omega)*denom)); - } else { - return v1; - } - }; +var vslerp = cp.v.slerp = function(v1, v2, t) +{ + var omega = Math.acos(vdot(v1, v2)); + + if(omega) { + var denom = 1/Math.sin(omega); + return vadd(vmult(v1, Math.sin((1 - t)*omega)*denom), vmult(v2, Math.sin(t*omega)*denom)); + } else { + return v1; + } +}; /// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians - var vslerpconst = cp.v.slerpconst = function(v1, v2, a) - { - var angle = Math.acos(vdot(v1, v2)); - return vslerp(v1, v2, min(a, angle)/angle); - }; +var vslerpconst = cp.v.slerpconst = function(v1, v2, a) +{ + var angle = Math.acos(vdot(v1, v2)); + return vslerp(v1, v2, min(a, angle)/angle); +}; /// Returns the unit length vector for the given angle (in radians). - var vforangle = cp.v.forangle = function(a) - { - return new Vect(Math.cos(a), Math.sin(a)); - }; +var vforangle = cp.v.forangle = function(a) +{ + return new Vect(Math.cos(a), Math.sin(a)); +}; /// Returns the angular direction v is pointing in (in radians). - var vtoangle = cp.v.toangle = function(v) - { - return Math.atan2(v.y, v.x); - }; +var vtoangle = cp.v.toangle = function(v) +{ + return Math.atan2(v.y, v.x); +}; /// Returns a string representation of v. Intended mostly for debugging purposes and not production use. - var vstr = cp.v.str = function(v) - { - return "(" + v.x.toFixed(3) + ", " + v.y.toFixed(3) + ")"; - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +var vstr = cp.v.str = function(v) +{ + return "(" + v.x.toFixed(3) + ", " + v.y.toFixed(3) + ")"; +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ /// Chipmunk's axis-aligned 2D bounding box type along with a few handy routines. - var numBB = 0; +var numBB = 0; // Bounding boxes are JS objects with {l, b, r, t} = left, bottom, right, top, respectively. - var BB = cp.BB = function(l, b, r, t) - { - this.l = l; - this.b = b; - this.r = r; - this.t = t; - - numBB++; - }; - - cp.bb = function(l, b, r, t) { return new BB(l, b, r, t); }; - - var bbNewForCircle = function(p, r) - { - return new BB( - p.x - r, - p.y - r, - p.x + r, - p.y + r - ); - }; +var BB = cp.BB = function(l, b, r, t) +{ + this.l = l; + this.b = b; + this.r = r; + this.t = t; + + numBB++; +}; + +cp.bb = function(l, b, r, t) { return new BB(l, b, r, t); }; + +var bbNewForCircle = function(p, r) +{ + return new BB( + p.x - r, + p.y - r, + p.x + r, + p.y + r + ); +}; /// Returns true if @c a and @c b intersect. - var bbIntersects = function(a, b) - { - return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t); - }; - var bbIntersects2 = function(bb, l, b, r, t) - { - return (bb.l <= r && l <= bb.r && bb.b <= t && b <= bb.t); - }; +var bbIntersects = function(a, b) +{ + return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t); +}; +var bbIntersects2 = function(bb, l, b, r, t) +{ + return (bb.l <= r && l <= bb.r && bb.b <= t && b <= bb.t); +}; /// Returns true if @c other lies completely within @c bb. - var bbContainsBB = function(bb, other) - { - return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t); - }; +var bbContainsBB = function(bb, other) +{ + return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t); +}; /// Returns true if @c bb contains @c v. - var bbContainsVect = function(bb, v) - { - return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y); - }; - var bbContainsVect2 = function(l, b, r, t, v) - { - return (l <= v.x && r >= v.x && b <= v.y && t >= v.y); - }; +var bbContainsVect = function(bb, v) +{ + return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y); +}; +var bbContainsVect2 = function(l, b, r, t, v) +{ + return (l <= v.x && r >= v.x && b <= v.y && t >= v.y); +}; /// Returns a bounding box that holds both bounding boxes. - var bbMerge = function(a, b){ - return new BB( - min(a.l, b.l), - min(a.b, b.b), - max(a.r, b.r), - max(a.t, b.t) - ); - }; +var bbMerge = function(a, b){ + return new BB( + min(a.l, b.l), + min(a.b, b.b), + max(a.r, b.r), + max(a.t, b.t) + ); +}; /// Returns a bounding box that holds both @c bb and @c v. - var bbExpand = function(bb, v){ - return new BB( - min(bb.l, v.x), - min(bb.b, v.y), - max(bb.r, v.x), - max(bb.t, v.y) - ); - }; +var bbExpand = function(bb, v){ + return new BB( + min(bb.l, v.x), + min(bb.b, v.y), + max(bb.r, v.x), + max(bb.t, v.y) + ); +}; /// Returns the area of the bounding box. - var bbArea = function(bb) - { - return (bb.r - bb.l)*(bb.t - bb.b); - }; +var bbArea = function(bb) +{ + return (bb.r - bb.l)*(bb.t - bb.b); +}; /// Merges @c a and @c b and returns the area of the merged bounding box. - var bbMergedArea = function(a, b) - { - return (max(a.r, b.r) - min(a.l, b.l))*(max(a.t, b.t) - min(a.b, b.b)); - }; +var bbMergedArea = function(a, b) +{ + return (max(a.r, b.r) - min(a.l, b.l))*(max(a.t, b.t) - min(a.b, b.b)); +}; - var bbMergedArea2 = function(bb, l, b, r, t) - { - return (max(bb.r, r) - min(bb.l, l))*(max(bb.t, t) - min(bb.b, b)); - }; +var bbMergedArea2 = function(bb, l, b, r, t) +{ + return (max(bb.r, r) - min(bb.l, l))*(max(bb.t, t) - min(bb.b, b)); +}; /// Return true if the bounding box intersects the line segment with ends @c a and @c b. - var bbIntersectsSegment = function(bb, a, b) - { - return (bbSegmentQuery(bb, a, b) != Infinity); - }; +var bbIntersectsSegment = function(bb, a, b) +{ + return (bbSegmentQuery(bb, a, b) != Infinity); +}; /// Clamp a vector to a bounding box. - var bbClampVect = function(bb, v) - { - var x = min(max(bb.l, v.x), bb.r); - var y = min(max(bb.b, v.y), bb.t); - return new Vect(x, y); - }; +var bbClampVect = function(bb, v) +{ + var x = min(max(bb.l, v.x), bb.r); + var y = min(max(bb.b, v.y), bb.t); + return new Vect(x, y); +}; // TODO edge case issue /// Wrap a vector to a bounding box. - var bbWrapVect = function(bb, v) - { - var ix = Math.abs(bb.r - bb.l); - var modx = (v.x - bb.l) % ix; - var x = (modx > 0) ? modx : modx + ix; - - var iy = Math.abs(bb.t - bb.b); - var mody = (v.y - bb.b) % iy; - var y = (mody > 0) ? mody : mody + iy; - - return new Vect(x + bb.l, y + bb.b); - }; - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - +var bbWrapVect = function(bb, v) +{ + var ix = Math.abs(bb.r - bb.l); + var modx = (v.x - bb.l) % ix; + var x = (modx > 0) ? modx : modx + ix; + + var iy = Math.abs(bb.t - bb.b); + var mody = (v.y - bb.b) % iy; + var y = (mody > 0) ? mody : mody + iy; + + return new Vect(x + bb.l, y + bb.b); +}; +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + /// Segment query info struct. - /* These are created using literals where needed. - typedef struct cpSegmentQueryInfo { - /// The shape that was hit, null if no collision occured. - cpShape *shape; - /// The normalized distance along the query segment in the range [0, 1]. - cpFloat t; - /// The normal of the surface hit. - cpVect n; - } cpSegmentQueryInfo; - */ - - var shapeIDCounter = 0; - - var CP_NO_GROUP = cp.NO_GROUP = 0; - var CP_ALL_LAYERS = cp.ALL_LAYERS = ~0; - - cp.resetShapeIdCounter = function() - { - shapeIDCounter = 0; - }; +/* These are created using literals where needed. +typedef struct cpSegmentQueryInfo { + /// The shape that was hit, null if no collision occured. + cpShape *shape; + /// The normalized distance along the query segment in the range [0, 1]. + cpFloat t; + /// The normal of the surface hit. + cpVect n; +} cpSegmentQueryInfo; +*/ + +var shapeIDCounter = 0; + +var CP_NO_GROUP = cp.NO_GROUP = 0; +var CP_ALL_LAYERS = cp.ALL_LAYERS = ~0; + +cp.resetShapeIdCounter = function() +{ + shapeIDCounter = 0; +}; /// The cpShape struct defines the shape of a rigid body. // /// Opaque collision shape struct. Do not create directly - instead use /// PolyShape, CircleShape and SegmentShape. - var Shape = cp.Shape = function(body) { - /// The rigid body this collision shape is attached to. - this.body = body; - - /// The current bounding box of the shape. - this.bb_l = this.bb_b = this.bb_r = this.bb_t = 0; - - this.hashid = shapeIDCounter++; - - /// Sensor flag. - /// Sensor shapes call collision callbacks but don't produce collisions. - this.sensor = false; - - /// Coefficient of restitution. (elasticity) - this.e = 0; - /// Coefficient of friction. - this.u = 0; - /// Surface velocity used when solving for friction. - this.surface_v = vzero; - - /// Collision type of this shape used when picking collision handlers. - this.collision_type = 0; - /// Group of this shape. Shapes in the same group don't collide. - this.group = 0; - // Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero. - this.layers = CP_ALL_LAYERS; - - this.space = null; - - // Copy the collision code from the prototype into the actual object. This makes collision - // function lookups slightly faster. - this.collisionCode = this.collisionCode; - }; - - Shape.prototype.setElasticity = function(e) { this.e = e; }; - Shape.prototype.setFriction = function(u) { this.body.activate(); this.u = u; }; - Shape.prototype.setLayers = function(layers) { this.body.activate(); this.layers = layers; }; - Shape.prototype.setSensor = function(sensor) { this.body.activate(); this.sensor = sensor; }; - Shape.prototype.setCollisionType = function(collision_type) { this.body.activate(); this.collision_type = collision_type; }; - Shape.prototype.getBody = function() { return this.body; }; - - Shape.prototype.active = function() - { -// return shape->prev || shape->body->shapeList == shape; - return this.body && this.body.shapeList.indexOf(this) !== -1; - }; - - Shape.prototype.setBody = function(body) - { - assert(!this.active(), "You cannot change the body on an active shape. You must remove the shape, then "); - this.body = body; - }; - - Shape.prototype.cacheBB = function() - { - return this.update(this.body.p, this.body.rot); - }; - - Shape.prototype.update = function(pos, rot) - { - assert(!isNaN(rot.x), 'Rotation is NaN'); - assert(!isNaN(pos.x), 'Position is NaN'); - this.cacheData(pos, rot); - }; - - Shape.prototype.getBB = function() - { - return new BB(this.bb_l, this.bb_b, this.bb_r, this.bb_t); - }; - - /* Not implemented - all these getters and setters. Just edit the object directly. - CP_DefineShapeStructGetter(cpBody*, body, Body); - void cpShapeSetBody(cpShape *shape, cpBody *body); - - CP_DefineShapeStructGetter(cpBB, bb, BB); - CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue); - CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse); - CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue); - CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue); - CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse); - CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue); - CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue); - CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue); - */ +var Shape = cp.Shape = function(body) { + /// The rigid body this collision shape is attached to. + this.body = body; + + /// The current bounding box of the shape. + this.bb_l = this.bb_b = this.bb_r = this.bb_t = 0; + + this.hashid = shapeIDCounter++; + + /// Sensor flag. + /// Sensor shapes call collision callbacks but don't produce collisions. + this.sensor = false; + + /// Coefficient of restitution. (elasticity) + this.e = 0; + /// Coefficient of friction. + this.u = 0; + /// Surface velocity used when solving for friction. + this.surface_v = vzero; + + /// Collision type of this shape used when picking collision handlers. + this.collision_type = 0; + /// Group of this shape. Shapes in the same group don't collide. + this.group = 0; + // Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero. + this.layers = CP_ALL_LAYERS; + + this.space = null; + + // Copy the collision code from the prototype into the actual object. This makes collision + // function lookups slightly faster. + this.collisionCode = this.collisionCode; +}; + +Shape.prototype.setElasticity = function(e) { this.e = e; }; +Shape.prototype.setFriction = function(u) { this.body.activate(); this.u = u; }; +Shape.prototype.setLayers = function(layers) { this.body.activate(); this.layers = layers; }; +Shape.prototype.setSensor = function(sensor) { this.body.activate(); this.sensor = sensor; }; +Shape.prototype.setCollisionType = function(collision_type) { this.body.activate(); this.collision_type = collision_type; }; +Shape.prototype.getBody = function() { return this.body; }; + +Shape.prototype.active = function() +{ +// return shape->prev || (shape->body && shape->body->shapeList == shape); + return this.body && this.body.shapeList.indexOf(this) !== -1; +}; + +Shape.prototype.setBody = function(body) +{ + assert(!this.active(), "You cannot change the body on an active shape. You must remove the shape from the space before changing the body."); + this.body = body; +}; + +Shape.prototype.cacheBB = function() +{ + return this.update(this.body.p, this.body.rot); +}; + +Shape.prototype.update = function(pos, rot) +{ + assert(!isNaN(rot.x), 'Rotation is NaN'); + assert(!isNaN(pos.x), 'Position is NaN'); + this.cacheData(pos, rot); +}; + +Shape.prototype.pointQuery = function(p) +{ + var info = this.nearestPointQuery(p); + if (info.d < 0) return info; +}; + +Shape.prototype.getBB = function() +{ + return new BB(this.bb_l, this.bb_b, this.bb_r, this.bb_t); +}; + +/* Not implemented - all these getters and setters. Just edit the object directly. +CP_DefineShapeStructGetter(cpBody*, body, Body); +void cpShapeSetBody(cpShape *shape, cpBody *body); + +CP_DefineShapeStructGetter(cpBB, bb, BB); +CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue); +CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse); +CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue); +CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue); +CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse); +CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue); +CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue); +CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue); +*/ /// Extended point query info struct. Returned from calling pointQuery on a shape. - var PointQueryExtendedInfo = function(shape){ - /// Shape that was hit, NULL if no collision occurred. - this.shape = shape; - /// Depth of the point inside the shape. - this.d = Infinity; - /// Direction of minimum norm to the shape's surface. - this.n = vzero; - }; - - var SegmentQueryInfo = function(shape, t, n){ - /// The shape that was hit, NULL if no collision occured. - this.shape = shape; - /// The normalized distance along the query segment in the range [0, 1]. - this.t = t; - /// The normal of the surface hit. - this.n = n; - }; +var PointQueryExtendedInfo = function(shape) +{ + /// Shape that was hit, NULL if no collision occurred. + this.shape = shape; + /// Depth of the point inside the shape. + this.d = Infinity; + /// Direction of minimum norm to the shape's surface. + this.n = vzero; +}; + +var NearestPointQueryInfo = function(shape, p, d) +{ + /// The nearest shape, NULL if no shape was within range. + this.shape = shape; + /// The closest point on the shape's surface. (in world space coordinates) + this.p = p; + /// The distance to the point. The distance is negative if the point is inside the shape. + this.d = d; +}; + +var SegmentQueryInfo = function(shape, t, n) +{ + /// The shape that was hit, NULL if no collision occured. + this.shape = shape; + /// The normalized distance along the query segment in the range [0, 1]. + this.t = t; + /// The normal of the surface hit. + this.n = n; +}; /// Get the hit point for a segment query. - SegmentQueryInfo.prototype.hitPoint = function(start, end) - { - return vlerp(start, end, this.t); - }; +SegmentQueryInfo.prototype.hitPoint = function(start, end) +{ + return vlerp(start, end, this.t); +}; /// Get the hit distance for a segment query. - SegmentQueryInfo.prototype.hitDist = function(start, end) - { - return vdist(start, end) * this.t; - }; +SegmentQueryInfo.prototype.hitDist = function(start, end) +{ + return vdist(start, end) * this.t; +}; // Circles. - var CircleShape = cp.CircleShape = function(body, radius, offset) - { - this.c = this.tc = offset; - this.r = radius; - - this.type = 'circle'; - - Shape.call(this, body); - }; - - CircleShape.prototype = Object.create(Shape.prototype); - - CircleShape.prototype.cacheData = function(p, rot) - { - //var c = this.tc = vadd(p, vrotate(this.c, rot)); - var c = this.tc = vrotate(this.c, rot).add(p); - //this.bb = bbNewForCircle(c, this.r); - var r = this.r; - this.bb_l = c.x - r; - this.bb_b = c.y - r; - this.bb_r = c.x + r; - this.bb_t = c.y + r; - }; +var CircleShape = cp.CircleShape = function(body, radius, offset) +{ + this.c = this.tc = offset; + this.r = radius; + + this.type = 'circle'; + + Shape.call(this, body); +}; + +CircleShape.prototype = Object.create(Shape.prototype); + +CircleShape.prototype.cacheData = function(p, rot) +{ + //var c = this.tc = vadd(p, vrotate(this.c, rot)); + var c = this.tc = vrotate(this.c, rot).add(p); + //this.bb = bbNewForCircle(c, this.r); + var r = this.r; + this.bb_l = c.x - r; + this.bb_b = c.y - r; + this.bb_r = c.x + r; + this.bb_t = c.y + r; +}; /// Test if a point lies within a shape. - CircleShape.prototype.pointQuery = function(p) - { - var delta = vsub(p, this.tc); - var distsq = vlengthsq(delta); - var r = this.r; - - if(distsq < r*r){ - var info = new PointQueryExtendedInfo(this); - - var dist = Math.sqrt(distsq); - info.d = r - dist; - info.n = vmult(delta, 1/dist); - return info; - } - }; - - var circleSegmentQuery = function(shape, center, r, a, b, info) - { - // offset the line to be relative to the circle - a = vsub(a, center); - b = vsub(b, center); - - var qa = vdot(a, a) - 2*vdot(a, b) + vdot(b, b); - var qb = -2*vdot(a, a) + 2*vdot(a, b); - var qc = vdot(a, a) - r*r; - - var det = qb*qb - 4*qa*qc; - - if(det >= 0) - { - var t = (-qb - Math.sqrt(det))/(2*qa); - if(0 <= t && t <= 1){ - return new SegmentQueryInfo(shape, t, vnormalize(vlerp(a, b, t))); - } - } - }; - - CircleShape.prototype.segmentQuery = function(a, b) - { - return circleSegmentQuery(this, this.tc, this.r, a, b); - }; +/*CircleShape.prototype.pointQuery = function(p) +{ + var delta = vsub(p, this.tc); + var distsq = vlengthsq(delta); + var r = this.r; + + if(distsq < r*r){ + var info = new PointQueryExtendedInfo(this); + + var dist = Math.sqrt(distsq); + info.d = r - dist; + info.n = vmult(delta, 1/dist); + return info; + } +};*/ + +CircleShape.prototype.nearestPointQuery = function(p) +{ + var deltax = p.x - this.tc.x; + var deltay = p.y - this.tc.y; + var d = vlength2(deltax, deltay); + var r = this.r; + + var nearestp = new Vect(this.tc.x + deltax * r/d, this.tc.y + deltay * r/d); + return new NearestPointQueryInfo(this, nearestp, d - r); +}; + +var circleSegmentQuery = function(shape, center, r, a, b, info) +{ + // offset the line to be relative to the circle + a = vsub(a, center); + b = vsub(b, center); + + var qa = vdot(a, a) - 2*vdot(a, b) + vdot(b, b); + var qb = -2*vdot(a, a) + 2*vdot(a, b); + var qc = vdot(a, a) - r*r; + + var det = qb*qb - 4*qa*qc; + + if(det >= 0) + { + var t = (-qb - Math.sqrt(det))/(2*qa); + if(0 <= t && t <= 1){ + return new SegmentQueryInfo(shape, t, vnormalize(vlerp(a, b, t))); + } + } +}; + +CircleShape.prototype.segmentQuery = function(a, b) +{ + return circleSegmentQuery(this, this.tc, this.r, a, b); +}; // The C API has these, and also getters. Its not idiomatic to // write getters and setters in JS. - /* - CircleShape.prototype.setRadius = function(radius) - { - this.r = radius; - } +/* +CircleShape.prototype.setRadius = function(radius) +{ + this.r = radius; +} - CircleShape.prototype.setOffset = function(offset) - { - this.c = offset; - }*/ +CircleShape.prototype.setOffset = function(offset) +{ + this.c = offset; +}*/ // Segment shape - var SegmentShape = cp.SegmentShape = function(body, a, b, r) - { - this.a = a; - this.b = b; - this.n = vperp(vnormalize(vsub(b, a))); - - this.ta = this.tb = this.tn = null; - - this.r = r; - - this.a_tangent = vzero; - this.b_tangent = vzero; - - this.type = 'segment'; - Shape.call(this, body); - }; - - SegmentShape.prototype = Object.create(Shape.prototype); - - SegmentShape.prototype.cacheData = function(p, rot) - { - this.ta = vadd(p, vrotate(this.a, rot)); - this.tb = vadd(p, vrotate(this.b, rot)); - this.tn = vrotate(this.n, rot); - - var l,r,b,t; - - if(this.ta.x < this.tb.x){ - l = this.ta.x; - r = this.tb.x; - } else { - l = this.tb.x; - r = this.ta.x; - } - - if(this.ta.y < this.tb.y){ - b = this.ta.y; - t = this.tb.y; - } else { - b = this.tb.y; - t = this.ta.y; - } - - var rad = this.r; - - this.bb_l = l - rad; - this.bb_b = b - rad; - this.bb_r = r + rad; - this.bb_t = t + rad; - }; - - SegmentShape.prototype.pointQuery = function(p) - { - if(!bbContainsVect2(this.bb_l, this.bb_b, this.bb_r, this.bb_t, p)) return; - - var a = this.ta; - var b = this.tb; - - var seg_delta = vsub(b, a); - var closest_t = clamp01(vdot(seg_delta, vsub(p, a))/vlengthsq(seg_delta)); - var closest = vadd(a, vmult(seg_delta, closest_t)); - - var delta = vsub(p, closest); - var distsq = vlengthsq(delta); - var r = this.r; - - if (distsq < r*r){ - var info = new PointQueryExtendedInfo(this); - - var dist = Math.sqrt(distsq); - info.d = r - dist; - info.n = vmult(delta, 1/dist); - return info; - } - }; - - SegmentShape.prototype.segmentQuery = function(a, b) - { - var n = this.tn; - var d = vdot(vsub(this.ta, a), n); - var r = this.r; - - var flipped_n = (d > 0 ? vneg(n) : n); - var n_offset = vsub(vmult(flipped_n, r), a); - - var seg_a = vadd(this.ta, n_offset); - var seg_b = vadd(this.tb, n_offset); - var delta = vsub(b, a); - - if(vcross(delta, seg_a)*vcross(delta, seg_b) <= 0){ - var d_offset = d + (d > 0 ? -r : r); - var ad = -d_offset; - var bd = vdot(delta, n) - d_offset; - - if(ad*bd < 0){ - return new SegmentQueryInfo(this, ad/(ad - bd), flipped_n); - } - } else if(r !== 0){ - var info1 = circleSegmentQuery(this, this.ta, this.r, a, b); - var info2 = circleSegmentQuery(this, this.tb, this.r, a, b); - - if (info1){ - return info2 && info2.t < info1.t ? info2 : info1; - } else { - return info2; - } - } - }; - - SegmentShape.prototype.setNeighbors = function(prev, next) - { - this.a_tangent = vsub(prev, this.a); - this.b_tangent = vsub(next, this.b); - }; - - SegmentShape.prototype.setEndpoints = function(a, b) - { - this.a = a; - this.b = b; - this.n = vperp(vnormalize(vsub(b, a))); - }; - - /* - cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius) - { - this.r = radius; - }*/ - - /* - CP_DeclareShapeGetter(cpSegmentShape, cpVect, A); - CP_DeclareShapeGetter(cpSegmentShape, cpVect, B); - CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal); - CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius); - */ - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - +var SegmentShape = cp.SegmentShape = function(body, a, b, r) +{ + this.a = a; + this.b = b; + this.n = vperp(vnormalize(vsub(b, a))); + + this.ta = this.tb = this.tn = null; + + this.r = r; + + this.a_tangent = vzero; + this.b_tangent = vzero; + + this.type = 'segment'; + Shape.call(this, body); +}; + +SegmentShape.prototype = Object.create(Shape.prototype); + +SegmentShape.prototype.cacheData = function(p, rot) +{ + this.ta = vadd(p, vrotate(this.a, rot)); + this.tb = vadd(p, vrotate(this.b, rot)); + this.tn = vrotate(this.n, rot); + + var l,r,b,t; + + if(this.ta.x < this.tb.x){ + l = this.ta.x; + r = this.tb.x; + } else { + l = this.tb.x; + r = this.ta.x; + } + + if(this.ta.y < this.tb.y){ + b = this.ta.y; + t = this.tb.y; + } else { + b = this.tb.y; + t = this.ta.y; + } + + var rad = this.r; + + this.bb_l = l - rad; + this.bb_b = b - rad; + this.bb_r = r + rad; + this.bb_t = t + rad; +}; + +SegmentShape.prototype.nearestPointQuery = function(p) +{ + var closest = closestPointOnSegment(p, this.ta, this.tb); + + var deltax = p.x - closest.x; + var deltay = p.y - closest.y; + var d = vlength2(deltax, deltay); + var r = this.r; + + var nearestp = (d ? vadd(closest, vmult(new Vect(deltax, deltay), r/d)) : closest); + return new NearestPointQueryInfo(this, nearestp, d - r); +}; + +SegmentShape.prototype.segmentQuery = function(a, b) +{ + var n = this.tn; + var d = vdot(vsub(this.ta, a), n); + var r = this.r; + + var flipped_n = (d > 0 ? vneg(n) : n); + var n_offset = vsub(vmult(flipped_n, r), a); + + var seg_a = vadd(this.ta, n_offset); + var seg_b = vadd(this.tb, n_offset); + var delta = vsub(b, a); + + if(vcross(delta, seg_a)*vcross(delta, seg_b) <= 0){ + var d_offset = d + (d > 0 ? -r : r); + var ad = -d_offset; + var bd = vdot(delta, n) - d_offset; + + if(ad*bd < 0){ + return new SegmentQueryInfo(this, ad/(ad - bd), flipped_n); + } + } else if(r !== 0){ + var info1 = circleSegmentQuery(this, this.ta, this.r, a, b); + var info2 = circleSegmentQuery(this, this.tb, this.r, a, b); + + if (info1){ + return info2 && info2.t < info1.t ? info2 : info1; + } else { + return info2; + } + } +}; + +SegmentShape.prototype.setNeighbors = function(prev, next) +{ + this.a_tangent = vsub(prev, this.a); + this.b_tangent = vsub(next, this.b); +}; + +SegmentShape.prototype.setEndpoints = function(a, b) +{ + this.a = a; + this.b = b; + this.n = vperp(vnormalize(vsub(b, a))); +}; + +/* +cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius) +{ + this.r = radius; +}*/ + +/* +CP_DeclareShapeGetter(cpSegmentShape, cpVect, A); +CP_DeclareShapeGetter(cpSegmentShape, cpVect, B); +CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal); +CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius); +*/ + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + /// Check that a set of vertexes is convex and has a clockwise winding. - var polyValidate = function(verts) - { - var len = verts.length; - for(var i=0; i 0){ - if(vcross2(bx - ax, by - ay, cx - bx, cy - by) > 0){ - return false; - } - } - - return true; - }; +var polyValidate = function(verts) +{ + var len = verts.length; + for(var i=0; i 0){ + if(vcross2(bx - ax, by - ay, cx - bx, cy - by) > 0){ + return false; + } + } + + return true; +}; /// Initialize a polygon shape. /// The vertexes must be convex and have a clockwise winding. - var PolyShape = cp.PolyShape = function(body, verts, offset) - { - assert(verts.length >= 4, "Polygons require some verts"); - assert(typeof(verts[0]) === 'number', 'Polygon verticies should be specified in a flattened list'); - // Fail if the user attempts to pass a concave poly, or a bad winding. - assert(polyValidate(verts), "Polygon is concave or has a reversed winding."); - - this.setVerts(verts, offset); - this.type = 'poly'; - Shape.call(this, body); - }; - - PolyShape.prototype = Object.create(Shape.prototype); - - var Axis = function(n, d) { - this.n = n; - this.d = d; - }; - - PolyShape.prototype.setVerts = function(verts, offset) - { - var len = verts.length; - var numVerts = len >> 1; - - // This a pretty bad way to do this in javascript. As a first pass, I want to keep - // the code similar to the C. - this.verts = new Array(len); - this.tVerts = new Array(len); - this.axes = new Array(numVerts); - this.tAxes = new Array(numVerts); - - for(var i=0; i>1] = new Axis(n, vdot2(n.x, n.y, ax, ay)); - this.tAxes[i>>1] = new Axis(new Vect(0,0), 0); - } - }; +var PolyShape = cp.PolyShape = function(body, verts, offset) +{ + this.setVerts(verts, offset); + this.type = 'poly'; + Shape.call(this, body); +}; + +PolyShape.prototype = Object.create(Shape.prototype); + +var SplittingPlane = function(n, d) +{ + this.n = n; + this.d = d; +}; + +SplittingPlane.prototype.compare = function(v) +{ + return vdot(this.n, v) - this.d; +}; + +PolyShape.prototype.setVerts = function(verts, offset) +{ + assert(verts.length >= 4, "Polygons require some verts"); + assert(typeof(verts[0]) === 'number', + 'Polygon verticies should be specified in a flattened list (eg [x1,y1,x2,y2,x3,y3,...])'); + + // Fail if the user attempts to pass a concave poly, or a bad winding. + assert(polyValidate(verts), "Polygon is concave or has a reversed winding. Consider using cpConvexHull()"); + + var len = verts.length; + var numVerts = len >> 1; + + // This a pretty bad way to do this in javascript. As a first pass, I want to keep + // the code similar to the C. + this.verts = new Array(len); + this.tVerts = new Array(len); + this.planes = new Array(numVerts); + this.tPlanes = new Array(numVerts); + + for(var i=0; i>1] = new SplittingPlane(n, vdot2(n.x, n.y, ax, ay)); + this.tPlanes[i>>1] = new SplittingPlane(new Vect(0,0), 0); + } +}; /// Initialize a box shaped polygon shape. - var BoxShape = cp.BoxShape = function(body, width, height) - { - var hw = width/2; - var hh = height/2; - - return BoxShape2(body, new BB(-hw, -hh, hw, hh)); - }; +var BoxShape = cp.BoxShape = function(body, width, height) +{ + var hw = width/2; + var hh = height/2; + + return BoxShape2(body, new BB(-hw, -hh, hw, hh)); +}; /// Initialize an offset box shaped polygon shape. - var BoxShape2 = cp.BoxShape2 = function(body, box) - { - var verts = [ - box.l, box.b, - box.l, box.t, - box.r, box.t, - box.r, box.b - ]; - - return new PolyShape(body, verts, vzero); - }; - - PolyShape.prototype.transformVerts = function(p, rot) - { - var src = this.verts; - var dst = this.tVerts; - - var l = Infinity, r = -Infinity; - var b = Infinity, t = -Infinity; - - for(var i=0; i (' + vx + ',' + vy + ')'); - - dst[i] = vx; - dst[i+1] = vy; - - l = min(l, vx); - r = max(r, vx); - b = min(b, vy); - t = max(t, vy); - } - - this.bb_l = l; - this.bb_b = b; - this.bb_r = r; - this.bb_t = t; - }; - - PolyShape.prototype.transformAxes = function(p, rot) - { - var src = this.axes; - var dst = this.tAxes; - - for(var i=0; i an) continue; - - var bn = vdot(b, n); - var t = (axes[i].d - an)/(bn - an); - if(t < 0 || 1 < t) continue; - - var point = vlerp(a, b, t); - var dt = -vcross(n, point); - var dtMin = -vcross2(n.x, n.y, verts[i*2], verts[i*2+1]); - var dtMax = -vcross2(n.x, n.y, verts[(i*2+2)%len], verts[(i*2+3)%len]); - - if(dtMin <= dt && dt <= dtMax){ - // josephg: In the original C code, this function keeps - // looping through axes after finding a match. I *think* - // this code is equivalent... - return new SegmentQueryInfo(this, t, n); - } - } - }; - - - PolyShape.prototype.getNumVerts = function() - { - return this.verts.length/2; - }; - - - PolyShape.prototype.getVert = function(idx) - { - return new Vect(this.verts[idx*2],this.verts[idx*2+1]); - }; - - PolyShape.prototype.valueOnAxis = function(n, d) - { - var verts = this.tVerts; - var m = vdot2(n.x, n.y, verts[0], verts[1]); - - for(var i=2; i 0) return false; - } - - return true; - }; - - PolyShape.prototype.containsVertPartial = function(vx, vy, n) - { - var axes = this.tAxes; - - for(var i=0; i 0) return false; - } - - return true; - }; +var BoxShape2 = cp.BoxShape2 = function(body, box) +{ + var verts = [ + box.l, box.b, + box.l, box.t, + box.r, box.t, + box.r, box.b + ]; + + return new PolyShape(body, verts, vzero); +}; + +PolyShape.prototype.transformVerts = function(p, rot) +{ + var src = this.verts; + var dst = this.tVerts; + + var l = Infinity, r = -Infinity; + var b = Infinity, t = -Infinity; + + for(var i=0; i (' + vx + ',' + vy + ')'); + + dst[i] = vx; + dst[i+1] = vy; + + l = min(l, vx); + r = max(r, vx); + b = min(b, vy); + t = max(t, vy); + } + + this.bb_l = l; + this.bb_b = b; + this.bb_r = r; + this.bb_t = t; +}; + +PolyShape.prototype.transformAxes = function(p, rot) +{ + var src = this.planes; + var dst = this.tPlanes; + + for(var i=0; i 0) outside = true; + + var v1x = verts[i*2]; + var v1y = verts[i*2 + 1]; + var closest = closestPointOnSegment2(p.x, p.y, v0x, v0y, v1x, v1y); + + var dist = vdist(p, closest); + if(dist < minDist){ + minDist = dist; + closestPoint = closest; + } + + v0x = v1x; + v0y = v1y; + } + + return new NearestPointQueryInfo(this, closestPoint, (outside ? minDist : -minDist)); +}; + +PolyShape.prototype.segmentQuery = function(a, b) +{ + var axes = this.tPlanes; + var verts = this.tVerts; + var numVerts = axes.length; + var len = numVerts * 2; + + for(var i=0; i an) continue; + + var bn = vdot(b, n); + var t = (axes[i].d - an)/(bn - an); + if(t < 0 || 1 < t) continue; + + var point = vlerp(a, b, t); + var dt = -vcross(n, point); + var dtMin = -vcross2(n.x, n.y, verts[i*2], verts[i*2+1]); + var dtMax = -vcross2(n.x, n.y, verts[(i*2+2)%len], verts[(i*2+3)%len]); + + if(dtMin <= dt && dt <= dtMax){ + // josephg: In the original C code, this function keeps + // looping through axes after finding a match. I *think* + // this code is equivalent... + return new SegmentQueryInfo(this, t, n); + } + } +}; + +PolyShape.prototype.valueOnAxis = function(n, d) +{ + var verts = this.tVerts; + var m = vdot2(n.x, n.y, verts[0], verts[1]); + + for(var i=2; i 0) return false; + } + + return true; +}; + +PolyShape.prototype.containsVertPartial = function(vx, vy, n) +{ + var planes = this.tPlanes; + + for(var i=0; i 0) return false; + } + + return true; +}; // These methods are provided for API compatibility with Chipmunk. I recommend against using // them - just access the poly.verts list directly. - PolyShape.prototype.getNumVerts = function() { return this.verts.length / 2; }; - PolyShape.prototype.getVert = function(i) - { - return new Vect(this.verts[i * 2], this.verts[i * 2 + 1]); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +PolyShape.prototype.getNumVerts = function() { return this.verts.length / 2; }; +PolyShape.prototype.getVert = function(i) +{ + return new Vect(this.verts[i * 2], this.verts[i * 2 + 1]); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ /// @defgroup cpBody cpBody /// Chipmunk's rigid body type. Rigid bodies hold the physical properties of an object like @@ -1320,1169 +1504,1173 @@ /// They are given a shape by creating collision shapes (cpShape) that point to the body. /// @{ - var Body = cp.Body = function(m, i) { - /// Mass of the body. - /// Must agree with cpBody.m_inv! Use body.setMass() when changing the mass for this reason. - //this.m; - /// Mass inverse. - //this.m_inv; - - /// Moment of inertia of the body. - /// Must agree with cpBody.i_inv! Use body.setMoment() when changing the moment for this reason. - //this.i; - /// Moment of inertia inverse. - //this.i_inv; - - /// Position of the rigid body's center of gravity. - this.p = new Vect(0,0); - /// Velocity of the rigid body's center of gravity. - this.vx = this.vy = 0; - /// Force acting on the rigid body's center of gravity. - this.f = new Vect(0,0); - - /// Rotation of the body around it's center of gravity in radians. - /// Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason. - //this.a; - /// Angular velocity of the body around it's center of gravity in radians/second. - this.w = 0; - /// Torque applied to the body around it's center of gravity. - this.t = 0; - - /// Cached unit length vector representing the angle of the body. - /// Used for fast rotations using cpvrotate(). - //cpVect rot; - - /// Maximum velocity allowed when updating the velocity. - this.v_limit = Infinity; - /// Maximum rotational rate (in radians/second) allowed when updating the angular velocity. - this.w_limit = Infinity; - - // This stuff is all private. - this.v_biasx = this.v_biasy = 0; - this.w_bias = 0; - - this.space = null; - - this.shapeList = []; - this.arbiterList = null; // These are both wacky linked lists. - this.constraintList = null; - - // This stuff is used to track information on the collision graph. - this.nodeRoot = null; - this.nodeNext = null; - this.nodeIdleTime = 0; - - // Set this.m and this.m_inv - this.setMass(m); - - // Set this.i and this.i_inv - this.setMoment(i); - - // Set this.a and this.rot - this.rot = new Vect(0,0); - this.setAngle(0); - }; +var Body = cp.Body = function(m, i) { + /// Mass of the body. + /// Must agree with cpBody.m_inv! Use body.setMass() when changing the mass for this reason. + //this.m; + /// Mass inverse. + //this.m_inv; + + /// Moment of inertia of the body. + /// Must agree with cpBody.i_inv! Use body.setMoment() when changing the moment for this reason. + //this.i; + /// Moment of inertia inverse. + //this.i_inv; + + /// Position of the rigid body's center of gravity. + this.p = new Vect(0,0); + /// Velocity of the rigid body's center of gravity. + this.vx = this.vy = 0; + /// Force acting on the rigid body's center of gravity. + this.f = new Vect(0,0); + + /// Rotation of the body around it's center of gravity in radians. + /// Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason. + //this.a; + /// Angular velocity of the body around it's center of gravity in radians/second. + this.w = 0; + /// Torque applied to the body around it's center of gravity. + this.t = 0; + + /// Cached unit length vector representing the angle of the body. + /// Used for fast rotations using cpvrotate(). + //cpVect rot; + + /// Maximum velocity allowed when updating the velocity. + this.v_limit = Infinity; + /// Maximum rotational rate (in radians/second) allowed when updating the angular velocity. + this.w_limit = Infinity; + + // This stuff is all private. + this.v_biasx = this.v_biasy = 0; + this.w_bias = 0; + + this.space = null; + + this.shapeList = []; + this.arbiterList = null; // These are both wacky linked lists. + this.constraintList = null; + + // This stuff is used to track information on the collision graph. + this.nodeRoot = null; + this.nodeNext = null; + this.nodeIdleTime = 0; + + // Set this.m and this.m_inv + this.setMass(m); + + // Set this.i and this.i_inv + this.setMoment(i); + + // Set this.a and this.rot + this.rot = new Vect(0,0); + this.setAngle(0); +}; // I wonder if this should use the constructor style like Body... - var createStaticBody = function() - { - body = new Body(Infinity, Infinity); - body.nodeIdleTime = Infinity; +var createStaticBody = function() +{ + var body = new Body(Infinity, Infinity); + body.nodeIdleTime = Infinity; - return body; - }; + return body; +}; cp.StaticBody = createStaticBody; - if (typeof DEBUG !== 'undefined' && DEBUG) { - var v_assert_nan = function(v, message){assert(v.x == v.x && v.y == v.y, message); }; - var v_assert_infinite = function(v, message){assert(Math.abs(v.x) !== Infinity && Math.abs(v.y) !== Infinity, message);}; - var v_assert_sane = function(v, message){v_assert_nan(v, message); v_assert_infinite(v, message);}; +if (typeof DEBUG !== 'undefined' && DEBUG) { + var v_assert_nan = function(v, message){assert(v.x == v.x && v.y == v.y, message); }; + var v_assert_infinite = function(v, message){assert(Math.abs(v.x) !== Infinity && Math.abs(v.y) !== Infinity, message);}; + var v_assert_sane = function(v, message){v_assert_nan(v, message); v_assert_infinite(v, message);}; - Body.prototype.sanityCheck = function() - { - assert(this.m === this.m && this.m_inv === this.m_inv, "Body's mass is invalid."); - assert(this.i === this.i && this.i_inv === this.i_inv, "Body's moment is invalid."); + Body.prototype.sanityCheck = function() + { + assert(this.m === this.m && this.m_inv === this.m_inv, "Body's mass is invalid."); + assert(this.i === this.i && this.i_inv === this.i_inv, "Body's moment is invalid."); - v_assert_sane(this.p, "Body's position is invalid."); - v_assert_sane(this.f, "Body's force is invalid."); - assert(this.vx === this.vx && Math.abs(this.vx) !== Infinity, "Body's velocity is invalid."); - assert(this.vy === this.vy && Math.abs(this.vy) !== Infinity, "Body's velocity is invalid."); + v_assert_sane(this.p, "Body's position is invalid."); + v_assert_sane(this.f, "Body's force is invalid."); + assert(this.vx === this.vx && Math.abs(this.vx) !== Infinity, "Body's velocity is invalid."); + assert(this.vy === this.vy && Math.abs(this.vy) !== Infinity, "Body's velocity is invalid."); - assert(this.a === this.a && Math.abs(this.a) !== Infinity, "Body's angle is invalid."); - assert(this.w === this.w && Math.abs(this.w) !== Infinity, "Body's angular velocity is invalid."); - assert(this.t === this.t && Math.abs(this.t) !== Infinity, "Body's torque is invalid."); + assert(this.a === this.a && Math.abs(this.a) !== Infinity, "Body's angle is invalid."); + assert(this.w === this.w && Math.abs(this.w) !== Infinity, "Body's angular velocity is invalid."); + assert(this.t === this.t && Math.abs(this.t) !== Infinity, "Body's torque is invalid."); - v_assert_sane(this.rot, "Internal error: Body's rotation vector is invalid."); + v_assert_sane(this.rot, "Body's rotation vector is invalid."); - assert(this.v_limit === this.v_limit, "Body's velocity limit is invalid."); - assert(this.w_limit === this.w_limit, "Body's angular velocity limit is invalid."); - }; - } else { - Body.prototype.sanityCheck = function(){}; - } + assert(this.v_limit === this.v_limit, "Body's velocity limit is invalid."); + assert(this.w_limit === this.w_limit, "Body's angular velocity limit is invalid."); + }; +} else { + Body.prototype.sanityCheck = function(){}; +} - Body.prototype.getPos = function() { return this.p; }; - Body.prototype.getVel = function() { return new Vect(this.vx, this.vy); }; - Body.prototype.getAngVel = function() { return this.w; }; +Body.prototype.getPos = function() { return this.p; }; +Body.prototype.getVel = function() { return new Vect(this.vx, this.vy); }; +Body.prototype.getAngVel = function() { return this.w; }; /// Returns true if the body is sleeping. - Body.prototype.isSleeping = function() - { - return this.nodeRoot !== null; - }; +Body.prototype.isSleeping = function() +{ + return this.nodeRoot !== null; +}; /// Returns true if the body is static. - Body.prototype.isStatic = function() - { - return this.nodeIdleTime === Infinity; - }; +Body.prototype.isStatic = function() +{ + return this.nodeIdleTime === Infinity; +}; /// Returns true if the body has not been added to a space. - Body.prototype.isRogue = function() - { - return this.space === null; - }; +Body.prototype.isRogue = function() +{ + return this.space === null; +}; // It would be nicer to use defineProperty for this, but its about 30x slower: // http://jsperf.com/defineproperty-vs-setter - Body.prototype.setMass = function(mass) - { - assert(mass > 0, "Mass must be positive and non-zero."); - - //activate is defined in cpSpaceComponent - this.activate(); - this.m = mass; - this.m_inv = 1/mass; - }; - - Body.prototype.setMoment = function(moment) - { - assert(moment > 0, "Moment of Inertia must be positive and non-zero."); - - this.activate(); - this.i = moment; - this.i_inv = 1/moment; - }; - - Body.prototype.addShape = function(shape) - { - this.shapeList.push(shape); - }; - - Body.prototype.removeShape = function(shape) - { - // This implementation has a linear time complexity with the number of shapes. - // The original implementation used linked lists instead, which might be faster if - // you're constantly editing the shape of a body. I expect most bodies will never - // have their shape edited, so I'm just going to use the simplest possible implemention. - deleteObjFromList(this.shapeList, shape); - }; - - var filterConstraints = function(node, body, filter) - { - if(node === filter){ - return node.next(body); - } else if(node.a === body){ - node.next_a = filterConstraints(node.next_a, body, filter); - } else { - node.next_b = filterConstraints(node.next_b, body, filter); - } - - return node; - }; - - Body.prototype.removeConstraint = function(constraint) - { - // The constraint must be in the constraints list when this is called. - this.constraintList = filterConstraints(this.constraintList, this, constraint); - }; - - Body.prototype.setPos = function(pos) - { - this.activate(); - this.sanityCheck(); - this.p = pos; - }; - - Body.prototype.setVel = function(velocity) - { - this.activate(); - this.vx = velocity.x; - this.vy = velocity.y; - }; - - Body.prototype.setAngVel = function(w) - { - this.activate(); - this.w = w; - }; - - Body.prototype.setAngleInternal = function(angle) - { - assert(!isNaN(angle), "Internal Error: Attempting to set body's angle to NaN"); - this.a = angle;//fmod(a, (cpFloat)M_PI*2.0f); - - //this.rot = vforangle(angle); - this.rot.x = Math.cos(angle); - this.rot.y = Math.sin(angle); - }; - - Body.prototype.setAngle = function(angle) - { - this.activate(); - this.sanityCheck(); - this.setAngleInternal(angle); - }; - - Body.prototype.velocity_func = function(gravity, damping, dt) - { - //this.v = vclamp(vadd(vmult(this.v, damping), vmult(vadd(gravity, vmult(this.f, this.m_inv)), dt)), this.v_limit); - var vx = this.vx * damping + (gravity.x + this.f.x * this.m_inv) * dt; - var vy = this.vy * damping + (gravity.y + this.f.y * this.m_inv) * dt; - - //var v = vclamp(new Vect(vx, vy), this.v_limit); - //this.vx = v.x; this.vy = v.y; - var v_limit = this.v_limit; - var lensq = vx * vx + vy * vy; - var scale = (lensq > v_limit*v_limit) ? v_limit / Math.sqrt(len) : 1; - this.vx = vx * scale; - this.vy = vy * scale; - - var w_limit = this.w_limit; - this.w = clamp(this.w*damping + this.t*this.i_inv*dt, -w_limit, w_limit); - - this.sanityCheck(); - }; - - Body.prototype.position_func = function(dt) - { - //this.p = vadd(this.p, vmult(vadd(this.v, this.v_bias), dt)); - - //this.p = this.p + (this.v + this.v_bias) * dt; - this.p.x += (this.vx + this.v_biasx) * dt; - this.p.y += (this.vy + this.v_biasy) * dt; - - this.setAngleInternal(this.a + (this.w + this.w_bias)*dt); - - this.v_biasx = this.v_biasy = 0; - this.w_bias = 0; - - this.sanityCheck(); - }; - - Body.prototype.resetForces = function() - { - this.activate(); - this.f = new Vect(0,0); - this.t = 0; - }; - - Body.prototype.applyForce = function(force, r) - { - this.activate(); - this.f = vadd(this.f, force); - this.t += vcross(r, force); - }; - - Body.prototype.applyImpulse = function(j, r) - { - this.activate(); - apply_impulse(this, j.x, j.y, r); - }; - - Body.prototype.getVelAtPoint = function(r) - { - return vadd(new Vect(this.vx, this.vy), vmult(vperp(r), this.w)); - }; +Body.prototype.setMass = function(mass) +{ + assert(mass > 0, "Mass must be positive and non-zero."); + + //activate is defined in cpSpaceComponent + this.activate(); + this.m = mass; + this.m_inv = 1/mass; +}; + +Body.prototype.setMoment = function(moment) +{ + assert(moment > 0, "Moment of Inertia must be positive and non-zero."); + + this.activate(); + this.i = moment; + this.i_inv = 1/moment; +}; + +Body.prototype.addShape = function(shape) +{ + this.shapeList.push(shape); +}; + +Body.prototype.removeShape = function(shape) +{ + // This implementation has a linear time complexity with the number of shapes. + // The original implementation used linked lists instead, which might be faster if + // you're constantly editing the shape of a body. I expect most bodies will never + // have their shape edited, so I'm just going to use the simplest possible implemention. + deleteObjFromList(this.shapeList, shape); +}; + +var filterConstraints = function(node, body, filter) +{ + if(node === filter){ + return node.next(body); + } else if(node.a === body){ + node.next_a = filterConstraints(node.next_a, body, filter); + } else { + node.next_b = filterConstraints(node.next_b, body, filter); + } + + return node; +}; + +Body.prototype.removeConstraint = function(constraint) +{ + // The constraint must be in the constraints list when this is called. + this.constraintList = filterConstraints(this.constraintList, this, constraint); +}; + +Body.prototype.setPos = function(pos) +{ + this.activate(); + this.sanityCheck(); + // If I allow the position to be set to vzero, vzero will get changed. + if (pos === vzero) { + pos = cp.v(0,0); + } + this.p = pos; +}; + +Body.prototype.setVel = function(velocity) +{ + this.activate(); + this.vx = velocity.x; + this.vy = velocity.y; +}; + +Body.prototype.setAngVel = function(w) +{ + this.activate(); + this.w = w; +}; + +Body.prototype.setAngleInternal = function(angle) +{ + assert(!isNaN(angle), "Internal Error: Attempting to set body's angle to NaN"); + this.a = angle;//fmod(a, (cpFloat)M_PI*2.0f); + + //this.rot = vforangle(angle); + this.rot.x = Math.cos(angle); + this.rot.y = Math.sin(angle); +}; + +Body.prototype.setAngle = function(angle) +{ + this.activate(); + this.sanityCheck(); + this.setAngleInternal(angle); +}; + +Body.prototype.velocity_func = function(gravity, damping, dt) +{ + //this.v = vclamp(vadd(vmult(this.v, damping), vmult(vadd(gravity, vmult(this.f, this.m_inv)), dt)), this.v_limit); + var vx = this.vx * damping + (gravity.x + this.f.x * this.m_inv) * dt; + var vy = this.vy * damping + (gravity.y + this.f.y * this.m_inv) * dt; + + //var v = vclamp(new Vect(vx, vy), this.v_limit); + //this.vx = v.x; this.vy = v.y; + var v_limit = this.v_limit; + var lensq = vx * vx + vy * vy; + var scale = (lensq > v_limit*v_limit) ? v_limit / Math.sqrt(lensq) : 1; + this.vx = vx * scale; + this.vy = vy * scale; + + var w_limit = this.w_limit; + this.w = clamp(this.w*damping + this.t*this.i_inv*dt, -w_limit, w_limit); + + this.sanityCheck(); +}; + +Body.prototype.position_func = function(dt) +{ + //this.p = vadd(this.p, vmult(vadd(this.v, this.v_bias), dt)); + + //this.p = this.p + (this.v + this.v_bias) * dt; + this.p.x += (this.vx + this.v_biasx) * dt; + this.p.y += (this.vy + this.v_biasy) * dt; + + this.setAngleInternal(this.a + (this.w + this.w_bias)*dt); + + this.v_biasx = this.v_biasy = 0; + this.w_bias = 0; + + this.sanityCheck(); +}; + +Body.prototype.resetForces = function() +{ + this.activate(); + this.f = new Vect(0,0); + this.t = 0; +}; + +Body.prototype.applyForce = function(force, r) +{ + this.activate(); + this.f = vadd(this.f, force); + this.t += vcross(r, force); +}; + +Body.prototype.applyImpulse = function(j, r) +{ + this.activate(); + apply_impulse(this, j.x, j.y, r); +}; + +Body.prototype.getVelAtPoint = function(r) +{ + return vadd(new Vect(this.vx, this.vy), vmult(vperp(r), this.w)); +}; /// Get the velocity on a body (in world units) at a point on the body in world coordinates. - Body.prototype.getVelAtWorldPoint = function(point) - { - return this.getVelAtPoint(vsub(point, this.p)); - }; +Body.prototype.getVelAtWorldPoint = function(point) +{ + return this.getVelAtPoint(vsub(point, this.p)); +}; /// Get the velocity on a body (in world units) at a point on the body in local coordinates. - Body.prototype.getVelAtLocalPoint = function(point) - { - return this.getVelAtPoint(vrotate(point, this.rot)); - }; - - Body.prototype.eachShape = function(func) - { - for(var i = 0, len = this.shapeList.length; i < len; i++) { - func(this.shapeList[i]); - } - }; - - Body.prototype.eachConstraint = function(func) - { - var constraint = this.constraintList; - while(constraint) { - var next = constraint.next(this); - func(constraint); - constraint = next; - } - }; - - Body.prototype.eachArbiter = function(func) - { - var arb = this.arbiterList; - while(arb){ - var next = arb.next(this); - - arb.swappedColl = (this === arb.body_b); - func(arb); - - arb = next; - } - }; +Body.prototype.getVelAtLocalPoint = function(point) +{ + return this.getVelAtPoint(vrotate(point, this.rot)); +}; + +Body.prototype.eachShape = function(func) +{ + for(var i = 0, len = this.shapeList.length; i < len; i++) { + func(this.shapeList[i]); + } +}; + +Body.prototype.eachConstraint = function(func) +{ + var constraint = this.constraintList; + while(constraint) { + var next = constraint.next(this); + func(constraint); + constraint = next; + } +}; + +Body.prototype.eachArbiter = function(func) +{ + var arb = this.arbiterList; + while(arb){ + var next = arb.next(this); + + arb.swappedColl = (this === arb.body_b); + func(arb); + + arb = next; + } +}; /// Convert body relative/local coordinates to absolute/world coordinates. - Body.prototype.local2World = function(v) - { - return vadd(this.p, vrotate(v, this.rot)); - }; +Body.prototype.local2World = function(v) +{ + return vadd(this.p, vrotate(v, this.rot)); +}; /// Convert body absolute/world coordinates to relative/local coordinates. - Body.prototype.world2Local = function(v) - { - return vunrotate(vsub(v, this.p), this.rot); - }; +Body.prototype.world2Local = function(v) +{ + return vunrotate(vsub(v, this.p), this.rot); +}; /// Get the kinetic energy of a body. - Body.prototype.kineticEnergy = function() - { - // Need to do some fudging to avoid NaNs - var vsq = this.vx*this.vx + this.vy*this.vy; - var wsq = this.w * this.w; - return (vsq ? vsq*this.m : 0) + (wsq ? wsq*this.i : 0); - }; - - /* Copyright (c) 2010 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - /** - @defgroup cpSpatialIndex cpSpatialIndex - - Spatial indexes are data structures that are used to accelerate collision detection - and spatial queries. Chipmunk provides a number of spatial index algorithms to pick from - and they are programmed in a generic way so that you can use them for holding more than - just Shapes. - - It works by using pointers to the objects you add and using a callback to ask your code - for bounding boxes when it needs them. Several types of queries can be performed an index as well - as reindexing and full collision information. All communication to the spatial indexes is performed - through callback functions. - - Spatial indexes should be treated as opaque structs. - This means you shouldn't be reading any of the fields directly. - - All spatial indexes define the following methods: - - // The number of objects in the spatial index. - count = 0; - - // Iterate the objects in the spatial index. @c func will be called once for each object. - each(func); - - // Returns true if the spatial index contains the given object. - // Most spatial indexes use hashed storage, so you must provide a hash value too. - contains(obj, hashid); - - // Add an object to a spatial index. - insert(obj, hashid); - - // Remove an object from a spatial index. - remove(obj, hashid); - - // Perform a full reindex of a spatial index. - reindex(); - - // Reindex a single object in the spatial index. - reindexObject(obj, hashid); - - // Perform a point query against the spatial index, calling @c func for each potential match. - // A pointer to the point will be passed as @c obj1 of @c func. - // func(shape); - pointQuery(point, func); - - // Perform a segment query against the spatial index, calling @c func for each potential match. - // func(shape); - segmentQuery(vect a, vect b, t_exit, func); - - // Perform a rectangle query against the spatial index, calling @c func for each potential match. - // func(shape); - query(bb, func); - - // Simultaneously reindex and find all colliding objects. - // @c func will be called once for each potentially overlapping pair of objects found. - // If the spatial index was initialized with a static index, it will collide it's objects against that as well. - reindexQuery(func); - */ - - var SpatialIndex = cp.SpatialIndex = function(staticIndex) - { - this.staticIndex = staticIndex; - - if(staticIndex){ - assert(!staticIndex.dynamicIndex, "This static index is already associated with a dynamic index."); - staticIndex.dynamicIndex = this; - } - }; +Body.prototype.kineticEnergy = function() +{ + // Need to do some fudging to avoid NaNs + var vsq = this.vx*this.vx + this.vy*this.vy; + var wsq = this.w * this.w; + return (vsq ? vsq*this.m : 0) + (wsq ? wsq*this.i : 0); +}; + +/* Copyright (c) 2010 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + @defgroup cpSpatialIndex cpSpatialIndex + + Spatial indexes are data structures that are used to accelerate collision detection + and spatial queries. Chipmunk provides a number of spatial index algorithms to pick from + and they are programmed in a generic way so that you can use them for holding more than + just Shapes. + + It works by using pointers to the objects you add and using a callback to ask your code + for bounding boxes when it needs them. Several types of queries can be performed an index as well + as reindexing and full collision information. All communication to the spatial indexes is performed + through callback functions. + + Spatial indexes should be treated as opaque structs. + This means you shouldn't be reading any of the fields directly. + + All spatial indexes define the following methods: + + // The number of objects in the spatial index. + count = 0; + + // Iterate the objects in the spatial index. @c func will be called once for each object. + each(func); + + // Returns true if the spatial index contains the given object. + // Most spatial indexes use hashed storage, so you must provide a hash value too. + contains(obj, hashid); + + // Add an object to a spatial index. + insert(obj, hashid); + + // Remove an object from a spatial index. + remove(obj, hashid); + + // Perform a full reindex of a spatial index. + reindex(); + + // Reindex a single object in the spatial index. + reindexObject(obj, hashid); + + // Perform a point query against the spatial index, calling @c func for each potential match. + // A pointer to the point will be passed as @c obj1 of @c func. + // func(shape); + pointQuery(point, func); + + // Perform a segment query against the spatial index, calling @c func for each potential match. + // func(shape); + segmentQuery(vect a, vect b, t_exit, func); + + // Perform a rectangle query against the spatial index, calling @c func for each potential match. + // func(shape); + query(bb, func); + + // Simultaneously reindex and find all colliding objects. + // @c func will be called once for each potentially overlapping pair of objects found. + // If the spatial index was initialized with a static index, it will collide it's objects against that as well. + reindexQuery(func); +*/ + +var SpatialIndex = cp.SpatialIndex = function(staticIndex) +{ + this.staticIndex = staticIndex; + + + if(staticIndex){ + if(staticIndex.dynamicIndex){ + throw new Error("This static index is already associated with a dynamic index."); + } + staticIndex.dynamicIndex = this; + } +}; // Collide the objects in an index against the objects in a staticIndex using the query callback function. - SpatialIndex.prototype.collideStatic = function(staticIndex, func) - { - if(staticIndex.count > 0){ - var query = staticIndex.query; - - this.each(function(obj) { - query(obj, new BB(obj.bb_l, obj.bb_b, obj.bb_r, obj.bb_t), func); - }); - } - }; - - - /* Copyright (c) 2009 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +SpatialIndex.prototype.collideStatic = function(staticIndex, func) +{ + if(staticIndex.count > 0){ + var query = staticIndex.query; + + this.each(function(obj) { + query(obj, new BB(obj.bb_l, obj.bb_b, obj.bb_r, obj.bb_t), func); + }); + } +}; + + +/* Copyright (c) 2009 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ // This file implements a modified AABB tree for collision detection. - var BBTree = cp.BBTree = function(staticIndex) - { - SpatialIndex.call(this, staticIndex); - - this.velocityFunc = null; - - // This is a hash from object ID -> object for the objects stored in the BBTree. - this.leaves = {}; - // A count of the number of leaves in the BBTree. - this.count = 0; - - this.root = null; - - // An object pool of tree nodes and pairs. - //this.pooledNodes = []; - //this.pooledPairs = []; - - this.stamp = 0; - }; - - BBTree.prototype = Object.create(SpatialIndex.prototype); - - var numNodes = 0; - - var Node = function(tree, a, b) - { - //Node *node = NodeFromPool(tree); - this.obj = null; - //this.bb = bbMerge(a.bb, b.bb); - this.bb_l = min(a.bb_l, b.bb_l); - this.bb_b = min(a.bb_b, b.bb_b); - this.bb_r = max(a.bb_r, b.bb_r); - this.bb_t = max(a.bb_t, b.bb_t); - this.parent = null; - - this.setA(a); - this.setB(b); - numNodes++; - }; - - var numLeaves = 0; - var Leaf = function(tree, obj) - { - //Node *node = NodeFromPool(tree); - - this.obj = obj; - //this.bb = tree.getBB(obj); - tree.getBB(obj, this); - - this.parent = null; - - this.stamp = 1; - this.pairs = null; - numLeaves++; - }; +var BBTree = cp.BBTree = function(staticIndex) +{ + SpatialIndex.call(this, staticIndex); + + this.velocityFunc = null; + + // This is a hash from object ID -> object for the objects stored in the BBTree. + this.leaves = {}; + // A count of the number of leaves in the BBTree. + this.count = 0; + + this.root = null; + + // A linked list containing an object pool of tree nodes and pairs. + this.pooledNodes = null; + this.pooledPairs = null; + + this.stamp = 0; +}; + +BBTree.prototype = Object.create(SpatialIndex.prototype); + +var numNodes = 0; + +var Node = function(tree, a, b) +{ + this.obj = null; + this.bb_l = min(a.bb_l, b.bb_l); + this.bb_b = min(a.bb_b, b.bb_b); + this.bb_r = max(a.bb_r, b.bb_r); + this.bb_t = max(a.bb_t, b.bb_t); + this.parent = null; + + this.setA(a); + this.setB(b); +}; + +BBTree.prototype.makeNode = function(a, b) +{ + var node = this.pooledNodes; + if(node){ + this.pooledNodes = node.parent; + node.constructor(this, a, b); + return node; + } else { + numNodes++; + return new Node(this, a, b); + } +}; + +var numLeaves = 0; +var Leaf = function(tree, obj) +{ + this.obj = obj; + tree.getBB(obj, this); + + this.parent = null; + + this.stamp = 1; + this.pairs = null; + numLeaves++; +}; // **** Misc Functions - BBTree.prototype.getBB = function(obj, dest) - { - var velocityFunc = this.velocityFunc; - if(velocityFunc){ - var coef = 0.1; - var x = (obj.bb_r - obj.bb_l)*coef; - var y = (obj.bb_t - obj.bb_b)*coef; - - var v = vmult(velocityFunc(obj), 0.1); - - dest.bb_l = obj.bb_l + min(-x, v.x); - dest.bb_b = obj.bb_b + min(-y, v.y); - dest.bb_r = obj.bb_r + max( x, v.x); - dest.bb_t = obj.bb_t + max( y, v.y); - } else { - dest.bb_l = obj.bb_l; - dest.bb_b = obj.bb_b; - dest.bb_r = obj.bb_r; - dest.bb_t = obj.bb_t; - } - }; - - BBTree.prototype.getStamp = function() - { - var dynamic = this.dynamicIndex; - return (dynamic && dynamic.stamp ? dynamic.stamp : this.stamp); - }; - - BBTree.prototype.incrementStamp = function() - { - if(this.dynamicIndex && this.dynamicIndex.stamp){ - this.dynamicIndex.stamp++; - } else { - this.stamp++; - } - } +BBTree.prototype.getBB = function(obj, dest) +{ + var velocityFunc = this.velocityFunc; + if(velocityFunc){ + var coef = 0.1; + var x = (obj.bb_r - obj.bb_l)*coef; + var y = (obj.bb_t - obj.bb_b)*coef; + + var v = vmult(velocityFunc(obj), 0.1); + + dest.bb_l = obj.bb_l + min(-x, v.x); + dest.bb_b = obj.bb_b + min(-y, v.y); + dest.bb_r = obj.bb_r + max( x, v.x); + dest.bb_t = obj.bb_t + max( y, v.y); + } else { + dest.bb_l = obj.bb_l; + dest.bb_b = obj.bb_b; + dest.bb_r = obj.bb_r; + dest.bb_t = obj.bb_t; + } +}; + +BBTree.prototype.getStamp = function() +{ + var dynamic = this.dynamicIndex; + return (dynamic && dynamic.stamp ? dynamic.stamp : this.stamp); +}; + +BBTree.prototype.incrementStamp = function() +{ + if(this.dynamicIndex && this.dynamicIndex.stamp){ + this.dynamicIndex.stamp++; + } else { + this.stamp++; + } +} // **** Pair/Thread Functions +var numPairs = 0; // Objects created with constructors are faster than object literals. :( - var Pair = function(a, b) - { - this.a = a; this.b = b; - }; - - var Thread = function(leaf, next) - { - this.prev = null; - this.next = next; - this.leaf = leaf; - }; - -// Benchmark this code with object pools on & off. - /* - BBTree.prototype.pairRecycle = function(pair) - { - this.pooledPairs.push(pair); - }; - - BBTree.prototype.pairFromPool = function() - { - return this.pooledPairs.pop() || new Pair(null, null); - }; - */ - - Thread.prototype.unlink = function() - { - var next = this.next; - var prev = this.prev; - - if(next){ - if(next.a.leaf == this.leaf) next.a.prev = prev; else next.b.prev = prev; - } - - if(prev){ - if(prev.a.leaf == this.leaf) prev.a.next = next; else prev.b.next = next; - } else { - this.leaf.pairs = next; - } - }; - - Leaf.prototype.clearPairs = function(tree) - { - var pair = this.pairs, - next; - - this.pairs = null; - - while(pair){ - if(pair.a.leaf == this){ - next = pair.a.next; - pair.b.unlink(); - //tree.pairRecycle(pair); - pair = next; - } else { - next = pair.b.next; - pair.a.unlink(); - //tree.pairRecycle(pair); - pair = next; - } - } - } - - var pairInsert = function(a, b, tree) - { - var nextA = a.pairs, nextB = b.pairs; - var pair = new Pair(new Thread(a, nextA), new Thread(b, nextB)); - a.pairs = b.pairs = pair; - - //var pair = tree.pairFromPool(); - //Pair temp = {{null, a, nextA},{null, b, nextB}}; - //*pair = temp; - - if(nextA){ - if(nextA.a.leaf == a) nextA.a.prev = pair; else nextA.b.prev = pair; - } - - if(nextB){ - if(nextB.a.leaf == b) nextB.a.prev = pair; else nextB.b.prev = pair; - } - }; +var Pair = function(leafA, nextA, leafB, nextB) +{ + this.prevA = null; + this.leafA = leafA; + this.nextA = nextA; + + this.prevB = null; + this.leafB = leafB; + this.nextB = nextB; +}; + +BBTree.prototype.makePair = function(leafA, nextA, leafB, nextB) +{ + //return new Pair(leafA, nextA, leafB, nextB); + var pair = this.pooledPairs; + if (pair) + { + this.pooledPairs = pair.prevA; + + pair.prevA = null; + pair.leafA = leafA; + pair.nextA = nextA; + + pair.prevB = null; + pair.leafB = leafB; + pair.nextB = nextB; + + //pair.constructor(leafA, nextA, leafB, nextB); + return pair; + } else { + numPairs++; + return new Pair(leafA, nextA, leafB, nextB); + } +}; + +Pair.prototype.recycle = function(tree) +{ + this.prevA = tree.pooledPairs; + tree.pooledPairs = this; +}; + +var unlinkThread = function(prev, leaf, next) +{ + if(next){ + if(next.leafA === leaf) next.prevA = prev; else next.prevB = prev; + } + + if(prev){ + if(prev.leafA === leaf) prev.nextA = next; else prev.nextB = next; + } else { + leaf.pairs = next; + } +}; + +Leaf.prototype.clearPairs = function(tree) +{ + var pair = this.pairs, + next; + + this.pairs = null; + + while(pair){ + if(pair.leafA === this){ + next = pair.nextA; + unlinkThread(pair.prevB, pair.leafB, pair.nextB); + } else { + next = pair.nextB; + unlinkThread(pair.prevA, pair.leafA, pair.nextA); + } + pair.recycle(tree); + pair = next; + } +}; + +var pairInsert = function(a, b, tree) +{ + var nextA = a.pairs, nextB = b.pairs; + var pair = tree.makePair(a, nextA, b, nextB); + a.pairs = b.pairs = pair; + + if(nextA){ + if(nextA.leafA === a) nextA.prevA = pair; else nextA.prevB = pair; + } + + if(nextB){ + if(nextB.leafA === b) nextB.prevA = pair; else nextB.prevB = pair; + } +}; // **** Node Functions - /* - static void - NodeRecycle(bbTree *tree, Node *node) - { - node.parent = tree.pooledNodes; - tree.pooledNodes = node; - } - - static Node * - NodeFromPool(bbTree *tree) - { - Node *node = tree.pooledNodes; - - if(node){ - tree.pooledNodes = node.parent; - return node; - } else { - // Pool is exhausted, make more - } - }*/ - - Node.prototype.setA = function(value) - { - this.A = value; - value.parent = this; - }; - - Node.prototype.setB = function(value) - { - this.B = value; - value.parent = this; - }; - - /* - static inline cpBool - NodeIsLeaf(Node *node) - { - return (node.obj != null); - }*/ - Leaf.prototype.isLeaf = true; - Node.prototype.isLeaf = false; - - Node.prototype.otherChild = function(child) - { - return (this.A == child ? this.B : this.A); - }; - - Node.prototype.replaceChild = function(child, value, tree) - { - assertSoft(child == this.A || child == this.B, "Node is not a child of parent."); - - if(this.A == child){ - //NodeRecycle(tree, parent.A); - this.setA(value); - } else { - //NodeRecycle(tree, parent.B); - this.setB(value); - } - - for(var node=this; node; node = node.parent){ - //node.bb = bbMerge(node.A.bb, node.B.bb); - var a = node.A; - var b = node.B; - node.bb_l = min(a.bb_l, b.bb_l); - node.bb_b = min(a.bb_b, b.bb_b); - node.bb_r = max(a.bb_r, b.bb_r); - node.bb_t = max(a.bb_t, b.bb_t); - } - }; - - Node.prototype.bbArea = Leaf.prototype.bbArea = function() - { - return (this.bb_r - this.bb_l)*(this.bb_t - this.bb_b); - }; - - var bbTreeMergedArea = function(a, b) - { - return (max(a.bb_r, b.bb_r) - min(a.bb_l, b.bb_l))*(max(a.bb_t, b.bb_t) - min(a.bb_b, b.bb_b)); - }; +Node.prototype.recycle = function(tree) +{ + this.parent = tree.pooledNodes; + tree.pooledNodes = this; +}; + +Leaf.prototype.recycle = function(tree) +{ + // Its not worth the overhead to recycle leaves. +}; + +Node.prototype.setA = function(value) +{ + this.A = value; + value.parent = this; +}; + +Node.prototype.setB = function(value) +{ + this.B = value; + value.parent = this; +}; + +Leaf.prototype.isLeaf = true; +Node.prototype.isLeaf = false; + +Node.prototype.otherChild = function(child) +{ + return (this.A == child ? this.B : this.A); +}; + +Node.prototype.replaceChild = function(child, value, tree) +{ + assertSoft(child == this.A || child == this.B, "Node is not a child of parent."); + + if(this.A == child){ + this.A.recycle(tree); + this.setA(value); + } else { + this.B.recycle(tree); + this.setB(value); + } + + for(var node=this; node; node = node.parent){ + //node.bb = bbMerge(node.A.bb, node.B.bb); + var a = node.A; + var b = node.B; + node.bb_l = min(a.bb_l, b.bb_l); + node.bb_b = min(a.bb_b, b.bb_b); + node.bb_r = max(a.bb_r, b.bb_r); + node.bb_t = max(a.bb_t, b.bb_t); + } +}; + +Node.prototype.bbArea = Leaf.prototype.bbArea = function() +{ + return (this.bb_r - this.bb_l)*(this.bb_t - this.bb_b); +}; + +var bbTreeMergedArea = function(a, b) +{ + return (max(a.bb_r, b.bb_r) - min(a.bb_l, b.bb_l))*(max(a.bb_t, b.bb_t) - min(a.bb_b, b.bb_b)); +}; // **** Subtree Functions // Would it be better to make these functions instance methods on Node and Leaf? - var bbProximity = function(a, b) - { - return Math.abs(a.bb_l + a.bb_r - b.bb_l - b.bb_r) + Math.abs(a.bb_b + b.bb_t - b.bb_b - b.bb_t); - } +var bbProximity = function(a, b) +{ + return Math.abs(a.bb_l + a.bb_r - b.bb_l - b.bb_r) + Math.abs(a.bb_b + a.bb_t - b.bb_b - b.bb_t); +}; - var subtreeInsert = function(subtree, leaf, tree) - { +var subtreeInsert = function(subtree, leaf, tree) +{ // var s = new Error().stack; // traces[s] = traces[s] ? traces[s]+1 : 1; - if(subtree == null){ - return leaf; - } else if(subtree.isLeaf){ - return new Node(tree, leaf, subtree); - } else { - var cost_a = subtree.B.bbArea() + bbTreeMergedArea(subtree.A, leaf); - var cost_b = subtree.A.bbArea() + bbTreeMergedArea(subtree.B, leaf); - - if(cost_a === cost_b){ - cost_a = bbProximity(subtree.A, leaf); - cost_b = bbProximity(subtree.B, leaf); - } - - if(cost_b < cost_a){ - subtree.setB(subtreeInsert(subtree.B, leaf, tree)); - } else { - subtree.setA(subtreeInsert(subtree.A, leaf, tree)); - } - + if(subtree == null){ + return leaf; + } else if(subtree.isLeaf){ + return tree.makeNode(leaf, subtree); + } else { + var cost_a = subtree.B.bbArea() + bbTreeMergedArea(subtree.A, leaf); + var cost_b = subtree.A.bbArea() + bbTreeMergedArea(subtree.B, leaf); + + if(cost_a === cost_b){ + cost_a = bbProximity(subtree.A, leaf); + cost_b = bbProximity(subtree.B, leaf); + } + + if(cost_b < cost_a){ + subtree.setB(subtreeInsert(subtree.B, leaf, tree)); + } else { + subtree.setA(subtreeInsert(subtree.A, leaf, tree)); + } + // subtree.bb = bbMerge(subtree.bb, leaf.bb); - subtree.bb_l = min(subtree.bb_l, leaf.bb_l); - subtree.bb_b = min(subtree.bb_b, leaf.bb_b); - subtree.bb_r = max(subtree.bb_r, leaf.bb_r); - subtree.bb_t = max(subtree.bb_t, leaf.bb_t); - - return subtree; - } - }; - - Node.prototype.intersectsBB = Leaf.prototype.intersectsBB = function(bb) - { - return (this.bb_l <= bb.r && bb.l <= this.bb_r && this.bb_b <= bb.t && bb.b <= this.bb_t); - }; - - var subtreeQuery = function(subtree, bb, func) - { - //if(bbIntersectsBB(subtree.bb, bb)){ - if(subtree.intersectsBB(bb)){ - if(subtree.isLeaf){ - func(subtree.obj); - } else { - subtreeQuery(subtree.A, bb, func); - subtreeQuery(subtree.B, bb, func); - } - } - }; + subtree.bb_l = min(subtree.bb_l, leaf.bb_l); + subtree.bb_b = min(subtree.bb_b, leaf.bb_b); + subtree.bb_r = max(subtree.bb_r, leaf.bb_r); + subtree.bb_t = max(subtree.bb_t, leaf.bb_t); + + return subtree; + } +}; + +Node.prototype.intersectsBB = Leaf.prototype.intersectsBB = function(bb) +{ + return (this.bb_l <= bb.r && bb.l <= this.bb_r && this.bb_b <= bb.t && bb.b <= this.bb_t); +}; + +var subtreeQuery = function(subtree, bb, func) +{ + //if(bbIntersectsBB(subtree.bb, bb)){ + if(subtree.intersectsBB(bb)){ + if(subtree.isLeaf){ + func(subtree.obj); + } else { + subtreeQuery(subtree.A, bb, func); + subtreeQuery(subtree.B, bb, func); + } + } +}; /// Returns the fraction along the segment query the node hits. Returns Infinity if it doesn't hit. - var nodeSegmentQuery = function(node, a, b) - { - var idx = 1/(b.x - a.x); - var tx1 = (node.bb_l == a.x ? -Infinity : (node.bb_l - a.x)*idx); - var tx2 = (node.bb_r == a.x ? Infinity : (node.bb_r - a.x)*idx); - var txmin = min(tx1, tx2); - var txmax = max(tx1, tx2); - - var idy = 1/(b.y - a.y); - var ty1 = (node.bb_b == a.y ? -Infinity : (node.bb_b - a.y)*idy); - var ty2 = (node.bb_t == a.y ? Infinity : (node.bb_t - a.y)*idy); - var tymin = min(ty1, ty2); - var tymax = max(ty1, ty2); - - if(tymin <= txmax && txmin <= tymax){ - var min_ = max(txmin, tymin); - var max_ = min(txmax, tymax); - - if(0.0 <= max_ && min_ <= 1.0) return max(min_, 0.0); - } - - return Infinity; - }; - - var subtreeSegmentQuery = function(subtree, a, b, t_exit, func) - { - if(subtree.isLeaf){ - return func(subtree.obj); - } else { - var t_a = nodeSegmentQuery(subtree.A, a, b); - var t_b = nodeSegmentQuery(subtree.B, a, b); - - if(t_a < t_b){ - if(t_a < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.A, a, b, t_exit, func)); - if(t_b < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.B, a, b, t_exit, func)); - } else { - if(t_b < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.B, a, b, t_exit, func)); - if(t_a < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.A, a, b, t_exit, func)); - } - - return t_exit; - } - }; - - /* - static void - SubtreeRecycle(bbTree *tree, Node *node) - { - if(!NodeIsLeaf(node)){ - SubtreeRecycle(tree, node.A); - SubtreeRecycle(tree, node.B); - NodeRecycle(tree, node); - } - }*/ - - var subtreeRemove = function(subtree, leaf, tree) - { - if(leaf == subtree){ - return null; - } else { - var parent = leaf.parent; - if(parent == subtree){ - var other = subtree.otherChild(leaf); - other.parent = subtree.parent; - //NodeRecycle(tree, subtree); - return other; - } else { - parent.parent.replaceChild(parent, parent.otherChild(leaf), tree); - return subtree; - } - } - }; +var nodeSegmentQuery = function(node, a, b) +{ + var idx = 1/(b.x - a.x); + var tx1 = (node.bb_l == a.x ? -Infinity : (node.bb_l - a.x)*idx); + var tx2 = (node.bb_r == a.x ? Infinity : (node.bb_r - a.x)*idx); + var txmin = min(tx1, tx2); + var txmax = max(tx1, tx2); + + var idy = 1/(b.y - a.y); + var ty1 = (node.bb_b == a.y ? -Infinity : (node.bb_b - a.y)*idy); + var ty2 = (node.bb_t == a.y ? Infinity : (node.bb_t - a.y)*idy); + var tymin = min(ty1, ty2); + var tymax = max(ty1, ty2); + + if(tymin <= txmax && txmin <= tymax){ + var min_ = max(txmin, tymin); + var max_ = min(txmax, tymax); + + if(0.0 <= max_ && min_ <= 1.0) return max(min_, 0.0); + } + + return Infinity; +}; + +var subtreeSegmentQuery = function(subtree, a, b, t_exit, func) +{ + if(subtree.isLeaf){ + return func(subtree.obj); + } else { + var t_a = nodeSegmentQuery(subtree.A, a, b); + var t_b = nodeSegmentQuery(subtree.B, a, b); + + if(t_a < t_b){ + if(t_a < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.A, a, b, t_exit, func)); + if(t_b < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.B, a, b, t_exit, func)); + } else { + if(t_b < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.B, a, b, t_exit, func)); + if(t_a < t_exit) t_exit = min(t_exit, subtreeSegmentQuery(subtree.A, a, b, t_exit, func)); + } + + return t_exit; + } +}; + +BBTree.prototype.subtreeRecycle = function(node) +{ + if(node.isLeaf){ + this.subtreeRecycle(node.A); + this.subtreeRecycle(node.B); + node.recycle(this); + } +}; + +var subtreeRemove = function(subtree, leaf, tree) +{ + if(leaf == subtree){ + return null; + } else { + var parent = leaf.parent; + if(parent == subtree){ + var other = subtree.otherChild(leaf); + other.parent = subtree.parent; + subtree.recycle(tree); + return other; + } else { + parent.parent.replaceChild(parent, parent.otherChild(leaf), tree); + return subtree; + } + } +}; // **** Marking Functions - /* - typedef struct MarkContext { - bbTree *tree; - Node *staticRoot; - cpSpatialIndexQueryFunc func; - } MarkContext; - */ - - var bbTreeIntersectsNode = function(a, b) - { - return (a.bb_l <= b.bb_r && b.bb_l <= a.bb_r && a.bb_b <= b.bb_t && b.bb_b <= a.bb_t); - }; - - var markLeafQuery = function(subtree, leaf, left, tree, func) - { - if(bbTreeIntersectsNode(leaf, subtree)){ - if(subtree.isLeaf){ - if(left){ - pairInsert(leaf, subtree, tree); - } else { - if(subtree.stamp < leaf.stamp) pairInsert(subtree, leaf, tree); - if(func) func(leaf.obj, subtree.obj); - } - } else { - markLeafQuery(subtree.A, leaf, left, tree, func); - markLeafQuery(subtree.B, leaf, left, tree, func); - } - } - }; - - var markLeaf = function(leaf, tree, staticRoot, func) - { - if(leaf.stamp == tree.getStamp()){ - if(staticRoot) markLeafQuery(staticRoot, leaf, false, tree, func); - - for(var node = leaf; node.parent; node = node.parent){ - if(node == node.parent.A){ - markLeafQuery(node.parent.B, leaf, true, tree, func); - } else { - markLeafQuery(node.parent.A, leaf, false, tree, func); - } - } - } else { - var pair = leaf.pairs; - while(pair){ - if(leaf == pair.b.leaf){ - if(func) func(pair.a.leaf.obj, leaf.obj); - pair = pair.b.next; - } else { - pair = pair.a.next; - } - } - } - }; - - var markSubtree = function(subtree, tree, staticRoot, func) - { - if(subtree.isLeaf){ - markLeaf(subtree, tree, staticRoot, func); - } else { - markSubtree(subtree.A, tree, staticRoot, func); - markSubtree(subtree.B, tree, staticRoot, func); - } - }; +/* +typedef struct MarkContext { + bbTree *tree; + Node *staticRoot; + cpSpatialIndexQueryFunc func; +} MarkContext; +*/ + +var bbTreeIntersectsNode = function(a, b) +{ + return (a.bb_l <= b.bb_r && b.bb_l <= a.bb_r && a.bb_b <= b.bb_t && b.bb_b <= a.bb_t); +}; + +Leaf.prototype.markLeafQuery = function(leaf, left, tree, func) +{ + if(bbTreeIntersectsNode(leaf, this)){ + if(left){ + pairInsert(leaf, this, tree); + } else { + if(this.stamp < leaf.stamp) pairInsert(this, leaf, tree); + if(func) func(leaf.obj, this.obj); + } + } +}; + +Node.prototype.markLeafQuery = function(leaf, left, tree, func) +{ + if(bbTreeIntersectsNode(leaf, this)){ + this.A.markLeafQuery(leaf, left, tree, func); + this.B.markLeafQuery(leaf, left, tree, func); + } +}; + +Leaf.prototype.markSubtree = function(tree, staticRoot, func) +{ + if(this.stamp == tree.getStamp()){ + if(staticRoot) staticRoot.markLeafQuery(this, false, tree, func); + + for(var node = this; node.parent; node = node.parent){ + if(node == node.parent.A){ + node.parent.B.markLeafQuery(this, true, tree, func); + } else { + node.parent.A.markLeafQuery(this, false, tree, func); + } + } + } else { + var pair = this.pairs; + while(pair){ + if(this === pair.leafB){ + if(func) func(pair.leafA.obj, this.obj); + pair = pair.nextB; + } else { + pair = pair.nextA; + } + } + } +}; + +Node.prototype.markSubtree = function(tree, staticRoot, func) +{ + this.A.markSubtree(tree, staticRoot, func); + this.B.markSubtree(tree, staticRoot, func); +}; // **** Leaf Functions - Leaf.prototype.containsObj = function(obj) - { - return (this.bb_l <= obj.bb_l && this.bb_r >= obj.bb_r && this.bb_b <= obj.bb_b && this.bb_t >= obj.bb_t); - }; - - Leaf.prototype.update = function(tree) - { - var root = tree.root; - var obj = this.obj; - - //if(!bbContainsBB(this.bb, bb)){ - if(!this.containsObj(obj)){ - tree.getBB(this.obj, this); - - root = subtreeRemove(root, this, tree); - tree.root = subtreeInsert(root, this, tree); - - this.clearPairs(tree); - this.stamp = tree.getStamp(); - - return true; - } - - return false; - }; - - Leaf.prototype.addPairs = function(tree) - { - var dynamicIndex = tree.dynamicIndex; - if(dynamicIndex){ - var dynamicRoot = dynamicIndex.root; - if(dynamicRoot){ - markLeafQuery(dynamicRoot, this, true, dynamicIndex, null); - } - } else { - var staticRoot = tree.staticIndex.root; - markLeaf(this, tree, staticRoot, null); - } - }; +Leaf.prototype.containsObj = function(obj) +{ + return (this.bb_l <= obj.bb_l && this.bb_r >= obj.bb_r && this.bb_b <= obj.bb_b && this.bb_t >= obj.bb_t); +}; + +Leaf.prototype.update = function(tree) +{ + var root = tree.root; + var obj = this.obj; + + //if(!bbContainsBB(this.bb, bb)){ + if(!this.containsObj(obj)){ + tree.getBB(this.obj, this); + + root = subtreeRemove(root, this, tree); + tree.root = subtreeInsert(root, this, tree); + + this.clearPairs(tree); + this.stamp = tree.getStamp(); + + return true; + } + + return false; +}; + +Leaf.prototype.addPairs = function(tree) +{ + var dynamicIndex = tree.dynamicIndex; + if(dynamicIndex){ + var dynamicRoot = dynamicIndex.root; + if(dynamicRoot){ + dynamicRoot.markLeafQuery(this, true, dynamicIndex, null); + } + } else { + var staticRoot = tree.staticIndex.root; + this.markSubtree(tree, staticRoot, null); + } +}; // **** Insert/Remove - BBTree.prototype.insert = function(obj, hashid) - { - var leaf = new Leaf(this, obj); +BBTree.prototype.insert = function(obj, hashid) +{ + var leaf = new Leaf(this, obj); - this.leaves[hashid] = leaf; - this.root = subtreeInsert(this.root, leaf, this); - this.count++; + this.leaves[hashid] = leaf; + this.root = subtreeInsert(this.root, leaf, this); + this.count++; + + leaf.stamp = this.getStamp(); + leaf.addPairs(this); + this.incrementStamp(); +}; - leaf.stamp = this.getStamp(); - leaf.addPairs(this); - this.incrementStamp(); - }; +BBTree.prototype.remove = function(obj, hashid) +{ + var leaf = this.leaves[hashid]; - BBTree.prototype.remove = function(obj, hashid) - { - var leaf = this.leaves[hashid]; + delete this.leaves[hashid]; + this.root = subtreeRemove(this.root, leaf, this); + this.count--; - delete this.leaves[hashid]; - this.root = subtreeRemove(this.root, leaf, this); - this.count--; + leaf.clearPairs(this); + leaf.recycle(this); +}; - leaf.clearPairs(this); - //NodeRecycle(tree, leaf); - }; - - BBTree.prototype.contains = function(obj, hashid) - { - return this.leaves[hashid] != null; - }; +BBTree.prototype.contains = function(obj, hashid) +{ + return this.leaves[hashid] != null; +}; // **** Reindex - var voidQueryFunc = function(obj1, obj2){}; - - BBTree.prototype.reindexQuery = function(func) - { - if(!this.root) return; - - // LeafUpdate() may modify this.root. Don't cache it. - var hashid, - leaves = this.leaves; - for (hashid in leaves) - { - leaves[hashid].update(this); - } - - var staticIndex = this.staticIndex; - var staticRoot = staticIndex && staticIndex.root; - - markSubtree(this.root, this, staticRoot, func); - if(staticIndex && !staticRoot) this.collideStatic(this, staticIndex, func); - - this.incrementStamp(); - }; - - BBTree.prototype.reindex = function() - { - this.reindexQuery(voidQueryFunc); - }; - - BBTree.prototype.reindexObject = function(obj, hashid) - { - var leaf = this.leaves[hashid]; - if(leaf){ - if(leaf.update(this)) leaf.addPairs(this); - this.incrementStamp(); - } - }; +var voidQueryFunc = function(obj1, obj2){}; + +BBTree.prototype.reindexQuery = function(func) +{ + if(!this.root) return; + + // LeafUpdate() may modify this.root. Don't cache it. + var hashid, + leaves = this.leaves; + for (hashid in leaves) + { + leaves[hashid].update(this); + } + + var staticIndex = this.staticIndex; + var staticRoot = staticIndex && staticIndex.root; + + this.root.markSubtree(this, staticRoot, func); + if(staticIndex && !staticRoot) this.collideStatic(this, staticIndex, func); + + this.incrementStamp(); +}; + +BBTree.prototype.reindex = function() +{ + this.reindexQuery(voidQueryFunc); +}; + +BBTree.prototype.reindexObject = function(obj, hashid) +{ + var leaf = this.leaves[hashid]; + if(leaf){ + if(leaf.update(this)) leaf.addPairs(this); + this.incrementStamp(); + } +}; // **** Query - BBTree.prototype.pointQuery = function(point, func) - { - // The base collision object is the provided point. - if(this.root) subtreeQuery(this.root, new BB(point.x, point.y, point.x, point.y), func); - }; +// This has since been removed from upstream Chipmunk - which recommends you just use query() below +// directly. +BBTree.prototype.pointQuery = function(point, func) +{ + this.query(new BB(point.x, point.y, point.x, point.y), func); +}; - BBTree.prototype.segmentQuery = function(a, b, t_exit, func) - { - if(this.root) subtreeSegmentQuery(this.root, a, b, t_exit, func); - }; +BBTree.prototype.segmentQuery = function(a, b, t_exit, func) +{ + if(this.root) subtreeSegmentQuery(this.root, a, b, t_exit, func); +}; - BBTree.prototype.query = function(bb, func) - { - if(this.root) subtreeQuery(this.root, bb, func); - }; +BBTree.prototype.query = function(bb, func) +{ + if(this.root) subtreeQuery(this.root, bb, func); +}; // **** Misc - BBTree.prototype.count = function() - { - return this.count; - }; +BBTree.prototype.count = function() +{ + return this.count; +}; - BBTree.prototype.each = function(func) - { - var hashid; - for(hashid in this.leaves) - { - func(this.leaves[hashid].obj); - } - }; +BBTree.prototype.each = function(func) +{ + var hashid; + for(hashid in this.leaves) + { + func(this.leaves[hashid].obj); + } +}; // **** Tree Optimization - var bbTreeMergedArea2 = function(node, l, b, r, t) - { - return (max(node.bb_r, r) - min(node.bb_l, l))*(max(node.bb_t, t) - min(node.bb_b, b)); - }; - - var partitionNodes = function(tree, nodes, offset, count) - { - if(count == 1){ - return nodes[offset]; - } else if(count == 2) { - return new Node(tree, nodes[offset], nodes[offset + 1]); - } - - // Find the AABB for these nodes - //var bb = nodes[offset].bb; - var node = nodes[offset]; - var bb_l = node.bb_l, - bb_b = node.bb_b, - bb_r = node.bb_r, - bb_t = node.bb_t; - - var end = offset + count; - for(var i=offset + 1; i bb_t - bb_b); - - // Sort the bounds and use the median as the splitting point - var bounds = new Array(count*2); - if(splitWidth){ - for(var i=offset; i bb_t - bb_b); + + // Sort the bounds and use the median as the splitting point + var bounds = new Array(count*2); + if(splitWidth){ + for(var i=offset; inext = next; - if(prev.body_a === body) { - prev.thread_a_next = next; - } else { - prev.thread_b_next = next; - } - } else { - body.arbiterList = next; - } - - if(next){ - // cpArbiterThreadForBody(next, body)->prev = prev; - if(next.body_a === body){ - next.thread_a_prev = prev; - } else { - next.thread_b_prev = prev; - } - } - }; - - Arbiter.prototype.unthread = function() - { - unthreadHelper(this, this.body_a, this.thread_a_prev, this.thread_a_next); - unthreadHelper(this, this.body_b, this.thread_b_prev, this.thread_b_next); - this.thread_a_prev = this.thread_a_next = null; - this.thread_b_prev = this.thread_b_next = null; - }; +Arbiter.prototype.getDepth = function(i) +{ + return this.contacts[i].dist; +}; + +/* +Arbiter.prototype.threadForBody = function(body) +{ + return (this.body_a === body ? this.thread_a : this.thread_b); +};*/ + +var unthreadHelper = function(arb, body, prev, next) +{ + // thread_x_y is quite ugly, but it avoids making unnecessary js objects per arbiter. + if(prev){ + // cpArbiterThreadForBody(prev, body)->next = next; + if(prev.body_a === body) { + prev.thread_a_next = next; + } else { + prev.thread_b_next = next; + } + } else { + body.arbiterList = next; + } + + if(next){ + // cpArbiterThreadForBody(next, body)->prev = prev; + if(next.body_a === body){ + next.thread_a_prev = prev; + } else { + next.thread_b_prev = prev; + } + } +}; + +Arbiter.prototype.unthread = function() +{ + unthreadHelper(this, this.body_a, this.thread_a_prev, this.thread_a_next); + unthreadHelper(this, this.body_b, this.thread_b_prev, this.thread_b_next); + this.thread_a_prev = this.thread_a_next = null; + this.thread_b_prev = this.thread_b_next = null; +}; //cpFloat //cpContactsEstimateCrushingImpulse(cpContact *contacts, int numContacts) @@ -2853,255 +3039,255 @@ // return (1 - vmag/fsum); //} - Arbiter.prototype.update = function(contacts, handler, a, b) - { - // Arbiters without contact data may exist if a collision function rejected the collision. - if(this.contacts){ - // Iterate over the possible pairs to look for hash value matches. - for(var i=0; i= mindist*mindist) return; - - var dist = Math.sqrt(distsq); - - // Allocate and initialize the contact. - return new Contact( - vadd(p1, vmult(delta, 0.5 + (r1 - 0.5*mindist)/(dist ? dist : Infinity))), - (dist ? vmult(delta, 1/dist) : new Vect(1, 0)), - dist - mindist, - 0 - ); - }; +var circle2circleQuery = function(p1, p2, r1, r2) +{ + var mindist = r1 + r2; + var delta = vsub(p2, p1); + var distsq = vlengthsq(delta); + if(distsq >= mindist*mindist) return; + + var dist = Math.sqrt(distsq); + + // Allocate and initialize the contact. + return new Contact( + vadd(p1, vmult(delta, 0.5 + (r1 - 0.5*mindist)/(dist ? dist : Infinity))), + (dist ? vmult(delta, 1/dist) : new Vect(1, 0)), + dist - mindist, + 0 + ); +}; // Collide circle shapes. - var circle2circle = function(circ1, circ2) - { - var contact = circle2circleQuery(circ1.tc, circ2.tc, circ1.r, circ2.r); - return contact ? [contact] : NONE; - }; - - var circle2segment = function(circleShape, segmentShape) - { - var seg_a = segmentShape.ta; - var seg_b = segmentShape.tb; - var center = circleShape.tc; - - var seg_delta = vsub(seg_b, seg_a); - var closest_t = clamp01(vdot(seg_delta, vsub(center, seg_a))/vlengthsq(seg_delta)); - var closest = vadd(seg_a, vmult(seg_delta, closest_t)); - - var contact = circle2circleQuery(center, closest, circleShape.r, segmentShape.r); - if(contact){ - var n = contact.n; - - // Reject endcap collisions if tangents are provided. - return ( - (closest_t === 0 && vdot(n, segmentShape.a_tangent) < 0) || - (closest_t === 1 && vdot(n, segmentShape.b_tangent) < 0) - ) ? NONE : [contact]; - } else { - return NONE; - } - } +var circle2circle = function(circ1, circ2) +{ + var contact = circle2circleQuery(circ1.tc, circ2.tc, circ1.r, circ2.r); + return contact ? [contact] : NONE; +}; + +var circle2segment = function(circleShape, segmentShape) +{ + var seg_a = segmentShape.ta; + var seg_b = segmentShape.tb; + var center = circleShape.tc; + + var seg_delta = vsub(seg_b, seg_a); + var closest_t = clamp01(vdot(seg_delta, vsub(center, seg_a))/vlengthsq(seg_delta)); + var closest = vadd(seg_a, vmult(seg_delta, closest_t)); + + var contact = circle2circleQuery(center, closest, circleShape.r, segmentShape.r); + if(contact){ + var n = contact.n; + + // Reject endcap collisions if tangents are provided. + return ( + (closest_t === 0 && vdot(n, segmentShape.a_tangent) < 0) || + (closest_t === 1 && vdot(n, segmentShape.b_tangent) < 0) + ) ? NONE : [contact]; + } else { + return NONE; + } +} // Find the minimum separating axis for the given poly and axis list. // @@ -3110,246 +3296,246 @@ // is the fastest implementation. // // See: http://jsperf.com/return-two-values-from-function/2 - var last_MSA_min = 0; - var findMSA = function(poly, axes) - { - var min_index = 0; - var min = poly.valueOnAxis(axes[0].n, axes[0].d); - if(min > 0) return -1; - - for(var i=1; i 0) { - return -1; - } else if(dist > min){ - min = dist; - min_index = i; - } - } - - last_MSA_min = min; - return min_index; - }; +var last_MSA_min = 0; +var findMSA = function(poly, planes) +{ + var min_index = 0; + var min = poly.valueOnAxis(planes[0].n, planes[0].d); + if(min > 0) return -1; + + for(var i=1; i 0) { + return -1; + } else if(dist > min){ + min = dist; + min_index = i; + } + } + + last_MSA_min = min; + return min_index; +}; // Add contacts for probably penetrating vertexes. // This handles the degenerate case where an overlap was detected, but no vertexes fall inside // the opposing polygon. (like a star of david) - var findVertsFallback = function(poly1, poly2, n, dist) - { - var arr = []; - - var verts1 = poly1.tVerts; - for(var i=0; i>1))); - } - } - - var verts2 = poly2.tVerts; - for(var i=0; i>1))); - } - } - - return (arr.length ? arr : findVertsFallback(poly1, poly2, n, dist)); - }; +var findVerts = function(poly1, poly2, n, dist) +{ + var arr = []; + + var verts1 = poly1.tVerts; + for(var i=0; i>1))); + } + } + + var verts2 = poly2.tVerts; + for(var i=0; i>1))); + } + } + + return (arr.length ? arr : findVertsFallback(poly1, poly2, n, dist)); +}; // Collide poly shapes together. - var poly2poly = function(poly1, poly2) - { - var mini1 = findMSA(poly2, poly1.tAxes); - if(mini1 == -1) return NONE; - var min1 = last_MSA_min; - - var mini2 = findMSA(poly1, poly2.tAxes); - if(mini2 == -1) return NONE; - var min2 = last_MSA_min; - - // There is overlap, find the penetrating verts - if(min1 > min2) - return findVerts(poly1, poly2, poly1.tAxes[mini1].n, min1); - else - return findVerts(poly1, poly2, vneg(poly2.tAxes[mini2].n), min2); - }; +var poly2poly = function(poly1, poly2) +{ + var mini1 = findMSA(poly2, poly1.tPlanes); + if(mini1 == -1) return NONE; + var min1 = last_MSA_min; + + var mini2 = findMSA(poly1, poly2.tPlanes); + if(mini2 == -1) return NONE; + var min2 = last_MSA_min; + + // There is overlap, find the penetrating verts + if(min1 > min2) + return findVerts(poly1, poly2, poly1.tPlanes[mini1].n, min1); + else + return findVerts(poly1, poly2, vneg(poly2.tPlanes[mini2].n), min2); +}; // Like cpPolyValueOnAxis(), but for segments. - var segValueOnAxis = function(seg, n, d) - { - var a = vdot(n, seg.ta) - seg.r; - var b = vdot(n, seg.tb) - seg.r; - return min(a, b) - d; - }; +var segValueOnAxis = function(seg, n, d) +{ + var a = vdot(n, seg.ta) - seg.r; + var b = vdot(n, seg.tb) - seg.r; + return min(a, b) - d; +}; // Identify vertexes that have penetrated the segment. - var findPointsBehindSeg = function(arr, seg, poly, pDist, coef) - { - var dta = vcross(seg.tn, seg.ta); - var dtb = vcross(seg.tn, seg.tb); - var n = vmult(seg.tn, coef); - - var verts = poly.tVerts; - for(var i=0; i= dt && dt >= dtb){ - arr.push(new Contact(new Vect(vx, vy), n, pDist, hashPair(poly.hashid, i))); - } - } - } - }; +var findPointsBehindSeg = function(arr, seg, poly, pDist, coef) +{ + var dta = vcross(seg.tn, seg.ta); + var dtb = vcross(seg.tn, seg.tb); + var n = vmult(seg.tn, coef); + + var verts = poly.tVerts; + for(var i=0; i= dt && dt >= dtb){ + arr.push(new Contact(new Vect(vx, vy), n, pDist, hashPair(poly.hashid, i))); + } + } + } +}; // This one is complicated and gross. Just don't go there... // TODO: Comment me! - var seg2poly = function(seg, poly) - { - var arr = []; - - var axes = poly.tAxes; - var numVerts = axes.length; - - var segD = vdot(seg.tn, seg.ta); - var minNorm = poly.valueOnAxis(seg.tn, segD) - seg.r; - var minNeg = poly.valueOnAxis(vneg(seg.tn), -segD) - seg.r; - if(minNeg > 0 || minNorm > 0) return NONE; - - var mini = 0; - var poly_min = segValueOnAxis(seg, axes[0].n, axes[0].d); - if(poly_min > 0) return NONE; - for(var i=0; i 0){ - return NONE; - } else if(dist > poly_min){ - poly_min = dist; - mini = i; - } - } - - var poly_n = vneg(axes[mini].n); - - var va = vadd(seg.ta, vmult(poly_n, seg.r)); - var vb = vadd(seg.tb, vmult(poly_n, seg.r)); - if(poly.containsVert(va.x, va.y)) - arr.push(new Contact(va, poly_n, poly_min, hashPair(seg.hashid, 0))); - if(poly.containsVert(vb.x, vb.y)) - arr.push(new Contact(vb, poly_n, poly_min, hashPair(seg.hashid, 1))); - - // Floating point precision problems here. - // This will have to do for now. +var seg2poly = function(seg, poly) +{ + var arr = []; + + var planes = poly.tPlanes; + var numVerts = planes.length; + + var segD = vdot(seg.tn, seg.ta); + var minNorm = poly.valueOnAxis(seg.tn, segD) - seg.r; + var minNeg = poly.valueOnAxis(vneg(seg.tn), -segD) - seg.r; + if(minNeg > 0 || minNorm > 0) return NONE; + + var mini = 0; + var poly_min = segValueOnAxis(seg, planes[0].n, planes[0].d); + if(poly_min > 0) return NONE; + for(var i=0; i 0){ + return NONE; + } else if(dist > poly_min){ + poly_min = dist; + mini = i; + } + } + + var poly_n = vneg(planes[mini].n); + + var va = vadd(seg.ta, vmult(poly_n, seg.r)); + var vb = vadd(seg.tb, vmult(poly_n, seg.r)); + if(poly.containsVert(va.x, va.y)) + arr.push(new Contact(va, poly_n, poly_min, hashPair(seg.hashid, 0))); + if(poly.containsVert(vb.x, vb.y)) + arr.push(new Contact(vb, poly_n, poly_min, hashPair(seg.hashid, 1))); + + // Floating point precision problems here. + // This will have to do for now. // poly_min -= cp_collision_slop; // TODO is this needed anymore? - - if(minNorm >= poly_min || minNeg >= poly_min) { - if(minNorm > minNeg) - findPointsBehindSeg(arr, seg, poly, minNorm, 1); - else - findPointsBehindSeg(arr, seg, poly, minNeg, -1); - } - - // If no other collision points are found, try colliding endpoints. - if(arr.length === 0){ - var mini2 = mini * 2; - var verts = poly.tVerts; - - var poly_a = new Vect(verts[mini2], verts[mini2+1]); - - var con; - if((con = circle2circleQuery(seg.ta, poly_a, seg.r, 0, arr))) return [con]; - if((con = circle2circleQuery(seg.tb, poly_a, seg.r, 0, arr))) return [con]; - - var len = numVerts * 2; - var poly_b = new Vect(verts[(mini2+2)%len], verts[(mini2+3)%len]); - if((con = circle2circleQuery(seg.ta, poly_b, seg.r, 0, arr))) return [con]; - if((con = circle2circleQuery(seg.tb, poly_b, seg.r, 0, arr))) return [con]; - } - -// console.log(poly.tVerts, poly.tAxes); + + if(minNorm >= poly_min || minNeg >= poly_min) { + if(minNorm > minNeg) + findPointsBehindSeg(arr, seg, poly, minNorm, 1); + else + findPointsBehindSeg(arr, seg, poly, minNeg, -1); + } + + // If no other collision points are found, try colliding endpoints. + if(arr.length === 0){ + var mini2 = mini * 2; + var verts = poly.tVerts; + + var poly_a = new Vect(verts[mini2], verts[mini2+1]); + + var con; + if((con = circle2circleQuery(seg.ta, poly_a, seg.r, 0, arr))) return [con]; + if((con = circle2circleQuery(seg.tb, poly_a, seg.r, 0, arr))) return [con]; + + var len = numVerts * 2; + var poly_b = new Vect(verts[(mini2+2)%len], verts[(mini2+3)%len]); + if((con = circle2circleQuery(seg.ta, poly_b, seg.r, 0, arr))) return [con]; + if((con = circle2circleQuery(seg.tb, poly_b, seg.r, 0, arr))) return [con]; + } + +// console.log(poly.tVerts, poly.tPlanes); // console.log('seg2poly', arr); - return arr; - }; + return arr; +}; // This one is less gross, but still gross. // TODO: Comment me! - var circle2poly = function(circ, poly) - { - var axes = poly.tAxes; - - var mini = 0; - var min = vdot(axes[0].n, circ.tc) - axes[0].d - circ.r; - for(var i=0; i 0){ - return NONE; - } else if(dist > min) { - min = dist; - mini = i; - } - } - - var n = axes[mini].n; - - var verts = poly.tVerts; - var len = verts.length; - var mini2 = mini<<1; - - //var a = poly.tVerts[mini]; - //var b = poly.tVerts[(mini + 1)%poly.tVerts.length]; - var ax = verts[mini2]; - var ay = verts[mini2+1]; - var bx = verts[(mini2+2)%len]; - var by = verts[(mini2+3)%len]; - - var dta = vcross2(n.x, n.y, ax, ay); - var dtb = vcross2(n.x, n.y, bx, by); - var dt = vcross(n, circ.tc); - - if(dt < dtb){ - var con = circle2circleQuery(circ.tc, new Vect(bx, by), circ.r, 0, con); - return con ? [con] : NONE; - } else if(dt < dta) { - return [new Contact( - vsub(circ.tc, vmult(n, circ.r + min/2)), - vneg(n), - min, - 0 - )]; - } else { - var con = circle2circleQuery(circ.tc, new Vect(ax, ay), circ.r, 0, con); - return con ? [con] : NONE; - } - }; +var circle2poly = function(circ, poly) +{ + var planes = poly.tPlanes; + + var mini = 0; + var min = vdot(planes[0].n, circ.tc) - planes[0].d - circ.r; + for(var i=0; i 0){ + return NONE; + } else if(dist > min) { + min = dist; + mini = i; + } + } + + var n = planes[mini].n; + + var verts = poly.tVerts; + var len = verts.length; + var mini2 = mini<<1; + + //var a = poly.tVerts[mini]; + //var b = poly.tVerts[(mini + 1)%poly.tVerts.length]; + var ax = verts[mini2]; + var ay = verts[mini2+1]; + var bx = verts[(mini2+2)%len]; + var by = verts[(mini2+3)%len]; + + var dta = vcross2(n.x, n.y, ax, ay); + var dtb = vcross2(n.x, n.y, bx, by); + var dt = vcross(n, circ.tc); + + if(dt < dtb){ + var con = circle2circleQuery(circ.tc, new Vect(bx, by), circ.r, 0, con); + return con ? [con] : NONE; + } else if(dt < dta) { + return [new Contact( + vsub(circ.tc, vmult(n, circ.r + min/2)), + vneg(n), + min, + 0 + )]; + } else { + var con = circle2circleQuery(circ.tc, new Vect(ax, ay), circ.r, 0, con); + return con ? [con] : NONE; + } +}; // The javascripty way to do this would be either nested object or methods on the prototypes. // @@ -3357,1407 +3543,1451 @@ // See: http://jsperf.com/dispatch // These are copied from the prototypes into the actual objects in the Shape constructor. - CircleShape.prototype.collisionCode = 0; - SegmentShape.prototype.collisionCode = 1; - PolyShape.prototype.collisionCode = 2; - - CircleShape.prototype.collisionTable = [ - circle2circle, - circle2segment, - circle2poly - ]; - - SegmentShape.prototype.collisionTable = [ - null, - function(seg, seg2) { return NONE; }, // seg2seg - seg2poly - ]; - - PolyShape.prototype.collisionTable = [ - null, - null, - poly2poly - ]; - - var collideShapes = cp.collideShapes = function(a, b) - { - assert(a.collisionCode <= b.collisionCode, 'Collided shapes must be sorted by type'); - return a.collisionTable[b.collisionCode](a, b); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var defaultCollisionHandler = new CollisionHandler(); +CircleShape.prototype.collisionCode = 0; +SegmentShape.prototype.collisionCode = 1; +PolyShape.prototype.collisionCode = 2; + +CircleShape.prototype.collisionTable = [ + circle2circle, + circle2segment, + circle2poly +]; + +SegmentShape.prototype.collisionTable = [ + null, + function(segA, segB) { return NONE; }, // seg2seg + seg2poly +]; + +PolyShape.prototype.collisionTable = [ + null, + null, + poly2poly +]; + +var collideShapes = cp.collideShapes = function(a, b) +{ + assert(a.collisionCode <= b.collisionCode, 'Collided shapes must be sorted by type'); + return a.collisionTable[b.collisionCode](a, b); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var defaultCollisionHandler = new CollisionHandler(); /// Basic Unit of Simulation in Chipmunk - var Space = cp.Space = function() { - this.stamp = 0; - this.curr_dt = 0; - - this.bodies = []; - this.rousedBodies = []; - this.sleepingComponents = []; - - this.staticShapes = new BBTree(null); - this.activeShapes = new BBTree(this.staticShapes); - - this.arbiters = []; - this.contactBuffersHead = null; - this.cachedArbiters = {}; - //this.pooledArbiters = []; - - this.constraints = []; - - this.locked = 0; - - this.collisionHandlers = {}; - this.defaultHandler = defaultCollisionHandler; - - this.postStepCallbacks = []; - - /// Number of iterations to use in the impulse solver to solve contacts. - this.iterations = 10; - - /// Gravity to pass to rigid bodies when integrating velocity. - this.gravity = vzero; - - /// Damping rate expressed as the fraction of velocity bodies retain each second. - /// A value of 0.9 would mean that each body's velocity will drop 10% per second. - /// The default value is 1.0, meaning no damping is applied. - /// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring. - this.damping = 1; - - /// Speed threshold for a body to be considered idle. - /// The default value of 0 means to let the space guess a good threshold based on gravity. - this.idleSpeedThreshold = 0; - - /// Time a group of bodies must remain idle in order to fall asleep. - /// Enabling sleeping also implicitly enables the the contact graph. - /// The default value of Infinity disables the sleeping algorithm. - this.sleepTimeThreshold = Infinity; - - /// Amount of encouraged penetration between colliding shapes.. - /// Used to reduce oscillating contacts and keep the collision cache warm. - /// Defaults to 0.1. If you have poor simulation quality, - /// increase this number as much as possible without allowing visible amounts of overlap. - this.collisionSlop = 0.1; - - /// Determines how fast overlapping shapes are pushed apart. - /// Expressed as a fraction of the error remaining after each second. - /// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz. - this.collisionBias = Math.pow(1 - 0.1, 60); - - /// Number of frames that contact information should persist. - /// Defaults to 3. There is probably never a reason to change this value. - this.collisionPersistence = 3; - - /// Rebuild the contact graph during each step. Must be enabled to use the cpBodyEachArbiter() function. - /// Disabled by default for a small performance boost. Enabled implicitly when the sleeping feature is enabled. - this.enableContactGraph = false; - - /// The designated static body for this space. - /// You can modify this body, or replace it with your own static body. - /// By default it points to a statically allocated cpBody in the cpSpace struct. - this.staticBody = new Body(Infinity, Infinity); - this.staticBody.nodeIdleTime = Infinity; - - // Cache the collideShapes callback function for the space. - this.collideShapes = this.makeCollideShapes(); - }; - - Space.prototype.getCurrentTimeStep = function() { return this.curr_dt; }; +var Space = cp.Space = function() { + this.stamp = 0; + this.curr_dt = 0; + + this.bodies = []; + this.rousedBodies = []; + this.sleepingComponents = []; + + this.staticShapes = new BBTree(null); + this.activeShapes = new BBTree(this.staticShapes); + + this.arbiters = []; + this.contactBuffersHead = null; + this.cachedArbiters = {}; + //this.pooledArbiters = []; + + this.constraints = []; + + this.locked = 0; + + this.collisionHandlers = {}; + this.defaultHandler = defaultCollisionHandler; + + this.postStepCallbacks = []; + + /// Number of iterations to use in the impulse solver to solve contacts. + this.iterations = 10; + + /// Gravity to pass to rigid bodies when integrating velocity. + this.gravity = vzero; + + /// Damping rate expressed as the fraction of velocity bodies retain each second. + /// A value of 0.9 would mean that each body's velocity will drop 10% per second. + /// The default value is 1.0, meaning no damping is applied. + /// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring. + this.damping = 1; + + /// Speed threshold for a body to be considered idle. + /// The default value of 0 means to let the space guess a good threshold based on gravity. + this.idleSpeedThreshold = 0; + + /// Time a group of bodies must remain idle in order to fall asleep. + /// Enabling sleeping also implicitly enables the the contact graph. + /// The default value of Infinity disables the sleeping algorithm. + this.sleepTimeThreshold = Infinity; + + /// Amount of encouraged penetration between colliding shapes.. + /// Used to reduce oscillating contacts and keep the collision cache warm. + /// Defaults to 0.1. If you have poor simulation quality, + /// increase this number as much as possible without allowing visible amounts of overlap. + this.collisionSlop = 0.1; + + /// Determines how fast overlapping shapes are pushed apart. + /// Expressed as a fraction of the error remaining after each second. + /// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz. + this.collisionBias = Math.pow(1 - 0.1, 60); + + /// Number of frames that contact information should persist. + /// Defaults to 3. There is probably never a reason to change this value. + this.collisionPersistence = 3; + + /// Rebuild the contact graph during each step. Must be enabled to use the cpBodyEachArbiter() function. + /// Disabled by default for a small performance boost. Enabled implicitly when the sleeping feature is enabled. + this.enableContactGraph = false; + + /// The designated static body for this space. + /// You can modify this body, or replace it with your own static body. + /// By default it points to a statically allocated cpBody in the cpSpace struct. + this.staticBody = new Body(Infinity, Infinity); + this.staticBody.nodeIdleTime = Infinity; + + // Cache the collideShapes callback function for the space. + this.collideShapes = this.makeCollideShapes(); +}; + +Space.prototype.getCurrentTimeStep = function() { return this.curr_dt; }; + +Space.prototype.setIterations = function(iter) { this.iterations = iter; }; /// returns true from inside a callback and objects cannot be added/removed. - Space.prototype.isLocked = function() - { - return this.locked; - }; - - var assertSpaceUnlocked = function(space) - { - assert(!space.locked, "This addition/removal cannot be done safely during a call to cpSpaceStep() \ +Space.prototype.isLocked = function() +{ + return this.locked; +}; + +var assertSpaceUnlocked = function(space) +{ + assert(!space.locked, "This addition/removal cannot be done safely during a call to cpSpaceStep() \ or during a query. Put these calls into a post-step callback."); - }; +}; // **** Collision handler function management /// Set a collision handler to be used whenever the two shapes with the given collision types collide. /// You can pass null for any function you don't want to implement. - Space.prototype.addCollisionHandler = function(a, b, begin, preSolve, postSolve, separate) - { - assertSpaceUnlocked(this); - - // Remove any old function so the new one will get added. - this.removeCollisionHandler(a, b); - - var handler = new CollisionHandler(); - handler.a = a; - handler.b = b; - if(begin) handler.begin = begin; - if(preSolve) handler.preSolve = preSolve; - if(postSolve) handler.postSolve = postSolve; - if(separate) handler.separate = separate; - - this.collisionHandlers[hashPair(a, b)] = handler; - }; +Space.prototype.addCollisionHandler = function(a, b, begin, preSolve, postSolve, separate) +{ + assertSpaceUnlocked(this); + + // Remove any old function so the new one will get added. + this.removeCollisionHandler(a, b); + + var handler = new CollisionHandler(); + handler.a = a; + handler.b = b; + if(begin) handler.begin = begin; + if(preSolve) handler.preSolve = preSolve; + if(postSolve) handler.postSolve = postSolve; + if(separate) handler.separate = separate; + + this.collisionHandlers[hashPair(a, b)] = handler; +}; /// Unset a collision handler. - Space.prototype.removeCollisionHandler = function(a, b) - { - assertSpaceUnlocked(this); - - delete this.collisionHandlers[hashPair(a, b)]; - }; +Space.prototype.removeCollisionHandler = function(a, b) +{ + assertSpaceUnlocked(this); + + delete this.collisionHandlers[hashPair(a, b)]; +}; /// Set a default collision handler for this space. /// The default collision handler is invoked for each colliding pair of shapes /// that isn't explicitly handled by a specific collision handler. /// You can pass null for any function you don't want to implement. - Space.prototype.setDefaultCollisionHandler = function(begin, preSolve, postSolve, separate) - { - assertSpaceUnlocked(this); +Space.prototype.setDefaultCollisionHandler = function(begin, preSolve, postSolve, separate) +{ + assertSpaceUnlocked(this); - var handler = new CollisionHandler(); - if(begin) handler.begin = begin; - if(preSolve) handler.preSolve = preSolve; - if(postSolve) handler.postSolve = postSolve; - if(separate) handler.separate = separate; + var handler = new CollisionHandler(); + if(begin) handler.begin = begin; + if(preSolve) handler.preSolve = preSolve; + if(postSolve) handler.postSolve = postSolve; + if(separate) handler.separate = separate; - this.defaultHandler = handler; - }; + this.defaultHandler = handler; +}; - Space.prototype.lookupHandler = function(a, b) - { - return this.collisionHandlers[hashPair(a, b)] || this.defaultHandler; - }; +Space.prototype.lookupHandler = function(a, b) +{ + return this.collisionHandlers[hashPair(a, b)] || this.defaultHandler; +}; // **** Body, Shape, and Joint Management /// Add a collision shape to the simulation. /// If the shape is attached to a static body, it will be added as a static shape. - Space.prototype.addShape = function(shape) - { - var body = shape.body; - if(body.isStatic()) return this.addStaticShape(shape); - - assert(!shape.space, "This shape is already added to a space and cannot be added to another."); - assertSpaceUnlocked(this); - - body.activate(); - body.addShape(shape); - - shape.update(body.p, body.rot); - this.activeShapes.insert(shape, shape.hashid); - shape.space = this; - - return shape; - }; +Space.prototype.addShape = function(shape) +{ + var body = shape.body; + if(body.isStatic()) return this.addStaticShape(shape); + + assert(!shape.space, "This shape is already added to a space and cannot be added to another."); + assertSpaceUnlocked(this); + + body.activate(); + body.addShape(shape); + + shape.update(body.p, body.rot); + this.activeShapes.insert(shape, shape.hashid); + shape.space = this; + + return shape; +}; /// Explicity add a shape as a static shape to the simulation. - Space.prototype.addStaticShape = function(shape) - { - assert(!shape.space, "This shape is already added to a space and cannot be added to another."); - assertSpaceUnlocked(this); - - var body = shape.body; - body.addShape(shape); - - shape.update(body.p, body.rot); - this.staticShapes.insert(shape, shape.hashid); - shape.space = this; - - return shape; - }; +Space.prototype.addStaticShape = function(shape) +{ + assert(!shape.space, "This shape is already added to a space and cannot be added to another."); + assertSpaceUnlocked(this); + + var body = shape.body; + body.addShape(shape); + + shape.update(body.p, body.rot); + this.staticShapes.insert(shape, shape.hashid); + shape.space = this; + + return shape; +}; /// Add a rigid body to the simulation. - Space.prototype.addBody = function(body) - { - assert(!body.isStatic(), "Static bodies cannot be added to a space as they are not meant to be simulated."); - assert(!body.space, "This body is already added to a space and cannot be added to another."); - assertSpaceUnlocked(this); - - this.bodies.push(body); - body.space = this; - - return body; - }; +Space.prototype.addBody = function(body) +{ + assert(!body.isStatic(), "Static bodies cannot be added to a space as they are not meant to be simulated."); + assert(!body.space, "This body is already added to a space and cannot be added to another."); + assertSpaceUnlocked(this); + + this.bodies.push(body); + body.space = this; + + return body; +}; /// Add a constraint to the simulation. - Space.prototype.addConstraint = function(constraint) - { - assert(!constraint.space, "This shape is already added to a space and cannot be added to another."); - assertSpaceUnlocked(this); - - var a = constraint.a, b = constraint.b; - - a.activate(); - b.activate(); - this.constraints.push(constraint); - - // Push onto the heads of the bodies' constraint lists - constraint.next_a = a.constraintList; a.constraintList = constraint; - constraint.next_b = b.constraintList; b.constraintList = constraint; - constraint.space = this; - - return constraint; - }; - - Space.prototype.filterArbiters = function(body, filter) - { - for (var hash in this.cachedArbiters) - { - var arb = this.cachedArbiters[hash]; - - // Match on the filter shape, or if it's null the filter body - if( - (body === arb.body_a && (filter === arb.a || filter === null)) || - (body === arb.body_b && (filter === arb.b || filter === null)) - ){ - // Call separate when removing shapes. - if(filter && arb.state !== 'cached') arb.callSeparate(this); - - arb.unthread(); - - deleteObjFromList(this.arbiters, arb); - //this.pooledArbiters.push(arb); - - delete this.cachedArbiters[hash]; - } - } - }; +Space.prototype.addConstraint = function(constraint) +{ + assert(!constraint.space, "This shape is already added to a space and cannot be added to another."); + assertSpaceUnlocked(this); + + var a = constraint.a, b = constraint.b; + + a.activate(); + b.activate(); + this.constraints.push(constraint); + + // Push onto the heads of the bodies' constraint lists + constraint.next_a = a.constraintList; a.constraintList = constraint; + constraint.next_b = b.constraintList; b.constraintList = constraint; + constraint.space = this; + + return constraint; +}; + +Space.prototype.filterArbiters = function(body, filter) +{ + for (var hash in this.cachedArbiters) + { + var arb = this.cachedArbiters[hash]; + + // Match on the filter shape, or if it's null the filter body + if( + (body === arb.body_a && (filter === arb.a || filter === null)) || + (body === arb.body_b && (filter === arb.b || filter === null)) + ){ + // Call separate when removing shapes. + if(filter && arb.state !== 'cached') arb.callSeparate(this); + + arb.unthread(); + + deleteObjFromList(this.arbiters, arb); + //this.pooledArbiters.push(arb); + + delete this.cachedArbiters[hash]; + } + } +}; /// Remove a collision shape from the simulation. - Space.prototype.removeShape = function(shape) - { - var body = shape.body; - if(body.isStatic()){ - this.removeStaticShape(shape); - } else { - assert(this.containsShape(shape), - "Cannot remove a shape that was not added to the space. (Removed twice maybe?)"); - assertSpaceUnlocked(this); - - body.activate(); - body.removeShape(shape); - this.filterArbiters(body, shape); - this.activeShapes.remove(shape, shape.hashid); - shape.space = null; - } - }; +Space.prototype.removeShape = function(shape) +{ + var body = shape.body; + if(body.isStatic()){ + this.removeStaticShape(shape); + } else { + assert(this.containsShape(shape), + "Cannot remove a shape that was not added to the space. (Removed twice maybe?)"); + assertSpaceUnlocked(this); + + body.activate(); + body.removeShape(shape); + this.filterArbiters(body, shape); + this.activeShapes.remove(shape, shape.hashid); + shape.space = null; + } +}; /// Remove a collision shape added using addStaticShape() from the simulation. - Space.prototype.removeStaticShape = function(shape) - { - assert(this.containsShape(shape), - "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)"); - assertSpaceUnlocked(this); - - var body = shape.body; - if(body.isStatic()) body.activateStatic(shape); - body.removeShape(shape); - this.filterArbiters(body, shape); - this.staticShapes.remove(shape, shape.hashid); - shape.space = null; - }; +Space.prototype.removeStaticShape = function(shape) +{ + assert(this.containsShape(shape), + "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)"); + assertSpaceUnlocked(this); + + var body = shape.body; + if(body.isStatic()) body.activateStatic(shape); + body.removeShape(shape); + this.filterArbiters(body, shape); + this.staticShapes.remove(shape, shape.hashid); + shape.space = null; +}; /// Remove a rigid body from the simulation. - Space.prototype.removeBody = function(body) - { - assert(this.containsBody(body), - "Cannot remove a body that was not added to the space. (Removed twice maybe?)"); - assertSpaceUnlocked(this); - - body.activate(); +Space.prototype.removeBody = function(body) +{ + assert(this.containsBody(body), + "Cannot remove a body that was not added to the space. (Removed twice maybe?)"); + assertSpaceUnlocked(this); + + body.activate(); // this.filterArbiters(body, null); - deleteObjFromList(this.bodies, body); - body.space = null; - }; + deleteObjFromList(this.bodies, body); + body.space = null; +}; /// Remove a constraint from the simulation. - Space.prototype.removeConstraint = function(constraint) - { - assert(this.containsConstraint(constraint), - "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)"); - assertSpaceUnlocked(this); - - constraint.a.activate(); - constraint.b.activate(); - deleteObjFromList(this.constraints, constraint); - - constraint.a.removeConstraint(constraint); - constraint.b.removeConstraint(constraint); - constraint.space = null; - }; +Space.prototype.removeConstraint = function(constraint) +{ + assert(this.containsConstraint(constraint), + "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)"); + assertSpaceUnlocked(this); + + constraint.a.activate(); + constraint.b.activate(); + deleteObjFromList(this.constraints, constraint); + + constraint.a.removeConstraint(constraint); + constraint.b.removeConstraint(constraint); + constraint.space = null; +}; /// Test if a collision shape has been added to the space. - Space.prototype.containsShape = function(shape) - { - return (shape.space === this); - }; +Space.prototype.containsShape = function(shape) +{ + return (shape.space === this); +}; /// Test if a rigid body has been added to the space. - Space.prototype.containsBody = function(body) - { - return (body.space == this); - }; +Space.prototype.containsBody = function(body) +{ + return (body.space == this); +}; /// Test if a constraint has been added to the space. - Space.prototype.containsConstraint = function(constraint) - { - return (constraint.space == this); - }; +Space.prototype.containsConstraint = function(constraint) +{ + return (constraint.space == this); +}; - Space.prototype.uncacheArbiter = function(arb) - { - delete this.cachedArbiters[hashPair(arb.a.hashid, arb.b.hashid)]; - deleteObjFromList(this.arbiters, arb); - }; +Space.prototype.uncacheArbiter = function(arb) +{ + delete this.cachedArbiters[hashPair(arb.a.hashid, arb.b.hashid)]; + deleteObjFromList(this.arbiters, arb); +}; // **** Iteration /// Call @c func for each body in the space. - Space.prototype.eachBody = function(func) - { - this.lock(); { - var bodies = this.bodies; - - for(var i=0; i keThreshold ? 0 : body.nodeIdleTime + dt); - } - } - - // Awaken any sleeping bodies found and then push arbiters to the bodies' lists. - var arbiters = this.arbiters; - for(var i=0, count=arbiters.length; i keThreshold ? 0 : body.nodeIdleTime + dt); + } + } + + // Awaken any sleeping bodies found and then push arbiters to the bodies' lists. + var arbiters = this.arbiters; + for(var i=0, count=arbiters.length; i= 0, "Internal Error: Space lock underflow."); +Space.prototype.unlock = function(runPostStep) +{ + this.locked--; + assert(this.locked >= 0, "Internal Error: Space lock underflow."); - if(!this.locked && runPostStep){ - var waking = this.rousedBodies; - for(var i=0; i this.collisionPersistence){ - // The tail buffer is available, rotate the ring - var tail = head.next; - tail.stamp = stamp; - tail.contacts.length = 0; - this.contactBuffersHead = tail; - } else { - // Allocate a new buffer and push it into the ring - var buffer = new ContactBuffer(stamp, head); - this.contactBuffersHead = head.next = buffer; - } - }; - - cpContact * - cpContactBufferGetArray(cpSpace *space) - { - if(space.contactBuffersHead.numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){ - // contact buffer could overflow on the next collision, push a fresh one. - space.pushFreshContactBuffer(); - } - - cpContactBufferHeader *head = space.contactBuffersHead; - return ((cpContactBuffer *)head)->contacts + head.numContacts; - } - - void - cpSpacePushContacts(cpSpace *space, int count) - { - cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!"); - space.contactBuffersHead.numContacts += count; - } - - static void - cpSpacePopContacts(cpSpace *space, int count){ - space.contactBuffersHead.numContacts -= count; - } - */ +/* josephg: + * + * This code might be faster in JS than just allocating objects each time - I'm + * really not sure. If the contact buffer solution is used, there will also + * need to be changes in cpCollision.js to fill a passed array instead of creating + * new arrays each time. + * + * TODO: Benchmark me once chipmunk is working. + */ + +/* +var ContactBuffer = function(stamp, splice) +{ + this.stamp = stamp; + // Contact buffers are a circular linked list. + this.next = splice ? splice.next : this; + this.contacts = []; +}; + +Space.prototype.pushFreshContactBuffer = function() +{ + var stamp = this.stamp; + + var head = this.contactBuffersHead; + + if(!head){ + // No buffers have been allocated, make one + this.contactBuffersHead = new ContactBuffer(stamp, null); + } else if(stamp - head.next.stamp > this.collisionPersistence){ + // The tail buffer is available, rotate the ring + var tail = head.next; + tail.stamp = stamp; + tail.contacts.length = 0; + this.contactBuffersHead = tail; + } else { + // Allocate a new buffer and push it into the ring + var buffer = new ContactBuffer(stamp, head); + this.contactBuffersHead = head.next = buffer; + } +}; + +cpContact * +cpContactBufferGetArray(cpSpace *space) +{ + if(space.contactBuffersHead.numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){ + // contact buffer could overflow on the next collision, push a fresh one. + space.pushFreshContactBuffer(); + } + + cpContactBufferHeader *head = space.contactBuffersHead; + return ((cpContactBuffer *)head)->contacts + head.numContacts; +} + +void +cpSpacePushContacts(cpSpace *space, int count) +{ + cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!"); + space.contactBuffersHead.numContacts += count; +} + +static void +cpSpacePopContacts(cpSpace *space, int count){ + space.contactBuffersHead.numContacts -= count; +} +*/ // **** Collision Detection Functions - /* Use this to re-enable object pools. - static void * - cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space) - { - if(space.pooledArbiters.num == 0){ - // arbiter pool is exhausted, make more - int count = CP_BUFFER_BYTES/sizeof(cpArbiter); - cpAssertHard(count, "Internal Error: Buffer size too small."); +/* Use this to re-enable object pools. +static void * +cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space) +{ + if(space.pooledArbiters.num == 0){ + // arbiter pool is exhausted, make more + int count = CP_BUFFER_BYTES/sizeof(cpArbiter); + cpAssertHard(count, "Internal Error: Buffer size too small."); - cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES); - cpArrayPush(space.allocatedBuffers, buffer); + cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES); + cpArrayPush(space.allocatedBuffers, buffer); - for(int i=0; i b.collisionCode){ - var temp = a; - a = b; - b = temp; - } - - // Narrow-phase collision detection. - //cpContact *contacts = cpContactBufferGetArray(space); - //int numContacts = cpCollideShapes(a, b, contacts); - var contacts = collideShapes(a, b); - if(contacts.length === 0) return; // Shapes are not colliding. - //cpSpacePushContacts(space, numContacts); - - // Get an arbiter from space.arbiterSet for the two shapes. - // This is where the persistant contact magic comes from. - var arbHash = hashPair(a.hashid, b.hashid); - var arb = space.cachedArbiters[arbHash]; - if (!arb){ - arb = space.cachedArbiters[arbHash] = new Arbiter(a, b); - } - - arb.update(contacts, handler, a, b); - - // Call the begin function first if it's the first step - if(arb.state == 'first coll' && !handler.begin(arb, space)){ - arb.ignore(); // permanently ignore the collision until separation - } - - if( - // Ignore the arbiter if it has been flagged - (arb.state !== 'ignore') && - // Call preSolve - handler.preSolve(arb, space) && - // Process, but don't add collisions for sensors. - !sensor - ){ - space.arbiters.push(arb); - } else { - //cpSpacePopContacts(space, numContacts); - - arb.contacts = null; - - // Normally arbiters are set as used after calling the post-solve callback. - // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve. - if(arb.state !== 'ignore') arb.state = 'normal'; - } - - // Time stamp the arbiter so we know it was used recently. - arb.stamp = space.stamp; - }; - }; +Space.prototype.makeCollideShapes = function() +{ + // It would be nicer to use .bind() or something, but this is faster. + var space_ = this; + return function(a, b){ + var space = space_; + + // Reject any of the simple cases + if( + // BBoxes must overlap + //!bbIntersects(a.bb, b.bb) + !(a.bb_l <= b.bb_r && b.bb_l <= a.bb_r && a.bb_b <= b.bb_t && b.bb_b <= a.bb_t) + // Don't collide shapes attached to the same body. + || a.body === b.body + // Don't collide objects in the same non-zero group + || (a.group && a.group === b.group) + // Don't collide objects that don't share at least on layer. + || !(a.layers & b.layers) + ) return; + + var handler = space.lookupHandler(a.collision_type, b.collision_type); + + var sensor = a.sensor || b.sensor; + if(sensor && handler === defaultCollisionHandler) return; + + // Shape 'a' should have the lower shape type. (required by cpCollideShapes() ) + if(a.collisionCode > b.collisionCode){ + var temp = a; + a = b; + b = temp; + } + + // Narrow-phase collision detection. + //cpContact *contacts = cpContactBufferGetArray(space); + //int numContacts = cpCollideShapes(a, b, contacts); + var contacts = collideShapes(a, b); + if(contacts.length === 0) return; // Shapes are not colliding. + //cpSpacePushContacts(space, numContacts); + + // Get an arbiter from space.arbiterSet for the two shapes. + // This is where the persistant contact magic comes from. + var arbHash = hashPair(a.hashid, b.hashid); + var arb = space.cachedArbiters[arbHash]; + if (!arb){ + arb = space.cachedArbiters[arbHash] = new Arbiter(a, b); + } + + arb.update(contacts, handler, a, b); + + // Call the begin function first if it's the first step + if(arb.state == 'first coll' && !handler.begin(arb, space)){ + arb.ignore(); // permanently ignore the collision until separation + } + + if( + // Ignore the arbiter if it has been flagged + (arb.state !== 'ignore') && + // Call preSolve + handler.preSolve(arb, space) && + // Process, but don't add collisions for sensors. + !sensor + ){ + space.arbiters.push(arb); + } else { + //cpSpacePopContacts(space, numContacts); + + arb.contacts = null; + + // Normally arbiters are set as used after calling the post-solve callback. + // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve. + if(arb.state !== 'ignore') arb.state = 'normal'; + } + + // Time stamp the arbiter so we know it was used recently. + arb.stamp = space.stamp; + }; +}; // Hashset filter func to throw away old arbiters. - Space.prototype.arbiterSetFilter = function(arb) - { - var ticks = this.stamp - arb.stamp; - - var a = arb.body_a, b = arb.body_b; - - // TODO should make an arbiter state for this so it doesn't require filtering arbiters for - // dangling body pointers on body removal. - // Preserve arbiters on sensors and rejected arbiters for sleeping objects. - // This prevents errant separate callbacks from happenening. - if( - (a.isStatic() || a.isSleeping()) && - (b.isStatic() || b.isSleeping()) - ){ - return true; - } - - // Arbiter was used last frame, but not this one - if(ticks >= 1 && arb.state != 'cached'){ - arb.callSeparate(this); - arb.state = 'cached'; - } - - if(ticks >= this.collisionPersistence){ - arb.contacts = null; - - //cpArrayPush(this.pooledArbiters, arb); - return false; - } - - return true; - }; +Space.prototype.arbiterSetFilter = function(arb) +{ + var ticks = this.stamp - arb.stamp; + + var a = arb.body_a, b = arb.body_b; + + // TODO should make an arbiter state for this so it doesn't require filtering arbiters for + // dangling body pointers on body removal. + // Preserve arbiters on sensors and rejected arbiters for sleeping objects. + // This prevents errant separate callbacks from happenening. + if( + (a.isStatic() || a.isSleeping()) && + (b.isStatic() || b.isSleeping()) + ){ + return true; + } + + // Arbiter was used last frame, but not this one + if(ticks >= 1 && arb.state != 'cached'){ + arb.callSeparate(this); + arb.state = 'cached'; + } + + if(ticks >= this.collisionPersistence){ + arb.contacts = null; + + //cpArrayPush(this.pooledArbiters, arb); + return false; + } + + return true; +}; // **** All Important cpSpaceStep() Function - var updateFunc = function(shape) - { - var body = shape.body; - shape.update(body.p, body.rot); - }; +var updateFunc = function(shape) +{ + var body = shape.body; + shape.update(body.p, body.rot); +}; /// Step the space forward in time by @c dt. - Space.prototype.step = function(dt) - { - // don't step if the timestep is 0! - if(dt === 0) return; - - assert(vzero.x === 0 && vzero.y === 0, "vzero is invalid"); - - this.stamp++; - - var prev_dt = this.curr_dt; - this.curr_dt = dt; - - var bodies = this.bodies; - var constraints = this.constraints; - var arbiters = this.arbiters; - - // Reset and empty the arbiter lists. - for(var i=0; imaxForce*(dt)) // a and b are bodies. - var relative_velocity = function(a, b, r1, r2){ - //var v1_sum = vadd(a.v, vmult(vperp(r1), a.w)); - var v1_sumx = a.vx + (-r1.y) * a.w; - var v1_sumy = a.vy + ( r1.x) * a.w; - - //var v2_sum = vadd(b.v, vmult(vperp(r2), b.w)); - var v2_sumx = b.vx + (-r2.y) * b.w; - var v2_sumy = b.vy + ( r2.x) * b.w; - +var relative_velocity = function(a, b, r1, r2){ + //var v1_sum = vadd(a.v, vmult(vperp(r1), a.w)); + var v1_sumx = a.vx + (-r1.y) * a.w; + var v1_sumy = a.vy + ( r1.x) * a.w; + + //var v2_sum = vadd(b.v, vmult(vperp(r2), b.w)); + var v2_sumx = b.vx + (-r2.y) * b.w; + var v2_sumy = b.vy + ( r2.x) * b.w; + // return vsub(v2_sum, v1_sum); - return new Vect(v2_sumx - v1_sumx, v2_sumy - v1_sumy); - }; - - var normal_relative_velocity = function(a, b, r1, r2, n){ - //return vdot(relative_velocity(a, b, r1, r2), n); - var v1_sumx = a.vx + (-r1.y) * a.w; - var v1_sumy = a.vy + ( r1.x) * a.w; - var v2_sumx = b.vx + (-r2.y) * b.w; - var v2_sumy = b.vy + ( r2.x) * b.w; - - return vdot2(v2_sumx - v1_sumx, v2_sumy - v1_sumy, n.x, n.y); - }; - - /* - var apply_impulse = function(body, j, r){ - body.v = vadd(body.v, vmult(j, body.m_inv)); - body.w += body.i_inv*vcross(r, j); - }; - - var apply_impulses = function(a, b, r1, r2, j) - { - apply_impulse(a, vneg(j), r1); - apply_impulse(b, j, r2); - }; - */ - - var apply_impulse = function(body, jx, jy, r){ + return new Vect(v2_sumx - v1_sumx, v2_sumy - v1_sumy); +}; + +var normal_relative_velocity = function(a, b, r1, r2, n){ + //return vdot(relative_velocity(a, b, r1, r2), n); + var v1_sumx = a.vx + (-r1.y) * a.w; + var v1_sumy = a.vy + ( r1.x) * a.w; + var v2_sumx = b.vx + (-r2.y) * b.w; + var v2_sumy = b.vy + ( r2.x) * b.w; + + return vdot2(v2_sumx - v1_sumx, v2_sumy - v1_sumy, n.x, n.y); +}; + +/* +var apply_impulse = function(body, j, r){ + body.v = vadd(body.v, vmult(j, body.m_inv)); + body.w += body.i_inv*vcross(r, j); +}; + +var apply_impulses = function(a, b, r1, r2, j) +{ + apply_impulse(a, vneg(j), r1); + apply_impulse(b, j, r2); +}; +*/ + +var apply_impulse = function(body, jx, jy, r){ // body.v = body.v.add(vmult(j, body.m_inv)); - body.vx += jx * body.m_inv; - body.vy += jy * body.m_inv; + body.vx += jx * body.m_inv; + body.vy += jy * body.m_inv; // body.w += body.i_inv*vcross(r, j); - body.w += body.i_inv*(r.x*jy - r.y*jx); - }; - - var apply_impulses = function(a, b, r1, r2, jx, jy) - { - apply_impulse(a, -jx, -jy, r1); - apply_impulse(b, jx, jy, r2); - }; - - var apply_bias_impulse = function(body, jx, jy, r) - { - //body.v_bias = vadd(body.v_bias, vmult(j, body.m_inv)); - body.v_biasx += jx * body.m_inv; - body.v_biasy += jy * body.m_inv; - body.w_bias += body.i_inv*vcross2(r.x, r.y, jx, jy); - }; - - /* - var apply_bias_impulses = function(a, b, r1, r2, j) - { - apply_bias_impulse(a, vneg(j), r1); - apply_bias_impulse(b, j, r2); - };*/ - - var k_scalar_body = function(body, r, n) - { - var rcn = vcross(r, n); - return body.m_inv + body.i_inv*rcn*rcn; - }; - - var k_scalar = function(a, b, r1, r2, n) - { - var value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n); - assertSoft(value !== 0, "Unsolvable collision or constraint."); - - return value; - }; + body.w += body.i_inv*(r.x*jy - r.y*jx); +}; + +var apply_impulses = function(a, b, r1, r2, jx, jy) +{ + apply_impulse(a, -jx, -jy, r1); + apply_impulse(b, jx, jy, r2); +}; + +var apply_bias_impulse = function(body, jx, jy, r) +{ + //body.v_bias = vadd(body.v_bias, vmult(j, body.m_inv)); + body.v_biasx += jx * body.m_inv; + body.v_biasy += jy * body.m_inv; + body.w_bias += body.i_inv*vcross2(r.x, r.y, jx, jy); +}; + +/* +var apply_bias_impulses = function(a, b, r1, r2, j) +{ + apply_bias_impulse(a, vneg(j), r1); + apply_bias_impulse(b, j, r2); +};*/ + +var k_scalar_body = function(body, r, n) +{ + var rcn = vcross(r, n); + return body.m_inv + body.i_inv*rcn*rcn; +}; + +var k_scalar = function(a, b, r1, r2, n) +{ + var value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n); + assertSoft(value !== 0, "Unsolvable collision or constraint."); + + return value; +}; // k1 and k2 are modified by the function to contain the outputs. - var k_tensor = function(a, b, r1, r2, k1, k2) - { - // calculate mass matrix - // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross... - var k11, k12, k21, k22; - var m_sum = a.m_inv + b.m_inv; - - // start with I*m_sum - k11 = m_sum; k12 = 0; - k21 = 0; k22 = m_sum; - - // add the influence from r1 - var a_i_inv = a.i_inv; - var r1xsq = r1.x * r1.x * a_i_inv; - var r1ysq = r1.y * r1.y * a_i_inv; - var r1nxy = -r1.x * r1.y * a_i_inv; - k11 += r1ysq; k12 += r1nxy; - k21 += r1nxy; k22 += r1xsq; - - // add the influnce from r2 - var b_i_inv = b.i_inv; - var r2xsq = r2.x * r2.x * b_i_inv; - var r2ysq = r2.y * r2.y * b_i_inv; - var r2nxy = -r2.x * r2.y * b_i_inv; - k11 += r2ysq; k12 += r2nxy; - k21 += r2nxy; k22 += r2xsq; - - // invert - var determinant = k11*k22 - k12*k21; - assertSoft(determinant !== 0, "Unsolvable constraint."); - - var det_inv = 1/determinant; - - k1.x = k22*det_inv; k1.y = -k12*det_inv; - k2.x = -k21*det_inv; k2.y = k11*det_inv; - }; - - var mult_k = function(vr, k1, k2) - { - return new Vect(vdot(vr, k1), vdot(vr, k2)); - }; - - var bias_coef = function(errorBias, dt) - { - return 1 - Math.pow(errorBias, dt); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +var k_tensor = function(a, b, r1, r2, k1, k2) +{ + // calculate mass matrix + // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross... + var k11, k12, k21, k22; + var m_sum = a.m_inv + b.m_inv; + + // start with I*m_sum + k11 = m_sum; k12 = 0; + k21 = 0; k22 = m_sum; + + // add the influence from r1 + var a_i_inv = a.i_inv; + var r1xsq = r1.x * r1.x * a_i_inv; + var r1ysq = r1.y * r1.y * a_i_inv; + var r1nxy = -r1.x * r1.y * a_i_inv; + k11 += r1ysq; k12 += r1nxy; + k21 += r1nxy; k22 += r1xsq; + + // add the influnce from r2 + var b_i_inv = b.i_inv; + var r2xsq = r2.x * r2.x * b_i_inv; + var r2ysq = r2.y * r2.y * b_i_inv; + var r2nxy = -r2.x * r2.y * b_i_inv; + k11 += r2ysq; k12 += r2nxy; + k21 += r2nxy; k22 += r2xsq; + + // invert + var determinant = k11*k22 - k12*k21; + assertSoft(determinant !== 0, "Unsolvable constraint."); + + var det_inv = 1/determinant; + + k1.x = k22*det_inv; k1.y = -k12*det_inv; + k2.x = -k21*det_inv; k2.y = k11*det_inv; +}; + +var mult_k = function(vr, k1, k2) +{ + return new Vect(vdot(vr, k1), vdot(vr, k2)); +}; + +var bias_coef = function(errorBias, dt) +{ + return 1 - Math.pow(errorBias, dt); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ // TODO: Comment me! // a and b are bodies that the constraint applies to. - var Constraint = cp.Constraint = function(a, b) - { - /// The first body connected to this constraint. - this.a = a; - /// The second body connected to this constraint. - this.b = b; - - this.space = null; - - this.next_a = null; - this.next_b = null; - - /// The maximum force that this constraint is allowed to use. - this.maxForce = Infinity; - /// The rate at which joint error is corrected. - /// Defaults to pow(1 - 0.1, 60) meaning that it will - /// correct 10% of the error every 1/60th of a second. - this.errorBias = Math.pow(1 - 0.1, 60); - /// The maximum rate at which joint error is corrected. - this.maxBias = Infinity; - }; - - Constraint.prototype.activateBodies = function() - { - if(this.a) this.a.activate(); - if(this.b) this.b.activate(); - }; +var Constraint = cp.Constraint = function(a, b) +{ + /// The first body connected to this constraint. + this.a = a; + /// The second body connected to this constraint. + this.b = b; + + this.space = null; + + this.next_a = null; + this.next_b = null; + + /// The maximum force that this constraint is allowed to use. + this.maxForce = Infinity; + /// The rate at which joint error is corrected. + /// Defaults to pow(1 - 0.1, 60) meaning that it will + /// correct 10% of the error every 1/60th of a second. + this.errorBias = Math.pow(1 - 0.1, 60); + /// The maximum rate at which joint error is corrected. + this.maxBias = Infinity; +}; + +Constraint.prototype.activateBodies = function() +{ + if(this.a) this.a.activate(); + if(this.b) this.b.activate(); +}; /// These methods are overridden by the constraint itself. - Constraint.prototype.preStep = function(dt) {}; - Constraint.prototype.applyCachedImpulse = function(dt_coef) {}; - Constraint.prototype.applyImpulse = function() {}; - Constraint.prototype.getImpulse = function() { return 0; }; +Constraint.prototype.preStep = function(dt) {}; +Constraint.prototype.applyCachedImpulse = function(dt_coef) {}; +Constraint.prototype.applyImpulse = function() {}; +Constraint.prototype.getImpulse = function() { return 0; }; /// Function called before the solver runs. This can be overridden by the user /// to customize the constraint. /// Animate your joint anchors, update your motor torque, etc. - Constraint.prototype.preSolve = function(space) {}; +Constraint.prototype.preSolve = function(space) {}; /// Function called after the solver runs. This can be overridden by the user /// to customize the constraint. /// Use the applied impulse to perform effects like breakable joints. - Constraint.prototype.postSolve = function(space) {}; - - Constraint.prototype.next = function(body) - { - return (this.a === body ? this.next_a : this.next_b); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var PinJoint = cp.PinJoint = function(a, b, anchr1, anchr2) - { - Constraint.call(this, a, b); - - this.anchr1 = anchr1; - this.anchr2 = anchr2; - - // STATIC_BODY_CHECK - var p1 = (a ? vadd(a.p, vrotate(anchr1, a.rot)) : anchr1); - var p2 = (b ? vadd(b.p, vrotate(anchr2, b.rot)) : anchr2); - this.dist = vlength(vsub(p2, p1)); - - assertSoft(this.dist > 0, "You created a 0 length pin joint. A pivot joint will be much more stable."); - - this.r1 = this.r2 = null; - this.n = null; - this.nMass = 0; - - this.jnAcc = this.jnMax = 0; - this.bias = 0; - }; - - PinJoint.prototype = Object.create(Constraint.prototype); - - PinJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - this.r1 = vrotate(this.anchr1, a.rot); - this.r2 = vrotate(this.anchr2, b.rot); - - var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); - var dist = vlength(delta); - this.n = vmult(delta, 1/(dist ? dist : Infinity)); - - // calculate mass normal - this.nMass = 1/k_scalar(a, b, this.r1, this.r2, this.n); - - // calculate bias velocity - var maxBias = this.maxBias; - this.bias = clamp(-bias_coef(this.errorBias, dt)*(dist - this.dist)/dt, -maxBias, maxBias); - - // compute max impulse - this.jnMax = this.maxForce * dt; - }; - - PinJoint.prototype.applyCachedImpulse = function(dt_coef) - { - var j = vmult(this.n, this.jnAcc*dt_coef); - apply_impulses(this.a, this.b, this.r1, this.r2, j.x, j.y); - }; - - PinJoint.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - var n = this.n; - - // compute relative velocity - var vrn = normal_relative_velocity(a, b, this.r1, this.r2, n); - - // compute normal impulse - var jn = (this.bias - vrn)*this.nMass; - var jnOld = this.jnAcc; - this.jnAcc = clamp(jnOld + jn, -this.jnMax, this.jnMax); - jn = this.jnAcc - jnOld; - - // apply impulse - apply_impulses(a, b, this.r1, this.r2, n.x*jn, n.y*jn); - }; - - PinJoint.prototype.getImpulse = function() - { - return Math.abs(this.jnAcc); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var SlideJoint = cp.SlideJoint = function(a, b, anchr1, anchr2, min, max) - { - Constraint.call(this, a, b); - - this.anchr1 = anchr1; - this.anchr2 = anchr2; - this.min = min; - this.max = max; - - this.r1 = this.r2 = this.n = null; - this.nMass = 0; - - this.jnAcc = this.jnMax = 0; - this.bias = 0; - }; - - SlideJoint.prototype = Object.create(Constraint.prototype); - - SlideJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - this.r1 = vrotate(this.anchr1, a.rot); - this.r2 = vrotate(this.anchr2, b.rot); - - var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); - var dist = vlength(delta); - var pdist = 0; - if(dist > this.max) { - pdist = dist - this.max; - this.n = vnormalize_safe(delta); - } else if(dist < this.min) { - pdist = this.min - dist; - this.n = vneg(vnormalize_safe(delta)); - } else { - this.n = vzero; - this.jnAcc = 0; - } - - // calculate mass normal - this.nMass = 1/k_scalar(a, b, this.r1, this.r2, this.n); - - // calculate bias velocity - var maxBias = this.maxBias; - this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); - - // compute max impulse - this.jnMax = this.maxForce * dt; - }; - - SlideJoint.prototype.applyCachedImpulse = function(dt_coef) - { - var jn = this.jnAcc * dt_coef; - apply_impulses(this.a, this.b, this.r1, this.r2, this.n.x * jn, this.n.y * jn); - }; - - SlideJoint.prototype.applyImpulse = function() - { - if(this.n.x === 0 && this.n.y === 0) return; // early exit - - var a = this.a; - var b = this.b; - - var n = this.n; - var r1 = this.r1; - var r2 = this.r2; - - // compute relative velocity - var vr = relative_velocity(a, b, r1, r2); - var vrn = vdot(vr, n); - - // compute normal impulse - var jn = (this.bias - vrn)*this.nMass; - var jnOld = this.jnAcc; - this.jnAcc = clamp(jnOld + jn, -this.jnMax, 0); - jn = this.jnAcc - jnOld; - - // apply impulse - apply_impulses(a, b, this.r1, this.r2, n.x * jn, n.y * jn); - }; - - SlideJoint.prototype.getImpulse = function() - { - return Math.abs(this.jnAcc); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ +Constraint.prototype.postSolve = function(space) {}; + +Constraint.prototype.next = function(body) +{ + return (this.a === body ? this.next_a : this.next_b); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var PinJoint = cp.PinJoint = function(a, b, anchr1, anchr2) +{ + Constraint.call(this, a, b); + + this.anchr1 = anchr1; + this.anchr2 = anchr2; + + // STATIC_BODY_CHECK + var p1 = (a ? vadd(a.p, vrotate(anchr1, a.rot)) : anchr1); + var p2 = (b ? vadd(b.p, vrotate(anchr2, b.rot)) : anchr2); + this.dist = vlength(vsub(p2, p1)); + + assertSoft(this.dist > 0, "You created a 0 length pin joint. A pivot joint will be much more stable."); + + this.r1 = this.r2 = null; + this.n = null; + this.nMass = 0; + + this.jnAcc = this.jnMax = 0; + this.bias = 0; +}; + +PinJoint.prototype = Object.create(Constraint.prototype); + +PinJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + this.r1 = vrotate(this.anchr1, a.rot); + this.r2 = vrotate(this.anchr2, b.rot); + + var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); + var dist = vlength(delta); + this.n = vmult(delta, 1/(dist ? dist : Infinity)); + + // calculate mass normal + this.nMass = 1/k_scalar(a, b, this.r1, this.r2, this.n); + + // calculate bias velocity + var maxBias = this.maxBias; + this.bias = clamp(-bias_coef(this.errorBias, dt)*(dist - this.dist)/dt, -maxBias, maxBias); + + // compute max impulse + this.jnMax = this.maxForce * dt; +}; + +PinJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + var j = vmult(this.n, this.jnAcc*dt_coef); + apply_impulses(this.a, this.b, this.r1, this.r2, j.x, j.y); +}; + +PinJoint.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + var n = this.n; + + // compute relative velocity + var vrn = normal_relative_velocity(a, b, this.r1, this.r2, n); + + // compute normal impulse + var jn = (this.bias - vrn)*this.nMass; + var jnOld = this.jnAcc; + this.jnAcc = clamp(jnOld + jn, -this.jnMax, this.jnMax); + jn = this.jnAcc - jnOld; + + // apply impulse + apply_impulses(a, b, this.r1, this.r2, n.x*jn, n.y*jn); +}; + +PinJoint.prototype.getImpulse = function() +{ + return Math.abs(this.jnAcc); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var SlideJoint = cp.SlideJoint = function(a, b, anchr1, anchr2, min, max) +{ + Constraint.call(this, a, b); + + this.anchr1 = anchr1; + this.anchr2 = anchr2; + this.min = min; + this.max = max; + + this.r1 = this.r2 = this.n = null; + this.nMass = 0; + + this.jnAcc = this.jnMax = 0; + this.bias = 0; +}; + +SlideJoint.prototype = Object.create(Constraint.prototype); + +SlideJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + this.r1 = vrotate(this.anchr1, a.rot); + this.r2 = vrotate(this.anchr2, b.rot); + + var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); + var dist = vlength(delta); + var pdist = 0; + if(dist > this.max) { + pdist = dist - this.max; + this.n = vnormalize_safe(delta); + } else if(dist < this.min) { + pdist = this.min - dist; + this.n = vneg(vnormalize_safe(delta)); + } else { + this.n = vzero; + this.jnAcc = 0; + } + + // calculate mass normal + this.nMass = 1/k_scalar(a, b, this.r1, this.r2, this.n); + + // calculate bias velocity + var maxBias = this.maxBias; + this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); + + // compute max impulse + this.jnMax = this.maxForce * dt; +}; + +SlideJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + var jn = this.jnAcc * dt_coef; + apply_impulses(this.a, this.b, this.r1, this.r2, this.n.x * jn, this.n.y * jn); +}; + +SlideJoint.prototype.applyImpulse = function() +{ + if(this.n.x === 0 && this.n.y === 0) return; // early exit + + var a = this.a; + var b = this.b; + + var n = this.n; + var r1 = this.r1; + var r2 = this.r2; + + // compute relative velocity + var vr = relative_velocity(a, b, r1, r2); + var vrn = vdot(vr, n); + + // compute normal impulse + var jn = (this.bias - vrn)*this.nMass; + var jnOld = this.jnAcc; + this.jnAcc = clamp(jnOld + jn, -this.jnMax, 0); + jn = this.jnAcc - jnOld; + + // apply impulse + apply_impulses(a, b, this.r1, this.r2, n.x * jn, n.y * jn); +}; + +SlideJoint.prototype.getImpulse = function() +{ + return Math.abs(this.jnAcc); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ // Pivot joints can also be created with (a, b, pivot); - var PivotJoint = cp.PivotJoint = function(a, b, anchr1, anchr2) - { - Constraint.call(this, a, b); - - if(typeof anchr2 === 'undefined') { - var pivot = anchr1; - - anchr1 = (a ? a.world2Local(pivot) : pivot); - anchr2 = (b ? b.world2Local(pivot) : pivot); - } - - this.anchr1 = anchr1; - this.anchr2 = anchr2; - - this.r1 = this.r2 = vzero; - - this.k1 = new Vect(0,0); this.k2 = new Vect(0,0); - - this.jAcc = vzero; - - this.jMaxLen = 0; - this.bias = vzero; - }; - - PivotJoint.prototype = Object.create(Constraint.prototype); - - PivotJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - this.r1 = vrotate(this.anchr1, a.rot); - this.r2 = vrotate(this.anchr2, b.rot); - - // Calculate mass tensor. Result is stored into this.k1 & this.k2. - k_tensor(a, b, this.r1, this.r2, this.k1, this.k2); - - // compute max impulse - this.jMaxLen = this.maxForce * dt; - - // calculate bias velocity - var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); - this.bias = vclamp(vmult(delta, -bias_coef(this.errorBias, dt)/dt), this.maxBias); - }; - - PivotJoint.prototype.applyCachedImpulse = function(dt_coef) - { - apply_impulses(this.a, this.b, this.r1, this.r2, this.jAcc.x * dt_coef, this.jAcc.y * dt_coef); - }; - - PivotJoint.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - var r1 = this.r1; - var r2 = this.r2; - - // compute relative velocity - var vr = relative_velocity(a, b, r1, r2); - - // compute normal impulse - var j = mult_k(vsub(this.bias, vr), this.k1, this.k2); - var jOld = this.jAcc; - this.jAcc = vclamp(vadd(this.jAcc, j), this.jMaxLen); - - // apply impulse - apply_impulses(a, b, this.r1, this.r2, this.jAcc.x - jOld.x, this.jAcc.y - jOld.y); - }; - - PivotJoint.prototype.getImpulse = function() - { - return vlength(this.jAcc); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var GrooveJoint = cp.GrooveJoint = function(a, b, groove_a, groove_b, anchr2) - { - Constraint.call(this, a, b); - - this.grv_a = groove_a; - this.grv_b = groove_b; - this.grv_n = vperp(vnormalize(vsub(groove_b, groove_a))); - this.anchr2 = anchr2; - - this.grv_tn = null; - this.clamp = 0; - this.r1 = this.r2 = null; - - this.k1 = new Vect(0,0); - this.k2 = new Vect(0,0); - - this.jAcc = vzero; - this.jMaxLen = 0; - this.bias = null; - }; - - GrooveJoint.prototype = Object.create(Constraint.prototype); - - GrooveJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - // calculate endpoints in worldspace - var ta = a.local2World(this.grv_a); - var tb = a.local2World(this.grv_b); - - // calculate axis - var n = vrotate(this.grv_n, a.rot); - var d = vdot(ta, n); - - this.grv_tn = n; - this.r2 = vrotate(this.anchr2, b.rot); - - // calculate tangential distance along the axis of r2 - var td = vcross(vadd(b.p, this.r2), n); - // calculate clamping factor and r2 - if(td <= vcross(ta, n)){ - this.clamp = 1; - this.r1 = vsub(ta, a.p); - } else if(td >= vcross(tb, n)){ - this.clamp = -1; - this.r1 = vsub(tb, a.p); - } else { - this.clamp = 0; - this.r1 = vsub(vadd(vmult(vperp(n), -td), vmult(n, d)), a.p); - } - - // Calculate mass tensor - k_tensor(a, b, this.r1, this.r2, this.k1, this.k2); - - // compute max impulse - this.jMaxLen = this.maxForce * dt; - - // calculate bias velocity - var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); - this.bias = vclamp(vmult(delta, -bias_coef(this.errorBias, dt)/dt), this.maxBias); - }; - - GrooveJoint.prototype.applyCachedImpulse = function(dt_coef) - { - apply_impulses(this.a, this.b, this.r1, this.r2, this.jAcc.x * dt_coef, this.jAcc.y * dt_coef); - }; - - GrooveJoint.prototype.grooveConstrain = function(j){ - var n = this.grv_tn; - var jClamp = (this.clamp*vcross(j, n) > 0) ? j : vproject(j, n); - return vclamp(jClamp, this.jMaxLen); - }; - - GrooveJoint.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - var r1 = this.r1; - var r2 = this.r2; - - // compute impulse - var vr = relative_velocity(a, b, r1, r2); - - var j = mult_k(vsub(this.bias, vr), this.k1, this.k2); - var jOld = this.jAcc; - this.jAcc = this.grooveConstrain(vadd(jOld, j)); - - // apply impulse - apply_impulses(a, b, this.r1, this.r2, this.jAcc.x - jOld.x, this.jAcc.y - jOld.y); - }; - - GrooveJoint.prototype.getImpulse = function() - { - return vlength(this.jAcc); - }; - - GrooveJoint.prototype.setGrooveA = function(value) - { - this.grv_a = value; - this.grv_n = vperp(vnormalize(vsub(this.grv_b, value))); - - this.activateBodies(); - }; - - GrooveJoint.prototype.setGrooveB = function(value) - { - this.grv_b = value; - this.grv_n = vperp(vnormalize(vsub(value, this.grv_a))); - - this.activateBodies(); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var defaultSpringForce = function(spring, dist){ - return (spring.restLength - dist)*spring.stiffness; - }; - - var DampedSpring = cp.DampedSpring = function(a, b, anchr1, anchr2, restLength, stiffness, damping) - { - Constraint.call(this, a, b); - - this.anchr1 = anchr1; - this.anchr2 = anchr2; - - this.restLength = restLength; - this.stiffness = stiffness; - this.damping = damping; - this.springForceFunc = defaultSpringForce; - - this.target_vrn = this.v_coef = 0; - - this.r1 = this.r2 = null; - this.nMass = 0; - this.n = null; - }; - - DampedSpring.prototype = Object.create(Constraint.prototype); - - DampedSpring.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - this.r1 = vrotate(this.anchr1, a.rot); - this.r2 = vrotate(this.anchr2, b.rot); - - var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); - var dist = vlength(delta); - this.n = vmult(delta, 1/(dist ? dist : Infinity)); - - var k = k_scalar(a, b, this.r1, this.r2, this.n); - assertSoft(k !== 0, "Unsolvable this."); - this.nMass = 1/k; - - this.target_vrn = 0; - this.v_coef = 1 - Math.exp(-this.damping*dt*k); - - // apply this force - var f_spring = this.springForceFunc(this, dist); - apply_impulses(a, b, this.r1, this.r2, this.n.x * f_spring * dt, this.n.y * f_spring * dt); - }; - - DampedSpring.prototype.applyCachedImpulse = function(dt_coef){}; - - DampedSpring.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - var n = this.n; - var r1 = this.r1; - var r2 = this.r2; - - // compute relative velocity - var vrn = normal_relative_velocity(a, b, r1, r2, n); - - // compute velocity loss from drag - var v_damp = (this.target_vrn - vrn)*this.v_coef; - this.target_vrn = vrn + v_damp; - - v_damp *= this.nMass; - apply_impulses(a, b, this.r1, this.r2, this.n.x * v_damp, this.n.y * v_damp); - }; - - DampedSpring.prototype.getImpulse = function() - { - return 0; - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var defaultSpringTorque = function(spring, relativeAngle){ - return (relativeAngle - spring.restAngle)*spring.stiffness; - } - - var DampedRotarySpring = cp.DampedRotarySpring = function(a, b, restAngle, stiffness, damping) - { - Constraint.call(this, a, b); - - this.restAngle = restAngle; - this.stiffness = stiffness; - this.damping = damping; - this.springTorqueFunc = defaultSpringTorque; - - this.target_wrn = 0; - this.w_coef = 0; - this.iSum = 0; - }; - - DampedRotarySpring.prototype = Object.create(Constraint.prototype); - - DampedRotarySpring.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - var moment = a.i_inv + b.i_inv; - assertSoft(moment !== 0, "Unsolvable spring."); - this.iSum = 1/moment; - - this.w_coef = 1 - Math.exp(-this.damping*dt*moment); - this.target_wrn = 0; - - // apply this torque - var j_spring = this.springTorqueFunc(this, a.a - b.a)*dt; - a.w -= j_spring*a.i_inv; - b.w += j_spring*b.i_inv; - }; +var PivotJoint = cp.PivotJoint = function(a, b, anchr1, anchr2) +{ + Constraint.call(this, a, b); + + if(typeof anchr2 === 'undefined') { + var pivot = anchr1; + + anchr1 = (a ? a.world2Local(pivot) : pivot); + anchr2 = (b ? b.world2Local(pivot) : pivot); + } + + this.anchr1 = anchr1; + this.anchr2 = anchr2; + + this.r1 = this.r2 = vzero; + + this.k1 = new Vect(0,0); this.k2 = new Vect(0,0); + + this.jAcc = vzero; + + this.jMaxLen = 0; + this.bias = vzero; +}; + +PivotJoint.prototype = Object.create(Constraint.prototype); + +PivotJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + this.r1 = vrotate(this.anchr1, a.rot); + this.r2 = vrotate(this.anchr2, b.rot); + + // Calculate mass tensor. Result is stored into this.k1 & this.k2. + k_tensor(a, b, this.r1, this.r2, this.k1, this.k2); + + // compute max impulse + this.jMaxLen = this.maxForce * dt; + + // calculate bias velocity + var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); + this.bias = vclamp(vmult(delta, -bias_coef(this.errorBias, dt)/dt), this.maxBias); +}; + +PivotJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + apply_impulses(this.a, this.b, this.r1, this.r2, this.jAcc.x * dt_coef, this.jAcc.y * dt_coef); +}; + +PivotJoint.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + var r1 = this.r1; + var r2 = this.r2; + + // compute relative velocity + var vr = relative_velocity(a, b, r1, r2); + + // compute normal impulse + var j = mult_k(vsub(this.bias, vr), this.k1, this.k2); + var jOld = this.jAcc; + this.jAcc = vclamp(vadd(this.jAcc, j), this.jMaxLen); + + // apply impulse + apply_impulses(a, b, this.r1, this.r2, this.jAcc.x - jOld.x, this.jAcc.y - jOld.y); +}; + +PivotJoint.prototype.getImpulse = function() +{ + return vlength(this.jAcc); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var GrooveJoint = cp.GrooveJoint = function(a, b, groove_a, groove_b, anchr2) +{ + Constraint.call(this, a, b); + + this.grv_a = groove_a; + this.grv_b = groove_b; + this.grv_n = vperp(vnormalize(vsub(groove_b, groove_a))); + this.anchr2 = anchr2; + + this.grv_tn = null; + this.clamp = 0; + this.r1 = this.r2 = null; + + this.k1 = new Vect(0,0); + this.k2 = new Vect(0,0); + + this.jAcc = vzero; + this.jMaxLen = 0; + this.bias = null; +}; + +GrooveJoint.prototype = Object.create(Constraint.prototype); + +GrooveJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + // calculate endpoints in worldspace + var ta = a.local2World(this.grv_a); + var tb = a.local2World(this.grv_b); + + // calculate axis + var n = vrotate(this.grv_n, a.rot); + var d = vdot(ta, n); + + this.grv_tn = n; + this.r2 = vrotate(this.anchr2, b.rot); + + // calculate tangential distance along the axis of r2 + var td = vcross(vadd(b.p, this.r2), n); + // calculate clamping factor and r2 + if(td <= vcross(ta, n)){ + this.clamp = 1; + this.r1 = vsub(ta, a.p); + } else if(td >= vcross(tb, n)){ + this.clamp = -1; + this.r1 = vsub(tb, a.p); + } else { + this.clamp = 0; + this.r1 = vsub(vadd(vmult(vperp(n), -td), vmult(n, d)), a.p); + } + + // Calculate mass tensor + k_tensor(a, b, this.r1, this.r2, this.k1, this.k2); + + // compute max impulse + this.jMaxLen = this.maxForce * dt; + + // calculate bias velocity + var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); + this.bias = vclamp(vmult(delta, -bias_coef(this.errorBias, dt)/dt), this.maxBias); +}; + +GrooveJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + apply_impulses(this.a, this.b, this.r1, this.r2, this.jAcc.x * dt_coef, this.jAcc.y * dt_coef); +}; + +GrooveJoint.prototype.grooveConstrain = function(j){ + var n = this.grv_tn; + var jClamp = (this.clamp*vcross(j, n) > 0) ? j : vproject(j, n); + return vclamp(jClamp, this.jMaxLen); +}; + +GrooveJoint.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + var r1 = this.r1; + var r2 = this.r2; + + // compute impulse + var vr = relative_velocity(a, b, r1, r2); + + var j = mult_k(vsub(this.bias, vr), this.k1, this.k2); + var jOld = this.jAcc; + this.jAcc = this.grooveConstrain(vadd(jOld, j)); + + // apply impulse + apply_impulses(a, b, this.r1, this.r2, this.jAcc.x - jOld.x, this.jAcc.y - jOld.y); +}; + +GrooveJoint.prototype.getImpulse = function() +{ + return vlength(this.jAcc); +}; + +GrooveJoint.prototype.setGrooveA = function(value) +{ + this.grv_a = value; + this.grv_n = vperp(vnormalize(vsub(this.grv_b, value))); + + this.activateBodies(); +}; + +GrooveJoint.prototype.setGrooveB = function(value) +{ + this.grv_b = value; + this.grv_n = vperp(vnormalize(vsub(value, this.grv_a))); + + this.activateBodies(); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var defaultSpringForce = function(spring, dist){ + return (spring.restLength - dist)*spring.stiffness; +}; + +var DampedSpring = cp.DampedSpring = function(a, b, anchr1, anchr2, restLength, stiffness, damping) +{ + Constraint.call(this, a, b); + + this.anchr1 = anchr1; + this.anchr2 = anchr2; + + this.restLength = restLength; + this.stiffness = stiffness; + this.damping = damping; + this.springForceFunc = defaultSpringForce; + + this.target_vrn = this.v_coef = 0; + + this.r1 = this.r2 = null; + this.nMass = 0; + this.n = null; +}; + +DampedSpring.prototype = Object.create(Constraint.prototype); + +DampedSpring.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + this.r1 = vrotate(this.anchr1, a.rot); + this.r2 = vrotate(this.anchr2, b.rot); + + var delta = vsub(vadd(b.p, this.r2), vadd(a.p, this.r1)); + var dist = vlength(delta); + this.n = vmult(delta, 1/(dist ? dist : Infinity)); + + var k = k_scalar(a, b, this.r1, this.r2, this.n); + assertSoft(k !== 0, "Unsolvable this."); + this.nMass = 1/k; + + this.target_vrn = 0; + this.v_coef = 1 - Math.exp(-this.damping*dt*k); + + // apply this force + var f_spring = this.springForceFunc(this, dist); + apply_impulses(a, b, this.r1, this.r2, this.n.x * f_spring * dt, this.n.y * f_spring * dt); +}; + +DampedSpring.prototype.applyCachedImpulse = function(dt_coef){}; + +DampedSpring.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + var n = this.n; + var r1 = this.r1; + var r2 = this.r2; + + // compute relative velocity + var vrn = normal_relative_velocity(a, b, r1, r2, n); + + // compute velocity loss from drag + var v_damp = (this.target_vrn - vrn)*this.v_coef; + this.target_vrn = vrn + v_damp; + + v_damp *= this.nMass; + apply_impulses(a, b, this.r1, this.r2, this.n.x * v_damp, this.n.y * v_damp); +}; + +DampedSpring.prototype.getImpulse = function() +{ + return 0; +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var defaultSpringTorque = function(spring, relativeAngle){ + return (relativeAngle - spring.restAngle)*spring.stiffness; +} + +var DampedRotarySpring = cp.DampedRotarySpring = function(a, b, restAngle, stiffness, damping) +{ + Constraint.call(this, a, b); + + this.restAngle = restAngle; + this.stiffness = stiffness; + this.damping = damping; + this.springTorqueFunc = defaultSpringTorque; + + this.target_wrn = 0; + this.w_coef = 0; + this.iSum = 0; +}; + +DampedRotarySpring.prototype = Object.create(Constraint.prototype); + +DampedRotarySpring.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + var moment = a.i_inv + b.i_inv; + assertSoft(moment !== 0, "Unsolvable spring."); + this.iSum = 1/moment; + + this.w_coef = 1 - Math.exp(-this.damping*dt*moment); + this.target_wrn = 0; + + // apply this torque + var j_spring = this.springTorqueFunc(this, a.a - b.a)*dt; + a.w -= j_spring*a.i_inv; + b.w += j_spring*b.i_inv; +}; // DampedRotarySpring.prototype.applyCachedImpulse = function(dt_coef){}; - DampedRotarySpring.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - // compute relative velocity - var wrn = a.w - b.w;//normal_relative_velocity(a, b, r1, r2, n) - this.target_vrn; - - // compute velocity loss from drag - // not 100% certain spring is derived correctly, though it makes sense - var w_damp = (this.target_wrn - wrn)*this.w_coef; - this.target_wrn = wrn + w_damp; - - //apply_impulses(a, b, this.r1, this.r2, vmult(this.n, v_damp*this.nMass)); - var j_damp = w_damp*this.iSum; - a.w += j_damp*a.i_inv; - b.w -= j_damp*b.i_inv; - }; +DampedRotarySpring.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + // compute relative velocity + var wrn = a.w - b.w;//normal_relative_velocity(a, b, r1, r2, n) - this.target_vrn; + + // compute velocity loss from drag + // not 100% certain spring is derived correctly, though it makes sense + var w_damp = (this.target_wrn - wrn)*this.w_coef; + this.target_wrn = wrn + w_damp; + + //apply_impulses(a, b, this.r1, this.r2, vmult(this.n, v_damp*this.nMass)); + var j_damp = w_damp*this.iSum; + a.w += j_damp*a.i_inv; + b.w -= j_damp*b.i_inv; +}; // DampedRotarySpring.prototype.getImpulse = function(){ return 0; }; - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var RotaryLimitJoint = cp.RotaryLimitJoint = function(a, b, min, max) - { - Constraint.call(this, a, b); - - this.min = min; - this.max = max; - - this.jAcc = 0; - - this.iSum = this.bias = this.jMax = 0; - }; - - RotaryLimitJoint.prototype = Object.create(Constraint.prototype); - - RotaryLimitJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - var dist = b.a - a.a; - var pdist = 0; - if(dist > this.max) { - pdist = this.max - dist; - } else if(dist < this.min) { - pdist = this.min - dist; - } - - // calculate moment of inertia coefficient. - this.iSum = 1/(1/a.i + 1/b.i); - - // calculate bias velocity - var maxBias = this.maxBias; - this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); - - // compute max impulse - this.jMax = this.maxForce * dt; - - // If the bias is 0, the joint is not at a limit. Reset the impulse. - if(!this.bias) this.jAcc = 0; - }; - - RotaryLimitJoint.prototype.applyCachedImpulse = function(dt_coef) - { - var a = this.a; - var b = this.b; - - var j = this.jAcc*dt_coef; - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - RotaryLimitJoint.prototype.applyImpulse = function() - { - if(!this.bias) return; // early exit - - var a = this.a; - var b = this.b; - - // compute relative rotational velocity - var wr = b.w - a.w; - - // compute normal impulse - var j = -(this.bias + wr)*this.iSum; - var jOld = this.jAcc; - if(this.bias < 0){ - this.jAcc = clamp(jOld + j, 0, this.jMax); - } else { - this.jAcc = clamp(jOld + j, -this.jMax, 0); - } - j = this.jAcc - jOld; - - // apply impulse - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - RotaryLimitJoint.prototype.getImpulse = function() - { - return Math.abs(joint.jAcc); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var RatchetJoint = cp.RatchetJoint = function(a, b, phase, ratchet) - { - Constraint.call(this, a, b); - - this.angle = 0; - this.phase = phase; - this.ratchet = ratchet; - - // STATIC_BODY_CHECK - this.angle = (b ? b.a : 0) - (a ? a.a : 0); - - this.iSum = this.bias = this.jAcc = this.jMax = 0; - }; - - RatchetJoint.prototype = Object.create(Constraint.prototype); - - RatchetJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - var angle = this.angle; - var phase = this.phase; - var ratchet = this.ratchet; - - var delta = b.a - a.a; - var diff = angle - delta; - var pdist = 0; - - if(diff*ratchet > 0){ - pdist = diff; - } else { - this.angle = Math.floor((delta - phase)/ratchet)*ratchet + phase; - } - - // calculate moment of inertia coefficient. - this.iSum = 1/(a.i_inv + b.i_inv); - - // calculate bias velocity - var maxBias = this.maxBias; - this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); - - // compute max impulse - this.jMax = this.maxForce * dt; - - // If the bias is 0, the joint is not at a limit. Reset the impulse. - if(!this.bias) this.jAcc = 0; - }; - - RatchetJoint.prototype.applyCachedImpulse = function(dt_coef) - { - var a = this.a; - var b = this.b; - - var j = this.jAcc*dt_coef; - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - RatchetJoint.prototype.applyImpulse = function() - { - if(!this.bias) return; // early exit - - var a = this.a; - var b = this.b; - - // compute relative rotational velocity - var wr = b.w - a.w; - var ratchet = this.ratchet; - - // compute normal impulse - var j = -(this.bias + wr)*this.iSum; - var jOld = this.jAcc; - this.jAcc = clamp((jOld + j)*ratchet, 0, this.jMax*Math.abs(ratchet))/ratchet; - j = this.jAcc - jOld; - - // apply impulse - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - RatchetJoint.prototype.getImpulse = function(joint) - { - return Math.abs(joint.jAcc); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var GearJoint = cp.GearJoint = function(a, b, phase, ratio) - { - Constraint.call(this, a, b); - - this.phase = phase; - this.ratio = ratio; - this.ratio_inv = 1/ratio; - - this.jAcc = 0; - - this.iSum = this.bias = this.jMax = 0; - }; - - GearJoint.prototype = Object.create(Constraint.prototype); - - GearJoint.prototype.preStep = function(dt) - { - var a = this.a; - var b = this.b; - - // calculate moment of inertia coefficient. - this.iSum = 1/(a.i_inv*this.ratio_inv + this.ratio*b.i_inv); - - // calculate bias velocity - var maxBias = this.maxBias; - this.bias = clamp(-bias_coef(this.errorBias, dt)*(b.a*this.ratio - a.a - this.phase)/dt, -maxBias, maxBias); - - // compute max impulse - this.jMax = this.maxForce * dt; - }; - - GearJoint.prototype.applyCachedImpulse = function(dt_coef) - { - var a = this.a; - var b = this.b; - - var j = this.jAcc*dt_coef; - a.w -= j*a.i_inv*this.ratio_inv; - b.w += j*b.i_inv; - }; - - GearJoint.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - // compute relative rotational velocity - var wr = b.w*this.ratio - a.w; - - // compute normal impulse - var j = (this.bias - wr)*this.iSum; - var jOld = this.jAcc; - this.jAcc = clamp(jOld + j, -this.jMax, this.jMax); - j = this.jAcc - jOld; - - // apply impulse - a.w -= j*a.i_inv*this.ratio_inv; - b.w += j*b.i_inv; - }; - - GearJoint.prototype.getImpulse = function() - { - return Math.abs(this.jAcc); - }; - - GearJoint.prototype.setRatio = function(value) - { - this.ratio = value; - this.ratio_inv = 1/value; - this.activateBodies(); - }; - - /* Copyright (c) 2007 Scott Lembcke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - - var SimpleMotor = cp.SimpleMotor = function(a, b, rate) - { - Constraint.call(this, a, b); - - this.rate = rate; - - this.jAcc = 0; - - this.iSum = this.jMax = 0; - }; - - SimpleMotor.prototype = Object.create(Constraint.prototype); - - SimpleMotor.prototype.preStep = function(dt) - { - // calculate moment of inertia coefficient. - this.iSum = 1/(this.a.i_inv + this.b.i_inv); - - // compute max impulse - this.jMax = this.maxForce * dt; - }; - - SimpleMotor.prototype.applyCachedImpulse = function(dt_coef) - { - var a = this.a; - var b = this.b; - - var j = this.jAcc*dt_coef; - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - SimpleMotor.prototype.applyImpulse = function() - { - var a = this.a; - var b = this.b; - - // compute relative rotational velocity - var wr = b.w - a.w + this.rate; - - // compute normal impulse - var j = -wr*this.iSum; - var jOld = this.jAcc; - this.jAcc = clamp(jOld + j, -this.jMax, this.jMax); - j = this.jAcc - jOld; - - // apply impulse - a.w -= j*a.i_inv; - b.w += j*b.i_inv; - }; - - SimpleMotor.prototype.getImpulse = function() - { - return Math.abs(this.jAcc); - }; +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var RotaryLimitJoint = cp.RotaryLimitJoint = function(a, b, min, max) +{ + Constraint.call(this, a, b); + + this.min = min; + this.max = max; + + this.jAcc = 0; + + this.iSum = this.bias = this.jMax = 0; +}; + +RotaryLimitJoint.prototype = Object.create(Constraint.prototype); + +RotaryLimitJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + var dist = b.a - a.a; + var pdist = 0; + if(dist > this.max) { + pdist = this.max - dist; + } else if(dist < this.min) { + pdist = this.min - dist; + } + + // calculate moment of inertia coefficient. + this.iSum = 1/(1/a.i + 1/b.i); + + // calculate bias velocity + var maxBias = this.maxBias; + this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); + + // compute max impulse + this.jMax = this.maxForce * dt; + + // If the bias is 0, the joint is not at a limit. Reset the impulse. + if(!this.bias) this.jAcc = 0; +}; + +RotaryLimitJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + var a = this.a; + var b = this.b; + + var j = this.jAcc*dt_coef; + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +RotaryLimitJoint.prototype.applyImpulse = function() +{ + if(!this.bias) return; // early exit + + var a = this.a; + var b = this.b; + + // compute relative rotational velocity + var wr = b.w - a.w; + + // compute normal impulse + var j = -(this.bias + wr)*this.iSum; + var jOld = this.jAcc; + if(this.bias < 0){ + this.jAcc = clamp(jOld + j, 0, this.jMax); + } else { + this.jAcc = clamp(jOld + j, -this.jMax, 0); + } + j = this.jAcc - jOld; + + // apply impulse + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +RotaryLimitJoint.prototype.getImpulse = function() +{ + return Math.abs(joint.jAcc); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var RatchetJoint = cp.RatchetJoint = function(a, b, phase, ratchet) +{ + Constraint.call(this, a, b); + + this.angle = 0; + this.phase = phase; + this.ratchet = ratchet; + + // STATIC_BODY_CHECK + this.angle = (b ? b.a : 0) - (a ? a.a : 0); + + this.iSum = this.bias = this.jAcc = this.jMax = 0; +}; + +RatchetJoint.prototype = Object.create(Constraint.prototype); + +RatchetJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + var angle = this.angle; + var phase = this.phase; + var ratchet = this.ratchet; + + var delta = b.a - a.a; + var diff = angle - delta; + var pdist = 0; + + if(diff*ratchet > 0){ + pdist = diff; + } else { + this.angle = Math.floor((delta - phase)/ratchet)*ratchet + phase; + } + + // calculate moment of inertia coefficient. + this.iSum = 1/(a.i_inv + b.i_inv); + + // calculate bias velocity + var maxBias = this.maxBias; + this.bias = clamp(-bias_coef(this.errorBias, dt)*pdist/dt, -maxBias, maxBias); + + // compute max impulse + this.jMax = this.maxForce * dt; + + // If the bias is 0, the joint is not at a limit. Reset the impulse. + if(!this.bias) this.jAcc = 0; +}; + +RatchetJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + var a = this.a; + var b = this.b; + + var j = this.jAcc*dt_coef; + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +RatchetJoint.prototype.applyImpulse = function() +{ + if(!this.bias) return; // early exit + + var a = this.a; + var b = this.b; + + // compute relative rotational velocity + var wr = b.w - a.w; + var ratchet = this.ratchet; + + // compute normal impulse + var j = -(this.bias + wr)*this.iSum; + var jOld = this.jAcc; + this.jAcc = clamp((jOld + j)*ratchet, 0, this.jMax*Math.abs(ratchet))/ratchet; + j = this.jAcc - jOld; + + // apply impulse + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +RatchetJoint.prototype.getImpulse = function(joint) +{ + return Math.abs(joint.jAcc); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var GearJoint = cp.GearJoint = function(a, b, phase, ratio) +{ + Constraint.call(this, a, b); + + this.phase = phase; + this.ratio = ratio; + this.ratio_inv = 1/ratio; + + this.jAcc = 0; + + this.iSum = this.bias = this.jMax = 0; +}; + +GearJoint.prototype = Object.create(Constraint.prototype); + +GearJoint.prototype.preStep = function(dt) +{ + var a = this.a; + var b = this.b; + + // calculate moment of inertia coefficient. + this.iSum = 1/(a.i_inv*this.ratio_inv + this.ratio*b.i_inv); + + // calculate bias velocity + var maxBias = this.maxBias; + this.bias = clamp(-bias_coef(this.errorBias, dt)*(b.a*this.ratio - a.a - this.phase)/dt, -maxBias, maxBias); + + // compute max impulse + this.jMax = this.maxForce * dt; +}; + +GearJoint.prototype.applyCachedImpulse = function(dt_coef) +{ + var a = this.a; + var b = this.b; + + var j = this.jAcc*dt_coef; + a.w -= j*a.i_inv*this.ratio_inv; + b.w += j*b.i_inv; +}; + +GearJoint.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + // compute relative rotational velocity + var wr = b.w*this.ratio - a.w; + + // compute normal impulse + var j = (this.bias - wr)*this.iSum; + var jOld = this.jAcc; + this.jAcc = clamp(jOld + j, -this.jMax, this.jMax); + j = this.jAcc - jOld; + + // apply impulse + a.w -= j*a.i_inv*this.ratio_inv; + b.w += j*b.i_inv; +}; + +GearJoint.prototype.getImpulse = function() +{ + return Math.abs(this.jAcc); +}; + +GearJoint.prototype.setRatio = function(value) +{ + this.ratio = value; + this.ratio_inv = 1/value; + this.activateBodies(); +}; + +/* Copyright (c) 2007 Scott Lembcke + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +var SimpleMotor = cp.SimpleMotor = function(a, b, rate) +{ + Constraint.call(this, a, b); + + this.rate = rate; + + this.jAcc = 0; + + this.iSum = this.jMax = 0; +}; + +SimpleMotor.prototype = Object.create(Constraint.prototype); + +SimpleMotor.prototype.preStep = function(dt) +{ + // calculate moment of inertia coefficient. + this.iSum = 1/(this.a.i_inv + this.b.i_inv); + + // compute max impulse + this.jMax = this.maxForce * dt; +}; + +SimpleMotor.prototype.applyCachedImpulse = function(dt_coef) +{ + var a = this.a; + var b = this.b; + + var j = this.jAcc*dt_coef; + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +SimpleMotor.prototype.applyImpulse = function() +{ + var a = this.a; + var b = this.b; + + // compute relative rotational velocity + var wr = b.w - a.w + this.rate; + + // compute normal impulse + var j = -wr*this.iSum; + var jOld = this.jAcc; + this.jAcc = clamp(jOld + j, -this.jMax, this.jMax); + j = this.jAcc - jOld; + + // apply impulse + a.w -= j*a.i_inv; + b.w += j*b.i_inv; +}; + +SimpleMotor.prototype.getImpulse = function() +{ + return Math.abs(this.jAcc); +}; })(); diff --git a/external/gaf/GAFBoot.js b/external/gaf/GAFBoot.js new file mode 100644 index 0000000000..0baccc7ecd --- /dev/null +++ b/external/gaf/GAFBoot.js @@ -0,0 +1,24 @@ +var gaf = gaf || {}; +gaf._tmp = gaf._tmp || {}; +gaf._initialized = false; + +gaf.CCGAFLoader = function() +{ + this.load = function(realUrl, url, item, cb) + { + if(!gaf._initialized) + { + gaf._setup(); + } + var loader = new gaf.Loader(); + loader.LoadFile(realUrl, function(data){cb(null, data)}); + }; +}; + +gaf._setup = function() +{ + gaf._setupShaders(); + gaf._initialized = true; +}; + +cc.loader.register('.gaf', new gaf.CCGAFLoader()); diff --git a/external/gaf/GAFMacros.js b/external/gaf/GAFMacros.js new file mode 100644 index 0000000000..ef34cc8f5d --- /dev/null +++ b/external/gaf/GAFMacros.js @@ -0,0 +1,33 @@ +var gaf = gaf || {}; + +gaf.COMPRESSION_NONE = 0x00474146; +gaf.COMPRESSION_ZIP = 0x00474143; + +gaf.IDNONE = 0xffffffff; +gaf.FIRST_FRAME_INDEX = 0; + +gaf.EFFECT_DROP_SHADOW = 0; +gaf.EFFECT_BLUR = 1; +gaf.EFFECT_GLOW = 2; +gaf.EFFECT_COLOR_MATRIX = 6; + +gaf.ACTION_STOP = 0; +gaf.ACTION_PLAY = 1; +gaf.ACTION_GO_TO_AND_STOP = 2; +gaf.ACTION_GO_TO_AND_PLAY = 3; +gaf.ACTION_DISPATCH_EVENT = 4; + +gaf.PI_FRAME = 0; +gaf.PI_EVENT_TYPE = 0; + +gaf.TYPE_TEXTURE = 0; +gaf.TYPE_TEXT_FIELD = 1; +gaf.TYPE_TIME_LINE = 2; + +gaf.UNIFORM_BLUR_TEXEL_OFFSET = "u_step"; +gaf.UNIFORM_GLOW_TEXEL_OFFSET = "u_step"; +gaf.UNIFORM_GLOW_COLOR = "u_glowColor"; +gaf.UNIFORM_ALPHA_TINT_MULT = "colorTransformMult"; +gaf.UNIFORM_ALPHA_TINT_OFFSET = "colorTransformOffsets"; +gaf.UNIFORM_ALPHA_COLOR_MATRIX_BODY = "colorMatrix"; +gaf.UNIFORM_ALPHA_COLOR_MATRIX_APPENDIX = "colorMatrix2"; diff --git a/external/gaf/Library/GAFAsset.js b/external/gaf/Library/GAFAsset.js new file mode 100644 index 0000000000..23804e61ff --- /dev/null +++ b/external/gaf/Library/GAFAsset.js @@ -0,0 +1,429 @@ +var gaf = gaf || {}; + +gaf.Asset = cc.Class.extend +({ + _className: "GAFAsset", + + // Private members + _header: null, + _timeLines: null, + _textFields: null, + _protos: null, + _objects: null, + _masks: null, + + _rootTimeLine: null, + _textureLoadDelegate: null, + _sceneFps: 60, + _sceneWidth: 0, + _sceneHeight: 0, + _sceneColor: 0, + _gafData: null, + _desiredAtlasScale: 1, + _usedAtlasScale: 0, + + _atlases: null, + _onLoadTasks: null, + _atlasScales: null, + _textureLoaded: false, // For async loading with cc.event manager + _atlasesToLoad: null, // Atlases that are not yet loaded + _gafName: null, + + /** + * @method initWithGAFFile + * @param {String} filePath - path to .gaf file + * @param {String function(String)} textureLoadDelegate - is used to change atlas path, e.g. to load `atlas.tga` instead of `atlas.png` + * @return {bool} + */ + initWithGAFFile: function (filePath, textureLoadDelegate) { + var self = this; + this._textureLoadDelegate = textureLoadDelegate; + this._gafName = filePath; + var gafData = cc.loader.getRes(filePath); + if(!gafData) + { + cc.loader.load(filePath, function(err, data){ + if(!err) + { + self._init(data[0]); + } + }); + } + else { + return this._init(gafData); + } + return false; + }, + + /** + * @method initWithGAFBundle + * @param {String} zipFilePath - path to the archive with .gaf and its textures + * @param {String} entryFile - name of the .gaf file in archive + * @param {function({path:String})} delegate - is used to change atlas path, e.g. to load `atlas.tga` instead of `atlas.png` + * @return {bool} + */ + initWithGAFBundle: function (zipFilePath, entryFile, delegate) + { + cc.assert(false, "initWithGAFBundle is not yet implemented"); + return false; + }, + + /** + * @method setRootTimelineWithName + * @param {String} name + */ + setRootTimelineWithName: function (name) + { + for(var i = 0, end = this._timeLines.length; i < end; ++i) + { + var object = this._timeLines[i]; + if (object && object.getLinkageName() === name) + { + this._setRootTimeline(object); + return; + } + } + }, + +/* addEventListener: function(name, listener) + {},*/ + + isAssetVersionPlayable: function () + { + return true; + }, + + /** + * Desired atlas scale. + * Default is 1.0f + * @returns {number} + */ + desiredAtlasScale : function(){ + return this._desiredAtlasScale; + }, + + /** + * Sets desired atlas scale. Will choose nearest atlas scale from available. + * Default is 1.0f + * @param scale + */ + setDesiredAtlasScale : function(desiredAtlasScale){ + this._desiredAtlasScale = desiredAtlasScale; + for(var currentScale in this._atlasScales)if(this._atlasScales.hasOwnProperty(currentScale)) + { + if( (this._usedAtlasScale === 0) || + (Math.abs(this._usedAtlasScale - desiredAtlasScale) > Math.abs(currentScale - desiredAtlasScale) )) + { + this._usedAtlasScale = currentScale; + } + + } + }, + + /** + * @method createObject + * @return {gaf.Object} + */ + createObject: function () + { + return this._instantiateGaf(this._gafData); + }, + + /** + * @method createObjectAndRun + * @param {boolean} arg0 - run looped + * @return {gaf.Object} + */ + createObjectAndRun: function (looped) + { + cc.assert(arguments.length === 1, "GAFAsset::createObjectAndRun should have one param"); + var object = this._instantiateGaf(this._gafData); + object.setLooped(looped, true); + object.start(); + return object; + }, + + /** + * @method setTextureLoadDelegate + * @param {function} delegate + */ + setTextureLoadDelegate: function (delegate) + { + debugger; + }, + + + /** + * @method getSceneFps + * @return {uint} + */ + getSceneFps: function () + { + return this._sceneFps; + }, + + /** + * @method getSceneWidth + * @return {uint} + */ + getSceneWidth: function () + { + debugger; + }, + + /** + * @method getSceneHeight + * @return {uint} + */ + getSceneHeight: function () + { + debugger; + }, + + /** + * @method getSceneColor + * @return {cc.color4b} + */ + getSceneColor: function () + { + debugger; + }, + + /** + * @method setSceneFps + * @param {uint} fps + */ + setSceneFps: function (fps) + { + this._sceneFps = fps; + }, + + /** + * @method setSceneWidth + * @param {uint} width + */ + setSceneWidth: function (width) + { + debugger; + }, + + /** + * @method setSceneHeight + * @param {uint} height + */ + setSceneHeight: function (height) + { + debugger; + }, + + /** + * @method setSceneColor + * @param {color4b_object} arg0 + */ + setSceneColor: function (color4B) + { + debugger; + }, + + /** + * @method getHeader + * @return {GAFHeader} + */ + getHeader: function () + { + return this._header; + }, + + getGAFFileName: function() + { + return this._gafName; + }, + + // Private + + ctor : function() + { + this._header = {}; + this._timeLines = []; + this._textFields = []; + this._objects = []; + this._masks = []; + this._protos = []; + this._atlases = {}; + this._onLoadTasks = []; + this._atlasScales = {}; + this._atlasesToLoad = {}; + + if(arguments.length > 0) + this.initWithGAFFile.apply(this, arguments); + }, + + _getProtos: function() + { + return this._protos; + }, + + _setRootTimeline : function(timeLine) + { + this._rootTimeLine = timeLine; + this._header.pivot = timeLine.getPivot(); + this._header.frameSize = timeLine.getRect(); + }, + + _setHeader : function (gafHeader) + { + for(var prop in gafHeader) + { + if(gafHeader.hasOwnProperty(prop)) + { + this._header[prop] = gafHeader[prop]; + } + } + }, + + _getMajorVerison : function() + { + return this._header.versionMajor; + }, + + _init : function(gafData) + { + var self = this; + this._gafData = gafData; + this._setHeader(gafData.header); + this._timeLinesToLink = []; + if(this._getMajorVerison() < 4) + { + this._pushTimeLine(new gaf._TimeLineProto(this, this._header.framesCount, this._header.frameSize, this._header.pivot)); + } + gaf._AssetPreload.Tags(this, gafData.tags, this._rootTimeLine); + + //Link and create + this._objects.forEach(function(item) + { + switch(item.type) + { + case gaf.TYPE_TEXTURE: + // Create gaf sprite proto if it is not yet created + if(!self._protos[item.objectId]) + { + self._protos[item.objectId] = new gaf._SpriteProto(self, self._atlasScales, item.elementAtlasIdRef); + } + break; + case gaf.TYPE_TIME_LINE: + // All time line protos are already created, just copy reference + self._protos[item.objectId] = self._timeLines[item.elementAtlasIdRef]; + break; + case gaf.TYPE_TEXT_FIELD: + // All text field protos are already created, just copy reference + self._protos[item.objectId] = self._textFields[item.elementAtlasIdRef]; + break; + default: + cc.log("Unknown object type: " + item.type); + break; + } + }); + this._masks.forEach(function(item) + { + if(self._protos[item.objectId]) + { + return; // this is continue + } + var proto = null; + switch(item.type) + { + case gaf.TYPE_TEXTURE: + // Create gaf sprite proto if it is not yet created + proto = new gaf._SpriteProto(self, self._atlasScales, item.elementAtlasIdRef); + break; + case gaf.TYPE_TIME_LINE: + // All time line protos are already created, just copy reference + proto = self._timeLines[item.elementAtlasIdRef]; + break; + case gaf.TYPE_TEXT_FIELD: + // All text field protos are already created, just copy reference + proto = self._textFields[item.elementAtlasIdRef]; + break; + } + self._protos[item.objectId] = new gaf._MaskProto(self, proto, item.elementAtlasIdRef); + }); + this.setDesiredAtlasScale(this._desiredAtlasScale); + + if(Object.keys(this._atlasesToLoad).length === 0) + { + this._textureLoaded = true; + this.dispatchEvent("load"); + } + }, + + _pushTimeLine : function(timeLine) + { + this._timeLines[timeLine.getId()] = timeLine; + + if(timeLine.getId() === 0) + { + this._setRootTimeline(timeLine); + } + }, + + _instantiateGaf : function() + { + var root = null; + root = this._rootTimeLine._gafConstruct(); + return root; + }, + + _onAtlasLoaded : function(id, atlas) + { + this._atlases[id] = atlas; + delete this._atlasesToLoad[id]; + if(Object.keys(this._atlasesToLoad).length === 0) + { + this._onLoadTasks.forEach(function(fn){fn()}); + this._onLoadTasks.length = 0; + this._textureLoaded = true; + this.dispatchEvent("load"); + } + }, + + isLoaded : function() + { + return this._textureLoaded; + }, + + _getSearchPaths: function(imageUrl) + { + var extendedPath = this.getGAFFileName().split('/'); + extendedPath[extendedPath.length-1] = imageUrl; + var alternativeUrl = extendedPath.join('/'); + + return [imageUrl, alternativeUrl]; + } +}); + +/** + * @method initWithGAFFile + * @param {String} gafFilePath - path to .gaf file + * @param {function({path:String})} delegate - is used to change atlas path, e.g. to load `atlas.tga` instead of `atlas.png` + * @return {gaf.Asset} + */ +gaf.Asset.create = function (gafFilePath, delegate) +{ + return new gaf.Asset(gafFilePath, delegate); +}; + +/** + * @method createWithBundle + * @param {String} zipFilePath - path to the archive with .gaf and its textures + * @param {String} entryFile - name of the .gaf file in archive + * @param {function({path:String})} delegate - is used to change atlas path, e.g. to load `atlas.tga` instead of `atlas.png` + * @return {gaf.Asset} + */ +gaf.Asset.createWithBundle = function (zipFilePath, entryFile, delegate) +{ + var asset = new gaf.Asset(); + asset.initWithGAFBundle(zipFilePath, entryFile, delegate); + return asset; +}; + +cc.EventHelper.prototype.apply(gaf.Asset.prototype); diff --git a/external/gaf/Library/GAFAssetPreload.js b/external/gaf/Library/GAFAssetPreload.js new file mode 100644 index 0000000000..8514e09f2d --- /dev/null +++ b/external/gaf/Library/GAFAssetPreload.js @@ -0,0 +1,270 @@ + +gaf.CGAffineTransformCocosFormatFromFlashFormat = function(transform) +{ + var t = {}; + t.a = transform.a; + t.b = -transform.b; + t.c = -transform.c; + t.d = transform.d; + t.tx = transform.tx; + t.ty = -transform.ty; + return t; +}; + +gaf._AssetPreload = function() +{ + this["0"] = this.End; + this["1"] = this.Atlases; + this["2"] = this.AnimationMasks; + this["3"] = this.AnimationObjects; + this["4"] = this.AnimationFrames; + this["5"] = this.NamedParts; + this["6"] = this.Sequences; + this["7"] = this.TextFields; + this["8"] = this.Atlases; // 2 + this["9"] = this.Stage; + this["10"] = this.AnimationObjects; //2 + this["11"] = this.AnimationMasks; // 2 + this["12"] = this.AnimationFrames; // 2 + this["13"] = this.TimeLine; +}; + +gaf._AssetPreload.prototype.End = function(asset, content, timeLine){ + if(timeLine) + { + timeLine.getFps = function() + { + return asset.getSceneFps(); + }; + } +}; + +gaf._AssetPreload.prototype.Tag = function(asset, tag, timeLine) +{ + (this[tag.tagId]).call(this, asset, tag.content, timeLine); +}; + +gaf._AssetPreload.prototype.Tags = function(asset, tags, timeLine) +{ + var self = this; + tags.forEach(function(tag) + { + self.Tag(asset, tag, timeLine); + }); +}; + +gaf._AssetPreload.prototype.AtlasCreateFrames = function(elements, asset, spriteFrames) +{ + elements.forEach(function (item) { + var texture = asset._atlases[item.atlasId]; + var rect = cc.rect(item.origin.x, item.origin.y, item.size.x, item.size.y); + var frame = new cc.SpriteFrame(texture, rect); + frame._gafAnchor = + { + x: (0 - (0 - (item.pivot.x / item.size.x))), + y: (0 + (1 - (item.pivot.y / item.size.y))) + }; + spriteFrames[item.elementAtlasId] = frame; + // 9 grid + }); +}; + + + +gaf._AssetPreload.prototype.Atlases = function(asset, content, timeLine) +{ + var spriteFrames = asset._atlasScales[content.scale] = asset._atlasScales[content.scale] || []; + var csf = cc.Director._getInstance().getContentScaleFactor(); + + content.atlases.forEach(function(item) + { + var atlasId = item.id; + var finalizeLoading = function() + { + gaf._AssetPreload.AtlasCreateFrames(content.elements, asset, spriteFrames); + }; + + var atlasPath = ""; + item.sources.forEach(function(atlasSource) + { + if(atlasSource.csf === csf) + { + atlasPath = atlasSource.source; + } + }); + cc.assert(atlasPath, "GAF Error. Texture for current CSF not found. Reconvert animation with correct parameters."); + + if(asset._textureLoadDelegate) + { + atlasPath = asset._textureLoadDelegate(atlasPath); + } + + var loaded = false; + var paths = asset._getSearchPaths(atlasPath); + for(var i = 0, len = paths.length; i < len; ++i){ + var path = paths[i]; + var atlas = cc.textureCache.getTextureForKey(path); + if(atlas && atlas.isLoaded()) + { + atlas.handleLoadedTexture(true); + loaded = true; + asset._atlases[atlasId] = atlas; + finalizeLoading(); + break; + } + } + // Need to load atlases async + if(!loaded) + { + var success = function (atlas) { + atlas.handleLoadedTexture(true); + asset._onAtlasLoaded(atlasId, atlas); + }; + + var fail = function () { + cc.log("GAF Error. Couldn't find `" + atlasPath + "` required by `" + asset.getGAFFileName() + "`"); + }; + + if(!asset._atlasesToLoad.hasOwnProperty(atlasId)) + { + gaf._AtlasLoader.loadArray(paths, success, fail); + asset._atlasesToLoad[atlasId] = {}; + } + asset._onLoadTasks.push(finalizeLoading); + } + }); +}; + +gaf._AssetPreload.prototype.AnimationObjects = function(asset, content, timeLine) +{ + content.forEach(function(item) + { + item.type = (item.type === undefined) ? gaf.TYPE_TEXTURE : item.type; + timeLine._objects.push(item.objectId); + asset._objects[item.objectId] = item; + }); +}; + +gaf._AssetPreload.prototype.convertTint = function(mat, alpha) +{ + if(!mat) + return null; + return { + mult: + { + r: mat.redMultiplier * 255, + g: mat.greenMultiplier * 255, + b: mat.blueMultiplier * 255, + a: alpha * 255 + }, + offset: + { + r: mat.redOffset * 255, + g: mat.greenOffset * 255, + b: mat.blueOffset * 255, + a: mat.alphaOffset * 255 + } + }; +}; + +gaf._AssetPreload.prototype.convertState = function(state) +{ + return { + hasColorTransform: state.hasColorTransform, + hasMask: state.hasMask, + hasEffect: state.hasEffect, + objectIdRef: state.objectIdRef, + depth: state.depth, + alpha: state.alpha * 255, + matrix: gaf.CGAffineTransformCocosFormatFromFlashFormat(state.matrix), + colorTransform: this.convertTint(state.colorTransform, state.alpha), + effect: state.effect, + maskObjectIdRef: state.maskObjectIdRef + }; +}; + +gaf._AssetPreload.prototype.AnimationFrames = function(asset, content, timeLine) +{ + var self = this; + cc.assert(timeLine, "Error. Time Line should not be null."); + var statesForId = {}; + var frames = []; + var lastFrame = {}; + for(var i = 0, len = content.length; i < len; ++i) + { + var frame = content[i]; + if(frame.state) + { + frame.state.forEach(function (state) + { + if (state.alpha !== 0) + { + statesForId[state.objectIdRef] = self.convertState(state); + } + else + { + statesForId[state.objectIdRef] = null; + } + }); + } + var stateArray = []; + for(var obj in statesForId){ if(statesForId.hasOwnProperty(obj) && statesForId[obj]) + { + stateArray.push(statesForId[obj]); + }} + lastFrame = frame; + frames[frame.frame - 1] = {states: stateArray, actions: frame.actions || null}; + } + timeLine.getFrames = function(){return frames}; +}; + +gaf._AssetPreload.prototype.NamedParts = function(asset, content, timeLine) +{ + var parts = {}; + content.forEach(function(item) + { + parts[item.name] = item.objectId; + }); + timeLine.getNamedParts = function(){return parts}; +}; + +gaf._AssetPreload.prototype.Sequences = function(asset, content, timeLine) +{ + var sequences = {}; + content.forEach(function(item){ + sequences[item.id] = {start: item.start - 1, end: item.end}; + }); + timeLine.getSequences = function(){return sequences}; +}; + +gaf._AssetPreload.prototype.TextFields = function(asset, content, timeLine) +{ + debugger; +}; + +gaf._AssetPreload.prototype.Stage = function(asset, content, timeLine) +{ + asset._sceneFps = content.fps; + asset._sceneColor = content.color; + asset._sceneWidth = content.width; + asset._sceneHeight = content.height; +}; + +gaf._AssetPreload.prototype.AnimationMasks = function(asset, content, timeLine) +{ + content.forEach(function(item) + { + item.type = (item.type === undefined) ? gaf.TYPE_TEXTURE : item.type; + timeLine._objects.push(item.objectId); + asset._masks[item.objectId] = item; + }); +}; + +gaf._AssetPreload.prototype.TimeLine = function(asset, content, timeLine) +{ + var result = new gaf._TimeLineProto(asset, content.animationFrameCount, content.boundingBox, content.pivotPoint, content.id, content.linkageName); + asset._pushTimeLine(result); + this.Tags(asset, content.tags, result); +}; + +gaf._AssetPreload = new gaf._AssetPreload(); diff --git a/external/gaf/Library/GAFAtlasLoader.js b/external/gaf/Library/GAFAtlasLoader.js new file mode 100644 index 0000000000..152bba0788 --- /dev/null +++ b/external/gaf/Library/GAFAtlasLoader.js @@ -0,0 +1,50 @@ +/** + * Created by admiral on 19.02.2015. + */ + +gaf._AtlasLoader = {}; +gaf._AtlasLoader.execute = function(condition, success, fail) +{ + condition() ? success() : fail(); +}; + +gaf._AtlasLoader.checkAtlas = function(atlas) // curried function +{ + return function(){return atlas && typeof atlas !== "string" && atlas.isLoaded()}; +}; + +gaf._AtlasLoader.load = function(path, success, fail) +{ + cc.textureCache.addImage(path, function(atlas){ + gaf._AtlasLoader.execute( + gaf._AtlasLoader.checkAtlas(atlas), + function(){success(atlas)}, + fail + ); + }); +}; + +gaf._AtlasLoader.loadFront = function(arr, success, fail) +{ + // Call recursively this function for each element starting from the first + // stops on first success, or fails after last element + return function() + { + if (arr.length > 0){ + gaf._AtlasLoader.load( + arr[0], + success, + gaf._AtlasLoader.loadFront( + arr.slice(1), + success, + fail + ));} + else + fail(); + } +}; + +gaf._AtlasLoader.loadArray = function(array, success, fail) +{ + gaf._AtlasLoader.loadFront(array, success, fail)(); +}; diff --git a/external/gaf/Library/GAFDataReader.js b/external/gaf/Library/GAFDataReader.js new file mode 100644 index 0000000000..3affbe1335 --- /dev/null +++ b/external/gaf/Library/GAFDataReader.js @@ -0,0 +1,229 @@ +gaf.DataReader = function(data) { + this.dataRaw = data; + this.buf = new DataView(data); + this.offset = [0]; +}; + +gaf.DataReader.prototype.constructor = gaf.DataReader; + +gaf.DataReader.prototype.newOffset = function(size){ + this.offset[this.offset.length - 1] += size; + if(this.getOffset() > this.maxOffset()){ + throw new Error("GAF format error"); + } + return this.offset[this.offset.length - 1] - size; +}; + +gaf.DataReader.prototype.maxOffset = function(){ + if(this.offset.length == 1){ + return this.buf.byteLength; + } + else{ + return this.offset[this.offset.length - 2]; + } +}; + +gaf.DataReader.prototype.getOffset = function(size){ + return this.offset[this.offset.length - 1]; +}; + +gaf.DataReader.prototype.Ubyte = function() { + return this.buf.getUint8(this.newOffset(1)); +}; + +gaf.DataReader.prototype.Boolean = function() { + var result = this.buf.getUint8(this.newOffset(1)); + if(result > 1){ + throw new Error("GAF format error"); + } + return result; +}; + +gaf.DataReader.prototype.Uint = function() { + return this.buf.getUint32(this.newOffset(4), true); +}; + +gaf.DataReader.prototype.Int = function() { + return this.buf.getInt32(this.newOffset(4), true); +}; + +gaf.DataReader.prototype.color = function() { + return { + b: this.Ubyte(), + g: this.Ubyte(), + r: this.Ubyte(), + a: this.Ubyte() + }; +}; + +gaf.DataReader.prototype.Ushort = function() { + return this.buf.getUint16(this.newOffset(2), true); +}; + +gaf.DataReader.prototype.Float = function() { + return this.buf.getFloat32(this.newOffset(4), true); +}; + +gaf.DataReader.prototype.String = function() { + var strLen = this.Ushort(); + var from = this.newOffset(strLen); + var to = this.getOffset(); + + try + { + var str = this.dataRaw.slice(from, to); + } + catch(e) + { + // Internet Explorer 10 T.T + if(e.message == "Object doesn't support property or method 'slice'") + { + str = []; + for(var i = from; i < to; ++i) + str.push(this.buf.getUint8(i)); + } + else + { + throw(e); + } + } + return decodeURIComponent(escape(String.fromCharCode.apply(null, new Uint8Array(str)))); + +}; + +gaf.DataReader.prototype.startNestedBuffer = function(length) { + this.offset.push(this.offset[this.offset.length-1]); + this.offset[this.offset.length-2] += length; +}; + +gaf.DataReader.prototype.endNestedBuffer = function() { + if (this.offset.length == 1) throw new Error('No nested buffer available'); + this.offset.pop(); +}; + +gaf.DataReader.prototype.Point = function(){ + return { + x: this.Float(), + y: this.Float() + }; +}; + +gaf.DataReader.prototype.Rect = function(){ + return { + x: this.Float(), + y: this.Float(), + width: this.Float(), + height: this.Float() + }; +}; + +gaf.DataReader.prototype.Matrix = function(){ + return { + a: this.Float(), + b: this.Float(), + c: this.Float(), + d: this.Float(), + tx: this.Float(), + ty: this.Float() + }; +}; + +gaf.DataReader.prototype.seek = function(pos){ + this.offset[this.offset.length-1] = pos; +}; + +gaf.DataReader.prototype.tell = function(){ + return this.offset[this.offset.length-1]; +}; + +/* Creates a fields parsing function +* @ returns a function that will read from DataReader `field` of type `type` +* @`key` - key for read data to be stored +* @`data` - data to store. Can be DataReader function name or a function that will return a value +* Note. Parameters pair `key` and `data` can be repeated any number of times*/ + +gaf.DataReader.prototype.fields = function(){ + var self = this; + var arguments_ = arguments; + return function(){ + arguments.callee.result = {}; + var i = 0; + if(arguments_.length % 2){ + throw new Error('Number of arguments is not even'); + } + while(i < arguments_.length){ + var field = arguments_[i++]; + var func = arguments_[i++]; + if(typeof func === 'function'){ + arguments.callee.result[field] = func(); + } + else if (func in self && typeof self[func] === 'function'){ + arguments.callee.result[field] = self[func].call(self); + } + else{ + throw new Error('Object DataReader has no function `' + func + '`'); + } + } + return arguments.callee.result; + } +}; + +/* +* Creates a parsing function +* @ returns function that will execute expression if caller's `result` field has `key` equal to `value` parameter +* @ `key` - key in caller's `result` element +* @ `value` - expected value of the `key` or a comparator function +* @ `func` - function to execute if condition is true +* */ + +gaf.DataReader.prototype.condition = function(key, value, func){ + var arguments_ = arguments; + return function() { + if(arguments_.length != 3){ + throw new Error('Condition function'); + } + var parent = arguments.callee.caller; + if(!('result' in parent)){ + throw new Error('Condition function caller has no key `result`'); + } + var container = parent.result; + var field = arguments_[0]; + var value = arguments_[1]; + var exec = arguments_[2]; + + var evaluate = null; + if(typeof value === 'function'){ + evaluate = function(){return value(container[field]);}; + } + else{ + evaluate = function(){return value == container[field];}; + } + if(evaluate()){ + return exec(); + } + else{ + return null; + } + } +}; + +/* +* Creates an array parsing function +* @ returns function that will execute `func` number of times read from DataReader +* @ `type` - type of count number +* @ `func` - function to be executed +* */ + +gaf.DataReader.prototype.array = function(){ + var self = this; + var arguments_ = arguments; + return function() { + arguments.callee.result = []; + var length = self[arguments_[0]].call(self); + for (var i = 0; i < length; ++i) { + var r = arguments_[1].call(); + arguments.callee.result.push(r); + } + return arguments.callee.result; + } +}; diff --git a/external/gaf/Library/GAFLoader.js b/external/gaf/Library/GAFLoader.js new file mode 100644 index 0000000000..3e40c33947 --- /dev/null +++ b/external/gaf/Library/GAFLoader.js @@ -0,0 +1,75 @@ +var gaf = gaf || {}; + +//@Private class +gaf.Loader = function(){ + + var readHeaderBegin = function(stream, header){ + header.compression = stream.Uint(); + header.versionMajor = stream.Ubyte(); + header.versionMinor = stream.Ubyte(); + header.fileLength = stream.Uint(); + }; + + var readHeaderEndV3 = function(stream, header) { + header.framesCount = stream.Ushort(); + header.frameSize = stream.Rect(); + header.pivot = stream.Point(); + }; + + var readHeaderEndV4 = function(stream, header){ + var scaleCount = stream.Uint(); + header.scaleValues = []; + for(var i = 0; i < scaleCount; ++i){ + header.scaleValues.push(stream.Float()); + } + var csfCount = stream.Uint(); + header.csfValues = []; + for(var i = 0; i < csfCount; ++i){ + header.csfValues.push(stream.Float()); + } + }; + + this.LoadFile = function(filePath, onLoaded){ + var oReq = new XMLHttpRequest(); + oReq.open("GET", filePath, true); + var self = this; + oReq.responseType = "arraybuffer"; + oReq.onload = function(oEvent) { + var gaf_data = new gaf.DataReader(oReq.response); + var gafFile = self.LoadStream(gaf_data); + if(onLoaded) + onLoaded(gafFile); + }; + oReq.send(); + }; + + this.LoadStream = function(stream){ + var header = {}; + readHeaderBegin(stream, header); + if(header.compression == gaf.COMPRESSION_NONE) { // GAF + } + else if(header.compression == gaf.COMPRESSION_ZIP){ // GAC + var compressed = stream.dataRaw.slice(stream.tell()); + + var inflate = new window.Zlib.Inflate(new Uint8Array(compressed)); + var decompressed = inflate.decompress(); + stream = new gaf.DataReader(decompressed.buffer); + } + else{ + throw new Error("GAF syntax error."); + } + + if(header.versionMajor < 4){ + readHeaderEndV3(stream, header); + } + else{ + readHeaderEndV4(stream, header); + } + + var tags = gaf.ReadTags(stream); + return { + header: header, + tags: tags + }; + }; +}; diff --git a/external/gaf/Library/GAFMask.js b/external/gaf/Library/GAFMask.js new file mode 100644 index 0000000000..34ca20681c --- /dev/null +++ b/external/gaf/Library/GAFMask.js @@ -0,0 +1,36 @@ + +gaf.Mask = gaf.Object.extend +({ + _className: "GAFMask", + _clippingNode: null, + + ctor : function(gafSpriteProto) + { + this._super(); + cc.assert(gafSpriteProto, "Error! Missing mandatory parameter."); + this._gafproto = gafSpriteProto; + }, + + _init : function() + { + var maskNodeProto = this._gafproto.getMaskNodeProto(); + cc.assert(maskNodeProto, "Error. Mask node for id ref " + this._gafproto.getIdRef() + " not found."); + this._maskNode = maskNodeProto._gafConstruct(); + this._clippingNode = cc.ClippingNode.create(this._maskNode); + this._clippingNode.setAlphaThreshold(0.5); + this.addChild(this._clippingNode); + }, + + setExternalTransform : function(affineTransform) + { + if(!cc.affineTransformEqualToTransform(this._maskNode._additionalTransform, affineTransform)) + { + this._maskNode.setAdditionalTransform(affineTransform); + } + }, + + _getNode : function() + { + return this._clippingNode; + } +}); \ No newline at end of file diff --git a/external/gaf/Library/GAFMaskProto.js b/external/gaf/Library/GAFMaskProto.js new file mode 100644 index 0000000000..6074fd1279 --- /dev/null +++ b/external/gaf/Library/GAFMaskProto.js @@ -0,0 +1,16 @@ + +gaf._MaskProto = function(asset, mask, idRef) +{ + this.getIdRef = function(){return idRef}; + this.getMaskNodeProto = function() {return mask}; + + /* + * Will construct GAFMask + */ + this._gafConstruct = function() + { + var ret = new gaf.Mask(this); + ret._init(); + return ret; + }; +}; diff --git a/external/gaf/Library/GAFObject.js b/external/gaf/Library/GAFObject.js new file mode 100644 index 0000000000..7d5375abe5 --- /dev/null +++ b/external/gaf/Library/GAFObject.js @@ -0,0 +1,426 @@ +var gaf = gaf || {}; + +gaf._stateHasCtx = function(state) +{ + // Check for tint color offset + if( state.hasColorTransform && + (state.colorTransform.offset.r > 0 || + state.colorTransform.offset.g > 0 || + state.colorTransform.offset.b > 0 || + state.colorTransform.offset.a > 0) + ) + { + return true; + } + + // Check for color transform filter + if(state.hasEffect) + { + for(var i = 0, total = state.effect.length; i < total; ++i) + { + if(state.effect[i].type === gaf.EFFECT_COLOR_MATRIX) + return true; + } + } + return false; +}; + +gaf.Object = cc.Node.extend +({ + _asset : null, + _className : "GAFObject", + _id : gaf.IDNONE, + _gafproto : null, + _parentTimeLine : null, + _lastVisibleInFrame : 0, + _filterStack : null, + _cascadeColorMult : null, + _cascadeColorOffset : null, + _needsCtx : false, + _usedAtlasScale: 1, + + // Public methods + ctor: function(scale) + { + if(arguments.length == 1) + { + this._usedAtlasScale = scale; + } + this._super(); + this._cascadeColorMult = cc.color(255, 255, 255, 255); + this._cascadeColorOffset = cc.color(0, 0, 0, 0); + this._filterStack = []; + }, + + /** + * @method setAnimationStartedNextLoopDelegate + * @param {function(Object)} delegate + */ + setAnimationStartedNextLoopDelegate : function (delegate) {}, + + /** + * @method setAnimationFinishedPlayDelegate + * @param {function(Object)} delegate + */ + setAnimationFinishedPlayDelegate : function (delegate) {}, + + /** + * @method setLooped + * @param {bool} looped + */ + setLooped : function (looped) {}, + + /** + * @method getBoundingBoxForCurrentFrame + * @return {cc.Rect} + */ + getBoundingBoxForCurrentFrame : function () {return null;}, + + /** + * @method setFps + * @param {uint} fps + */ + setFps : function (fps) {}, + + /** + * @method getObjectByName + * @param {String} name - name of the object to find + * @return {gaf.Object} + */ + getObjectByName : function (name) {return null;}, + + /** + * @method clearSequence + */ + clearSequence : function () {}, + + /** + * @method getIsAnimationRunning + * @return {bool} + */ + getIsAnimationRunning : function () {return false;}, + + /** + * @method getSequences + * @return [string] - list of sequences if has any + */ + getSequences : function(){return [];}, + + + /** + * @method gotoAndStop + * @param {uint|String} value - label ot frame number + * @return {bool} + */ + gotoAndStop : function (value) {}, + + /** + * @method getStartFrame + * @param {String} frameLabel + * @return {uint} + */ + getStartFrame : function (frameLabel) {return gaf.IDNONE;}, + + /** + * @method setFramePlayedDelegate + * @param {function(Object, frame)} delegate + */ + setFramePlayedDelegate : function (delegate) {}, + + /** + * @method getCurrentFrameIndex + * @return {uint} + */ + getCurrentFrameIndex : function () { + return gaf.IDNONE; + }, + + /** + * @method getTotalFrameCount + * @return {uint} + */ + getTotalFrameCount : function () {return 0;}, + + /** + * @method start + */ + start : function () {}, + + /** + * @method stop + */ + stop : function () {}, + + /** + * @method isVisibleInCurrentFrame + * @return {bool} + */ + isVisibleInCurrentFrame : function () + { + /*if (this._parentTimeLine && + ((this._parentTimeLine.getCurrentFrameIndex() + 1) != this._lastVisibleInFrame)) + { + return false; + } + else + { + return true; + }*/ + return !(this._parentTimeLine && ((this._parentTimeLine.getCurrentFrameIndex() + 1) != this._lastVisibleInFrame)); + }, + + /** + * @method isDone + * @return {bool} + */ + isDone : function () {return true;}, + + /** + * @method playSequence + * @param {String} name - name of the sequence to play + * @param {bool} looped - play looped + * @param {bool} resume - whether to resume animation if stopped. True by default + * @return {bool} + */ + playSequence : function (name, looped, resume) {return false;}, + + /** + * @method isReversed + * @return {bool} + */ + isReversed : function () {return false;}, + + /** + * @method setSequenceDelegate + * @param {function(Object, sequenceName)} delegate + */ + setSequenceDelegate : function (delegate) {}, + + /** + * @method setFrame + * @param {uint} index + * @return {bool} + */ + setFrame : function (index) {return false;}, + + /** + * @method setControlDelegate + * @param {function} func + */ + setControlDelegate : function (func) {}, + + /** + * @method getEndFrame + * @param {String} frameLabel + * @return {uint} + */ + getEndFrame : function (frameLabel) {return gaf.IDNONE;}, + + /** + * @method pauseAnimation + */ + pauseAnimation : function () {}, + + /** + * @method gotoAndPlay + * @param {uint|String} value - label ot frame number + * @return {bool} + */ + gotoAndPlay : function (value) {}, + + /** + * @method isLooped + * @return {bool} + */ + isLooped : function () {return false;}, + + /** + * @method resumeAnimation + */ + resumeAnimation : function () {}, + + /** + * @method setReversed + * @param {bool} reversed + */ + setReversed : function (reversed) {}, + + /** + * @method hasSequences + * @return {bool} + */ + hasSequences : function () {return false;}, + + /** + * @method getFps + * @return {uint} + */ + getFps : function () {return 60;}, + + /** + * @method setLocator + * @param {bool} locator + * Locator object will not draw itself, but its children will be drawn + */ + setLocator : function (locator){}, + + setExternalTransform : function(affineTransform) + { + if(!cc.affineTransformEqualToTransform(this._additionalTransform, affineTransform)) + { + this.setAdditionalTransform(affineTransform); + } + }, + + getExternalTransform : function() + { + return this._additionalTransform; + }, + + setAnimationRunning: function () {}, + + //////////////// + // Private + //////////////// + _enableTick: function(val){}, + + _resetState : function() + {}, + + _updateVisibility : function(state, parent) + { + var alphaOffset = state.hasColorTransform ? state.colorTransform.offset.a : 0; + this.setOpacity(state.alpha + alphaOffset); + //return this.isVisible(); + }, + + // @Override + isVisible : function() + { + return this.getOpacity() > 0; + }, + + // @Override + visit: function(parentCmd) + { + if(this.isVisibleInCurrentFrame()) + { + this._super(parentCmd); + } + }, + + _getFilters : function(){return null}, + + _processAnimation : function(){}, + + + _applyState : function(state, parent) + { + this._applyStateSuper(state, parent); + }, + + _applyStateSuper : function(state, parent) + { + this._needsCtx = parent._needsCtx; + this._filterStack.length = 0; // clear + this._parentTimeLine = parent; // only gaf time line can call applyState. Assign it as parent + if(this._usedAtlasScale != 1) + { + var newMat = cc.clone(state.matrix); + newMat.tx *= this._usedAtlasScale; + newMat.ty *= this._usedAtlasScale; + this.setExternalTransform(newMat); // apply transformations of the state + } + else + { + this.setExternalTransform(state.matrix); // apply transformations of the state + } + // Cascade filters + // TODO: apply more than one filter + if (state.hasEffect) { + this._filterStack = this._filterStack.concat(state.effect); + this._needsCtx = true; + } + if (parent._filterStack && parent._filterStack.length > 0) { + this._filterStack = this._filterStack.concat(parent._filterStack); + } + + if(this._filterStack.length > 0 && this._filterStack[0].type === gaf.EFFECT_COLOR_MATRIX) + { + this._needsCtx = true; + } + + // Cascade color transformations + + // If state has a tint, then we should process it + if (state.hasColorTransform) + { + this._cascadeColorMult.r = state.colorTransform.mult.r * parent._cascadeColorMult.r / 255; + this._cascadeColorMult.g = state.colorTransform.mult.g * parent._cascadeColorMult.g / 255; + this._cascadeColorMult.b = state.colorTransform.mult.b * parent._cascadeColorMult.b / 255; + this._cascadeColorMult.a = state.colorTransform.mult.a * parent._cascadeColorMult.a / 255; + + this._cascadeColorOffset.r = state.colorTransform.offset.r + parent._cascadeColorOffset.r; + this._cascadeColorOffset.g = state.colorTransform.offset.g + parent._cascadeColorOffset.g; + this._cascadeColorOffset.b = state.colorTransform.offset.b + parent._cascadeColorOffset.b; + this._cascadeColorOffset.a = state.colorTransform.offset.a + parent._cascadeColorOffset.a; + } + else + { + this._cascadeColorMult.r = parent._cascadeColorMult.r; + this._cascadeColorMult.g = parent._cascadeColorMult.g; + this._cascadeColorMult.b = parent._cascadeColorMult.b; + this._cascadeColorMult.a = state.alpha * (parent._cascadeColorMult.a / 255); + + this._cascadeColorOffset.r = parent._cascadeColorOffset.r; + this._cascadeColorOffset.g = parent._cascadeColorOffset.g; + this._cascadeColorOffset.b = parent._cascadeColorOffset.b; + this._cascadeColorOffset.a = parent._cascadeColorOffset.a; + } + + if (this._cascadeColorOffset.r > 0 || + this._cascadeColorOffset.g > 0 || + this._cascadeColorOffset.b > 0 || + this._cascadeColorOffset.a > 0) + { + this._needsCtx = true; + } + }, + + _initRendererCmd: function() + { + this._renderCmd = cc.renderer.getRenderCmd(this); + this._renderCmd._visit = this._renderCmd.visit; + var self = this; + this._renderCmd.visit = function(parentCmd) { + if(self.isVisibleInCurrentFrame()){ + this._visit(parentCmd); + } + } + }, + + _getNode : function() + { + return this; + }, + + setAnchorPoint : function(point, y) + { + if (y === undefined) + { + this._super(point.x, point.y - 1); + } + else + { + this._super(point, y - 1); + } + } + +}); + +gaf.Object._createNullObject = function() +{ + var ret = new gaf.Object(); + ret.isVisible = function(){return true}; + return ret; +}; diff --git a/external/gaf/Library/GAFShaderManager.js b/external/gaf/Library/GAFShaderManager.js new file mode 100644 index 0000000000..fd72f79825 --- /dev/null +++ b/external/gaf/Library/GAFShaderManager.js @@ -0,0 +1,63 @@ + +gaf._glShaderInit = function() { + gaf._Uniforms = { + ColorTransformMult: -1, + ColorTransformOffset: -1, + ColorMatrixBody: -1, + ColorMatrixAppendix: -1, + BlurTexelOffset: -1, + GlowTexelOffset: -1, + GlowColor: -1 + }; + + gaf._shaderCreate = function (fs, vs) { + var program = new cc.GLProgram(); + var result = program.initWithVertexShaderByteArray(vs, fs); + cc.assert(result, "Shader init error"); + program.addAttribute(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION); + program.addAttribute(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR); + program.addAttribute(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_TEX_COORDS); + result = program.link(); + cc.assert(result, "Shader linking error"); + program.updateUniforms(); + return program; + }; + + gaf._shaderCreateAlpha = function () { + var program = gaf._shaderCreate(gaf.SHADER_COLOR_MATRIX_FRAG, cc.SHADER_POSITION_TEXTURE_COLOR_VERT); + gaf._Uniforms.ColorTransformMult = program.getUniformLocationForName(gaf.UNIFORM_ALPHA_TINT_MULT); + gaf._Uniforms.ColorTransformOffset = program.getUniformLocationForName(gaf.UNIFORM_ALPHA_TINT_OFFSET); + gaf._Uniforms.ColorMatrixBody = program.getUniformLocationForName(gaf.UNIFORM_ALPHA_COLOR_MATRIX_BODY); + gaf._Uniforms.ColorMatrixAppendix = program.getUniformLocationForName(gaf.UNIFORM_ALPHA_COLOR_MATRIX_APPENDIX); + return program; + }; + + gaf._shaderCreateBlur = function () { + var program = gaf._shaderCreate(gaf.SHADER_GAUSSIAN_BLUR_FRAG, cc.SHADER_POSITION_TEXTURE_COLOR_VERT); + gaf._Uniforms.BlurTexelOffset = program._glContext.getUniformLocation(program._programObj, gaf.UNIFORM_BLUR_TEXEL_OFFSET); + + return program; + }; + + gaf._shaderCreateGlow = function () { + var program = gaf._shaderCreate(gaf.SHADER_GLOW_FRAG, cc.SHADER_POSITION_TEXTURE_COLOR_VERT); + gaf._Uniforms.GlowTexelOffset = program._glContext.getUniformLocation(program._programObj, gaf.UNIFORM_GLOW_TEXEL_OFFSET); + gaf._Uniforms.GlowColor = program._glContext.getUniformLocation(program._programObj, gaf.UNIFORM_GLOW_COLOR); + return program; + }; + + gaf._Shaders = { + Alpha: gaf._shaderCreateAlpha(), + Blur: gaf._shaderCreateBlur(), + Glow: gaf._shaderCreateGlow() + }; +}; + +gaf._setupShaders = function() { + if (cc._renderType === cc._RENDER_TYPE_WEBGL) { + gaf._glShaderInit(); + } + else { + delete gaf._glShaderInit; + } +}; diff --git a/external/gaf/Library/GAFShaders.js b/external/gaf/Library/GAFShaders.js new file mode 100644 index 0000000000..7d91537285 --- /dev/null +++ b/external/gaf/Library/GAFShaders.js @@ -0,0 +1,58 @@ +gaf.SHADER_GAUSSIAN_BLUR_FRAG = + "varying mediump vec2 v_texCoord;\n" + + "uniform mediump vec2 u_step;\n" + + "void main()\n" + + "{ \n" + + " mediump vec4 sum = vec4(0.0); \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 4.0) * 0.05; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 3.0) * 0.09; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 2.0) * 0.12; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 1.0) * 0.15; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 0.0) * 0.18; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 1.0) * 0.15; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 2.0) * 0.12; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 3.0) * 0.09; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 4.0) * 0.05; \n" + + " gl_FragColor = sum; \n" + + "} \n"; + +gaf.SHADER_GLOW_FRAG = + "varying mediump vec2 v_texCoord;\n" + + "uniform mediump vec2 u_step;\n" + + "uniform mediump vec4 u_glowColor;\n" + + "void main()\n" + + "{ \n" + + " mediump vec4 sum = vec4(0.0); \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 4.0) * 0.05; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 3.0) * 0.09; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 2.0) * 0.12; \n" + + " sum += texture2D(CC_Texture0, v_texCoord - u_step * 1.0) * 0.15; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 0.0) * 0.18; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 1.0) * 0.15; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 2.0) * 0.12; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 3.0) * 0.09; \n" + + " sum += texture2D(CC_Texture0, v_texCoord + u_step * 4.0) * 0.05; \n" + + " gl_FragColor = sum * u_glowColor; \n" + + "} \n"; + +gaf.SHADER_COLOR_MATRIX_FRAG = + "varying mediump vec2 v_texCoord;\n" + + "varying mediump vec4 v_fragmentColor;\n" + + "uniform mediump vec4 colorTransformMult;\n" + + "uniform mediump vec4 colorTransformOffsets;\n" + + "uniform mediump mat4 colorMatrix;\n" + + "uniform mediump vec4 colorMatrix2;\n" + + "void main()\n" + + "{ \n" + + " vec4 texColor = texture2D(CC_Texture0, v_texCoord); \n" + + " const float kMinimalAlphaAllowed = 1.0e-8; \n" + + " if (texColor.a > kMinimalAlphaAllowed) \n" + + " { \n" + + " texColor = vec4(texColor.rgb / texColor.a, texColor.a); \n" + + " vec4 ctxColor = texColor * colorTransformMult + colorTransformOffsets; \n" + + " vec4 adjustColor = colorMatrix * ctxColor + colorMatrix2; \n" + + " adjustColor *= v_fragmentColor; \n" + + " texColor = vec4(adjustColor.rgb * adjustColor.a, adjustColor.a); \n" + + " } \n" + + " gl_FragColor = texColor; \n" + + "}\n"; diff --git a/external/gaf/Library/GAFSprite.js b/external/gaf/Library/GAFSprite.js new file mode 100644 index 0000000000..07ea732f44 --- /dev/null +++ b/external/gaf/Library/GAFSprite.js @@ -0,0 +1,100 @@ + +gaf.Sprite = gaf.Object.extend +({ + _className: "GAFSprite", + + _hasCtx: false, + _hasFilter: false, + + ctor : function(gafSpriteProto, usedScale) + { + this._super(usedScale); + cc.assert(gafSpriteProto, "Error! Missing mandatory parameter."); + this._gafproto = gafSpriteProto; + }, + + // Private + + _init : function() + { + var frame = this._gafproto.getFrame(); + cc.assert(frame instanceof cc.SpriteFrame, "Error. Wrong object type."); + + // Create sprite with custom render command from frame + this._sprite = new cc.Sprite(); + this._sprite._renderCmd = this._gafCreateRenderCmd(this._sprite); + this._sprite.initWithSpriteFrame(frame); + + this._sprite.setAnchorPoint(this._gafproto.getAnchor()); + this.addChild(this._sprite); + //this._sprite.setCascadeColorEnabled(true); + //this._sprite.setCascadeOpacityEnabled(true); + this._sprite.setOpacityModifyRGB(true); + + if(cc._renderType === cc._RENDER_TYPE_WEBGL) + this._sprite.setBlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + }, + + _applyState : function(state, parent) + { + this._applyStateSuper(state, parent); + if(this._needsCtx) + { + // Enable ctx state if wasn't enabled + if(!this._hasCtx) + { + this._enableCtx(); + this._hasCtx = true; + } + // Set ctx shader + this._applyCtxState(state); + } + else + { + // Disable ctx state if was enabled + if(this._hasCtx) + { + this._disableCtx(); + this._hasCtx = false; + } + // Apply color + if(!cc.colorEqual(this._sprite._realColor, this._cascadeColorMult)) + { + this._sprite.setColor(this._cascadeColorMult); + } + // Apply opacity + if(this._sprite.getOpacity() != this._cascadeColorMult.a) + { + this._sprite.setOpacity(this._cascadeColorMult.a); + } + + } + }, + + _enableCtx: function() + { + this._sprite._renderCmd._enableCtx(); + }, + + _disableCtx: function() + { + this._sprite._renderCmd._disableCtx(); + }, + + _applyCtxState: function(state){ + this._sprite._renderCmd._applyCtxState(this); + }, + + getBoundingBoxForCurrentFrame: function () + { + var result = this._sprite.getBoundingBox(); + return cc._rectApplyAffineTransformIn(result, this.getNodeToParentTransform()); + }, + + _gafCreateRenderCmd: function(item){ + if(cc._renderType === cc._RENDER_TYPE_CANVAS) + return new gaf.Sprite.CanvasRenderCmd(item); + else + return new gaf.Sprite.WebGLRenderCmd(item); + } +}); diff --git a/external/gaf/Library/GAFSpriteCanvasRenderCmd.js b/external/gaf/Library/GAFSpriteCanvasRenderCmd.js new file mode 100644 index 0000000000..26f7b0ed18 --- /dev/null +++ b/external/gaf/Library/GAFSpriteCanvasRenderCmd.js @@ -0,0 +1,233 @@ + +(function() { + gaf.Sprite.CanvasRenderCmd = function (renderable) { + cc.Sprite.CanvasRenderCmd.call(this, renderable); + this._hasTintMult = false; + this._hasTintOffset = false; + this._hasCtx = false; + this._tintMult = cc.color(255,255,255,255); + this._tintOffset = cc.color(0,0,0,0); + this._textureDirty = false; + }; + var proto = gaf.Sprite.CanvasRenderCmd.prototype = Object.create(cc.Sprite.CanvasRenderCmd.prototype); + proto.constructor = gaf.Sprite.CanvasRenderCmd; + + proto._disableCtx = function(){ + this._hasTintOffset = false; + this._hasCtx = false; + this._textureDirty = true; + this.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); + this._tintMult = cc.color(255,255,255,255); + this._tintOffset = cc.color(0,0,0,0); + }; + + proto._enableCtx = function(){ + + }; + + proto._applyCtxState = function(gafObject){ + + var tintMult = gafObject._cascadeColorMult; + var tintOffset = gafObject._cascadeColorOffset; + var opacity = tintMult.a; + + // Apply opacity + if(this._node.getOpacity() != opacity) + { + this._node.setOpacity(opacity); + } + + // Check Tint multiplicator + var multDirty = !cc.colorEqual(this._tintMult, tintMult); + if(multDirty) + { + this._node.setColor(tintMult); + this._tintMult = tintMult; + this._hasTintMult = + (tintMult.r !== 255 || + tintMult.g !== 255 || + tintMult.b !== 255 ); + } + + // Check Tint offset + var offfsetDirty = + (this._tintOffset.r != tintOffset.r) || + (this._tintOffset.g != tintOffset.g) || + (this._tintOffset.b != tintOffset.b) || + (this._tintOffset.a != tintOffset.a); + + if(offfsetDirty) + { + this._tintOffset = tintOffset; + this._hasTintOffset = + (tintOffset.r !== 0 || + tintOffset.g !== 0 || + tintOffset.b !== 0 || + tintOffset.a !== 0 ); + } + + // Update dirty flag + this._textureDirty = multDirty || offfsetDirty; + if(this._textureDirty) + { + this.setDirtyFlag(cc.Node._dirtyFlags.colorDirty); + } + + + this._hasCtx = gafObject._filterStack.length > 0 && gafObject._filterStack[0].type === gaf.EFFECT_COLOR_MATRIX; + + }; + + proto.rendering = function(ctx, scaleX, scaleY) + { + var node = this._node; + var locTextureCoord = this._textureCoord, + alpha = (this._displayedOpacity / 255); + + if ((node._texture && ((locTextureCoord.width === 0 || locTextureCoord.height === 0) //set texture but the texture isn't loaded. + || !node._texture._textureLoaded)) || alpha === 0) + return; + + var wrapper = ctx || cc._renderContext, + context = wrapper.getContext(); + var locX = node._offsetPosition.x, + locHeight = node._rect.height, + locWidth = node._rect.width, + locY = -node._offsetPosition.y - locHeight, + image; + + wrapper.setTransform(this._worldTransform, scaleX, scaleY); + wrapper.setCompositeOperation(this._blendFuncStr); + wrapper.setGlobalAlpha(alpha); + + if(node._flippedX || node._flippedY) + wrapper.save(); + if (node._flippedX) { + locX = -locX - locWidth; + context.scale(-1, 1); + } + if (node._flippedY) { + locY = node._offsetPosition.y; + context.scale(1, -1); + } + + image = node._texture._htmlElementObj; + + if (this._colorized) { + context.drawImage(image, + 0, 0, locTextureCoord.width,locTextureCoord.height, + locX * scaleX,locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } else { + context.drawImage(image, + locTextureCoord.renderX, locTextureCoord.renderY, locTextureCoord.width, locTextureCoord.height, + locX * scaleX, locY * scaleY, locWidth * scaleX, locHeight * scaleY); + } + + if(node._flippedX || node._flippedY) + wrapper.restore(); + cc.g_NumberOfDraws++; + }; + + if(cc.sys._supportCanvasNewBlendModes){ + proto._updateColor = function () { + var displayedColor = this._displayedColor, node = this._node; + this._hasTintMult |= (displayedColor.r !== 255 || displayedColor.g !== 255 || displayedColor.b !== 255); + + // If no color changes + if(this._textureDirty) + { + this._textureDirty = false; + if (this._colorized) { + this._colorized = false; + node.texture = this._originalTexture; + } + } + else + { + return; + } + + var locElement, locTexture = node._texture, locRect = this._textureCoord; + if(this._hasTintMult) + { + if (locTexture && locRect.validRect && this._originalTexture) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + + this._colorized = true; + if (this._hasTintOffset || this._hasCtx) displayedColor = this._tintMult; + + locElement = cc.Sprite.CanvasRenderCmd._generateTintImageWithMultiply(this._originalTexture._htmlElementObj, displayedColor, locRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.texture = locTexture; + } + } + + locTexture = node._texture; + if(this._hasTintOffset) + { + var cacheTextureForColor = cc.textureCache.getTextureColors(this._originalTexture.getHtmlElementObj()); + if (locTexture && locRect.validRect && this._originalTexture) { + locElement = locTexture.getHtmlElementObj(); + if (!locElement) + return; + if(this._colorized) + var texRect = cc.rect(0,0,locRect.width, locRect.height); + else + texRect = locRect; + locElement = this._gafGenerateTintImage(node.texture._htmlElementObj, texRect, cacheTextureForColor, this._tintOffset, locRect); + locTexture = new cc.Texture2D(); + locTexture.initWithElement(locElement); + locTexture.handleLoadedTexture(); + node.texture = locTexture; + this._colorized = true; + } + } + + + }; + + proto._gafGenerateTintImage = function(texture, texRect, tintedImgCache, color, rect, renderCanvas){ + if (!rect) + rect = cc.rect(0, 0, texture.width, texture.height); + + // Create a new buffer if required + var w = Math.min(rect.width, tintedImgCache[0].width); + var h = Math.min(rect.height, tintedImgCache[0].height); + var buff = renderCanvas, ctx; + if (!buff) { + buff = cc.newElement("canvas"); + buff.width = w; + buff.height = h; + ctx = buff.getContext("2d"); + } else { + ctx = buff.getContext("2d"); + ctx.clearRect(0, 0, w, h); + } + ctx.save(); + + // draw a channel with alpha of the original image + ctx.globalCompositeOperation = 'source-over'; + //ctx.globalAlpha = 1; + ctx.drawImage(tintedImgCache[2], rect.x, rect.y, w, h, 0, 0, w, h); + + // draw a rect of specified color + ctx.globalCompositeOperation = 'source-in'; + ctx.fillStyle = 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',1)'; + ctx.fillRect(0, 0, w, h); + + // add the desired image to the drawn + ctx.globalCompositeOperation = 'lighter'; + ctx.drawImage(texture, texRect.x, texRect.y, w, h, 0, 0, w, h); + + + ctx.restore(); + return buff; + + }; + } + +})(); diff --git a/external/gaf/Library/GAFSpriteProto.js b/external/gaf/Library/GAFSpriteProto.js new file mode 100644 index 0000000000..6e33fa7d5f --- /dev/null +++ b/external/gaf/Library/GAFSpriteProto.js @@ -0,0 +1,36 @@ + +gaf._SpriteProto = function(asset, atlasFrames, elementAtlasIdRef) +{ + //this._anchor = atlasFrame._gafAnchor; + //delete atlasFrame._gafAnchor; + + this.getFrames = function(){return atlasFrames}; + this.getIdRef = function(){return elementAtlasIdRef}; + //this.getAnchor = function() {return this._anchor}; + this.getAsset = function() {return asset}; + + /* + * Will construct GAFSprite + */ + this._gafConstruct = function() + { + var usedScale = this.getAsset()._usedAtlasScale; + var ret = new gaf.Sprite(this, usedScale); + ret._init(); + return ret; + }; +}; + +gaf._SpriteProto.prototype.getFrame = function() +{ + var usedScale = this.getAsset()._usedAtlasScale; + cc.assert(usedScale, "Error. Atlas scale zero."); + var frames = this.getFrames()[usedScale]; + cc.assert(frames, "Error. No frames found for used scale `"+usedScale+"`"); + return frames[this.getIdRef()]; +}; + +gaf._SpriteProto.prototype.getAnchor = function() +{ + return this.getFrame()._gafAnchor; +}; diff --git a/external/gaf/Library/GAFSpriteWebGLRenderCmd.js b/external/gaf/Library/GAFSpriteWebGLRenderCmd.js new file mode 100644 index 0000000000..eabe25b0c9 --- /dev/null +++ b/external/gaf/Library/GAFSpriteWebGLRenderCmd.js @@ -0,0 +1,132 @@ + +(function(){ + gaf.Sprite.WebGLRenderCmd = function (renderable) { + cc.Sprite.WebGLRenderCmd.call(this, renderable); + this._defualtShader = cc.shaderCache.programForKey(cc.SHADER_POSITION_TEXTURECOLOR); + this._customShader = gaf._Shaders.Alpha; + + //this._shaderProgram = this._defualtShader; + + this._tintMult = null; + this._tintOffset = null; + this._ctxMatrixBody = null; + this._ctxMatrixAppendix = null; + }; + + var proto = gaf.Sprite.WebGLRenderCmd.prototype = Object.create(cc.Sprite.WebGLRenderCmd.prototype); + proto.constructor = gaf.Sprite.WebGLRenderCmd; + + proto._identityVec = [1.0, 1.0, 1.0, 1.0]; + proto._zeroVec = [0.0, 0.0, 0.0, 0.0]; + proto._identityMat = [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ]; + + proto._disableCtx = function(){ + this.setShaderProgram(this._defualtShader); + }; + + proto._enableCtx = function(){ + this.setShaderProgram(this._customShader); + }; + + proto._applyCtxState = function(gafObject){ + var tintMult = gafObject._cascadeColorMult; + this._tintMult = [ + tintMult.r / 255, + tintMult.g / 255, + tintMult.b / 255, + tintMult.a / 255 + ]; + + var tintOffset = gafObject._cascadeColorOffset; + this._tintOffset = [ + tintOffset.r / 255, + tintOffset.g / 255, + tintOffset.b / 255, + tintOffset.a / 255 + ]; + + var filterStack = gafObject._filterStack; + if(filterStack && filterStack.length > 0 && filterStack[0].type === gaf.EFFECT_COLOR_MATRIX) + { + var m = filterStack[0].colorMatrix; + this._ctxMatrixBody = [ + m.rr, m.rg, m.rb, m.ra, + m.gr, m.gg, m.gb, m.ga, + m.br, m.bg, m.bb, m.ba, + m.ar, m.ag, m.ab, m.aa + ]; + this._ctxMatrixAppendix = [ + m.r / 255, + m.g / 255, + m.b / 255, + m.a / 255 + ]; + } + else + { + this._ctxMatrixBody = null; + this._ctxMatrixAppendix = null; + } + }; + + proto._setUniforms = function() + { + if(this._shaderProgram === this._customShader) + { + this._shaderProgram.use(); + { + this._shaderProgram.setUniformLocationWith4fv( + gaf._Uniforms.ColorTransformMult, + this._tintMult, + 1 + ); + this._shaderProgram.setUniformLocationWith4fv( + gaf._Uniforms.ColorTransformOffset, + this._tintOffset, + 1 + ); + } + + if(this._ctxMatrixBody && this._ctxMatrixAppendix) + { + this._shaderProgram.setUniformLocationWithMatrix4fv( + gaf._Uniforms.ColorMatrixBody, + this._ctxMatrixBody, + 1 + ); + this._shaderProgram.setUniformLocationWith4fv( + gaf._Uniforms.ColorMatrixAppendix, + this._ctxMatrixAppendix, + 1 + ); + } + else + { + this._shaderProgram.setUniformLocationWithMatrix4fv( + gaf._Uniforms.ColorMatrixBody, + this._identityMat, + 1 + ); + this._shaderProgram.setUniformLocationWith4fv( + gaf._Uniforms.ColorMatrixAppendix, + this._zeroVec, + 1 + ); + } + } + }; + + proto.rendering = function(ctx) + { + this._setUniforms(); + + // Super call + cc.Sprite.WebGLRenderCmd.prototype.rendering.call(this, ctx); + }; + +})(); diff --git a/external/gaf/Library/GAFTags.js b/external/gaf/Library/GAFTags.js new file mode 100644 index 0000000000..09f8186538 --- /dev/null +++ b/external/gaf/Library/GAFTags.js @@ -0,0 +1,378 @@ + +gaf.ReadSingleTag = function(stream){ + var tagId = stream.Ushort(); + var tag = gaf.Tags[tagId]; + var result = {}; + if(typeof tag === "undefined"){ + console.log("GAF. Non implemented tag detected."); + gaf.Tags.Default.parse(stream, tagId); + } + else{ + //console.log("tag " + tag.tagName); + result = tag.parse(stream, tagId); + } + return result; +}; + +gaf.ReadTags = function(stream){ + var tags = []; + try { + do { + var tag = gaf.ReadSingleTag(stream); + tags.push(tag); + } while (tag.tagId != 0); + } + catch (e){ + if (e instanceof Error && e.message == "GAF format error"){ + console.log("GAF format error:\n" + e.stack); + // Tag will be closed and parser will continue from where it should. + } + else{ + console.log(e.stack); + throw e; + } + } + return tags; +}; + + +gaf.Tag = function(){ + this.Default = Object.create(gaf.Tag.base); + this["0"] = Object.create(gaf.Tag.End); + this["1"] = Object.create(gaf.Tag.DefineAtlas); + this["2"] = Object.create(gaf.Tag.DefineAnimationMasks); + this["3"] = Object.create(gaf.Tag.DefineAnimationObjects); + this["4"] = Object.create(gaf.Tag.DefineAnimationFrames); + this["5"] = Object.create(gaf.Tag.DefineNamedParts); + this["6"] = Object.create(gaf.Tag.DefineSequences); + this["7"] = Object.create(gaf.Tag.DefineTextFields); + this["8"] = Object.create(gaf.Tag.DefineAtlas2); + this["9"] = Object.create(gaf.Tag.DefineStage); + this["10"] = Object.create(gaf.Tag.DefineAnimationObjects2); + this["11"] = Object.create(gaf.Tag.DefineAnimationMasks2); + this["12"] = Object.create(gaf.Tag.DefineAnimationFrames2); + this["13"] = Object.create(gaf.Tag.DefineTimeline); +}; + +gaf.Tag.base = function() {}; +gaf.Tag.base.parse = function(stream, tagId){ + var size = stream.Uint(); + + stream.startNestedBuffer(size); + var result = this.doParse(stream); + stream.endNestedBuffer(); + + result.tagName = this.tagName; + result.tagId = tagId; + return result; +}; +gaf.Tag.base.doParse = function(stream){ + return {}; + }; + +gaf.Tag.End = Object.create(gaf.Tag.base); +gaf.Tag.End.tagName = "TagEnd"; + +gaf.Tag.DefineAtlas = Object.create(gaf.Tag.base); +gaf.Tag.DefineAtlas.tagName = "TagDefineAtlas"; +gaf.Tag.DefineAtlas.doParse = function (s) { + var exec = s.fields( + 'scale', 'Float', + 'atlases', s.array('Ubyte', s.fields( + 'id', 'Uint', + 'sources', s.array('Ubyte', s.fields( + 'source', 'String', + 'csf', 'Float' + )) + )), + 'elements', s.array('Uint', s.fields( + 'pivot', 'Point', + 'origin', 'Point', + 'scale', 'Float', + 'size', 'Point', + 'atlasId', 'Uint', + 'elementAtlasId', 'Uint' + )) + ); + return {'content': exec()}; +}; + +gaf.Tag.DefineAnimationMasks = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationMasks.tagName = "TagDefineAnimationMasks"; +gaf.Tag.DefineAnimationMasks.doParse = function (s) { + var exec = s.array('Uint', s.fields( + 'objectId', 'Uint', + 'elementAtlasIdRef', 'Uint' + )); + var result = {'content': exec()}; + debugger; + return result; +}; + +gaf.Tag.DefineAnimationObjects = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationObjects.tagName = "TagDefineAnimationObjects"; +gaf.Tag.DefineAnimationObjects.doParse = function (s) { + var exec = s.array('Uint', s.fields( + 'objectId', 'Uint', + 'elementAtlasIdRef', 'Uint' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineAnimationFrames = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationFrames.tagName = "TagDefineAnimationFrames"; +gaf.Tag.DefineAnimationFrames.doParse = function(s){ + var exec = s.array('Uint', s.fields( + 'frame', 'Uint', + 'state', s.array('Uint', s.fields( + 'hasColorTransform', 'Ubyte', + 'hasMask', 'Ubyte', + 'hasEffect', 'Ubyte', + 'objectIdRef', 'Uint', + 'depth', 'Int', + 'alpha', 'Float', + 'matrix', 'Matrix', + 'colorTransform', s.condition('hasColorTransform', 1, s.fields( + 'alphaOffset', 'Float', + 'redMultiplier', 'Float', + 'redOffset', 'Float', + 'greenMultiplier', 'Float', + 'greenOffset', 'Float', + 'blueMultiplier', 'Float', + 'blueOffset', 'Float' + )), + 'effect', s.condition('hasEffect', 1, s.array('Ubyte', gaf.Tag._readFilter(s))), + 'maskObjectIdRef', s.condition('hasMask', 1, s.fields( + 'maskObjectIdRef', 'Uint' + )) + )) + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineNamedParts = Object.create(gaf.Tag.base); +gaf.Tag.DefineNamedParts.tagName = "TagDefineNamedParts"; +gaf.Tag.DefineNamedParts.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'objectId', 'Uint', + 'name', 'String' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineSequences = Object.create(gaf.Tag.base); +gaf.Tag.DefineSequences.tagName = "TagDefineSequences"; +gaf.Tag.DefineSequences.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'id', 'String', + 'start', 'Ushort', + 'end', 'Ushort' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineTextFields = Object.create(gaf.Tag.base); +gaf.Tag.DefineTextFields.tagName = "TagDefineTextFields"; +gaf.Tag.DefineTextFields.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'id', 'Uint', + 'pivot', 'Point', + 'end', 'Ushort', + 'width', 'Float', + 'height', 'Float', + 'text', 'String', + 'embedFonts', 'Boolean', + 'multiline', 'Boolean', + 'wordWrap', 'Boolean', + 'hasRestrict', 'Boolean', + 'restrict', s.condition('hasRestrict', 1, function (){return s['String'];}), + 'editable', 'Boolean', + 'selectable', 'Boolean', + 'displayAsPassword', 'Boolean', + 'maxChars', 'Uint', + 'align', 'Uint', + 'blockIndent', 'Uint', + 'bold', 'Boolean', + 'bullet', 'Boolean', + 'color', 'color', + 'font', 'String', + 'indent', 'Uint', + 'italic', 'Boolean', + 'kerning', 'Boolean', + 'leading', 'Uint', + 'leftMargin', 'Uint', + 'letterSpacing', 'Float', + 'rightMargin', 'Uint', + 'size', 'Uint', + 'tabStops', s.array('Uint', s.fields( + 'value', 'Uint' + )), + 'target', 'string', + 'underline', 'Boolean', + 'url', 'String' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineAtlas2 = Object.create(gaf.Tag.base); +gaf.Tag.DefineAtlas2.tagName = "TagDefineAtlas2"; +gaf.Tag.DefineAtlas2.doParse = function(s) { + var exec = s.fields( + 'scale', 'Float', + 'atlases', s.array('Ubyte', s.fields( + 'id', 'Uint', + 'sources', s.array('Ubyte', s.fields( + 'source', 'String', + 'csf', 'Float' + )) + )), + 'elements', s.array('Uint', s.fields( + 'pivot', 'Point', + 'origin', 'Point', + 'scale', 'Float', + 'size', 'Point', + 'atlasId', 'Uint', + 'elementAtlasId', 'Uint', + 'hasScale9Grid', 'Boolean', + 'scale9GridRect', s.condition('hasScale9Grid', 1, function(){return s.Rect();}) + )) + ); + return {'content': exec()}; +}; + +gaf.Tag.DefineStage = Object.create(gaf.Tag.base); +gaf.Tag.DefineStage.tagName = "TagDefineStage"; +gaf.Tag.DefineStage.doParse = function(s) { + var exec = s.fields( + 'fps', 'Ubyte', + 'color', 'color', + 'width', 'Ushort', + 'height', 'Ushort' + ); + return {'content': exec()}; +}; + +gaf.Tag.DefineAnimationObjects2 = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationObjects2.tagName = "TagDefineAnimationObjects2"; +gaf.Tag.DefineAnimationObjects2.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'objectId', 'Uint', + 'elementAtlasIdRef', 'Uint', + 'type', 'Ushort' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineAnimationMasks2 = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationMasks2.tagName = "TagDefineAnimationMasks2"; +gaf.Tag.DefineAnimationMasks2.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'objectId', 'Uint', + 'elementAtlasIdRef', 'Uint', + 'type', 'Ushort' + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineAnimationFrames2 = Object.create(gaf.Tag.base); +gaf.Tag.DefineAnimationFrames2.tagName = "TagDefineAnimationFrames2"; +gaf.Tag.DefineAnimationFrames2.doParse = function(s) { + var exec = s.array('Uint', s.fields( + 'frame', 'Uint', + 'hasChangesInDisplayList', 'Boolean', + 'hasActions', 'Boolean', + 'state', s.condition('hasChangesInDisplayList', 1, s.array('Uint', s.fields( + 'hasColorTransform', 'Boolean', + 'hasMask', 'Boolean', + 'hasEffect', 'Boolean', + 'objectIdRef', 'Uint', + 'depth', 'Int', + 'alpha', 'Float', + 'matrix', 'Matrix', + 'colorTransform', s.condition('hasColorTransform', 1, s.fields( + 'alphaOffset', 'Float', + 'redMultiplier', 'Float', + 'redOffset', 'Float', + 'greenMultiplier', 'Float', + 'greenOffset', 'Float', + 'blueMultiplier', 'Float', + 'blueOffset', 'Float' + )), + 'effect', s.condition('hasEffect', 1, s.array('Ubyte', gaf.Tag._readFilter(s))), + 'maskObjectIdRef', s.condition('hasMask', 1, function(){return s.Uint()}) + ))), + 'actions', s.condition('hasActions', 1, s.array('Uint', s.fields( + 'type', 'Uint', + 'scope', 'String', + 'params', gaf.Tag._readActionArguments(s) + ))) + )); + return {'content': exec()}; +}; + +gaf.Tag.DefineTimeline = Object.create(gaf.Tag.base); +gaf.Tag.DefineTimeline.tagName = "TagDefineTimeline"; +gaf.Tag.DefineTimeline.doParse = function(s) { + var exec = s.fields( + 'id', 'Uint', + 'animationFrameCount', 'Uint', + 'boundingBox', 'Rect', + 'pivotPoint', 'Point', + 'hasLinkage', 'Boolean', + 'linkageName', s.condition('hasLinkage', 1, function () { + return s.String(); + }) + ); + var result = {'content': exec()}; + result.content.tags = gaf.ReadTags(s); + return result; +}; + +gaf.Tag._readActionArguments = function(s){ + return function(){ + var size = s.Uint(); + var ret = []; + s.startNestedBuffer(size); + while(s.maxOffset() < s.tell()){ + ret.push(s.String()); + } + s.endNestedBuffer(); + return ret; + }; +}; + +gaf.Tag._readFilter = function(s){ + return s.fields( + 'type', 'Uint', + 'dropShadow', s.condition('type', gaf.EFFECT_DROP_SHADOW, s.fields( // DropShadow + 'color', 'color', + 'blurX', 'Float', + 'blurY', 'Float', + 'angle', 'Float', + 'distance', 'Float', + 'strength', 'Float', + 'inner', 'Boolean', + 'knockout', 'Boolean' + )), + 'blur', s.condition('type', gaf.EFFECT_BLUR, s.fields( // Blur + 'blurX', 'Float', + 'blurY', 'Float' + )), + 'glow', s.condition('type', gaf.EFFECT_GLOW, s.fields( // Glow + 'color', 'color', + 'blurX', 'Float', + 'blurY', 'Float', + 'strength', 'Float', + 'inner', 'Boolean', + 'knockout', 'Boolean' + )), + 'colorMatrix', s.condition('type', gaf.EFFECT_COLOR_MATRIX, s.fields( // ColorMatrix + 'rr', 'Float', 'gr', 'Float', 'br', 'Float', 'ar', 'Float', 'r', 'Float', + 'rg', 'Float', 'gg', 'Float', 'bg', 'Float', 'ag', 'Float', 'g', 'Float', + 'rb', 'Float', 'gb', 'Float', 'bb', 'Float', 'ab', 'Float', 'b', 'Float', + 'ra', 'Float', 'ga', 'Float', 'ba', 'Float', 'aa', 'Float', 'a', 'Float' + )) + ) +}; + +gaf.Tags = new gaf.Tag(); diff --git a/external/gaf/Library/GAFTextField.js b/external/gaf/Library/GAFTextField.js new file mode 100644 index 0000000000..04f9744920 --- /dev/null +++ b/external/gaf/Library/GAFTextField.js @@ -0,0 +1,6 @@ + +gaf.TextField = gaf.Object.extend +({ + _className: "GAFTextField" + +}); \ No newline at end of file diff --git a/external/gaf/Library/GAFTimeLine.js b/external/gaf/Library/GAFTimeLine.js new file mode 100644 index 0000000000..ef9387aa46 --- /dev/null +++ b/external/gaf/Library/GAFTimeLine.js @@ -0,0 +1,547 @@ + +gaf.TimeLine = gaf.Object.extend +({ + _className: "GAFTimeLine", + _objects: null, + _container: null, + _animationStartedNextLoopDelegate: null, + _animationFinishedPlayDelegate: null, + _framePlayedDelegate: null, + _sequenceDelegate: null, + _fps: 60, + _frameTime: 1/60, + _currentSequenceStart: gaf.FIRST_FRAME_INDEX, + _currentSequenceEnd: gaf.FIRST_FRAME_INDEX, + _totalFrameCount: 0, + _isRunning: false, + _isLooped: false, + _isReversed: false, + _timeDelta: 0, + _animationsSelectorScheduled: false, + _currentFrame: gaf.FIRST_FRAME_INDEX, + + + setAnimationStartedNextLoopDelegate: function (delegate) + { + this._animationStartedNextLoopDelegate = delegate; + }, + setAnimationFinishedPlayDelegate: function (delegate) + { + this._animationFinishedPlayDelegate = delegate; + }, + setLooped: function (looped, recursively) + { + this._isLooped = looped; + if (recursively) + { + this._objects.forEach(function (item) + { + item.setLooped(looped, recursively); + }); + } + }, + getBoundingBoxForCurrentFrame: function () + { + var result = null;//cc.rect(); + var isFirstObj = true; + this._objects.forEach(function (item) { + if(item.isVisibleInCurrentFrame() && item.isVisible()) + { + var bb = item.getBoundingBoxForCurrentFrame(); + if(!bb) + { + bb = item.getBoundingBox(); + } + if (isFirstObj) + { + isFirstObj = false; + result = bb; + } + else + { + result = cc.rectUnion(result, bb); + } + } + }); + return cc._rectApplyAffineTransformIn(result, this._container.getNodeToParentTransform()); + }, + setFps: function (fps) + { + cc.assert(fps !== 0, 'Error! Fps is set to zero.'); + this._fps = fps; + this._frameTime = 1/fps; + }, + getObjectByName: function (name) + { + var elements = name.split('.'); + var result = null; + var retId = -1; + var timeLine = this; + var BreakException = {}; + try + { + elements.forEach(function(element) + { + var parts = timeLine._gafproto.getNamedParts(); + if(parts.hasOwnProperty(element)) + { + retId = parts[element]; + } + else + { + // Sequence is incorrect + BreakException.lastElement = element; + throw BreakException; + } + result = timeLine._objects[retId]; + timeLine = result; + }); + } + catch (e) + { + if (e!==BreakException) + { + throw e; + } + cc.log("Sequence incorrect: `" + name + "` At: `" + BreakException.lastElement + "`"); + return null; + } + return result; + }, + clearSequence: function () + { + this._currentSequenceStart = gaf.FIRST_FRAME_INDEX; + this._currentSequenceEnd = this._gafproto.getTotalFrames(); + }, + getIsAnimationRunning: function () + { + return this._isRunning; + }, + gotoAndStop: function (value) + { + var frame = 0; + if (typeof value === 'string') + { + frame = this.getStartFrame(value); + } + else + { + frame = value; + } + if (this.setFrame(frame)) + { + this.setAnimationRunning(false, false); + return true; + } + return false; + }, + gotoAndPlay: function (value) + { + var frame = 0; + if (typeof value === 'string') + { + frame = this.getStartFrame(value); + } + else + { + frame = value; + } + if (this.setFrame(frame)) + { + this.setAnimationRunning(true, false); + return true; + } + return false; + }, + getStartFrame: function (frameLabel) + { + var seq = this._gafproto.getSequences()[frameLabel]; + if (seq) + { + return seq.start; + } + return gaf.IDNONE; + }, + getEndFrame: function (frameLabel) + { + var seq = this._gafproto.getSequences()[frameLabel]; + if (seq) + { + return seq.end; + } + return gaf.IDNONE; + }, + setFramePlayedDelegate: function (delegate) + { + this._framePlayedDelegate = delegate; + }, + getCurrentFrameIndex: function () + { + return this._showingFrame; + }, + getTotalFrameCount: function () + { + return this._gafproto.getTotalFrames(); + }, + start: function () + { + this._enableTick(true); + if (!this._isRunning) + { + this._currentFrame = gaf.FIRST_FRAME_INDEX; + this.setAnimationRunning(true, true); + } + }, + stop: function () + { + this._enableTick(false); + if (this._isRunning) + { + this._currentFrame = gaf.FIRST_FRAME_INDEX; + this.setAnimationRunning(false, true); + } + }, + isDone: function () + { + if (this._isLooped) + { + return false; + } + else + { + if (!this._isReversed) + { + return this._currentFrame > this._totalFrameCount; + } + else + { + return this._currentFrame < gaf.FIRST_FRAME_INDEX - 1; + } + } + }, + getSequences: function() + { + return this._gafproto.getSequences(); + }, + playSequence: function (name, looped) + { + var s = this.getStartFrame(name); + var e = this.getEndFrame(name); + if (gaf.IDNONE === s || gaf.IDNONE === e) + { + return false; + } + this._currentSequenceStart = s; + this._currentSequenceEnd = e; + if (this._currentFrame < this._currentSequenceStart || this._currentFrame > this._currentSequenceEnd) + { + this._currentFrame = this._currentSequenceStart; + } + else + { + this._currentFrame = this._currentSequenceStart; + } + this.setLooped(looped, false); + this.resumeAnimation(); + return true; + }, + isReversed: function () + { + return this._isReversed; + }, + setSequenceDelegate: function (delegate) + { + this._sequenceDelegate = delegate; + }, + setFrame: function (index) + { + if (index >= gaf.FIRST_FRAME_INDEX && index < this._totalFrameCount) + { + this._showingFrame = index; + this._currentFrame = index; + this._processAnimation(); + return true; + } + return false; + }, + + pauseAnimation: function () + { + if (this._isRunning) + { + this.setAnimationRunning(false, false); + } + }, + isLooped: function () + { + return this._isLooped; + }, + resumeAnimation: function () + { + if (!this._isRunning) + { + this.setAnimationRunning(true, false); + } + }, + setReversed: function (reversed) + { + this._isReversed = reversed; + }, + hasSequences: function () + { + return this._gafproto.getSequences().length > 0; + }, + getFps: function () + { + return this._fps; + }, + + + // Private + + ctor: function(gafTimeLineProto, scale) + { + this._super(scale); + this._objects = []; + cc.assert(gafTimeLineProto, "Error! Missing mandatory parameter."); + this._gafproto = gafTimeLineProto; + }, + + setExternalTransform: function(affineTransform) + { + if(!cc.affineTransformEqualToTransform(this._container._additionalTransform, affineTransform)) + { + this._container.setAdditionalTransform(affineTransform); + } + }, + + _init: function() + { + this.setContentSize(this._gafproto.getBoundingBox()); + this._currentSequenceEnd = this._gafproto.getTotalFrames(); + this._totalFrameCount = this._currentSequenceEnd; + this.setFps(this._gafproto.getFps()); + this._container = new cc.Node(); + this.addChild(this._container); + + var self = this; + var asset = this._gafproto.getAsset(); + + // Construct objects for current time line + this._gafproto.getObjects().forEach(function(object) + { + var objectProto = asset._getProtos()[object]; + cc.assert(objectProto, "Error. GAF proto for type: " + object.type + " and reference id: " + object + " not found."); + self._objects[object] = objectProto._gafConstruct(); + }); + }, + + _enableTick: function(val) + { + if (!this._animationsSelectorScheduled && val) + { + this.schedule(this._processAnimations); + this._animationsSelectorScheduled = true; + } + else if (this._animationsSelectorScheduled && !val) + { + this.unschedule(this._processAnimations); + this._animationsSelectorScheduled = false; + } + }, + + _processAnimations: function (dt) + { + this._timeDelta += dt; + while (this._timeDelta >= this._frameTime) + { + this._timeDelta -= this._frameTime; + this._step(); + } + }, + + _step: function () + { + this._showingFrame = this._currentFrame; + + if(!this.getIsAnimationRunning()) + { + this._processAnimation(); + return; + } + + if(this._sequenceDelegate) + { + var seq; + if(!this._isReversed) + { + seq = this._getSequenceByLastFrame(this._currentFrame); + } + else + { + seq = this._getSequenceByFirstFrame(this._currentFrame + 1); + } + + if (seq) + { + this._sequenceDelegate(this, seq); + } + } + if (this._isCurrentFrameLastInSequence()) + { + if(this._isLooped) + { + if(this._animationStartedNextLoopDelegate) + this._animationStartedNextLoopDelegate(this); + } + else + { + this.setAnimationRunning(false, false); + if(this._animationFinishedPlayDelegate) + this._animationFinishedPlayDelegate(this); + } + } + this._processAnimation(); + this._currentFrame = this._nextFrame(); + }, + + _isCurrentFrameLastInSequence: function() + { + if (this._isReversed) + return this._currentFrame == this._currentSequenceStart; + return this._currentFrame == this._currentSequenceEnd - 1; + }, + + _nextFrame: function() + { + if (this._isCurrentFrameLastInSequence()) + { + if (!this._isLooped) + return this._currentFrame; + + if (this._isReversed) + return this._currentSequenceEnd - 1; + else + return this._currentSequenceStart; + } + + return this._currentFrame + (this._isReversed ? -1 : 1); + }, + + _processAnimation: function () + { + //var id = this._gafproto.getId(); + this._realizeFrame(this._container, this._currentFrame); + if (this._framePlayedDelegate) + { + this._framePlayedDelegate(this, this._currentFrame); + } + }, + _realizeFrame: function(out, frameIndex) + { + var self = this; + var objects = self._objects; + var frames = self._gafproto.getFrames(); + if(frameIndex > frames.length) + { + return; + } + var currentFrame = frames[frameIndex]; + if(!currentFrame) + { + return; + } + var states = currentFrame.states; + for(var stateIdx = 0, total = states.length; stateIdx < total; ++stateIdx) + { + var state = states[stateIdx]; + var object = objects[state.objectIdRef]; + if(!object) + { + return; + } + if(state.alpha < 0) + { + object._resetState(); + } + object._updateVisibility(state, self); + if(!object.isVisible()) + { + continue; + } + object._applyState(state, self); + var parent = out; + if(state.hasMask) + { + parent = objects[state.maskObjectIdRef]._getNode(); + cc.assert(parent, "Error! Mask not found."); + } + object._lastVisibleInFrame = 1 + frameIndex; + gaf.TimeLine.rearrangeSubobject(parent, object, state.depth); + if(object._step) + { + object._step(); + } + } + }, + setAnimationRunning: function (value, recursively) + { + this._isRunning = value; + if(recursively) + { + this._objects.forEach(function (obj) + { + if (obj && obj.setAnimationRunning) + { + obj.setAnimationRunning(value, recursively); + } + }); + } + }, + + _getSequenceByLastFrame: function(){ + var sequences = this._gafproto.getSequences(); + for(var item in sequences){ + if(sequences.hasOwnProperty(item)){ + if(sequences[item].end === frame + 1) + { + return item; + } + } + } + return ""; + }, + + _resetState : function() + { + this._super(); + this._currentFrame = this._currentSequenceStart; + }, + + _getSequenceByFirstFrame: function(){ + var sequences = this._gafproto.getSequences(); + for(var item in sequences){ + if(sequences.hasOwnProperty(item)){ + if(sequences[item].start === frame) + { + return item; + } + } + } + return ""; + } +}); + +gaf.TimeLine.rearrangeSubobject = function(out, object, depth) +{ + var parent = object.getParent(); + if (parent !== out) + { + object.removeFromParent(false); + out.addChild(object, depth); + } + else + { + object.setLocalZOrder(depth); + } +}; diff --git a/external/gaf/Library/GAFTimeLineProto.js b/external/gaf/Library/GAFTimeLineProto.js new file mode 100644 index 0000000000..9d78b219d9 --- /dev/null +++ b/external/gaf/Library/GAFTimeLineProto.js @@ -0,0 +1,32 @@ + +gaf._TimeLineProto = function(asset, animationFrameCount, boundingBox, pivotPoint, id, linkageName) +{ + id = typeof id != 'undefined' ? id : 0; + linkageName = linkageName || ""; + + this._objects = []; + + this.getTotalFrames = function(){return animationFrameCount}; + this.getBoundingBox = function() {return boundingBox}; + this.getId = function() {return id}; + this.getLinkageName = function() {return linkageName}; + this.getPivot = function(){return pivotPoint}; + this.getRect = function(){return boundingBox}; + this.getNamedParts = function() {return {}}; // Map name -> id + this.getSequences = function() {return {}}; // Map name -> {start, end} + this.getFrames = function(){return []}; // Array {states, actions} + this.getFps = function(){return 60}; + this.getObjects = function(){return this._objects}; + this.getAsset = function(){return asset}; + + /* + * Will construct GAFTimeLine + */ + this._gafConstruct = function() + { + var usedScale = this.getAsset()._usedAtlasScale; + var ret = new gaf.TimeLine(this, usedScale); + ret._init(); + return ret; + }; +}; diff --git a/external/gaf/gaf_viewer.css b/external/gaf/gaf_viewer.css new file mode 100644 index 0000000000..60933161d2 --- /dev/null +++ b/external/gaf/gaf_viewer.css @@ -0,0 +1,42 @@ +#drop_zone { + border: 2px dashed #bbb; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + padding: 25px; + text-align: center; + font: 20pt bold 'Vollkorn'; + color: #bbb; + +} +.renderjson a { + text-decoration: none; +} +.renderjson .disclosure { + color: crimson; + font-size: 150%; +} +.renderjson .syntax { + color: grey; +} +.renderjson .string { + color: darkred; +} +.renderjson .number { + color: darkcyan; +} +.renderjson .boolean { + color: blueviolet; +} +.renderjson .key { + color: darkblue; +} +.renderjson .keyword { + color: blue; +} +.renderjson .object.syntax { + color: lightseagreen; +} +.renderjson .array.syntax { + color: orange; +} diff --git a/external/gaf/gaf_viewer.html b/external/gaf/gaf_viewer.html new file mode 100644 index 0000000000..2c66aeb05f --- /dev/null +++ b/external/gaf/gaf_viewer.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + +
    Drop GAF here
    + + + + + + \ No newline at end of file diff --git a/external/gaf/gaf_viewer.js b/external/gaf/gaf_viewer.js new file mode 100644 index 0000000000..db5bdbea7f --- /dev/null +++ b/external/gaf/gaf_viewer.js @@ -0,0 +1,219 @@ + /* + * Created by Teivaz on 29.11.2014. + * Thanks to David Caldwell for `renderjson` + */ +function handleFileSelect(evt) { + evt.stopPropagation(); + evt.preventDefault(); + + var files = evt.dataTransfer.files; + + var output = []; + for (var i = 0, f; f = files[i]; i++) { + var name = escape(f.name); + var ext = name.split('.').pop(); + if (ext == 'gaf') { + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(req) { + var arrayBuffer = new gaf.DataReader(req.target.result); + var loader = new gaf.Loader(); + var data = loader.LoadStream(arrayBuffer); + document.getElementById('list').appendChild(renderjson(data)); + }; + })(f); + reader.readAsArrayBuffer(f); + } + } +} + +function handleDragOver(evt) { + evt.stopPropagation(); + evt.preventDefault(); + evt.dataTransfer.dropEffect = 'copy'; +} + +var dropZone = document.getElementById('drop_zone'); +dropZone.addEventListener('dragover', handleDragOver, false); +dropZone.addEventListener('drop', handleFileSelect, false); + +var module; +(module || {}).exports = renderjson = (function() { + var themetext = function( /* [class, text]+ */ ) { + var spans = []; + while (arguments.length) + spans.push(append(span(Array.prototype.shift.call(arguments)), + text(Array.prototype.shift.call(arguments)))); + return spans; + }; + var append = function( /* el, ... */ ) { + var el = Array.prototype.shift.call(arguments); + for (var a = 0; a < arguments.length; a++) + if (arguments[a].constructor == Array) + append.apply(this, [el].concat(arguments[a])); + else + el.appendChild(arguments[a]); + return el; + }; + var prepend = function(el, child) { + el.insertBefore(child, el.firstChild); + return el; + }; + var isempty = function(obj) { + for (var k in obj) + if (obj.hasOwnProperty(k)) return false; + return true; + }; + var text = function(txt) { + return document.createTextNode(txt) + }; + var div = function() { + return document.createElement("div") + }; + var span = function(classname) { + var s = document.createElement("span"); + if (classname) s.className = classname; + return s; + }; + var A = function A(txt, classname, callback) { + var a = document.createElement("a"); + if (classname) a.className = classname; + a.appendChild(text(txt)); + a.href = '#'; + a.onclick = function() { + callback(); + return false; + }; + return a; + }; + + function _renderjson(json, indent, dont_indent, show_level, sort_objects) { + var my_indent = dont_indent ? "" : indent; + + if (json === null) return themetext(null, my_indent, "keyword", "null"); + if (json === void 0) return themetext(null, my_indent, "keyword", "undefined"); + if (typeof(json) != "object") // Strings, numbers and bools + return themetext(null, my_indent, typeof(json), JSON.stringify(json)); + + var disclosure = function(open, close, type, builder) { + var content; + var empty = span(type); + var show = function() { + if (!content) append(empty.parentNode, + content = prepend(builder(), + A(renderjson.hide, "disclosure", + function() { + content.style.display = "none"; + empty.style.display = "inline"; + }))); + content.style.display = "inline"; + empty.style.display = "none"; + }; + + function isColor(a){ + return a.hasOwnProperty('a') && a.hasOwnProperty('r') && a.hasOwnProperty('g') && a.hasOwnProperty('b'); + } + + var color_rect = span(); + if (json.hasOwnProperty("tagName")) + var placeholder = json.tagName; + else if (json.hasOwnProperty("header")) + placeholder = " GAF v" + json.header.versionMajor + "." + json.header.versionMinor + " "; + else if (json.constructor == Array) + placeholder = " " + json.length + " "; + else if (json.hasOwnProperty("id")) + placeholder = " id:" + json.id + " ... "; + else if (json.hasOwnProperty("objectId")) + placeholder = " id:" + json.objectId + " ... "; + else if (json.hasOwnProperty("frame")) + placeholder = " frame:" + json.frame + " ... "; + else if(isColor(json)){ + color_rect.style.backgroundColor = "rgba("+json.r+","+json.g+","+json.b+","+json.a / 255.0+")";// parseInt(json.r).toString(16) + parseInt(json.g).toString(16) + parseInt(json.b).toString(16); + color_rect.style.height = '10px'; + color_rect.style.width = '10px'; + color_rect.style.display = 'inline-block'; + color_rect.style.margin = '0 4px'; + color_rect.style.border = '1px solid #7f7f7f'; + } + + placeholder = placeholder || ' ... '; + append(empty, + A(renderjson.show, "disclosure", show), + color_rect, + themetext(type + " syntax", open), + A(placeholder, null, show), + themetext(type + " syntax", close)); + + var el = append(span(), text(my_indent.slice(0, -1)), empty); + if (show_level > 0) + show(); + return el; + }; + + if (json.constructor == Array) { + if (json.length == 0) return themetext(null, my_indent, "array syntax", "[]"); + + return disclosure("[", "]", "array", function() { + var as = append(span("array"), themetext("array syntax", "[", null, "\n")); + for (var i = 0; i < json.length; i++) + append(as, + _renderjson(json[i], indent + " ", false, show_level - 1, sort_objects), + i != json.length - 1 ? themetext("syntax", ",") : [], + text("\n")); + append(as, themetext(null, indent, "array syntax", "]")); + return as; + }); + } + + // object + if (isempty(json)) + return themetext(null, my_indent, "object syntax", "{}"); + + + return disclosure("{", "}", "object", function() { + var os = append(span("object"), themetext("object syntax", "{", null, "\n")); + for (var k in json) var last = k; + var keys = Object.keys(json); + if (sort_objects) + keys = keys.sort(); + for (var i in keys) { + var k = keys[i]; + append(os, themetext(null, indent + " ", "key", '"' + k + '"', "object syntax", ': '), + _renderjson(json[k], indent + " ", true, show_level - 1, sort_objects), + k != last ? themetext("syntax", ",") : [], + text("\n")); + } + append(os, themetext(null, indent, "object syntax", "}")); + return os; + }); + } + + var renderjson = function renderjson(json) { + var pre = append(document.createElement("pre"), _renderjson(json, "", false, renderjson.show_to_level, renderjson.sort_objects)); + pre.className = "renderjson"; + return pre; + }; + renderjson.set_icons = function(show, hide) { + renderjson.show = show; + renderjson.hide = hide; + return renderjson; + }; + renderjson.set_show_to_level = function(level) { + renderjson.show_to_level = typeof level == "string" && + level.toLowerCase() === "all" ? Number.MAX_VALUE : level; + return renderjson; + }; + renderjson.set_sort_objects = function(sort_bool) { + renderjson.sort_objects = sort_bool; + return renderjson; + }; + // Backwards compatiblity. Use set_show_to_level() for new code. + renderjson.set_show_by_default = function(show) { + renderjson.show_to_level = show ? Number.MAX_VALUE : 0; + return renderjson; + }; + renderjson.set_icons('⊕', '⊖'); + renderjson.set_show_by_default(false); + renderjson.set_sort_objects(false); + return renderjson; +})(); \ No newline at end of file diff --git a/external/pluginx/Plugin.js b/external/pluginx/Plugin.js new file mode 100644 index 0000000000..1a2aaced03 --- /dev/null +++ b/external/pluginx/Plugin.js @@ -0,0 +1,254 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * plugin manager + * @class + * + */ +(function(){ + + if(cc === undefined){ + return; + } + + var config = cc.game.config.plugin || {}; + + //Native plugin usage + var PluginManager = function(){}; + + PluginManager.prototype = { + constructor: PluginManager, + + /** + * @returns {PluginManager} + * @expose + */ + getInstance: function(){ + return this; + }, + + /** + * @param {String} pluginName + * @expose + */ + loadPlugin: function(pluginName){ + + }, + + /** + * + * @param pluginName + * @expose + */ + unloadPlugin: function(pluginName){ + + } + }; + + var PluginAssembly = function(){}; + + PluginAssembly.prototype = { + constructor: PluginAssembly, + + /** + * @param {Boolean} debug + * @expose + */ + setDebugMode: function(debug){}, + + /** + * @param {String} appKey + * @expose + */ + startSession: function(appKey){}, + + /** + * @param {Boolean} Capture + * @expose + */ + setCaptureUncaughtException: function(Capture){}, + + /** + * @param {String} funName + * @param {All} Params + * @expose + */ + callFuncWithParam: function(funName){ + if(typeof this[funName] === 'function'){ + return this[funName].apply(this, Array.prototype.splice.call(arguments, 1)); + }else{ + cc.log("function is not define"); + } + }, + + /** + * @param {String} funName + * @param {All} Params + * @expose + */ + callStringFuncWithParam: function(funName){ + this.callFuncWithParam.apply(arguments); + }, + + /** + * @returns {String} + * @expose + */ + getPluginName: function(){ + return this._name; + }, + + /** + * @returns {String} + * @expose + */ + getPluginVersion: function(){ + return this._version; + } + }; + + /** @expose */ + PluginAssembly.extend = function(name, porp){ + var p, prototype = {}; + for(p in PluginAssembly.prototype){ + prototype[p] = PluginAssembly.prototype[p]; + } + for(p in porp){ + prototype[p] = porp[p]; + } + var tmp = eval("(function " + name + "Plugin(){})"); + prototype.constructor = tmp; + tmp.prototype = prototype; + return tmp; + }; + + //Param + var Param = function(type, value){ + var paramType = plugin.PluginParam.ParamType,tmpValue; + switch(type){ + case paramType.TypeInt: + tmpValue = parseInt(value); + break; + case paramType.TypeFloat: + tmpValue = parseFloat(value); + break; + case paramType.TypeBool: + tmpValue = Boolean(value); + break; + case paramType.TypeString: + tmpValue = String(value); + break; + case paramType.TypeStringMap: + tmpValue = value//JSON.stringify(value); + break; + default: + tmpValue = value; + } + return tmpValue + }; + + /** @expose */ + Param.ParamType = { + /** @expose */ + TypeInt:1, + /** @expose */ + TypeFloat:2, + /** @expose */ + TypeBool:3, + /** @expose */ + TypeString:4, + /** @expose */ + TypeStringMap:5 + }; + + /** @expose */ + Param.AdsResultCode = { + /** @expose */ + AdsReceived:0, + /** @expose */ + FullScreenViewShown:1, + /** @expose */ + FullScreenViewDismissed:2, + /** @expose */ + PointsSpendSucceed:3, + /** @expose */ + PointsSpendFailed:4, + /** @expose */ + NetworkError:5, + /** @expose */ + UnknownError:6 + }; + + /** @expose */ + Param.PayResultCode = { + /** @expose */ + PaySuccess:0, + /** @expose */ + PayFail:1, + /** @expose */ + PayCancel:2, + /** @expose */ + PayTimeOut:3 + }; + + /** @expose */ + Param.ShareResultCode = { + /** @expose */ + ShareSuccess:0, + /** @expose */ + ShareFail:1, + /** @expose */ + ShareCancel:2, + /** @expose */ + ShareTimeOut:3 + }; + + /** @expose */ + var PluginList = {}; + + /** @expose */ + var Plugin = { + + /** @expose */ + extend: function(name, extend){ + PluginList[name] = new (PluginAssembly.extend(name, extend)); + typeof PluginList[name].ctor === "function" && PluginList[name].ctor(config[name]); + }, + + /** @expose */ + PluginList: PluginList, + + /** @expose */ + PluginParam: Param, + + /** @expose */ + PluginManager: new PluginManager() + + }; + + /** @expose */ + window.plugin = Plugin; + +})(); \ No newline at end of file diff --git a/external/pluginx/platform/facebook.js b/external/pluginx/platform/facebook.js new file mode 100644 index 0000000000..190115951a --- /dev/null +++ b/external/pluginx/platform/facebook.js @@ -0,0 +1,557 @@ +/**************************************************************************** + Copyright (c) 2013-2014 Chukong Technologies Inc. + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +/** + * Facebook SDK for Web Platform
    + * FacebookAgent... + * + * @property {String} name - plugin name + * @property {String} version - API version + */ +plugin.extend('facebook', { + name: "", + version: "", + _userInfo: null, + _isLoggedIn: false, + + /** + * HTTP methods constants + * @constant + * @type {Object} + */ + HttpMethod: { + 'GET': 'get', + 'POST': 'post', + 'DELETE': 'delete' + }, + + /** + * Succeed code returned in callbacks + * @constant + * @type {Number} + */ + CODE_SUCCEED: 0, + + /** + * App event names constants + * @constant + * @type {Object} + */ + AppEvent: { + 'ACTIVATED_APP': FB.AppEvents.EventNames.ACTIVATED_APP, + 'COMPLETED_REGISTRATION': FB.AppEvents.EventNames.COMPLETED_REGISTRATION, + 'VIEWED_CONTENT': FB.AppEvents.EventNames.VIEWED_CONTENT, + 'SEARCHED': FB.AppEvents.EventNames.SEARCHED, + 'RATED': FB.AppEvents.EventNames.RATED, + 'COMPLETED_TUTORIAL': FB.AppEvents.EventNames.COMPLETED_TUTORIAL, + 'ADDED_TO_CART': FB.AppEvents.EventNames.ADDED_TO_CART, + 'ADDED_TO_WISHLIST': FB.AppEvents.EventNames.ADDED_TO_WISHLIST, + 'INITIATED_CHECKOUT': FB.AppEvents.EventNames.INITIATED_CHECKOUT, + 'ADDED_PAYMENT_INFO': FB.AppEvents.EventNames.ADDED_PAYMENT_INFO, + 'PURCHASED': FB.AppEvents.EventNames.PURCHASED, + 'ACHIEVED_LEVEL': FB.AppEvents.EventNames.ACHIEVED_LEVEL, + 'UNLOCKED_ACHIEVEMENT': FB.AppEvents.EventNames.UNLOCKED_ACHIEVEMENT, + 'SPENT_CREDITS': FB.AppEvents.EventNames.SPENT_CREDITS + }, + + /** + * App event parameter names constants + * @constant + * @type {Object} + */ + AppEventParam: { + 'CURRENCY': FB.AppEvents.ParameterNames.CURRENCY, + 'REGISTRATION_METHOD': FB.AppEvents.ParameterNames.REGISTRATION_METHOD, + 'CONTENT_TYPE': FB.AppEvents.ParameterNames.CONTENT_TYPE, + 'CONTENT_ID': FB.AppEvents.ParameterNames.CONTENT_ID, + 'SEARCH_STRING': FB.AppEvents.ParameterNames.SEARCH_STRING, + 'SUCCESS': FB.AppEvents.ParameterNames.SUCCESS, + 'MAX_RATING_VALUE': FB.AppEvents.ParameterNames.MAX_RATING_VALUE, + 'PAYMENT_INFO_AVAILABLE': FB.AppEvents.ParameterNames.PAYMENT_INFO_AVAILABLE, + 'NUM_ITEMS': FB.AppEvents.ParameterNames.NUM_ITEMS, + 'LEVEL': FB.AppEvents.ParameterNames.LEVEL, + 'DESCRIPTION': FB.AppEvents.ParameterNames.DESCRIPTION + }, + + /** + * App event parameter values constants + * @constant + * @type {Object} + */ + AppEventParamValue: { + 'VALUE_YES': "1", + 'VALUE_NO': "0" + }, + + _checkLoginStatus: function() { + var self = this; + FB.getLoginStatus(function (response) { + if (response && response.status === 'connected') { + //login + self._isLoggedIn = true; + //save user info + self._userInfo = response['authResponse']; + } else { + // Reset cached status + self._isLoggedIn = false; + self._userInfo = {}; + } + }); + }, + + ctor: function (config) { + this.name = "facebook"; + this.version = "1.0"; + this._userInfo = {}; + this._isLoggedIn = false; + + if (!FB) { + return; + } + + //This configuration will be read from the project.json. + FB.init(config); + this._checkLoginStatus(); + + plugin.FacebookAgent = this; + }, + /** + * Gets the current object + * @returns {FacebookAgent} + */ + getInstance: function () { + return this; + }, + /** + * Login to facebook + * @param {Function} callback + * @param {Array} permissions + * @example + * //example + * plugin.FacebookAgent.login(); + */ + login: function (permissions, callback) { + var self = this; + if (typeof permissions == 'function') { + callback = permissions; + permissions = []; + } + if (permissions.every(function (item) { + if (item != 'public_profile') + return true; + })) { + permissions.push("public_profile"); + } + var permissionsStr = permissions.join(','); + FB.login(function (response) { + if (response['authResponse']) { + //save user info + self._isLoggedIn = true; + self._userInfo = response['authResponse']; + var permissList = response['authResponse']['grantedScopes'].split(","); + typeof callback === 'function' && callback(0, { + accessToken: response['authResponse']['accessToken'], + permissions: permissList + }); + } else { + self._isLoggedIn = false; + self._userInfo = {}; + typeof callback === 'function' && callback(response['error_code'] || 1, { + error_message: response['error_message'] || "Unknown error" + }); + } + }, { + scope: permissionsStr, + return_scopes: true + }); + }, + /** + * Checking login status + * @return {Bool} Whether user is logged in + * @example + * //example + * plugin.FacebookAgent.isLoggedIn(type, msg); + */ + isLoggedIn: function () { + //this._checkLoginStatus(); + return this._isLoggedIn; + }, + + /** + * Logout of facebook + * @param {Function} callback + * @example + * //example + * plugin.FacebookAgent.logout(callback); + */ + logout: function (callback) { + var self = this; + FB.logout(function (response) { + if (response['authResponse']) { + // user is now logged out + self._isLoggedIn = false; + self._userInfo = {}; + typeof callback === 'function' && callback(0, {"isLoggedIn": false}); + } else { + typeof callback === 'function' && callback(response['error_code'] || 1, { + error_message: response['error_message'] || "Unknown error" + }); + } + }); + }, + + /** + * Acquiring new permissions + * @deprecated since v3.0 + * @param permissions + * @param callback + * @example + * //example + * plugin.FacebookAgent.requestPermissions(["manage_pages"], callback); + */ + _requestPermissions: function (permissions, callback) { + var permissionsStr = permissions.join(','); + var self = this; + FB.login(function (response) { + if (response['authResponse']) { + var permissList = response['authResponse']['grantedScopes'].split(","); + //save user info + self._isLoggedIn = true; + self._userInfo = response['authResponse']; + typeof callback === 'function' && callback(0, { + permissions: permissList + }); + } else { + self._isLoggedIn = false; + self._userInfo = {}; + typeof callback === 'function' && callback(response['error_code'] || 1, { + error_message: response['error_message'] || "Unknown error" + }); + } + }, { + scope: permissionsStr, + return_scopes: true + }); + }, + + /** + * Acquiring AccessToken + * @return {String} + * @example + * //example + * var accessToken = plugin.FacebookAgent.getAccessToken(); + */ + getAccessToken: function () { + return this._userInfo ? this._userInfo['accessToken'] : null; + }, + + /** + * Acquiring User ID + * @return {String} + * @example + * //example + * var userID = plugin.FacebookAgent.getUserID(); + */ + getUserID: function () { + return this._userInfo ? this._userInfo['userID'] : null; + }, + + _share: function (info, callback) { + FB.ui({ + method: 'share', + name: info['title'], + caption: info['caption'], + description: info['text'], + href: info['link'], + picture: info['imageUrl'] + }, + function (response) { + if (response) { + if (response['post_id']) + typeof callback === 'function' && callback(0, { + didComplete: true, + post_id: response['post_id'] + }); + else + typeof callback === 'function' && callback(response['error_code'] || 1, { + error_message: response['error_message'] || "Unknown error" + }); + } else { + typeof callback === 'function' && callback(1, { + error_message: "Unknown error" + }); + } + }); + }, + + /** + * Request a web dialog for Facebook sharing + * @param info + * @param callback + */ + dialog: function (info, callback) { + if (!info) { + typeof callback === 'function' && callback(1, { + error_message: "No info parameter provided" + }); + return; + } + if (!this.canPresentDialog(info)) { + typeof callback === 'function' && callback(1, { + error_message: "The requested dialog: " + info['dialog'] + " can not be presented on Web" + }); + return; + } + + // Preprocess properties + info['name'] = info['name'] || info['site']; + delete info['site']; + + info['href'] = info['href'] || info['link'] || info['siteUrl']; + delete info['siteUrl']; + delete info['link']; + + info['picture'] = info['picture'] || info['image'] || info['photo'] || info['imageUrl'] || info['imagePath']; + delete info['imageUrl']; + delete info['imagePath']; + delete info['photo']; + delete info['image']; + + info['caption'] = info['title'] || info['caption']; + delete info['title']; + + info['description'] = info['text'] || info['description']; + delete info['text']; + + var method = info['dialog']; + delete info['dialog']; + + if (method === 'shareLink' || method == 'feedDialog') { + info['method'] = 'share'; + } else if (method == 'messageLink') { + info['method'] = 'send'; + info['link'] = info['href']; + } else if (method == 'shareOpenGraph') { + info['method'] = 'share_open_graph'; + + if (info['url']) { + var obj = {}; + if (info["preview_property_name"]) + obj[info["preview_property_name"]] = info["url"]; + else + obj["object"] = info["url"]; + + for (var p in info) { + if (p != "method" && p != "action_type" && p != "action_properties") { + info[p] && (obj[p] = info[p]); + delete info[p]; + } + } + + info['action_properties'] = JSON.stringify(obj); + } + } + + FB.ui(info, + function (response) { + if (response && typeof callback === 'function') { + if (response['post_id'] || response['success']) { + callback(0, { + didComplete: true, + post_id: response['post_id'] || "" + }); + } + else { + if (response['error_code']) { + callback(response['error_code'], { + error_message : response['error_message'] || 'Unknown error' + }); + } + else callback(0, response); + } + } else if (response == undefined && typeof callback === 'function') { + callback(1, { + error_message: "Unknown error" + }); + } + }); + }, + + /** + * Check whether the share request can be achieved + * @param info + */ + canPresentDialog: function (info) { + if (info && info['dialog'] && ( + info['dialog'] === 'shareLink' || + info['dialog'] === 'feedDialog' || + info['dialog'] === 'shareOpenGraph' || + info['dialog'] === 'messageLink')) + return true; + else + return false; + }, + /** + * FB.api + * @param {String} path + * @param {Number} httpmethod + * @param {Object} params + * @param {Function} callback + */ + api: function (path, httpmethod, params, callback) { + if (typeof params === 'function') { + callback = params; + params = {}; + } + FB.api(path, httpmethod, params, function (response) { + if (response.error) { + typeof callback === 'function' && callback(response['error']['code'], { + error_message: response['error']['message'] || 'Unknown error' + }) + } else { + typeof callback === 'function' && callback(0, response); + } + }); + }, + + _getPermissionList: function (callback) { + FB.api("/me/permissions", function (response) { + if (response['data']) { + var permissionList = []; + for (var i = 0; i < response['data'].length; i++) { + if (response['data'][i]["status"] == "granted") { + permissionList.push(response['data'][i]['permission']); + } + } + typeof callback == 'function' && callback(0, { + permissions: permissionList + }); + } else { + if (!response['error']) + response['error'] = {}; + typeof callback == 'function' && callback(response['error']['code'] || 1, { + error_message: response['error']['message'] || 'Unknown error' + }); + } + }) + }, + + destroyInstance: function () { + }, + canvas:{ + /** + * Payment request + * @param {Object} info + * @param {Function} callback + */ + pay: function (info, callback) { + /* + * Reference document + * https://developers.facebook.com/docs/payments/reference/paydialog + */ + info['method'] = 'pay'; + info['action'] = 'purchaseitem'; + + FB.ui(info, function (response) { + if (response['error_code']) { + callback(response['error_code'] || 1, { + error_message: response['error_message'] || response['error_msg'] || 'Unknown error' + }); + } else { + callback(0, response); + } + }) + } + }, + + /** + * Send an app requests to friends + * @param {Object} info + * @param {Function} callback + */ + appRequest: function (info, callback) { + if (!info) { + typeof callback === 'function' && callback(1, { + error_message: "No info parameter provided" + }); + return; + } + + info['method'] = "apprequests"; + + FB.ui(info, + function (response) { + if (response) { + if (response['error_code']) { + typeof callback === 'function' && callback(response['error_code'], { + error_message : response['error_message'] || 'Unknown error' + }); + } + else { + typeof callback === 'function' && callback(0, response); + } + } else { + typeof callback === 'function' && callback(1, { + error_message: "Unknown error" + }); + } + }); + }, + + /** + * Log an event + * @param {String} eventName + * @param {Number} valueToSum + * @param {Object} parameters + */ + logEvent: function (eventName, valueToSum, parameters) { + if (eventName == undefined) return; + if (valueToSum === undefined && parameters === undefined) { + FB.AppEvents.logEvent(eventName, null, null); + } else if (typeof valueToSum === "number" && parameters === undefined) { + FB.AppEvents.logEvent(eventName, valueToSum); + } else if (typeof valueToSum === "object" && parameters === undefined) { + FB.AppEvents.logEvent(eventName, null, valueToSum); + } else { + FB.AppEvents.logEvent(eventName, valueToSum, parameters); + } + }, + + /** + * Activate App + */ + activateApp: function () { + FB.AppEvents.activateApp(); + }, + + /** + * Log a purchase + * @param {Number} amount Amount of the purchase + * @param {String} currency The currency + * @param {Object} param Supplemental parameters + */ + logPurchase:function(amount, currency, param){ + FB.AppEvents.logPurchase(amount, currency, param); + } +}); diff --git a/external/pluginx/platform/facebook_sdk.js b/external/pluginx/platform/facebook_sdk.js new file mode 100644 index 0000000000..bc05068323 --- /dev/null +++ b/external/pluginx/platform/facebook_sdk.js @@ -0,0 +1,151 @@ + +/*1411456395,,JIT Construction: v1425205,zh_CN*/ + +/** + * Copyright Facebook Inc. + * + * Licensed under the Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + */ +try {window.FB || (function(window) { + var self = window, document = window.document; + var setTimeout = window.setTimeout, setInterval = window.setInterval,clearTimeout = window.clearTimeout,clearInterval = window.clearInterval;var __DEV__ = 0; + function emptyFunction() {}; + var __w, __t; + __t=function(a){return a[0];};__w=function(a){return a;}; + var require,__d;(function(a){var b={},c={},d=['global','require','requireDynamic','requireLazy','module','exports'];require=function(e,f){if(c.hasOwnProperty(e))return c[e];if(!b.hasOwnProperty(e)){if(f)return null;throw new Error('Module '+e+' has not been defined');}var g=b[e],h=g.deps,i=g.factory.length,j,k=[];for(var l=0;l1?Number(arguments[1]):0;if(isNaN(j))j=0;var k=Math.min(Math.max(j,0),i.length);return i.indexOf(String(h),j)==k;};g.endsWith=function(h){var i=String(this);if(this==null)throw new TypeError('String.prototype.endsWith called on null or undefined');var j=i.length,k=String(h),l=arguments.length>1?Number(arguments[1]):j;if(isNaN(l))l=0;var m=Math.min(Math.max(l,0),j),n=m-k.length;if(n<0)return false;return i.lastIndexOf(k,n)==n;};g.contains=function(h){if(this==null)throw new TypeError('String.prototype.contains called on null or undefined');var i=String(this),j=arguments.length>1?Number(arguments[1]):0;if(isNaN(j))j=0;return i.indexOf(String(h),j)!=-1;};g.repeat=function(h){if(this==null)throw new TypeError('String.prototype.repeat called on null or undefined');var i=String(this),j=h?Number(h):0;if(isNaN(j))j=0;if(j<0||j===Infinity)throw RangeError();if(j===1)return i;if(j===0)return '';var k='';while(j){if(j&1)k+=i;if((j>>=1))i+=i;}return k;};e.exports=g;},null); + __d("ES5Array",[],function(a,b,c,d,e,f){var g={};g.isArray=function(h){return Object.prototype.toString.call(h)=='[object Array]';};e.exports=g;},null); + __d("ie8DontEnum",[],function(a,b,c,d,e,f){var g=['toString','toLocaleString','valueOf','hasOwnProperty','isPrototypeOf','prototypeIsEnumerable','constructor'],h=({}).hasOwnProperty,i=function(){};if(({toString:true}).propertyIsEnumerable('toString'))i=function(j,k){for(var l=0;l1)))/4)-ca((ga-1901+ha)/100)+ca((ga-1601+ha)/400);};}if(typeof JSON=="object"&&JSON){k.stringify=JSON.stringify;k.parse=JSON.parse;}if((m=typeof k.stringify=="function"&&!ea)){(ba=function(){return 1;}).toJSON=ba;try{m=k.stringify(0)==="0"&&k.stringify(new Number())==="0"&&k.stringify(new String())=='""'&&k.stringify(g)===j&&k.stringify(j)===j&&k.stringify()===j&&k.stringify(ba)==="1"&&k.stringify([ba])=="[1]"&&k.stringify([j])=="[null]"&&k.stringify(null)=="null"&&k.stringify([j,g,null])=="[null,null,null]"&&k.stringify({result:[ba,true,false,null,"\0\b\n\f\r\t"]})==l&&k.stringify(null,ba)==="1"&&k.stringify([1,2],null,1)=="[\n 1,\n 2\n]"&&k.stringify(new Date(-8.64e+15))=='"-271821-04-20T00:00:00.000Z"'&&k.stringify(new Date(8.64e+15))=='"+275760-09-13T00:00:00.000Z"'&&k.stringify(new Date(-62198755200000))=='"-000001-01-01T00:00:00.000Z"'&&k.stringify(new Date(-1))=='"1969-12-31T23:59:59.999Z"';}catch(fa){m=false;}}if(typeof k.parse=="function")try{if(k.parse("0")===0&&!k.parse(false)){ba=k.parse(l);if((r=ba.A.length==5&&ba.A[0]==1)){try{r=!k.parse('"\t"');}catch(fa){}if(r)try{r=k.parse("01")!=1;}catch(fa){}}}}catch(fa){r=false;}ba=l=null;if(!m||!r){if(!(h={}.hasOwnProperty))h=function(ga){var ha={},ia;if((ha.__proto__=null,ha.__proto__={toString:1},ha).toString!=g){h=function(ja){var ka=this.__proto__,la=ja in (this.__proto__=null,this);this.__proto__=ka;return la;};}else{ia=ha.constructor;h=function(ja){var ka=(this.constructor||ia).prototype;return ja in this&&!(ja in ka&&this[ja]===ka[ja]);};}ha=null;return h.call(this,ga);};i=function(ga,ha){var ia=0,ja,ka,la,ma;(ja=function(){this.valueOf=0;}).prototype.valueOf=0;ka=new ja();for(la in ka)if(h.call(ka,la))ia++;ja=ka=null;if(!ia){ka=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];ma=function(na,oa){var pa=g.call(na)=="[object Function]",qa,ra;for(qa in na)if(!(pa&&qa=="prototype")&&h.call(na,qa))oa(qa);for(ra=ka.length;qa=ka[--ra];h.call(na,qa)&&oa(qa));};}else if(ia==2){ma=function(na,oa){var pa={},qa=g.call(na)=="[object Function]",ra;for(ra in na)if(!(qa&&ra=="prototype")&&!h.call(pa,ra)&&(pa[ra]=1)&&h.call(na,ra))oa(ra);};}else ma=function(na,oa){var pa=g.call(na)=="[object Function]",qa,ra;for(qa in na)if(!(pa&&qa=="prototype")&&h.call(na,qa)&&!(ra=qa==="constructor"))oa(qa);if(ra||h.call(na,(qa="constructor")))oa(qa);};return ma(ga,ha);};if(!m){n={"\\":"\\\\",'"':'\\"',"\b":"\\b","\f":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"};o=function(ga,ha){return ("000000"+(ha||0)).slice(-ga);};p=function(ga){var ha='"',ia=0,ja;for(;ja=ga.charAt(ia);ia++)ha+='\\"\b\f\n\r\t'.indexOf(ja)>-1?n[ja]:ja<" "?"\\u00"+o(2,ja.charCodeAt(0).toString(16)):ja;return ha+'"';};q=function(ga,ha,ia,ja,ka,la,ma){var na=ha[ga],oa,pa,qa,ra,sa,ta,ua,va,wa,xa,ya,za,ab,bb,cb;if(typeof na=="object"&&na){oa=g.call(na);if(oa=="[object Date]"&&!h.call(na,"toJSON")){if(na>-1/0&&na<1/0){if(ea){ra=ca(na/86400000);for(pa=ca(ra/365.2425)+1970-1;ea(pa+1,0)<=ra;pa++);for(qa=ca((ra-ea(pa,0))/30.42);ea(pa,qa+1)<=ra;qa++);ra=1+ra-ea(pa,qa);sa=(na%86400000+86400000)%86400000;ta=ca(sa/3600000)%24;ua=ca(sa/60000)%60;va=ca(sa/1000)%60;wa=sa%1000;}else{pa=na.getUTCFullYear();qa=na.getUTCMonth();ra=na.getUTCDate();ta=na.getUTCHours();ua=na.getUTCMinutes();va=na.getUTCSeconds();wa=na.getUTCMilliseconds();}na=(pa<=0||pa>=10000?(pa<0?"-":"+")+o(6,pa<0?-pa:pa):o(4,pa))+"-"+o(2,qa+1)+"-"+o(2,ra)+"T"+o(2,ta)+":"+o(2,ua)+":"+o(2,va)+"."+o(3,wa)+"Z";}else na=null;}else if(typeof na.toJSON=="function"&&((oa!="[object Number]"&&oa!="[object String]"&&oa!="[object Array]")||h.call(na,"toJSON")))na=na.toJSON(ga);}if(ia)na=ia.call(ha,ga,na);if(na===null)return "null";oa=g.call(na);if(oa=="[object Boolean]"){return ""+na;}else if(oa=="[object Number]"){return na>-1/0&&na<1/0?""+na:"null";}else if(oa=="[object String]")return p(na);if(typeof na=="object"){for(ab=ma.length;ab--;)if(ma[ab]===na)throw TypeError();ma.push(na);xa=[];bb=la;la+=ka;if(oa=="[object Array]"){for(za=0,ab=na.length;za0)for(ja="",ia>10&&(ia=10);ja.length-1){z++;}else if("{}[]:,".indexOf(ia)>-1){z++;return ia;}else if(ia=='"'){for(ja="@",z++;z-1){ja+=t[ia];z++;}else if(ia=="u"){ka=++z;for(la=z+4;z="0"&&ia<="9"||ia>="a"&&ia<="f"||ia>="A"&&ia<="F"))u();}ja+=s("0x"+ga.slice(ka,z));}else u();}else{if(ia=='"')break;ja+=ia;z++;}}if(ga.charAt(z)=='"'){z++;return ja;}u();}else{ka=z;if(ia=="-"){ma=true;ia=ga.charAt(++z);}if(ia>="0"&&ia<="9"){if(ia=="0"&&(ia=ga.charAt(z+1),ia>="0"&&ia<="9"))u();ma=false;for(;z="0"&&ia<="9");z++);if(ga.charAt(z)=="."){la=++z;for(;la="0"&&ia<="9");la++);if(la==z)u();z=la;}ia=ga.charAt(z);if(ia=="e"||ia=="E"){ia=ga.charAt(++z);if(ia=="+"||ia=="-")z++;for(la=z;la="0"&&ia<="9");la++);if(la==z)u();z=la;}return +ga.slice(ka,z);}if(ma)u();if(ga.slice(z,z+4)=="true"){z+=4;return true;}else if(ga.slice(z,z+5)=="false"){z+=5;return false;}else if(ga.slice(z,z+4)=="null"){z+=4;return null;}u();}}return "$";};w=function(ga){var ha,ia,ja;if(ga=="$")u();if(typeof ga=="string"){if(ga.charAt(0)=="@")return ga.slice(1);if(ga=="["){ha=[];for(;;ia||(ia=true)){ga=v();if(ga=="]")break;if(ia)if(ga==","){ga=v();if(ga=="]")u();}else u();if(ga==",")u();ha.push(w(ga));}return ha;}else if(ga=="{"){ha={};for(;;ia||(ia=true)){ga=v();if(ga=="}")break;if(ia)if(ga==","){ga=v();if(ga=="}")u();}else u();if(ga==","||typeof ga!="string"||ga.charAt(0)!="@"||v()!=":")u();ha[ga.slice(1)]=w(v());}return ha;}u();}return ga;};y=function(ga,ha,ia){var ja=x(ga,ha,ia);if(ja===j){delete ga[ha];}else ga[ha]=ja;};x=function(ga,ha,ia){var ja=ga[ha],ka;if(typeof ja=="object"&&ja)if(g.call(ja)=="[object Array]"){for(ka=ja.length;ka--;)y(ja,ka,ia);}else i(ja,function(la){y(ja,la,ia);});return ia.call(ga,ha,ja);};k.parse=function(ga,ha){z=0;aa=ga;var ia=w(v());if(v()!="$")u();z=aa=null;return ha&&g.call(ha)=="[object Function]"?x((ba={},ba[""]=ia,ba),"",ha):ia;};}}}).call(this);},null); + __d("ES6Object",["ie8DontEnum"],function(a,b,c,d,e,f,g){var h=({}).hasOwnProperty,i={assign:function(j){var k=Array.prototype.slice.call(arguments,1);if(j==null)throw new TypeError('Object.assign target cannot be null or undefined');j=Object(j);for(var l=0;l>>0;for(var l=0;l9999?'+':''))+('00000'+Math.abs(i)).slice(0<=i&&i<=9999?-4:-6);return i+'-'+g(this.getUTCMonth()+1)+'-'+g(this.getUTCDate())+'T'+g(this.getUTCHours())+':'+g(this.getUTCMinutes())+':'+g(this.getUTCSeconds())+'.'+(this.getUTCMilliseconds()/1000).toFixed(3).slice(2,5)+'Z';}};e.exports=h;},null); + __d("ES6Number",[],function(a,b,c,d,e,f){var g={isFinite:function(h){return (typeof h=='number')&&isFinite(h);},isNaN:function(h){return (typeof h=='number')&&isNaN(h);}};e.exports=g;},null); + __d("ES",["ES5ArrayPrototype","ES5FunctionPrototype","ES5StringPrototype","ES5Array","ES5Object","ES5Date","JSON3","ES6Object","ES6ArrayPrototype","ES6DatePrototype","ES6Number"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q){var r=({}).toString,s={'JSON.stringify':m.stringify,'JSON.parse':m.parse},t={'Array.prototype':g,'Function.prototype':h,'String.prototype':i,Object:k,Array:j,Date:l},u={Object:n,'Array.prototype':o,'Date.prototype':p,Number:q};function v(x){for(var y in x){if(!x.hasOwnProperty(y))continue;var z=x[y],aa=y.split('.'),ba=aa.length==2?window[aa[0]][aa[1]]:window[y];for(var ca in z){if(!z.hasOwnProperty(ca))continue;var da=ba[ca];s[y+'.'+ca]=da&&/\{\s+\[native code\]\s\}/.test(da)?da:z[ca];}}}v(t);v(u);function w(x,y,z){var aa=Array.prototype.slice.call(arguments,3),ba=z?r.call(x).slice(8,-1)+'.prototype':x,ca=s[ba+'.'+y]||x[y];if(typeof ca==='function')return ca.apply(x,aa);}e.exports=w;},null); + var ES = require('ES'); + __d("JSSDKRuntimeConfig",[],{"locale":"zh_CN","rtl":false,"revision":"1425205"});__d("JSSDKConfig",[],{"bustCache":true,"tagCountLogRate":0.01,"errorHandling":{"rate":4},"usePluginPipe":true,"features":{"allow_non_canvas_app_events":false,"event_subscriptions_log":{"rate":0.01,"value":10000},"kill_fragment":true,"xfbml_profile_pic_server":true,"error_handling":{"rate":4},"e2e_ping_tracking":{"rate":1.0e-6},"xd_timeout":{"rate":4,"value":30000},"use_bundle":true,"launch_payment_dialog_via_pac":{"rate":100}},"api":{"mode":"warn","whitelist":["Canvas","Canvas.Prefetcher","Canvas.Prefetcher.addStaticResource","Canvas.Prefetcher.setCollectionMode","Canvas.getPageInfo","Canvas.hideFlashElement","Canvas.scrollTo","Canvas.setAutoGrow","Canvas.setDoneLoading","Canvas.setSize","Canvas.setUrlHandler","Canvas.showFlashElement","Canvas.startTimer","Canvas.stopTimer","Data","Data.process","Data.query","Data.query:wait","Data.waitOn","Data.waitOn:wait","Event","Event.subscribe","Event.unsubscribe","Music.flashCallback","Music.init","Music.send","Payment","Payment.cancelFlow","Payment.continueFlow","Payment.init","Payment.lockForProcessing","Payment.unlockForProcessing","Payment.parse","Payment.setSize","ThirdPartyProvider","ThirdPartyProvider.init","ThirdPartyProvider.sendData","UA","UA.nativeApp","XFBML","XFBML.RecommendationsBar","XFBML.RecommendationsBar.markRead","XFBML.parse","addFriend","api","getAccessToken","getAuthResponse","getLoginStatus","getUserID","init","login","logout","publish","share","ui","ui:subscribe","AppEvents","AppEvents.activateApp","AppEvents.logEvent","AppEvents.logPurchase","AppEvents.EventNames","AppEvents.ParameterNames"]},"initSitevars":{"enableMobileComments":1,"iframePermissions":{"read_stream":false,"manage_mailbox":false,"manage_friendlists":false,"read_mailbox":false,"publish_checkins":true,"status_update":true,"photo_upload":true,"video_upload":true,"sms":false,"create_event":true,"rsvp_event":true,"offline_access":true,"email":true,"xmpp_login":false,"create_note":true,"share_item":true,"export_stream":false,"publish_stream":true,"publish_likes":true,"ads_management":false,"contact_email":true,"access_private_data":false,"read_insights":false,"read_requests":false,"read_friendlists":true,"manage_pages":false,"physical_login":false,"manage_groups":false,"read_deals":false}}});__d("UrlMapConfig",[],{"www":"www.facebook.com","m":"m.facebook.com","connect":"connect.facebook.net","business":"business.facebook.com","api_https":"api.facebook.com","api_read_https":"api-read.facebook.com","graph_https":"graph.facebook.com","fbcdn_http":"static.ak.fbcdn.net","fbcdn_https":"fbstatic-a.akamaihd.net","cdn_http":"static.ak.facebook.com","cdn_https":"s-static.ak.facebook.com"});__d("JSSDKXDConfig",[],{"XdUrl":"\/connect\/xd_arbiter.php?version=41","XdBundleUrl":"\/connect\/xd_arbiter\/ZEbdHPQfV3x.js?version=41","Flash":{"path":"https:\/\/connect.facebook.net\/rsrc.php\/v1\/yR\/r\/ks_9ZXiQ0GL.swf"},"useCdn":true});__d("JSSDKCssConfig",[],{"rules":".fb_hidden{position:absolute;top:-10000px;z-index:10001}.fb_invisible{display:none}.fb_reset{background:none;border:0;border-spacing:0;color:#000;cursor:auto;direction:ltr;font-family:\"lucida grande\", tahoma, verdana, arial, sans-serif;font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:1;margin:0;overflow:visible;padding:0;text-align:left;text-decoration:none;text-indent:0;text-shadow:none;text-transform:none;visibility:visible;white-space:normal;word-spacing:normal}.fb_reset>div{overflow:hidden}.fb_link img{border:none}\n.fb_dialog{background:rgba(82, 82, 82, .7);position:absolute;top:-10000px;z-index:10001}.fb_reset .fb_dialog_legacy{overflow:visible}.fb_dialog_advanced{padding:10px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.fb_dialog_content{background:#fff;color:#333}.fb_dialog_close_icon{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yq\/r\/IE9JII6Z1Ys.png) no-repeat scroll 0 0 transparent;_background-image:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yL\/r\/s816eWC-2sl.gif);cursor:pointer;display:block;height:15px;position:absolute;right:18px;top:17px;width:15px}.fb_dialog_mobile .fb_dialog_close_icon{top:5px;left:5px;right:auto}.fb_dialog_padding{background-color:transparent;position:absolute;width:1px;z-index:-1}.fb_dialog_close_icon:hover{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yq\/r\/IE9JII6Z1Ys.png) no-repeat scroll 0 -15px transparent;_background-image:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yL\/r\/s816eWC-2sl.gif)}.fb_dialog_close_icon:active{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yq\/r\/IE9JII6Z1Ys.png) no-repeat scroll 0 -30px transparent;_background-image:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yL\/r\/s816eWC-2sl.gif)}.fb_dialog_loader{background-color:#f2f2f2;border:1px solid #606060;font-size:25px;padding:20px}.fb_dialog_top_left,.fb_dialog_top_right,.fb_dialog_bottom_left,.fb_dialog_bottom_right{height:10px;width:10px;overflow:hidden;position:absolute}.fb_dialog_top_left{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/ye\/r\/8YeTNIlTZjm.png) no-repeat 0 0;left:-10px;top:-10px}.fb_dialog_top_right{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/ye\/r\/8YeTNIlTZjm.png) no-repeat 0 -10px;right:-10px;top:-10px}.fb_dialog_bottom_left{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/ye\/r\/8YeTNIlTZjm.png) no-repeat 0 -20px;bottom:-10px;left:-10px}.fb_dialog_bottom_right{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/ye\/r\/8YeTNIlTZjm.png) no-repeat 0 -30px;right:-10px;bottom:-10px}.fb_dialog_vert_left,.fb_dialog_vert_right,.fb_dialog_horiz_top,.fb_dialog_horiz_bottom{position:absolute;background:#525252;filter:alpha(opacity=70);opacity:.7}.fb_dialog_vert_left,.fb_dialog_vert_right{width:10px;height:100\u0025}.fb_dialog_vert_left{margin-left:-10px}.fb_dialog_vert_right{right:0;margin-right:-10px}.fb_dialog_horiz_top,.fb_dialog_horiz_bottom{width:100\u0025;height:10px}.fb_dialog_horiz_top{margin-top:-10px}.fb_dialog_horiz_bottom{bottom:0;margin-bottom:-10px}.fb_dialog_iframe{line-height:0}.fb_dialog_content .dialog_title{background:#6d84b4;border:1px solid #3b5998;color:#fff;font-size:15px;font-weight:bold;margin:0}.fb_dialog_content .dialog_title>span{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/yd\/r\/Cou7n-nqK52.gif) no-repeat 5px 50\u0025;float:left;padding:5px 0 7px 26px}body.fb_hidden{-webkit-transform:none;height:100\u0025;margin:0;overflow:visible;position:absolute;top:-10000px;left:0;width:100\u0025}.fb_dialog.fb_dialog_mobile.loading{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/ya\/r\/3rhSv5V8j3o.gif) white no-repeat 50\u0025 50\u0025;min-height:100\u0025;min-width:100\u0025;overflow:hidden;position:absolute;top:0;z-index:10001}.fb_dialog.fb_dialog_mobile.loading.centered{max-height:590px;min-height:590px;max-width:500px;min-width:500px}#fb-root #fb_dialog_ipad_overlay{background:rgba(0, 0, 0, .45);position:absolute;left:0;top:0;width:100\u0025;min-height:100\u0025;z-index:10000}#fb-root #fb_dialog_ipad_overlay.hidden{display:none}.fb_dialog.fb_dialog_mobile.loading iframe{visibility:hidden}.fb_dialog_content .dialog_header{-webkit-box-shadow:white 0 1px 1px -1px inset;background:-webkit-gradient(linear, 0\u0025 0\u0025, 0\u0025 100\u0025, from(#738ABA), to(#2C4987));border-bottom:1px solid;border-color:#1d4088;color:#fff;font:14px Helvetica, sans-serif;font-weight:bold;text-overflow:ellipsis;text-shadow:rgba(0, 30, 84, .296875) 0 -1px 0;vertical-align:middle;white-space:nowrap}.fb_dialog_content .dialog_header table{-webkit-font-smoothing:subpixel-antialiased;height:43px;width:100\u0025}.fb_dialog_content .dialog_header td.header_left{font-size:13px;padding-left:5px;vertical-align:middle;width:60px}.fb_dialog_content .dialog_header td.header_right{font-size:13px;padding-right:5px;vertical-align:middle;width:60px}.fb_dialog_content .touchable_button{background:-webkit-gradient(linear, 0\u0025 0\u0025, 0\u0025 100\u0025, from(#4966A6), color-stop(.5, #355492), to(#2A4887));border:1px solid #29447e;-webkit-background-clip:padding-box;-webkit-border-radius:3px;-webkit-box-shadow:rgba(0, 0, 0, .117188) 0 1px 1px inset, rgba(255, 255, 255, .167969) 0 1px 0;display:inline-block;margin-top:3px;max-width:85px;line-height:18px;padding:4px 12px;position:relative}.fb_dialog_content .dialog_header .touchable_button input{border:none;background:none;color:#fff;font:12px Helvetica, sans-serif;font-weight:bold;margin:2px -12px;padding:2px 6px 3px 6px;text-shadow:rgba(0, 30, 84, .296875) 0 -1px 0}.fb_dialog_content .dialog_header .header_center{color:#fff;font-size:17px;font-weight:bold;line-height:18px;text-align:center;vertical-align:middle}.fb_dialog_content .dialog_content{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/y9\/r\/jKEcVPZFk-2.gif) no-repeat 50\u0025 50\u0025;border:1px solid #555;border-bottom:0;border-top:0;height:150px}.fb_dialog_content .dialog_footer{background:#f2f2f2;border:1px solid #555;border-top-color:#ccc;height:40px}#fb_dialog_loader_close{float:left}.fb_dialog.fb_dialog_mobile .fb_dialog_close_button{text-shadow:rgba(0, 30, 84, .296875) 0 -1px 0}.fb_dialog.fb_dialog_mobile .fb_dialog_close_icon{visibility:hidden}\n.fb_iframe_widget{display:inline-block;position:relative}.fb_iframe_widget span{display:inline-block;position:relative;text-align:justify}.fb_iframe_widget iframe{position:absolute}.fb_iframe_widget_lift{z-index:1}.fb_hide_iframes iframe{position:relative;left:-10000px}.fb_iframe_widget_loader{position:relative;display:inline-block}.fb_iframe_widget_fluid{display:inline}.fb_iframe_widget_fluid span{width:100\u0025}.fb_iframe_widget_loader iframe{min-height:32px;z-index:2;zoom:1}.fb_iframe_widget_loader .FB_Loader{background:url(http:\/\/static.ak.fbcdn.net\/rsrc.php\/v2\/y9\/r\/jKEcVPZFk-2.gif) no-repeat;height:32px;width:32px;margin-left:-16px;position:absolute;left:50\u0025;z-index:4}\n.fbpluginrecommendationsbarleft,.fbpluginrecommendationsbarright{position:fixed !important;bottom:0;z-index:999}.fbpluginrecommendationsbarleft{left:10px}.fbpluginrecommendationsbarright{right:10px}","components":["css:fb.css.base","css:fb.css.dialog","css:fb.css.iframewidget","css:fb.css.plugin.recommendationsbar"]});__d("ApiClientConfig",[],{"FlashRequest":{"swfUrl":"https:\/\/connect.facebook.net\/rsrc.php\/v1\/yW\/r\/PvklbuW2Ycn.swf"}});__d("JSSDKCanvasPrefetcherConfig",[],{"blacklist":[144959615576466],"sampleRate":500});__d("JSSDKPluginPipeConfig",[],{"threshold":0,"enabledApps":{"209753825810663":1,"187288694643718":1}}); + __d("QueryString",[],function(a,b,c,d,e,f){function g(k){var l=[];ES(ES('Object','keys',false,k).sort(),'forEach',true,function(m){var n=k[m];if(typeof n==='undefined')return;if(n===null){l.push(m);return;}l.push(encodeURIComponent(m)+'='+encodeURIComponent(n));});return l.join('&');}function h(k,l){var m={};if(k==='')return m;var n=k.split('&');for(var o=0;oh);},ie64:function(){return x.ie()&&r;},firefox:function(){return w()||i;},opera:function(){return w()||j;},webkit:function(){return w()||k;},safari:function(){return x.webkit();},chrome:function(){return w()||l;},windows:function(){return w()||o;},osx:function(){return w()||n;},linux:function(){return w()||p;},iphone:function(){return w()||s;},mobile:function(){return w()||(s||t||q||v);},nativeApp:function(){return w()||u;},android:function(){return w()||q;},ipad:function(){return w()||t;}};e.exports=x;},null); + __d("hasNamePropertyBug",["guid","UserAgent_DEPRECATED"],function(a,b,c,d,e,f,g,h){var i=h.ie()?undefined:false;function j(){var l=document.createElement("form"),m=l.appendChild(document.createElement("input"));m.name=g();i=m!==l.elements[m.name];l=m=null;return i;}function k(){return typeof i==='undefined'?j():i;}e.exports=k;},null); + __d("wrapFunction",[],function(a,b,c,d,e,f){var g={};function h(i,j,k){j=j||'default';return function(){var l=j in g?g[j](i,k):i;return l.apply(this,arguments);};}h.setWrapper=function(i,j){j=j||'default';g[j]=i;};e.exports=h;},null); + __d("DOMEventListener",["wrapFunction"],function(a,b,c,d,e,f,g){var h,i;if(window.addEventListener){h=function(k,l,m){m.wrapper=g(m,'entry','DOMEventListener.add '+l);k.addEventListener(l,m.wrapper,false);};i=function(k,l,m){k.removeEventListener(l,m.wrapper,false);};}else if(window.attachEvent){h=function(k,l,m){m.wrapper=g(m,'entry','DOMEventListener.add '+l);k.attachEvent('on'+l,m.wrapper);};i=function(k,l,m){k.detachEvent('on'+l,m.wrapper);};}else i=h=function(){};var j={add:function(k,l,m){h(k,l,m);return {remove:function(){i(k,l,m);k=null;}};},remove:i};e.exports=j;},null); + __d("sdk.createIframe",["guid","hasNamePropertyBug","DOMEventListener"],function(a,b,c,d,e,f,g,h,i){function j(k){k=ES('Object','assign',false,{},k);var l,m=k.name||g(),n=k.root,o=k.style||{border:'none'},p=k.url,q=k.onload,r=k.onerror;if(h()){l=document.createElement('');j.root.innerHTML=('');k=true;setTimeout(function(){j.root.innerHTML=o;j.root.firstChild.src=j.url;j.onInsert&&j.onInsert(j.root.firstChild);},0);}else{var p=document.createElement('iframe');p.id=j.id;p.name=j.name;p.onload=m;p.scrolling='no';p.style.border='none';p.style.overflow='hidden';if(j.title)p.title=j.title;if(j.className)p.className=j.className;if(j.height!==undefined)p.style.height=j.height+'px';if(j.width!==undefined)if(j.width=='100%'){p.style.width=j.width;}else p.style.width=j.width+'px';j.root.appendChild(p);k=true;p.src=j.url;j.onInsert&&j.onInsert(p);}}e.exports=i;},null); + __d("Miny",[],function(a,b,c,d,e,f){var g='Miny1',h={encode:[],decode:{}},i='wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'.split('');function j(n){for(var o=h.encode.length;o2000)if(p.payload&&typeof p.payload==='string'){var t=j.encode(p.payload);if(t&&t.length>>18),g.charCodeAt((l>>>12)&63),g.charCodeAt((l>>>6)&63),g.charCodeAt(l&63));}var i='>___?456789:;<=_______'+'\0\1\2\3\4\5\6\7\b\t\n\13\f\r\16\17\20\21\22\23\24\25\26\27\30\31'+'______\32\33\34\35\36\37 !"#$%&\'()*+,-./0123';function j(l){l=(i.charCodeAt(l.charCodeAt(0)-43)<<18)|(i.charCodeAt(l.charCodeAt(1)-43)<<12)|(i.charCodeAt(l.charCodeAt(2)-43)<<6)|i.charCodeAt(l.charCodeAt(3)-43);return String.fromCharCode(l>>>16,(l>>>8)&255,l&255);}var k={encode:function(l){l=unescape(encodeURI(l));var m=(l.length+2)%3;l=(l+'\0\0'.slice(m)).replace(/[\s\S]{3}/g,h);return l.slice(0,l.length+m-2)+'=='.slice(m);},decode:function(l){l=l.replace(/[^A-Za-z0-9+\/]/g,'');var m=(l.length+3)&3;l=(l+'AAA'.slice(m)).replace(/..../g,j);l=l.slice(0,l.length+m-3);try{return decodeURIComponent(escape(l));}catch(n){throw new Error('Not valid UTF-8');}},encodeObject:function(l){return k.encode(ES('JSON','stringify',false,l));},decodeObject:function(l){return ES('JSON','parse',false,k.decode(l));},encodeNums:function(l){return String.fromCharCode.apply(String,ES(l,'map',true,function(m){return g.charCodeAt((m|-(m>63))&-(m>0)&63);}));}};e.exports=k;},null); + __d("sdk.SignedRequest",["Base64"],function(a,b,c,d,e,f,g){function h(j){if(!j)return null;var k=j.split('.',2)[1].replace(/\-/g,'+').replace(/\_/g,'/');return g.decodeObject(k);}var i={parse:h};e.exports=i;},null); + __d("URIRFC3986",[],function(a,b,c,d,e,f){var g=new RegExp('^'+'([^:/?#]+:)?'+'(//'+'([^\\\\/?#@]*@)?'+'('+'\\[[A-Fa-f0-9:.]+\\]|'+'[^\\/?#:]*'+')'+'(:[0-9]*)?'+')?'+'([^?#]*)'+'(\\?[^#]*)?'+'(#.*)?'),h={parse:function(i){if(ES(i,'trim',true)==='')return null;var j=i.match(g),k={};k.uri=j[0]?j[0]:null;k.scheme=j[1]?j[1].substr(0,j[1].length-1):null;k.authority=j[2]?j[2].substr(2):null;k.userinfo=j[3]?j[3].substr(0,j[3].length-1):null;k.host=j[2]?j[4]:null;k.port=j[5]?(j[5].substr(1)?parseInt(j[5].substr(1),10):null):null;k.path=j[6]?j[6]:null;k.query=j[7]?j[7].substr(1):null;k.fragment=j[8]?j[8].substr(1):null;k.isGenericURI=k.authority===null&&!!k.scheme;return k;}};e.exports=h;},null); + __d("createObjectFrom",[],function(a,b,c,d,e,f){function g(h,i){var j={},k=ES('Array','isArray',false,i);if(typeof i=='undefined')i=true;for(var l=h.length;l--;)j[h[l]]=k?i[l]:i;return j;}e.exports=g;},null); + __d("URISchemes",["createObjectFrom"],function(a,b,c,d,e,f,g){var h=g(['fb','fbcf','fbconnect','fb-messenger','fbrpc','file','ftp','http','https','mailto','ms-app','itms','itms-apps','itms-services','market','svn+ssh','fbstaging','tel','sms']),i={isAllowed:function(j){if(!j)return true;return h.hasOwnProperty(j.toLowerCase());}};e.exports=i;},null); + __d("copyProperties",[],function(a,b,c,d,e,f){function g(h,i,j,k,l,m,n){h=h||{};var o=[i,j,k,l,m],p=0,q;while(o[p]){q=o[p++];for(var r in q)h[r]=q[r];if(q.hasOwnProperty&&q.hasOwnProperty('toString')&&(typeof q.toString!='undefined')&&(h.toString!==q.toString))h.toString=q.toString;}return h;}e.exports=g;},null); + __d("eprintf",[],function(a,b,c,d,e,f){var g=function(h){var i=ES(Array.prototype.slice.call(arguments),'map',true,function(l){return String(l);}),j=h.split('%s').length-1;if(j!==i.length-1)return g('eprintf args number mismatch: %s',ES('JSON','stringify',false,i));var k=1;return h.replace(/%s/g,function(l){return String(i[k++]);});};e.exports=g;},null); + __d("ex",["eprintf"],function(a,b,c,d,e,f,g){var h=function(){var i=Array.prototype.slice.call(arguments,0);i=ES(i,'map',true,function(j){return String(j);});if(i[0].split('%s').length!==i.length)return h('ex args number mismatch: %s',ES('JSON','stringify',false,i));return h._prefix+ES('JSON','stringify',false,i)+h._suffix;};h._prefix='';e.exports=h;},null); + __d("invariant",[],function(a,b,c,d,e,f){"use strict";var g=function(h,i,j,k,l,m,n,o){if(!h){var p;if(i===undefined){p=new Error('Minified exception occurred; use the non-minified dev environment '+'for the full error message and additional helpful warnings.');}else{var q=[j,k,l,m,n,o],r=0;p=new Error('Invariant Violation: '+i.replace(/%s/g,function(){return q[r++];}));}p.framesToPop=1;throw p;}};e.exports=g;},null); + __d("URIBase",["URIRFC3986","URISchemes","copyProperties","ex","invariant"],function(a,b,c,d,e,f,g,h,i,j,k){var l=new RegExp('[\\x00-\\x2c\\x2f\\x3b-\\x40\\x5c\\x5e\\x60\\x7b-\\x7f'+'\\uFDD0-\\uFDEF\\uFFF0-\\uFFFF'+'\\u2047\\u2048\\uFE56\\uFE5F\\uFF03\\uFF0F\\uFF1F]'),m=new RegExp('^(?:[^/]*:|'+'[\\x00-\\x1f]*/[\\x00-\\x1f]*/)');function n(p,q,r,s){if(!q)return true;if(q instanceof o){p.setProtocol(q.getProtocol());p.setDomain(q.getDomain());p.setPort(q.getPort());p.setPath(q.getPath());p.setQueryData(s.deserialize(s.serialize(q.getQueryData())));p.setFragment(q.getFragment());p.setForceFragmentSeparator(q.getForceFragmentSeparator());return true;}q=ES(q.toString(),'trim',true);var t=g.parse(q)||{};if(!r&&!h.isAllowed(t.scheme))return false;p.setProtocol(t.scheme||'');if(!r&&l.test(t.host))return false;p.setDomain(t.host||'');p.setPort(t.port||'');p.setPath(t.path||'');if(r){p.setQueryData(s.deserialize(t.query)||{});}else try{p.setQueryData(s.deserialize(t.query)||{});}catch(u){return false;}p.setFragment(t.fragment||'');if(t.fragment==='')p.setForceFragmentSeparator(true);if(t.userinfo!==null)if(r){throw new Error(j('URI.parse: invalid URI (userinfo is not allowed in a URI): %s',p.toString()));}else return false;if(!p.getDomain()&&ES(p.getPath(),'indexOf',true,'\\')!==-1)if(r){throw new Error(j('URI.parse: invalid URI (no domain but multiple back-slashes): %s',p.toString()));}else return false;if(!p.getProtocol()&&m.test(q))if(r){throw new Error(j('URI.parse: invalid URI (unsafe protocol-relative URLs): %s',p.toString()));}else return false;return true;}function o(p,q){"use strict";k(q);this.$URIBase0=q;this.$URIBase1='';this.$URIBase2='';this.$URIBase3='';this.$URIBase4='';this.$URIBase5='';this.$URIBase6={};this.$URIBase7=false;n(this,p,true,q);}o.prototype.setProtocol=function(p){"use strict";k(h.isAllowed(p));this.$URIBase1=p;return this;};o.prototype.getProtocol=function(p){"use strict";return this.$URIBase1;};o.prototype.setSecure=function(p){"use strict";return this.setProtocol(p?'https':'http');};o.prototype.isSecure=function(){"use strict";return this.getProtocol()==='https';};o.prototype.setDomain=function(p){"use strict";if(l.test(p))throw new Error(j('URI.setDomain: unsafe domain specified: %s for url %s',p,this.toString()));this.$URIBase2=p;return this;};o.prototype.getDomain=function(){"use strict";return this.$URIBase2;};o.prototype.setPort=function(p){"use strict";this.$URIBase3=p;return this;};o.prototype.getPort=function(){"use strict";return this.$URIBase3;};o.prototype.setPath=function(p){"use strict";this.$URIBase4=p;return this;};o.prototype.getPath=function(){"use strict";return this.$URIBase4;};o.prototype.addQueryData=function(p,q){"use strict";if(Object.prototype.toString.call(p)==='[object Object]'){i(this.$URIBase6,p);}else this.$URIBase6[p]=q;return this;};o.prototype.setQueryData=function(p){"use strict";this.$URIBase6=p;return this;};o.prototype.getQueryData=function(){"use strict";return this.$URIBase6;};o.prototype.removeQueryData=function(p){"use strict";if(!ES('Array','isArray',false,p))p=[p];for(var q=0,r=p.length;q0||this.getFragment());};o.prototype.toString=function(){"use strict";var p='';if(this.$URIBase1)p+=this.$URIBase1+'://';if(this.$URIBase2)p+=this.$URIBase2;if(this.$URIBase3)p+=':'+this.$URIBase3;if(this.$URIBase4){p+=this.$URIBase4;}else if(p)p+='/';var q=this.$URIBase0.serialize(this.$URIBase6);if(q)p+='?'+q;if(this.$URIBase5){p+='#'+this.$URIBase5;}else if(this.$URIBase7)p+='#';return p;};o.prototype.getOrigin=function(){"use strict";return this.$URIBase1+'://'+this.$URIBase2+(this.$URIBase3?':'+this.$URIBase3:'');};o.isValidURI=function(p,q){return n(new o(null,q),p,false,q);};e.exports=o;},null); + __d("sdk.URI",["Assert","QueryString","URIBase"],function(a,b,c,d,e,f,g,h,i){var j=/\.facebook\.com$/,k={serialize:function(o){return o?h.encode(o):'';},deserialize:function(o){return o?h.decode(o):{};}};for(var l in i)if(i.hasOwnProperty(l))n[l]=i[l];var m=i===null?null:i.prototype;n.prototype=ES('Object','create',false,m);n.prototype.constructor=n;n.__superConstructor__=i;function n(o){"use strict";g.isString(o,'The passed argument was of invalid type.');if(!(this instanceof n))return new n(o);i.call(this,o,k);}n.prototype.isFacebookURI=function(){"use strict";return j.test(this.getDomain());};n.prototype.valueOf=function(){"use strict";return this.toString();};e.exports=n;},null); + __d("sdk.Event",[],function(a,b,c,d,e,f){var g={SUBSCRIBE:'event.subscribe',UNSUBSCRIBE:'event.unsubscribe',subscribers:function(){if(!this._subscribersMap)this._subscribersMap={};return this._subscribersMap;},subscribe:function(h,i){var j=this.subscribers();if(!j[h]){j[h]=[i];}else if(ES(j[h],'indexOf',true,i)==-1)j[h].push(i);if(h!=this.SUBSCRIBE&&h!=this.UNSUBSCRIBE)this.fire(this.SUBSCRIBE,h,j[h]);},unsubscribe:function(h,i){var j=this.subscribers()[h];if(j)ES(j,'forEach',true,function(k,l){if(k==i)j.splice(l,1);});if(h!=this.SUBSCRIBE&&h!=this.UNSUBSCRIBE)this.fire(this.UNSUBSCRIBE,h,j);},monitor:function(h,i){if(!i()){var j=this,k=function(){if(i.apply(i,arguments))j.unsubscribe(h,k);};this.subscribe(h,k);}},clear:function(h){delete this.subscribers()[h];},fire:function(h){var i=Array.prototype.slice.call(arguments,1),j=this.subscribers()[h];if(j)ES(j,'forEach',true,function(k){if(k)k.apply(this,i);});}};e.exports=g;},null); + __d("Queue",["copyProperties"],function(a,b,c,d,e,f,g){var h={};function i(j){"use strict";this._opts=g({interval:0,processor:null},j);this._queue=[];this._stopped=true;}i.prototype._dispatch=function(j){"use strict";if(this._stopped||this._queue.length===0)return;if(!this._opts.processor){this._stopped=true;throw new Error('No processor available');}if(this._opts.interval){this._opts.processor.call(this,this._queue.shift());this._timeout=setTimeout(ES(this._dispatch,'bind',true,this),this._opts.interval);}else while(this._queue.length)this._opts.processor.call(this,this._queue.shift());};i.prototype.enqueue=function(j){"use strict";if(this._opts.processor&&!this._stopped){this._opts.processor.call(this,j);}else this._queue.push(j);return this;};i.prototype.start=function(j){"use strict";if(j)this._opts.processor=j;this._stopped=false;this._dispatch();return this;};i.prototype.isStarted=function(){"use strict";return !this._stopped;};i.prototype.dispatch=function(){"use strict";this._dispatch(true);};i.prototype.stop=function(j){"use strict";this._stopped=true;if(j)clearTimeout(this._timeout);return this;};i.prototype.merge=function(j,k){"use strict";this._queue[k?'unshift':'push'].apply(this._queue,j._queue);j._queue=[];this._dispatch();return this;};i.prototype.getLength=function(){"use strict";return this._queue.length;};i.get=function(j,k){"use strict";var l;if(j in h){l=h[j];}else l=h[j]=new i(k);return l;};i.exists=function(j){"use strict";return j in h;};i.remove=function(j){"use strict";return delete h[j];};e.exports=i;},null); + __d("JSONRPC",["Log"],function(a,b,c,d,e,f,g){function h(i){"use strict";this.$JSONRPC0=0;this.$JSONRPC1={};this.remote=ES(function(j){this.$JSONRPC2=j;return this.remote;},'bind',true,this);this.local={};this.$JSONRPC3=i;}h.prototype.stub=function(i){"use strict";this.remote[i]=ES(function(){var j=Array.prototype.slice.call(arguments,0),k={jsonrpc:'2.0',method:i};if(typeof j[j.length-1]=='function'){k.id=++this.$JSONRPC0;this.$JSONRPC1[k.id]=j.pop();}k.params=j;this.$JSONRPC3(ES('JSON','stringify',false,k),this.$JSONRPC2||{method:i});},'bind',true,this);};h.prototype.read=function(i,j){"use strict";var k=ES('JSON','parse',false,i),l=k.id;if(!k.method){if(!this.$JSONRPC1[l]){g.warn('Could not find callback %s',l);return;}var m=this.$JSONRPC1[l];delete this.$JSONRPC1[l];delete k.id;delete k.jsonrpc;m(k);return;}var n=this,o=this.local[k.method],p;if(l){p=function(s,t){var u={jsonrpc:'2.0',id:l};u[s]=t;setTimeout(function(){n.$JSONRPC3(ES('JSON','stringify',false,u),j);},0);};}else p=function(){};if(!o){g.error('Method "%s" has not been defined',k.method);p('error',{code:-32601,message:'Method not found',data:k.method});return;}k.params.push(ES(p,'bind',true,null,'result'));k.params.push(ES(p,'bind',true,null,'error'));try{var r=o.apply(j||null,k.params);if(typeof r!=='undefined')p('result',r);}catch(q){g.error('Invokation of RPC method %s resulted in the error: %s',k.method,q.message);p('error',{code:-32603,message:'Internal error',data:q.message});}};e.exports=h;},null); + __d("sdk.RPC",["Assert","JSONRPC","Queue"],function(a,b,c,d,e,f,g,h,i){var j=new i(),k=new h(function(m){j.enqueue(m);}),l={local:k.local,remote:k.remote,stub:ES(k.stub,'bind',true,k),setInQueue:function(m){g.isInstanceOf(i,m);m.start(function(n){k.read(n);});},getOutQueue:function(){return j;}};e.exports=l;},null); + __d("sdk.Scribe",["QueryString","sdk.Runtime","UrlMap"],function(a,b,c,d,e,f,g,h,i){function j(l,m){if(typeof m.extra=='object')m.extra.revision=h.getRevision();(new Image()).src=g.appendToUrl(i.resolve('www',true)+'/common/scribe_endpoint.php',{c:l,m:ES('JSON','stringify',false,m)});}var k={log:j};e.exports=k;},null); + __d("emptyFunction",["copyProperties"],function(a,b,c,d,e,f,g){function h(j){return function(){return j;};}function i(){}g(i,{thatReturns:h,thatReturnsFalse:h(false),thatReturnsTrue:h(true),thatReturnsNull:h(null),thatReturnsThis:function(){return this;},thatReturnsArgument:function(j){return j;}});e.exports=i;},null); + __d("htmlSpecialChars",[],function(a,b,c,d,e,f){var g=/&/g,h=//g,j=/"/g,k=/'/g;function l(m){if(typeof m=='undefined'||m===null||!m.toString)return '';if(m===false){return '0';}else if(m===true)return '1';return m.toString().replace(g,'&').replace(j,'"').replace(k,''').replace(h,'<').replace(i,'>');}e.exports=l;},null); + __d("Flash",["DOMEventListener","DOMWrapper","QueryString","UserAgent_DEPRECATED","copyProperties","guid","htmlSpecialChars"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n={},o,p=h.getWindow().document;function q(v){var w=p.getElementById(v);if(w)w.parentNode.removeChild(w);delete n[v];}function r(){for(var v in n)if(n.hasOwnProperty(v))q(v);}function s(v){return v.replace(/\d+/g,function(w){return '000'.substring(w.length)+w;});}function t(v){if(!o){if(j.ie()>=9)g.add(window,'unload',r);o=true;}n[v]=v;}var u={embed:function(v,w,x,y){var z=l();v=m(v).replace(/&/g,'&');x=k({allowscriptaccess:'always',flashvars:y,movie:v},x||{});if(typeof x.flashvars=='object')x.flashvars=i.encode(x.flashvars);var aa=[];for(var ba in x)if(x.hasOwnProperty(ba)&&x[ba])aa.push('');var ca=w.appendChild(p.createElement('span')),da=''+aa.join('')+'';ca.innerHTML=da;var ea=ca.firstChild;t(z);return ea;},remove:q,getVersion:function(){var v='Shockwave Flash',w='application/x-shockwave-flash',x='ShockwaveFlash.ShockwaveFlash',y;if(navigator.plugins&&typeof navigator.plugins[v]=='object'){var z=navigator.plugins[v].description;if(z&&navigator.mimeTypes&&navigator.mimeTypes[w]&&navigator.mimeTypes[w].enabledPlugin)y=z.match(/\d+/g);}if(!y)try{y=(new ActiveXObject(x)).GetVariable('$version').match(/(\d+),(\d+),(\d+),(\d+)/);y=Array.prototype.slice.call(y,1);}catch(aa){}return y;},checkMinVersion:function(v){var w=u.getVersion();if(!w)return false;return s(w.join('.'))>=s(v);},isAvailable:function(){return !!u.getVersion();}};e.exports=u;},null); + __d("XDM",["DOMEventListener","DOMWrapper","emptyFunction","Flash","GlobalCallback","guid","Log","UserAgent_DEPRECATED","wrapFunction"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={},q={transports:[]},r=h.getWindow();function s(u){var v={},w=u.length,x=q.transports;while(w--)v[u[w]]=1;w=x.length;while(w--){var y=x[w],z=p[y];if(!v[y]&&z.isAvailable())return y;}}var t={register:function(u,v){m.debug('Registering %s as XDM provider',u);q.transports.push(u);p[u]=v;},create:function(u){if(!u.whenReady&&!u.onMessage){m.error('An instance without whenReady or onMessage makes no sense');throw new Error('An instance without whenReady or '+'onMessage makes no sense');}if(!u.channel){m.warn('Missing channel name, selecting at random');u.channel=l();}if(!u.whenReady)u.whenReady=i;if(!u.onMessage)u.onMessage=i;var v=u.transport||s(u.blacklist||[]),w=p[v];if(w&&w.isAvailable()){m.debug('%s is available',v);w.init(u);return v;}}};t.register('flash',(function(){var u=false,v,w=false,x=15000,y;return {isAvailable:function(){return j.checkMinVersion('8.0.24');},init:function(z){m.debug('init flash: '+z.channel);var aa={send:function(da,ea,fa,ga){m.debug('sending to: %s (%s)',ea,ga);v.postMessage(da,ea,ga);}};if(u){z.whenReady(aa);return;}var ba=z.root.appendChild(r.document.createElement('div')),ca=k.create(function(){k.remove(ca);clearTimeout(y);m.info('xdm.swf called the callback');var da=k.create(function(ea,fa){ea=decodeURIComponent(ea);fa=decodeURIComponent(fa);m.debug('received message %s from %s',ea,fa);z.onMessage(ea,fa);},'xdm.swf:onMessage');v.init(z.channel,da);z.whenReady(aa);},'xdm.swf:load');v=j.embed(z.flashUrl,ba,null,{protocol:location.protocol.replace(':',''),host:location.host,callback:ca,log:w});y=setTimeout(function(){m.warn('The Flash component did not load within %s ms - '+'verify that the container is not set to hidden or invisible '+'using CSS as this will cause some browsers to not load '+'the components',x);},x);u=true;}};})());t.register('postmessage',(function(){var u=false;return {isAvailable:function(){return !!r.postMessage;},init:function(v){m.debug('init postMessage: '+v.channel);var w='_FB_'+v.channel,x={send:function(y,z,aa,ba){if(r===aa){m.error('Invalid windowref, equal to window (self)');throw new Error();}m.debug('sending to: %s (%s)',z,ba);var ca=function(){aa.postMessage('_FB_'+ba+y,z);};if(n.ie()==8||n.ieCompatibilityMode()){setTimeout(ca,0);}else ca();}};if(u){v.whenReady(x);return;}g.add(r,'message',o(function(event){var y=event.data,z=event.origin||'native';if(!/^(https?:\/\/|native$)/.test(z)){m.debug('Received message from invalid origin type: %s',z);return;}if(typeof y!='string'){m.warn('Received message of type %s from %s, expected a string',typeof y,z);return;}m.debug('received message %s from %s',y,z);if(y.substring(0,w.length)==w)y=y.substring(w.length);v.onMessage(y,z);},'entry','onMessage'));v.whenReady(x);u=true;}};})());e.exports=t;},null); + __d("isFacebookURI",[],function(a,b,c,d,e,f){var g=null,h=['http','https'];function i(j){if(!g)g=new RegExp('(^|\\.)facebook\\.com$','i');if(j.isEmpty())return false;if(!j.getDomain()&&!j.getProtocol())return true;return (ES(h,'indexOf',true,j.getProtocol())!==-1&&g.test(j.getDomain()));}e.exports=i;},null); + __d("sdk.XD",["sdk.Content","sdk.Event","Log","QueryString","Queue","sdk.RPC","sdk.Runtime","sdk.Scribe","sdk.URI","UrlMap","JSSDKXDConfig","XDM","isFacebookURI","sdk.createIframe","sdk.feature","guid"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v){var w=new k(),x=new k(),y=new k(),z,aa,ba=v(),ca=q.useCdn?'cdn':'www',da=u('use_bundle')?q.XdBundleUrl:q.XdUrl,ea=p.resolve(ca,false)+da,fa=p.resolve(ca,true)+da,ga=v(),ha=location.protocol+'//'+location.host,ia,ja=false,ka='Facebook Cross Domain Communication Frame',la={},ma=new k();l.setInQueue(ma);function na(ta){i.info('Remote XD can talk to facebook.com (%s)',ta);m.setEnvironment(ta==='canvas'?m.ENVIRONMENTS.CANVAS:m.ENVIRONMENTS.PAGETAB);}function oa(ta,ua){if(!ua){i.error('No senderOrigin');throw new Error();}var va=/^https?/.exec(ua)[0];switch(ta.xd_action){case 'proxy_ready':var wa,xa;if(va=='https'){wa=y;xa=aa;}else{wa=x;xa=z;}if(ta.registered){na(ta.registered);w=wa.merge(w);}i.info('Proxy ready, starting queue %s containing %s messages',va+'ProxyQueue',wa.getLength());wa.start(function(za){ia.send(typeof za==='string'?za:j.encode(za),ua,xa.contentWindow,ga+'_'+va);});break;case 'plugin_ready':i.info('Plugin %s ready, protocol: %s',ta.name,va);la[ta.name]={protocol:va};if(k.exists(ta.name)){var ya=k.get(ta.name);i.debug('Enqueuing %s messages for %s in %s',ya.getLength(),ta.name,va+'ProxyQueue');(va=='https'?y:x).merge(ya);}break;}if(ta.data)pa(ta.data,ua);}function pa(ta,ua){if(ua&&ua!=='native'&&!s(o(ua)))return;if(typeof ta=='string'){if(/^FB_RPC:/.test(ta)){ma.enqueue(ta.substring(7));return;}if(ta.substring(0,1)=='{'){try{ta=ES('JSON','parse',false,ta);}catch(va){i.warn('Failed to decode %s as JSON',ta);return;}}else ta=j.decode(ta);}if(!ua)if(ta.xd_sig==ba)ua=ta.xd_origin;if(ta.xd_action){oa(ta,ua);return;}if(ta.access_token)m.setSecure(/^https/.test(ha));if(ta.cb){var wa=sa._callbacks[ta.cb];if(!sa._forever[ta.cb])delete sa._callbacks[ta.cb];if(wa)wa(ta);}}function qa(ta,ua){if(ta=='facebook'){ua.relation='parent.parent';w.enqueue(ua);}else{ua.relation='parent.frames["'+ta+'"]';var va=la[ta];if(va){i.debug('Enqueuing message for plugin %s in %s',ta,va.protocol+'ProxyQueue');(va.protocol=='https'?y:x).enqueue(ua);}else{i.debug('Buffering message for plugin %s',ta);k.get(ta).enqueue(ua);}}}l.getOutQueue().start(function(ta){qa('facebook','FB_RPC:'+ta);});function ra(ta){if(ja)return;var ua=g.appendHidden(document.createElement('div')),va=r.create({blacklist:null,root:ua,channel:ga,flashUrl:q.Flash.path,whenReady:function(wa){ia=wa;var xa={channel:ga,origin:location.protocol+'//'+location.host,transport:va,xd_name:ta},ya='#'+j.encode(xa);if(m.getSecure()!==true)z=t({url:ea+ya,name:'fb_xdm_frame_http',id:'fb_xdm_frame_http',root:ua,'aria-hidden':true,title:ka,tabindex:-1});aa=t({url:fa+ya,name:'fb_xdm_frame_https',id:'fb_xdm_frame_https',root:ua,'aria-hidden':true,title:ka,tabindex:-1});},onMessage:pa});if(!va)n.log('jssdk_error',{appId:m.getClientID(),error:'XD_TRANSPORT',extra:{message:'Failed to create a valid transport'}});ja=true;}var sa={rpc:l,_callbacks:{},_forever:{},_channel:ga,_origin:ha,onMessage:pa,recv:pa,init:ra,sendToFacebook:qa,inform:function(ta,ua,va,wa){qa('facebook',{method:ta,params:ES('JSON','stringify',false,ua||{}),behavior:wa||'p',relation:va});},handler:function(ta,ua,va,wa){var xa='#'+j.encode({cb:this.registerCallback(ta,va,wa),origin:ha+'/'+ga,domain:location.hostname,relation:ua||'opener'});return (location.protocol=='https:'?fa:ea)+xa;},registerCallback:function(ta,ua,va){va=va||v();if(ua)sa._forever[va]=true;sa._callbacks[va]=ta;return va;}};h.subscribe('init:post',function(ta){ra(ta.xdProxyName);var ua=u('xd_timeout');if(ua)setTimeout(function(){var va=aa&&(!!z==x.isStarted()&&!!aa==y.isStarted());if(!va)n.log('jssdk_error',{appId:m.getClientID(),error:'XD_INITIALIZATION',extra:{message:'Failed to initialize in '+ua+'ms'}});},ua);});e.exports=sa;},null); + __d("sdk.Auth",["sdk.Cookie","sdk.createIframe","DOMWrapper","sdk.feature","sdk.getContextType","guid","sdk.Impressions","Log","ObservableMixin","sdk.Runtime","sdk.SignedRequest","UrlMap","sdk.URI","sdk.XD"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t){var u,v,w=new o();function x(da,ea){var fa=p.getUserID(),ga='';if(da)if(da.userID){ga=da.userID;}else if(da.signedRequest){var ha=q.parse(da.signedRequest);if(ha&&ha.user_id)ga=ha.user_id;}var ia=p.getLoginStatus(),ja=(ia==='unknown'&&da)||(p.getUseCookie()&&p.getCookieUserID()!==ga),ka=fa&&!da,la=da&&fa&&fa!=ga,ma=da!=u,na=ea!=(ia||'unknown');p.setLoginStatus(ea);p.setAccessToken(da&&da.accessToken||null);p.setUserID(ga);u=da;var oa={authResponse:da,status:ea};if(ka||la)w.inform('logout',oa);if(ja||la)w.inform('login',oa);if(ma)w.inform('authresponse.change',oa);if(na)w.inform('status.change',oa);return oa;}function y(){return u;}function z(da,ea,fa){return function(ga){var ha;if(ga&&ga.access_token){var ia=q.parse(ga.signed_request);ea={accessToken:ga.access_token,userID:ia.user_id,expiresIn:parseInt(ga.expires_in,10),signedRequest:ga.signed_request};if(ga.granted_scopes)ea.grantedScopes=ga.granted_scopes;if(p.getUseCookie()){var ja=ea.expiresIn===0?0:ES('Date','now',false)+ea.expiresIn*1000,ka=g.getDomain();if(!ka&&ga.base_domain)g.setDomain('.'+ga.base_domain);g.setSignedRequestCookie(ga.signed_request,ja);}ha='connected';x(ea,ha);}else if(fa==='logout'||fa==='login_status'){if(ga.error&&ga.error==='not_authorized'){ha='not_authorized';}else ha='unknown';x(null,ha);if(p.getUseCookie())g.clearSignedRequestCookie();}if(ga&&ga.https==1)p.setSecure(true);if(da)da({authResponse:ea,status:p.getLoginStatus()});return ea;};}function aa(da){var ea,fa=ES('Date','now',false);if(v){clearTimeout(v);v=null;}var ga=z(da,u,'login_status'),ha=s(r.resolve('www',true)+'/connect/ping').setQueryData({client_id:p.getClientID(),response_type:'token,signed_request,code',domain:location.hostname,origin:k(),redirect_uri:t.handler(function(ia){if(j('e2e_ping_tracking',true)){var ja={init:fa,close:ES('Date','now',false),method:'ping'};n.debug('e2e: %s',ES('JSON','stringify',false,ja));m.log(114,{payload:ja});}ea.parentNode.removeChild(ea);if(ga(ia))v=setTimeout(function(){aa(function(){});},1200000);},'parent'),sdk:'joey',kid_directed_site:p.getKidDirectedSite()});ea=h({root:i.getRoot(),name:l(),url:ha.toString(),style:{display:'none'}});}var ba;function ca(da,ea){if(!p.getClientID()){n.warn('FB.getLoginStatus() called before calling FB.init().');return;}if(da)if(!ea&&ba=='loaded'){da({status:p.getLoginStatus(),authResponse:y()});return;}else w.subscribe('FB.loginStatus',da);if(!ea&&ba=='loading')return;ba='loading';var fa=function(ga){ba='loaded';w.inform('FB.loginStatus',ga);w.clearSubscribers('FB.loginStatus');};aa(fa);}ES('Object','assign',false,w,{getLoginStatus:ca,fetchLoginStatus:aa,setAuthResponse:x,getAuthResponse:y,parseSignedRequest:q.parse,xdResponseWrapper:z});e.exports=w;},null); + __d("toArray",["invariant"],function(a,b,c,d,e,f,g){function h(i){var j=i.length;g(!ES('Array','isArray',false,i)&&(typeof i==='object'||typeof i==='function'));g(typeof j==='number');g(j===0||(j-1) in i);if(i.hasOwnProperty)try{return Array.prototype.slice.call(i);}catch(k){}var l=Array(j);for(var m=0;m=0;}function q(z,aa){g.isTruthy(z,'element not specified');g.isString(aa);if(!p(z,aa))z.className=n(z,'className')+' '+aa;}function r(z,aa){g.isTruthy(z,'element not specified');g.isString(aa);var ba=new RegExp('\\s*'+aa,'g');z.className=ES(n(z,'className').replace(ba,''),'trim',true);}function s(z,aa,ba){g.isString(z);aa=aa||document.body;ba=ba||'*';if(aa.querySelectorAll)return h(aa.querySelectorAll(ba+'.'+z));var ca=aa.getElementsByTagName(ba),da=[];for(var ea=0,fa=ca.length;ea2000){h.remove(n.callback);return false;}p.onerror=function(){q({error:{type:'http',message:'unknown error'}});};var r=function(){setTimeout(function(){q({error:{type:'http',message:'unknown error'}});},0);};if(p.addEventListener){p.addEventListener('load',r,false);}else p.onreadystatechange=function(){if(/loaded|complete/.test(this.readyState))r();};p.src=l;g.getRoot().appendChild(p);return true;}var k={execute:j};e.exports=k;},null); + __d("ApiClient",["ArgumentError","Assert","CORSRequest","FlashRequest","flattenObject","JSONPRequest","Log","ObservableMixin","sprintf","sdk.URI","UrlMap","ApiClientConfig","invariant"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s){var t,u,v,w={get:true,post:true,'delete':true,put:true},x={fql_query:true,fql_multiquery:true,friends_get:true,notifications_get:true,stream_get:true,users_getinfo:true},y=[],z=[],aa=null,ba=50,ca=105440539523;function da(la,ma,na,oa){if(v)na=ES('Object','assign',false,{},v,na);na.access_token=na.access_token||t;na.pretty=na.pretty||0;na=k(na);var pa={jsonp:l,cors:i,flash:j},qa;if(na.transport){qa=[na.transport];delete na.transport;}else qa=['jsonp','cors','flash'];for(var ra=0;ra0);var la=y,ma=z;y=[];z=[];aa=null;ga('/','POST',{batch:ES('JSON','stringify',false,la),include_headers:false,batch_app_id:u||ca},function(na){if(ES('Array','isArray',false,na)){ES(na,'forEach',true,function(oa,pa){ma[pa](ES('JSON','parse',false,oa.body));});}else ES(ma,'forEach',true,function(oa){return oa({error:{message:'Fatal: batch call failed.'}});});});}function ja(la,ma){h.isObject(la);h.isString(la.method,'method missing');if(!ma)m.warn('No callback passed to the ApiClient');var na=la.method.toLowerCase().replace('.','_');la.format='json-strings';la.api_key=u;var oa=na in x?'api_read':'api',pa=q.resolve(oa)+'/restserver.php',qa=ES(ea,'bind',true,null,ma,'/restserver.php','get',la);da(pa,'get',la,qa);}var ka=ES('Object','assign',false,new n(),{setAccessToken:function(la){t=la;},setClientID:function(la){u=la;},setDefaultParams:function(la){v=la;},rest:ja,graph:ga,scheduleBatchCall:ha});j.setSwfUrl(r.FlashRequest.swfUrl);e.exports=ka;},null); + __d("sdk.PlatformVersioning",["sdk.Runtime","ManagedError"],function(a,b,c,d,e,f,g,h){var i=/^v\d+\.\d\d?$/,j={REGEX:i,assertVersionIsSet:function(){if(!g.getVersion())throw new h('init not called with valid version');},assertValidVersion:function(k){if(!i.test(k))throw new h('invalid version specified');}};e.exports=j;},null); + __d("sdk.api",["ApiClient","sdk.PlatformVersioning","sdk.Runtime","sdk.URI"],function(a,b,c,d,e,f,g,h,i,j){var k;i.subscribe('ClientID.change',function(m){g.setClientID(m);});i.subscribe('AccessToken.change',function(m){k=m;g.setAccessToken(m);});g.setDefaultParams({sdk:'joey'});g.subscribe('request.complete',function(m,n,o,p){var q=false;if(p&&typeof p=='object')if(p.error){if(p.error=='invalid_token'||(p.error.type=='OAuthException'&&p.error.code==190))q=true;}else if(p.error_code)if(p.error_code=='190')q=true;if(q&&k===i.getAccessToken())i.setAccessToken(null);});g.subscribe('request.complete',function(m,n,o,p){if(((m=='/me/permissions'&&n==='delete')||(m=='/restserver.php'&&o.method=='Auth.revokeAuthorization'))&&p===true)i.setAccessToken(null);});function l(m){if(typeof m==='string'){if(i.getIsVersioned()){h.assertVersionIsSet();if(!/https?/.test(m)&&m.charAt(0)!=='/')m='/'+m;m=j(m).setDomain(null).setProtocol(null).toString();if(!h.REGEX.test(m.substring(1,ES(m,'indexOf',true,'/',1))))m='/'+i.getVersion()+m;var n=[m].concat(Array.prototype.slice.call(arguments,1));g.graph.apply(g,n);}else g.graph.apply(g,arguments);}else g.rest.apply(g,arguments);}e.exports=l;},null); + __d("legacy:fb.api",["FB","sdk.api"],function(a,b,c,d,e,f,g,h){g.provide('',{api:h});},3); + __d("merge",[],function(a,b,c,d,e,f){"use strict";var g=function(h,i){return ES('Object','assign',false,{},h,i);};e.exports=g;},null); + __d("sdk.AppEvents",["Assert","sdk.Impressions","merge","sdk.Runtime"],function(a,b,c,d,e,f,g,h,i,j){var k={COMPLETED_REGISTRATION:'fb_mobile_complete_registration',VIEWED_CONTENT:'fb_mobile_content_view',SEARCHED:'fb_mobile_search',RATED:'fb_mobile_rate',COMPLETED_TUTORIAL:'fb_mobile_tutorial_completion',ADDED_TO_CART:'fb_mobile_add_to_cart',ADDED_TO_WISHLIST:'fb_mobile_add_to_wishlist',INITIATED_CHECKOUT:'fb_mobile_initiated_checkout',ADDED_PAYMENT_INFO:'fb_mobile_add_payment_info',ACHIEVED_LEVEL:'fb_mobile_level_achieved',UNLOCKED_ACHIEVEMENT:'fb_mobile_achievement_unlocked',SPENT_CREDITS:'fb_mobile_spent_credits'},l={ACTIVATED_APP:'fb_mobile_activate_app',PURCHASED:'fb_mobile_purchase'},m={CURRENCY:'fb_currency',REGISTRATION_METHOD:'fb_registration_method',CONTENT_TYPE:'fb_content_type',CONTENT_ID:'fb_content_id',SEARCH_STRING:'fb_search_string',SUCCESS:'fb_success',MAX_RATING_VALUE:'fb_max_rating_value',PAYMENT_INFO_AVAILABLE:'fb_payment_info_available',NUM_ITEMS:'fb_num_items',LEVEL:'fb_level',DESCRIPTION:'fb_description'},n=40,o='^[0-9a-zA-Z_]+[0-9a-zA-Z _-]*$';function p(t,u,v,w){g.isTrue(q(u),'Invalid event name: '+u+'. '+'It must be between 1 and '+n+' characters, '+'and must be contain only alphanumerics, _, - or spaces, '+'starting with alphanumeric or _.');var x={ae:1,ev:u,vts:v,canvas:j.isCanvasEnvironment()?1:0};if(w)x.cd=w;h.impression({api_key:t,payload:ES('JSON','stringify',false,x)});}function q(t){if(t===null||t.length===0||t.length>n||!(new RegExp(o)).test(t))return false;return true;}function r(t,u,v,w){var x={};x[m.CURRENCY]=v;p(t,l.PURCHASED,u,i(w,x));}function s(t){p(t,l.ACTIVATED_APP);}e.exports={activateApp:s,logEvent:p,logPurchase:r,isValidEventName:q,EventNames:k,ParameterNames:m};},null); + __d("legacy:fb.appevents",["Assert","sdk.AppEvents","FB","sdk.feature","sdk.Runtime"],function(a,b,c,d,e,f,g,h,i,j,k){i.provide('AppEvents',{logEvent:function(l,m,n){g.isTrue(j('allow_non_canvas_app_events')||k.isCanvasEnvironment(),'You can only use this function in Facebook Canvas environment');g.isString(l,'Invalid eventName');g.maybeNumber(m,'Invalid valueToSum');g.maybeObject(n,'Invalid params');var o=k.getClientID();g.isTrue(o!==null&&o.length>0,'You need to call FB.init() with App ID first.');h.logEvent(o,l,m,n);},logPurchase:function(l,m,n){g.isTrue(j('allow_non_canvas_app_events')||k.isCanvasEnvironment(),'You can only use this function in Facebook Canvas environment');g.isNumber(l,'Invalid purchaseAmount');g.isString(m,'Invalid currency');g.maybeObject(n,'Invalid params');var o=k.getClientID();g.isTrue(o!==null&&o.length>0,'You need to call FB.init() with App ID first.');h.logPurchase(o,l,m,n);},activateApp:function(){g.isTrue(j('allow_non_canvas_app_events')||k.isCanvasEnvironment(),'You can only use this function in Facebook Canvas environment');var l=k.getClientID();g.isTrue(l!==null&&l.length>0,'You need to call FB.init() with App ID first.');h.activateApp(l);},EventNames:h.EventNames,ParameterNames:h.ParameterNames});},3); + __d("sdk.Canvas.Environment",["sdk.RPC"],function(a,b,c,d,e,f,g){function h(k){g.remote.getPageInfo(function(l){k(l.result);});}function i(k,l){g.remote.scrollTo({x:k||0,y:l||0});}g.stub('getPageInfo');g.stub('scrollTo');var j={getPageInfo:h,scrollTo:i};e.exports=j;},null); + __d("sdk.Intl",["Log"],function(a,b,c,d,e,f,g){var h=('['+'.!?'+'\u3002'+'\uFF01'+'\uFF1F'+'\u0964'+'\u2026'+'\u0EAF'+'\u1801'+'\u0E2F'+'\uFF0E'+']');function i(l){if(typeof l!='string')return false;return !!l.match(new RegExp(h+'['+')"'+"'"+'\u00BB'+'\u0F3B'+'\u0F3D'+'\u2019'+'\u201D'+'\u203A'+'\u3009'+'\u300B'+'\u300D'+'\u300F'+'\u3011'+'\u3015'+'\u3017'+'\u3019'+'\u301B'+'\u301E'+'\u301F'+'\uFD3F'+'\uFF07'+'\uFF09'+'\uFF3D'+'\\s'+']*$'));}function j(l,m){if(m!==undefined)if(typeof m!='object'){g.error('The second arg to FB.Intl.tx() must be an Object for '+'FB.Intl.tx('+l+', ...)');}else{var n;for(var o in m)if(m.hasOwnProperty(o)){if(i(m[o])){n=new RegExp('\\{'+o+'\\}'+h+'*','g');}else n=new RegExp('\\{'+o+'\\}','g');l=l.replace(n,m[o]);}}return l;}function k(){throw new Error('Placeholder function');}k._=j;e.exports={tx:k};},null); + __d("sdk.Dialog",["sdk.Canvas.Environment","sdk.Content","sdk.DOM","DOMEventListener","sdk.Intl","ObservableMixin","sdk.Runtime","Type","UserAgent_DEPRECATED","sdk.feature"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){var q=590,r=500,s=240,t=575,u=function(){var y;if(p('dialog_resize_refactor')){var z=v();y=z&&(z.height>=q||z.width>=r);}else y=!!o.ipad();u=function(){return y;};return y;};function v(){if(p('dialog_resize_refactor')){var y=i.getViewportInfo();if(y.height&&y.width)return {width:Math.min(y.width,q),height:Math.min(y.height,r)};}return null;}var w=n.extend({constructor:function y(z,aa){this.parent();this.id=z;this.display=aa;this._e2e={};if(!x._dialogs){x._dialogs={};x._addOrientationHandler();}x._dialogs[z]=this;this.trackEvent('init');},trackEvent:function(y,z){if(this._e2e[y])return this;this._e2e[y]=z||ES('Date','now',false);if(y=='close')this.inform('e2e:end',this._e2e);return this;},trackEvents:function(y){if(typeof y==='string')y=ES('JSON','parse',false,y);for(var z in y)if(y.hasOwnProperty(z))this.trackEvent(z,y[z]);return this;}},l),x={newInstance:function(y,z){return new w(y,z);},_dialogs:null,_lastYOffset:0,_loaderEl:null,_overlayEl:null,_stack:[],_active:null,get:function(y){return x._dialogs[y];},_findRoot:function(y){while(y){if(i.containsCss(y,'fb_dialog'))return y;y=y.parentNode;}},_createWWWLoader:function(y){y=y?y:460;return x.create({content:('
    '+' '+'
    '+'
    '+' Facebook'+'
    '+'
    '+'
    '+''),width:y});},_createMobileLoader:function(){var y=o.nativeApp()?'':(''+' '+' '+' '+' '+' '+' '+' '+'
    '+' '+' '+'
    '+k.tx._("\u52a0\u8f7d\u4e2d...")+'
    '+'
    '+'
    ');return x.create({classes:'loading'+(u()?' centered':''),content:('
    '+y+'
    ')});},_restoreBodyPosition:function(){if(!u()){var y=document.getElementsByTagName('body')[0];i.removeCss(y,'fb_hidden');}},_showTabletOverlay:function(){if(!u())return;if(!x._overlayEl){x._overlayEl=document.createElement('div');x._overlayEl.setAttribute('id','fb_dialog_ipad_overlay');h.append(x._overlayEl,null);}x._overlayEl.className='';},_hideTabletOverlay:function(){if(u())x._overlayEl.className='hidden';},showLoader:function(y,z){x._showTabletOverlay();if(!x._loaderEl)x._loaderEl=x._findRoot(o.mobile()?x._createMobileLoader():x._createWWWLoader(z));if(!y)y=function(){};var aa=document.getElementById('fb_dialog_loader_close');i.removeCss(aa,'fb_hidden');aa.onclick=function(){x._hideLoader();x._restoreBodyPosition();x._hideTabletOverlay();y();};var ba=document.getElementById('fb_dialog_ipad_overlay');if(ba)ba.ontouchstart=aa.onclick;x._makeActive(x._loaderEl);},_hideLoader:function(){if(x._loaderEl&&x._loaderEl==x._active)x._loaderEl.style.top='-10000px';},_makeActive:function(y){x._setDialogSizes();x._lowerActive();x._active=y;if(m.isEnvironment(m.ENVIRONMENTS.CANVAS))g.getPageInfo(function(z){x._centerActive(z);});x._centerActive();},_lowerActive:function(){if(!x._active)return;x._active.style.top='-10000px';x._active=null;},_removeStacked:function(y){x._stack=ES(x._stack,'filter',true,function(z){return z!=y;});},_centerActive:function(y){var z=x._active;if(!z)return;var aa=i.getViewportInfo(),ba=parseInt(z.offsetWidth,10),ca=parseInt(z.offsetHeight,10),da=aa.scrollLeft+(aa.width-ba)/2,ea=(aa.height-ca)/2.5;if(dafa)ga=fa;ga+=aa.scrollTop;if(o.mobile()){var ha=100;if(u()){ha+=(aa.height-ca)/2;}else{var ia=document.getElementsByTagName('body')[0];i.addCss(ia,'fb_hidden');if(p('dialog_resize_refactor'))ia.style.width='auto';ga=10000;}var ja=i.getByClass('fb_dialog_padding',z);if(ja.length)ja[0].style.height=ha+'px';}z.style.left=(da>0?da:0)+'px';z.style.top=(ga>0?ga:0)+'px';},_setDialogSizes:function(){if(!o.mobile()||u())return;for(var y in x._dialogs)if(x._dialogs.hasOwnProperty(y)){var z=document.getElementById(y);if(z){z.style.width=x.getDefaultSize().width+'px';z.style.height=x.getDefaultSize().height+'px';}}},getDefaultSize:function(){if(o.mobile()){var y=v();if(y)return y;if(o.ipad())return {width:r,height:q};if(o.android()){return {width:screen.availWidth,height:screen.availHeight};}else{var z=window.innerWidth,aa=window.innerHeight,ba=z/aa>1.2;return {width:z,height:Math.max(aa,(ba?screen.width:screen.height))};}}return {width:t,height:s};},_handleOrientationChange:function(y){var z=p('dialog_resize_refactor',false)?i.getViewportInfo().width:screen.availWidth;if(o.android()&&z==x._availScreenWidth){setTimeout(x._handleOrientationChange,50);return;}x._availScreenWidth=z;if(u()){x._centerActive();}else{var aa=x.getDefaultSize().width;for(var ba in x._dialogs)if(x._dialogs.hasOwnProperty(ba)){var ca=document.getElementById(ba);if(ca)ca.style.width=aa+'px';}}},_addOrientationHandler:function(){if(!o.mobile())return;var y="onorientationchange" in window?'orientationchange':'resize';x._availScreenWidth=p('dialog_resize_refactor',false)?i.getViewportInfo().width:screen.availWidth;j.add(window,y,x._handleOrientationChange);},create:function(y){y=y||{};var z=document.createElement('div'),aa=document.createElement('div'),ba='fb_dialog';if(y.closeIcon&&y.onClose){var ca=document.createElement('a');ca.className='fb_dialog_close_icon';ca.onclick=y.onClose;z.appendChild(ca);}ba+=' '+(y.classes||'');if(o.ie()){ba+=' fb_dialog_legacy';ES(['vert_left','vert_right','horiz_top','horiz_bottom','top_left','top_right','bottom_left','bottom_right'],'forEach',true,function(fa){var ga=document.createElement('span');ga.className='fb_dialog_'+fa;z.appendChild(ga);});}else ba+=o.mobile()?' fb_dialog_mobile':' fb_dialog_advanced';if(y.content)h.append(y.content,aa);z.className=ba;var da=parseInt(y.width,10);if(!isNaN(da))z.style.width=da+'px';aa.className='fb_dialog_content';z.appendChild(aa);if(o.mobile()){var ea=document.createElement('div');ea.className='fb_dialog_padding';z.appendChild(ea);}h.append(z);if(y.visible)x.show(z);return aa;},show:function(y){var z=x._findRoot(y);if(z){x._removeStacked(z);x._hideLoader();x._makeActive(z);x._stack.push(z);if('fbCallID' in y)x.get(y.fbCallID).inform('iframe_show').trackEvent('show');}},hide:function(y){var z=x._findRoot(y);x._hideLoader();if(z==x._active){x._lowerActive();x._restoreBodyPosition();x._hideTabletOverlay();if('fbCallID' in y)x.get(y.fbCallID).inform('iframe_hide').trackEvent('hide');}},remove:function(y){y=x._findRoot(y);if(y){var z=x._active==y;x._removeStacked(y);if(z){x._hideLoader();if(x._stack.length>0){x.show(x._stack.pop());}else{x._lowerActive();x._restoreBodyPosition();x._hideTabletOverlay();}}else if(x._active===null&&x._stack.length>0)x.show(x._stack.pop());setTimeout(function(){y.parentNode.removeChild(y);},3000);}},isActive:function(y){var z=x._findRoot(y);return z&&z===x._active;}};e.exports=x;},null); + __d("sdk.Frictionless",["sdk.Auth","sdk.api","sdk.Event","sdk.Dialog"],function(a,b,c,d,e,f,g,h,i,j){var k={_allowedRecipients:{},_useFrictionless:false,_updateRecipients:function(){k._allowedRecipients={};h('/me/apprequestformerrecipients',function(l){if(!l||l.error)return;ES(l.data,'forEach',true,function(m){k._allowedRecipients[m.recipient_id]=true;});});},init:function(){k._useFrictionless=true;g.getLoginStatus(function(l){if(l.status=='connected')k._updateRecipients();});i.subscribe('auth.login',function(l){if(l.authResponse)k._updateRecipients();});},_processRequestResponse:function(l,m){return function(n){var o=n&&n.updated_frictionless;if(k._useFrictionless&&o)k._updateRecipients();if(n){if(!m&&n.frictionless){j._hideLoader();j._restoreBodyPosition();j._hideIPadOverlay();}delete n.frictionless;delete n.updated_frictionless;}l&&l(n);};},isAllowed:function(l){if(!l)return false;if(typeof l==='number')return l in k._allowedRecipients;if(typeof l==='string')l=l.split(',');l=ES(l,'map',true,function(o){return ES(String(o),'trim',true);});var m=true,n=false;ES(l,'forEach',true,function(o){m=m&&o in k._allowedRecipients;n=true;});return m&&n;}};i.subscribe('init:post',function(l){if(l.frictionlessRequests)k.init();});e.exports=k;},null); + __d("sdk.Native",["Log","UserAgent_DEPRECATED"],function(a,b,c,d,e,f,g,h){var i='fbNativeReady',j={onready:function(k){if(!h.nativeApp()){g.error('FB.Native.onready only works when the page is rendered '+'in a WebView of the native Facebook app. Test if this is the '+'case calling FB.UA.nativeApp()');return;}if(window.__fbNative&&!this.nativeReady)ES('Object','assign',false,this,window.__fbNative);if(this.nativeReady){k();}else{var l=function(m){window.removeEventListener(i,l);this.onready(k);};window.addEventListener(i,l,false);}}};e.exports=j;},null); + __d("resolveURI",[],function(a,b,c,d,e,f){function g(h){if(!h)return window.location.href;h=h.replace(/&/g,'&').replace(/"/g,'"');var i=document.createElement('div');i.innerHTML='';return i.firstChild.href;}e.exports=g;},null); + __d("sdk.UIServer",["sdk.Auth","sdk.Content","createObjectFrom","sdk.Dialog","sdk.DOM","sdk.Event","flattenObject","sdk.Frictionless","sdk.getContextType","guid","insertIframe","Log","sdk.Native","QueryString","resolveURI","sdk.RPC","sdk.Runtime","JSSDKConfig","UrlMap","UserAgent_DEPRECATED","sdk.XD"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa){var ba={transform:function(ea){if(ea.params.display==='touch'&&ea.params.access_token&&window.postMessage){ea.params.channel=da._xdChannelHandler(ea.id,'parent');if(!z.nativeApp())ea.params.in_iframe=1;return ea;}else return da.genericTransform(ea);},getXdRelation:function(ea){var fa=ea.display;if(fa==='touch'&&window.postMessage&&ea.in_iframe)return 'parent';return da.getXdRelation(ea);}},ca={'stream.share':{size:{width:670,height:340},url:'sharer.php',transform:function(ea){if(!ea.params.u)ea.params.u=window.location.toString();ea.params.display='popup';return ea;}},apprequests:{transform:function(ea){ea=ba.transform(ea);ea.params.frictionless=n&&n._useFrictionless;if(ea.params.frictionless){if(n.isAllowed(ea.params.to)){ea.params.display='iframe';ea.params.in_iframe=true;ea.hideLoader=true;}ea.cb=n._processRequestResponse(ea.cb,ea.hideLoader);}ea.closeIcon=false;return ea;},getXdRelation:ba.getXdRelation},feed:ba,'permissions.oauth':{url:'dialog/oauth',size:{width:(z.mobile()?null:475),height:(z.mobile()?null:183)},transform:function(ea){if(!w.getClientID()){r.error('FB.login() called before FB.init().');return;}if(g.getAuthResponse()&&!ea.params.scope&&!ea.params.auth_type){r.error('FB.login() called when user is already connected.');ea.cb&&ea.cb({status:w.getLoginStatus(),authResponse:g.getAuthResponse()});return;}var fa=ea.cb,ga=ea.id;delete ea.cb;var ha=ES('Object','keys',false,ES('Object','assign',false,ea.params.response_type?i(ea.params.response_type.split(',')):{},{token:true,signed_request:true})).join(',');if(ea.params.display==='async'){ES('Object','assign',false,ea.params,{client_id:w.getClientID(),origin:o(),response_type:ha,domain:location.hostname});ea.cb=g.xdResponseWrapper(fa,g.getAuthResponse(),'permissions.oauth');}else ES('Object','assign',false,ea.params,{client_id:w.getClientID(),redirect_uri:u(da.xdHandler(fa,ga,'opener',g.getAuthResponse(),'permissions.oauth')),origin:o(),response_type:ha,domain:location.hostname});return ea;}},'auth.logout':{url:'logout.php',transform:function(ea){if(!w.getClientID()){r.error('FB.logout() called before calling FB.init().');}else if(!g.getAuthResponse()){r.error('FB.logout() called without an access token.');}else{ea.params.next=da.xdHandler(ea.cb,ea.id,'parent',g.getAuthResponse(),'logout');return ea;}}},'login.status':{url:'dialog/oauth',transform:function(ea){var fa=ea.cb,ga=ea.id;delete ea.cb;ES('Object','assign',false,ea.params,{client_id:w.getClientID(),redirect_uri:da.xdHandler(fa,ga,'parent',g.getAuthResponse(),'login_status'),origin:o(),response_type:'token,signed_request,code',domain:location.hostname});return ea;}}},da={Methods:ca,_loadedNodes:{},_defaultCb:{},_resultToken:'"xxRESULTTOKENxx"',genericTransform:function(ea){if(ea.params.display=='dialog'||ea.params.display=='iframe')ES('Object','assign',false,ea.params,{display:'iframe',channel:da._xdChannelHandler(ea.id,'parent.parent')},true);return ea;},checkOauthDisplay:function(ea){var fa=ea.scope||ea.perms||w.getScope();if(!fa)return ea.display;var ga=fa.split(/\s|,/g);for(var ha=0;ha2000;},getDisplayMode:function(ea,fa){if(fa.display==='hidden'||fa.display==='none')return fa.display;var ga=w.isEnvironment(w.ENVIRONMENTS.CANVAS)||w.isEnvironment(w.ENVIRONMENTS.PAGETAB);if(ga&&!fa.display)return 'async';if(z.mobile()||fa.display==='touch')return 'touch';if(!w.getAccessToken()&&(fa.display=='iframe'||fa.display=='dialog')&&!ea.loggedOutIframe){r.error('"dialog" mode can only be used when the user is connected.');return 'popup';}if(ea.connectDisplay&&!ga)return ea.connectDisplay;return fa.display||(w.getAccessToken()?'dialog':'popup');},getXdRelation:function(ea){var fa=ea.display;if(fa==='popup'||fa==='touch')return 'opener';if(fa==='dialog'||fa==='iframe'||fa==='hidden'||fa==='none')return 'parent';if(fa==='async')return 'parent.frames['+window.name+']';},popup:function(ea){var fa=typeof window.screenX!='undefined'?window.screenX:window.screenLeft,ga=typeof window.screenY!='undefined'?window.screenY:window.screenTop,ha=typeof window.outerWidth!='undefined'?window.outerWidth:document.documentElement.clientWidth,ia=typeof window.outerHeight!='undefined'?window.outerHeight:(document.documentElement.clientHeight-22),ja=z.mobile()?null:ea.size.width,ka=z.mobile()?null:ea.size.height,la=(fa<0)?window.screen.width+fa:fa,ma=parseInt(la+((ha-ja)/2),10),na=parseInt(ga+((ia-ka)/2.5),10),oa=[];if(ja!==null)oa.push('width='+ja);if(ka!==null)oa.push('height='+ka);oa.push('left='+ma);oa.push('top='+na);oa.push('scrollbars=1');if(ea.name=='permissions.request'||ea.name=='permissions.oauth')oa.push('location=1,toolbar=0');oa=oa.join(',');var pa;if(ea.post){pa=window.open('about:blank',ea.id,oa);if(pa){da.setLoadedNode(ea,pa,'popup');h.submitToTarget({url:ea.url,target:ea.id,params:ea.params});}}else{pa=window.open(ea.url,ea.id,oa);if(pa)da.setLoadedNode(ea,pa,'popup');}if(!pa)return;if(ea.id in da._defaultCb)da._popupMonitor();},setLoadedNode:function(ea,fa,ga){if(ea.params&&ea.params.display!='popup')fa.fbCallID=ea.id;fa={node:fa,type:ga,fbCallID:ea.id};da._loadedNodes[ea.id]=fa;},getLoadedNode:function(ea){var fa=typeof ea=='object'?ea.id:ea,ga=da._loadedNodes[fa];return ga?ga.node:null;},hidden:function(ea){ea.className='FB_UI_Hidden';ea.root=h.appendHidden('');da._insertIframe(ea);},iframe:function(ea){ea.className='FB_UI_Dialog';var fa=function(){da._triggerDefault(ea.id);};ea.root=j.create({onClose:fa,closeIcon:ea.closeIcon===undefined?true:ea.closeIcon,classes:(z.ipad()?'centered':'')});if(!ea.hideLoader)j.showLoader(fa,ea.size.width);k.addCss(ea.root,'fb_dialog_iframe');da._insertIframe(ea);},touch:function(ea){if(ea.params&&ea.params.in_iframe){if(ea.ui_created){j.showLoader(function(){da._triggerDefault(ea.id);},0);}else da.iframe(ea);}else if(z.nativeApp()&&!ea.ui_created){ea.frame=ea.id;s.onready(function(){da.setLoadedNode(ea,s.open(ea.url+'#cb='+ea.frameName),'native');});da._popupMonitor();}else if(!ea.ui_created)da.popup(ea);},async:function(ea){ea.params.redirect_uri=location.protocol+'//'+location.host+location.pathname;delete ea.params.access_token;v.remote.showDialog(ea.params,function(fa){var ga=fa.result;if(ga&&ga.e2e){var ha=j.get(ea.id);ha.trackEvents(ga.e2e);ha.trackEvent('close');delete ga.e2e;}ea.cb(ga);});},getDefaultSize:function(){return j.getDefaultSize();},_insertIframe:function(ea){da._loadedNodes[ea.id]=false;var fa=function(ga){if(ea.id in da._loadedNodes)da.setLoadedNode(ea,ga,'iframe');};if(ea.post){q({url:'about:blank',root:ea.root,className:ea.className,width:ea.size.width,height:ea.size.height,id:ea.id,onInsert:fa,onload:function(ga){h.submitToTarget({url:ea.url,target:ga.name,params:ea.params});}});}else q({url:ea.url,root:ea.root,className:ea.className,width:ea.size.width,height:ea.size.height,id:ea.id,name:ea.frameName,onInsert:fa});},_handleResizeMessage:function(ea,fa){var ga=da.getLoadedNode(ea);if(!ga)return;if(fa.height)ga.style.height=fa.height+'px';if(fa.width)ga.style.width=fa.width+'px';aa.inform('resize.ack',fa||{},'parent.frames['+ga.name+']');if(!j.isActive(ga))j.show(ga);},_triggerDefault:function(ea){da._xdRecv({frame:ea},da._defaultCb[ea]||function(){});},_popupMonitor:function(){var ea;for(var fa in da._loadedNodes)if(da._loadedNodes.hasOwnProperty(fa)&&fa in da._defaultCb){var ga=da._loadedNodes[fa];if(ga.type!='popup'&&ga.type!='native')continue;var ha=ga.node;try{if(ha.closed){da._triggerDefault(fa);}else ea=true;}catch(ia){}}if(ea&&!da._popupInterval){da._popupInterval=setInterval(da._popupMonitor,100);}else if(!ea&&da._popupInterval){clearInterval(da._popupInterval);da._popupInterval=null;}},_xdChannelHandler:function(ea,fa){return aa.handler(function(ga){var ha=da.getLoadedNode(ea);if(!ha)return;if(ga.type=='resize'){da._handleResizeMessage(ea,ga);}else if(ga.type=='hide'){j.hide(ha);}else if(ga.type=='rendered'){var ia=j._findRoot(ha);j.show(ia);}else if(ga.type=='fireevent')l.fire(ga.event);},fa,true,null);},_xdNextHandler:function(ea,fa,ga,ha){if(ha)da._defaultCb[fa]=ea;return aa.handler(function(ia){da._xdRecv(ia,ea);},ga)+'&frame='+fa;},_xdRecv:function(ea,fa){var ga=da.getLoadedNode(ea.frame);if(ga)if(ga.close){try{ga.close();if(/iPhone.*Version\/(5|6)/.test(navigator.userAgent)&&RegExp.$1!=='5')window.focus();da._popupCount--;}catch(ha){}}else if(k.containsCss(ga,'FB_UI_Hidden')){setTimeout(function(){ga.parentNode.parentNode.removeChild(ga.parentNode);},3000);}else if(k.containsCss(ga,'FB_UI_Dialog'))j.remove(ga);delete da._loadedNodes[ea.frame];delete da._defaultCb[ea.frame];if(ea.e2e){var ia=j.get(ea.frame);ia.trackEvents(ea.e2e);ia.trackEvent('close');delete ea.e2e;}fa(ea);},_xdResult:function(ea,fa,ga,ha){return (da._xdNextHandler(function(ia){ea&&ea(ia.result&&ia.result!=da._resultToken&&ES('JSON','parse',false,ia.result));},fa,ga,ha)+'&result='+encodeURIComponent(da._resultToken));},xdHandler:function(ea,fa,ga,ha,ia){return da._xdNextHandler(g.xdResponseWrapper(ea,ha,ia),fa,ga,true);}};v.stub('showDialog');e.exports=da;},null); + __d("sdk.ui",["Assert","sdk.Impressions","Log","sdk.PlatformVersioning","sdk.Runtime","sdk.UIServer","sdk.feature"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(o,p){g.isObject(o);g.maybeFunction(p);if(k.getIsVersioned()){j.assertVersionIsSet();if(o.version){j.assertValidVersion(o.version);}else o.version=k.getVersion();}o=ES('Object','assign',false,{},o);if(!o.method){i.error('"method" is a required parameter for FB.ui().');return null;}if(o.method=='pay.prompt')o.method='pay';var q=o.method;if(o.redirect_uri){i.warn('When using FB.ui, you should not specify a redirect_uri.');delete o.redirect_uri;}if((q=='permissions.request'||q=='permissions.oauth')&&(o.display=='iframe'||o.display=='dialog'))o.display=l.checkOauthDisplay(o);var r=m('e2e_tracking',true);if(r)o.e2e={};var s=l.prepareCall(o,p||function(){});if(!s)return null;var t=s.params.display;if(t==='dialog'){t='iframe';}else if(t==='none')t='hidden';var u=l[t];if(!u){i.error('"display" must be one of "popup", '+'"dialog", "iframe", "touch", "async", "hidden", or "none"');return null;}if(r)s.dialog.subscribe('e2e:end',function(v){v.method=q;v.display=t;i.debug('e2e: %s',ES('JSON','stringify',false,v));h.log(114,{payload:v});});u(s);return s.dialog;}e.exports=n;},null); + __d("legacy:fb.auth",["sdk.Auth","sdk.Cookie","copyProperties","sdk.Event","FB","Log","sdk.Runtime","sdk.SignedRequest","sdk.ui"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){k.provide('',{getLoginStatus:function(){return g.getLoginStatus.apply(g,arguments);},getAuthResponse:function(){return g.getAuthResponse();},getAccessToken:function(){return m.getAccessToken()||null;},getUserID:function(){return m.getUserID()||m.getCookieUserID();},login:function(p,q){if(q&&q.perms&&!q.scope){q.scope=q.perms;delete q.perms;l.warn('OAuth2 specification states that \'perms\' '+'should now be called \'scope\'. Please update.');}var r=m.isEnvironment(m.ENVIRONMENTS.CANVAS)||m.isEnvironment(m.ENVIRONMENTS.PAGETAB);o(i({method:'permissions.oauth',display:r?'async':'popup',domain:location.hostname},q||{}),p);},logout:function(p){o({method:'auth.logout',display:'hidden'},p);}});g.subscribe('logout',ES(j.fire,'bind',true,j,'auth.logout'));g.subscribe('login',ES(j.fire,'bind',true,j,'auth.login'));g.subscribe('authresponse.change',ES(j.fire,'bind',true,j,'auth.authResponseChange'));g.subscribe('status.change',ES(j.fire,'bind',true,j,'auth.statusChange'));j.subscribe('init:post',function(p){if(p.status)g.getLoginStatus();if(m.getClientID())if(p.authResponse){g.setAuthResponse(p.authResponse,'connected');}else if(m.getUseCookie()){var q=h.loadSignedRequest(),r;if(q){try{r=n.parse(q);}catch(s){h.clearSignedRequestCookie();}if(r&&r.user_id)m.setCookieUserID(r.user_id);}h.loadMeta();}});},3); + __d("sdk.Canvas.IframeHandling",["DOMWrapper","sdk.RPC"],function(a,b,c,d,e,f,g,h){var i=null,j;function k(){var o=g.getWindow().document,p=o.body,q=o.documentElement,r=Math.max(p.offsetTop,0),s=Math.max(q.offsetTop,0),t=p.scrollHeight+r,u=p.offsetHeight+r,v=q.scrollHeight+s,w=q.offsetHeight+s;return Math.max(t,u,v,w);}function l(o){if(typeof o!='object')o={};var p=0,q=0;if(!o.height){o.height=k();p=16;q=4;}if(!o.frame)o.frame=window.name||'iframe_canvas';if(j){var r=j.height,s=o.height-r;if(s<=q&&s>=-p)return false;}j=o;h.remote.setSize(o);return true;}function m(o,p){if(p===undefined&&typeof o==='number'){p=o;o=true;}if(o||o===undefined){if(i===null)i=setInterval(function(){l();},p||100);l();}else if(i!==null){clearInterval(i);i=null;}}h.stub('setSize');var n={setSize:l,setAutoGrow:m};e.exports=n;},null); + __d("sdk.Canvas.Navigation",["sdk.RPC"],function(a,b,c,d,e,f,g){function h(j){g.local.navigate=function(k){j({path:k});};g.remote.setNavigationEnabled(true);}g.stub('setNavigationEnabled');var i={setUrlHandler:h};e.exports=i;},null); + __d("sdk.Canvas.Plugin",["sdk.api","sdk.RPC","Log","UserAgent_DEPRECATED","sdk.Runtime","createArrayFrom"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m='CLSID:D27CDB6E-AE6D-11CF-96B8-444553540000',n='CLSID:444785F1-DE89-4295-863A-D46C3A781394',o=null,p=!(j.osx()>=10.9&&(j.chrome()>=31||j.webkit()>=537.71||j.firefox()>=25));function q(aa){aa._hideunity_savedstyle={};aa._hideunity_savedstyle.left=aa.style.left;aa._hideunity_savedstyle.position=aa.style.position;aa._hideunity_savedstyle.width=aa.style.width;aa._hideunity_savedstyle.height=aa.style.height;aa.style.left='-10000px';aa.style.position='absolute';aa.style.width='1px';aa.style.height='1px';}function r(aa){if(aa._hideunity_savedstyle){aa.style.left=aa._hideunity_savedstyle.left;aa.style.position=aa._hideunity_savedstyle.position;aa.style.width=aa._hideunity_savedstyle.width;aa.style.height=aa._hideunity_savedstyle.height;}}function s(aa){aa._old_visibility=aa.style.visibility;aa.style.visibility='hidden';}function t(aa){aa.style.visibility=aa._old_visibility||'';delete aa._old_visibility;}function u(aa){var ba=aa.type?aa.type.toLowerCase():null,ca=ba==='application/x-shockwave-flash'||(aa.classid&&aa.classid.toUpperCase()==m);if(!ca)return false;var da=/opaque|transparent/i;if(da.test(aa.getAttribute('wmode')))return false;for(var ea=0;ea1/l||m=='*'||~ES(m,'indexOf',true,j.getClientID()))return;setTimeout(p,30000);}function r(u){n=u;}function s(u){o.push(u);}var t={COLLECT_AUTOMATIC:k.AUTOMATIC,COLLECT_MANUAL:k.MANUAL,addStaticResource:s,setCollectionMode:r,_maybeSample:q};e.exports=t;},null); + __d("legacy:fb.canvas.prefetcher",["FB","sdk.Canvas.Prefetcher","sdk.Event","sdk.Runtime"],function(a,b,c,d,e,f,g,h,i,j){g.provide('Canvas.Prefetcher',h);i.subscribe('init:post',function(k){if(j.isEnvironment(j.ENVIRONMENTS.CANVAS))h._maybeSample();});},3); + __d("legacy:fb.canvas.presence",["sdk.RPC","sdk.Event"],function(a,b,c,d,e,f,g,h){h.subscribe(h.SUBSCRIBE,i);h.subscribe(h.UNSUBSCRIBE,j);g.stub('useFriendsOnline');function i(k,l){if(k!='canvas.friendsOnlineUpdated')return;if(l.length===1)g.remote.useFriendsOnline(true);}function j(k,l){if(k!='canvas.friendsOnlineUpdated')return;if(l.length===0)g.remote.useFriendsOnline(false);}},3); + __d("legacy:fb.event",["FB","sdk.Event","sdk.Runtime","sdk.Scribe","sdk.feature"],function(a,b,c,d,e,f,g,h,i,j,k){var l=[],m=null,n=k('event_subscriptions_log',false);g.provide('Event',{subscribe:function(o,p){if(n){l.push(o);if(!m)m=setTimeout(function(){j.log('jssdk_error',{appId:i.getClientID(),error:'EVENT_SUBSCRIPTIONS_LOG',extra:{line:0,name:'EVENT_SUBSCRIPTIONS_LOG',script:'N/A',stack:'N/A',message:l.sort().join(',')}});l.length=0;m=null;},n);}return h.subscribe(o,p);},unsubscribe:ES(h.unsubscribe,'bind',true,h)});},3); + __d("legacy:fb.frictionless",["FB","sdk.Frictionless"],function(a,b,c,d,e,f,g,h){g.provide('Frictionless',h);},3); + __d("sdk.init",["sdk.Cookie","sdk.ErrorHandling","sdk.Event","Log","ManagedError","sdk.PlatformVersioning","QueryString","sdk.Runtime","sdk.URI","createArrayFrom"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p){function q(s){var t=(typeof s=='number'&&s>0)||(typeof s=='string'&&/^[0-9a-f]{21,}$|^[0-9]{1,21}$/.test(s));if(t)return s.toString();j.warn('Invalid App Id: Must be a number or numeric string representing '+'the application id.');return null;}function r(s){if(n.getInitialized())j.warn('FB.init has already been called - this could indicate a problem');if(n.getIsVersioned()){if(Object.prototype.toString.call(s)!=='[object Object]')throw new k('Invalid argument');if(s.authResponse)j.warn('Setting authResponse is not supported');if(!s.version)s.version=o(location.href).getQueryData().sdk_version;l.assertValidVersion(s.version);n.setVersion(s.version);}else{if(/number|string/.test(typeof s)){j.warn('FB.init called with invalid parameters');s={apiKey:s};}s=ES('Object','assign',false,{status:true},s||{});}var t=q(s.appId||s.apiKey);if(t!==null)n.setClientID(t);if('scope' in s)n.setScope(s.scope);if(s.cookie){n.setUseCookie(true);if(typeof s.cookie==='string')g.setDomain(s.cookie);}if(s.kidDirectedSite)n.setKidDirectedSite(true);n.setInitialized(true);i.fire('init:post',s);}setTimeout(function(){var s=/(connect\.facebook\.net|\.facebook\.com\/assets.php).*?#(.*)/;ES(p(document.getElementsByTagName('script')),'forEach',true,function(t){if(t.src){var u=s.exec(t.src);if(u){var v=m.decode(u[2]);for(var w in v)if(v.hasOwnProperty(w)){var x=v[w];if(x=='0')v[w]=0;}r(v);}}});if(window.fbAsyncInit&&!window.fbAsyncInit.hasRun){window.fbAsyncInit.hasRun=true;h.unguard(window.fbAsyncInit)();}},0);e.exports=r;},null); + __d("legacy:fb.init",["FB","sdk.init"],function(a,b,c,d,e,f,g,h){g.provide('',{init:h});},3); + __d("legacy:fb.pay",["copyProperties","sdk.Runtime","sdk.UIServer","sdk.XD","sdk.feature","FB"],function(a,b,c,d,e,f,g,h,i,j,k){b('FB');var l={error_code:1383001,error_message:'An unknown error caused the dialog to be closed'},m=function(n){return function(o){if(o&&typeof o.response==='string'){n(ES('JSON','parse',false,o.response));}else if(typeof o==='object'){n(o);}else n(l);};};g(i.Methods,{pay:{size:{width:555,height:120},connectDisplay:'popup',transform:function(n){if(k('launch_payment_dialog_via_pac')){n.cb=m(n.cb);return n;}else{n.cb=m(n.cb);if(!h.isEnvironment(h.ENVIRONMENTS.CANVAS)){n.params.order_info=ES('JSON','stringify',false,n.params.order_info);return n;}var o=j.handler(n.cb,'parent.frames['+(window.name||'iframe_canvas')+']');n.params.channel=o;n.params.uiserver=true;j.inform('Pay.Prompt',n.params);}}}});},3); + __d("legacy:fb.ui",["FB","sdk.ui"],function(a,b,c,d,e,f,g,h){g.provide('',{ui:h});},3); + __d("runOnce",[],function(a,b,c,d,e,f){function g(h){var i,j;return function(){if(!i){i=true;j=h();}return j;};}e.exports=g;},null); + __d("XFBML",["Assert","createArrayFrom","sdk.DOM","sdk.feature","sdk.Impressions","Log","ObservableMixin","runOnce","UserAgent_DEPRECATED"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={},q={},r=0,s=new m();function t(ba,ca){return ba[ca]+'';}function u(ba){return ba.scopeName?(ba.scopeName+':'+ba.nodeName):'';}function v(ba){return p[t(ba,'nodeName').toLowerCase()]||p[u(ba).toLowerCase()];}function w(ba){var ca=ES(ES(t(ba,'className'),'trim',true).split(/\s+/),'filter',true,function(da){return q.hasOwnProperty(da);});if(ca.length===0)return undefined;if(ba.getAttribute('fb-xfbml-state')||!ba.childNodes||ba.childNodes.length===0||(ba.childNodes.length===1&&ba.childNodes[0].nodeType===3)||(ba.children.length===1&&t(ba.children[0],'className')==='fb-xfbml-parse-ignore'))return q[ca[0]];}function x(ba){var ca={};ES(h(ba.attributes),'forEach',true,function(da){ca[t(da,'name')]=t(da,'value');});return ca;}function y(ba,ca,da){var ea=document.createElement('div');i.addCss(ba,ca+'-'+da);ES(h(ba.childNodes),'forEach',true,function(fa){ea.appendChild(fa);});ES(h(ba.attributes),'forEach',true,function(fa){ea.setAttribute(fa.name,fa.value);});ba.parentNode.replaceChild(ea,ba);return ea;}function z(ba,ca,da){g.isTrue(ba&&ba.nodeType&&ba.nodeType===1&&!!ba.getElementsByTagName,'Invalid DOM node passed to FB.XFBML.parse()');g.isFunction(ca,'Invalid callback passed to FB.XFBML.parse()');var ea=++r;l.info('XFBML Parsing Start %s',ea);var fa=1,ga=0,ha=function(){fa--;if(fa===0){l.info('XFBML Parsing Finish %s, %s tags found',ea,ga);ca();s.inform('render',ea,ga);}g.isTrue(fa>=0,'onrender() has been called too many times');};ES(h(ba.getElementsByTagName('*')),'forEach',true,function(ja){if(!da&&ja.getAttribute('fb-xfbml-state'))return;if(ja.nodeType!==1)return;var ka=v(ja)||w(ja);if(!ka)return;if(o.ie()<9&&ja.scopeName)ja=y(ja,ka.xmlns,ka.localName);fa++;ga++;var la=new ka.ctor(ja,ka.xmlns,ka.localName,x(ja));la.subscribe('render',n(function(){ja.setAttribute('fb-xfbml-state','rendered');ha();}));var ma=function(){if(ja.getAttribute('fb-xfbml-state')=='parsed'){s.subscribe('render.queue',ma);}else{ja.setAttribute('fb-xfbml-state','parsed');la.process();}};ma();});s.inform('parse',ea,ga);var ia=30000;setTimeout(function(){if(fa>0)l.warn('%s tags failed to render in %s ms',fa,ia);},ia);ha();}s.subscribe('render',function(){var ba=s.getSubscribers('render.queue');s.clearSubscribers('render.queue');ES(ba,'forEach',true,function(ca){ca();});});ES('Object','assign',false,s,{registerTag:function(ba){var ca=ba.xmlns+':'+ba.localName;g.isUndefined(p[ca],ca+' already registered');p[ca]=ba;q[ba.xmlns+'-'+ba.localName]=ba;},parse:function(ba,ca){z(ba||document.body,ca||function(){},true);},parseNew:function(){z(document.body,function(){},false);}});if(j('log_tag_count')){var aa=function(ba,ca){s.unsubscribe('parse',aa);setTimeout(ES(k.log,'bind',true,null,102,{tag_count:ca}),5000);};s.subscribe('parse',aa);}e.exports=s;},null); + __d("PluginPipe",["sdk.Content","sdk.feature","guid","insertIframe","Miny","ObservableMixin","JSSDKPluginPipeConfig","sdk.Runtime","UrlMap","UserAgent_DEPRECATED","XFBML"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q){var r=new l(),s=m.threshold,t=[];function u(){return !!(h('plugin_pipe')&&n.getSecure()!==undefined&&(p.chrome()||p.firefox())&&m.enabledApps[n.getClientID()]);}function v(){var x=t;t=[];if(x.length<=s){ES(x,'forEach',true,function(aa){j(aa.config);});return;}var y=x.length+1;function z(){y--;if(y===0)w(x);}ES(x,'forEach',true,function(aa){var ba={};for(var ca in aa.config)ba[ca]=aa.config[ca];ba.url=o.resolve('www',n.getSecure())+'/plugins/plugin_pipe_shell.php';ba.onload=z;j(ba);});z();}q.subscribe('parse',v);function w(x){var y=document.createElement('span');g.appendHidden(y);var z={};ES(x,'forEach',true,function(ea){z[ea.config.name]={plugin:ea.tag,params:ea.params};});var aa=ES('JSON','stringify',false,z),ba=k.encode(aa);ES(x,'forEach',true,function(ea){var fa=document.getElementsByName(ea.config.name)[0];fa.onload=ea.config.onload;});var ca=o.resolve('www',n.getSecure())+'/plugins/pipe.php',da=i();j({url:'about:blank',root:y,name:da,className:'fb_hidden fb_invisible',onload:function(){g.submitToTarget({url:ca,target:da,params:{plugins:ba.length-1)?n:l;});},isValid:function(){for(var k=this.dom;k;k=k.parentNode)if(k==document.body)return true;},clear:function(){g.html(this.dom,'');}},i);e.exports=j;},null); + __d("sdk.XFBML.IframeWidget",["sdk.Arbiter","sdk.Auth","sdk.Content","sdk.DOM","sdk.Event","sdk.XFBML.Element","guid","insertIframe","QueryString","sdk.Runtime","sdk.ui","UrlMap","sdk.XD"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s){var t=l.extend({_iframeName:null,_showLoader:true,_refreshOnAuthChange:false,_allowReProcess:false,_fetchPreCachedLoader:false,_visibleAfter:'load',_widgetPipeEnabled:false,_borderReset:false,_repositioned:false,getUrlBits:function(){throw new Error('Inheriting class needs to implement getUrlBits().');},setupAndValidate:function(){return true;},oneTimeSetup:function(){},getSize:function(){},getIframeName:function(){return this._iframeName;},getIframeTitle:function(){return 'Facebook Social Plugin';},getChannelUrl:function(){if(!this._channelUrl){var x=this;this._channelUrl=s.handler(function(y){x.fire('xd.'+y.type,y);},'parent.parent',true);}return this._channelUrl;},getIframeNode:function(){return this.dom.getElementsByTagName('iframe')[0];},arbiterInform:function(event,x,y){s.sendToFacebook(this.getIframeName(),{method:event,params:ES('JSON','stringify',false,x||{}),behavior:y||g.BEHAVIOR_PERSISTENT});},_arbiterInform:function(event,x,y){var z='parent.frames["'+this.getIframeNode().name+'"]';s.inform(event,x,z,y);},getDefaultWebDomain:function(){return r.resolve('www');},process:function(x){if(this._done){if(!this._allowReProcess&&!x)return;this.clear();}else this._oneTimeSetup();this._done=true;this._iframeName=this.getIframeName()||this._iframeName||m();if(!this.setupAndValidate()){this.fire('render');return;}if(this._showLoader)this._addLoader();j.addCss(this.dom,'fb_iframe_widget');if(this._visibleAfter!='immediate'){j.addCss(this.dom,'fb_hide_iframes');}else this.subscribe('iframe.onload',ES(this.fire,'bind',true,this,'render'));var y=this.getSize()||{},z=this.getFullyQualifiedURL();if(y.width=='100%')j.addCss(this.dom,'fb_iframe_widget_fluid');this.clear();n({url:z,root:this.dom.appendChild(document.createElement('span')),name:this._iframeName,title:this.getIframeTitle(),className:p.getRtl()?'fb_rtl':'fb_ltr',height:y.height,width:y.width,onload:ES(this.fire,'bind',true,this,'iframe.onload')});this._resizeFlow(y);this.loaded=false;this.subscribe('iframe.onload',ES(function(){this.loaded=true;if(!this._isResizeHandled)j.addCss(this.dom,'fb_hide_iframes');},'bind',true,this));},generateWidgetPipeIframeName:function(){u++;return 'fb_iframe_'+u;},getFullyQualifiedURL:function(){var x=this._getURL();x+='?'+o.encode(this._getQS());if(x.length>2000){x='about:blank';var y=ES(function(){this._postRequest();this.unsubscribe('iframe.onload',y);},'bind',true,this);this.subscribe('iframe.onload',y);}return x;},_getWidgetPipeShell:function(){return r.resolve('www')+'/common/widget_pipe_shell.php';},_oneTimeSetup:function(){this.subscribe('xd.resize',ES(this._handleResizeMsg,'bind',true,this));this.subscribe('xd.resize',ES(this._bubbleResizeEvent,'bind',true,this));this.subscribe('xd.resize.iframe',ES(this._resizeIframe,'bind',true,this));this.subscribe('xd.resize.flow',ES(this._resizeFlow,'bind',true,this));this.subscribe('xd.resize.flow',ES(this._bubbleResizeEvent,'bind',true,this));this.subscribe('xd.refreshLoginStatus',function(){h.getLoginStatus(function(){},true);});this.subscribe('xd.logout',function(){q({method:'auth.logout',display:'hidden'},function(){});});if(this._refreshOnAuthChange)this._setupAuthRefresh();if(this._visibleAfter=='load')this.subscribe('iframe.onload',ES(this._makeVisible,'bind',true,this));this.subscribe('xd.verify',ES(function(x){this.arbiterInform('xd/verify',x.token);},'bind',true,this));this.oneTimeSetup();},_makeVisible:function(){this._removeLoader();j.removeCss(this.dom,'fb_hide_iframes');this.fire('render');},_setupAuthRefresh:function(){h.getLoginStatus(ES(function(x){var y=x.status;k.subscribe('auth.statusChange',ES(function(z){if(!this.isValid())return;if(y=='unknown'||z.status=='unknown')this.process(true);y=z.status;},'bind',true,this));},'bind',true,this));},_handleResizeMsg:function(x){if(!this.isValid())return;this._resizeIframe(x);this._resizeFlow(x);if(!this._borderReset){this.getIframeNode().style.border='none';this._borderReset=true;}this._isResizeHandled=true;this._makeVisible();},_bubbleResizeEvent:function(x){var y={height:x.height,width:x.width,pluginID:this.getAttribute('plugin-id')};k.fire('xfbml.resize',y);},_resizeIframe:function(x){var y=this.getIframeNode();if(x.reposition==="true")this._repositionIframe(x);x.height&&(y.style.height=x.height+'px');x.width&&(y.style.width=x.width+'px');this._updateIframeZIndex();},_resizeFlow:function(x){var y=this.dom.getElementsByTagName('span')[0];x.height&&(y.style.height=x.height+'px');x.width&&(y.style.width=x.width+'px');this._updateIframeZIndex();},_updateIframeZIndex:function(){var x=this.dom.getElementsByTagName('span')[0],y=this.getIframeNode(),z=y.style.height===x.style.height&&y.style.width===x.style.width,aa=z?'removeCss':'addCss';j[aa](y,'fb_iframe_widget_lift');},_repositionIframe:function(x){var y=this.getIframeNode(),z=parseInt(j.getStyle(y,'width'),10),aa=j.getPosition(y).x,ba=j.getViewportInfo().width,ca=parseInt(x.width,10);if(aa+ca>ba&&aa>ca){y.style.left=z-ca+'px';this.arbiterInform('xd/reposition',{type:'horizontal'});this._repositioned=true;}else if(this._repositioned){y.style.left='0px';this.arbiterInform('xd/reposition',{type:'restore'});this._repositioned=false;}},_addLoader:function(){if(!this._loaderDiv){j.addCss(this.dom,'fb_iframe_widget_loader');this._loaderDiv=document.createElement('div');this._loaderDiv.className='FB_Loader';this.dom.appendChild(this._loaderDiv);}},_removeLoader:function(){if(this._loaderDiv){j.removeCss(this.dom,'fb_iframe_widget_loader');if(this._loaderDiv.parentNode)this._loaderDiv.parentNode.removeChild(this._loaderDiv);this._loaderDiv=null;}},_getQS:function(){return ES('Object','assign',false,{api_key:p.getClientID(),locale:p.getLocale(),sdk:'joey',kid_directed_site:p.getKidDirectedSite(),ref:this.getAttribute('ref')},this.getUrlBits().params);},_getURL:function(){var x=this.getDefaultWebDomain(),y='';return x+'/plugins/'+y+this.getUrlBits().name+'.php';},_postRequest:function(){i.submitToTarget({url:this._getURL(),target:this.getIframeNode().name,params:this._getQS()});}}),u=0,v={};function w(){var x={};for(var y in v){var z=v[y];x[y]={widget:z.getUrlBits().name,params:z._getQS()};}return x;}e.exports=t;},null); + __d("sdk.XFBML.Comments",["sdk.Event","sdk.XFBML.IframeWidget","QueryString","sdk.Runtime","JSSDKConfig","UrlMap","UserAgent_DEPRECATED"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=h.extend({_visibleAfter:'immediate',_refreshOnAuthChange:true,setupAndValidate:function(){var o={channel_url:this.getChannelUrl(),colorscheme:this.getAttribute('colorscheme'),skin:this.getAttribute('skin'),numposts:this.getAttribute('num-posts',10),width:this._getLengthAttribute('width'),href:this.getAttribute('href'),permalink:this.getAttribute('permalink'),publish_feed:this.getAttribute('publish_feed'),order_by:this.getAttribute('order_by'),mobile:this._getBoolAttribute('mobile')};if(!o.width&&!o.permalink)o.width=550;if(k.initSitevars.enableMobileComments&&m.mobile()&&o.mobile!==false){o.mobile=true;delete o.width;}if(!o.skin)o.skin=o.colorscheme;if(!o.href){o.migrated=this.getAttribute('migrated');o.xid=this.getAttribute('xid');o.title=this.getAttribute('title',document.title);o.url=this.getAttribute('url',document.URL);o.quiet=this.getAttribute('quiet');o.reverse=this.getAttribute('reverse');o.simple=this.getAttribute('simple');o.css=this.getAttribute('css');o.notify=this.getAttribute('notify');if(!o.xid){var p=ES(document.URL,'indexOf',true,'#');if(p>0){o.xid=encodeURIComponent(document.URL.substring(0,p));}else o.xid=encodeURIComponent(document.URL);}if(o.migrated)o.href=l.resolve('www')+'/plugins/comments_v1.php?'+'app_id='+j.getClientID()+'&xid='+encodeURIComponent(o.xid)+'&url='+encodeURIComponent(o.url);}else{var q=this.getAttribute('fb_comment_id');if(!q){q=i.decode(document.URL.substring(ES(document.URL,'indexOf',true,'?')+1)).fb_comment_id;if(q&&ES(q,'indexOf',true,'#')>0)q=q.substring(0,ES(q,'indexOf',true,'#'));}if(q){o.fb_comment_id=q;this.subscribe('render',ES(function(){if(!window.location.hash)window.location.hash=this.getIframeNode().id;},'bind',true,this));}}this._attr=o;return true;},oneTimeSetup:function(){this.subscribe('xd.addComment',ES(this._handleCommentMsg,'bind',true,this));this.subscribe('xd.commentCreated',ES(this._handleCommentCreatedMsg,'bind',true,this));this.subscribe('xd.commentRemoved',ES(this._handleCommentRemovedMsg,'bind',true,this));},getSize:function(){if(!this._attr.permalink)return {width:this._attr.mobile?'100%':this._attr.width,height:160};},getUrlBits:function(){return {name:'comments',params:this._attr};},getDefaultWebDomain:function(){return l.resolve(this._attr.mobile?'m':'www',true);},_handleCommentMsg:function(o){if(!this.isValid())return;g.fire('comments.add',{post:o.post,user:o.user,widget:this});},_handleCommentCreatedMsg:function(o){if(!this.isValid())return;var p={href:o.href,commentID:o.commentID,parentCommentID:o.parentCommentID,message:o.message};g.fire('comment.create',p);},_handleCommentRemovedMsg:function(o){if(!this.isValid())return;var p={href:o.href,commentID:o.commentID};g.fire('comment.remove',p);}});e.exports=n;},null); + __d("sdk.XFBML.CommentsCount",["ApiClient","sdk.DOM","sdk.XFBML.Element","sprintf"],function(a,b,c,d,e,f,g,h,i,j){var k=i.extend({process:function(){h.addCss(this.dom,'fb_comments_count_zero');var l=this.getAttribute('href',window.location.href);g.scheduleBatchCall('/v2.1/'+encodeURIComponent(l),{fields:'share'},ES(function(m){var n=(m.share&&m.share.comment_count)||0;h.html(this.dom,j('%s',n));if(n>0)h.removeCss(this.dom,'fb_comments_count_zero');this.fire('render');},'bind',true,this));}});e.exports=k;},null); + __d("safeEval",[],function(a,b,c,d,e,f){function g(h,i){if(h===null||typeof h==='undefined')return;if(typeof h!=='string')return h;if(/^\w+$/.test(h)&&typeof window[h]==='function')return window[h].apply(null,i||[]);return Function('return eval("'+h.replace(/"/g,'\\"')+'");').apply(null,i||[]);}e.exports=g;},null); + __d("sdk.Helper",["sdk.ErrorHandling","sdk.Event","UrlMap","safeEval","sprintf"],function(a,b,c,d,e,f,g,h,i,j,k){var l={isUser:function(m){return m<2.2e+09||(m>=1e+14&&m<=100099999989999)||(m>=8.9e+13&&m<=89999999999999);},upperCaseFirstChar:function(m){if(m.length>0){return m.substr(0,1).toUpperCase()+m.substr(1);}else return m;},getProfileLink:function(m,n,o){if(!o&&m)o=k('%s/profile.php?id=%s',i.resolve('www'),m.uid||m.id);if(o)n=k('%s',o,n);return n;},invokeHandler:function(m,n,o){if(m)if(typeof m==='string'){g.unguard(j)(m,o);}else if(m.apply)g.unguard(m).apply(n,o||[]);},fireEvent:function(m,n){var o=n._attr.href;n.fire(m,o);h.fire(m,o,n);},executeFunctionByName:function(m){var n=Array.prototype.slice.call(arguments,1),o=m.split("."),p=o.pop(),q=window;for(var r=0;r"'\/]/g,h={'&':'&','<':'<','>':'>','"':'"',"'":''','/':'/'};function i(j){return j.replace(g,function(k){return h[k];});}e.exports=i;},null); + __d("sdk.XFBML.Name",["ApiClient","escapeHTML","sdk.Event","sdk.XFBML.Element","sdk.Helper","Log","sdk.Runtime"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){var n=({}).hasOwnProperty,o=j.extend({process:function(){ES('Object','assign',false,this,{_uid:this.getAttribute('uid'),_firstnameonly:this._getBoolAttribute('first-name-only'),_lastnameonly:this._getBoolAttribute('last-name-only'),_possessive:this._getBoolAttribute('possessive'),_reflexive:this._getBoolAttribute('reflexive'),_objective:this._getBoolAttribute('objective'),_linked:this._getBoolAttribute('linked',true),_subjectId:this.getAttribute('subject-id')});if(!this._uid){l.error('"uid" is a required attribute for ');this.fire('render');return;}var p=[];if(this._firstnameonly){p.push('first_name');}else if(this._lastnameonly){p.push('last_name');}else p.push('name');if(this._subjectId){p.push('gender');if(this._subjectId==m.getUserID())this._reflexive=true;}i.monitor('auth.statusChange',ES(function(){if(!this.isValid()){this.fire('render');return true;}if(!this._uid||this._uid=='loggedinuser')this._uid=m.getUserID();if(!this._uid)return;g.scheduleBatchCall('/v1.0/'+this._uid,{fields:p.join(',')},ES(function(q){if(n.call(q,'error')){l.warn('The name is not found for ID: '+this._uid);return;}if(this._subjectId==this._uid){this._renderPronoun(q);}else this._renderOther(q);this.fire('render');},'bind',true,this));},'bind',true,this));},_renderPronoun:function(p){var q='',r=this._objective;if(this._subjectId){r=true;if(this._subjectId===this._uid)this._reflexive=true;}if(this._uid==m.getUserID()&&this._getBoolAttribute('use-you',true)){if(this._possessive){if(this._reflexive){q='your own';}else q='your';}else if(this._reflexive){q='yourself';}else q='you';}else switch(p.gender){case 'male':if(this._possessive){q=this._reflexive?'his own':'his';}else if(this._reflexive){q='himself';}else if(r){q='him';}else q='he';break;case 'female':if(this._possessive){q=this._reflexive?'her own':'her';}else if(this._reflexive){q='herself';}else if(r){q='her';}else q='she';break;default:if(this._getBoolAttribute('use-they',true)){if(this._possessive){if(this._reflexive){q='their own';}else q='their';}else if(this._reflexive){q='themselves';}else if(r){q='them';}else q='they';}else if(this._possessive){if(this._reflexive){q='his/her own';}else q='his/her';}else if(this._reflexive){q='himself/herself';}else if(r){q='him/her';}else q='he/she';break;}if(this._getBoolAttribute('capitalize',false))q=k.upperCaseFirstChar(q);this.dom.innerHTML=q;},_renderOther:function(p){var q='',r='';if(this._uid==m.getUserID()&&this._getBoolAttribute('use-you',true)){if(this._reflexive){if(this._possessive){q='your own';}else q='yourself';}else if(this._possessive){q='your';}else q='you';}else if(p){if(null===p.first_name)p.first_name='';if(null===p.last_name)p.last_name='';if(this._firstnameonly&&p.first_name!==undefined){q=h(p.first_name);}else if(this._lastnameonly&&p.last_name!==undefined)q=h(p.last_name);if(!q)q=h(p.name);if(q!==''&&this._possessive)q+='\'s';}if(!q)q=h(this.getAttribute('if-cant-see','Facebook User'));if(q){if(this._getBoolAttribute('capitalize',false))q=k.upperCaseFirstChar(q);if(p&&this._linked){r=k.getProfileLink(p,q,this.getAttribute('href',null));}else r=q;}this.dom.innerHTML=r;}});e.exports=o;},null); + __d("sdk.XFBML.RecommendationsBar",["sdk.Arbiter","DOMEventListener","sdk.Event","sdk.XFBML.IframeWidget","resolveURI","sdk.Runtime"],function(a,b,c,d,e,f,g,h,i,j,k,l){var m=j.extend({getUrlBits:function(){return {name:'recommendations_bar',params:this._attr};},setupAndValidate:function(){function n(w,x){var y=0,z=null;function aa(){x();z=null;y=ES('Date','now',false);}return function(){if(!z){var ba=ES('Date','now',false);if(ba-y=this._attr.trigger;}}});e.exports=m;},null); + __d("sdk.XFBML.Registration",["sdk.Auth","sdk.Helper","sdk.XFBML.IframeWidget","sdk.Runtime","UrlMap"],function(a,b,c,d,e,f,g,h,i,j,k){var l=i.extend({_visibleAfter:'immediate',_baseHeight:167,_fieldHeight:28,_skinnyWidth:520,_skinnyBaseHeight:173,_skinnyFieldHeight:52,setupAndValidate:function(){this._attr={action:this.getAttribute('action'),border_color:this.getAttribute('border-color'),channel_url:this.getChannelUrl(),client_id:j.getClientID(),fb_only:this._getBoolAttribute('fb-only',false),fb_register:this._getBoolAttribute('fb-register',false),fields:this.getAttribute('fields'),height:this._getPxAttribute('height'),redirect_uri:this.getAttribute('redirect-uri',window.location.href),no_footer:this._getBoolAttribute('no-footer'),no_header:this._getBoolAttribute('no-header'),onvalidate:this.getAttribute('onvalidate'),width:this._getPxAttribute('width',600),target:this.getAttribute('target')};if(this._attr.onvalidate)this.subscribe('xd.validate',ES(function(m){var n=ES('JSON','parse',false,m.value),o=ES(function(q){this.arbiterInform('Registration.Validation',{errors:q,id:m.id});},'bind',true,this),p=h.executeFunctionByName(this._attr.onvalidate,n,o);if(p)o(p);},'bind',true,this));this.subscribe('xd.authLogin',ES(this._onAuthLogin,'bind',true,this));this.subscribe('xd.authLogout',ES(this._onAuthLogout,'bind',true,this));return true;},getSize:function(){return {width:this._attr.width,height:this._getHeight()};},_getHeight:function(){if(this._attr.height)return this._attr.height;var m;if(!this._attr.fields){m=['name'];}else try{m=ES('JSON','parse',false,this._attr.fields);}catch(n){m=this._attr.fields.split(/,/);}if(this._attr.width + * jsb.fileUtils is the native file utils' singleton object,
    + * please refer to Cocos2d-x's API to know how to use it.
    + * Only available in JSB + * @class + * @name jsb.fileUtils + * @extend cc.Class + */ +jsb.fileUtils = /** @lends jsb.fileUtils# */{ + + /** + * @function fullPathForFilename + * @param {String} arg0 + * @return {String} + */ + fullPathForFilename : function (str) + { + return ; + }, + + /** + * @function getStringFromFile + * @param {String} arg0 + * @return {String} + */ + getStringFromFile : function (str) + { + return ; + }, + + /** + * @function removeFile + * @param {String} arg0 + * @return {bool} + */ + removeFile : function (str) + { + return false; + }, + + /** + * @function isAbsolutePath + * @param {String} arg0 + * @return {bool} + */ + isAbsolutePath : function (str) + { + return false; + }, + + /** + * @function renameFile + * @param {String} arg0 + * @param {String} arg1 + * @param {String} arg2 + * @return {bool} + */ + renameFile : function (str, str, str) + { + return false; + }, + + /** + * @function loadFilenameLookupDictionaryFromFile + * @param {String} arg0 + */ + loadFilenameLookupDictionaryFromFile : function (str) + { + }, + + /** + * @function isPopupNotify + * @return {bool} + */ + isPopupNotify : function () + { + return false; + }, + + /** + * @function getValueVectorFromFile + * @param {String} arg0 + * @return {Array} + */ + getValueVectorFromFile : function (str) + { + return new Array(); + }, + + /** + * @function getSearchPaths + * @return {Array} + */ + getSearchPaths : function () + { + return new Array(); + }, + + /** + * @function writeToFile + * @param {map_object} arg0 + * @param {String} arg1 + * @return {bool} + */ + writeToFile : function (map, str) + { + return false; + }, + + /** + * @function getValueMapFromFile + * @param {String} arg0 + * @return {map_object} + */ + getValueMapFromFile : function (str) + { + return map_object; + }, + + /** + * @function getFileSize + * @param {String} arg0 + * @return {long} + */ + getFileSize : function (str) + { + return 0; + }, + + /** + * @function removeDirectory + * @param {String} arg0 + * @return {bool} + */ + removeDirectory : function (str) + { + return false; + }, + + /** + * @function setSearchPaths + * @param {Array} arg0 + */ + setSearchPaths : function (array) + { + }, + + /** + * @function writeStringToFile + * @param {String} arg0 + * @param {String} arg1 + * @return {bool} + */ + writeStringToFile : function (str, str) + { + return false; + }, + + /** + * @function setSearchResolutionsOrder + * @param {Array} arg0 + */ + setSearchResolutionsOrder : function (array) + { + }, + + /** + * @function addSearchResolutionsOrder + * @param {String} arg0 + */ + addSearchResolutionsOrder : function (str) + { + }, + + /** + * @function addSearchPath + * @param {String} arg0 + */ + addSearchPath : function (str) + { + }, + + /** + * @function isFileExist + * @param {String} arg0 + * @return {bool} + */ + isFileExist : function (str) + { + return false; + }, + + /** + * @function purgeCachedEntries + */ + purgeCachedEntries : function () + { + }, + + /** + * @function fullPathFromRelativeFile + * @param {String} arg0 + * @param {String} arg1 + * @return {String} + */ + fullPathFromRelativeFile : function (str, str) + { + return ; + }, + + /** + * @function isDirectoryExist + * @param {String} arg0 + * @return {bool} + */ + isDirectoryExist : function (str) + { + return false; + }, + + /** + * @function getSearchResolutionsOrder + * @return {Array} + */ + getSearchResolutionsOrder : function () + { + return new Array(); + }, + + /** + * @function createDirectory + * @param {String} arg0 + * @return {bool} + */ + createDirectory : function (str) + { + return false; + }, + + /** + * @function createDirectories + * @param {String} arg0 + * @return {bool} + */ + createDirectories : function (str) + { + return false; + }, + + /** + * @function getWritablePath + * @return {String} + */ + getWritablePath : function () + { + return ; + } + +}; + +/** + * @class + */ +jsb.EventAssetsManager = cc.Class.extend(/** @lends jsb.EventAssetsManager# */{ + + /** + * @function getAssetsManager + * @return {cc.AssetsManager} + */ + getAssetsManager : function ( + ) + { + return cc.AssetsManager; + }, + + /** + * @function getAssetId + * @return {String} + */ + getAssetId : function ( + ) + { + return ; + }, + + /** + * @function getCURLECode + * @return {int} + */ + getCURLECode : function ( + ) + { + return 0; + }, + + /** + * @function getMessage + * @return {String} + */ + getMessage : function ( + ) + { + return ; + }, + + /** + * @function getCURLMCode + * @return {int} + */ + getCURLMCode : function ( + ) + { + return 0; + }, + + /** + * @function getPercentByFile + * @return {float} + */ + getPercentByFile : function ( + ) + { + return 0; + }, + + /** + * @function getEventCode + * @return {cc.EventAssetsManager::EventCode} + */ + getEventCode : function ( + ) + { + return 0; + }, + + /** + * @function getPercent + * @return {float} + */ + getPercent : function ( + ) + { + return 0; + }, + + /** + * @function EventAssetsManager + * @constructor + * @param {String} arg0 + * @param {cc.AssetsManager} arg1 + * @param {cc.EventAssetsManager::EventCode} arg2 + * @param {float} arg3 + * @param {float} arg4 + * @param {String} arg5 + * @param {String} arg6 + * @param {int} arg7 + * @param {int} arg8 + */ + EventAssetsManager : function ( + str, + assetsmanager, + eventcode, + float, + float, + str, + str, + int, + int + ) + { + } +}); + + +/** + * @class + */ +jsb.EventListenerAssetsManager = cc.Class.extend(/** @lends jsb.EventListenerAssetsManager# */{ + + /** + * @function init + * @param {cc.AssetsManager} arg0 + * @param {function} arg1 + * @return {bool} + */ + init : function ( + assetsmanager, + func + ) + { + return false; + }, + + /** + * @function create + * @param {cc.AssetsManager} arg0 + * @param {function} arg1 + * @return {cc.EventListenerAssetsManager} + */ + create : function ( + assetsmanager, + func + ) + { + return cc.EventListenerAssetsManager; + }, + + /** + * @function EventListenerAssetsManager + * @constructor + */ + EventListenerAssetsManager : function ( + ) + { + } + +}); + +/** + * @class + * jsb.AssetsManager is the native AssetsManager for your game resources or scripts. + * please refer to this document to know how to use it: http://www.cocos2d-x.org/docs/manual/framework/html5/v3/assets-manager/en + * Only available in JSB + */ +jsb.AssetsManager = cc.Class.extend(/** @lends jsb.AssetsManager# */{ + + /** + * @function getState + * @return {jsb.AssetsManager::State} + */ + getState : function () + { + return 0; + }, + + /** + * @function checkUpdate + */ + checkUpdate : function () + { + }, + + /** + * @function getStoragePath + * @return {String} + */ + getStoragePath : function () + { + return ; + }, + + /** + * @function update + */ + update : function () + { + }, + + /** + * @function getLocalManifest + * @return {jsb.Manifest} + */ + getLocalManifest : function () + { + return cc.Manifest; + }, + + /** + * @function getRemoteManifest + * @return {jsb.Manifest} + */ + getRemoteManifest : function () + { + return cc.Manifest; + }, + + /** + * @function downloadFailedAssets + */ + downloadFailedAssets : function () + { + }, + + /** + * @function create + * @param {String} arg0 + * @param {String} arg1 + * @return {jsb.AssetsManager} + */ + create : function (str, str) + { + return cc.AssetsManager; + }, + + /** + * @function AssetsManager + * @constructor + * @param {String} arg0 + * @param {String} arg1 + */ + ctor : function (str, str) + { + } + +}); + +/** + * @class + */ +jsb.Manifest = cc.Class.extend(/** @lends jsb.Manifest# */{ + + /** + * @function getManifestFileUrl + * @return {String} + */ + getManifestFileUrl : function () + { + return ; + }, + + /** + * @function isVersionLoaded + * @return {bool} + */ + isVersionLoaded : function () + { + return false; + }, + + /** + * @function isLoaded + * @return {bool} + */ + isLoaded : function () + { + return false; + }, + + /** + * @function getPackageUrl + * @return {String} + */ + getPackageUrl : function () + { + return ; + }, + + /** + * @function getVersion + * @return {String} + */ + getVersion : function () + { + return ; + }, + + /** + * @function getVersionFileUrl + * @return {String} + */ + getVersionFileUrl : function () + { + return ; + } +}); + +/** + * jsb.reflection is a bridge to let you invoke Java static functions. + * please refer to this document to know how to use it: http://www.cocos2d-x.org/docs/manual/framework/html5/v3/reflection/en + * Only available on iOS/Mac/Android platform + * @class + * @name jsb.reflection + */ +jsb.reflection = /** @lends jsb.reflection# */{ + /** + * @function + */ + callStaticMethod : function(){ + } +}; \ No newline at end of file diff --git a/moduleConfig.json b/moduleConfig.json index 20cdaaefdb..a089e198d8 100644 --- a/moduleConfig.json +++ b/moduleConfig.json @@ -27,7 +27,9 @@ "clipping-nodes" : [ "core", "shape-nodes", - "cocos2d/clipping-nodes/CCClippingNode.js" + "cocos2d/clipping-nodes/CCClippingNode.js", + "cocos2d/clipping-nodes/CCClippingNodeCanvasRenderCmd.js", + "cocos2d/clipping-nodes/CCClippingNodeWebGLRenderCmd.js" ], "compression" : [ "core", @@ -70,10 +72,16 @@ "cocos2d/core/event-manager/CCEventManager.js", "cocos2d/core/event-manager/CCEventExtension.js", - "cocos2d/core/base-nodes/BaseNodesWebGL.js", + "cocos2d/core/renderer/RendererCanvas.js", + "cocos2d/core/renderer/RendererWebGL.js", + "cocos2d/core/base-nodes/BaseNodesPropertyDefine.js", "cocos2d/core/base-nodes/CCNode.js", + "cocos2d/core/base-nodes/CCNodeCanvasRenderCmd.js", + "cocos2d/core/base-nodes/CCNodeWebGLRenderCmd.js", "cocos2d/core/base-nodes/CCAtlasNode.js", + "cocos2d/core/base-nodes/CCAtlasNodeCanvasRenderCmd.js", + "cocos2d/core/base-nodes/CCAtlasNodeWebGLRenderCmd.js", "cocos2d/core/textures/TexturesWebGL.js", "cocos2d/core/textures/TexturesPropertyDefine.js", @@ -84,14 +92,18 @@ "cocos2d/core/scenes/CCScene.js", "cocos2d/core/scenes/CCLoaderScene.js", - "cocos2d/core/layers/CCLayerWebGL.js", - "cocos2d/core/layers/CCLayerPropertyDefine.js", "cocos2d/core/layers/CCLayer.js", + "cocos2d/core/layers/CCLayerCanvasRenderCmd.js", + "cocos2d/core/layers/CCLayerWebGLRenderCmd.js", - "cocos2d/core/sprites/SpritesWebGL.js", "cocos2d/core/sprites/SpritesPropertyDefine.js", "cocos2d/core/sprites/CCSprite.js", + "cocos2d/core/sprites/CCSpriteCanvasRenderCmd.js", + "cocos2d/core/sprites/CCSpriteWebGLRenderCmd.js", "cocos2d/core/sprites/CCSpriteBatchNode.js", + "cocos2d/core/sprites/CCSpriteBatchNodeCanvasRenderCmd.js", + "cocos2d/core/sprites/CCSpriteBatchNodeWebGLRenderCmd.js", + "cocos2d/core/sprites/CCBakeSprite.js", "cocos2d/core/sprites/CCAnimation.js", "cocos2d/core/sprites/CCAnimationCache.js", "cocos2d/core/sprites/CCSpriteFrame.js", @@ -106,9 +118,10 @@ "cocos2d/core/CCDrawingPrimitivesCanvas.js", "cocos2d/core/CCDrawingPrimitivesWebGL.js", - "cocos2d/core/labelttf/LabelTTFWebGL.js", "cocos2d/core/labelttf/LabelTTFPropertyDefine.js", "cocos2d/core/labelttf/CCLabelTTF.js", + "cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js", + "cocos2d/core/labelttf/CCLabelTTFWebGLRenderCmd.js", "cocos2d/core/CCActionManager.js" ], @@ -138,7 +151,11 @@ "core", "cocos2d/labels/CCLabelAtlas.js", - "cocos2d/labels/CCLabelBMFont.js" + "cocos2d/labels/CCLabelAtlasCanvasRenderCmd.js", + "cocos2d/labels/CCLabelAtlasWebGLRenderCmd.js", + "cocos2d/labels/CCLabelBMFont.js", + "cocos2d/labels/CCLabelBMFontCanvasRenderCmd.js", + "cocos2d/labels/CCLabelBMFontWebGLRenderCmd.js" ], "menus" : [ "core", "actions", @@ -149,17 +166,20 @@ "motion-streak" : [ "core", "shaders", "kazmath", "labels", - "cocos2d/motion-streak/CCMotionStreak.js" + "cocos2d/motion-streak/CCMotionStreak.js", + "cocos2d/motion-streak/CCMotionStreakWebGLRenderCmd.js" ], "node-grid" : [ "core", - "cocos2d/node-grid/CCNodeGrid.js" + "cocos2d/node-grid/CCNodeGrid.js", + "cocos2d/node-grid/CCNodeGridWebGLRenderCmd.js" ], "parallax" : [ "core", - "cocos2d/parallax/CCParallaxNode.js" + "cocos2d/parallax/CCParallaxNode.js", + "cocos2d/parallax/CCParallaxNodeRenderCmd.js" ], "particle" : [ "core", "compression", @@ -167,25 +187,37 @@ "cocos2d/particle/CCPNGReader.js", "cocos2d/particle/CCTIFFReader.js", "cocos2d/particle/CCParticleSystem.js", + "cocos2d/particle/CCParticleSystemCanvasRenderCmd.js", + "cocos2d/particle/CCParticleSystemWebGLRenderCmd.js", "cocos2d/particle/CCParticleExamples.js", - "cocos2d/particle/CCParticleBatchNode.js" + "cocos2d/particle/CCParticleBatchNode.js", + "cocos2d/particle/CCParticleBatchNodeCanvasRenderCmd.js", + "cocos2d/particle/CCParticleBatchNodeWebGLRenderCmd.js" ], "physics" : [ "core", "shape-nodes", "cocos2d/physics/CCPhysicsSprite.js", - "cocos2d/physics/CCPhysicsDebugNode.js" + "cocos2d/physics/CCPhysicsDebugNode.js", + "cocos2d/physics/CCPhysicsDebugNodeCanvasRenderCmd.js", + "cocos2d/physics/CCPhysicsDebugNodeWebGLRenderCmd.js", + "cocos2d/physics/CCPhysicsSpriteCanvasRenderCmd.js", + "cocos2d/physics/CCPhysicsSpriteWebGLRenderCmd.js" ], "progress-timer" : [ "core", "actions", "cocos2d/progress-timer/CCProgressTimer.js", - "cocos2d/progress-timer/CCActionProgressTimer.js" + "cocos2d/progress-timer/CCActionProgressTimer.js", + "cocos2d/progress-timer/CCProgressTimerCanvasRenderCmd.js", + "cocos2d/progress-timer/CCProgressTimerWebGLRenderCmd.js" ], "render-texture" : [ "core", - "cocos2d/render-texture/CCRenderTexture.js" + "cocos2d/render-texture/CCRenderTexture.js", + "cocos2d/render-texture/CCRenderTextureCanvasRenderCmd.js", + "cocos2d/render-texture/CCRenderTextureWebGLRenderCmd.js" ], "shaders" : [ "core", "kazmath", @@ -198,7 +230,9 @@ "shape-nodes" : [ "core", - "cocos2d/shape-nodes/CCDrawNode.js" + "cocos2d/shape-nodes/CCDrawNode.js", + "cocos2d/shape-nodes/CCDrawNodeCanvasRenderCmd.js", + "cocos2d/shape-nodes/CCDrawNodeWebGLRenderCmd.js" ], "text-input" : [ "core", @@ -213,7 +247,9 @@ "cocos2d/tilemap/CCTMXTiledMap.js", "cocos2d/tilemap/CCTMXXMLParser.js", "cocos2d/tilemap/CCTMXObjectGroup.js", - "cocos2d/tilemap/CCTMXLayer.js" + "cocos2d/tilemap/CCTMXLayer.js", + "cocos2d/tilemap/CCTMXLayerCanvasRenderCmd.js", + "cocos2d/tilemap/CCTMXLayerWebGLRenderCmd.js" ], "transitions" : [ "core", "actions", "render-texture", "progress-timer", @@ -231,8 +267,6 @@ "text-input", "menus", "tilemap", "parallax", "audio" ], - - "ccbreader" : [ "core", "audio", "gui", "menus", "particle", "actions", "labels", @@ -254,13 +288,30 @@ "extensions/editbox/CCdomNode.js", "extensions/editbox/CCEditBox.js" ], + "ccpool" : [ + "core", + + "extensions/ccpool/CCPool.js" + ], "ccui" : [ - "core", "gui", "actions", "labels", "text-input","clipping-nodes", + "core", "actions", "labels", "text-input","clipping-nodes", + "extensions/ccui/base-classes/CCProtectedNode.js", + "extensions/ccui/base-classes/CCProtectedNodeCanvasRenderCmd.js", + "extensions/ccui/base-classes/CCProtectedNodeWebGLRenderCmd.js", "extensions/ccui/system/CocosGUI.js", "extensions/ccui/base-classes/UIWidget.js", + "extensions/ccui/base-classes/UIWidgetRenderCmd.js", + "extensions/ccui/base-classes/UIScale9Sprite.js", + "extensions/ccui/base-classes/UIScale9SpriteCanvasRenderCmd.js", + "extensions/ccui/base-classes/UIScale9SpriteWebGLRenderCmd.js", "extensions/ccui/layouts/UILayout.js", + "extensions/ccui/layouts/UILayoutCanvasRenderCmd.js", + "extensions/ccui/layouts/UILayoutWebGLRenderCmd.js", "extensions/ccui/layouts/UILayoutParameter.js", - "extensions/ccui/layouts/UILayoutDefine.js", + "extensions/ccui/layouts/UILayoutManager.js", + "extensions/ccui/layouts/UIHBox.js", + "extensions/ccui/layouts/UIRelativeBox.js", + "extensions/ccui/layouts/UIVBox.js", "extensions/ccui/system/UIHelper.js", "extensions/ccui/uiwidgets/UIButton.js", "extensions/ccui/uiwidgets/UICheckBox.js", @@ -281,6 +332,7 @@ "extensions/cocostudio/components/CCComponent.js", "extensions/cocostudio/components/CCComponentContainer.js", + "extensions/ccui/layouts/UILayoutComponent.js", "extensions/cocostudio/CocoStudio.js", "extensions/cocostudio/armature/utils/CCArmatureDefine.js", @@ -295,11 +347,15 @@ "extensions/cocostudio/armature/display/CCDisplayFactory.js", "extensions/cocostudio/armature/display/CCDisplayManager.js", "extensions/cocostudio/armature/display/CCSkin.js", + "extensions/cocostudio/armature/display/CCSkinCanvasRenderCmd.js", + "extensions/cocostudio/armature/display/CCSkinWebGLRenderCmd.js", "extensions/cocostudio/armature/animation/CCProcessBase.js", "extensions/cocostudio/armature/animation/CCArmatureAnimation.js", "extensions/cocostudio/armature/animation/CCTween.js", "extensions/cocostudio/armature/physics/CCColliderDetector.js", "extensions/cocostudio/armature/CCArmature.js", + "extensions/cocostudio/armature/CCArmatureCanvasRenderCmd.js", + "extensions/cocostudio/armature/CCArmatureWebGLRenderCmd.js", "extensions/cocostudio/armature/CCBone.js", "extensions/cocostudio/action/CCActionFrame.js", @@ -317,8 +373,20 @@ "extensions/cocostudio/trigger/TriggerMng.js", "extensions/cocostudio/trigger/TriggerObj.js", - "extensions/cocostudio/reader/GUIReader.js", - "extensions/cocostudio/reader/SceneReader.js" + "extensions/cocostudio/timeline/ActionTimeline.js", + "extensions/cocostudio/timeline/Frame.js", + "extensions/cocostudio/timeline/Timeline.js", + + "extensions/cocostudio/loader/load.js", + "extensions/cocostudio/loader/parsers/scene-1.x.js", + "extensions/cocostudio/loader/parsers/uiParser-1.x.js", + "extensions/cocostudio/loader/parsers/action-1.x.js", + "extensions/cocostudio/loader/parsers/action-2.x.js", + "extensions/cocostudio/loader/parsers/timelineParser-1.x.js", + "extensions/cocostudio/loader/parsers/timelineParser-2.x.js", + "extensions/cocostudio/loader/parsers/compatible.js" + + ], "gui" : [ "core", "clipping-nodes", "render-texture", "actions", "progress-timer", @@ -328,6 +396,8 @@ "extensions/gui/control-extension/CCControlUtils.js", "extensions/gui/control-extension/CCInvocation.js", "extensions/gui/control-extension/CCScale9Sprite.js", + "extensions/gui/control-extension/CCScale9SpriteCanvasRenderCmd.js", + "extensions/gui/control-extension/CCScale9SpriteWebGLRenderCmd.js", "extensions/gui/control-extension/CCMenuPassive.js", "extensions/gui/control-extension/CCControlSaturationBrightnessPicker.js", "extensions/gui/control-extension/CCControlHuePicker.js", @@ -337,6 +407,8 @@ "extensions/gui/control-extension/CCControlStepper.js", "extensions/gui/control-extension/CCControlPotentiometer.js", "extensions/gui/scrollview/CCScrollView.js", + "extensions/gui/scrollview/CCScrollViewCanvasRenderCmd.js", + "extensions/gui/scrollview/CCScrollViewWebGLRenderCmd.js", "extensions/gui/scrollview/CCSorting.js", "extensions/gui/scrollview/CCTableView.js" ], @@ -344,27 +416,47 @@ "pluginx" : [ "core", - "extensions/pluginx/protocols/Config.js", - "extensions/pluginx/protocols/PluginUtils.js", - "extensions/pluginx/protocols/PluginProtocol.js", - "extensions/pluginx/protocols/ProtocolSocial.js", - "extensions/pluginx/protocols/ProtocolAds.js", - "extensions/pluginx/protocols/ProtocolAnalytics.js", - - "extensions/pluginx/protocols/PluginFactory.js", - "extensions/pluginx/protocols/PluginManager.js", - + "external/pluginx/Plugin.js" + ], + "plugin-facebook" : [ + "external/pluginx/platform/facebook_sdk.js", + "external/pluginx/platform/facebook.js" + ], - "extensions/pluginx/plugins/SocialWeibo.js", - "extensions/pluginx/plugins/SocialQQWeibo.js", - "extensions/pluginx/plugins/SocialQzone.js", - "extensions/pluginx/plugins/SocialTwitter.js", - "extensions/pluginx/plugins/SocialFacebook.js", + "spine":[ + "core", - "extensions/pluginx/plugins/AnalyticsFlurry.js" + "extensions/spine/Spine.js", + "extensions/spine/CCSkeleton.js", + "extensions/spine/CCSkeletonAnimation.js", + "extensions/spine/CCSkeletonCanvasRenderCmd.js", + "extensions/spine/CCSkeletonWebGLRenderCmd.js" ], - "extensions" : ["gui", "ccbreader", "editbox", "cocostudio", "pluginx"], + "gaf":[ + "core", + "external/gaf/GAFMacros.js", + "external/gaf/GAFBoot.js", + "external/gaf/Library/GAFAssetPreload.js", + "external/gaf/Library/GAFAsset.js", + "external/gaf/Library/GAFObject.js", + "external/gaf/Library/GAFTimeLine.js", + "external/gaf/Library/GAFTextField.js", + "external/gaf/Library/GAFSprite.js", + "external/gaf/Library/GAFMask.js", + "external/gaf/Library/GAFSpriteCanvasRenderCmd.js", + "external/gaf/Library/GAFSpriteWebGLRenderCmd.js", + "external/gaf/Library/GAFTimeLineProto.js", + "external/gaf/Library/GAFSpriteProto.js", + "external/gaf/Library/GAFMaskProto.js", + "external/gaf/Library/GAFTags.js", + "external/gaf/Library/GAFLoader.js", + "external/gaf/Library/GAFDataReader.js", + "external/gaf/Library/GAFShaders.js", + "external/gaf/Library/GAFShaderManager.js", + "external/gaf/Library/GAFAtlasLoader.js" + ], + "extensions" : ["gui", "ccbreader", "editbox", "cocostudio", "spine", "ccpool"], "box2d" : [ "core", "physics", @@ -377,10 +469,9 @@ "external/chipmunk/chipmunk.js" ], "socketio" : [ - "external/socketio/socket.io.min.js" ], - "external" : ["box2d", "chipmunk", "socketio"] + "external" : ["box2d", "chipmunk", "socketio", "pluginx", "gaf"] }, "bootFile" : "CCBoot.js" } \ No newline at end of file diff --git a/template/index.html b/template/index.html index 1e314249d6..e0f577b927 100644 --- a/template/index.html +++ b/template/index.html @@ -19,10 +19,11 @@ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } + + + - - \ No newline at end of file diff --git a/template/main.js b/template/main.js index 8d14ccf6a2..b0afefa923 100644 --- a/template/main.js +++ b/template/main.js @@ -1,4 +1,7 @@ cc.game.onStart = function(){ + if(!cc.sys.isNative && document.getElementById("cocosLoading")) //If referenced loading.js, please remove it + document.body.removeChild(document.getElementById("cocosLoading")); + var designSize = cc.size(480, 800); var screenSize = cc.view.getFrameSize(); diff --git a/template/project.json b/template/project.json index 0c277b291a..a4a9435aab 100644 --- a/template/project.json +++ b/template/project.json @@ -1,5 +1,6 @@ { "debugMode" : 1, + "noCache": false, "showFPS" : true, "frameRate" : 60, "id" : "gameCanvas", diff --git a/template/res/loading.js b/template/res/loading.js new file mode 100644 index 0000000000..d17a700344 --- /dev/null +++ b/template/res/loading.js @@ -0,0 +1 @@ +(function(){var createStyle=function(){return".cocosLoading{position:absolute;margin:-30px -60px;padding:0;top:50%;left:50%}"+".cocosLoading ul{margin:0;padding:0;}"+".cocosLoading span{color:#FFF;text-align:center;display:block;}"+".cocosLoading li{list-style:none;float:left;border-radius:15px;width:15px;height:15px;background:#FFF;margin:5px 0 0 10px}"+".cocosLoading li .ball,.cocosLoading li .unball{background-color:#2187e7;background-image:-moz-linear-gradient(90deg,#2187e7 25%,#a0eaff);background-image:-webkit-linear-gradient(90deg,#2187e7 25%,#a0eaff);width:15px;height:15px;border-radius:50px}"+".cocosLoading li .ball{transform:scale(0);-moz-transform:scale(0);-webkit-transform:scale(0);animation:showDot 1s linear forwards;-moz-animation:showDot 1s linear forwards;-webkit-animation:showDot 1s linear forwards}"+".cocosLoading li .unball{transform:scale(1);-moz-transform:scale(1);-webkit-transform:scale(1);animation:hideDot 1s linear forwards;-moz-animation:hideDot 1s linear forwards;-webkit-animation:hideDot 1s linear forwards}"+"@keyframes showDot{0%{transform:scale(0,0)}100%{transform:scale(1,1)}}"+"@-moz-keyframes showDot{0%{-moz-transform:scale(0,0)}100%{-moz-transform:scale(1,1)}}"+"@-webkit-keyframes showDot{0%{-webkit-transform:scale(0,0)}100%{-webkit-transform:scale(1,1)}}"+"@keyframes hideDot{0%{transform:scale(1,1)}100%{transform:scale(0,0)}}"+"@-moz-keyframes hideDot{0%{-moz-transform:scale(1,1)}100%{-moz-transform:scale(0,0)}}"+"@-webkit-keyframes hideDot{0%{-webkit-transform:scale(1,1)}100%{-webkit-transform:scale(0,0)}}"};var createDom=function(id,num){id=id||"cocosLoading";num=num||5;var i,item;var div=document.createElement("div");div.className="cocosLoading";div.id=id;var bar=document.createElement("ul");var list=[];for(i=0;i=list.length){direction=!direction;index=0;time=1000}else{time=300}animation()},time)};animation()};(function(){var bgColor=document.body.style.background;document.body.style.background="#000";var style=document.createElement("style");style.type="text/css";style.innerHTML=createStyle();document.head.appendChild(style);var list=createDom();startAnimation(list,function(){var div=document.getElementById("cocosLoading");if(!div){document.body.style.background=bgColor}return !!div})})()})(); \ No newline at end of file diff --git a/template/src/myApp.js b/template/src/myApp.js index 55c767b6f0..f91b7c40af 100644 --- a/template/src/myApp.js +++ b/template/src/myApp.js @@ -1,29 +1,3 @@ -/**************************************************************************** - Copyright (c) 2010-2012 cocos2d-x.org - Copyright (c) 2008-2010 Ricardo Quesada - Copyright (c) 2011 Zynga Inc. - - http://www.cocos2d-x.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ****************************************************************************/ - var MyLayer = cc.Layer.extend({ helloLabel:null, sprite:null, @@ -41,7 +15,7 @@ var MyLayer = cc.Layer.extend({ var size = cc.director.getWinSize(); // add a "close" icon to exit the progress. it's an autorelease object - var closeItem = cc.MenuItemImage.create( + var closeItem = new cc.MenuItemImage( s_CloseNormal, s_CloseSelected, function () { @@ -49,7 +23,7 @@ var MyLayer = cc.Layer.extend({ },this); closeItem.setAnchorPoint(0.5, 0.5); - var menu = cc.Menu.create(closeItem); + var menu = new cc.Menu(closeItem); menu.setPosition(0, 0); this.addChild(menu, 1); closeItem.setPosition(size.width - 20, 20); @@ -58,17 +32,17 @@ var MyLayer = cc.Layer.extend({ // 3. add your codes below... // add a label shows "Hello World" // create and initialize a label - this.helloLabel = cc.LabelTTF.create("Hello World", "Impact", 38); + this.helloLabel = new cc.LabelTTF("Hello World", "Impact", 38); // position the label on the center of the screen this.helloLabel.setPosition(size.width / 2, size.height - 40); // add the label as a child to this layer this.addChild(this.helloLabel, 5); // add "Helloworld" splash screen" - this.sprite = cc.Sprite.create(s_HelloWorld); + this.sprite = new cc.Sprite(s_HelloWorld); this.sprite.setAnchorPoint(0.5, 0.5); this.sprite.setPosition(size.width / 2, size.height / 2); - this.sprite.setScale(size.height/this.sprite.getContentSize().height); + this.sprite.setScale(size.height / this.sprite.getContentSize().height); this.addChild(this.sprite, 0); } }); diff --git a/tools/XmlCheck.js b/tools/XmlCheck.js new file mode 100644 index 0000000000..159933cd37 --- /dev/null +++ b/tools/XmlCheck.js @@ -0,0 +1,143 @@ +const fs = require("fs"); +const path = require("path"); +const modules = JSON.parse(fs.readFileSync("../moduleConfig.json")); + +var contains = [ + "../cocos2d", + "../extensions", + "../external", + "../Base64Images.js", + "../CCBoot.js", + "../CCDebugger.js" +]; +(function(){ + var i = 0; + function read(name){ + if(fs.existsSync(name)){ + var stat = fs.statSync(name); + if(stat.isDirectory()){ + contains.splice(i--, 1); + var fileList = fs.readdirSync(name); + for(var n=0; n((.|\r\n|\r|\n)*?)\<\/sources/g, function(a, b){ + a.replace(/file name\=\"(.*)\"\/\>/g, function(c, d){ + arr[index] && arr[index].push("../" + d); + }); + index++; + }); +})(); +console.log(" The number of files in the XML file : %s", xmlFile.length); + +contains = contains.map(function(a){ + return path.normalize(a); +}); +moduleFile = moduleFile.map(function(a){ + return path.normalize(a); +}); +xmlFile = xmlFile.map(function(a){ + return path.normalize(a); +}); +xmlFile2 = xmlFile2.map(function(a){ + return path.normalize(a); +}); + +console.log("\x1B[0m\x1B[33m"); +console.log(" warn : moduleConfig missing..."); +contains.forEach(function(a){ + if(!moduleFile.some(function(b){return b==a})) + console.log(" " + a); +}); + + +console.log("\x1B[0m\x1B[92m"); +console.log(" warn : engine dir missing..."); +moduleFile.forEach(function(a){ + if(!contains.some(function(b){return b==a})) + console.log(" " + a); +}); + + +console.log("\x1B[0m\x1B[96m"); +console.log(" warn : xml(all) file missing..."); +contains.forEach(function(a){ + if(!xmlFile.some(function(b){return b==a})) + console.log(" " + a); +}); + + +console.log("\x1B[0m\x1B[91m"); +console.log(" warn : xml(all) redundant files..."); +xmlFile.forEach(function(a){ + if(!contains.some(function(b){return b==a})) + console.log(" " + a); +}); + + +console.log("\x1B[0m\x1B[94m"); +console.log(" warn : xml(core) maybe missing files..."); +xmlFile2.forEach(function(a){ + var basename = path.basename(a); + basename = basename.substr(0, basename.indexOf(".")); + contains.forEach(function(b){ + if(b.indexOf(basename) > -1 && a != b){ + if( + b.indexOf("extensions") == -1 && + !xmlFile2.some(function(c){return b == c;}) + ) + console.log(" " + b); + } + }); +}); + + +console.log("\x1B[0m\x1B[35m"); +console.log(" warn : xml(core) redundant files..."); +xmlFile2.forEach(function(a){ + if(!contains.some(function(b){return b==a})) + console.log(" " + a); +}); +console.log("\x1B[0m"); \ No newline at end of file diff --git a/tools/build.xml b/tools/build.xml index c54e093bbd..326af567d2 100644 --- a/tools/build.xml +++ b/tools/build.xml @@ -5,8 +5,8 @@ classpath="./compiler/compiler.jar"/> - + debug="false" output="./../lib/cocos2d-js-v3.6-min.js"> + @@ -15,17 +15,19 @@ + + - + @@ -34,28 +36,43 @@ + + + + + + + + + + + - - + + + + - - - - + + + + + + - - + + @@ -63,7 +80,10 @@ + + + @@ -82,12 +102,24 @@ + + + + + + + + + + + + @@ -102,6 +134,8 @@ + + @@ -113,8 +147,12 @@ + + + + @@ -124,13 +162,18 @@ + + + + + @@ -140,6 +183,8 @@ + + @@ -157,9 +202,18 @@ + + + + + + - + + + + @@ -175,6 +229,7 @@ + @@ -189,11 +244,15 @@ + + + + @@ -207,32 +266,40 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + debug="false" output="./../lib/cocos2d-js-v3.6-core-min.js"> + @@ -242,9 +309,10 @@ - + + @@ -252,25 +320,46 @@ - + + + + + + + - + + + - - + + + + - \ No newline at end of file + diff --git a/tools/compiler/compiler.jar b/tools/compiler/compiler.jar old mode 100755 new mode 100644 diff --git a/tools/genBuildXml.js b/tools/genBuildXml.js index 87d8f00bb0..30da208caa 100644 --- a/tools/genBuildXml.js +++ b/tools/genBuildXml.js @@ -57,11 +57,16 @@ module.exports = function(projectDir, projectJson, buildOpt){ if(arr) ccJsList = ccJsList.concat(arr); } + var externalList = []; function getFileArrStr(jsList){ var str = ""; for(var i = 0, li = jsList.length; i < li; i++){ - str += ' ' - if(i < li - 1) str += '\r\n'; + if(/^external/.test(jsList[i]) && !/Plugin/.test(jsList[i])){ + externalList.push(jsList[i]); + }else{ + str += ' '; + if(i < li - 1) str += '\r\n'; + } } return str; } @@ -80,4 +85,5 @@ module.exports = function(projectDir, projectJson, buildOpt){ buildContent = buildContent.replace(/%userJsList%/gi, getFileArrStr(userJsList)); fs.writeFileSync(path.join(realPublishDir, "build.xml"), buildContent); + return externalList; }; diff --git a/tools/jsdoc_toolkit/build.xml b/tools/jsdoc_toolkit/build.xml index 0198fe08c0..e037685c34 100644 --- a/tools/jsdoc_toolkit/build.xml +++ b/tools/jsdoc_toolkit/build.xml @@ -20,10 +20,13 @@ + + - + + @@ -32,11 +35,15 @@ + - + + + + @@ -56,19 +63,9 @@ - - - - - - @@ -90,7 +87,6 @@ - @@ -109,8 +105,6 @@ - @@ -124,24 +118,9 @@ - - - - - @@ -159,10 +138,15 @@ + + - + + + + @@ -175,11 +159,9 @@ - - - - - + + + @@ -189,7 +171,6 @@ - @@ -212,6 +193,14 @@ + + + + + + + + diff --git a/tools/publish.js b/tools/publish.js index a0802aefa9..4b28867133 100644 --- a/tools/publish.js +++ b/tools/publish.js @@ -21,7 +21,7 @@ var buildOpt = { if(!fs.existsSync(realPublishDir)) core4cc.mkdirSyncRecursive(realPublishDir); -require("./genBuildXml")(projectDir, projectJson, buildOpt); +var externalList = require("./genBuildXml")(projectDir, projectJson, buildOpt); var outputJsPath = path.join(realPublishDir, buildOpt.outputFileName); if(fs.existsSync(outputJsPath)) fs.unlinkSync(outputJsPath); @@ -52,8 +52,21 @@ exec("cd " + realPublishDir + " && ant", function(err, data, info){ core4cc.copyFiles(path.join(projectDir, "res"), publishResDir); var indexContent = fs.readFileSync(path.join(projectDir, "index.html")).toString(); - indexContent = indexContent.replace(/<\/script>/g, ""); + var externalScript = ""; + externalList.forEach(function(external){ + externalScript += "\n"; + }); + indexContent = indexContent.replace(/<\/script>/g, externalScript); indexContent = indexContent.replace(/"main\.js"\s*/, '"' + buildOpt.outputFileName + '"'); + + externalScript = ""; + [ + "external/pluginx/platform/facebook_sdk.js", + "external/pluginx/platform/facebook.js" + ].forEach(function(external){ + externalScript += "\n"; + }); + indexContent += externalScript; fs.writeFileSync(path.join(realPublishDir, "index.html"), indexContent); console.log("Finished!") }); \ No newline at end of file