ruby2d 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  );