├── .gitignore ├── LICENSE ├── README.md ├── lib ├── blendmode.js ├── core.js ├── dfont.js ├── ejoy2dgame.js ├── ex01.js ├── ex02.js ├── ex04.js ├── ex05.js ├── ex09.js ├── geometry.js ├── http.js ├── label.js ├── list.js ├── main.js ├── material.js ├── matrix.js ├── path.js ├── render.js ├── renderbuffer.js ├── richtext.js ├── scissor.js ├── screen.js ├── shader.js ├── sprite.js ├── sprite_trans.js ├── spritepack.js ├── string.js ├── text.js ├── texture.js ├── uri.js └── utils.js ├── sample ├── ex01.html ├── ex02.html ├── ex04.html ├── ex05.html ├── sample.1.png └── sample.json ├── simple_http_svr.go └── tools └── ejoy2d2json ├── json.lua └── main.lua /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | static/.vscode 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 小V 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | > ejoy2d_js: jvascript and webGL implementation of ejoy2d 5 | 6 | General 7 | === 8 | javascript and webGL implementation of 2d game engine [ejoy2d](https://github.com/ejoy/ejoy2d) 9 | 10 | now it implements core API of ejoy2d but some feature still missing, include: 11 | 12 | - rich text 13 | - particle 14 | 15 | Tools 16 | === 17 | ejoy2d_js can not use the raw ejoy2d assets,because is lua file. You can use the tool provided by the the repo to convert ejoy2d lua asset to json 18 | 19 | see tools/ejoy2d2json/ 20 | 21 | to run,you should have [lua](http://www.lua.org/) installed, then run: 22 | 23 | `lua main.lua input output` 24 | 25 | it will convert input.lua to output.json 26 | 27 | then you can use output.json as asset for ejoy2d_js 28 | 29 | Run example 30 | === 31 | the repo provide an simple http server implement in go-lang for developer and debug 32 | 33 | see simple_http_svr.go 34 | 35 | to build, you need install [go-lang](https://golang.org) 36 | 37 | and you can build with (assumed the current directory is $GOPATH) 38 | 39 | `go build ejoy2d_js 40 | 41 | ./ejoy2d.js ./src/ejoy2d_js (pass the repo path to the program, to find the assets, js, html etc)` 42 | 43 | then you can open browser 44 | 45 | - localhost:9528/ex01.html 46 | - localhost:9528/ex02.html 47 | - localhost:9528/ex04.html 48 | - localhost:9528/ex05.html 49 | 50 | 51 | all samle files are located in sample fold. 52 | 53 | enjoy 54 | 55 | feel free to contact me via email 56 | 57 | -------------------------------------------------------------------------------- /lib/blendmode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/26. 3 | */ 4 | var BLEND_GL_ZERO = 0; 5 | var BLEND_GL_ONE = 1; 6 | var BLEND_GL_SRC_COLOR = 0x0300; 7 | var BLEND_GL_ONE_MINUS_SRC_COLOR = 0x0301; 8 | var BLEND_GL_SRC_ALPHA = 0x0302; 9 | var BLEND_GL_ONE_MINUS_SRC_ALPHA = 0x0303; 10 | var BLEND_GL_DST_ALPHA = 0x0304; 11 | var BLEND_GL_ONE_MINUS_DST_ALPHA = 0x0305; 12 | var BLEND_GL_DST_COLOR = 0x0306; 13 | var BLEND_GL_ONE_MINUS_DST_COLOR = 0x0307; 14 | var BLEND_GL_SRC_ALPHA_SATURATE = 0x0308; 15 | ejoy2d.blendmode = { 16 | blendMode : function (gl_mode) { 17 | switch(gl_mode) { 18 | case BLEND_GL_ZERO: 19 | return BLEND_ZERO; 20 | case BLEND_GL_ONE: 21 | return BLEND_ONE; 22 | case BLEND_GL_SRC_COLOR: 23 | return BLEND_SRC_COLOR; 24 | case BLEND_GL_ONE_MINUS_SRC_COLOR: 25 | return BLEND_ONE_MINUS_SRC_COLOR; 26 | case BLEND_GL_SRC_ALPHA: 27 | return BLEND_SRC_ALPHA; 28 | case BLEND_GL_ONE_MINUS_SRC_ALPHA: 29 | return BLEND_ONE_MINUS_SRC_ALPHA; 30 | case BLEND_GL_DST_ALPHA: 31 | return BLEND_DST_ALPHA; 32 | case BLEND_GL_ONE_MINUS_DST_ALPHA: 33 | return BLEND_ONE_MINUS_DST_ALPHA; 34 | case BLEND_GL_DST_COLOR: 35 | return BLEND_DST_COLOR; 36 | case BLEND_GL_ONE_MINUS_DST_COLOR: 37 | return BLEND_ONE_MINUS_DST_COLOR; 38 | case BLEND_GL_SRC_ALPHA_SATURATE: 39 | return BLEND_SRC_ALPHA_SATURATE; 40 | } 41 | return BLEND_DISABLE; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /lib/core.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/8/20. 3 | */ 4 | 5 | ejoy2d = {}; 6 | 7 | ejoy2d.extend = function(target, ex) { 8 | var prop, 9 | copy; 10 | 11 | for(prop in ex) { 12 | copy = ex[prop]; 13 | if(pc.type(copy) == "object") { 14 | target[prop] = pc.extend({}, copy); 15 | } else if(pc.type(copy) == "array") { 16 | target[prop] = pc.extend([], copy); 17 | } else { 18 | target[prop] = copy; 19 | } 20 | } 21 | return target; 22 | }; 23 | 24 | /** 25 | * Return true if the Object is not undefined 26 | * @param {Object} o The Object to test 27 | * @returns {Boolean} True if the Object is not undefined 28 | * @function 29 | * @name pc.isDefined 30 | */ 31 | ejoy2d.isDefined= function(o) { 32 | var a; 33 | return (o !== a); 34 | }; 35 | 36 | /** 37 | * Convert an array-like object into a normal array. 38 | * For example, this is useful for converting the arguments object into an array. 39 | * @param {Object} arr The array to convert 40 | * @return {Array} An array 41 | * @function 42 | * @name pc.makeArray 43 | */ 44 | ejoy2d.makeArray = function (arr) { 45 | var i, 46 | ret = [], 47 | length = arr.length; 48 | 49 | for(i = 0; i < length; ++i) { 50 | ret.push(arr[i]); 51 | } 52 | 53 | return ret; 54 | }; -------------------------------------------------------------------------------- /lib/dfont.js: -------------------------------------------------------------------------------- 1 | 2 | ejoy2d.dfont = function (width, height) { 3 | this.width = width; 4 | this.height = height; 5 | this.max_line = 0; 6 | this.version = 0; 7 | 8 | this._init(); 9 | }; 10 | 11 | ejoy2d.dfont.prototype = (function(){ 12 | var HASH_SIZE = 4096; 13 | var TINY_FONT = 12; 14 | 15 | var ListNode = function() { 16 | this.prev = this; 17 | this.next = this; 18 | } 19 | 20 | ListNode.prototype = { 21 | setData : function(data) { 22 | this.data = data; 23 | }, 24 | del: function (){ 25 | var prev = this.prev; 26 | var next = this.next; 27 | if(next) { 28 | next.prev = prev; 29 | } 30 | if(prev) { 31 | prev.next = next; 32 | } 33 | this.prev = null; 34 | this.next = null; 35 | }, 36 | add_after : function(p) { 37 | this.next = p.next; 38 | this.prev = p; 39 | if(p.next.prev) 40 | p.next.prev = this; 41 | p.next = this; 42 | }, 43 | add_before : function(p) { 44 | this.next = p; 45 | this.prev = p.prev; 46 | if(p.prev) { 47 | p.prev.next = this; 48 | } 49 | p.prev = this; 50 | } 51 | }; 52 | 53 | 54 | var HashRect = function(){ 55 | this.next_char = new ListNode(); 56 | this.next_char.setData(this); 57 | this.time = new ListNode(); 58 | this.time.setData(this); 59 | // struct hash_rect * next_hash; 60 | // struct list_head next_char; 61 | // struct list_head time; 62 | // int version; 63 | // int c; 64 | // int line; 65 | // int font; 66 | // int edge; 67 | // struct dfont_rect rect; 68 | }; 69 | var Line = function( start, h, space) { 70 | this.start_line = start; 71 | this.height = h; 72 | this.space = space; 73 | this.head = new ListNode(); 74 | } 75 | 76 | 77 | var hash = function(c, font, edge) { 78 | if (edge != 0) { 79 | edge = 1; 80 | } 81 | return (((c ^ (font * 97))<<1)|edge) % HASH_SIZE; 82 | }; 83 | 84 | 85 | return { 86 | _init : function() { 87 | var maxLine = Math.floor(this.height / TINY_FONT); 88 | var maxChar = Math.floor(maxLine * this.width / TINY_FONT); 89 | var fl = new HashRect(); 90 | var pre = fl; 91 | for(var i = 1; i < maxChar; ++i) { 92 | var r = new HashRect(); 93 | pre.next_hash = r; 94 | pre = r; 95 | } 96 | this.freelist = fl; 97 | this.hash = []; 98 | this.time = new ListNode(); 99 | this.line = []; 100 | }, 101 | 102 | _new_line:function(height) { 103 | var start_line = 0; 104 | if (this.max_line > 0) { 105 | var lastline = this.line[this.max_line-1]; 106 | start_line = lastline.start_line + lastline.height; 107 | } 108 | if (start_line + height > this.height) 109 | return -1; 110 | var max = Math.floor(this.height / TINY_FONT); 111 | if (this.max_line >= max) 112 | return -1; 113 | var idx = this.max_line; 114 | this.max_line = this.max_line +1; 115 | var line = new Line(start_line, height, this.width); 116 | this.line[idx] = line; 117 | return idx; 118 | }, 119 | 120 | _find_line: function(width, height) { 121 | // console.log("---->>> max line", this.max_line, width, height); 122 | for (var i=0; i < this.max_line; i++) { 123 | var line = this.line[i]; 124 | // console.log("---??? check line:", i, line.height, line.space); 125 | if (height == line.height && width <= line.space) { 126 | return i; 127 | } 128 | } 129 | return this._new_line(height); 130 | }, 131 | 132 | _new_node:function() { 133 | if (!this.freelist) 134 | return null; 135 | ret = this.freelist; 136 | this.freelist = ret.next_hash; 137 | if(!ret.rect) 138 | ret.rect = {}; 139 | return ret; 140 | }, 141 | 142 | _find_space : function(line, width) { 143 | var start_pos = 0; 144 | var hr; 145 | var max_space = 0; 146 | var head = line.head; 147 | var hr = head.next; 148 | while(hr != head) { 149 | var data = hr.data; 150 | var space = data.rect.x - start_pos; 151 | if (space >= width) { 152 | var n = this._new_node(); 153 | if ( !n ) 154 | return null; 155 | n.line = line; 156 | n.rect.x = start_pos; 157 | n.rect.y = line.start_line; 158 | n.rect.w = width; 159 | n.rect.h = line.height; 160 | 161 | // add to tail of line.char 162 | n.next_char.add_before(hr); 163 | return n; 164 | } 165 | 166 | if (space > max_space) { 167 | max_space = space; 168 | } 169 | start_pos = data.rect.x + data.rect.w; 170 | hr = hr.next; 171 | } 172 | var space = this.width - start_pos; 173 | if (space < width) { 174 | if (space > max_space) { 175 | line.space = space; 176 | } else { 177 | line.space = max_space; 178 | } 179 | console.log("--------->>> aoaooa 1111"); 180 | return null; 181 | } 182 | var n = this._new_node(); 183 | if (!n) { 184 | console.log("--------->>> aoaooa"); 185 | return null; 186 | } 187 | 188 | n.line = line; 189 | n.rect.x = start_pos; 190 | n.rect.y = line.start_line; 191 | n.rect.w = width; 192 | n.rect.h = line.height; 193 | 194 | // add n to the tail of line.char 195 | n.next_char.add_before(head); 196 | return n; 197 | }, 198 | _adjust_space:function(hr) { 199 | var line = this.line[hr.line]; 200 | if (hr.next_char.next == line.head) { 201 | hr.rect.w = this.width - this.rect.x; 202 | } else { 203 | var next = hr.next_char.data; 204 | hr.rect.w = next.rect.x - hr.rect.x; 205 | } 206 | 207 | if (hr.next_char.prev == line.head) { 208 | hr.rect.w += hr.rect.x; 209 | hr.rect.x = 0; 210 | } else { 211 | var prev = hr.next_char.prev.data; 212 | var x = prev.rect.x + prev.rect.w; 213 | hr.rect.w += hr.rect.x - x; 214 | hr.rect.x = x; 215 | } 216 | if (hr.rect.w > line.space) { 217 | line.space = hr.rect.w; 218 | } 219 | }, 220 | _release_char:function(c, font, edge) { 221 | var h = hash(font, edge); 222 | var hr = this.hash[h]; 223 | if (hr.c == c && hr.font == font && hr.edge == edge) { 224 | this.hash[h] = hr.next_hash; 225 | hr.time.del(); 226 | this._adjust_space(hr); 227 | return hr; 228 | } 229 | var last = hr.data; 230 | hr = hr.next_hash; 231 | while (hr) { 232 | var data = hr.data; 233 | if (c == data.c && data.font == font && data.edge == edge) { 234 | last.next_hash = data.next_hash; 235 | hr.time.del(); 236 | this._adjust_space(hr); 237 | return hr; 238 | } 239 | last = data; 240 | hr = hr.next_hash; 241 | } 242 | console.assert(0); 243 | return null; 244 | }, 245 | _release_space:function(width, height) { 246 | var hr, tmp; 247 | var hr = this.time.next; 248 | while(hr != this.time) { 249 | var data = hr.data; 250 | if (data.version == this.version) 251 | continue; 252 | if (data.rect.h != height) { 253 | continue; 254 | } 255 | var ret = this._release_char(data.c, data.font, data.edge); 256 | var w = data.rect.w; 257 | if (w >= width) { 258 | ret.rect.w = width; 259 | return ret; 260 | } else { 261 | ret.next_char.del(); 262 | //list_del(&ret->next_char); 263 | ret.next = this.freelist; 264 | this.freelist = ret; 265 | } 266 | hr = hr.next; 267 | } 268 | return null; 269 | }, 270 | _insert_char:function(c, font, hr, edge) { 271 | hr.c = c; 272 | hr.font = font; 273 | hr.edge = edge; 274 | hr.version = this.version; 275 | hr.time.add_before(this.time); 276 | var h = hash(c, font, edge); 277 | hr.next_hash = this.hash[h]; 278 | this.hash[h] = hr; 279 | return hr.rect; 280 | }, 281 | 282 | _move_to_time_tail : function(hr) { 283 | var last = this.time.prev_time; 284 | last.next_time = hr; 285 | hr.prev_time = last; 286 | hr.next = this.time; 287 | this.time.prev_time = hr; 288 | }, 289 | _move_to_time_head : function(hr) { 290 | var head = this.time.next_time; 291 | hr.next_time = head; 292 | head.prev_time = hr; 293 | hr.prev_time = this.time; 294 | this.time.next_time = hr; 295 | }, 296 | 297 | 298 | /*-------------API----------------------*/ 299 | 300 | lookup:function (c, font, edge) { 301 | 302 | var h = hash(c, font, edge); 303 | var hr = this.hash[h]; 304 | while (hr) { 305 | if (hr.c == c && hr.font == font && hr.edge == edge) { 306 | hr.time.del(); 307 | hr.time.add_before(this.time); 308 | hr.version = this.version; 309 | return hr.rect; 310 | } 311 | hr = hr.next_hash; 312 | } 313 | return null; 314 | }, 315 | 316 | flush: function(){ 317 | this.version++; 318 | }, 319 | insert : function(c, font, width, height, edge) { 320 | if (width > this.width) 321 | return null; 322 | var rlt = this.lookup(c, font, edge); 323 | console.assert(rlt == null); 324 | while(true) { 325 | var line = this._find_line(width, height); 326 | if (line == -1) 327 | break; 328 | var hr = this._find_space(this.line[line], width); 329 | if (hr) { 330 | return this._insert_char(c ,font, hr, edge); 331 | } 332 | } 333 | var hr = this._release_space(width, height); 334 | if (hr) { 335 | return this._insert_char(c, font, hr, edge); 336 | } 337 | return null; 338 | }, 339 | remove : function(c, font, edge) { 340 | var h = hash(c, font, edge); 341 | var hr = this.hash[h]; 342 | while (hr) { 343 | if (hr.c == c && data.font == font && hr.edge == edge) { 344 | hr.time.del(); 345 | hr.time.add_after(this.time); 346 | // this._move_to_time_head(hr); 347 | hr.version = this.version-1; 348 | return; 349 | } 350 | hr = hr.next_hash; 351 | } 352 | } 353 | }; 354 | })(); 355 | -------------------------------------------------------------------------------- /lib/ejoy2dgame.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/27. 3 | */ 4 | 5 | var InputType = { 6 | TOUCH_BEGIN : 0, 7 | TOUCH_END : 1, 8 | TOUCH_MOVE : 2 9 | }; 10 | 11 | ejoy2d.game = function(fw) { 12 | _G.OS = "js"; 13 | this.fw = fw; 14 | 15 | ejoy2d.shader.init(); 16 | ejoy2d.screen.init(1024, 768, 1.0); 17 | 18 | ejoy2d.label.init(); 19 | ejoy2d.label.load(); 20 | this.real_time = 0.0; 21 | this.logic_time = 0.0; 22 | this.LOGIC_FRAME = 30; 23 | this.oneInvFrame = 1.0/30.0; 24 | }; 25 | 26 | 27 | 28 | ejoy2d.game.prototype = { 29 | exit:function(fw) { 30 | ejoy2d.label.unload(); 31 | ejoy2d.texture.exit(); 32 | ejoy2d.shader.unload(); 33 | }, 34 | 35 | setLogicFrame:function(fram_rate){ 36 | this.LOGIC_FRAME = frameRate; 37 | this.oneInvFrame = 1.0/frameRate; 38 | }, 39 | 40 | update:function(dt) { 41 | // if (this.logic_time == 0.0) { 42 | // this.real_time = this.oneInvFrame; 43 | // } else { 44 | // this.real_time += dt; 45 | // } 46 | // console.log("time:", this.logic_time, this.real_time, dt); 47 | // while (this.logic_time < this.real_time) { 48 | // this.fw.logicFrame(); 49 | // this.logic_time += this.oneInvFrame; 50 | // } 51 | this.fw.logicFrame(); 52 | }, 53 | draw:function() { 54 | this.fw.draw(); 55 | ejoy2d.shader.flush(); 56 | ejoy2d.label.flush(); 57 | }, 58 | touch:function(id, x, y, status) { 59 | this.fw.touch(status, x, y); 60 | }, 61 | gesture:function(ty, x1, y1, x2, y2, s) { 62 | this.fw.gesture(ty, x1, y1, x2, y2, s); 63 | }, 64 | message:function(id, state, data, n) { 65 | this.fw.message(state, data, n); 66 | }, 67 | pause:function(){ 68 | this.fw.pause(); 69 | }, 70 | resume:function(){ 71 | this.fw.resume(); 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /lib/ex01.js: -------------------------------------------------------------------------------- 1 | var ex01 =((function(){ 2 | 3 | 4 | var isInited = false; 5 | 6 | var obj; 7 | var turret; 8 | var obj2; 9 | 10 | 11 | 12 | var srt = { 13 | offx:512*SCREEN_SCALE, 14 | offy:384*SCREEN_SCALE, 15 | scalex : 1024 * 1.2, 16 | scaley : 1024 * 1.2, 17 | rot: 0 18 | }; 19 | 20 | //var img_src = document.getElementsByName("img_src").getAttribute(src); 21 | ///console.log("-------------->>????aoaoao--->>", img_src); 22 | 23 | return { 24 | init:function() { 25 | //shader.load(geometryShaderID, geoFS, geoVS); 26 | // shader.load(BuiltinProgram.picture, spriteFS, spriteVS); 27 | //geometry.setprogram(geometryShaderID); 28 | var img = new Image(); 29 | img.src = "sample.1.png"; 30 | img.onload = function() { 31 | console.log(img.name, img.width, img.height); 32 | console.log("load texture succeed", typeof img); 33 | ejoy2d.texture.load_img(1, TEXTURE_RGBA8, img); 34 | ejoy2d.http.get("sample.json",function(resp) { 35 | if(resp != null) { 36 | console.log("get sample.json succeed"); 37 | var sp = new ejoy2d.spritepack(resp,null); 38 | var id = sp.getIDByName("cannon"); 39 | obj = new ejoy2d.sprite(sp, id); 40 | turret = obj.fetch("turret"); 41 | obj.ps(-100, 0, 0.5); 42 | 43 | id = sp.getIDByName("mine"); 44 | obj2 = new ejoy2d.sprite(sp, id); 45 | 46 | obj2.ps(100, 0); 47 | obj2.ps(1.2); 48 | 49 | var resource = obj2.fetch("resource") 50 | resource.setframe(10, false); 51 | 52 | var label = obj2.fetch("label"); 53 | var aabb = []; 54 | obj2.aabb(srt, true, aabb); 55 | var w = Math.floor(aabb[2] - aabb[0]); 56 | var h = Math.floor(aabb[3] - aabb[1]); 57 | var aabbStr = "AABB:" + w.toString() + "x" + h.toString(); 58 | label.setText(aabbStr); 59 | 60 | isInited = true; 61 | } 62 | }); 63 | }; 64 | img.onerror = function () { 65 | console.log("Failed to load image: sample.1.png"); 66 | } 67 | }, 68 | logicFrame:function() 69 | { 70 | if(isInited) { 71 | turret.setframe(turret.frame +1, false); 72 | obj2.setframe(obj2.frame +1, false); 73 | } 74 | }, 75 | draw:function(){ 76 | shader.clear(0xff808080); 77 | if (isInited) { 78 | obj.draw(srt); 79 | obj2.draw(srt); 80 | } 81 | } 82 | }; 83 | 84 | })()); 85 | -------------------------------------------------------------------------------- /lib/ex02.js: -------------------------------------------------------------------------------- 1 | var ex02 =((function(){ 2 | 3 | var isInited = false; 4 | var TEX_ID = 1; 5 | 6 | var vb = [ 7 | 88, 0, 88, 45, 147, 45, 147, 0, // texture coord 8 | -958, -580, -958, 860, 918, 860, 918, -580, // screen coord, 16x pixel, (0,0) is the center of screen 9 | ] 10 | 11 | return { 12 | init:function() { 13 | var img = new Image(); 14 | img.src = "sample.1.png"; 15 | img.onload = function() { 16 | console.log(img.name, img.width, img.height); 17 | console.log("load texture succeed", typeof img); 18 | ejoy2d.texture.load_img(TEX_ID, TEXTURE_RGBA8, img); 19 | isInited = true; 20 | }; 21 | img.onerror = function () { 22 | console.log("Failed to load image: sample.1.png"); 23 | } 24 | }, 25 | logicFrame:function() 26 | { 27 | }, 28 | draw:function(){ 29 | shader.clear(0xff808080); 30 | if (isInited) { 31 | ejoy2d.shader.draw(TEX_ID, vb) 32 | } 33 | } 34 | }; 35 | 36 | })()); 37 | -------------------------------------------------------------------------------- /lib/ex04.js: -------------------------------------------------------------------------------- 1 | var ex04 =((function(){ 2 | 3 | 4 | var isInited = false; 5 | 6 | var obj; 7 | 8 | var srt = { 9 | offx:512*SCREEN_SCALE, 10 | offy:384*SCREEN_SCALE, 11 | scalex : 1024 * 1.2, 12 | scaley : 1024 * 1.2, 13 | rot: 0 14 | }; 15 | 16 | var scissor = false; 17 | 18 | return { 19 | init:function() { 20 | //shader.load(geometryShaderID, geoFS, geoVS); 21 | // shader.load(BuiltinProgram.picture, spriteFS, spriteVS); 22 | //geometry.setprogram(geometryShaderID); 23 | var img = new Image(); 24 | img.src = "sample.1.png"; 25 | img.onload = function() { 26 | console.log(img.name, img.width, img.height); 27 | console.log("load texture succeed", typeof img); 28 | ejoy2d.texture.load_img(1, TEXTURE_RGBA8, img); 29 | ejoy2d.http.get("sample.json",function(resp) { 30 | if(resp != null) { 31 | console.log("get sample.json succeed"); 32 | var sp = new ejoy2d.spritepack(resp,null); 33 | 34 | var id = sp.getIDByName("mine"); 35 | obj = new ejoy2d.sprite(sp, id); 36 | 37 | //obj.ps(100, 0); 38 | //obj.ps(1.2); 39 | 40 | var resource = obj.fetch("resource") 41 | resource.setframe(10, false); 42 | isInited = true; 43 | } 44 | }); 45 | }; 46 | img.onerror = function () { 47 | console.log("Failed to load image: sample.1.png"); 48 | } 49 | }, 50 | logicFrame:function() 51 | { 52 | if(isInited) { 53 | obj.setframe(obj.frame +1, false); 54 | } 55 | }, 56 | draw:function(){ 57 | shader.clear(0xff808080); 58 | if (isInited) { 59 | obj.draw(srt); 60 | } 61 | }, 62 | touch:function(what, x, y) { 63 | //console.log("---->>> aoaoao touch:", what, x, y); 64 | if(what == InputType.TOUCH_END) { 65 | var touched = obj.test(x*SCREEN_SCALE, y*SCREEN_SCALE, srt); 66 | if(touched) { 67 | if(touched.name == "label") { 68 | touched.setText("Touch label"); 69 | } 70 | if(touched.name == "panel") { 71 | scissor = !scissor; 72 | touched.enableScissor(scissor); 73 | var label = obj.fetch("label"); 74 | label.setText(scissor?"Set Scissor":"Clear Scor"); 75 | } 76 | } 77 | else 78 | { 79 | var label = obj.fetch("label"); 80 | label.setText("Not Hit"); 81 | } 82 | 83 | } 84 | } 85 | }; 86 | 87 | })()); 88 | -------------------------------------------------------------------------------- /lib/ex05.js: -------------------------------------------------------------------------------- 1 | var ex05 =((function(){ 2 | 3 | var isInited = false; 4 | var obj; 5 | var turret; 6 | var frame = 0; 7 | 8 | var srt = { 9 | offx:512*SCREEN_SCALE, 10 | offy:384*SCREEN_SCALE, 11 | scalex : 1024, 12 | scaley : 1024, 13 | rot: 0 14 | }; 15 | 16 | return { 17 | init:function() { 18 | //shader.load(geometryShaderID, geoFS, geoVS); 19 | // shader.load(BuiltinProgram.picture, spriteFS, spriteVS); 20 | //geometry.setprogram(geometryShaderID); 21 | var img = new Image(); 22 | img.src = "sample.1.png"; 23 | img.onload = function() { 24 | console.log(img.name, img.width, img.height); 25 | console.log("load texture succeed", typeof img); 26 | ejoy2d.texture.load_img(1, TEXTURE_RGBA8, img); 27 | ejoy2d.http.get("sample.json",function(resp) { 28 | if(resp != null) { 29 | console.log("get sample.json succeed"); 30 | var sp = new ejoy2d.spritepack(resp,null); 31 | var id = sp.getIDByName("cannon"); 32 | obj = new ejoy2d.sprite(sp, id); 33 | turret = obj.fetch("turret"); 34 | 35 | var labelData ={ 36 | data :[ 37 | { 38 | type : SpriteType.label, 39 | color : 0xffffffff, 40 | width : 100, 41 | height : 100, 42 | align : 0, 43 | size : 30, 44 | edge : false, 45 | auto_scale : true, 46 | } 47 | ] 48 | }; 49 | var label = new ejoy2d.sprite(labelData, 0); 50 | label.setText("Hello"); 51 | var idx = turret.child("anchor"); 52 | console.log(idx); 53 | turret.mount(idx, label); 54 | isInited = true; 55 | } 56 | }); 57 | }; 58 | img.onerror = function () { 59 | console.log("Failed to load image: sample.1.png"); 60 | } 61 | }, 62 | logicFrame:function() { 63 | if(isInited) { 64 | turret.setframe(turret.frame +1, false); 65 | } 66 | }, 67 | draw:function(){ 68 | shader.clear(0xff808080); 69 | if (isInited) { 70 | obj.draw(srt); 71 | } 72 | }, 73 | touch:function(what, x, y) { 74 | 75 | if(what == InputType.TOUCH_END) { 76 | frame = frame +1; 77 | console.log(frame) 78 | } 79 | 80 | } 81 | }; 82 | 83 | })()); 84 | -------------------------------------------------------------------------------- /lib/ex09.js: -------------------------------------------------------------------------------- 1 | var ex09 =((function(){ 2 | var x = 0; 3 | var y = 768; 4 | 5 | var geometryShaderID = 3; 6 | 7 | 8 | var hexagon = new Array(10); 9 | for(var i =0; i < 5;++i) 10 | { 11 | var r = Math.PI * 2 * i / 6 12 | hexagon[i*2] = Math.sin(r) * 100 + 300; 13 | hexagon[i*2 +1] = Math.cos(r) * 100 + 300; 14 | } 15 | 16 | var gspr; 17 | var turret; 18 | 19 | var srt = { 20 | offx:500*SCREEN_SCALE, 21 | offy:384*SCREEN_SCALE, 22 | scalex : 1024, 23 | scaley : 1024, 24 | rot: 0 25 | }; 26 | 27 | //var img_src = document.getElementsByName("img_src").getAttribute(src); 28 | ///console.log("-------------->>????aoaoao--->>", img_src); 29 | 30 | return { 31 | init:function() { 32 | //shader.load(geometryShaderID, geoFS, geoVS); 33 | // shader.load(BuiltinProgram.picture, spriteFS, spriteVS); 34 | //geometry.setprogram(geometryShaderID); 35 | var img = new Image(); 36 | img.src = "sample.1.png"; 37 | img.onload = function() { 38 | console.log(img.name, img.width, img.height); 39 | console.log("load texture succeed", typeof img); 40 | ejoy2d.texture.load_img(1, TEXTURE_RGBA8, img); 41 | ejoy2d.http.get("sample.json",function(resp) { 42 | if(resp != null) { 43 | console.log("get sample.json succeed"); 44 | console.log(typeof resp); 45 | var sp = new ejoy2d.spritepack(resp,null); 46 | var id = sp.getIDByName("mine"); 47 | gspr = new ejoy2d.sprite(sp, id); 48 | var label = gspr.fetch("label"); 49 | var resource = gspr.fetch("resource") 50 | resource.setframe(10, false); 51 | gspr.setframe(11, false); 52 | label.setText("你好,webgl"); 53 | // turret = gspr.fetch("turret"); 54 | //this.spr.Init(); 55 | } 56 | }); 57 | }; 58 | img.onerror = function () { 59 | console.log("Failed to load image: sample.1.png"); 60 | } 61 | //ejoy2d.http.get("sample.1.png",function(resp) { 62 | // // console.log(resp); 63 | // console.log("load texture succeed"); 64 | // ejoy2d.http.get("sample.json",function(resp) { 65 | // if(resp != null) { 66 | // console.log("get sample.json succeed"); 67 | // console.log(typeof resp); 68 | // var sp = new ejoy2d.spritepack(resp,null); 69 | // var id = sp.getIDByName("cannon"); 70 | // gspr = new ejoy2d.sprite(sp, id); 71 | // //this.spr.Init(); 72 | // } 73 | // }); 74 | //}); 75 | }, 76 | logicFrame:function() 77 | { 78 | // if(turret) 79 | // { 80 | // turret.setframe(turret.frame +1, false); 81 | // // console.log("---------<>>>", gspr.frame); 82 | // } 83 | if(gspr) { 84 | gspr.setframe(gspr.frame +1, false); 85 | // console.log("---------<>>>", gspr.frame); 86 | } 87 | }, 88 | draw:function(){ 89 | shader.clear(0xff808080); 90 | if (gspr) 91 | { 92 | gspr.draw(srt); 93 | } 94 | //geometry.line(0, 0, x, y, 0xffffffff); 95 | //geometry.box(100,100,200,300, 0x80ff0000); 96 | //geometry.polygon(hexagon, 0x40ffff00); 97 | } 98 | }; 99 | 100 | })()); 101 | -------------------------------------------------------------------------------- /lib/geometry.js: -------------------------------------------------------------------------------- 1 | 2 | ejoy2d.geometry = (function(){ 3 | var PROGRAM =0; 4 | var convert_color = function(c) { 5 | var alpha = (c >> 24) & 0xff; 6 | if (alpha == 0xff) { 7 | return c; 8 | } 9 | if (alpha == 0) { 10 | return c | 0xff000000; 11 | } 12 | var red = (c >> 16) & 0xff; 13 | var green = (c >> 8) & 0xff; 14 | var blue = (c) & 0xff; 15 | red = red * alpha / 255; 16 | green = green * alpha / 255; 17 | blue = blue * alpha / 255; 18 | 19 | return alpha << 24 | red << 16 | green << 8 | blue; 20 | }; 21 | return { 22 | setprogram:function(p) { 23 | PROGRAM = p; 24 | return 0; 25 | }, 26 | /* 27 | float[4] endpointer x1,y1,x2,y2 28 | uint32_t color 29 | */ 30 | line: function(x1,y1,x2,y2,c) { 31 | x1 = x1 * SCREEN_SCALE; 32 | y1 = y1 * SCREEN_SCALE; 33 | x2 = x2 * SCREEN_SCALE; 34 | y2 = y2 * SCREEN_SCALE; 35 | var color = convert_color(c); 36 | var vp = new Array(4*4); 37 | vp[0] = x1; 38 | vp[0 +1] = y1; 39 | vp[4 +0] = x2; 40 | vp[4 +1] = y2; 41 | if (Math.abs(x1-x2) > Math.abs(y1-y2)) { 42 | vp[8] = x2; 43 | vp[8+1]= y2+SCREEN_SCALE; 44 | vp[12] = x1; 45 | vp[12 +1] = y1+SCREEN_SCALE; 46 | } else { 47 | vp[8] = x2+SCREEN_SCALE; 48 | vp[8 +1] = y2; 49 | vp[12] = x1+SCREEN_SCALE; 50 | vp[12 +1] = y1; 51 | } 52 | 53 | for (var i=0;i<4;i++) { 54 | var base = i*4; 55 | vp[base +2] = 0; 56 | vp[base +3] = 0; 57 | var rlt = ejoy2d.screen.trans(vp[base +0], vp[base +1]); 58 | vp[base +0] = rlt[0]; 59 | vp[base +1] = rlt[1]; 60 | } 61 | shader.program(PROGRAM); 62 | shader.do_draw(vp, color, 0); 63 | return 0; 64 | }, 65 | /* 66 | float x,y 67 | float w,h 68 | uint32_t color 69 | */ 70 | box: function(x, y, w, h, c) { 71 | x = x * SCREEN_SCALE; 72 | y = y * SCREEN_SCALE; 73 | w = w * SCREEN_SCALE; 74 | h = h * SCREEN_SCALE; 75 | var color = convert_color(c); 76 | var vp = new Array(4*4); 77 | vp[0] = x; 78 | vp[0+1] = y; 79 | vp[4] = x+w; 80 | vp[4+1] = y; 81 | vp[8] = x+w; 82 | vp[8+1] = y+h; 83 | vp[12] = x; 84 | vp[12+1] = y+h; 85 | for (var i=0;i<4;i++) { 86 | var base = i*4; 87 | vp[base +2] = 0; 88 | vp[base +3] = 0; 89 | var rlt = ejoy2d.screen.trans(vp[base +0], vp[base +1]); 90 | vp[base +0] = rlt[0]; 91 | vp[base +1] = rlt[1]; 92 | } 93 | shader.program(PROGRAM); 94 | //console.log("----------->>> shader:", vp); 95 | shader.do_draw(vp, color, 0); 96 | }, 97 | /* 98 | table float[] 99 | uint32_t color 100 | */ 101 | polygon:function(vs,c) { 102 | var color = convert_color(c); 103 | var n = vs.length; 104 | var point = n/2; 105 | var vb = new Array(point*4); 106 | for (var i=0;i>>>>", i ,vs[i*2], vs[i*2 +1]); 110 | var rlt = ejoy2d.screen.trans(vx,vy); 111 | vb[i*4] = rlt[0]; 112 | vb[i*4+1] = rlt[1]; 113 | vb[i*4+2] = 0; 114 | vb[i*4+3] = 0; 115 | //console.log("--->>",i,vb[i*4], vb[i*4 +1], vb[i*4 +2], vb[i*4 +3]); 116 | } 117 | shader.program(PROGRAM); 118 | if (point == 4) { 119 | shader.draw(vb, color, 0); 120 | } else { 121 | shader.drawpolygon(point, vb, color); 122 | } 123 | } 124 | }; 125 | })(); 126 | -------------------------------------------------------------------------------- /lib/http.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/8/20. 3 | */ 4 | 5 | ejoy2d.http = (function(){ 6 | /** 7 | * @private 8 | * @enum {String} 9 | * @name ContentType 10 | * @description An enum of the most common content types 11 | */ 12 | var ContentType = { 13 | FORM_URLENCODED : "application/x-www-form-urlencoded", 14 | GIF : "image/gif", 15 | JPEG : "image/jpeg", 16 | DDS : "image/dds", 17 | JSON : "application/json", 18 | PNG : "image/png", 19 | TEXT : "text/plain", 20 | XML : "application/xml", 21 | WAV : "audio/x-wav", 22 | OGG : "audio/ogg", 23 | MP3 : "audio/mpeg", 24 | BIN : "application/octet-stream" 25 | }; 26 | 27 | var ResponseType = { 28 | TEXT: 'text', 29 | ARRAY_BUFFER: 'arraybuffer', 30 | BLOB: 'blob', 31 | DOCUMENT: 'document' 32 | }; 33 | 34 | var binaryExtensions = [ 35 | '.model', 36 | '.wav', 37 | '.ogg', 38 | '.mp3', 39 | '.dds' 40 | ]; 41 | 42 | return { 43 | /** 44 | * @function 45 | * @name ejoy2d.http.get 46 | * @description Perform an HTTP GET request to the given url. 47 | * @param {String} url 48 | * @param {Function} success Callback passed response text. 49 | * @param {Object} [options] Additional options 50 | * @param {Object} [options.params] Parameter to be encoded and added to the url as a query string 51 | * @param {Object} [options.error] Callback used on error called with arguments (status, xhr, exception) 52 | * @param {Object} [options.headers] HTTP headers to add to the request 53 | * @param {Object} [options.cache] If false, then add a timestamp to the request to prevent caching 54 | * @param {XmlHttpRequest} [xhr] An XmlHttpRequest object. If one isn't provided a new one will be created. 55 | */ 56 | get: function (url, success, options, xhr) { 57 | options = options || {}; 58 | options.success = success; 59 | return this.request("GET", url, options, xhr); 60 | }, 61 | 62 | /** 63 | * @function 64 | * @name ejoy2d.http.post 65 | * @description Perform an HTTP POST request to the given url 66 | * @param {String} url 67 | * @param {Function} success - callback passed response text. 68 | * @param {Object | FormData | Document} data Data to send to the server. 69 | * @param {Object} [options] Additional options 70 | * @param {Object} [options.error] Callback used on error called with arguments (status, xhr, exception) 71 | * @param {Object} [options.headers] HTTP headers to add to the request 72 | * @param {Object} [options.cache] If false, then add a timestamp to the request to prevent caching 73 | * @param {XmlHttpRequest} [xhr] An XmlHttpRequest object. If one isn't provided a new one will be created. 74 | */ 75 | post: function (url, success, data, options, xhr) { 76 | options = options || {}; 77 | options.success = success; 78 | options.postdata = data; 79 | return this.request("POST", url, options, xhr); 80 | }, 81 | 82 | /** 83 | * @function 84 | * @name ejoy2d.http.put 85 | * @description Perform an HTTP PUT request to the given url 86 | * @param {String} url 87 | * @param {Function} success callback passed response text 88 | * @param {Object | FormData | Document} data Data to send to the server. 89 | * @param {Object} [options] Additional options 90 | * @param {Object} [options.error] Callback used on error called with arguments (status, xhr, exception) 91 | * @param {Object} [options.headers] HTTP headers to add to the request 92 | * @param {Object} [options.cache] If false, then add a timestamp to the request to prevent caching 93 | * @param {XmlHttpRequest} [xhr] An XmlHttpRequest object. If one isn't provided a new one will be created. 94 | */ 95 | put: function (url, success, data, options, xhr) { 96 | options = options || {}; 97 | options.success = success; 98 | options.postdata = data; 99 | return this.request("PUT", url, options, xhr); 100 | }, 101 | 102 | /** 103 | * @function 104 | * @name ejoy2d.http.del 105 | * @description Perform an HTTP DELETE request to the given url 106 | * @param {Object} url 107 | * @param {Object} success 108 | * @param {Object} options 109 | * @param {XmlHttpRequest} xhr 110 | */ 111 | del: function (url, success, options, xhr) { 112 | options = options || {}; 113 | options.success = success; 114 | return this.request("DELETE", url, options, xhr); 115 | }, 116 | 117 | /** 118 | * Make an XmlHttpRequest to the given url 119 | * @param {String} method 120 | * @param {String} url 121 | * @param {Object} [options] Additional options 122 | * @param {Object} [options.success] Callback used on success called with arguments (response, status, xhr) 123 | * @param {Object} [options.error] Callback used on error called with arguments (status, xhr, exception) 124 | * @param {Object} [options.headers] HTTP headers to add to the request 125 | * @param {Document | Object} [options.postdata] Data to send in the body of the request. 126 | * Some content types are handled automatically, If postdata is an XML Document it is handled, if the Content-Type header is set to 'application/json' then 127 | * the postdata is JSON stringified, otherwise by default the data is sent as form-urlencoded 128 | * @param {Object} [options.cache] If false, then add a timestamp to the request to prevent caching 129 | * @param {XmlHttpRequest} [xhr] An XmlHttpRequest object. If one isn't provided a new one will be created. 130 | */ 131 | request: function (method, url, options, xhr) { 132 | var uri, query, timestamp, postdata; 133 | var errored = false; 134 | 135 | options = options || {}; 136 | 137 | // fill in dummy implementations of success, error to simplify callbacks later 138 | if (options.success == null) { 139 | options.success = function (){}; 140 | } 141 | if (options.error == null) { 142 | options.error = function (){}; 143 | } 144 | if (options.async == null) { 145 | options.async = true; 146 | } 147 | if (options.headers == null) { 148 | options.headers = {}; 149 | } 150 | 151 | if (options.postdata != null) { 152 | if (options.postdata instanceof Document) { 153 | // It's an XML document, so we can send it directly. 154 | // XMLHttpRequest will set the content type correctly. 155 | postdata = options.postdata; 156 | } 157 | else if (options.postdata instanceof FormData) { 158 | postdata = options.postdata; 159 | } 160 | else if (options.postdata instanceof Object) { 161 | // Now to work out how to encode the post data based on the headers 162 | var contentType = options.headers["Content-Type"]; 163 | // If there is no type then default to form-encoded 164 | if(!ejoy2d.isDefined(contentType)) { 165 | options.headers["Content-Type"] = ContentType.FORM_URLENCODED; 166 | contentType = options.headers["Content-Type"]; 167 | } 168 | switch(contentType) { 169 | case ContentType.FORM_URLENCODED: 170 | // Normal URL encoded form data 171 | postdata = ""; 172 | var bFirstItem = true; 173 | 174 | // Loop round each entry in the map and encode them into the post data 175 | for (var key in options.postdata) { 176 | if (options.postdata.hasOwnProperty(key)) { 177 | if (bFirstItem) { 178 | bFirstItem = false; 179 | } 180 | else { 181 | postdata += "&"; 182 | } 183 | postdata += escape(key) + "=" + escape(options.postdata[key]); 184 | } 185 | } 186 | break; 187 | case ContentType.JSON: 188 | default: 189 | if (contentType == null) { 190 | options.headers["Content-Type"] = ContentType.JSON; 191 | } 192 | postdata = JSON.stringify(options.postdata); 193 | break; 194 | } 195 | } 196 | else { 197 | postdata = options.postdata; 198 | } 199 | } 200 | 201 | if (!xhr) { 202 | xhr = new XMLHttpRequest(); 203 | } 204 | 205 | if (options.cache === false) { 206 | // Add timestamp to url to prevent browser caching file 207 | timestamp = new Date().getTime(); 208 | 209 | uri = new ejoy2d.URI(url); 210 | if (!uri.query) { 211 | uri.query = "ts=" + timestamp; 212 | } 213 | else { 214 | uri.query = uri.query + "&ts=" + timestamp; 215 | } 216 | url = uri.toString(); 217 | } 218 | 219 | if (options.query) { 220 | uri = new ejoy2d.URI(url); 221 | query = ejoy2d.extend(uri.getQuery(), options.query); 222 | uri.setQuery(query); 223 | url = uri.toString(); 224 | } 225 | 226 | xhr.open(method, url, options.async); 227 | xhr.withCredentials = options.withCredentials !== undefined ? options.withCredentials : true; 228 | xhr.responseType = options.responseType || this.guessResponseType(url); 229 | 230 | // Set the http headers 231 | for (var header in options.headers) { 232 | if (options.headers.hasOwnProperty(header)) { 233 | xhr.setRequestHeader(header, options.headers[header]); 234 | } 235 | } 236 | 237 | xhr.onreadystatechange = function () { 238 | this.onReadyStateChange(method, url, options, xhr); 239 | }.bind(this); 240 | 241 | xhr.onerror = function () { 242 | this.onError(method, url, options, xhr); 243 | errored = true; 244 | }.bind(this); 245 | 246 | try { 247 | xhr.send(postdata); 248 | } 249 | catch (e) { 250 | // DWE: Don't callback on exceptions as behaviour is inconsistent, e.g. cross-domain request errors don't throw an exception. 251 | // Error callback should be called by xhr.onerror() callback instead. 252 | if (!errored) { 253 | options.error(xhr.status, xhr, e); 254 | } 255 | } 256 | 257 | // Return the request object as it can be handy for blocking calls 258 | return xhr; 259 | }, 260 | 261 | guessResponseType: function (url) { 262 | var uri = new ejoy2d.URI(url); 263 | var ext = ejoy2d.path.getExtension(uri.path); 264 | 265 | if(binaryExtensions.indexOf(ext) >= 0) { 266 | return ResponseType.ARRAY_BUFFER; 267 | } 268 | 269 | return ResponseType.TEXT; 270 | }, 271 | 272 | isBinaryContentType: function (contentType) { 273 | var binTypes = [ContentType.WAV, ContentType.OGG, ContentType.MP3, ContentType.BIN, ContentType.DDS]; 274 | if (binTypes.indexOf(contentType) >= 0) { 275 | return true; 276 | } 277 | 278 | return false; 279 | }, 280 | 281 | onReadyStateChange: function (method, url, options, xhr) { 282 | if (xhr.readyState === 4) { 283 | switch (xhr.status) { 284 | case 0: { 285 | // If this is a local resource then continue (IOS) otherwise the request 286 | // didn't complete, possibly an exception or attempt to do cross-domain request 287 | if (url[0] != '/') { 288 | this.onSuccess(method, url, options, xhr); 289 | } 290 | 291 | break; 292 | } 293 | case 200: 294 | case 201: 295 | case 206: 296 | case 304: { 297 | this.onSuccess(method, url, options, xhr); 298 | break; 299 | } 300 | default: { 301 | //options.error(xhr.status, xhr, null); 302 | this.onError(method, url, options, xhr); 303 | break; 304 | } 305 | } 306 | } 307 | }, 308 | 309 | onSuccess: function (method, url, options, xhr) { 310 | var response; 311 | var header; 312 | var contentType; 313 | var parameter; 314 | var parts; 315 | header = xhr.getResponseHeader("Content-Type"); 316 | if (header) { 317 | // Split up header into content type and parameter 318 | parts = header.split(";"); 319 | contentType = parts[0].trim(); 320 | if(parts[1]) { 321 | parameter = parts[1].trim(); 322 | } 323 | } 324 | // Check the content type to see if we want to parse it 325 | if (contentType === ContentType.JSON || ejoy2d.string.endsWith(url, ".json")) { 326 | // It's a JSON response 327 | response = JSON.parse(xhr.responseText); 328 | } else if (this.isBinaryContentType(contentType)) { 329 | response = xhr.response; 330 | } else { 331 | if (xhr.responseType === ResponseType.ARRAY_BUFFER) { 332 | logWARNING(ejoy2d.string.format('responseType: {0} being served with Content-Type: {1}', ResponseType.ARRAY_BUFFER, contentType)); 333 | response = xhr.response; 334 | } else { 335 | if (xhr.responseType === ResponseType.DOCUMENT || contentType === ContentType.XML) { 336 | // It's an XML response 337 | response = xhr.responseXML; 338 | } else { 339 | // It's raw data 340 | response = xhr.responseText; 341 | } 342 | } 343 | } 344 | options.success(response, xhr.status, xhr); 345 | }, 346 | 347 | onError: function (method, url, options, xhr) { 348 | options.error(xhr.status, xhr, null); 349 | } 350 | }; 351 | })(); 352 | -------------------------------------------------------------------------------- /lib/label.js: -------------------------------------------------------------------------------- 1 | 2 | ejoy2d.label = (function() { 3 | 4 | var TEX_WIDTH = 512; 5 | var TEX_HEIGHT = 512; 6 | var TEX_FMT = TEXTURE_A8; 7 | var FONT_SIZE = 31; 8 | 9 | var LABEL_ALIGN_LEFT = 0; 10 | var LABEL_ALIGN_RIGHT = 1; 11 | var LABEL_ALIGN_CENTER = 2; 12 | 13 | var dfont = null; 14 | var tex = null; 15 | var font_ctx = {}; 16 | 17 | var log_cnt = 1; 18 | 19 | var newLineChar = "\n".charCodeAt(0); 20 | 21 | function font_create(size, ctx) { 22 | if( !ctx.font) { 23 | var textCtx =document.getElementById("textCanvas").getContext("2d"); 24 | ctx.font = textCtx; 25 | ctx.size = size; 26 | 27 | textCtx.font = size.toString() + "px monospace"; 28 | textCtx.textAlign = "center"; 29 | textCtx.textBaseline = "middle"; 30 | textCtx.fillStyle = "black"; 31 | } 32 | // textCtx.clearRect(0, 0, textCtx.canvas.width, textCtx.canvas.height); 33 | // textCtx.fillText(text, width / 2, height / 2); 34 | }; 35 | function font_size(chr, ctx) { 36 | var m = ctx.font.measureText(chr); 37 | ctx.w = Math.ceil(m.width); 38 | ctx.h = ctx.size; 39 | return ctx; 40 | }; 41 | function font_glyph(chr, buffer, ctx) { 42 | var textCtx = ctx.font; 43 | var w = textCtx.canvas.width; 44 | var h = textCtx.canvas.height; 45 | textCtx.clearRect(0, 0, w, h); 46 | textCtx.fillText(chr, w / 2, w / 2); 47 | var sx = w/2 - Math.floor(ctx.w/2); 48 | var sy = h/2 - Math.floor(ctx.h/2); 49 | var img = textCtx.getImageData(sx, sy, ctx.w, ctx.h); 50 | var len = ctx.w*ctx.h; 51 | for(var i =0; i < len; ++i ) { 52 | buffer[i] = img.data[i*4 + 3]; 53 | } 54 | }; 55 | function font_release(ctx) { 56 | // ctx.font = undefined; 57 | }; 58 | 59 | function set_point(v, idx, m, xx, yy, tx, ty) { 60 | var vx = (xx * m[0] + yy * m[2]) / 1024 + m[4]; 61 | var vy = (xx * m[1] + yy * m[3]) / 1024 + m[5]; 62 | var tmp = ejoy2d.screen.trans(vx, vy); 63 | 64 | // if(log_cnt <= 1) 65 | // console.log("----xx, yy", xx, yy," -- ", vx, vy, m) 66 | 67 | v[idx +0] = tmp[0]; 68 | v[idx +1] = tmp[1]; 69 | 70 | v[idx +2] = Math.floor(tx * (65535.0/TEX_WIDTH)); 71 | v[idx +3] = Math.floor(ty * (65535.0/TEX_HEIGHT)); 72 | ///console.log("--->>>", v[idx +0], v[idx +1], v[idx +2], v[idx +3]); 73 | }; 74 | 75 | var vb = new Array(14); 76 | function draw_rect(rect, size, mat, color, additive) { 77 | // if(log_cnt <= 1) 78 | // console.log("-------->>>> draw rect: ---->>>>>>>", rect); 79 | 80 | var w = (rect.w -1) * size / FONT_SIZE ; 81 | var h = (rect.h -1) * size / FONT_SIZE ; 82 | 83 | var m = mat.m; 84 | set_point(vb, 0, m, 0, 0, rect.x, rect.y); 85 | set_point(vb, 4, m, w*SCREEN_SCALE, 0, rect.x+rect.w-1, rect.y); 86 | set_point(vb, 8, m, w*SCREEN_SCALE, h*SCREEN_SCALE, rect.x+rect.w-1, rect.y+rect.h-1); 87 | set_point(vb, 12, m, 0, h*SCREEN_SCALE, rect.x, rect.y+rect.h-1); 88 | 89 | // console.log("--------->>> begin draw:"); 90 | ejoy2d.shader.do_draw(vb, color, additive); 91 | }; 92 | 93 | var glyph_buff = new Uint8Array(50*50); 94 | function gen_char(unicode, chr, size, edge) { 95 | // todo : use large size when size is large 96 | var ctx = font_ctx; 97 | font_create(FONT_SIZE, font_ctx); 98 | if (!ctx.font) { 99 | return null; 100 | } 101 | 102 | font_size(chr,font_ctx); 103 | var rect = dfont.insert(unicode, FONT_SIZE, ctx.w+1, ctx.h+1, edge); 104 | if (!rect) { 105 | dfont.flush(); 106 | rect = dfont.insert(unicode, FONT_SIZE, ctx.w+1, ctx.h+1, edge); 107 | if (!rect) { 108 | font_release(font_ctx); 109 | return null; 110 | } 111 | } 112 | ctx.w = rect.w; 113 | ctx.h = rect.h; 114 | //var bf_sz = ctx.w * ctx.h; 115 | if (edge) { 116 | // var tmp = new Array(bf_sz); 117 | // font_glyph(chr, tmp); 118 | // gen_outline(ctx.w, ctx.h, tmp, buffer); 119 | } else { 120 | font_glyph(chr, glyph_buff, font_ctx); 121 | } 122 | // write_pgm(unicode, ctx.w, ctx.h, buffer); 123 | font_release(font_ctx); 124 | ejoy2d.render.texture_subupdate(tex, glyph_buff, rect.x, rect.y, rect.w, rect.h); 125 | return rect; 126 | } 127 | 128 | 129 | function draw_size(unicode, chr, size, edge) { 130 | var rect = dfont.lookup(unicode, FONT_SIZE ,edge); 131 | if (!rect) { 132 | rect = gen_char(unicode, chr, size, edge); 133 | } 134 | if (rect) { 135 | return (rect.w -1) * size / FONT_SIZE; 136 | } 137 | return 0; 138 | }; 139 | function draw_height( unicode, chr, size, edge) { 140 | var rect = dfont.lookup(unicode, FONT_SIZE, edge); 141 | if (!rect) { 142 | rect = gen_char(unicode, chr, size, edge); 143 | } 144 | if (rect) { 145 | return rect.h * size / FONT_SIZE; 146 | } 147 | return 0; 148 | }; 149 | 150 | function get_char_size(unicode, size, edge) { 151 | var rect = dfont.lookup(unicode, FONT_SIZE, edge); 152 | var ctx = {}; 153 | font_create(FONT_SIZE, ctx); 154 | if ( !ctx.font) { 155 | ctx.w = 0; 156 | ctx.h = 0; 157 | return ctx; 158 | } 159 | 160 | if ( !rect ) { 161 | font_size(unicode, ctx); 162 | //see gen_char 163 | ctx.w += 1; 164 | ctx.h += 1; 165 | ctx.w = (ctx.w -1) * size / FONT_SIZE; 166 | ctx.h = ctx.h * size / FONT_SIZE; 167 | } else { 168 | ctx.w = (rect.w -1) * size / FONT_SIZE; 169 | ctx.h = rect.h * size / FONT_SIZE; 170 | } 171 | // font_release should not reset ctx.w/ctx.h 172 | font_release(ctx); 173 | return ctx; 174 | }; 175 | 176 | function draw_utf8(unicode, cx, cy, size, srt, color, arg, edge) { 177 | var rect = dfont.lookup(unicode, FONT_SIZE, edge); 178 | // if(log_cnt <= 1) 179 | // console.log("--->>> draw_utf8 cx cy\t", unicode, cx, cy); 180 | if ( !rect ) { 181 | return 0; 182 | } 183 | var mat1 = new ejoy2d.matrix([1024, 0, 0, 1024, cx*SCREEN_SCALE, cy*SCREEN_SCALE]); 184 | var m; 185 | if (arg.mat) { 186 | m = new ejoy2d.matrix(); 187 | m.mul(mat1, arg.mat); 188 | } else { 189 | m = mat1; 190 | } 191 | // m = mat1; 192 | m.srt(srt); 193 | 194 | draw_rect(rect, size, m, color, arg.additive); 195 | 196 | return (rect.w-1) * size / FONT_SIZE ; 197 | }; 198 | 199 | function get_rich_field_color(rich, idx) { 200 | for (var i=0; i < rich.count; i++) { 201 | var field = rich.fields[i]; 202 | if (idx >= field.start && idx <= field.end && field.type == RL_COLOR) { 203 | return field.color; 204 | } 205 | } 206 | return 0; 207 | }; 208 | function get_rich_filed_lf(rich, idx, offset) { 209 | return null; 210 | // for (var i=0; i< rich.fields.length; i++) { 211 | // var field = rich.fields[i]; 212 | // if (idx==field.start && idx==field.end && field.type== RL_LINEFEED) { 213 | // return field.val / 1000.0; 214 | // } 215 | // } 216 | }; 217 | 218 | function draw_line(rich, l, srt, arg, color, cy, w, start, end, pre_char_cnt, space_scale) { 219 | var str = rich.text; 220 | var cx = 0; 221 | var size = l.size; 222 | if (l.auto_scale != 0 && w > l.width) 223 | { 224 | var scale = l.width * 1.0/w; 225 | size = scale * size; 226 | cy = cy + (l.size - size) / 2; 227 | w = l.width; 228 | } 229 | l.space_w = 0.0; 230 | l.align = LABEL_ALIGN_LEFT; 231 | switch (l.align) { 232 | case LABEL_ALIGN_LEFT: 233 | cx = 0.0; 234 | break; 235 | case LABEL_ALIGN_RIGHT: 236 | cx = l.width - w; 237 | break; 238 | case LABEL_ALIGN_CENTER: 239 | cx = (l.width - w)/2; 240 | break; 241 | } 242 | 243 | var char_cnt = 0; 244 | for (var j=start; j> 24) & 0xff; 264 | var g1 = (c1 >> 16) & 0xff; 265 | var b1 = (c1 >> 8) & 0xff; 266 | var a1 = (c1) & 0xff; 267 | var r2 = (c2 >> 24) & 0xff; 268 | var g2 = (c2 >> 16) & 0xff; 269 | var b2 = (c2 >> 8) & 0xff; 270 | var a2 = c2 & 0xff; 271 | 272 | return (Math.floor(r1 * r2 /255)) << 24 | 273 | (Math.floor(g1 * g2 /255)) << 16 | 274 | (Math.floor(b1 * b2 /255)) << 8 | 275 | (Math.floor(a1 * a2 /255)); 276 | } 277 | 278 | var char_size_rlt = []; 279 | 280 | 281 | return { 282 | init : function() { 283 | ejoy2d.label.load(); 284 | }, 285 | load : function() { 286 | if( dfont) return; 287 | 288 | dfont = new ejoy2d.dfont(TEX_WIDTH, TEX_HEIGHT); 289 | tex = ejoy2d.render.texture_create(TEX_WIDTH, TEX_HEIGHT, TEX_FMT, TEXTURE_2D, 0); 290 | ejoy2d.render.texture_update(tex, TEX_WIDTH, TEX_HEIGHT, null, 0, 0); 291 | }, 292 | flush : function() { 293 | if(dfont) { 294 | dfont.flush(); 295 | } 296 | }, 297 | unload:function() { 298 | ejoy2d.render.release(TEXTURE, tex); 299 | dfont.release(); 300 | dfont = null; 301 | }, 302 | draw :function (rich, l, srt, arg) { 303 | ejoy2d.shader.texture(tex, 0); 304 | var color = ejoy2d.label.get_color(l, arg); 305 | var str = rich.text; 306 | 307 | var ch = 0, w = 0, cy = 0, pre = 0, char_cnt = 0, idx = 0; 308 | for (var i=0; i < str.length; ++i) { 309 | var unicode = str.charCodeAt(i); 310 | var chr = str.charAt(i); 311 | w += draw_size(unicode, chr, l.size, l.edge) + l.space_w; 312 | if (ch == 0) { 313 | ch = draw_height(unicode, chr, l.size, l.edge) + l.space_h; 314 | } 315 | var space_scale=1.0; 316 | var lf = get_rich_filed_lf(rich, idx, space_scale); 317 | if(((!l.auto_scale) && lf) || unicode == newLineChar) { 318 | char_cnt = draw_line(rich, l, srt, arg, color, cy, w, pre, i, char_cnt, space_scale); 319 | cy += ch; 320 | pre = i; 321 | w = 0; 322 | ch = 0; 323 | } 324 | idx++; 325 | } 326 | draw_line(rich, l, srt, arg, color, cy, w, pre, i, char_cnt, 1.0); 327 | // if(log_cnt <= 1) 328 | // { 329 | // console.log("-------->>> label.draw --------->>> end",rich.text); 330 | // log_cnt ++; 331 | // } 332 | }, 333 | char_size : function(l, chr) { 334 | var ct = get_char_size(chr, l.size, l.edge); 335 | char_size_rlt[0] = ct.w + l.space_w; // width 336 | char_size_rlt[1] = ct.h + l.space_h; // height 337 | return len; 338 | }, 339 | size : function(str, l, width, height) { 340 | var w=0, max_w=0, h=0, max_h=0; 341 | for (var i=0; i < str.length; ++i) { 342 | var char_code = str.charCodeAt(i); 343 | var ct = get_char_size(char_code, l.size, l.edge); 344 | w += ct.w + l.space_w; 345 | if (h==0) { 346 | h = ct.h + l.space_h; 347 | } 348 | if(( (!l.auto_scale) && w > l.width) || char_code == newLineChar) { 349 | max_h += h; 350 | h = 0; 351 | if (w > max_w) max_w = w; 352 | w = 0; 353 | } 354 | } 355 | max_h += h; 356 | if (w > max_w) max_w = w; 357 | if (l.auto_scale > 0 && max_w > l.width) 358 | max_w = l.width; 359 | 360 | char_size_rlt[0] = max_w; 361 | char_size_rlt[1] = max_h; 362 | }, 363 | get_color:function( l, arg) { 364 | var color; 365 | if (arg.color == 0xffffffff) { 366 | color = l.color; 367 | } 368 | else if (l.color == 0xffffffff){ 369 | color = arg.color; 370 | } else { 371 | color = color_mul(l.color, arg.color); 372 | } 373 | return color; 374 | } 375 | 376 | }; 377 | })(); 378 | -------------------------------------------------------------------------------- /lib/list.js: -------------------------------------------------------------------------------- 1 | 2 | ejoy2d.list = function() { 3 | 4 | } 5 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/14. 3 | */ 4 | 5 | 6 | var gl; 7 | var shader; 8 | var texture; 9 | var render; 10 | var material; 11 | var renderbuffer; 12 | var ej_screen; 13 | var scissor; 14 | var geometry; 15 | 16 | 17 | 18 | 19 | var _G = {}; 20 | function init(canvas,fw) { 21 | /// init gl 22 | var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; 23 | for(var i =0; i < names.length; ++i) { 24 | try{ 25 | gl = canvas.getContext(names[i]); 26 | gl.viewportWidth = canvas.width; 27 | gl.viewportHeight = canvas.height; 28 | } catch(e) {} 29 | if(gl) { 30 | break; 31 | } 32 | } 33 | if (!gl) { 34 | alert("Could not init WegGL,sorry :-("); 35 | return 36 | } 37 | 38 | /// inti ejoy2d 39 | shader = ejoy2d.shader; 40 | texture = ejoy2d.texture; 41 | render = ejoy2d.render; 42 | material = ejoy2d.material; 43 | renderbuffer = ejoy2d.renderbuffer; 44 | ej_screen = ejoy2d.screen; 45 | scissor = ejoy2d.scissor; 46 | geometry = ejoy2d.geometry; 47 | 48 | //render.init(); 49 | 50 | fw.init(); 51 | _G.game = new ejoy2d.game(fw); 52 | 53 | 54 | ////////// dealing with user input 55 | // closure 56 | var cg = _G.game; 57 | var isMouseDown = false; 58 | var bounds = canvas.getBoundingClientRect() 59 | var canvasPosX = bounds.left; 60 | var canvasPosY = bounds.top; 61 | 62 | canvas.onmousedown = function(e){ 63 | var posX = e.pageX - canvasPosX; 64 | var posY = e.pageY - canvasPosY; 65 | isMouseDown = true; 66 | //console.log("------<<<<< Mouse down at", posX, posY); 67 | cg.touch(0, posX, posY, InputType.TOUCH_BEGIN); 68 | 69 | }; 70 | canvas.onmouseup = function(e) { 71 | var posX = e.pageX - canvasPosX; 72 | var posY = e.pageY - canvasPosY; 73 | isMouseDown = false; 74 | cg.touch(0, posX, posY, InputType.TOUCH_END); 75 | }; 76 | canvas.onmousemove = function(e) { 77 | if(isMouseDown) { 78 | var posX = e.pageX - canvasPosX; 79 | var posY = e.pageY - canvasPosY; 80 | cg.touch(0, posX, posY, InputType.TOUCH_MOVE); 81 | } 82 | }; 83 | /// end of user input 84 | } 85 | 86 | function drawScene() { 87 | _G.game.draw(); 88 | shader.flush() 89 | } 90 | 91 | var lastTime = 0; 92 | 93 | function update() { 94 | var timeNow = new Date().getTime(); 95 | if (lastTime != 0) { 96 | var elapsed = timeNow - lastTime; 97 | _G.game.update(elapsed); 98 | } 99 | lastTime = timeNow; 100 | } 101 | 102 | function tick() { 103 | requestAnimFrame(tick); 104 | update(); 105 | drawScene(); 106 | } 107 | 108 | 109 | function webGLStart(fw) { 110 | var canvas = document.getElementById("main_canvas"); 111 | console.log("--->> begin to init cavas:", canvas); 112 | init(canvas, fw); 113 | tick(); 114 | } 115 | -------------------------------------------------------------------------------- /lib/material.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/26. 3 | */ 4 | 5 | ejoy2d.material = function(){ 6 | this.texture = new Array(MAX_TEXTURE_CHANNEL); 7 | this.uniform_enable = new Array(MAX_UNIFORM); 8 | }; 9 | ejoy2d.material.prototype = { 10 | init:function(RS,prog) { 11 | this.p = p; 12 | }, 13 | apply:function(RS, prog) { 14 | var p = this.p; 15 | if (p != RS.program[prog]) 16 | return; 17 | if (p.material == m) { 18 | return; 19 | } 20 | p.material = m; 21 | p.reset_uniform = true; 22 | for (var i=0;i< p.uniform_number;i++) { 23 | if (m.uniform_enable[i]) { 24 | var u = p.uniform[i]; 25 | if (u.loc != null) { 26 | render.shader_setuniform(u.loc, u.type, this.uniform, u.offset); 27 | } 28 | } 29 | } 30 | for (var i=0;i< p.texture_number;i++) { 31 | var tex = this.texture[i]; 32 | if (tex) { 33 | var glid = texture.glid(tex); 34 | if (glid) { 35 | shader.texture(glid, i); 36 | } 37 | } 38 | } 39 | }, 40 | 41 | /////////////////////////////////// 42 | /////////////// API /////////////// 43 | setuniform:function(index, n, v) { 44 | var p = this.p; 45 | console.assert(index >= 0 && index < p.uniform_number); 46 | var u = p.uniform[index]; 47 | if (shader.uniformsize(u.type) != n) { 48 | return true; 49 | } 50 | var offset = u.uniform; 51 | for(var i =0; i < n;++i) { 52 | this.uniform[offset +i] = v[i]; 53 | } 54 | this.uniform_enable[index] = true; 55 | return false; 56 | }, 57 | settexture:function(channel, texture) { 58 | if (channel >= MAX_TEXTURE_CHANNEL) { 59 | return true; 60 | } 61 | this.texture[channel] = texture; 62 | return false; 63 | } 64 | /////////// end of API //////////////// 65 | /////////////////////////////////////// 66 | }; -------------------------------------------------------------------------------- /lib/matrix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/17. 3 | */ 4 | 5 | var EJMAT_R_FACTOR = 4096.0; 6 | 7 | var _I = [1024, 0, 0, 1024, 0, 0]; 8 | 9 | ejoy2d.matrix = function(mat){ 10 | this.m = new Int32Array(6); 11 | if(mat) { 12 | for(var i = 0; i < 6; ++i) { 13 | this.m[i] = mat[i]; 14 | } 15 | } else { 16 | this.identity(); 17 | } 18 | }; 19 | 20 | 21 | ejoy2d.matrix.prototype = { 22 | mul : function(mm1, mm2) { 23 | var m = this.m; 24 | var m1 = mm1.m; 25 | var m2 = mm2.m; 26 | m[0] = (m1[0] * m2[0] + m1[1] * m2[2]) /1024; 27 | m[1] = (m1[0] * m2[1] + m1[1] * m2[3]) /1024; 28 | m[2] = (m1[2] * m2[0] + m1[3] * m2[2]) /1024; 29 | m[3] = (m1[2] * m2[1] + m1[3] * m2[3]) /1024; 30 | m[4] = (m1[4] * m2[0] + m1[5] * m2[2]) /1024 + m2[4]; 31 | m[5] = (m1[4] * m2[1] + m1[5] * m2[3]) /1024 + m2[5]; 32 | }, 33 | identity : function(output) { 34 | this.m[0] = 1024; 35 | this.m[1] = 0; 36 | this.m[2] = 0; 37 | this.m[3] = 1024; 38 | this.m[4] = 0; 39 | this.m[5] = 0; 40 | if(output) 41 | console.log(this, this.m) 42 | }, 43 | make_identity : function(output) { 44 | this.m[0] = 10; 45 | this.m[1] = 0; 46 | this.m[2] = 0; 47 | this.m[3] = 0; 48 | this.m[4] = 0; 49 | this.m[5] = 0; 50 | if(output) 51 | console.log(this, this.m) 52 | }, 53 | 54 | 55 | _inverse_scale:function(m , o) { 56 | var m = this.m; 57 | if (m[0] == 0 || m[3] == 0) 58 | return 1; 59 | o[0] = (1024 * 1024) / m[0]; 60 | o[1] = 0; 61 | o[2] = 0; 62 | o[3] = (1024 * 1024) / m[3]; 63 | o[4] = - (m[4] * o[0]) / 1024; 64 | o[5] = - (m[5] * o[3]) / 1024; 65 | return 0; 66 | }, 67 | 68 | _inverse_rot:function(m, o) { 69 | var m = this.m; 70 | if (m[1] == 0 || m[2] == 0) 71 | return 1; 72 | o[0] = 0; 73 | o[1] = (1024 * 1024) / m[2]; 74 | o[2] = (1024 * 1024) / m[1]; 75 | o[3] = 0; 76 | o[4] = - (m[5] * o[2]) / 1024; 77 | o[5] = - (m[4] * o[1]) / 1024; 78 | return 0; 79 | }, 80 | 81 | inverse:function(mo) { 82 | var m = this.m; 83 | var o = mo.m; 84 | if (m[1] == 0 && m[2] == 0) { 85 | return this._inverse_scale(m,o); 86 | } 87 | if (m[0] == 0 && m[3] == 0) { 88 | return this._inverse_rot(m,o); 89 | } 90 | var t = m[0] * m[3] - m[1] * m[2] ; 91 | if (t == 0) 92 | return 1; 93 | o[0] = (m[3] * (1024 * 1024) / t); 94 | o[1] = (-m[1] * (1024 * 1024) / t); 95 | o[2] = (-m[2] * (1024 * 1024) / t); 96 | o[3] = (m[0] * (1024 * 1024) / t); 97 | o[4] = -(m[4] * o[0] + m[5] * o[2]) / 1024; 98 | o[5] = -(m[4] * o[1] + m[5] * o[3]) / 1024; 99 | return 0; 100 | }, 101 | 102 | i_cos_tbl : [ 103 | 1024,1023,1022,1021,1019,1016,1012,1008,1004,999,993,986,979,972,964,955, 104 | 946,936,925,914,903,890,878,865,851,837,822,807,791,775,758,741, 105 | 724,706,687,668,649,629,609,589,568,547,526,504,482,460,437,414, 106 | 391,368,344,321,297,273,248,224,199,175,150,125,100,75,50,25, 107 | 0,-25,-50,-75,-100,-125,-150,-175,-199,-224,-248,-273,-297,-321,-344,-368, 108 | -391,-414,-437,-460,-482,-504,-526,-547,-568,-589,-609,-629,-649,-668,-687,-706, 109 | -724,-741,-758,-775,-791,-807,-822,-837,-851,-865,-878,-890,-903,-914,-925,-936, 110 | -946,-955,-964,-972,-979,-986,-993,-999,-1004,-1008,-1012,-1016,-1019,-1021,-1022,-1023, 111 | -1024,-1023,-1022,-1021,-1019,-1016,-1012,-1008,-1004,-999,-993,-986,-979,-972,-964,-955, 112 | -946,-936,-925,-914,-903,-890,-878,-865,-851,-837,-822,-807,-791,-775,-758,-741, 113 | -724,-706,-687,-668,-649,-629,-609,-589,-568,-547,-526,-504,-482,-460,-437,-414, 114 | -391,-368,-344,-321,-297,-273,-248,-224,-199,-175,-150,-125,-100,-75,-50,-25, 115 | 0,25,50,75,100,125,150,175,199,224,248,273,297,321,344,368, 116 | 391,414,437,460,482,504,526,547,568,589,609,629,649,668,687,706, 117 | 724,741,758,775,791,807,822,837,851,865,878,890,903,914,925,936, 118 | 946,955,964,972,979,986,993,999,1004,1008,1012,1016,1019,1021,1022,1023, 119 | ], 120 | 121 | // SRT to matrix 122 | 123 | icost:function(dd) { 124 | dd = Math.floor(dd) & 0xff; // % 256 125 | return this.i_cos_tbl[dd]; 126 | }, 127 | 128 | icosd:function(d) { 129 | var dd = d*0.25; 130 | return this.icost(dd); 131 | }, 132 | 133 | isind:function(d) { 134 | var dd = 64 - d*0.25; 135 | return this.icost(dd); 136 | }, 137 | 138 | rot_mat:function(d) { 139 | if (d==0) 140 | return; 141 | var m = this.m; 142 | var cosd = this.icosd(d); 143 | var sind = this.isind(d); 144 | 145 | var m0_cosd = m[0] * cosd; 146 | var m0_sind = m[0] * sind; 147 | var m1_cosd = m[1] * cosd; 148 | var m1_sind = m[1] * sind; 149 | var m2_cosd = m[2] * cosd; 150 | var m2_sind = m[2] * sind; 151 | var m3_cosd = m[3] * cosd; 152 | var m3_sind = m[3] * sind; 153 | var m4_cosd = m[4] * cosd; 154 | var m4_sind = m[4] * sind; 155 | var m5_cosd = m[5] * cosd; 156 | var m5_sind = m[5] * sind; 157 | 158 | m[0] = (m0_cosd - m1_sind) /1024; 159 | m[1] = (m0_sind + m1_cosd) /1024; 160 | m[2] = (m2_cosd - m3_sind) /1024; 161 | m[3] = (m2_sind + m3_cosd) /1024; 162 | m[4] = (m4_cosd - m5_sind) /1024; 163 | m[5] = (m4_sind + m5_cosd) /1024; 164 | }, 165 | 166 | scale_mat:function(sx, sy) { 167 | var m = this.m; 168 | if (sx != 1024) { 169 | m[0] = m[0] * sx / 1024; 170 | m[2] = m[2] * sx / 1024; 171 | m[4] = m[4] * sx / 1024; 172 | } 173 | if (sy != 1024) { 174 | m[1] = m[1] * sy / 1024; 175 | m[3] = m[3] * sy / 1024; 176 | m[5] = m[5] * sy / 1024; 177 | } 178 | }, 179 | 180 | srt:function(_srt) { 181 | if (!_srt) { 182 | return; 183 | } 184 | var m = this.m; 185 | this.scale_mat(_srt.scalex, _srt.scaley); 186 | this.rot_mat(_srt.rot); 187 | m[4] += _srt.offx; 188 | m[5] += _srt.offy; 189 | }, 190 | sr:function(sx, sy, d) { 191 | var m = this.m; 192 | var cosd = icosd(d); 193 | var sind = isind(d); 194 | 195 | var m0_cosd = sx * cosd; 196 | var m0_sind = sx * sind; 197 | var m3_cosd = sy * cosd; 198 | var m3_sind = sy * sind; 199 | 200 | m[0] = m0_cosd /1024; 201 | m[1] = m0_sind /1024; 202 | m[2] = -m3_sind /1024; 203 | m[3] = m3_cosd /1024; 204 | }, 205 | 206 | rs:function(sx, sy, d) { 207 | var m = this.m; 208 | var cosd = icosd(d); 209 | var sind = isind(d); 210 | 211 | var m0_cosd = sx * cosd; 212 | var m0_sind = sx * sind; 213 | var m3_cosd = sy * cosd; 214 | var m3_sind = sy * sind; 215 | 216 | m[0] = m0_cosd /1024; 217 | m[1] = m3_sind /1024; 218 | m[2] = -m0_sind /1024; 219 | m[3] = m3_cosd /1024; 220 | }, 221 | 222 | 223 | 224 | 225 | ///////////////////// API /////////////////// 226 | trans:function(x, y) { 227 | this.m[4] += x * SCREEN_SCALE; 228 | this.m[5] += y * SCREEN_SCALE; 229 | }, 230 | 231 | scaleAndRot:function(sx,sy,rot) { 232 | var sx=1024,sy=1024,r=0; 233 | this.rs(sx, sy, r); 234 | 235 | return 0; 236 | }, 237 | scale:function(sx, sy) { 238 | if(!sy) 239 | sy = sx; 240 | this.scale_mat(this.m, sx, sy); 241 | }, 242 | rot:function(r) { 243 | this.rot_mat(this.m, r); 244 | }, 245 | clone:function() { 246 | var mat = new ejoy2d.matrix(); 247 | mat.m = this.m.slice(0); 248 | return mat; 249 | }, 250 | copyFrom : function(mat) { 251 | this.m = mat.m.slice(0); 252 | }, 253 | tostring:function() { 254 | var m = this.m; 255 | string.format("Mat(%d,%d,%d,%d,%d,%d)", 256 | m[0],m[1],m[2],m[3],m[4],m[5]); 257 | return 1; 258 | }, 259 | export : function() { 260 | var rlt = new Array(6); 261 | var m = this.m; 262 | for (i=0;i<6;i++) { 263 | rlt[i] = m[i]; 264 | } 265 | return rlt; 266 | }, 267 | import : function(m) { 268 | var mm = this.m; 269 | for (i=0;i<6;i++) { 270 | mm[i] = m[i]; 271 | } 272 | return 0; 273 | } 274 | //////////////////end of API //////////////// 275 | }; 276 | -------------------------------------------------------------------------------- /lib/path.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/8/20. 3 | */ 4 | ejoy2d.path = function () { 5 | return { 6 | /** 7 | * The character that separates path segments 8 | * @name ejoy2d.path.delimiter 9 | */ 10 | delimiter: "/", 11 | /** 12 | * Join two sections of file path together, insert a delimiter if needed. 13 | * @param {String} one First part of path to join 14 | * @param {String} two Second part of path to join 15 | * @function 16 | * @name ejoy2d.path.join 17 | */ 18 | /* 19 | join: function(one, two) { 20 | if(two[0] === ejoy2d.path.delimiter) { 21 | return two; 22 | } 23 | 24 | if(one && two && one[one.length - 1] !== ejoy2d.path.delimiter && two[0] !== ejoy2d.path.delimiter) { 25 | return one + ejoy2d.path.delimiter + two; 26 | } 27 | else { 28 | return one + two; 29 | } 30 | }, 31 | */ 32 | join: function () { 33 | var index; 34 | var num = arguments.length; 35 | var result = arguments[0]; 36 | 37 | for(index = 0; index < num - 1; ++index) { 38 | var one = arguments[index]; 39 | var two = arguments[index+1]; 40 | if(!ejoy2d.isDefined(one) || !ejoy2d.isDefined(two)) { 41 | throw new Error("undefined argument to ejoy2d.path.join"); 42 | } 43 | if(two[0] === ejoy2d.path.delimiter) { 44 | result = two; 45 | continue; 46 | } 47 | 48 | if(one && two && one[one.length - 1] !== ejoy2d.path.delimiter && two[0] !== ejoy2d.path.delimiter) { 49 | result += (ejoy2d.path.delimiter + two); 50 | } else { 51 | result += (two); 52 | } 53 | } 54 | 55 | return result; 56 | }, 57 | 58 | /** 59 | * @function 60 | * @name ejoy2d.path.split 61 | * @description Split the pathname path into a pair [head, tail] where tail is the final part of the path 62 | * after the last delimiter and head is everything leading up to that. tail will never contain a slash 63 | */ 64 | split: function (path) { 65 | var parts = path.split(ejoy2d.path.delimiter); 66 | var tail = parts.slice(parts.length-1)[0]; 67 | var head = parts.slice(0,parts.length-1).join(ejoy2d.path.delimiter); 68 | return [head, tail]; 69 | }, 70 | 71 | /** 72 | * @function 73 | * @name ejoy2d.path.getBasename 74 | * @description Return the basename of the path. That is the second element of the pair returned by 75 | * passing path into {@link ejoy2d.path.split}. 76 | * @example 77 | * ejoy2d.path.getBasename("/path/to/file.txt"); // returns "path.txt" 78 | * ejoy2d.path.getBasename("/path/to/dir"); // returns "dir" 79 | * @returns {String} The basename 80 | */ 81 | getBasename: function(path) { 82 | return ejoy2d.path.split(path)[1]; 83 | }, 84 | 85 | /** 86 | * Get the directory name from the path. This is everything up to the final instance of ejoy2d.path.delimiter 87 | * @param {String} path The path to get the directory from 88 | * @function 89 | * @name ejoy2d.path.getDirectory 90 | */ 91 | getDirectory: function(path) { 92 | var parts = path.split(ejoy2d.path.delimiter); 93 | return parts.slice(0,parts.length-1).join(ejoy2d.path.delimiter); 94 | }, 95 | 96 | getExtension: function (path) { 97 | var ext = path.split(".").pop(); 98 | if (ext !== path) { 99 | return "." + ext; 100 | } else { 101 | return ""; 102 | } 103 | }, 104 | 105 | isRelativePath: function (s) { 106 | return s.charAt(0) !== "/" && s.match(/:\/\//) === null; 107 | }, 108 | 109 | extractPath: function (s) { 110 | var path = ".", 111 | parts = s.split("/"), 112 | i = 0; 113 | 114 | if (parts.length > 1) { 115 | if (ejoy2d.path.isRelativePath(s) === false) { 116 | path = ""; 117 | } 118 | for (i = 0; i < parts.length - 1; ++i) { 119 | path += "/" + parts[i]; 120 | } 121 | } 122 | return path; 123 | } 124 | }; 125 | } (); -------------------------------------------------------------------------------- /lib/renderbuffer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/18. 3 | */ 4 | 5 | var MAX_COMMBINE = 1024; 6 | ejoy2d.renderbuffer = function(){ 7 | this.object = 0; 8 | this.texid = 0; 9 | this.vbid = 0; 10 | this.quad = new ArrayBuffer(MAX_COMMBINE); 11 | this.vb = new Float32Array(this.quad); 12 | this.uv = new Uint16Array(this.quad); 13 | this.color = new Uint8Array(this.quad); 14 | this.init(); 15 | }; 16 | ejoy2d.renderbuffer.prototype = { 17 | // init_render:function(r) { 18 | // }, 19 | add:function(vb, color, additive) { 20 | if (this.object >= MAX_COMMBINE) { 21 | return true; 22 | } 23 | var idx = this.object*4; 24 | var pidx = idx * 5; 25 | var tidx = idx*10 + 4; 26 | var cidx = idx*20 + 12; 27 | for (var i=0;i<4;i++) { 28 | var ii = i*4; 29 | this.vb[pidx] = vb[ii]; 30 | this.vb[pidx+1] = vb[ii + 1]; 31 | pidx +=5; 32 | 33 | this.uv[tidx] = vb[ii + 2]; 34 | this.uv[tidx+1] = vb[ii + 3]; 35 | tidx +=10; 36 | //console.log("--->>> let's see ", i, vb[ii], vb[ii +1]) 37 | this.color[cidx] = (color >> 16) & 0xff; 38 | this.color[cidx +1] = (color >> 8) & 0xff; 39 | this.color[cidx +2] = (color) & 0xff; 40 | this.color[cidx +3] = (color >> 24) & 0xff; 41 | this.color[cidx +4] = (additive >> 16) & 0xff; 42 | this.color[cidx +5] = (additive >> 8) & 0xff; 43 | this.color[cidx +6] = (additive) & 0xff; 44 | this.color[cidx +7] = (additive >> 24) & 0xff; 45 | cidx +=20; 46 | } 47 | this.object = this.object +1; 48 | // console.log("--------??? aoaoao cur index buffer object:", this.object); 49 | if (this.object >= MAX_COMMBINE) { 50 | return true; 51 | } 52 | return false; 53 | }, 54 | 55 | _update_tex:function(id) { 56 | if (this.object == 0) { 57 | this.texid = id; 58 | } else if (this.texid != id) { 59 | return true; 60 | } 61 | return false; 62 | }, 63 | 64 | _drawquad:function(picture, arg) { 65 | var tmp; 66 | var vb = new Array(16); 67 | var i,j=0; 68 | if (!arg.mat) { 69 | tmp = new ejoy2d.matrix(); 70 | } else { 71 | tmp = arg.mat.clone(); 72 | } 73 | var m = tmp.m; 74 | var object = this.object; 75 | for (i=0;i= 33 && unicode <= 47) return true; 11 | // : to @ 12 | if(unicode >= 58 && unicode <= 64) return true; 13 | // [ to ` 14 | if(unicode >= 91 && unicode <= 96) return true; 15 | // { to ~ 16 | if(unicode >= 123 && unicode <= 126) return true; 17 | 18 | return false; 19 | } 20 | 21 | 22 | function is_ASCII_SBC_punct(unicode) 23 | { 24 | return is_ASCII_DBC_punct(unicode-65248); 25 | } 26 | 27 | function is_JP_punct(unicode) { 28 | if (unicode) return false; 29 | if(unicode >= 65377 && unicode <= 65381) return true; 30 | if(unicode == 0x3002 || unicode == 0x3001 || unicode == 0x300C || 31 | unicode == 0x300D || unicode == 0x30FB) 32 | return true; 33 | return false; 34 | } 35 | 36 | function is_punct(unicode) { 37 | if(unicode) return false; 38 | if(is_ASCII_DBC_punct(unicode)) return true; 39 | if(is_ASCII_SBC_punct(unicode)) return true; 40 | if(is_JP_punct(unicode)) return true; 41 | return false; 42 | } 43 | 44 | 45 | 46 | function is_ascii(unicode) { 47 | if (!unicode) return false; 48 | if(unicode >= 33 && unicode <= 126) return true; 49 | var shift = unicode-65248; 50 | if (shift >= 33 && shift <= 126) return true; 51 | return false; 52 | } 53 | 54 | 55 | 56 | function is_alnum(unicode) { 57 | if(!unicode) 58 | return false; 59 | return is_ascii(unicode) && !is_punct(unicode); 60 | } 61 | 62 | var char_sizes = []; 63 | function char_width(idx) 64 | { 65 | return char_sizes[idx] 66 | } 67 | 68 | function char_height(idx) 69 | { 70 | return char_sizes[idx+1] 71 | } 72 | 73 | var gap = 4; 74 | 75 | var CTL_CODE_POP=0; 76 | var CTL_CODE_COLOR=1; 77 | var CTL_CODE_LINEFEED=2; 78 | 79 | var TAG_REG = /#\[\w+\]/; 80 | var TAG_REG_G = /#\[\w+\]/g; 81 | 82 | var operates = { 83 | yellow : { val : 0xFFFFFF00, type : "color" }, 84 | red : { val : 0xFFFF0000, type : "color" }, 85 | blue : { val : 0xFF0000FF, type : "color" }, 86 | green : { val:0xFF00FF00, type:"color" }, 87 | stop : { type : CTL_CODE_POP }, 88 | lf : { type:CTL_CODE_LINEFEED } 89 | }; 90 | 91 | function _locate_alnum(sizes, anchor) { 92 | var start = anchor; 93 | var forward_len = sizes[start]; 94 | while (sizes[start-gap+3]) { 95 | if(start-gap < 3 || !is_alnum(sizes[start-gap+3])) 96 | break; 97 | start = start - gap; 98 | forward_len = forward_len + sizes[start]; 99 | } 100 | var stop = anchor; 101 | var backward_len = 0; 102 | while(sizes[stop+gap+3]) { 103 | if(!is_alnum(sizes[stop+gap+3])) 104 | break; 105 | stop = stop + gap; 106 | backward_len = backward_len + sizes[stop] 107 | } 108 | return [forward_len, start, stop, backward_len]; 109 | } 110 | 111 | 112 | 113 | function _add_linefeed(fields, pos, offset) { 114 | var field = [false, false, false, false]; 115 | field[1] = pos - 1; // zero base index 116 | field[2] = pos - 1; 117 | field[3] = CTL_CODE_LINEFEED; 118 | if(offset) 119 | field[4] = Math.round(offset); 120 | else 121 | field[4] = 1000; 122 | fields.push(field); 123 | } 124 | 125 | var layout_rlt = []; 126 | function _layout(label, txt, fields) { 127 | // print(txt) 128 | // {label_width, label_height, char_width_1, char_width_1, unicode_len_1, unicode_1...} 129 | var size_cnt = label.size(char_sizes, txt); 130 | 131 | var width = char_sizes[0]; 132 | var line_width = 0; 133 | var ignore_next =0, extra_len = 0; 134 | var max_width =0, max_height =0, line_max_height =0; 135 | for(var i=2; i < size_cnt; i += gap) { 136 | var idx = i; 137 | if(ignore_next == 0) 138 | line_width = line_width + 1; 139 | else 140 | ignore_next = ignore_next-1; 141 | 142 | if(extra_len > 0) { 143 | line_width = line_width + extra_len; 144 | extra_len = 0 145 | } 146 | // reset if \n 147 | if (txt.charCodeAt(idx) == 10){ 148 | max_height = max_height + char_height(idx); 149 | line_width = 0 150 | } 151 | 152 | line_max_height = char_height(idx) > line_max_height ? char_height(idx) : line_max_height; 153 | 154 | if(line_width >= width) { 155 | max_width = line_width > max_width ? line_width : max_width; 156 | max_height = max_height + line_max_height; 157 | line_max_height = 0; 158 | 159 | var pos = (idx+1) / gap; 160 | var next_unicode = str.charCodeAt(idx+gap); 161 | // make sure punctation does not stand at line head 162 | if (is_punct(next_unicode)) { 163 | line_width = line_width + char_width(idx+gap); 164 | pos = pos + 1; 165 | next_unicode = txt.charCodeAt(idx+gap+gap); 166 | ignore_next = ignore_next + 1 167 | } 168 | 169 | 170 | if (next_unicode && next_unicode != 10){ 171 | if (ignore_next > 0 || !is_alnum(txt.charCodeAt(idx))) { 172 | _add_linefeed(fields, pos) 173 | } else { 174 | var info = _locate_alnum(char_sizes, idx); 175 | var forward_len = info[0]; 176 | var start = info[1]; 177 | var stop = info[2]; 178 | var backward_len = info[3]; 179 | var scale; 180 | if(stop == idx+gap && !is_punct(char_unicode(stop+gap))){ 181 | ignore_next = ignore_next+1; 182 | scale = line_width * 1000 / (line_width + char_width(stop)); 183 | scale = scale >= 970? scale : 1000; 184 | line_width = line_width + char_width(stop); 185 | _add_linefeed(fields, pos+1, scale) 186 | } 187 | else { 188 | scale = width * 1000 / (line_width - forward_len); 189 | // local scale = line_width * 1000 / (line_width - forward_len) 190 | if(scale <= 1250 && scale > 0) 191 | { 192 | extra_len = forward_len; 193 | line_width = line_width - extra_len; 194 | _add_linefeed(fields, ((start+1) / gap)-1, scale) 195 | } 196 | 197 | else 198 | { 199 | _add_linefeed(fields, pos) 200 | } 201 | } 202 | } 203 | // print("............delta:", line_width, line_width - width, char_width(idx), ignore_next) 204 | line_width = 0 205 | } 206 | } 207 | } 208 | if(line_width < width && line_width > 0) 209 | max_height = max_height + line_max_height; 210 | 211 | max_width = max_width == 0?line_width : max_width; 212 | layout_rlt[0] = max_width; 213 | layout_rlt[1] = max_height; 214 | return layout_rlt; 215 | } 216 | 217 | 218 | function _post_format(label, txt, fields) { 219 | var lr = _layout(label, txt, fields); 220 | return [txt, fields, lr[0], lr[1]]; 221 | } 222 | 223 | return { 224 | init_operators : function(ops) { 225 | for(var k in ops){ 226 | operates[k] = ops[k] 227 | } 228 | }, 229 | is_rich : function(str) { 230 | return str.search(TAG_REG) != -1; 231 | }, 232 | format : function(label, txt) { 233 | var fields = []; 234 | var pos_pieces = []; 235 | var tags = text.match(TAG_REG_G); 236 | if(!tags) 237 | return _post_format(label, txt, fields); 238 | 239 | var s=0; 240 | var e=0; 241 | var pos_cnt = 0; 242 | var tag_cnt = tags.length; 243 | var i =0; 244 | for(i =0; i < tag_len; ++i ) { 245 | s = txt.search(TAG_REG); 246 | var tag = tags[i]; 247 | e = s + tag.length -1; 248 | tag = tag.substr(2, tag.length -3); 249 | if (!operates[tag]) { 250 | txt = text.replace(TAG_REG, ""); 251 | } 252 | else { 253 | var pos = s; 254 | pos_cnt = pos_cnt+1; 255 | pos_pieces[pos_cnt] = pos; 256 | 257 | pos_cnt = pos_cnt+1; 258 | pos_pieces[pos_cnt] = tag; 259 | 260 | txt = txt.replace(TAG_REG, ""); 261 | } 262 | } 263 | 264 | var count = pos_cnt / 2; 265 | var last_field = null; 266 | var tlen = txt.length; 267 | var field = null; 268 | for(i=1; i < count; ++i) { 269 | pos = pos_pieces[2*i-1]; 270 | tag = pos_pieces[2*i]; 271 | var ope = operates[tag]; 272 | if (ope.type == "color") { 273 | field = [false, false, false, false]; 274 | field[1] = pos; 275 | field[2] = i==count ? tlen : pos_pieces[2*(i+1)-1]-1; 276 | field[3] = CTL_CODE_COLOR; 277 | field[4] = ope.val; 278 | fields.add(field); 279 | last_field = field; 280 | } 281 | else if(ope.type == CTL_CODE_POP) { 282 | last_field = null; 283 | } 284 | else if(ope.type == CTL_CODE_LINEFEED){ 285 | field = [false, false, false, false]; 286 | field[1] = pos; 287 | field[2] = pos; 288 | field[3] = ope.type; 289 | field[4] = ope.val; 290 | fields.push(field); 291 | 292 | if(last_field) { 293 | var field_restore = [false, false, false]; 294 | field_restore[1] = pos; 295 | field_restore[2] = i==count? tlen : pos_pieces[2*(i+1)-1]-1; 296 | field_restore[3] = last_field[3]; 297 | field_restore[4] = last_field[4]; 298 | fields.push(field_restore); 299 | last_field = field_restore; 300 | } 301 | } 302 | } 303 | return _post_format(label, txt, fields); 304 | } 305 | }; 306 | })(); -------------------------------------------------------------------------------- /lib/scissor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/22. 3 | */ 4 | 5 | ejoy2d.scissor = (function(){ 6 | var SCISSOR_MAX = 8; 7 | var scissor_tmp_array = new Array(4); 8 | 9 | var S = {}; 10 | S.depth = 0; 11 | var box = new Array(SCISSOR_MAX); 12 | var i =0; 13 | for(i =0; i < SCISSOR_MAX; ++i) { 14 | var b = { 15 | x:0, 16 | y:0, 17 | width:0, 18 | height:0, 19 | }; 20 | box[i] = b; 21 | } 22 | S.box = box; 23 | 24 | 25 | S._intersection = function(b, output) { 26 | var newx = b.x > output[0] ? b.x : output[0]; 27 | var newy = b.y > output[1] ? b.y : output[1]; 28 | 29 | var bx = b.x + b.width; 30 | var by = b.y + b.height; 31 | var ax = output[0] + output[2]; 32 | var ay = output[1] + output[3]; 33 | var neww = (bx > ax ? ax : bx) - newx; 34 | var newh = (by > ay ? ay : by) - newy; 35 | 36 | output[0] = newx; 37 | output[1] = newy; 38 | output[2] = neww; 39 | output[3] = newh; 40 | }; 41 | S.push = function(x, y, w, h) { 42 | console.assert(this.depth < SCISSOR_MAX); 43 | shader.flush(); 44 | if (this.depth == 0) { 45 | shader.scissortest(1); 46 | } 47 | 48 | if (this.depth >= 1) { 49 | scissor_tmp_array[0] = x; 50 | scissor_tmp_array[1] = y; 51 | scissor_tmp_array[2] = w; 52 | scissor_tmp_array[3] = h; 53 | this._intersection(this.box[this.depth-1], scissor_tmp_array); 54 | x = scissor_tmp_array[0]; 55 | y = scissor_tmp_array[1]; 56 | w = scissor_tmp_array[2]; 57 | h = scissor_tmp_array[3]; 58 | } 59 | 60 | var s = this.box[this.depth++]; 61 | s.x = x; 62 | s.y = y; 63 | s.width = w; 64 | s.height = h; 65 | ejoy2d.screen.scissor(s.x, s.y, s.width, s.height); 66 | }; 67 | 68 | S.pop = function() { 69 | var S = this.S; 70 | console.assert(this.depth > 0); 71 | shader.flush(); 72 | --this.depth; 73 | if (this.depth == 0) { 74 | shader.scissortest(0); 75 | return; 76 | } 77 | var s = this.box[this.depth-1]; 78 | ejoy2d.screen.scissor(s.x, s.y, s.width, s.height); 79 | } 80 | return S; 81 | }()); -------------------------------------------------------------------------------- /lib/screen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/21. 3 | */ 4 | 5 | var SCREEN_SCALE = 16; 6 | 7 | ejoy2d.screen = ((function(){ 8 | var trans_tmp = new Array(2); 9 | return { 10 | init_render:function(r) { 11 | // for ejoy2d compatibility, ejoy2d may call screen_init before screen_initrender 12 | /// screen_init(SCREEN.width, SCREEN.height, SCREEN.scale); 13 | }, 14 | init:function(w, h, scale) { 15 | //console.log("ejoy screen_init:", w, h, scale); 16 | this.width = Math.floor(w); 17 | this.height = Math.floor(h); 18 | this.scale = scale; 19 | this.invw = 2.0 / SCREEN_SCALE / w; 20 | this.invh = -2.0 / SCREEN_SCALE / h; 21 | render.setviewport(0, 0, w * scale, h * scale ); 22 | }, 23 | 24 | trans:function(x, y) { 25 | trans_tmp[0] = x * this.invw; 26 | trans_tmp[1] = y * this.invh; 27 | return trans_tmp; 28 | }, 29 | scissor:function(x, y, w, h) { 30 | y = this.height - y - h; 31 | if (x<0) { 32 | w += x; 33 | x = 0; 34 | } else if (x>this.width) { 35 | w=0; 36 | h=0; 37 | } 38 | if (y<0) { 39 | h += y; 40 | y = 0; 41 | } else if (y>this.height) { 42 | w=0; 43 | h=0; 44 | } 45 | if (w<=0 || h<=0) { 46 | w=0; 47 | h=0; 48 | } 49 | x *= this.scale; 50 | y *= this.scale; 51 | w *= this.scale; 52 | h *= this.scale; 53 | 54 | render.setscissor(x,y,w,h); 55 | }, 56 | is_visible:function(x, y) 57 | { 58 | return x >= 0.0 && x <= 2.0 && y>=-2.0 && y<= 0.0; 59 | }, 60 | is_poly_invisible:function(points, len, stride) { 61 | var i =0; 62 | // test left of x 63 | var invisible = true; 64 | for(i =0; i < len && invisible;++i) 65 | { 66 | if(points[i*stride] >= 0.0) 67 | invisible = false; 68 | } 69 | if(invisible) 70 | return true; 71 | 72 | // test right of axis x 73 | invisible = true; 74 | for(i =0; i < len && invisible;++i) 75 | { 76 | if(points[i*stride] <= 2.0) 77 | invisible = false; 78 | } 79 | if(invisible) 80 | return true; 81 | 82 | // test above of axis y 83 | invisible = true; 84 | for(i =0; i < len && invisible;++i) 85 | { 86 | if(points[i*stride +1] >= -2.0) 87 | invisible = false; 88 | } 89 | if(invisible) 90 | return true; 91 | 92 | // test below of axis y 93 | invisible = true; 94 | for(i =0; i < len && invisible;++i) 95 | { 96 | if(points[i*stride +1] <= 0.0) 97 | invisible = false; 98 | } 99 | return invisible; 100 | } 101 | }; 102 | })()); 103 | -------------------------------------------------------------------------------- /lib/shader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/15. 3 | */ 4 | 5 | var BuiltinProgram = { 6 | default : -1, 7 | picture : 0, 8 | renderbuffer : 1, 9 | text : 2, 10 | textEdge : 3, 11 | geometry : 4, 12 | }; 13 | 14 | ejoy2d.shader = (function(){ 15 | 16 | var geoVS = "\ 17 | precision lowp float;\ 18 | attribute vec4 position;\ 19 | attribute vec2 texcoord;\ 20 | attribute vec4 color;\ 21 | varying vec4 v_color;\ 22 | varying vec2 v_texcoord;\ 23 | void main() {\ 24 | gl_Position = position + vec4(-1.0, 1.0, 0.0,0.0);\ 25 | v_color = color;\ 26 | v_texcoord = texcoord;\ 27 | }"; 28 | var geoFS ="\ 29 | precision highp float;\ 30 | varying vec2 v_texcoord;\ 31 | varying vec4 v_color;\ 32 | uniform sampler2D texture0;\ 33 | void main() {\ 34 | gl_FragColor = texture2D(texture0, v_texcoord);\ 35 | }"; 36 | 37 | 38 | var spriteFS = "\ 39 | precision highp float;\ 40 | varying vec2 v_texcoord;\ 41 | varying vec4 v_color;\ 42 | varying vec4 v_additive;\ 43 | uniform sampler2D texture0;\ 44 | void main() {\ 45 | gl_FragColor = texture2D(texture0, v_texcoord);\ 46 | }"; 47 | 48 | var spriteVS = "\ 49 | precision lowp float;\ 50 | attribute vec4 position;\ 51 | attribute vec2 texcoord;\ 52 | attribute vec4 color;\ 53 | attribute vec4 additive;\ 54 | varying vec2 v_texcoord;\ 55 | varying vec4 v_color;\ 56 | varying vec4 v_additive;\ 57 | void main() {\ 58 | gl_Position = position + vec4(-1.0,1.0,0,0);\ 59 | v_texcoord = texcoord;\ 60 | v_color = color;\ 61 | v_additive = additive;\ 62 | }"; 63 | 64 | 65 | var textFS = "\ 66 | precision highp float;\ 67 | varying vec2 v_texcoord;\ 68 | varying vec4 v_color;\ 69 | varying vec4 v_additive;\ 70 | uniform sampler2D texture0;\ 71 | void main() {\ 72 | gl_FragColor = texture2D(texture0, v_texcoord);\ 73 | }"; 74 | 75 | // float c = texture2D(texture0, v_texcoord).r;\ 76 | // float alpha = clamp(c, 0.0, 0.5) * 2.0;\ 77 | // gl_FragColor.xyz = (v_color.xyz + v_additive.xyz) * alpha;\ 78 | // gl_FragColor.w = alpha;\ 79 | // gl_FragColor *= v_color.w;\ 80 | 81 | 82 | var MAX_UNIFORM = 16; 83 | var MAX_TEXTURE_CHANNEL = 8; 84 | 85 | var MAX_COMMBINE = 512; 86 | var MAX_PROGRAM = 8; 87 | var ATTRIB_VERTEX = 0; 88 | var ATTRIB_TEXTCOORD = 1; 89 | var ATTRIB_COLOR = 2; 90 | 91 | var _RS = null; 92 | return { 93 | init: function () { 94 | if (_RS) return; 95 | 96 | var rs = { 97 | current_program: null, 98 | blendchange: 0, 99 | object: 0, 100 | tex : [] 101 | }; 102 | rs.program = []; 103 | for (i = 0; i < MAX_PROGRAM; ++i) { 104 | rs.program[i] = {}; 105 | } 106 | 107 | var renderInitArgs = {}; 108 | renderInitArgs.max_buffer = 128; 109 | renderInitArgs.max_layout = 4; 110 | renderInitArgs.max_target = 128; 111 | renderInitArgs.max_texture = 256; 112 | renderInitArgs.max_shader = MAX_PROGRAM; 113 | 114 | rs.R = render.init(renderInitArgs); 115 | texture.init_render(rs.R); 116 | // ejoy2d.screen.init_render(rs.R); 117 | //label.init_render(rs.R); 118 | //sprite.init_render(rs.R); 119 | ///renderbuffer.init_render(rs.R); 120 | 121 | render.setblend(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); 122 | 123 | rs.index_buffer = gl.createBuffer(); 124 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, rs.index_buffer); 125 | 126 | var idxs = new Uint16Array(6 *MAX_COMMBINE); 127 | for (i = 0; i < MAX_COMMBINE; i++) { 128 | idxs[i * 6] = i * 4; 129 | idxs[i * 6 + 1] = i * 4 + 1; 130 | idxs[i * 6 + 2] = i * 4 + 2; 131 | idxs[i * 6 + 3] = i * 4; 132 | idxs[i * 6 + 4] = i * 4 + 2; 133 | idxs[i * 6 + 5] = i * 4 + 3; 134 | } 135 | 136 | rs.index_buffer = render.buffer_create(INDEXBUFFER, idxs, 6 * MAX_COMMBINE, 2); 137 | rs.vertex_buffer = render.buffer_create(VERTEXBUFFER, null, 4 * MAX_COMMBINE, 2*4 + 2*2 + 4 +4); 138 | 139 | var va = [ 140 | { name: "position", vbslot : 0, n : 2, size: 4, offset : 0 }, 141 | { name: "texcoord", vbslot : 0, n : 2, size: 2, offset : 8 }, 142 | { name: "color", vbslot : 0, n : 4, size: 1, offset : 12 }, 143 | { name: "additive", vbslot : 0, n : 4, size: 1, offset : 16 }, 144 | ]; 145 | rs.layout = render.register_vertexlayout(4, va); 146 | rs.vb = new ejoy2d.renderbuffer(); 147 | render.set(VERTEXLAYOUT, rs.layout, 0); 148 | render.set(INDEXBUFFER, rs.index_buffer, 0); 149 | render.set(VERTEXBUFFER, rs.vertex_buffer, 0); 150 | 151 | _RS = rs; 152 | 153 | ejoy2d.shader.load(BuiltinProgram.geometry, geoFS, geoVS); 154 | ejoy2d.shader.load(BuiltinProgram.picture, spriteFS, spriteVS); 155 | ejoy2d.shader.load(BuiltinProgram.text, textFS, spriteVS); 156 | 157 | }, 158 | reset:function() { 159 | render.state_reset(); 160 | render.setblend(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); 161 | if (_RS.current_program != -1) { 162 | render.shader_bind(_RS.program[_RS.current_program].prog); 163 | } 164 | render.set(VERTEXLAYOUT, rs.layout, 0); 165 | render.set(TEXTURE, _RS.tex[0], 0); 166 | render.set(INDEXBUFFER, _RS.index_buffer,0); 167 | render.set(VERTEXBUFFER, _RS.vertex_buffer,0); 168 | }, 169 | 170 | program_init: function (p, fs, vs, texUniformNames) { 171 | var args = {}; 172 | args.vs = vs; 173 | args.fs = fs; 174 | args.texture = texture; 175 | args.texture_uniform = texUniformNames; 176 | p.prog = render.shader_create(args); 177 | render.shader_bind(p.prog); 178 | render.shader_bind(0); 179 | }, 180 | 181 | 182 | 183 | renderbuffer_commit:function(rb) { 184 | render.draw(DRAW_TRIANGLE, 0, 6 * rb.object); 185 | }, 186 | 187 | rs_commit: function() { 188 | var rb = _RS.vb; 189 | if (rb.object == 0) 190 | return; 191 | render.buffer_update(_RS.vertex_buffer, rb.quad, 4 * rb.object); 192 | this.renderbuffer_commit(rb); 193 | 194 | rb.object = 0; 195 | }, 196 | 197 | drawbuffer : function(rb, tx, ty, scale) { 198 | this.rs_commit(); 199 | 200 | var glid = texture.glid(rb.texid); 201 | if (!glid) 202 | return; 203 | this.texture(glid, 0); 204 | render.set(VERTEXBUFFER, rb.vbid, 0); 205 | 206 | var transed = ejoy2d.screen.trans(scale,scale); 207 | var sx = transed[0]; 208 | var sy = transed[1]; 209 | transed = ejoy2d.screen.trans(tx, ty); 210 | var tx = transed[0]; 211 | var ty = transed[1]; 212 | var v = [sx, sy, tx, ty]; 213 | // we should call shader_adduniform to add "st" uniform first 214 | this.setuniform(PROGRAM_RENDERBUFFER, 0, UNIFORM_FLOAT4, v); 215 | 216 | this.program(PROGRAM_RENDERBUFFER); 217 | 218 | this.renderbuffer_commit(rb); 219 | 220 | render.set(VERTEXBUFFER, _RS.vertex_buffer, 0); 221 | }, 222 | 223 | texture: function (id, channel) { 224 | console.assert(channel < MAX_TEXTURE_CHANNEL); 225 | var ts = _RS.tex; 226 | if (ts[channel] != id) { 227 | this.rs_commit(); 228 | ts[channel] = id; 229 | render.set(TEXTURE, id, channel); 230 | } 231 | }, 232 | apply_uniform: function(p) { 233 | for (var i=0;i=0) 237 | render.shader_setuniform(u.loc, u.type, p.uniform_value, u.offset); 238 | } 239 | } 240 | p.reset_uniform = false; 241 | }, 242 | 243 | program: function (n, m) { 244 | var p = _RS.program[n]; 245 | if (_RS.current_program != n || p.reset_uniform || m) { 246 | this.rs_commit(); 247 | } 248 | if (_RS.current_program != n) { 249 | _RS.current_program = n; 250 | render.shader_bind(p.prog); 251 | delete p.material; 252 | this.apply_uniform(p); 253 | } else if (p.reset_uniform) { 254 | this.apply_uniform(p); 255 | } 256 | if (m) { 257 | m.apply(_RS, n); 258 | } 259 | }, 260 | 261 | mask: function (x, y) { 262 | var rs = _RS; 263 | var p = rs.program[rs.current_program]; 264 | if (!p || p.mask == null) 265 | return; 266 | if (p.arg_mask_x == x && p.arg_mask_y == y) 267 | return; 268 | p.arg_mask_x = x; 269 | p.arg_mask_y = y; 270 | gl.uniform2f(p.mask, x, y); 271 | }, 272 | 273 | do_draw: function (vb, color, additive) { 274 | if (_RS.vb.add(vb, color, additive)) { 275 | this.rs_commit(); 276 | } 277 | }, 278 | 279 | draw_quad: function (vbp, color, max, index) { 280 | var vb = new Array(16); 281 | var i = 0; 282 | /// first point 283 | for (i = 0; i < 4; ++i) { 284 | vb[i] = vbp[i] 285 | } 286 | 287 | /// other vertex 288 | for (i = 1; i < 4; i++) { 289 | var j = i + index; 290 | var n = (j <= max) ? j : max; 291 | for (var u = 0; u < 4; ++u) { 292 | vb[u + i * 4] = vbp[n * 4 + u]; 293 | } 294 | } 295 | this.do_draw(vb, color); 296 | }, 297 | 298 | 299 | drawpolygon: function (n, vb, color, additive) { 300 | var i = 0; 301 | --n; 302 | do { 303 | this.draw_quad(vb, color, n, i); 304 | i += 2; 305 | } while (i < n - 1); 306 | }, 307 | 308 | flush: function () { 309 | this.rs_commit(); 310 | }, 311 | 312 | defaultblend: function () { 313 | var rs = _RS; 314 | if (rs.blendchange) { 315 | this.rs_commit(); 316 | rs.blendchange = false; 317 | render.setblend(BLEND_ONE, BLEND_ONE_MINUS_SRC_ALPHA); 318 | } 319 | }, 320 | scissortest:function(enable) { 321 | render.enablescissor(enable); 322 | }, 323 | uniformsize:function(t) { 324 | var n = 0; 325 | switch(t) { 326 | case UNIFORM_INVALID: 327 | n = 0; 328 | break; 329 | case UNIFORM_FLOAT1: 330 | n = 1; 331 | break; 332 | case UNIFORM_FLOAT2: 333 | n = 2; 334 | break; 335 | case UNIFORM_FLOAT3: 336 | n = 3; 337 | break; 338 | case UNIFORM_FLOAT4: 339 | n = 4; 340 | break; 341 | case UNIFORM_FLOAT33: 342 | n = 9; 343 | break; 344 | case UNIFORM_FLOAT44: 345 | n = 16; 346 | break; 347 | } 348 | return n; 349 | }, 350 | setuniform:function(prog, index, t, v) { 351 | this.rs_commit(); 352 | var p = _RS.program[prog]; 353 | console.assert(index >= 0 && index < p.uniform_number); 354 | var u = p.uniform[index]; 355 | console.assert(t == u.type); 356 | var n = this.uniformsize(t); 357 | var offset = u.offset; 358 | for(var i = 0; i < n; ++i) { 359 | p.uniform_value[offset +i] = v[i]; 360 | } 361 | p.reset_uniform = true; 362 | p.uniform_change[index] = true; 363 | }, 364 | 365 | adduniform:function(prog, name, t) { 366 | // reset current_program 367 | console.assert(prog >=0 && prog < MAX_PROGRAM); 368 | this.program(prog); 369 | var p = _RS.program[prog]; 370 | console.assert(p.uniform_number < MAX_UNIFORM); 371 | var loc = render.shader_locuniform(name); 372 | var index = p.uniform_number++; 373 | var u = p.uniform[index]; 374 | u.loc = loc; 375 | u.type = t; 376 | if (index == 0) { 377 | u.offset = 0; 378 | } else { 379 | var lu = p.uniform[index-1]; 380 | u.offset = lu.offset + this.uniformsize(lu.type); 381 | } 382 | if (loc < 0) 383 | return -1; 384 | return index; 385 | }, 386 | ////////////////////////////////////////////// 387 | /////////////////// API ////////////////////// 388 | load: function (prog, fs, vs, texture, texUniformNames) { 389 | if(!texture) { 390 | texture = 0; 391 | texUniformNames = new Array(); 392 | } 393 | var rs = _RS; 394 | console.assert(prog >= 0 && prog < MAX_PROGRAM); 395 | var p = rs.program[prog]; 396 | if(p.prog){ 397 | render.release(SHADER, p.prog); 398 | p.prog = 0; 399 | } 400 | this.program_init(p, fs, vs, texUniformNames); 401 | p.texture_number = texture; 402 | _RS.current_program = -1; 403 | }, 404 | 405 | unload: function () { 406 | if (_RS == NULL) { 407 | return; 408 | } 409 | 410 | texture.initrender(); 411 | ejoy2d.screen.initrender(); 412 | //label.initrender(); 413 | sprite.initrender(); 414 | renderbuffer.initrender(); 415 | 416 | render.exit(); 417 | _RS = null; 418 | }, 419 | blend: function (m1, m2) { 420 | if((!m1) || (!m2)) 421 | { 422 | this.defaultblend(); 423 | } 424 | if (m1 != BLEND_GL_ONE || m2 != BLEND_GL_ONE_MINUS_SRC_ALPHA) { 425 | this.rs_commit(); 426 | _RS.blendchange = true; 427 | var src = blendmode.blend_mode(m1); 428 | var dst = blendmode.blend_mode(m2); 429 | render.setblend(src, dst); 430 | } 431 | }, 432 | /* 433 | int texture 434 | table float[16] 435 | uint32_t color 436 | uint32_t additive 437 | */ 438 | draw:function(tex, vb, color, additive) { 439 | var texid = texture.glid(tex); 440 | if (texid == undefined) { 441 | return false; 442 | } 443 | if(color == undefined) { 444 | color = 0xffffffff; 445 | } 446 | if( additive == undefined) { 447 | additive = 0; 448 | } 449 | this.program(BuiltinProgram.picture, null); 450 | this.texture(texid, 0); 451 | 452 | var cnt = vb.length/4; 453 | var vbb = []; 454 | for (var i=0;i> 24) & 0xff; 14 | var g1 = (c1 >> 16) & 0xff; 15 | var b1 = (c1 >> 8) & 0xff; 16 | var a1 = (c1) & 0xff; 17 | var r2 = (c2 >> 24) & 0xff; 18 | var g2 = (c2 >> 16) & 0xff; 19 | var b2 = (c2 >> 8) & 0xff; 20 | var a2 = c2 & 0xff; 21 | 22 | return (r1 * r2 /255) << 24 | 23 | (g1 * g2 /255) << 16 | 24 | (b1 * b2 /255) << 8 | 25 | (a1 * a2 /255) ; 26 | }; 27 | 28 | var clamp =function(c) { 29 | return ((c) > 255 ? 255 : (c)); 30 | }; 31 | 32 | var color_add = function(c1, c2) { 33 | var r1 = (c1 >> 16) & 0xff; 34 | var g1 = (c1 >> 8) & 0xff; 35 | var b1 = (c1) & 0xff; 36 | var r2 = (c2 >> 16) & 0xff; 37 | var g2 = (c2 >> 8) & 0xff; 38 | var b2 = (c2) & 0xff; 39 | return clamp(r1+r2) << 16 | 40 | clamp(g1+g2) << 8 | 41 | clamp(b1+b2); 42 | }; 43 | var log_cnt = 0; 44 | 45 | return { 46 | copyFrom : function(a){ 47 | if(a.mat) 48 | this.mat = a.mat.clone(); 49 | this.color = a.color; 50 | this.additive = a.additive; 51 | this.program = a.program; 52 | }, 53 | mul: function(a, b, output) { 54 | this.copyFrom(a); 55 | if (!b) { 56 | return this; 57 | } 58 | if (!this.mat) { 59 | this.mat = b.mat?b.mat.clone() : new ejoy2d.matrix(); 60 | } else if (b.mat) { 61 | this.mat.mul(this.mat, b.mat); 62 | } 63 | 64 | if (this.color == 0xffffffff) { 65 | this.color = b.color; 66 | } else if (b.color != 0xffffffff) { 67 | this.color = color_mul(this.color, b.color); 68 | } 69 | if (this.additive == 0) { 70 | this.additive = b.additive; 71 | } else if (b.additive != 0) { 72 | this.additive = color_add(this.additive, b.additive); 73 | } 74 | if (this.program == BuiltinProgram.default) { 75 | this.program = b.program; 76 | } 77 | return this; 78 | } 79 | }; 80 | })()); 81 | -------------------------------------------------------------------------------- /lib/spritepack.js: -------------------------------------------------------------------------------- 1 | var SpriteType = { 2 | empty : 0, 3 | picture : 1, 4 | animation : 2, 5 | polygon : 3, 6 | label : 4, 7 | panel : 5, 8 | anchor : 6, 9 | matrix : 7 10 | }; 11 | 12 | ejoy2d.spritepack = function(json, texs) { 13 | this.tex = texs; 14 | var data = new Array(); 15 | this.data = data; 16 | var namedCmp = {}; 17 | this.namedCmp = namedCmp; 18 | var allMatrix = null; 19 | for(var i in json) { 20 | var v = json[i]; 21 | var cmp = {}; 22 | cmp.type = v[0]; 23 | switch(cmp.type) { 24 | case SpriteType.label: 25 | cmp.id = v[1]; 26 | cmp.color = v[2]; 27 | cmp.width = v[3]; 28 | cmp.height = v[4]; 29 | cmp.align = v[5]; 30 | cmp.size = v[6]; 31 | cmp.edge = v[7]; 32 | cmp.auto_scale = v[8]; 33 | break; 34 | case SpriteType.panel: 35 | cmp.id = v[1]; 36 | cmp.width = v[2]; 37 | cmp.height = v[3]; 38 | cmp.scissor = v[4]; 39 | break; 40 | case SpriteType.matrix: 41 | allMatrix = v; 42 | break; 43 | case SpriteType.picture: 44 | cmp.id = v[1]; 45 | var info = v[2]; 46 | var rect = {}; 47 | rect.texid = info[0]; 48 | rect.texture_coord = [];// = info[1].slice(0); 49 | for(var ti = 0; ti < 4; ++ti) { 50 | var idx = ti*2; 51 | var tc = ejoy2d.texture.texcoord(info[0], info[1][idx], info[1][idx +1]); 52 | rect.texture_coord[idx] = tc[0]; 53 | rect.texture_coord[idx +1] = tc[1]; 54 | } 55 | rect.screen_coord = info[2].slice(0); 56 | cmp.rect = []; 57 | cmp.n = 1; 58 | cmp.rect.push(rect); 59 | break; 60 | case SpriteType.animation: 61 | cmp.id = v[1]; 62 | var cc = v[2]; 63 | 64 | if(v[4]) // exported 65 | namedCmp[v[4]] = v[1]; 66 | 67 | var c = new Array(); 68 | cmp.component = c; 69 | for(var idx in cc) 70 | { 71 | var cmpPart = {}; 72 | if(typeof(cc[idx]) == "number") { 73 | cmpPart.id = cc[idx]; 74 | } else { 75 | cmpPart.id = cc[idx][0]; 76 | cmpPart.name = cc[idx][1]; 77 | } 78 | c[idx] = cmpPart; 79 | } 80 | var frames = new Array(); 81 | cmp.frame = frames; 82 | for(var uu in v[3]){ 83 | var fd = v[3][uu] 84 | var oneFrame = new Array(); 85 | for(var ii in fd ){ 86 | var f = {} 87 | var f1 = fd[ii]; 88 | if(typeof(f1) == "number") { 89 | f.component_id = f1; 90 | f.t = new ejoy2d.sprite_trans(); 91 | } else { 92 | f.component_id = f1[0]; 93 | f.t = new ejoy2d.sprite_trans(); 94 | if(typeof(f1[1]) == "number") 95 | f.t.mat = new ejoy2d.matrix(allMatrix[f1[1] +1]); 96 | else 97 | f.t.mat = new ejoy2d.matrix(f1[1]); 98 | f.touchable = f1[2]; 99 | } 100 | oneFrame[ii] = f; 101 | } 102 | frames[uu] = oneFrame; 103 | } 104 | var action = []; 105 | var a = {}; 106 | a.start_frame =0; 107 | a.number = frames.length; 108 | action.push(a); 109 | cmp.action = action; 110 | 111 | break; 112 | } 113 | data[cmp.id] = cmp; 114 | } 115 | }; 116 | 117 | ejoy2d.spritepack.prototype = { 118 | getDataByName: function (name) { 119 | return this.data[this.namedCmp[name]]; 120 | }, 121 | getIDByName: function (name) { 122 | return this.namedCmp[name]; 123 | } 124 | }; 125 | -------------------------------------------------------------------------------- /lib/string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/8/20. 3 | */ 4 | /** 5 | * @name ejoy2d.string 6 | * @namespace Extended String API 7 | */ 8 | ejoy2d.string = function () { 9 | return { 10 | /** 11 | * @name ejoy2d.string.ASCII_LOWERCASE 12 | * @description All lowercase letters 13 | * @type String 14 | */ 15 | ASCII_LOWERCASE: "abcdefghijklmnopqrstuvwxyz", 16 | 17 | /** 18 | * @name ejoy2d.string.ASCII_UPPERCASE 19 | * @description All uppercase letters 20 | * @type String 21 | */ 22 | ASCII_UPPERCASE: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 23 | 24 | /** 25 | * @name ejoy2d.string.ASCII_LETTERS 26 | * @description All ASCII letters 27 | * @type String 28 | */ 29 | ASCII_LETTERS: this.ASCII_LOWERCASE + this.ASCII_UPPERCASE, 30 | /** 31 | * @function 32 | * @name ejoy2d.string.format 33 | * @description Return a string with {n} replaced with the n-th argument 34 | * @param {String} s The string to format 35 | * @param {Object} [arguments] All other arguments are substituted into the string 36 | * @returns {String} The formatted string 37 | * @example 38 | * var s = ejoy2d.string.format("Hello {0}", "world"); 39 | * console.log(s); // Prints "Hello world" 40 | */ 41 | format: function (s) { 42 | var i = 0, 43 | regexp, 44 | args = ejoy2d.makeArray(arguments); 45 | 46 | // drop first argument 47 | args.shift(); 48 | 49 | for (i = 0; i < args.length; i++) { 50 | regexp = new RegExp('\\{' + i + '\\}', 'gi'); 51 | s = s.replace(regexp, args[i]); 52 | } 53 | return s; 54 | }, 55 | 56 | /** 57 | * @function 58 | * @name ejoy2d.string.startsWith 59 | * @description Check if a string s starts with another string subs 60 | * @param {String} s The string to look in 61 | * @param {String} subs The string to look for 62 | * @returns {Boolean} True if s starts with subs 63 | * @example 64 | * var s = "abc"; 65 | * if (ejoy2d.string.startsWith(s, "a")) { 66 | * console.log('Starts with a'); 67 | * } 68 | */ 69 | startsWith: function (s, subs) { 70 | return (s.indexOf(subs) === 0); 71 | }, 72 | 73 | /** 74 | * @function 75 | * @name ejoy2d.string.endsWith 76 | * @description Check if a string s ends with another string subs 77 | * @param {String} s The string to look in 78 | * @param {String} subs The string to look for 79 | * @returns {Boolean} True if s ends with subs 80 | */ 81 | endsWith: function (s, subs) { 82 | return (s.lastIndexOf(subs, s.length - subs.length) !== -1); 83 | }, 84 | 85 | /** 86 | * @function 87 | * @name ejoy2d.string.toBool 88 | * @description Convert a string value to a boolean. In non-strict mode (the default), 'true' is converted to true, all other values 89 | * are converted to false. In strict mode, 'true' is converted to true, 'false' is converted to false, all other values will throw 90 | * an Exception. 91 | * @param {String} s The string to convert 92 | * @param {Boolean} [strict] In strict mode an Exception is thrown if s is not an accepted string value. Defaults to false 93 | * @returns {Boolean} The converted value 94 | */ 95 | toBool: function (s, strict) { 96 | if (s === 'true') { 97 | return true; 98 | } 99 | 100 | if (strict) { 101 | if (s === 'false') { 102 | return false; 103 | } 104 | 105 | throw new Error('Not a boolean string'); 106 | } 107 | 108 | return false; 109 | } 110 | }; 111 | } (); 112 | 113 | -------------------------------------------------------------------------------- /lib/text.js: -------------------------------------------------------------------------------- 1 | 2 | ejoy2d.text = ((function () { 3 | var context; 4 | return { 5 | init : function() { 6 | var canvas = document.getElementById("text"); 7 | // make a 2D context for it 8 | var ctx = textCanvas.getContext("2d"); 9 | } 10 | }; 11 | })()) 12 | -------------------------------------------------------------------------------- /lib/texture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/6/16. 3 | */ 4 | 5 | ejoy2d.texture = (function (){ 6 | var R = null; 7 | /// texture pool 8 | var pool = new Array(); 9 | var texcoord_tmp = new Array(2); 10 | return { 11 | init_render: function (r) { 12 | R = r; 13 | }, 14 | 15 | load: function (id, pixel_format, pixel_width, pixel_height, data) { 16 | if (id >= this.MAX_TEXTURE) { 17 | return "Too many texture"; 18 | } 19 | var tex = pool[id]; 20 | if (!tex) { 21 | tex = {}; 22 | pool[id] = tex; 23 | } 24 | 25 | tex.fb = 0; 26 | tex.width = pixel_width; 27 | tex.height = pixel_height; 28 | tex.invw = 1.0 / pixel_width; 29 | tex.invh = 1.0 / pixel_height; 30 | if (!tex.id) { 31 | tex.id = ejoy2d.render.texture_create(pixel_width, pixel_height, pixel_format, TEXTURE_2D, 0); 32 | } 33 | if (!data) { 34 | return; 35 | } 36 | 37 | ejoy2d.render.texture_update(tex.id, pixel_width, pixel_height, data, 0, 0); 38 | }, 39 | load_img: function (id, pixel_format, img) { 40 | if (id >= this.MAX_TEXTURE) { 41 | return "Too many texture"; 42 | } 43 | 44 | if (!img) { 45 | return; 46 | } 47 | 48 | var tex = pool[id]; 49 | if (!tex) { 50 | tex = {}; 51 | pool[id] = tex; 52 | } 53 | 54 | tex.fb = 0; 55 | tex.width = img.width; 56 | tex.height = img.height; 57 | tex.invw = 1.0 / img.width; 58 | tex.invh = 1.0 / img.height; 59 | if (!tex.id) { 60 | tex.id = ejoy2d.render.texture_create(img.width, img.height, pixel_format, TEXTURE_2D, 0); 61 | } 62 | 63 | ejoy2d.render.texture_update_img(tex.id, img, 0, 0); 64 | }, 65 | 66 | texcoord: function (id, x, y) { 67 | if (id < 0 || id >= pool.length) { 68 | return [Math.floor(x), Math.floor(y)]; 69 | } 70 | //console.log("------------>>> texcoord for:", id, pool.length); 71 | var tex = pool[id]; 72 | if (!tex.invw) { 73 | // not load the texture 74 | texcoord_tmp[0] = Math.floor(x); 75 | texcoord_tmp[1] = Math.floor(y); 76 | return texcoord_tmp; 77 | } 78 | 79 | x *= tex.invw; 80 | y *= tex.invh; 81 | if (x > 1.0) 82 | x = 1.0; 83 | if (y > 1.0) 84 | y = 1.0; 85 | 86 | x *= 0xffff; 87 | y *= 0xffff; 88 | 89 | texcoord_tmp[0] = Math.floor(x); 90 | texcoord_tmp[1] = Math.floor(y); 91 | return texcoord_tmp; 92 | }, 93 | unload: function (id) { 94 | if (id < 0 || id >= pool.length) 95 | return; 96 | var tex = pool[id]; 97 | if (!tex.id) 98 | return; 99 | ejoy2d.render.release(TEXTURE, tex.id); 100 | if (tex.fb) 101 | ejoy2d.render.release(TARGET, tex.fb); 102 | delete tex.id; 103 | delete tex.fb; 104 | }, 105 | 106 | glid: function (id) { 107 | if (id < 0 || id >= pool.length) 108 | return; 109 | var tex = pool[id]; 110 | return tex.id; 111 | }, 112 | clearall: function () { 113 | var i; 114 | for (i = 0; i < pool_count; i++) { 115 | this.unload(i); 116 | } 117 | }, 118 | 119 | set_inv: function (id, invw, invh) { 120 | if (id < 0 || id >= pool.length) 121 | return; 122 | 123 | var tex = pool[id]; 124 | tex.invw = invw; 125 | tex.invh = invh; 126 | }, 127 | 128 | swap: function (ida, idb) { 129 | if (ida < 0 || idb < 0 || ida >= pool.length || idb >= pool.length) 130 | return; 131 | 132 | var pool = pool; 133 | var tex = pool[ida]; 134 | pool[ida] = pool[idb]; 135 | pool[idb] = tex; 136 | }, 137 | 138 | size: function (id) { 139 | if (id < 0 || id >= pool.length) 140 | return; 141 | var tex = pool[id]; 142 | return [tex.width, tex.height]; 143 | }, 144 | 145 | delete_framebuffer: function (id) { 146 | if (id < 0 || id >= pool.length) 147 | return; 148 | 149 | var tex = pool[id]; 150 | if (tex.fb) { 151 | ejoy2d.render.release(TARGET, tex.fb); 152 | delete tex.fb; 153 | } 154 | }, 155 | 156 | update: function (id, pixel_width, pixel_height, data) { 157 | if (id >= this.MAX_TEXTURE) { 158 | return "Too many texture"; 159 | } 160 | 161 | if (!data) { 162 | return "no content"; 163 | } 164 | var tex = pool[id]; 165 | if (!tex.id) { 166 | return "not a valid texture"; 167 | } 168 | ejoy2d.render.texture_update(tex.id, pixel_width, pixel_height, data, 0, 0); 169 | } 170 | }; 171 | })(); 172 | -------------------------------------------------------------------------------- /lib/uri.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by v on 2015/8/20. 3 | */ 4 | 5 | ejoy2d.URI = function (uri) { 6 | // See http://tools.ietf.org/html/rfc2396#appendix-B for details of RegExp 7 | var re = /^(([^:\/?\#]+):)?(\/\/([^\/?\#]*))?([^?\#]*)(\?([^\#]*))?(\#(.*))?/, 8 | result = uri.match(re); 9 | 10 | /** 11 | * @name pc.URI#scheme 12 | * @description The scheme. (e.g. http) 13 | */ 14 | this.scheme = result[2]; 15 | 16 | /** 17 | * @name pc.URI#authority 18 | * @description The authority. (e.g. www.example.com) 19 | */ 20 | this.authority = result[4]; 21 | 22 | /** 23 | * @name pc.URI#path 24 | * @description The path. (e.g. /users/example) 25 | */ 26 | this.path = result[5]; 27 | 28 | /** 29 | * @name pc.URI#query 30 | * @description The query, the section after a ?. (e.g. search=value) 31 | */ 32 | this.query = result[7]; 33 | 34 | /** 35 | * @name pc.URI#fragment 36 | * @description The fragment, the section after a # 37 | */ 38 | this.fragment = result[9]; 39 | 40 | /** 41 | * @function 42 | * @name pc.URI#toString 43 | * @description Convert URI back to string 44 | */ 45 | this.toString = function () { 46 | var s = ""; 47 | 48 | if (this.scheme) { 49 | s += this.scheme + ":"; 50 | } 51 | 52 | if (this.authority) { 53 | s += "//" + this.authority; 54 | } 55 | 56 | s += this.path; 57 | 58 | if (this.query) { 59 | s += "?" + this.query; 60 | } 61 | 62 | if (this.fragment) { 63 | s += "#" + this.fragment; 64 | } 65 | 66 | return s; 67 | }; 68 | 69 | /** 70 | * @function 71 | * @name pc.URI#getQuery 72 | * @description Returns the query parameters as an Object 73 | * @example 74 | *
 75 |      * var s = "http://example.com?a=1&b=2&c=3
 76 |      * var uri = new pc.URI(s);
 77 |      * var q = uri.getQuery();
 78 |      * console.log(q.a); // logs "1"
 79 |      * console.log(q.b); // logs "2"
 80 |      * console.log(q.c); // logs "3"
 81 |      * 
82 | */ 83 | this.getQuery = function () { 84 | var vars; 85 | var pair; 86 | var result = {}; 87 | 88 | if (this.query) { 89 | vars = decodeURIComponent(this.query).split("&"); 90 | vars.forEach(function (item, index, arr) { 91 | pair = item.split("="); 92 | result[pair[0]] = pair[1]; 93 | }, this); 94 | } 95 | 96 | return result; 97 | }; 98 | 99 | /** 100 | * @function 101 | * @name pc.URI#setQuery 102 | * @description Set the query section of the URI from a Object 103 | * @param {Object} params Key-Value pairs to encode into the query string 104 | * @example 105 | * var s = "http://example.com"; 106 | * var uri = new pc.URI(s); 107 | * uri.setQuery({"a":1,"b":2}); 108 | * console.log(uri.toString()); // logs "http://example.com?a=1&b=2 109 | */ 110 | this.setQuery = function (params) { 111 | q = ""; 112 | for (var key in params) { 113 | if (params.hasOwnProperty(key)) { 114 | if (q !== "") { 115 | q += "&"; 116 | } 117 | q += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]); 118 | } 119 | } 120 | 121 | this.query = q; 122 | }; 123 | }; -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WebGLUtils = function() { 5 | 6 | /** 7 | * Creates the HTLM for a failure message 8 | * @param {string} canvasContainerId id of container of th 9 | * canvas. 10 | * @return {string} The html. 11 | */ 12 | var makeFailHTML = function(msg) { 13 | return '' + 14 | '' + 15 | '
' + 16 | '
' + 17 | '
' + msg + '
' + 18 | '
' + 19 | '
'; 20 | }; 21 | 22 | /** 23 | * Mesasge for getting a webgl browser 24 | * @type {string} 25 | */ 26 | var GET_A_WEBGL_BROWSER = '' + 27 | 'This page requires a browser that supports WebGL.
' + 28 | 'Click here to upgrade your browser.'; 29 | 30 | /** 31 | * Mesasge for need better hardware 32 | * @type {string} 33 | */ 34 | var OTHER_PROBLEM = '' + 35 | "It doesn't appear your computer can support WebGL.
" + 36 | 'Click here for more information.'; 37 | 38 | /** 39 | * Creates a webgl context. If creation fails it will 40 | * change the contents of the container of the 41 | * tag to an error message with the correct links for WebGL. 42 | * @param {Element} canvas. The canvas element to create a 43 | * context from. 44 | * @param {WebGLContextCreationAttirbutes} opt_attribs Any 45 | * creation attributes you want to pass in. 46 | * @param {function:(msg)} opt_onError An function to call 47 | * if there is an error during creation. 48 | * @return {WebGLRenderingContext} The created context. 49 | */ 50 | var setupWebGL = function(canvas, opt_attribs, opt_onError) { 51 | function handleCreationError(msg) { 52 | var container = canvas.parentNode; 53 | if (container) { 54 | var str = window.WebGLRenderingContext ? 55 | OTHER_PROBLEM : 56 | GET_A_WEBGL_BROWSER; 57 | if (msg) { 58 | str += "

Status: " + msg; 59 | } 60 | container.innerHTML = makeFailHTML(str); 61 | } 62 | }; 63 | 64 | opt_onError = opt_onError || handleCreationError; 65 | 66 | if (canvas.addEventListener) { 67 | canvas.addEventListener("webglcontextcreationerror", function(event) { 68 | opt_onError(event.statusMessage); 69 | }, false); 70 | } 71 | var context = create3DContext(canvas, opt_attribs); 72 | if (!context) { 73 | if (!window.WebGLRenderingContext) { 74 | opt_onError(""); 75 | } 76 | } 77 | return context; 78 | }; 79 | 80 | /** 81 | * Creates a webgl context. 82 | * @param {!Canvas} canvas The canvas tag to get context 83 | * from. If one is not passed in one will be created. 84 | * @return {!WebGLContext} The created context. 85 | */ 86 | var create3DContext = function(canvas, opt_attribs) { 87 | var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; 88 | var context = null; 89 | for (var ii = 0; ii < names.length; ++ii) { 90 | try { 91 | context = canvas.getContext(names[ii], opt_attribs); 92 | } catch(e) {} 93 | if (context) { 94 | break; 95 | } 96 | } 97 | return context; 98 | }; 99 | var checkGLError = function(gl) { 100 | var err = gl.getError(); 101 | if(err != 0 ) { 102 | console.trace(); 103 | console.log("Ejoy2D gl Error: %d", err); 104 | } 105 | }; 106 | 107 | 108 | return { 109 | create3DContext: create3DContext, 110 | setupWebGL: setupWebGL, 111 | checkGLError:checkGLError 112 | }; 113 | }(); 114 | 115 | 116 | 117 | /** 118 | * Provides requestAnimationFrame in a cross browser way. 119 | */ 120 | window.requestAnimFrame = (function() { 121 | return window.requestAnimationFrame || 122 | window.webkitRequestAnimationFrame || 123 | window.mozRequestAnimationFrame || 124 | window.oRequestAnimationFrame || 125 | window.msRequestAnimationFrame || 126 | function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { 127 | window.setTimeout(callback, 1000/60); 128 | }; 129 | })(); 130 | -------------------------------------------------------------------------------- /sample/ex01.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ejoy2d-js 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Base sprite draw
35 |
36 | 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /sample/ex02.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ejoy2d-js 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Debug draw demo
35 |
36 | 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /sample/ex04.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ejoy2d-js 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Hit test. Click the mine sprite
35 |
36 | 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /sample/ex05.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ejoy2d-js 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | Mount sprite
35 |
36 | 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /sample/sample.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqrt2v/ejoy2d_js/694fa499a2d8b2db4856632d32d881cbd7a044c0/sample/sample.1.png -------------------------------------------------------------------------------- /sample/sample.json: -------------------------------------------------------------------------------- 1 | [[7,[1008,-175,175,1008,136,787]],[1,0,[1,[226,61,226,94,254,94,254,61],[-382,-640,-382,428,514,428,514,-640]]],[1,1,[1,[66,97,34,97,34,128,66,128],[-368,-620,-372,388,604,392,608,-616]]],[1,2,[1,[178,112,144,112,144,137,178,137],[-388,-652,-384,452,416,452,412,-652]]],[1,3,[1,[73,73,37,73,37,97,73,97],[-392,-656,-392,496,376,496,376,-656]]],[1,4,[1,[36,73,0,73,0,97,36,97],[-388,-656,-388,496,380,496,380,-656]]],[1,5,[1,[204,122,204,152,238,152,238,122],[-408,-608,-408,352,680,352,680,-608]]],[1,6,[1,[204,95,204,121,241,121,241,95],[-450,-568,-450,276,734,276,734,-568]]],[1,7,[1,[187,54,187,79,226,79,226,54],[-478,-556,-478,244,758,244,758,-556]]],[1,8,[1,[193,0,193,26,233,26,233,0],[-494,-580,-494,240,786,240,786,-580]]],[1,9,[1,[187,26,187,54,226,54,226,26],[-494,-636,-494,248,754,248,754,-636]]],[1,10,[1,[88,46,88,75,127,75,127,46],[-486,-696,-486,244,762,244,762,-696]]],[1,11,[1,[147,25,147,56,187,56,187,25],[-478,-748,-478,244,790,244,790,-748]]],[1,12,[1,[166,80,166,112,203,112,203,80],[-454,-784,-454,240,730,240,730,-784]]],[1,13,[1,[109,92,109,125,143,125,143,92],[-424,-820,-424,224,676,224,676,-820]]],[1,14,[1,[34,97,0,97,0,129,34,129],[-400,-860,-404,212,604,216,608,-856]]],[1,15,[1,[227,26,227,60,255,60,255,26],[-378,-892,-378,196,518,196,518,-892]]],[1,16,[1,[108,76,73,76,73,101,108,101],[-388,-920,-388,200,412,200,412,-920]]],[1,17,[1,[36,48,0,48,0,72,36,72],[-396,-956,-396,196,372,196,372,-956]]],[1,18,[1,[73,48,37,48,37,72,73,72],[-384,-956,-384,196,384,196,384,-956]]],[2,19,[1,0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,[-1,"anchor"]],[[0,[19,[724,-724,724,724,565,565]]],[0,[19,[741,-706,706,741,551,578]]],[0,[19,[758,-687,687,758,536,592]]],[0,[19,[775,-668,668,775,521,605]]],[0,[19,[775,-668,668,775,521,605]]],[0,[19,[791,-649,649,791,507,617]]],[0,[19,[807,-629,629,807,491,630]]],[0,[19,[807,-629,629,807,491,630]]],[0,[19,[822,-609,609,822,475,642]]],[0,[19,[837,-589,589,837,460,653]]],[1,[19,[851,-568,568,851,443,664]]],[1,[19,[851,-568,568,851,443,664]]],[1,[19,[865,-547,547,865,427,675]]],[1,[19,[878,-526,526,878,410,685]]],[1,[19,[878,-526,526,878,410,685]]],[1,[19,[890,-504,504,890,393,695]]],[1,[19,[903,-482,482,903,376,705]]],[1,[19,[914,-460,460,914,359,714]]],[1,[19,[914,-460,460,914,359,714]]],[1,[19,[925,-437,437,925,341,722]]],[2,[19,[936,-414,414,936,323,731]]],[2,[19,[936,-414,414,936,323,731]]],[2,[19,[946,-391,391,946,305,739]]],[2,[19,[955,-368,368,955,287,746]]],[2,[19,[964,-344,344,964,268,753]]],[2,[19,[964,-344,344,964,268,753]]],[2,[19,[972,-321,321,972,250,759]]],[2,[19,[979,-297,297,979,232,764]]],[2,[19,[979,-297,297,979,232,764]]],[2,[19,[986,-273,273,986,213,770]]],[3,[19,[993,-248,248,993,193,775]]],[3,[19,[999,-224,224,999,175,780]]],[3,[19,[999,-224,224,999,175,780]]],[3,[19,[1004,-199,199,1004,155,784]]],[3,[19,0]],[3,[19,0]],[3,[19,[1012,-150,150,1012,117,790]]],[3,[19,[1016,-125,125,1016,97,793]]],[3,[19,[1019,-100,100,1019,78,796]]],[3,[19,[1019,-100,100,1019,78,796]]],[4,[19,[1021,-75,75,1021,58,797]]],[4,[19,[1022,-50,50,1022,39,798]]],[4,[19,[1022,-50,50,1022,39,798]]],[4,[19,[1023,-25,25,1023,19,799]]],[4,[19,[1024,0,0,1024,0,800]]],[4,[19,[1024,0,0,1024,0,800]]],[4,[19,[1024,0,0,1024,0,800]]],[4,[19,[1023,25,-25,1023,-19,799]]],[4,[19,[1022,50,-50,1022,-39,798]]],[4,[19,[1022,50,-50,1022,-39,798]]],[[3,[-1024,0,0,1024,0,0]],[19,[1021,75,-75,1021,-58,797]]],[[3,[-1024,0,0,1024,0,0]],[19,[1019,100,-100,1019,-78,796]]],[[3,[-1024,0,0,1024,0,0]],[19,[1019,100,-100,1019,-78,796]]],[[3,[-1024,0,0,1024,0,0]],[19,[1016,125,-125,1016,-97,793]]],[[3,[-1024,0,0,1024,0,0]],[19,[1012,150,-150,1012,-117,790]]],[[3,[-1024,0,0,1024,0,0]],[19,[1008,175,-175,1008,-136,787]]],[[3,[-1024,0,0,1024,0,0]],[19,[1008,175,-175,1008,-136,787]]],[[3,[-1024,0,0,1024,0,0]],[19,[1004,199,-199,1004,-155,784]]],[[3,[-1024,0,0,1024,0,0]],[19,[999,224,-224,999,-175,780]]],[[3,[-1024,0,0,1024,0,0]],[19,[999,224,-224,999,-175,780]]],[[2,[-1024,0,0,1024,0,0]],[19,[993,248,-248,993,-193,775]]],[[2,[-1024,0,0,1024,0,0]],[19,[986,273,-273,986,-213,770]]],[[2,[-1024,0,0,1024,0,0]],[19,[979,297,-297,979,-232,764]]],[[2,[-1024,0,0,1024,0,0]],[19,[979,297,-297,979,-232,764]]],[[2,[-1024,0,0,1024,0,0]],[19,[972,321,-321,972,-250,759]]],[[2,[-1024,0,0,1024,0,0]],[19,[964,344,-344,964,-268,753]]],[[2,[-1024,0,0,1024,0,0]],[19,[964,344,-344,964,-268,753]]],[[2,[-1024,0,0,1024,0,0]],[19,[955,368,-368,955,-287,746]]],[[2,[-1024,0,0,1024,0,0]],[19,[946,391,-391,946,-305,739]]],[[2,[-1024,0,0,1024,0,0]],[19,[936,414,-414,936,-323,731]]],[[1,[-1024,0,0,1024,0,0]],[19,[936,414,-414,936,-323,731]]],[[1,[-1024,0,0,1024,0,0]],[19,[925,437,-437,925,-341,722]]],[[1,[-1024,0,0,1024,0,0]],[19,[914,460,-460,914,-359,714]]],[[1,[-1024,0,0,1024,0,0]],[19,[914,460,-460,914,-359,714]]],[[1,[-1024,0,0,1024,0,0]],[19,[903,482,-482,903,-376,705]]],[[1,[-1024,0,0,1024,0,0]],[19,[890,504,-504,890,-393,695]]],[[1,[-1024,0,0,1024,0,0]],[19,[878,526,-526,878,-410,685]]],[[1,[-1024,0,0,1024,0,0]],[19,[878,526,-526,878,-410,685]]],[[1,[-1024,0,0,1024,0,0]],[19,[865,547,-547,865,-427,675]]],[[1,[-1024,0,0,1024,0,0]],[19,[851,568,-568,851,-443,664]]],[[0,[-1024,0,0,1024,0,0]],[19,[851,568,-568,851,-443,664]]],[[0,[-1024,0,0,1024,0,0]],[19,[837,589,-589,837,-460,653]]],[[0,[-1024,0,0,1024,0,0]],[19,[822,609,-609,822,-475,642]]],[[0,[-1024,0,0,1024,0,0]],[19,[807,629,-629,807,-491,630]]],[[0,[-1024,0,0,1024,0,0]],[19,[807,629,-629,807,-491,630]]],[[0,[-1024,0,0,1024,0,0]],[19,[791,649,-649,791,-507,617]]],[[0,[-1024,0,0,1024,0,0]],[19,[775,668,-668,775,-521,605]]],[[0,[-1024,0,0,1024,0,0]],[19,[775,668,-668,775,-521,605]]],[[0,[-1024,0,0,1024,0,0]],[19,[758,687,-687,758,-536,592]]],[[0,[-1024,0,0,1024,0,0]],[19,[741,706,-706,741,-551,578]]],[[5,[-1024,0,0,1024,0,0]],[19,[724,724,-724,724,-565,565]]],[[5,[-1024,0,0,1024,0,0]],[19,[724,724,-724,724,-565,565]]],[[5,[-1024,0,0,1024,0,0]],[19,[706,741,-741,706,-578,551]]],[[5,[-1024,0,0,1024,0,0]],[19,[687,758,-758,687,-592,536]]],[[5,[-1024,0,0,1024,0,0]],[19,[687,758,-758,687,-592,536]]],[[5,[-1024,0,0,1024,0,0]],[19,[668,775,-775,668,-605,521]]],[[5,[-1024,0,0,1024,0,0]],[19,[649,791,-791,649,-617,507]]],[[5,[-1024,0,0,1024,0,0]],[19,[649,791,-791,649,-617,507]]],[[5,[-1024,0,0,1024,0,0]],[19,[629,807,-807,629,-630,491]]],[[5,[-1024,0,0,1024,0,0]],[19,[609,822,-822,609,-642,475]]],[[6,[-1024,0,0,1024,0,0]],[19,[589,837,-837,589,-653,460]]],[[6,[-1024,0,0,1024,0,0]],[19,[589,837,-837,589,-653,460]]],[[6,[-1024,0,0,1024,0,0]],[19,[568,851,-851,568,-664,443]]],[[6,[-1024,0,0,1024,0,0]],[19,[547,865,-865,547,-675,427]]],[[6,[-1024,0,0,1024,0,0]],[19,[547,865,-865,547,-675,427]]],[[6,[-1024,0,0,1024,0,0]],[19,[526,878,-878,526,-685,410]]],[[6,[-1024,0,0,1024,0,0]],[19,[504,890,-890,504,-695,393]]],[[6,[-1024,0,0,1024,0,0]],[19,[482,903,-903,482,-705,376]]],[[6,[-1024,0,0,1024,0,0]],[19,[482,903,-903,482,-705,376]]],[[6,[-1024,0,0,1024,0,0]],[19,[460,914,-914,460,-714,359]]],[[7,[-1024,0,0,1024,0,0]],[19,[437,925,-925,437,-722,341]]],[[7,[-1024,0,0,1024,0,0]],[19,[437,925,-925,437,-722,341]]],[[7,[-1024,0,0,1024,0,0]],[19,[414,936,-936,414,-731,323]]],[[7,[-1024,0,0,1024,0,0]],[19,[391,946,-946,391,-739,305]]],[[7,[-1024,0,0,1024,0,0]],[19,[368,955,-955,368,-746,287]]],[[7,[-1024,0,0,1024,0,0]],[19,[368,955,-955,368,-746,287]]],[[7,[-1024,0,0,1024,0,0]],[19,[344,964,-964,344,-753,268]]],[[7,[-1024,0,0,1024,0,0]],[19,[321,972,-972,321,-759,250]]],[[7,[-1024,0,0,1024,0,0]],[19,[321,972,-972,321,-759,250]]],[[7,[-1024,0,0,1024,0,0]],[19,[297,979,-979,297,-764,232]]],[[8,[-1024,0,0,1024,0,0]],[19,[273,986,-986,273,-770,213]]],[[8,[-1024,0,0,1024,0,0]],[19,[248,993,-993,248,-775,193]]],[[8,[-1024,0,0,1024,0,0]],[19,[248,993,-993,248,-775,193]]],[[8,[-1024,0,0,1024,0,0]],[19,[224,999,-999,224,-780,175]]],[[8,[-1024,0,0,1024,0,0]],[19,[199,1004,-1004,199,-784,155]]],[[8,[-1024,0,0,1024,0,0]],[19,[199,1004,-1004,199,-784,155]]],[[8,[-1024,0,0,1024,0,0]],[19,[175,1008,-1008,175,-787,136]]],[[8,[-1024,0,0,1024,0,0]],[19,[150,1012,-1012,150,-790,117]]],[[8,[-1024,0,0,1024,0,0]],[19,[125,1016,-1016,125,-793,97]]],[[8,[-1024,0,0,1024,0,0]],[19,[125,1016,-1016,125,-793,97]]],[[9,[-1024,0,0,1024,0,0]],[19,[100,1019,-1019,100,-796,78]]],[[9,[-1024,0,0,1024,0,0]],[19,[75,1021,-1021,75,-797,58]]],[[9,[-1024,0,0,1024,0,0]],[19,[75,1021,-1021,75,-797,58]]],[[9,[-1024,0,0,1024,0,0]],[19,[50,1022,-1022,50,-798,39]]],[[9,[-1024,0,0,1024,0,0]],[19,[25,1023,-1023,25,-799,19]]],[[9,[-1024,0,0,1024,0,0]],[19,[0,1024,-1024,0,-800,0]]],[[9,[-1024,0,0,1024,0,0]],[19,[0,1024,-1024,0,-800,0]]],[[9,[-1024,0,0,1024,0,0]],[19,[-25,1023,-1023,-25,-799,-19]]],[[9,[-1024,0,0,1024,0,0]],[19,[-50,1022,-1022,-50,-798,-39]]],[[9,[-1024,0,0,1024,0,0]],[19,[-50,1022,-1022,-50,-798,-39]]],[[10,[-1024,0,0,1024,0,0]],[19,[-75,1021,-1021,-75,-797,-58]]],[[10,[-1024,0,0,1024,0,0]],[19,[-100,1019,-1019,-100,-796,-78]]],[[10,[-1024,0,0,1024,0,0]],[19,[-100,1019,-1019,-100,-796,-78]]],[[10,[-1024,0,0,1024,0,0]],[19,[-125,1016,-1016,-125,-793,-97]]],[[10,[-1024,0,0,1024,0,0]],[19,[-150,1012,-1012,-150,-790,-117]]],[[10,[-1024,0,0,1024,0,0]],[19,[-175,1008,-1008,-175,-787,-136]]],[[10,[-1024,0,0,1024,0,0]],[19,[-175,1008,-1008,-175,-787,-136]]],[[10,[-1024,0,0,1024,0,0]],[19,[-199,1004,-1004,-199,-784,-155]]],[[10,[-1024,0,0,1024,0,0]],[19,[-224,999,-999,-224,-780,-175]]],[[10,[-1024,0,0,1024,0,0]],[19,[-224,999,-999,-224,-780,-175]]],[[11,[-1024,0,0,1024,0,0]],[19,[-248,993,-993,-248,-775,-193]]],[[11,[-1024,0,0,1024,0,0]],[19,[-273,986,-986,-273,-770,-213]]],[[11,[-1024,0,0,1024,0,0]],[19,[-297,979,-979,-297,-764,-232]]],[[11,[-1024,0,0,1024,0,0]],[19,[-297,979,-979,-297,-764,-232]]],[[11,[-1024,0,0,1024,0,0]],[19,[-321,972,-972,-321,-759,-250]]],[[11,[-1024,0,0,1024,0,0]],[19,[-344,964,-964,-344,-753,-268]]],[[11,[-1024,0,0,1024,0,0]],[19,[-344,964,-964,-344,-753,-268]]],[[11,[-1024,0,0,1024,0,0]],[19,[-368,955,-955,-368,-746,-287]]],[[11,[-1024,0,0,1024,0,0]],[19,[-391,946,-946,-391,-739,-305]]],[[11,[-1024,0,0,1024,0,0]],[19,[-414,936,-936,-414,-731,-323]]],[[12,[-1024,0,0,1024,0,0]],[19,[-414,936,-936,-414,-731,-323]]],[[12,[-1024,0,0,1024,0,0]],[19,[-437,925,-925,-437,-722,-341]]],[[12,[-1024,0,0,1024,0,0]],[19,[-460,914,-914,-460,-714,-359]]],[[12,[-1024,0,0,1024,0,0]],[19,[-460,914,-914,-460,-714,-359]]],[[12,[-1024,0,0,1024,0,0]],[19,[-482,903,-903,-482,-705,-376]]],[[12,[-1024,0,0,1024,0,0]],[19,[-504,890,-890,-504,-695,-393]]],[[12,[-1024,0,0,1024,0,0]],[19,[-526,878,-878,-526,-685,-410]]],[[12,[-1024,0,0,1024,0,0]],[19,[-526,878,-878,-526,-685,-410]]],[[12,[-1024,0,0,1024,0,0]],[19,[-547,865,-865,-547,-675,-427]]],[[12,[-1024,0,0,1024,0,0]],[19,[-568,851,-851,-568,-664,-443]]],[[13,[-1024,0,0,1024,0,0]],[19,[-568,851,-851,-568,-664,-443]]],[[13,[-1024,0,0,1024,0,0]],[19,[-589,837,-837,-589,-653,-460]]],[[13,[-1024,0,0,1024,0,0]],[19,[-609,822,-822,-609,-642,-475]]],[[13,[-1024,0,0,1024,0,0]],[19,[-629,807,-807,-629,-630,-491]]],[[13,[-1024,0,0,1024,0,0]],[19,[-629,807,-807,-629,-630,-491]]],[[13,[-1024,0,0,1024,0,0]],[19,[-649,791,-791,-649,-617,-507]]],[[13,[-1024,0,0,1024,0,0]],[19,[-668,775,-775,-668,-605,-521]]],[[13,[-1024,0,0,1024,0,0]],[19,[-668,775,-775,-668,-605,-521]]],[[13,[-1024,0,0,1024,0,0]],[19,[-687,758,-758,-687,-592,-536]]],[[13,[-1024,0,0,1024,0,0]],[19,[-706,741,-741,-706,-578,-551]]],[[14,[-1024,0,0,1024,0,0]],[19,[-724,724,-724,-724,-565,-565]]],[[14,[-1024,0,0,1024,0,0]],[19,[-724,724,-724,-724,-565,-565]]],[[14,[-1024,0,0,1024,0,0]],[19,[-741,706,-706,-741,-551,-578]]],[[14,[-1024,0,0,1024,0,0]],[19,[-758,687,-687,-758,-536,-592]]],[[14,[-1024,0,0,1024,0,0]],[19,[-758,687,-687,-758,-536,-592]]],[[14,[-1024,0,0,1024,0,0]],[19,[-775,668,-668,-775,-521,-605]]],[[14,[-1024,0,0,1024,0,0]],[19,[-791,649,-649,-791,-507,-617]]],[[14,[-1024,0,0,1024,0,0]],[19,[-791,649,-649,-791,-507,-617]]],[[14,[-1024,0,0,1024,0,0]],[19,[-807,629,-629,-807,-491,-630]]],[[14,[-1024,0,0,1024,0,0]],[19,[-822,609,-609,-822,-475,-642]]],[[15,[-1024,0,0,1024,0,0]],[19,[-837,589,-589,-837,-460,-653]]],[[15,[-1024,0,0,1024,0,0]],[19,[-837,589,-589,-837,-460,-653]]],[[15,[-1024,0,0,1024,0,0]],[19,[-851,568,-568,-851,-443,-664]]],[[15,[-1024,0,0,1024,0,0]],[19,[-865,547,-547,-865,-427,-675]]],[[15,[-1024,0,0,1024,0,0]],[19,[-865,547,-547,-865,-427,-675]]],[[15,[-1024,0,0,1024,0,0]],[19,[-878,526,-526,-878,-410,-685]]],[[15,[-1024,0,0,1024,0,0]],[19,[-890,504,-504,-890,-393,-695]]],[[15,[-1024,0,0,1024,0,0]],[19,[-903,482,-482,-903,-376,-705]]],[[15,[-1024,0,0,1024,0,0]],[19,[-903,482,-482,-903,-376,-705]]],[[15,[-1024,0,0,1024,0,0]],[19,[-914,460,-460,-914,-359,-714]]],[[16,[-1024,0,0,1024,0,0]],[19,[-925,437,-437,-925,-341,-722]]],[[16,[-1024,0,0,1024,0,0]],[19,[-925,437,-437,-925,-341,-722]]],[[16,[-1024,0,0,1024,0,0]],[19,[-936,414,-414,-936,-323,-731]]],[[16,[-1024,0,0,1024,0,0]],[19,[-946,391,-391,-946,-305,-739]]],[[16,[-1024,0,0,1024,0,0]],[19,[-955,368,-368,-955,-287,-746]]],[[16,[-1024,0,0,1024,0,0]],[19,[-955,368,-368,-955,-287,-746]]],[[16,[-1024,0,0,1024,0,0]],[19,[-964,344,-344,-964,-268,-753]]],[[16,[-1024,0,0,1024,0,0]],[19,[-972,321,-321,-972,-250,-759]]],[[16,[-1024,0,0,1024,0,0]],[19,[-972,321,-321,-972,-250,-759]]],[[16,[-1024,0,0,1024,0,0]],[19,[-979,297,-297,-979,-232,-764]]],[[17,[-1024,0,0,1024,0,0]],[19,[-986,273,-273,-986,-213,-770]]],[[17,[-1024,0,0,1024,0,0]],[19,[-993,248,-248,-993,-193,-775]]],[[17,[-1024,0,0,1024,0,0]],[19,[-993,248,-248,-993,-193,-775]]],[[17,[-1024,0,0,1024,0,0]],[19,[-999,224,-224,-999,-175,-780]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1004,199,-199,-1004,-155,-784]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1004,199,-199,-1004,-155,-784]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1008,175,-175,-1008,-136,-787]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1012,150,-150,-1012,-117,-790]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1016,125,-125,-1016,-97,-793]]],[[17,[-1024,0,0,1024,0,0]],[19,[-1016,125,-125,-1016,-97,-793]]],[18,[19,[-1019,100,-100,-1019,-78,-796]]],[18,[19,[-1021,75,-75,-1021,-58,-797]]],[18,[19,[-1021,75,-75,-1021,-58,-797]]],[18,[19,[-1022,50,-50,-1022,-39,-798]]],[18,[19,[-1023,25,-25,-1023,-19,-799]]],[18,[19,[-1024,0,0,-1024,0,-800]]],[18,[19,[-1024,0,0,-1024,0,-800]]],[18,[19,[-1023,-25,25,-1023,19,-799]]],[18,[19,[-1022,-50,50,-1022,39,-798]]],[18,[19,[-1022,-50,50,-1022,39,-798]]],[17,[19,[-1021,-75,75,-1021,58,-797]]],[17,[19,[-1019,-100,100,-1019,78,-796]]],[17,[19,[-1019,-100,100,-1019,78,-796]]],[17,[19,[-1016,-125,125,-1016,97,-793]]],[17,[19,[-1012,-150,150,-1012,117,-790]]],[17,[19,[-1008,-175,175,-1008,136,-787]]],[17,[19,[-1008,-175,175,-1008,136,-787]]],[17,[19,[-1004,-199,199,-1004,155,-784]]],[17,[19,[-999,-224,224,-999,175,-780]]],[17,[19,[-999,-224,224,-999,175,-780]]],[16,[19,[-993,-248,248,-993,193,-775]]],[16,[19,[-986,-273,273,-986,213,-770]]],[16,[19,[-979,-297,297,-979,232,-764]]],[16,[19,[-979,-297,297,-979,232,-764]]],[16,[19,[-972,-321,321,-972,250,-759]]],[16,[19,[-964,-344,344,-964,268,-753]]],[16,[19,[-964,-344,344,-964,268,-753]]],[16,[19,[-955,-368,368,-955,287,-746]]],[16,[19,[-946,-391,391,-946,305,-739]]],[16,[19,[-936,-414,414,-936,323,-731]]],[15,[19,[-936,-414,414,-936,323,-731]]],[15,[19,[-925,-437,437,-925,341,-722]]],[15,[19,[-914,-460,460,-914,359,-714]]],[15,[19,[-914,-460,460,-914,359,-714]]],[15,[19,[-903,-482,482,-903,376,-705]]],[15,[19,[-890,-504,504,-890,393,-695]]],[15,[19,[-878,-526,526,-878,410,-685]]],[15,[19,[-878,-526,526,-878,410,-685]]],[15,[19,[-865,-547,547,-865,427,-675]]],[15,[19,[-851,-568,568,-851,443,-664]]],[14,[19,[-851,-568,568,-851,443,-664]]],[14,[19,[-837,-589,589,-837,460,-653]]],[14,[19,[-822,-609,609,-822,475,-642]]],[14,[19,[-807,-629,629,-807,491,-630]]],[14,[19,[-807,-629,629,-807,491,-630]]],[14,[19,[-791,-649,649,-791,507,-617]]],[14,[19,[-775,-668,668,-775,521,-605]]],[14,[19,[-775,-668,668,-775,521,-605]]],[14,[19,[-758,-687,687,-758,536,-592]]],[14,[19,[-741,-706,706,-741,551,-578]]],[13,[19,[-724,-724,724,-724,565,-565]]],[13,[19,[-724,-724,724,-724,565,-565]]],[13,[19,[-706,-741,741,-706,578,-551]]],[13,[19,[-687,-758,758,-687,592,-536]]],[13,[19,[-687,-758,758,-687,592,-536]]],[13,[19,[-668,-775,775,-668,605,-521]]],[13,[19,[-649,-791,791,-649,617,-507]]],[13,[19,[-649,-791,791,-649,617,-507]]],[13,[19,[-629,-807,807,-629,630,-491]]],[13,[19,[-609,-822,822,-609,642,-475]]],[12,[19,[-589,-837,837,-589,653,-460]]],[12,[19,[-589,-837,837,-589,653,-460]]],[12,[19,[-568,-851,851,-568,664,-443]]],[12,[19,[-547,-865,865,-547,675,-427]]],[12,[19,[-547,-865,865,-547,675,-427]]],[12,[19,[-526,-878,878,-526,685,-410]]],[12,[19,[-504,-890,890,-504,695,-393]]],[12,[19,[-482,-903,903,-482,705,-376]]],[12,[19,[-482,-903,903,-482,705,-376]]],[12,[19,[-460,-914,914,-460,714,-359]]],[11,[19,[-437,-925,925,-437,722,-341]]],[11,[19,[-437,-925,925,-437,722,-341]]],[11,[19,[-414,-936,936,-414,731,-323]]],[11,[19,[-391,-946,946,-391,739,-305]]],[11,[19,[-368,-955,955,-368,746,-287]]],[11,[19,[-368,-955,955,-368,746,-287]]],[11,[19,[-344,-964,964,-344,753,-268]]],[11,[19,[-321,-972,972,-321,759,-250]]],[11,[19,[-321,-972,972,-321,759,-250]]],[11,[19,[-297,-979,979,-297,764,-232]]],[10,[19,[-273,-986,986,-273,770,-213]]],[10,[19,[-248,-993,993,-248,775,-193]]],[10,[19,[-248,-993,993,-248,775,-193]]],[10,[19,[-224,-999,999,-224,780,-175]]],[10,[19,[-199,-1004,1004,-199,784,-155]]],[10,[19,[-199,-1004,1004,-199,784,-155]]],[10,[19,[-175,-1008,1008,-175,787,-136]]],[10,[19,[-150,-1012,1012,-150,790,-117]]],[10,[19,[-125,-1016,1016,-125,793,-97]]],[10,[19,[-125,-1016,1016,-125,793,-97]]],[9,[19,[-100,-1019,1019,-100,796,-78]]],[9,[19,[-75,-1021,1021,-75,797,-58]]],[9,[19,[-75,-1021,1021,-75,797,-58]]],[9,[19,[-50,-1022,1022,-50,798,-39]]],[9,[19,[-25,-1023,1023,-25,799,-19]]],[9,[19,[0,-1024,1024,0,800,0]]],[9,[19,[0,-1024,1024,0,800,0]]],[9,[19,[25,-1023,1023,25,799,19]]],[9,[19,[50,-1022,1022,50,798,39]]],[9,[19,[50,-1022,1022,50,798,39]]],[8,[19,[75,-1021,1021,75,797,58]]],[8,[19,[100,-1019,1019,100,796,78]]],[8,[19,[100,-1019,1019,100,796,78]]],[8,[19,[125,-1016,1016,125,793,97]]],[8,[19,[150,-1012,1012,150,790,117]]],[8,[19,[175,-1008,1008,175,787,136]]],[8,[19,[175,-1008,1008,175,787,136]]],[8,[19,[199,-1004,1004,199,784,155]]],[8,[19,[224,-999,999,224,780,175]]],[8,[19,[224,-999,999,224,780,175]]],[7,[19,[248,-993,993,248,775,193]]],[7,[19,[273,-986,986,273,770,213]]],[7,[19,[297,-979,979,297,764,232]]],[7,[19,[297,-979,979,297,764,232]]],[7,[19,[321,-972,972,321,759,250]]],[7,[19,[344,-964,964,344,753,268]]],[7,[19,[344,-964,964,344,753,268]]],[7,[19,[368,-955,955,368,746,287]]],[7,[19,[391,-946,946,391,739,305]]],[7,[19,[414,-936,936,414,731,323]]],[6,[19,[414,-936,936,414,731,323]]],[6,[19,[437,-925,925,437,722,341]]],[6,[19,[460,-914,914,460,714,359]]],[6,[19,[460,-914,914,460,714,359]]],[6,[19,[482,-903,903,482,705,376]]],[6,[19,[504,-890,890,504,695,393]]],[6,[19,[526,-878,878,526,685,410]]],[6,[19,[526,-878,878,526,685,410]]],[6,[19,[547,-865,865,547,675,427]]],[6,[19,[568,-851,851,568,664,443]]],[5,[19,[568,-851,851,568,664,443]]],[5,[19,[589,-837,837,589,653,460]]],[5,[19,[609,-822,822,609,642,475]]],[5,[19,[629,-807,807,629,630,491]]],[5,[19,[629,-807,807,629,630,491]]],[5,[19,[649,-791,791,649,617,507]]],[5,[19,[668,-775,775,668,605,521]]],[5,[19,[668,-775,775,668,605,521]]],[5,[19,[687,-758,758,687,592,536]]],[5,[19,[706,-741,741,706,578,551]]]]],[1,20,[1,[58,152,31,152,31,179,58,179],[16,4,16,868,864,872,864,8]]],[1,21,[1,[185,138,158,138,158,164,185,164],[16,8,16,872,864,868,864,4]]],[1,22,[1,[92,149,65,149,65,176,92,176],[16,4,16,868,864,872,864,8]]],[2,23,[20,22,21],[[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[1],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2]]],[1,24,[1,[0,0,0,48,88,48,88,0],[-869,-224,-869,598,644,598,644,-224]]],[1,25,[1,[88,0,88,45,147,45,147,0],[-958,-580,-958,860,918,860,918,-580]]],[2,26,[24,25,[19,"turret"]],[[0,1,2]],"cannon"],[1,27,[1,[96,125,66,125,66,149,96,149],[-244,-604,-244,356,508,360,508,-600]]],[1,28,[1,[96,101,66,101,66,125,96,125],[-244,-604,-244,356,508,360,508,-600]]],[1,29,[1,[157,138,127,138,127,161,157,161],[-244,-600,-244,360,508,356,508,-604]]],[1,30,[1,[127,125,97,125,97,149,127,149],[-240,-604,-240,356,512,360,512,-600]]],[1,31,[1,[30,129,0,129,0,153,30,153],[-244,-604,-244,356,508,360,508,-600]]],[1,32,[1,[64,128,34,128,34,152,64,152],[-244,-604,-244,356,508,360,508,-600]]],[2,33,[29,30,31,32,27,28],[[0],[0],[0],[0],[1],[1],[1],[1],[2],[2],[2],[2],[3],[3],[3],[3],[4],[4],[4],[4],[5],[5],[5],[5]]],[1,34,[1,[0,0,0,48,88,48,88,0],[-1042,-411,-1042,535,700,535,700,-411]]],[1,35,[1,[179,112,179,137,203,137,203,112],[-48,-540,-48,260,732,260,732,-540]]],[1,36,[1,[128,57,128,92,166,92,166,57],[-938,-256,-938,864,278,864,278,-256]]],[1,37,[1,[147,0,147,25,193,25,193,0],[-894,-796,-894,-8,566,-8,566,-796]]],[2,38,[34,35,33,36,37,[23,"resource"],[39,"label"],[40,"panel"]],[[[7,[1024,0,0,1024,-400,-400],true],0,1,2,3,4,5,[6,[1024,0,0,1024,-800,800],true]]],"mine"],[4,39,4294967295,100,40,2,20,false],[5,40,100,150,false]] -------------------------------------------------------------------------------- /simple_http_svr.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // import "io" 4 | import ( 5 | "flag" 6 | "fmt" 7 | "html/template" 8 | "io/ioutil" 9 | "log" 10 | "net/http" 11 | "os" 12 | "strings" 13 | ) 14 | 15 | var resRoot string 16 | 17 | func main() { 18 | flag.Parse() 19 | resRoot = flag.Arg(0) 20 | if flag.NArg() < 1 { 21 | log.Fatal("Error! should pass res root as parameter") 22 | return 23 | } 24 | fmt.Println("--------------123") 25 | fmt.Println(resRoot) 26 | http.HandleFunc("/", handleExample) 27 | err := http.ListenAndServe(":9527", nil) 28 | if err != nil { 29 | log.Fatal("fatel: listen and serve", err) 30 | } 31 | } 32 | 33 | func handleExample(w http.ResponseWriter, r *http.Request) { 34 | r.ParseForm() //解析参数,默认是不会解析的 35 | 36 | path := r.URL.Path 37 | t := path[strings.LastIndex(path, "."):] 38 | 39 | fmt.Println("path", r.URL.Path) 40 | fmt.Println("type:", t) 41 | 42 | switch t { 43 | case ".js": 44 | handleAsset("text/javascript", resRoot+"lib/"+path, w) 45 | case ".json": 46 | handleAsset("application/json", resRoot+"sample/"+path, w) 47 | case ".png": 48 | handleAsset("image/x-png", resRoot+"sample/"+path, w) 49 | case ".html": 50 | handleHtml(resRoot+"/sample/"+path, w) 51 | default: 52 | } 53 | 54 | } 55 | 56 | func handleAsset(ct string, path string, w http.ResponseWriter) { 57 | w.Header().Set("content-type", ct) 58 | 59 | fin, err := os.Open(path) 60 | 61 | defer fin.Close() 62 | 63 | if err != nil { 64 | log.Fatal("Static resources:", err) 65 | } 66 | 67 | fd, err := ioutil.ReadAll(fin) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | w.Write(fd) 72 | } 73 | 74 | func handleHtml(path string, w http.ResponseWriter) { 75 | t, _ := template.ParseFiles(path) 76 | t.Execute(w, nil) 77 | } 78 | -------------------------------------------------------------------------------- /tools/ejoy2d2json/json.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- JSON4Lua: JSON encoding / decoding support for the Lua language. 3 | -- json Module. 4 | -- Author: Craig Mason-Jones 5 | -- Homepage: http://github.com/craigmj/json4lua/ 6 | -- Version: 1.0.0 7 | -- This module is released under the MIT License (MIT). 8 | -- Please see LICENCE.txt for details. 9 | -- 10 | -- USAGE: 11 | -- This module exposes two functions: 12 | -- json.encode(o) 13 | -- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string. 14 | -- json.decode(json_string) 15 | -- Returns a Lua object populated with the data encoded in the JSON string json_string. 16 | -- 17 | -- REQUIREMENTS: 18 | -- compat-5.1 if using Lua 5.0 19 | -- 20 | -- CHANGELOG 21 | -- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix). 22 | -- Fixed Lua 5.1 compatibility issues. 23 | -- Introduced json.null to have null values in associative arrays. 24 | -- json.encode() performance improvement (more than 50%) through table.concat rather than .. 25 | -- Introduced decode ability to ignore /**/ comments in the JSON string. 26 | -- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays. 27 | ----------------------------------------------------------------------------- 28 | 29 | ----------------------------------------------------------------------------- 30 | -- Imports and dependencies 31 | ----------------------------------------------------------------------------- 32 | local math = require('math') 33 | local string = require("string") 34 | local table = require("table") 35 | 36 | ----------------------------------------------------------------------------- 37 | -- Module declaration 38 | ----------------------------------------------------------------------------- 39 | local json = {} -- Public namespace 40 | local json_private = {} -- Private namespace 41 | 42 | -- Public functions 43 | 44 | -- Private functions 45 | local decode_scanArray 46 | local decode_scanComment 47 | local decode_scanConstant 48 | local decode_scanNumber 49 | local decode_scanObject 50 | local decode_scanString 51 | local decode_scanWhitespace 52 | local encodeString 53 | local isArray 54 | local isEncodable 55 | 56 | ----------------------------------------------------------------------------- 57 | -- PUBLIC FUNCTIONS 58 | ----------------------------------------------------------------------------- 59 | --- Encodes an arbitrary Lua object / variable. 60 | -- @param v The Lua object / variable to be JSON encoded. 61 | -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode) 62 | function json.encode (v) 63 | -- Handle nil values 64 | if v==nil then 65 | return "null" 66 | end 67 | 68 | local vtype = type(v) 69 | 70 | -- Handle strings 71 | if vtype=='string' then 72 | return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string 73 | end 74 | 75 | -- Handle booleans 76 | if vtype=='number' or vtype=='boolean' then 77 | return tostring(v) 78 | end 79 | 80 | -- Handle tables 81 | if vtype=='table' then 82 | local rval = {} 83 | -- Consider arrays separately 84 | local bArray, maxCount = isArray(v) 85 | if bArray then 86 | for i = 1,maxCount do 87 | table.insert(rval, json.encode(v[i])) 88 | end 89 | else -- An object, not an array 90 | for i,j in pairs(v) do 91 | if isEncodable(i) and isEncodable(j) then 92 | table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j)) 93 | end 94 | end 95 | end 96 | if bArray then 97 | return '[' .. table.concat(rval,',') ..']' 98 | else 99 | return '{' .. table.concat(rval,',') .. '}' 100 | end 101 | end 102 | 103 | -- Handle null values 104 | if vtype=='function' and v==null then 105 | return 'null' 106 | end 107 | 108 | assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v)) 109 | end 110 | 111 | 112 | --- Decodes a JSON string and returns the decoded value as a Lua data structure / value. 113 | -- @param s The string to scan. 114 | -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1. 115 | -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil, 116 | -- and the position of the first character after 117 | -- the scanned JSON object. 118 | function json.decode(s, startPos) 119 | startPos = startPos and startPos or 1 120 | startPos = decode_scanWhitespace(s,startPos) 121 | assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']') 122 | local curChar = string.sub(s,startPos,startPos) 123 | -- Object 124 | if curChar=='{' then 125 | return decode_scanObject(s,startPos) 126 | end 127 | -- Array 128 | if curChar=='[' then 129 | return decode_scanArray(s,startPos) 130 | end 131 | -- Number 132 | if string.find("+-0123456789.e", curChar, 1, true) then 133 | return decode_scanNumber(s,startPos) 134 | end 135 | -- String 136 | if curChar==[["]] or curChar==[[']] then 137 | return decode_scanString(s,startPos) 138 | end 139 | if string.sub(s,startPos,startPos+1)=='/*' then 140 | return decode(s, decode_scanComment(s,startPos)) 141 | end 142 | -- Otherwise, it must be a constant 143 | return decode_scanConstant(s,startPos) 144 | end 145 | 146 | --- The null function allows one to specify a null value in an associative array (which is otherwise 147 | -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null } 148 | function null() 149 | return null -- so json.null() will also return null ;-) 150 | end 151 | ----------------------------------------------------------------------------- 152 | -- Internal, PRIVATE functions. 153 | -- Following a Python-like convention, I have prefixed all these 'PRIVATE' 154 | -- functions with an underscore. 155 | ----------------------------------------------------------------------------- 156 | 157 | --- Scans an array from JSON into a Lua object 158 | -- startPos begins at the start of the array. 159 | -- Returns the array and the next starting position 160 | -- @param s The string being scanned. 161 | -- @param startPos The starting position for the scan. 162 | -- @return table, int The scanned array as a table, and the position of the next character to scan. 163 | function decode_scanArray(s,startPos) 164 | local array = {} -- The return value 165 | local stringLen = string.len(s) 166 | assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s ) 167 | startPos = startPos + 1 168 | -- Infinite loop for array elements 169 | repeat 170 | startPos = decode_scanWhitespace(s,startPos) 171 | assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.') 172 | local curChar = string.sub(s,startPos,startPos) 173 | if (curChar==']') then 174 | return array, startPos+1 175 | end 176 | if (curChar==',') then 177 | startPos = decode_scanWhitespace(s,startPos+1) 178 | end 179 | assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.') 180 | object, startPos = json.decode(s,startPos) 181 | table.insert(array,object) 182 | until false 183 | end 184 | 185 | --- Scans a comment and discards the comment. 186 | -- Returns the position of the next character following the comment. 187 | -- @param string s The JSON string to scan. 188 | -- @param int startPos The starting position of the comment 189 | function decode_scanComment(s, startPos) 190 | assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos) 191 | local endPos = string.find(s,'*/',startPos+2) 192 | assert(endPos~=nil, "Unterminated comment in string at " .. startPos) 193 | return endPos+2 194 | end 195 | 196 | --- Scans for given constants: true, false or null 197 | -- Returns the appropriate Lua type, and the position of the next character to read. 198 | -- @param s The string being scanned. 199 | -- @param startPos The position in the string at which to start scanning. 200 | -- @return object, int The object (true, false or nil) and the position at which the next character should be 201 | -- scanned. 202 | function decode_scanConstant(s, startPos) 203 | local consts = { ["true"] = true, ["false"] = false, ["null"] = nil } 204 | local constNames = {"true","false","null"} 205 | 206 | for i,k in pairs(constNames) do 207 | if string.sub(s,startPos, startPos + string.len(k) -1 )==k then 208 | return consts[k], startPos + string.len(k) 209 | end 210 | end 211 | assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos) 212 | end 213 | 214 | --- Scans a number from the JSON encoded string. 215 | -- (in fact, also is able to scan numeric +- eqns, which is not 216 | -- in the JSON spec.) 217 | -- Returns the number, and the position of the next character 218 | -- after the number. 219 | -- @param s The string being scanned. 220 | -- @param startPos The position at which to start scanning. 221 | -- @return number, int The extracted number and the position of the next character to scan. 222 | function decode_scanNumber(s,startPos) 223 | local endPos = startPos+1 224 | local stringLen = string.len(s) 225 | local acceptableChars = "+-0123456789.e" 226 | while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true) 227 | and endPos<=stringLen 228 | ) do 229 | endPos = endPos + 1 230 | end 231 | local stringValue = 'return ' .. string.sub(s,startPos, endPos-1) 232 | local stringEval = loadstring(stringValue) 233 | assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos) 234 | return stringEval(), endPos 235 | end 236 | 237 | --- Scans a JSON object into a Lua object. 238 | -- startPos begins at the start of the object. 239 | -- Returns the object and the next starting position. 240 | -- @param s The string being scanned. 241 | -- @param startPos The starting position of the scan. 242 | -- @return table, int The scanned object as a table and the position of the next character to scan. 243 | function decode_scanObject(s,startPos) 244 | local object = {} 245 | local stringLen = string.len(s) 246 | local key, value 247 | assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s) 248 | startPos = startPos + 1 249 | repeat 250 | startPos = decode_scanWhitespace(s,startPos) 251 | assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.') 252 | local curChar = string.sub(s,startPos,startPos) 253 | if (curChar=='}') then 254 | return object,startPos+1 255 | end 256 | if (curChar==',') then 257 | startPos = decode_scanWhitespace(s,startPos+1) 258 | end 259 | assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.') 260 | -- Scan the key 261 | key, startPos = json.decode(s,startPos) 262 | assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) 263 | startPos = decode_scanWhitespace(s,startPos) 264 | assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) 265 | assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos) 266 | startPos = decode_scanWhitespace(s,startPos+1) 267 | assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) 268 | value, startPos = json.decode(s,startPos) 269 | object[key]=value 270 | until false -- infinite loop while key-value pairs are found 271 | end 272 | 273 | -- START SoniEx2 274 | -- Initialize some things used by decode_scanString 275 | -- You know, for efficiency 276 | local escapeSequences = { 277 | ["\\t"] = "\t", 278 | ["\\f"] = "\f", 279 | ["\\r"] = "\r", 280 | ["\\n"] = "\n", 281 | ["\\b"] = "\b" 282 | } 283 | setmetatable(escapeSequences, {__index = function(t,k) 284 | -- skip "\" aka strip escape 285 | return string.sub(k,2) 286 | end}) 287 | -- END SoniEx2 288 | 289 | --- Scans a JSON string from the opening inverted comma or single quote to the 290 | -- end of the string. 291 | -- Returns the string extracted as a Lua string, 292 | -- and the position of the next non-string character 293 | -- (after the closing inverted comma or single quote). 294 | -- @param s The string being scanned. 295 | -- @param startPos The starting position of the scan. 296 | -- @return string, int The extracted string as a Lua string, and the next character to parse. 297 | function decode_scanString(s,startPos) 298 | assert(startPos, 'decode_scanString(..) called without start position') 299 | local startChar = string.sub(s,startPos,startPos) 300 | -- START SoniEx2 301 | -- PS: I don't think single quotes are valid JSON 302 | assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string') 303 | --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart) 304 | local t = {} 305 | local i,j = startPos,startPos 306 | while string.find(s, startChar, j+1) ~= j+1 do 307 | local oldj = j 308 | i,j = string.find(s, "\\.", j+1) 309 | local x,y = string.find(s, startChar, oldj+1) 310 | if not i or x < i then 311 | i,j = x,y-1 312 | end 313 | table.insert(t, string.sub(s, oldj+1, i-1)) 314 | if string.sub(s, i, j) == "\\u" then 315 | local a = string.sub(s,j+1,j+4) 316 | j = j + 4 317 | local n = tonumber(a, 16) 318 | assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j) 319 | -- math.floor(x/2^y) == lazy right shift 320 | -- a % 2^b == bitwise_and(a, (2^b)-1) 321 | -- 64 = 2^6 322 | -- 4096 = 2^12 (or 2^6 * 2^6) 323 | local x 324 | if n < 0x80 then 325 | x = string.char(n % 0x80) 326 | elseif n < 0x800 then 327 | -- [110x xxxx] [10xx xxxx] 328 | x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40)) 329 | else 330 | -- [1110 xxxx] [10xx xxxx] [10xx xxxx] 331 | x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40)) 332 | end 333 | table.insert(t, x) 334 | else 335 | table.insert(t, escapeSequences[string.sub(s, i, j)]) 336 | end 337 | end 338 | table.insert(t,string.sub(j, j+1)) 339 | assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")") 340 | return table.concat(t,""), j+2 341 | -- END SoniEx2 342 | end 343 | 344 | --- Scans a JSON string skipping all whitespace from the current start position. 345 | -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached. 346 | -- @param s The string being scanned 347 | -- @param startPos The starting position where we should begin removing whitespace. 348 | -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string 349 | -- was reached. 350 | function decode_scanWhitespace(s,startPos) 351 | local whitespace=" \n\r\t" 352 | local stringLen = string.len(s) 353 | while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do 354 | startPos = startPos + 1 355 | end 356 | return startPos 357 | end 358 | 359 | --- Encodes a string to be JSON-compatible. 360 | -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-) 361 | -- @param s The string to return as a JSON encoded (i.e. backquoted string) 362 | -- @return The string appropriately escaped. 363 | 364 | local escapeList = { 365 | ['"'] = '\\"', 366 | ['\\'] = '\\\\', 367 | ['/'] = '\\/', 368 | ['\b'] = '\\b', 369 | ['\f'] = '\\f', 370 | ['\n'] = '\\n', 371 | ['\r'] = '\\r', 372 | ['\t'] = '\\t' 373 | } 374 | 375 | function json_private.encodeString(s) 376 | local s = tostring(s) 377 | return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat 378 | end 379 | 380 | -- Determines whether the given Lua type is an array or a table / dictionary. 381 | -- We consider any table an array if it has indexes 1..n for its n items, and no 382 | -- other data in the table. 383 | -- I think this method is currently a little 'flaky', but can't think of a good way around it yet... 384 | -- @param t The table to evaluate as an array 385 | -- @return boolean, number True if the table can be represented as an array, false otherwise. If true, 386 | -- the second returned value is the maximum 387 | -- number of indexed elements in the array. 388 | function isArray(t) 389 | -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable 390 | -- (with the possible exception of 'n') 391 | local maxIndex = 0 392 | for k,v in pairs(t) do 393 | if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair 394 | if (not isEncodable(v)) then return false end -- All array elements must be encodable 395 | maxIndex = math.max(maxIndex,k) 396 | else 397 | if (k=='n') then 398 | if v ~= table.getn(t) then return false end -- False if n does not hold the number of elements 399 | else -- Else of (k=='n') 400 | if isEncodable(v) then return false end 401 | end -- End of (k~='n') 402 | end -- End of k,v not an indexed pair 403 | end -- End of loop across all pairs 404 | return true, maxIndex 405 | end 406 | 407 | --- Determines whether the given Lua object / table / variable can be JSON encoded. The only 408 | -- types that are JSON encodable are: string, boolean, number, nil, table and json.null. 409 | -- In this implementation, all other types are ignored. 410 | -- @param o The object to examine. 411 | -- @return boolean True if the object should be JSON encoded, false if it should be ignored. 412 | function isEncodable(o) 413 | local t = type(o) 414 | return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or (t=='function' and o==null) 415 | end 416 | 417 | return json -------------------------------------------------------------------------------- /tools/ejoy2d2json/main.lua: -------------------------------------------------------------------------------- 1 | local json = require('json') 2 | 3 | local f, o = ... 4 | 5 | print('---->>> input f:', f) 6 | 7 | local data = require(f) 8 | 9 | local types = { 10 | empty =0, 11 | picture =1, 12 | animation =2, 13 | polygon = 3, 14 | label = 4, 15 | pannel = 5, 16 | anchor = 6, 17 | matrix = 7, 18 | } 19 | 20 | local rlt = {} 21 | for k,v in pairs(data) do 22 | local t = {} 23 | t[1] = assert(types[v.type]) 24 | if v.type == 'matrix' then 25 | t[2] = v[1] 26 | elseif v.type == 'picture' then 27 | t[2] = v.id 28 | local p = {} 29 | t[3] = p 30 | local info = v[1] 31 | p[1] = info.tex 32 | p[2] = info.src 33 | p[3] = info.screen 34 | elseif v.type == 'animation' then 35 | t[2] = v.id 36 | -- components 37 | local cc = {} 38 | for _, cmp in ipairs(v.component) do 39 | if not cmp.name then 40 | table.insert(cc, cmp.id) 41 | else 42 | local c = {} 43 | if not cmp.id then 44 | c[1] = -1 45 | else 46 | c[1] = cmp.id 47 | end 48 | c[2] = cmp.name 49 | table.insert(cc, c) 50 | end 51 | end 52 | t[3] = cc 53 | -- frame 54 | local frames = {} 55 | for _, f in ipairs(v[1]) do 56 | local nf = {} 57 | for _, sf in ipairs(f) do 58 | if type(sf) == 'table' then 59 | local fc = {} 60 | fc[1] = sf.index 61 | fc[2] = sf.mat 62 | if sf.touch then 63 | fc[3] = sf.touch 64 | end 65 | table.insert(nf, fc) 66 | else 67 | table.insert(nf, sf) 68 | end 69 | end 70 | table.insert(frames, nf) 71 | end 72 | t[4] = frames 73 | if v.export then 74 | t[5] = v.export 75 | end 76 | elseif v.type == 'label' then 77 | print("-------aoaooaaoaoa -------->>>>", v.id) 78 | t[2] = v.id 79 | t[3] = v.color 80 | t[4] = v.width 81 | t[5] = v.height 82 | t[6] = v.align 83 | t[7] = v.size 84 | t[8] = v.noedge 85 | elseif v.type == 'pannel' then 86 | t[2] = v.id 87 | t[3] = v.width 88 | t[4] = v.height 89 | t[5] = v.scissor 90 | end 91 | rlt[k] = t 92 | end 93 | 94 | local of = io.open(o..'.json', 'w') 95 | of:write(json.encode(rlt)) 96 | of:close() 97 | 98 | print('--->> done:', f) 99 | 100 | 101 | 102 | 103 | --------------------------------------------------------------------------------