ruby2d 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/assets/simple2d.js CHANGED
@@ -1,18 +1,18 @@
1
- // Simple2D.js — v0.1.0, built 03-01-2017
1
+ // Simple2D.js — v0.2.0, built 06-04-2017
2
2
 
3
3
  // start.js - Open the anonymous function defining the Simple 2D module
4
4
 
5
5
  (function(undefined) {
6
-
6
+
7
7
  // Check if Simple 2D is already loaded
8
8
  if (typeof(this.S2D) !== 'undefined') {
9
9
  console.warn("Simple 2D already loaded! Loading twice may cause problems.");
10
10
  return this.S2D;
11
11
  }
12
-
12
+
13
13
  // Create the Simple 2D module
14
14
  var S2D = this.S2D = {};
15
-
15
+
16
16
  // ... Simple 2D library starts here ...
17
17
 
18
18
 
@@ -21,16 +21,42 @@
21
21
  // Simple 2D OpenGL namespace
22
22
  S2D.GL = {};
23
23
 
24
- // Simple 2D definitions
25
- Object.defineProperty(S2D, "KEYDOWN", { value: 1 });
26
- Object.defineProperty(S2D, "KEY", { value: 2 });
27
- Object.defineProperty(S2D, "KEYUP", { value: 3 });
28
-
29
24
  // Viewport scaling modes
30
25
  Object.defineProperty(S2D, "FIXED", { value: 1 });
31
26
  Object.defineProperty(S2D, "SCALE", { value: 2 });
32
27
  Object.defineProperty(S2D, "STRETCH", { value: 3 });
33
28
 
29
+ // Keyboard events
30
+ Object.defineProperty(S2D, "KEY_DOWN", { value: 1 });
31
+ Object.defineProperty(S2D, "KEY_HELD", { value: 2 });
32
+ Object.defineProperty(S2D, "KEY_UP", { value: 3 });
33
+
34
+ // Mouse events
35
+ Object.defineProperty(S2D, "MOUSE_DOWN", { value: 1 });
36
+ Object.defineProperty(S2D, "MOUSE_UP", { value: 2 });
37
+ Object.defineProperty(S2D, "MOUSE_SCROLL", { value: 3 });
38
+ Object.defineProperty(S2D, "MOUSE_MOVE", { value: 4 });
39
+ Object.defineProperty(S2D, "MOUSE_LEFT", { value: 5 });
40
+ Object.defineProperty(S2D, "MOUSE_MIDDLE", { value: 6 });
41
+ Object.defineProperty(S2D, "MOUSE_RIGHT", { value: 7 });
42
+ Object.defineProperty(S2D, "MOUSE_X1", { value: 8 });
43
+ Object.defineProperty(S2D, "MOUSE_X2", { value: 9 });
44
+ Object.defineProperty(S2D, "MOUSE_SCROLL_NORMAL", { value: 10 });
45
+ Object.defineProperty(S2D, "MOUSE_SCROLL_INVERTED", { value: 11 });
46
+
47
+ // Event
48
+ S2D.Event = {
49
+ which: null,
50
+ type: null,
51
+ button: null,
52
+ key: null,
53
+ x: 0,
54
+ y: 0,
55
+ delta_x: 0,
56
+ delta_y: 0,
57
+ direction: null
58
+ };
59
+
34
60
  // Color
35
61
  S2D.Color = {
36
62
  r: 1.0,
@@ -56,7 +82,9 @@ S2D.Window = {
56
82
  render: null,
57
83
  mouse: {
58
84
  x: 0,
59
- y: 0
85
+ y: 0,
86
+ last_x: 0,
87
+ last_y: 0
60
88
  },
61
89
  on_key: null,
62
90
  on_mouse: null,
@@ -83,10 +111,13 @@ S2D.Image = {
83
111
  // Sprite
84
112
  S2D.Sprite = {
85
113
  img: null,
114
+ color: null,
86
115
  x: 0,
87
116
  y: 0,
88
117
  width: null,
89
118
  height: null,
119
+ clip_width: null,
120
+ clip_height: null,
90
121
  tx1: null,
91
122
  ty1: null,
92
123
  tx2: null,
@@ -130,27 +161,27 @@ S2D.keys_down = [];
130
161
  // On keyboard starting at top row, left to right
131
162
  S2D.key_map = {
132
163
  27: "Escape",
133
-
164
+
134
165
  192: "`",
135
166
  189: "-",
136
167
  187: "=",
137
168
  8: "Backspace",
138
-
169
+
139
170
  9: "Tab",
140
171
  219: "[",
141
172
  221: "]",
142
173
  220: "\\",
143
-
174
+
144
175
  20: "CapsLock",
145
176
  186: ";",
146
177
  222: "'",
147
178
  13: "Return",
148
-
179
+
149
180
  16: "Shift",
150
181
  188: ",",
151
182
  190: ".",
152
183
  191: "/",
153
-
184
+
154
185
  17: "Ctrl",
155
186
  18: "Option",
156
187
  91: "Left Command",
@@ -190,28 +221,28 @@ S2D.TrimCanvas = function(c) {
190
221
  bottom: null
191
222
  },
192
223
  x, y;
193
-
224
+
194
225
  for (i = 0; i < l; i += 4) {
195
226
  if (pixels.data[i+3] !== 0) {
196
227
  x = (i / 4) % c.width;
197
228
  y = ~~((i / 4) / c.width);
198
-
229
+
199
230
  if (bound.top === null) {
200
231
  bound.top = y;
201
232
  }
202
-
233
+
203
234
  if (bound.left === null) {
204
235
  bound.left = x;
205
236
  } else if (x < bound.left) {
206
237
  bound.left = x;
207
238
  }
208
-
239
+
209
240
  if (bound.right === null) {
210
241
  bound.right = x;
211
242
  } else if (bound.right < x) {
212
243
  bound.right = x;
213
244
  }
214
-
245
+
215
246
  if (bound.bottom === null) {
216
247
  bound.bottom = y;
217
248
  } else if (bound.bottom < y) {
@@ -219,54 +250,141 @@ S2D.TrimCanvas = function(c) {
219
250
  }
220
251
  }
221
252
  }
222
-
253
+
223
254
  var trimHeight = bound.bottom - bound.top,
224
255
  trimWidth = bound.right - bound.left,
225
256
  trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
226
-
257
+
227
258
  copy.canvas.width = trimWidth;
228
259
  copy.canvas.height = trimHeight;
229
260
  copy.putImageData(trimmed, 0, 0);
230
-
261
+
231
262
  // open new window with trimmed image:
232
263
  return copy.canvas;
233
264
  };
234
265
 
266
+ // Creates a global "addWheelListener" method
267
+ // example: addWheelListener(el, function(e) { console.log(e.deltaY); e.preventDefault(); });
268
+ // Adapted from: https://developer.mozilla.org/en-US/docs/Web/Events/wheel
269
+ (function(window, document) {
270
+
271
+ var prefix = "",
272
+ _addEventListener, support;
273
+
274
+ // detect event model
275
+ if (window.addEventListener) {
276
+ _addEventListener = "addEventListener";
277
+ } else {
278
+ _addEventListener = "attachEvent";
279
+ prefix = "on";
280
+ }
281
+
282
+ // detect available wheel event
283
+ support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
284
+ document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
285
+ "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
286
+
287
+ window.addWheelListener = function(elem, callback, useCapture) {
288
+ _addWheelListener(elem, support, callback, useCapture);
289
+
290
+ // handle MozMousePixelScroll in older Firefox
291
+ if (support == "DOMMouseScroll") {
292
+ _addWheelListener(elem, "MozMousePixelScroll", callback, useCapture);
293
+ }
294
+ };
295
+
296
+ function _addWheelListener(elem, eventName, callback, useCapture) {
297
+ elem[_addEventListener](prefix + eventName, support == "wheel" ? callback : function(originalEvent) {
298
+ !originalEvent && (originalEvent = window.event);
299
+
300
+ // create a normalized event object
301
+ var event = {
302
+ // keep a ref to the original event object
303
+ originalEvent: originalEvent,
304
+ target: originalEvent.target || originalEvent.srcElement,
305
+ type: "wheel",
306
+ deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
307
+ deltaX: 0,
308
+ deltaY: 0,
309
+ deltaZ: 0,
310
+ preventDefault: function() {
311
+ originalEvent.preventDefault ?
312
+ originalEvent.preventDefault() :
313
+ originalEvent.returnValue = false;
314
+ }
315
+ };
316
+
317
+ // calculate deltaY (and deltaX) according to the event
318
+ if (support == "mousewheel") {
319
+ event.deltaY = -1 / 40 * originalEvent.wheelDelta;
320
+ // Webkit also support wheelDeltaX
321
+ originalEvent.wheelDeltaX && (event.deltaX = -1 / 40 * originalEvent.wheelDeltaX);
322
+ } else {
323
+ event.deltaY = originalEvent.detail;
324
+ }
325
+
326
+ // it's time to fire the callback
327
+ return callback(event);
328
+
329
+ }, useCapture || false);
330
+ }
331
+
332
+ })(window, document);
333
+
235
334
 
236
335
  // shapes.js
237
336
 
238
337
  /*
239
338
  * Draw a triangle
240
339
  */
241
- S2D.DrawTriangle = function(x1, y1, c1r, c1g, c1b, c1a,
242
- x2, y2, c2r, c2g, c2b, c2a,
243
- x3, y3, c3r, c3g, c3b, c3a) {
244
-
245
- S2D.GL.DrawTriangle(x1, y1, c1r, c1g, c1b, c1a,
246
- x2, y2, c2r, c2g, c2b, c2a,
247
- x3, y3, c3r, c3g, c3b, c3a);
340
+ S2D.DrawTriangle = function(x1, y1, r1, g1, b1, a1,
341
+ x2, y2, r2, g2, b2, a2,
342
+ x3, y3, r3, g3, b3, a3) {
343
+
344
+ S2D.GL.DrawTriangle(x1, y1, r1, g1, b1, a1,
345
+ x2, y2, r2, g2, b2, a2,
346
+ x3, y3, r3, g3, b3, a3);
248
347
  };
249
348
 
250
349
 
251
350
  /*
252
351
  * Draw a quad, using two triangles
253
352
  */
254
- S2D.DrawQuad = function(x1, y1,
255
- c1r, c1g, c1b, c1a,
256
- x2, y2,
257
- c2r, c2g, c2b, c2a,
258
- x3, y3,
259
- c3r, c3g, c3b, c3a,
260
- x4, y4,
261
- c4r, c4g, c4b, c4a) {
262
-
263
- S2D.GL.DrawTriangle(x1, y1, c1r, c1g, c1b, c1a,
264
- x2, y2, c2r, c2g, c2b, c2a,
265
- x3, y3, c3r, c3g, c3b, c3a);
266
-
267
- S2D.GL.DrawTriangle(x3, y3, c3r, c3g, c3b, c3a,
268
- x4, y4, c4r, c4g, c4b, c4a,
269
- x1, y1, c1r, c1g, c1b, c1a);
353
+ S2D.DrawQuad = function(x1, y1, r1, g1, b1, a1,
354
+ x2, y2, r2, g2, b2, a2,
355
+ x3, y3, r3, g3, b3, a3,
356
+ x4, y4, r4, g4, b4, a4) {
357
+
358
+ S2D.GL.DrawTriangle(x1, y1, r1, g1, b1, a1,
359
+ x2, y2, r2, g2, b2, a2,
360
+ x3, y3, r3, g3, b3, a3);
361
+
362
+ S2D.GL.DrawTriangle(x3, y3, r3, g3, b3, a3,
363
+ x4, y4, r4, g4, b4, a4,
364
+ x1, y1, r1, g1, b1, a1);
365
+ };
366
+
367
+
368
+ /*
369
+ * Draw a line from a quad
370
+ */
371
+ S2D.DrawLine = function(x1, y1, x2, y2,
372
+ width,
373
+ r1, g1, b1, a1,
374
+ r2, g2, b2, a2,
375
+ r3, g3, b3, a3,
376
+ r4, g4, b4, a4) {
377
+
378
+ var length = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
379
+ var x = ((x2 - x1) / length) * width / 2;
380
+ var y = ((y2 - y1) / length) * width / 2;
381
+
382
+ S2D.DrawQuad(
383
+ x1 - y, y1 + x, r1, g1, b1, a1,
384
+ x1 + y, y1 - x, r2, g2, b2, a2,
385
+ x2 + y, y2 - x, r3, g3, b3, a3,
386
+ x2 - y, y2 + x, r4, g4, b4, a4
387
+ );
270
388
  };
271
389
 
272
390
 
@@ -277,24 +395,24 @@ S2D.DrawQuad = function(x1, y1,
277
395
  * Params: path = image file path
278
396
  */
279
397
  S2D.CreateImage = function(path, loadedCallback) {
280
-
398
+
281
399
  // TODO: Check if image file exists
282
-
400
+
283
401
  // Create image object
284
402
  var img = Object.create(S2D.Image);
285
403
  img.data = new Image();
286
404
  img.color = Object.create(S2D.Color);
287
-
405
+
288
406
  img.data.onload = function() {
289
407
  img.texture = S2D.GL.CreateTexture(this);
290
- if (!img.width) img.width = this.width;
408
+ if (!img.width ) img.width = this.width;
291
409
  if (!img.height) img.height = this.height;
292
410
  if (loadedCallback) loadedCallback();
293
411
  };
294
-
412
+
295
413
  // Causes image to be loaded
296
414
  img.data.src = path;
297
-
415
+
298
416
  return img;
299
417
  };
300
418
 
@@ -314,15 +432,18 @@ S2D.DrawImage = function(img) {
314
432
  * Create a sprite, given an image file path
315
433
  */
316
434
  S2D.CreateSprite = function(path) {
317
-
435
+
318
436
  // TODO: Check if sprite image file exists
319
-
437
+
320
438
  var spr = Object.create(S2D.Sprite);
439
+ spr.color = Object.create(S2D.Color);
321
440
  spr.img = S2D.CreateImage(path, function() {
322
- spr.width = spr.img.width;
323
- spr.height = spr.img.height;
441
+ if (!spr.width ) spr.width = spr.img.width;
442
+ if (!spr.height) spr.height = spr.img.height;
443
+ spr.clip_width = spr.img.width;
444
+ spr.clip_height = spr.img.height;
324
445
  });
325
-
446
+
326
447
  spr.tx1 = 0.0;
327
448
  spr.ty1 = 0.0;
328
449
  spr.tx2 = 1.0;
@@ -331,7 +452,7 @@ S2D.CreateSprite = function(path) {
331
452
  spr.ty3 = 1.0;
332
453
  spr.tx4 = 0.0;
333
454
  spr.ty4 = 1.0;
334
-
455
+
335
456
  return spr;
336
457
  };
337
458
 
@@ -341,44 +462,46 @@ S2D.CreateSprite = function(path) {
341
462
  */
342
463
  S2D.ClipSprite = function(spr, x, y, w, h) {
343
464
  if (!spr) return;
344
-
465
+
345
466
  // Calculate ratios
346
467
  // rw = ratio width; rh = ratio height
347
468
  var rw = w / spr.img.width;
348
469
  var rh = h / spr.img.height;
349
-
470
+
350
471
  // Apply ratios to x, y coordinates
351
472
  // cx = crop x coord; cy = crop y coord
352
473
  var cx = x * rw;
353
474
  var cy = y * rh;
354
-
475
+
355
476
  // Convert given width, height to doubles
356
477
  // cw = crop width; ch = crop height
357
478
  var cw = w;
358
479
  var ch = h;
359
-
480
+
360
481
  // Apply ratio to texture width and height
361
482
  // tw = texture width; th = texture height
362
483
  var tw = rw * w;
363
484
  var th = rh * h;
364
-
485
+
365
486
  // Calculate and store sprite texture values
366
-
487
+
367
488
  spr.tx1 = cx / cw;
368
489
  spr.ty1 = cy / ch;
369
-
490
+
370
491
  spr.tx2 = (cx + tw) / cw;
371
492
  spr.ty2 = cy / ch;
372
-
493
+
373
494
  spr.tx3 = (cx + tw) / cw;
374
495
  spr.ty3 = (cy + th) / ch;
375
-
496
+
376
497
  spr.tx4 = cx / cw;
377
498
  spr.ty4 = (cy + th) / ch;
378
-
379
- // Store the sprite width and height
380
- spr.width = w;
381
- spr.height = h;
499
+
500
+ // Store the sprite dimensions
501
+ spr.width = (spr.width / spr.clip_width ) * w;
502
+ spr.height = (spr.height / spr.clip_height) * h;
503
+ spr.clip_width = w;
504
+ spr.clip_height = h;
382
505
  };
383
506
 
384
507
 
@@ -397,37 +520,39 @@ S2D.DrawSprite = function(spr) {
397
520
  * Create text, given a font file path, the message, and size
398
521
  */
399
522
  S2D.CreateText = function(font, msg, size) {
400
-
523
+
401
524
  // Create image object
402
525
  var txt = Object.create(S2D.Text);
403
526
  txt.color = Object.create(S2D.Color);
404
- txt.font = font;
527
+ txt.font = font ? font : null;
405
528
  txt.msg = msg;
406
529
  txt.size = size;
407
-
530
+
531
+ S2D.SetText(txt, txt.msg);
532
+
408
533
  return txt;
409
534
  };
410
535
 
411
536
 
412
537
  /*
413
- * Sets the text message
414
- */
538
+ * Sets the text message
539
+ */
415
540
  S2D.SetText = function(txt, msg) {
416
541
  if (msg == "") return; // no need to create a texture
417
-
418
- S2D.GL.FreeTexture(txt.texture);
419
-
542
+
543
+ if (txt.texture) S2D.GL.FreeTexture(txt.texture);
544
+
420
545
  // Create a canvas element to make a texture
421
546
  var ctx = document.createElement("canvas").getContext("2d");
422
-
547
+
423
548
  // TODO: Width and height should probably be variable, based on
424
549
  // `ctx.measureText(msg).width` or something.
425
550
  var w = 1000;
426
551
  var h = 1000;
427
-
552
+
428
553
  // Double size of font for high DPI
429
554
  var size = txt.size * 2;
430
-
555
+
431
556
  // Set context attributes and draw text
432
557
  ctx.canvas.width = w;
433
558
  ctx.canvas.height = h;
@@ -436,7 +561,7 @@ S2D.SetText = function(txt, msg) {
436
561
  ctx.textBaseline = "bottom";
437
562
  ctx.fillStyle = "white";
438
563
  ctx.fillText(msg, w, h);
439
-
564
+
440
565
  txt.data = S2D.TrimCanvas(ctx.canvas); // trim the transparent pixels
441
566
  txt.texture = S2D.GL.CreateTexture(txt.data);
442
567
  txt.width = txt.data.width / 2; // half size of texture for high DPI
@@ -449,11 +574,7 @@ S2D.SetText = function(txt, msg) {
449
574
  */
450
575
  S2D.DrawText = function(txt) {
451
576
  if (!txt) return;
452
-
453
- if (!txt.texture) {
454
- S2D.SetText(txt, txt.msg);
455
- }
456
-
577
+ if (!txt.texture) S2D.SetText(txt, txt.msg);
457
578
  S2D.GL.DrawText(txt);
458
579
  };
459
580
 
@@ -464,12 +585,12 @@ S2D.DrawText = function(txt) {
464
585
  * Create a sound, given an audio file path
465
586
  */
466
587
  S2D.CreateSound = function(path) {
467
-
588
+
468
589
  // TODO: Check if audio file exists
469
-
590
+
470
591
  var sound = Object.create(S2D.Sound);
471
592
  sound.data = new Audio(path);
472
-
593
+
473
594
  return sound;
474
595
  };
475
596
 
@@ -489,12 +610,12 @@ S2D.PlaySound = function(sound) {
489
610
  * Create the music, given an audio file path
490
611
  */
491
612
  S2D.CreateMusic = function(path) {
492
-
613
+
493
614
  // TODO: Check if audio file exists
494
-
615
+
495
616
  var music = Object.create(S2D.Music);
496
617
  music.data = new Audio(path);
497
-
618
+
498
619
  return music;
499
620
  };
500
621
 
@@ -543,12 +664,12 @@ S2D.StopMusic = function() {
543
664
  */
544
665
  S2D.FadeOutMusic = function(ms) {
545
666
  if (!S2D.current_music) return;
546
-
667
+
547
668
  if (S2D.current_music.paused) {
548
669
  S2D.StopMusic();
549
670
  return;
550
671
  }
551
-
672
+
552
673
  var fadeAudio = setInterval(function () {
553
674
  if (S2D.current_music.volume >= 0.05) {
554
675
  S2D.current_music.volume -= 0.05;
@@ -557,7 +678,7 @@ S2D.FadeOutMusic = function(ms) {
557
678
  S2D.current_music.volume = 1.0;
558
679
  clearInterval(fadeAudio);
559
680
  }
560
-
681
+
561
682
  }, ms / 20);
562
683
  };
563
684
 
@@ -568,30 +689,30 @@ S2D.FadeOutMusic = function(ms) {
568
689
  * Get the mouse coordinates relative to the viewport
569
690
  */
570
691
  S2D.GetMouseOnViewport = function(win, wx, wy) {
571
-
692
+
572
693
  var scale; // viewport scale factor
573
694
  var w, h; // width and height of scaled viewport
574
695
  var x, y; // mouse positions to be returned
575
-
696
+
576
697
  switch (win.viewport.mode) {
577
-
698
+
578
699
  case S2D.FIXED:
579
700
  x = wx / (win.orig_width / win.viewport.width);
580
701
  y = wy / (win.orig_height / win.viewport.height);
581
702
  break;
582
-
703
+
583
704
  case S2D.SCALE:
584
705
  var o = S2D.GL.GetViewportScale(win);
585
706
  x = wx * 1 / o.scale - (win.width - o.w) / (2.0 * o.scale);
586
707
  y = wy * 1 / o.scale - (win.height - o.h) / (2.0 * o.scale);
587
708
  break;
588
-
709
+
589
710
  case S2D.STRETCH:
590
711
  x = wx * win.viewport.width / win.width;
591
712
  y = wy * win.viewport.height / win.height;
592
713
  break;
593
714
  }
594
-
715
+
595
716
  return {
596
717
  x: x,
597
718
  y: y
@@ -599,15 +720,34 @@ S2D.GetMouseOnViewport = function(win, wx, wy) {
599
720
  };
600
721
 
601
722
 
723
+ /*
724
+ * Get the mouse button name from its code
725
+ */
726
+ S2D.GetMouseButtonName = function(code) {
727
+ switch (code) {
728
+ case 0:
729
+ return S2D.MOUSE_LEFT;
730
+ case 1:
731
+ return S2D.MOUSE_MIDDLE;
732
+ case 2:
733
+ return S2D.MOUSE_RIGHT;
734
+ case 3:
735
+ return S2D.MOUSE_X1;
736
+ case 4:
737
+ return S2D.MOUSE_X2;
738
+ }
739
+ };
740
+
741
+
602
742
  // window.js
603
743
 
604
744
  /*
605
745
  * Create a window
606
746
  */
607
747
  S2D.CreateWindow = function(title, width, height, update, render, element, opts) {
608
-
748
+
609
749
  var win = Object.create(S2D.Window);
610
-
750
+
611
751
  win.title = title;
612
752
  win.width = width;
613
753
  win.height = height;
@@ -623,14 +763,14 @@ S2D.CreateWindow = function(title, width, height, update, render, element, opts)
623
763
  win.background.g = 0;
624
764
  win.background.b = 0;
625
765
  win.background.a = 1;
626
-
766
+
627
767
  // `element` can be an ID string (e.g. "#game") or an actual DOM element
628
768
  if (typeof(element) == 'string') {
629
769
  win.element = document.getElementById(element);
630
770
  } else {
631
771
  win.element = element;
632
772
  }
633
-
773
+
634
774
  return win;
635
775
  };
636
776
 
@@ -639,53 +779,64 @@ S2D.CreateWindow = function(title, width, height, update, render, element, opts)
639
779
  * Show the window
640
780
  */
641
781
  S2D.Show = function(win) {
642
-
782
+
643
783
  // Create the canvas element
644
-
784
+
645
785
  var el = document.createElement('canvas');
646
786
  win.element.appendChild(el);
647
-
787
+
648
788
  el.setAttribute('width', win.width);
649
789
  el.setAttribute('height', win.height);
650
790
  el.innerHTML = "Your browser doesn't appear to support" +
651
791
  "the <code>&lt;canvas&gt;</code> element.";
652
-
792
+
653
793
  win.canvas = el;
654
-
794
+
795
+ // Prevent right clicking in canvas
796
+ win.canvas.addEventListener("contextmenu", function(e) { e.preventDefault(); });
797
+
655
798
  // Detect and set up canvas for high DPI
656
-
799
+
657
800
  win.canvas.style.width = win.width + "px";
658
801
  win.canvas.style.height = win.height + "px";
659
-
802
+
660
803
  var ratio = window.devicePixelRatio ||
661
804
  window.webkitDevicePixelRatio ||
662
805
  window.mozDevicePixelRatio ||
663
806
  window.opDevicePixelRatio || 1;
664
-
807
+
665
808
  win.canvas.width = win.width * devicePixelRatio;
666
809
  win.canvas.height = win.height * devicePixelRatio;
667
810
  win.pixel_ratio = ratio;
668
-
811
+
669
812
  // Initialize WebGL
670
813
  S2D.GL.Init(win);
671
-
814
+
672
815
  S2D.onkeydown = function(e) {
673
- var key = S2D.GetKey(e.keyCode);
674
- if (!S2D.keys_down.includes(key)) {
675
- S2D.keys_down.push(key);
676
- if (win.on_key) win.on_key(S2D.KEYDOWN, key);
816
+ if (win.on_key) {
817
+ var key = S2D.GetKey(e.keyCode);
818
+ if (!S2D.keys_down.includes(key)) {
819
+ S2D.keys_down.push(key);
820
+ var event = Object.create(S2D.Event);
821
+ event.type = S2D.KEY_DOWN; event.key = key;
822
+ win.on_key(event);
823
+ }
677
824
  }
678
825
  };
679
826
  document.addEventListener("keydown", S2D.onkeydown);
680
-
827
+
681
828
  S2D.onkeyup = function(e) {
682
- var key = S2D.GetKey(e.keyCode);
683
- var i = S2D.keys_down.indexOf(key);
684
- if (i > -1) S2D.keys_down.splice(i, 1);
685
- if (win.on_key) win.on_key(S2D.KEYUP, key);
829
+ if (win.on_key) {
830
+ var key = S2D.GetKey(e.keyCode);
831
+ var i = S2D.keys_down.indexOf(key);
832
+ if (i > -1) S2D.keys_down.splice(i, 1);
833
+ var event = Object.create(S2D.Event);
834
+ event.type = S2D.KEY_UP; event.key = key;
835
+ win.on_key(event);
836
+ }
686
837
  };
687
838
  document.addEventListener("keyup", S2D.onkeyup);
688
-
839
+
689
840
  // Clear keys down list when focus is lost
690
841
  window.addEventListener("blur", function functionName() {
691
842
  var e = {};
@@ -694,60 +845,107 @@ S2D.Show = function(win) {
694
845
  S2D.onkeyup(e);
695
846
  });
696
847
  });
697
-
848
+
698
849
  S2D.onmousedown = function(e) {
699
- var x = e.pageX - win.canvas.offsetLeft;
700
- var y = e.pageY - win.canvas.offsetTop;
701
- var o = S2D.GetMouseOnViewport(win, x, y);
702
- if (win.on_mouse) win.on_mouse(o.x, o.y);
850
+ if (win.on_mouse) {
851
+ var o = S2D.GetMouseOnViewport(win,
852
+ e.pageX - win.canvas.offsetLeft, e.pageY - win.canvas.offsetTop
853
+ );
854
+ var event = Object.create(S2D.Event);
855
+ event.type = S2D.MOUSE_DOWN;
856
+ event.button = S2D.GetMouseButtonName(e.button);
857
+ event.x = o.x; event.y = o.y;
858
+ win.on_mouse(event);
859
+ }
703
860
  };
704
861
  document.addEventListener("mousedown", S2D.onmousedown);
705
-
706
- // Get and store mouse position
862
+
863
+ S2D.onmouseup = function(e) {
864
+ if (win.on_mouse) {
865
+ var o = S2D.GetMouseOnViewport(win,
866
+ e.pageX - win.canvas.offsetLeft, e.pageY - win.canvas.offsetTop
867
+ );
868
+ var event = Object.create(S2D.Event);
869
+ event.type = S2D.MOUSE_UP;
870
+ event.button = S2D.GetMouseButtonName(e.button);
871
+ event.x = o.x; event.y = o.y;
872
+ win.on_mouse(event);
873
+ }
874
+ };
875
+ document.addEventListener("mouseup", S2D.onmouseup);
876
+
877
+ // Get and store mouse position, call mouse move
707
878
  S2D.onmousemove = function(e) {
708
- var x = e.pageX - win.canvas.offsetLeft;
709
- var y = e.pageY - win.canvas.offsetTop;
710
- var o = S2D.GetMouseOnViewport(win, x, y);
879
+ var o = S2D.GetMouseOnViewport(win,
880
+ e.pageX - win.canvas.offsetLeft, e.pageY - win.canvas.offsetTop
881
+ );
711
882
  win.mouse.x = o.x;
712
883
  win.mouse.y = o.y;
884
+ if (win.on_mouse) {
885
+ var event = Object.create(S2D.Event);
886
+ event.type = S2D.MOUSE_MOVE;
887
+ event.x = o.x; event.y = o.y;
888
+ event.delta_x = o.x - win.mouse.last_x; event.delta_y = o.y - win.mouse.last_y;
889
+ win.on_mouse(event);
890
+ win.mouse.last_x = o.x; win.mouse.last_y = o.y;
891
+ }
713
892
  };
714
893
  document.addEventListener("mousemove", S2D.onmousemove);
715
-
894
+
895
+ // Get and store mouse wheel scrolling
896
+ S2D.onmousewheel = function(e) {
897
+ if (win.on_mouse) {
898
+ var event = Object.create(S2D.Event);
899
+ event.type = S2D.MOUSE_SCROLL;
900
+ event.direction = e.webkitDirectionInvertedFromDevice ?
901
+ S2D.MOUSE_SCROLL_INVERTED : S2D.MOUSE_SCROLL_NORMAL;
902
+ event.delta_x = e.deltaX;
903
+ event.delta_y = e.deltaY;
904
+ win.on_mouse(event);
905
+ }
906
+ e.preventDefault();
907
+ };
908
+ window.addWheelListener(document, S2D.onmousewheel);
909
+
716
910
  // Main loop
717
-
911
+
718
912
  var req; // the animation frame request
719
913
  var start_ms = new Date();
720
914
  var end_ms = new Date();
721
915
  var elapsed_ms;
722
-
916
+
723
917
  function mainLoop(win) {
724
-
918
+
725
919
  if (win.close) {
726
920
  cancelAnimationFrame(req);
727
921
  return;
728
922
  }
729
-
923
+
730
924
  S2D.GL.Clear(win.background);
731
-
925
+
732
926
  // Update frame counter
733
927
  win.frames++;
734
-
928
+
735
929
  // Calculate and store FPS
736
930
  end_ms = new Date();
737
931
  elapsed_ms = end_ms.getTime() - start_ms.getTime();
738
932
  win.fps = win.frames / (elapsed_ms / 1000.0);
739
-
933
+
740
934
  // Detect keys held down
741
935
  S2D.keys_down.forEach(function(key) {
742
- if (win.on_key) win.on_key(S2D.KEY, key);
936
+ if (win.on_key) {
937
+ var event = Object.create(S2D.Event);
938
+ event.type = S2D.KEY_HELD; event.key = key;
939
+ win.on_key(event);
940
+ }
743
941
  });
744
-
942
+
745
943
  if (win.update) win.update();
746
944
  if (win.render) win.render();
747
-
945
+
748
946
  requestAnimationFrame(function() { mainLoop(win); });
749
947
  }
750
-
948
+
751
949
  req = requestAnimationFrame(function() { mainLoop(win); });
752
950
  };
753
951
 
@@ -789,7 +987,7 @@ var orthoMatrix = [
789
987
  * Initialize WebGL
790
988
  */
791
989
  S2D.GL.Init = function(win) {
792
-
990
+
793
991
  // Initialize the GL context
794
992
  try {
795
993
  // Try to grab the standard context. If it fails, fallback to experimental.
@@ -797,13 +995,13 @@ S2D.GL.Init = function(win) {
797
995
  } catch(e) {
798
996
  console.log("GL error caught");
799
997
  }
800
-
998
+
801
999
  // If we don't have a GL context, give up now
802
1000
  if (!gl) {
803
1001
  console.error("Unable to initialize WebGL. Your browser may not support it.");
804
1002
  return null;
805
1003
  }
806
-
1004
+
807
1005
  S2D.GL.WebGLInit();
808
1006
  S2D.GL.SetViewport(win);
809
1007
  };
@@ -813,11 +1011,11 @@ S2D.GL.Init = function(win) {
813
1011
  * Initialize WebGL
814
1012
  */
815
1013
  S2D.GL.WebGLInit = function() {
816
-
1014
+
817
1015
  // Enable transparency
818
1016
  gl.enable(gl.BLEND);
819
1017
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
820
-
1018
+
821
1019
  // Vertex shader source string
822
1020
  var vertexSource = `
823
1021
  uniform mat4 u_matrix;
@@ -831,7 +1029,7 @@ S2D.GL.WebGLInit = function() {
831
1029
  v_texcoord = a_texcoord;
832
1030
  gl_Position = u_matrix * a_position;
833
1031
  }`;
834
-
1032
+
835
1033
  // Fragment shader source string
836
1034
  var fragmentSource = `
837
1035
  precision mediump float;
@@ -839,7 +1037,7 @@ S2D.GL.WebGLInit = function() {
839
1037
  void main(void) {
840
1038
  gl_FragColor = v_color;
841
1039
  }`;
842
-
1040
+
843
1041
  // Fragment shader source string for textures
844
1042
  var texFragmentSource = `
845
1043
  precision mediump float;
@@ -849,55 +1047,55 @@ S2D.GL.WebGLInit = function() {
849
1047
  void main(void) {
850
1048
  gl_FragColor = texture2D(s_texture, v_texcoord) * v_color;
851
1049
  }`;
852
-
1050
+
853
1051
  // Load the vertex and fragment shaders
854
1052
  var vertexShader = S2D.GL.LoadShader( gl.VERTEX_SHADER, vertexSource, "Vertex");
855
1053
  var fragmentShader = S2D.GL.LoadShader(gl.FRAGMENT_SHADER, fragmentSource, "Fragment");
856
1054
  var texFragmentShader = S2D.GL.LoadShader(gl.FRAGMENT_SHADER, texFragmentSource, "Texture Fragment");
857
-
1055
+
858
1056
  // Triangle Shader //
859
-
1057
+
860
1058
  // Create the texture shader program object
861
1059
  shaderProgram = gl.createProgram();
862
-
1060
+
863
1061
  // Attach the shader objects to the program object
864
1062
  gl.attachShader(shaderProgram, vertexShader);
865
1063
  gl.attachShader(shaderProgram, fragmentShader);
866
-
1064
+
867
1065
  // Link the shader program
868
1066
  gl.linkProgram(shaderProgram);
869
-
1067
+
870
1068
  // Check if linked
871
1069
  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
872
1070
  console.error("Unable to initialize the shader program.");
873
1071
  }
874
-
1072
+
875
1073
  // Get the attribute locations
876
1074
  positionLocation = gl.getAttribLocation(shaderProgram, "a_position");
877
1075
  colorLocation = gl.getAttribLocation(shaderProgram, "a_color");
878
-
1076
+
879
1077
  // Texture Shader //
880
-
1078
+
881
1079
  // Create the texture shader program object
882
1080
  texShaderProgram = gl.createProgram();
883
-
1081
+
884
1082
  // Attach the shader objects to the program object
885
1083
  gl.attachShader(texShaderProgram, vertexShader);
886
1084
  gl.attachShader(texShaderProgram, texFragmentShader);
887
-
1085
+
888
1086
  // Link the shader program
889
1087
  gl.linkProgram(texShaderProgram);
890
-
1088
+
891
1089
  // Check if linked
892
1090
  if (!gl.getProgramParameter(texShaderProgram, gl.LINK_STATUS)) {
893
1091
  console.error("Unable to initialize the texture shader program.");
894
1092
  }
895
-
1093
+
896
1094
  // Get the attribute locations
897
1095
  texPositionLocation = gl.getAttribLocation(texShaderProgram, "a_position");
898
1096
  texColorLocation = gl.getAttribLocation(texShaderProgram, "a_color");
899
1097
  texCoordLocation = gl.getAttribLocation(texShaderProgram, "a_texcoord");
900
-
1098
+
901
1099
  // Get the sampler location
902
1100
  samplerLocation = gl.getUniformLocation(texShaderProgram, "s_texture");
903
1101
  };
@@ -907,17 +1105,17 @@ S2D.GL.WebGLInit = function() {
907
1105
  * Creates a shader object, loads shader string, and compiles.
908
1106
  */
909
1107
  S2D.GL.LoadShader = function(type, shaderSrc, shaderName) {
910
-
1108
+
911
1109
  var shader = gl.createShader(type);
912
-
1110
+
913
1111
  gl.shaderSource(shader, shaderSrc);
914
1112
  gl.compileShader(shader);
915
-
1113
+
916
1114
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
917
1115
  console.error("Error compiling shader \"" + shaderName + "\":\n" + gl.getShaderInfoLog(shader));
918
1116
  return null;
919
1117
  }
920
-
1118
+
921
1119
  return shader;
922
1120
  };
923
1121
 
@@ -926,15 +1124,15 @@ S2D.GL.LoadShader = function(type, shaderSrc, shaderName) {
926
1124
  * Calculate the viewport's scaled width and height
927
1125
  */
928
1126
  S2D.GL.GetViewportScale = function(win) {
929
-
1127
+
930
1128
  var s = Math.min(
931
1129
  win.width / win.viewport.width,
932
1130
  win.height / win.viewport.height
933
1131
  );
934
-
1132
+
935
1133
  var w = win.viewport.width * s;
936
1134
  var h = win.viewport.height * s;
937
-
1135
+
938
1136
  return {
939
1137
  w: w,
940
1138
  h: h,
@@ -947,51 +1145,51 @@ S2D.GL.GetViewportScale = function(win) {
947
1145
  * Sets the viewport and matrix projection
948
1146
  */
949
1147
  S2D.GL.SetViewport = function(win) {
950
-
1148
+
951
1149
  var ortho_w = win.viewport.width;
952
1150
  var ortho_h = win.viewport.height;
953
1151
  var x, y, w, h; // calculated GL viewport values
954
-
1152
+
955
1153
  x = 0; y = 0; w = win.width; h = win.height;
956
-
1154
+
957
1155
  switch (win.viewport.mode) {
958
-
1156
+
959
1157
  case S2D.FIXED:
960
1158
  w = win.orig_width;
961
1159
  h = win.orig_height;
962
1160
  y = win.height - h;
963
1161
  break;
964
-
1162
+
965
1163
  case S2D.SCALE:
966
1164
  var o = S2D.GL.GetViewportScale(win);
967
1165
  // Center the viewport
968
1166
  x = win.width / 2.0 - o.w/2.0;
969
1167
  y = win.height / 2.0 - o.h/2.0;
970
1168
  break;
971
-
1169
+
972
1170
  case S2D.STRETCH:
973
1171
  break;
974
1172
  }
975
-
1173
+
976
1174
  gl.viewport(
977
1175
  x * win.pixel_ratio,
978
1176
  y * win.pixel_ratio,
979
1177
  w * win.pixel_ratio,
980
1178
  h * win.pixel_ratio
981
1179
  );
982
-
1180
+
983
1181
  orthoMatrix[0] = 2.0 / ortho_w;
984
1182
  orthoMatrix[5] = -2.0 / ortho_h;
985
-
1183
+
986
1184
  gl.useProgram(shaderProgram);
987
-
1185
+
988
1186
  gl.uniformMatrix4fv(
989
1187
  gl.getUniformLocation(shaderProgram, "u_matrix"),
990
1188
  false, new Float32Array(orthoMatrix)
991
1189
  );
992
-
1190
+
993
1191
  gl.useProgram(texShaderProgram);
994
-
1192
+
995
1193
  gl.uniformMatrix4fv(
996
1194
  gl.getUniformLocation(texShaderProgram, "u_matrix"),
997
1195
  false, new Float32Array(orthoMatrix)
@@ -1012,24 +1210,25 @@ S2D.GL.Clear = function(clr) {
1012
1210
  * Creates a texture for rendering
1013
1211
  */
1014
1212
  S2D.GL.CreateTexture = function(data) {
1015
-
1213
+ if (!gl) return;
1214
+
1016
1215
  var texture = gl.createTexture();
1017
-
1216
+
1018
1217
  // Bind the named texture to a texturing target
1019
1218
  gl.bindTexture(gl.TEXTURE_2D, texture);
1020
-
1219
+
1021
1220
  // Specifies the 2D texture image
1022
1221
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
1023
-
1222
+
1024
1223
  // Set the filtering mode
1025
1224
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
1026
1225
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
1027
-
1226
+
1028
1227
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1029
1228
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1030
-
1229
+
1031
1230
  gl.bindTexture(gl.TEXTURE_2D, null);
1032
-
1231
+
1033
1232
  return texture;
1034
1233
  };
1035
1234
 
@@ -1045,38 +1244,38 @@ S2D.GL.FreeTexture = function(texture) {
1045
1244
  /*
1046
1245
  * Draw triangle
1047
1246
  */
1048
- S2D.GL.DrawTriangle = function(x1, y1, c1r, c1g, c1b, c1a,
1049
- x2, y2, c2r, c2g, c2b, c2a,
1050
- x3, y3, c3r, c3g, c3b, c3a) {
1051
-
1247
+ S2D.GL.DrawTriangle = function(x1, y1, r1, g1, b1, a1,
1248
+ x2, y2, r2, g2, b2, a2,
1249
+ x3, y3, r3, g3, b3, a3) {
1250
+
1052
1251
  var vertices = [
1053
1252
  x1, y1, 0.0,
1054
1253
  x2, y2, 0.0,
1055
1254
  x3, y3, 0.0
1056
1255
  ];
1057
-
1256
+
1058
1257
  var colors = [
1059
- c1r, c1g, c1b, c1a,
1060
- c2r, c2g, c2b, c2a,
1061
- c3r, c3g, c3b, c3a
1258
+ r1, g1, b1, a1,
1259
+ r2, g2, b2, a2,
1260
+ r3, g3, b3, a3
1062
1261
  ];
1063
-
1262
+
1064
1263
  gl.useProgram(shaderProgram);
1065
-
1264
+
1066
1265
  // Vertex
1067
1266
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
1068
1267
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
1069
-
1268
+
1070
1269
  gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
1071
1270
  gl.enableVertexAttribArray(positionLocation);
1072
-
1271
+
1073
1272
  // Colors
1074
1273
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
1075
1274
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1076
-
1275
+
1077
1276
  gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
1078
1277
  gl.enableVertexAttribArray(colorLocation);
1079
-
1278
+
1080
1279
  // Draw
1081
1280
  gl.drawArrays(gl.TRIANGLES, 0, 3);
1082
1281
  };
@@ -1089,48 +1288,48 @@ S2D.GL.DrawTexture = function(x, y, w, h,
1089
1288
  r, g, b, a,
1090
1289
  tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4,
1091
1290
  texture) {
1092
-
1291
+
1093
1292
  var vertices =
1094
1293
  // x, y coords | x, y texture coords
1095
1294
  [ x, y, 0.0, tx1, ty1,
1096
1295
  x + w, y, 0.0, tx2, ty2,
1097
1296
  x + w, y + h, 0.0, tx3, ty3,
1098
1297
  x, y + h, 0.0, tx4, ty4 ];
1099
-
1298
+
1100
1299
  var colors = [
1101
1300
  r, g, b, a,
1102
1301
  r, g, b, a,
1103
1302
  r, g, b, a,
1104
1303
  r, g, b, a
1105
1304
  ];
1106
-
1305
+
1107
1306
  gl.useProgram(texShaderProgram);
1108
-
1307
+
1109
1308
  // Vertex
1110
1309
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
1111
1310
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
1112
-
1311
+
1113
1312
  gl.vertexAttribPointer(texPositionLocation, 3, gl.FLOAT, false, 5*4, 0);
1114
1313
  gl.enableVertexAttribArray(texPositionLocation);
1115
-
1314
+
1116
1315
  gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 5*4, 3*4);
1117
1316
  gl.enableVertexAttribArray(texCoordLocation);
1118
-
1317
+
1119
1318
  // Colors
1120
1319
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
1121
1320
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
1122
-
1321
+
1123
1322
  gl.vertexAttribPointer(texColorLocation, 4, gl.FLOAT, false, 0, 0);
1124
1323
  gl.enableVertexAttribArray(texColorLocation);
1125
-
1324
+
1126
1325
  gl.activeTexture(gl.TEXTURE0);
1127
1326
  gl.bindTexture(gl.TEXTURE_2D, texture);
1128
-
1327
+
1129
1328
  gl.uniform1i(samplerLocation, 0);
1130
-
1329
+
1131
1330
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
1132
1331
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
1133
-
1332
+
1134
1333
  gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
1135
1334
  };
1136
1335
 
@@ -1154,7 +1353,7 @@ S2D.GL.DrawImage = function(img) {
1154
1353
  S2D.GL.DrawSprite = function(spr) {
1155
1354
  S2D.GL.DrawTexture(
1156
1355
  spr.x, spr.y, spr.width, spr.height,
1157
- spr.img.color.r, spr.img.color.g, spr.img.color.b, spr.img.color.a,
1356
+ spr.color.r, spr.color.g, spr.color.b, spr.color.a,
1158
1357
  spr.tx1, spr.ty1, spr.tx2, spr.ty2, spr.tx3, spr.ty3, spr.tx4, spr.ty4,
1159
1358
  spr.img.texture
1160
1359
  );