main.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. function main(assets) {
  2. console.log("assets:", assets);
  3. game = new Game(assets);
  4. game.init();
  5. game.prog = loadProgram2(assets.vertexShader.vert, assets.fragmentShader.frag);
  6. // var [vao, vbo] = makeBuffer();
  7. // var resolutionUniformLocation = gl.getUniformLocation(prog, "u_resolution");
  8. // Pass in the canvas resolution so we can convert from
  9. // pixels to clipspace in the shader
  10. // gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
  11. // gl.ELEMENT_ARRAY_BUFFER
  12. var last = -1;
  13. var globalTimer = 0;
  14. requestAnimationFrame(draw);
  15. function draw(time) {
  16. var now = time * 0.001;
  17. if(last == -1) {
  18. last = now;
  19. requestAnimationFrame(draw);
  20. return;
  21. }
  22. var te = now - last;
  23. last = now;
  24. game.gameTime += te;
  25. // drawFrame(game, te, globalTimer);
  26. game.loop(te);
  27. requestAnimationFrame(draw);
  28. }
  29. // gl.bindBuffer(gl.ARRAY_BUFFER, buffer with offsets);
  30. // gl.vertexAttribPointer(offset attrib location in shader, 3, gl.FLOAT, false, 12, 0);
  31. // gl.vertexAttribDivisor(offset attrib location in shader, 1);
  32. //
  33. // gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, number of vertices to render, number of instances to render);
  34. }
  35. function loadAssets(manifest, cb) {
  36. var assets = {
  37. 'fragmentShader': {},
  38. 'vertexShader': {},
  39. 'json': {},
  40. 'image': {},
  41. 'imageArray': {},
  42. };
  43. function textgrab(m, cb) {
  44. ajaxGet(m.src, function(err, txt) {
  45. if(err) return cb(err);
  46. if(assets[m.type][m.name]) {
  47. console.log("duplicate asset for:", m);
  48. }
  49. assets[m.type][m.name] = txt;
  50. cb(null);
  51. });
  52. }
  53. function jsongrab(m, cb) {
  54. getJSON(m.src, function(err, txt) {
  55. if(err) return cb(err);
  56. if(assets[m.type][m.name]) {
  57. console.log("duplicate asset for:", m);
  58. }
  59. assets[m.type][m.name] = txt;
  60. cb(null);
  61. });
  62. }
  63. function imagegrab(m, cb) {
  64. var img = new Image();
  65. img.addEventListener('load', function() {
  66. if(assets[m.type][m.name]) {
  67. console.log("duplicate asset for:", m);
  68. }
  69. assets[m.type][m.name] = img;
  70. cb(null);
  71. });
  72. img.src = m.src;
  73. }
  74. function imageArraygrab(m, cb) {
  75. var imgList = [];
  76. function getimg(url, cb) {
  77. var img = new Image();
  78. imgList.push(img);
  79. img.addEventListener('load', function() { cb(img); });
  80. console.log(url);
  81. img.src = url;
  82. }
  83. var list = m.src.map(function(u) { return [getimg, u]; });
  84. asyncParallel(list, function(err) {
  85. if(assets[m.type][m.name]) {
  86. console.log("duplicate asset for:", m);
  87. }
  88. // TODO: load the array here
  89. assets[m.type][m.name] = loadTextureArray(imgList);
  90. cb(null);
  91. })
  92. }
  93. var loaders = {
  94. 'fragmentShader': textgrab,
  95. 'vertexShader': textgrab,
  96. 'json': jsongrab,
  97. 'image': imagegrab,
  98. 'imageArray': imageArraygrab,
  99. };
  100. var todo = [];
  101. for(var a in manifest) {
  102. var m = manifest[a];
  103. var fn = loaders[m.type];
  104. if(typeof fn == 'function') {
  105. todo.push([fn, m]);
  106. }
  107. }
  108. asyncParallel(todo, function(err) {
  109. cb(err, assets);
  110. });
  111. }
  112. function Game(assets) {
  113. this.assets = assets;
  114. this.nextIndex = 1;
  115. this.entities = [];
  116. this.components = {
  117. position: {},
  118. nextpos: {},
  119. velocity: {},
  120. acceleration: {},
  121. rotation: {},
  122. scale: {},
  123. alpha: {},
  124. urge: {},
  125. maxSpeed: {},
  126. movable: {},
  127. };
  128. this.systems = Systems;
  129. this.maxStep = .01;
  130. this.secondAcc = 0;
  131. this.gameTime = 0;
  132. }
  133. Game.prototype.init = function() {
  134. var game = this;
  135. // init input stuff
  136. this.input = {
  137. down: [],
  138. pressed: [],
  139. };
  140. document.addEventListener('keydown', function(e) {
  141. game.input.down[e.which] = 1;
  142. game.input.down[e.which] |= 0;
  143. e.preventDefault();
  144. });
  145. document.addEventListener('keyup', function(e) {
  146. game.input.down[e.which] = 0;
  147. game.input.pressed[e.which] = (game.input.pressed[e.which]>>>0) + 1;
  148. e.preventDefault();
  149. });
  150. this.cameraCenter = [-32,-32, -10];
  151. // this.scale = -200.05;
  152. this.scale = 1;//-200.05;
  153. this.aspectRatio = gl.drawingBufferHeight / gl.drawingBufferWidth;
  154. var quad = new Float32Array([
  155. 0, 0, 0, 0, 1,
  156. 0, 1, 0, 0, 0,
  157. 1, 0, 0, 1, 1,
  158. 1, 1, 0, 1, 0,
  159. ]);
  160. var buf = [];
  161. var font = this.assets.json.sdf_data.fonts["Courier"].regular;
  162. var adv = makeSDFChar("F".charCodeAt(0), font, this.assets.json.sdf_data, buf, 0, 0);
  163. adv += makeSDFChar("o".charCodeAt(0), font, this.assets.json.sdf_data, buf, adv, 0);
  164. adv += makeSDFChar("o".charCodeAt(0), font, this.assets.json.sdf_data, buf, adv, 0);
  165. adv += makeSDFChar("d".charCodeAt(0), font, this.assets.json.sdf_data, buf, adv, 0);
  166. //quad = new Float32Array(buf);
  167. this.vaoInfo = makeVAO([
  168. { buf: 0, name: 'vpos', loc: 0, count: 3, type: gl.FLOAT, norm: false },
  169. { buf: 0, name: 'vtex', loc: 1, count: 2, type: gl.FLOAT, norm: false },
  170. { buf: 1, name: 'pos', loc: 2, count: 3, type: gl.FLOAT, norm: false, divisor: 1 },
  171. { buf: 1, name: 'box', loc: 3, count: 4, type: gl.FLOAT, norm: false, divisor: 1 },
  172. { buf: 1, name: 'tex', loc: 4, count: 4, type: gl.FLOAT, norm: false, divisor: 1 },
  173. { buf: 1, name: 'color', loc: 5, count: 4, type: gl.FLOAT, norm: false, divisor: 1 },
  174. ]);
  175. this.vbo = makeVBO(quad, this.vaoInfo, 0);
  176. var inst = new Float32Array(buf);
  177. this.instvbo = makeVBO(inst, this.vaoInfo, 1);
  178. this.sdftex = loadTexture(this.assets.image.sdf_data);
  179. var ash = this.aspectRatio / 2;
  180. this.m_proj = mat4.create();
  181. // mat4.ortho(this.m_proj, -0.5, 0.5, -ash, ash, 0, 1000);
  182. mat4.perspective(this.m_proj, 3.14 / 2.0,
  183. gl.drawingBufferWidth / gl.drawingBufferHeight,
  184. 0.01, 1000);
  185. // console.log(glMatrix)
  186. this.terrain = new Terrain(this.assets);
  187. this.activeSprites = new SpriteSet(this.assets);
  188. for(var i = 0; i < 5; i++) {
  189. var e = this.addEntity();
  190. var pos = {
  191. x: 32 + (Math.random() * 2) - 1,
  192. y: 32 + (Math.random() * 2) - 1
  193. };
  194. this.addComponent(e, 'position', pos);
  195. this.addComponent(e, 'movable', 1);
  196. this.addComponent(e, 'scale', .5 + Math.random() * 2);
  197. this.addComponent(e, 'maxSpeed', 4.5 + Math.random() * 2);
  198. this.addComponent(e, 'nextpos', pt(pos.x, pos.y));
  199. this.addComponent(e, 'acceleration', {x:0,y:0});//pt(Math.random() * .1, Math.random() * .1));
  200. this.addComponent(e, 'velocity', pt(0,0));
  201. this.activeSprites.addInstance(e, 'marker-blue');
  202. }
  203. this.followEID = 3;
  204. console.log('init complete');
  205. }
  206. Game.prototype.addEntity = function() {
  207. var i = this.nextIndex++;
  208. return i;
  209. };
  210. Game.prototype.getAllComponents = function(eid) {
  211. var l = [];
  212. for(var cn in this.components) { if(this.components.hasOwnProperty(cn)) {
  213. var cmp = this.components[cn][eid]
  214. if(cmp) {
  215. l.push({type: cn, data: cmp});
  216. }
  217. }}
  218. return l;
  219. };
  220. // checks existence first
  221. Game.prototype.addComponent = function(eid, name, data) {
  222. if(!this.components[name])
  223. this.components[name] = {};
  224. this.components[name][eid] = data;
  225. };
  226. // doesn't check existence
  227. Game.prototype.setComp = function(eid, name, data) {
  228. this.components[name][eid] = data;
  229. };
  230. Game.prototype.getComp = function(eid, name) {
  231. return this.components[name] ? this.components[name][eid] : null;
  232. };
  233. Game.prototype.removeComp = function(eid, name) {
  234. delete this.components[name][eid];
  235. };
  236. Game.prototype.spawn = function(entity) {
  237. var eid = this.addEntity();
  238. for(var prop in entity) { if(entity.hasOwnProperty(prop)) {
  239. var data = entity[prop];
  240. // fuck references. real languages use pointers.
  241. if(typeof data == 'object')
  242. data = clone(data);
  243. this.addComponent(eid, prop, data);
  244. }}
  245. return eid;
  246. }
  247. function runSystem(allComps, reqComps, cb){
  248. var len = reqComps.length;
  249. for(var eid in allComps[reqComps[0]]) {
  250. var go = true;
  251. var e = {};
  252. for(var i = 0; i < len; i++) {
  253. var cn = reqComps[i];
  254. if(!allComps[cn] || !allComps[cn].hasOwnProperty(eid)) {
  255. go = false;
  256. break;
  257. }
  258. e[cn] = allComps[cn][eid]
  259. }
  260. if(go) cb(e, eid);
  261. }
  262. }
  263. Game.prototype.loop = function(te) {
  264. //console.log('looping');
  265. // this.updateInput();
  266. // inludes timers
  267. this.updateGame(te);
  268. this.render();
  269. // if(this.runGame) window.requestAnimFrame(this.animFrame);
  270. };
  271. Game.prototype.updateGame = function(te) {
  272. // timeless stuff
  273. // this.systems.userControl();
  274. this.secondAcc += te;
  275. var steps = Math.floor(te / this.maxStep);
  276. var leftover = te - (steps * this.maxStep);
  277. // nice little physics steps
  278. for(var i = 0; i < steps; i++) {
  279. this.gameTime += this.maxStep;
  280. this.step(this.maxStep);
  281. }
  282. this.gameTime += leftover;
  283. this.step(leftover);
  284. // once per frame
  285. this.frameStep(te);
  286. // ~once per second
  287. if(this.secondAcc > 1) {
  288. this.secondStep(this.secondAcc);
  289. this.secondAcc = 0;
  290. };
  291. return te;
  292. }
  293. // this is for things that need reasonable integration like physics
  294. Game.prototype.step = function(te) {
  295. // this.systems.move(te);
  296. this.systems.goTo();
  297. // console.log(te);
  298. this.systems.acceleration(te);
  299. this.systems.velocity(te);
  300. // return;
  301. this.systems.urge(te);
  302. // this.systems.checkCollisions();
  303. // the odometer must be called immediately before movement finalization
  304. this.systems.odometer();
  305. this.systems.finalizeMove();
  306. };
  307. // this is for things that need per-frame updates, but can handle large steps like HUD
  308. Game.prototype.frameStep = function(te) {
  309. return;
  310. this.systems.mapFollows();
  311. this.systems.lookAt();
  312. };
  313. // called ~ once every second. useful for game logic, etc
  314. Game.prototype.secondStep = function(te) {
  315. return;
  316. this.systems.ai.thirst();
  317. this.systems.ai.thirsty_LocateStand();
  318. this.systems.ai.buyDrink();
  319. this.systems.ai.followPaths();
  320. };
  321. Game.prototype.render = function() {
  322. // function drawFrame(game, timeElapsed, globalTime) {
  323. gl.clearColor(0, 0, 0, 0);
  324. gl.clear(gl.COLOR_BUFFER_BIT);
  325. gl.enable(gl.BLEND);
  326. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  327. this.vp = mat4.create();
  328. var scrollSpeed = 0.05;
  329. var u = {x:0, y:0, acc: 6};
  330. var ii = this.input;
  331. if(ii.down[37]) {
  332. //console.log(ii);
  333. // this.cameraCenter[0] += scrollSpeed;
  334. u.x = -1;
  335. }
  336. if(ii.down[39]) {
  337. //console.log(ii);
  338. // this.cameraCenter[0] += -scrollSpeed;
  339. u.x = 1;
  340. }
  341. if(ii.down[38]) {
  342. //console.log(ii);
  343. // this.cameraCenter[1] += -scrollSpeed;
  344. u.y = 1;
  345. }
  346. if(ii.down[40]) {
  347. //console.log(ii);
  348. // this.cameraCenter[1] += scrollSpeed;
  349. u.y = -1;
  350. }
  351. if(ii.down[90]) { // z
  352. // this.scale += 0.0003;
  353. this.cameraCenter[2] += 1;
  354. }
  355. if(ii.down[88]) { // x
  356. // this.scale -= 0.0003;
  357. this.cameraCenter[2] -= 1;
  358. }
  359. this.scale = Math.max(0.001, this.scale);
  360. this.scale = Math.min(1000.1, this.scale);
  361. // var len = Math.hypot(u.x, u.y);
  362. // u.x = u.x / len;
  363. // u.y = u.y / len;
  364. this.components.urge[this.followEID] = u;
  365. var pos = this.components.position[this.followEID];
  366. var follow = vec4.fromValues(pos.x, pos.y, 0, 1);
  367. gl.useProgram(this.prog);
  368. this.m_view = mat4.create();
  369. //console.log(this.m_view);
  370. // mat4.scale(this.m_view, this.m_view, [this.scale, this.scale, this.scale]);
  371. mat4.translate(this.m_view, this.m_view, this.cameraCenter);
  372. mat4.mul(this.vp, this.m_proj, this.m_view);
  373. var ff = vec4.create();
  374. vec4.transformMat4(ff, follow, this.vp);
  375. // perspective divide
  376. ff[0] /= ff[3];
  377. ff[1] /= ff[3];
  378. ff[2] /= ff[3];
  379. if(ff[0] < -.8) {
  380. this.cameraCenter[0] += 0.5;
  381. }
  382. else if(ff[0] > .8) {
  383. this.cameraCenter[0] += -0.5;
  384. }
  385. if(ff[1] < -.8) {
  386. this.cameraCenter[1] += 0.5;
  387. }
  388. else if(ff[1] > .8) {
  389. this.cameraCenter[1] += -0.5;
  390. }
  391. this.terrain.render(this);
  392. this.activeSprites.render(this);
  393. // console.log(game.vp);
  394. /*
  395. gl.bindBuffer(gl.ARRAY_BUFFER, game.vbo.vbo);
  396. gl.bindBuffer(gl.ARRAY_BUFFER, game.instvbo.vbo);
  397. gl.activeTexture(gl.TEXTURE0 + 0);
  398. gl.bindTexture(gl.TEXTURE_2D, game.sdftex.tex);
  399. var vp_ul = gl.getUniformLocation(game.prog, "mViewProj");
  400. var tex_ul = gl.getUniformLocation(game.prog, "sTex");
  401. gl.uniformMatrix4fv(vp_ul, false, game.vp);
  402. gl.uniform1i(tex_ul, 0);
  403. var primitiveType = gl.TRIANGLE_STRIP;
  404. var offset = 0;
  405. var count = 4;
  406. var instances = 4;
  407. gl.drawArraysInstanced(primitiveType, offset, count, instances);
  408. */
  409. }