littlejsengine 1.16.2 → 1.17.5

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.
Files changed (57) hide show
  1. package/dist/littlejs.d.ts +291 -246
  2. package/dist/littlejs.esm.js +1520 -1271
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +1178 -920
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +1170 -912
  7. package/examples/box2d/gameObjects.js +4 -4
  8. package/examples/breakout/game.js +5 -6
  9. package/examples/electron/index.html +2 -2
  10. package/examples/electron/tiles.png +0 -0
  11. package/examples/htmlMenu/tiles.png +0 -0
  12. package/examples/index.html +9 -8
  13. package/examples/logo.png +0 -0
  14. package/examples/module/build.bat +7 -0
  15. package/examples/module/build.js +121 -0
  16. package/examples/module/tiles.png +0 -0
  17. package/examples/platformer/game.js +1 -1
  18. package/examples/platformer/gameEffects.js +25 -29
  19. package/examples/platformer/gameLevel.js +27 -28
  20. package/examples/puzzle/game.js +2 -2
  21. package/examples/shorts/base.html +4 -1
  22. package/examples/shorts/box2dPool.js +2 -2
  23. package/examples/shorts/box2dTileLayer.js +48 -0
  24. package/examples/shorts/clock.js +3 -3
  25. package/examples/shorts/fontImage.js +4 -3
  26. package/examples/shorts/music.js +2 -2
  27. package/examples/shorts/musicPlayer.js +2 -2
  28. package/examples/shorts/parallax.js +1 -1
  29. package/examples/shorts/sequencer.js +1 -1
  30. package/examples/shorts/shapes.js +1 -1
  31. package/examples/shorts/texture.js +10 -6
  32. package/examples/shorts/tiles.png +0 -0
  33. package/examples/shorts/tiltedView.js +2 -0
  34. package/examples/starter/index.html +2 -2
  35. package/examples/starter/tiles.png +0 -0
  36. package/examples/typescript/tiles.png +0 -0
  37. package/examples/uiSystem/game.js +1 -1
  38. package/examples/uiSystem/tiles.png +0 -0
  39. package/package.json +5 -5
  40. package/plugins/box2d.js +167 -63
  41. package/plugins/postProcess.js +47 -28
  42. package/plugins/uiSystem.js +18 -18
  43. package/plugins/zzfxm.js +2 -2
  44. package/reference.md +4 -3
  45. package/src/engine.js +182 -181
  46. package/src/engineAudio.js +47 -63
  47. package/src/engineDebug.js +8 -8
  48. package/src/engineDraw.js +184 -124
  49. package/src/engineExport.js +325 -334
  50. package/src/engineFont.png +0 -0
  51. package/src/engineInput.js +18 -24
  52. package/src/engineMath.js +24 -113
  53. package/src/engineObject.js +27 -26
  54. package/src/engineParticles.js +2 -2
  55. package/src/engineTileLayer.js +229 -192
  56. package/src/engineUtilities.js +100 -4
  57. package/src/engineWebGL.js +124 -73
@@ -53,7 +53,7 @@ class ParallaxLayer extends CanvasLayer
53
53
  this.context.clearRect(0,0,1,h);
54
54
 
55
55
  // make WebGL texture
56
- this.useWebGL();
56
+ this.updateWebGL();
57
57
  }
58
58
 
59
59
  render()
@@ -72,7 +72,7 @@ function gameInit()
72
72
  new UISystemPlugin;
73
73
  uiSystem.defaultCornerRadius = 8;
74
74
  uiSystem.defaultShadowColor = BLACK;
75
- canvasClearColor = hsl(0,0,.3);
75
+ canvasClearColor = GRAY;
76
76
 
77
77
  // create sequencer buttons
78
78
  for (let step=stepCount; step--;)
@@ -7,7 +7,7 @@ function gameRender()
7
7
 
8
8
  // polygon shapes
9
9
  drawRectGradient(vec2(-6,0), vec2(5,4), RED, BLUE)
10
- drawRegularPoly(vec2(0,0), vec2(4), 3, PURPLE, .3, WHITE, time);
10
+ drawRegularPoly(vec2(), vec2(4), 3, PURPLE, .3, WHITE, time);
11
11
  let starPath = []
12
12
  for (let i=10; i--;)
13
13
  starPath.push(vec2(0,2*(i%2?.4:1)).rotate(i/10*PI*2));
@@ -1,12 +1,16 @@
1
1
  function gameRender()
2
2
  {
3
3
  // show the full texture
4
- let pos = vec2(0,0); // world position to draw
5
- let size = vec2(15); // world size of the tile
6
- let color = hsl(0,0,1); // color to multiply the tile by
7
- let tilePos = vec2(0,0); // top left corner in pixels
8
- let tileSize = vec2(256); // source size in pixels
4
+ let pos = vec2(); // world position to draw
5
+ let size = vec2(15); // world size of the tile
6
+ let color = hsl(0,0,1); // color to multiply the tile by
7
+ let tilePos = vec2(); // top left corner in pixels
8
+ let tileSize = vec2(256); // source size in pixels
9
9
  let tileInfo = new TileInfo(tilePos, tileSize); // tile info
10
- drawRect(pos, size, GRAY); // draw background
10
+
11
+ // draw background
12
+ drawRect(pos, size, GRAY);
13
+
14
+ // draw the tile
11
15
  drawTile(pos, size, tileInfo, color);
12
16
  }
Binary file
@@ -19,6 +19,8 @@ class Player extends GameObject
19
19
  {
20
20
  update()
21
21
  {
22
+ super.update();
23
+
22
24
  // apply movement controls
23
25
  const moveInput = keyDirection().clampLength(1).scale(.2);
24
26
  this.velocity = this.velocity.add(moveInput);
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.js?1.16.2></script>
10
+ <script src=../../dist/littlejs.js?1.17.5></script>
11
11
 
12
12
  <!-- LittleJS Engine Source
13
13
  <script src=../../src/engine.js></script>
@@ -32,4 +32,4 @@
32
32
  -->
33
33
 
34
34
  <!-- Add your game scripts here -->
35
- <script src=game.js?1.16.2></script>
35
+ <script src=game.js?1.17.5></script>
Binary file
Binary file
@@ -38,7 +38,7 @@ function createUI()
38
38
  // setup example menu
39
39
  uiMenu = new LJS.UIObject(vec2(0,500));
40
40
  uiRoot.addChild(uiMenu);
41
- const uiBackground = new LJS.UIObject(vec2(0,0), vec2(450,580));
41
+ const uiBackground = new LJS.UIObject(vec2(), vec2(450,580));
42
42
  uiBackground.lineWidth = 8;
43
43
  uiMenu.addChild(uiBackground);
44
44
 
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.16.2",
3
+ "version": "1.17.5",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "dist/littlejs.esm.js",
6
6
  "types": "dist/littlejs.d.ts",
@@ -34,11 +34,11 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "bestzip": "^2.2.1",
37
+ "electron": "^38.2.0",
38
+ "electron-packager": "^17.1.2",
37
39
  "google-closure-compiler": "~20230502.0.0",
38
40
  "roadroller": "~2.1.0",
39
41
  "typescript": "~5.1.6",
40
- "uglify-js": "~3.17.4",
41
- "electron": "^38.2.0",
42
- "electron-packager": "^17.1.2"
42
+ "uglify-js": "~3.17.4"
43
43
  }
44
- }
44
+ }
package/plugins/box2d.js CHANGED
@@ -9,6 +9,7 @@
9
9
  * - Contact begin and end callbacks
10
10
  * - Wraps b2Vec2 type to/from Vector2
11
11
  * - Raycasting and querying
12
+ * - Box2dTileLayer for grid based collision
12
13
  * - Every type of joint
13
14
  * - Debug physics drawing
14
15
  * @namespace Box2D
@@ -60,21 +61,24 @@ class Box2dObject extends EngineObject
60
61
  bodyDef.set_type(bodyType);
61
62
  bodyDef.set_position(box2d.vec2dTo(pos));
62
63
  bodyDef.set_angle(-angle);
64
+
65
+ /** @property {Object} - The Box2d body */
63
66
  this.body = box2d.world.CreateBody(bodyDef);
64
- this.body.object = this;
67
+ /** @property {Color} - Line color used for default box2d drawing */
65
68
  this.lineColor = BLACK;
66
- box2d.objects.push(this);
67
-
68
- // edge lists and loops for drawing
69
+ /** @property {Array<Object>} - List of all edges for default box2d drawing */
69
70
  this.edgeLists = [];
71
+ /** @property {Array<Object>} - List of all edge loops for default box2d drawing */
70
72
  this.edgeLoops = [];
73
+
74
+ this.body.object = this; // link body to this object
75
+ box2d.objects.push(this); // keep track of all box2d objects
71
76
  }
72
77
 
73
78
  /** Destroy this object and its physics body */
74
79
  destroy()
75
80
  {
76
- if (this.destroyed)
77
- return;
81
+ if (this.destroyed) return;
78
82
 
79
83
  // destroy physics body, fixtures, and joints
80
84
  ASSERT(this.body, 'Box2dObject has no body to destroy');
@@ -105,11 +109,12 @@ class Box2dObject extends EngineObject
105
109
  }
106
110
 
107
111
  /** Draws all this object's fixtures
108
- * @param {Color} [color]
109
- * @param {Color} [lineColor]
110
- * @param {number} [lineWidth]
112
+ * @param {Color} [color]
113
+ * @param {Color} [lineColor]
114
+ * @param {number} [lineWidth]
115
+ * @param {boolean} [useWebGL=glEnable]
111
116
  * @param {CanvasRenderingContext2D} [context] */
112
- drawFixtures(color=WHITE, lineColor=BLACK, lineWidth=.1, context)
117
+ drawFixtures(color=WHITE, lineColor=BLACK, lineWidth=.1, useWebGL, context)
113
118
  {
114
119
  // draw non-edge fixtures
115
120
  this.getFixtureList().forEach((fixture)=>
@@ -117,7 +122,7 @@ class Box2dObject extends EngineObject
117
122
  const shape = box2d.castObjectType(fixture.GetShape());
118
123
  if (shape.GetType() !== box2d.instance.b2Shape.e_edge)
119
124
  {
120
- box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, context);
125
+ box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, useWebGL, context);
121
126
  }
122
127
  });
123
128
 
@@ -343,6 +348,14 @@ class Box2dObject extends EngineObject
343
348
  return fixtures;
344
349
  }
345
350
 
351
+ /** Destroy a fixture from the body
352
+ * @param {Object} [fixture] */
353
+ destroyFixture(fixture) { this.body.DestroyFixture(fixture); }
354
+
355
+ /** Destroy all fixture from the body */
356
+ destroyAllFixtures()
357
+ { this.getFixtureList().forEach(fixture=>this.destroyFixture(fixture)); }
358
+
346
359
  ///////////////////////////////////////////////////////////////////////////////
347
360
  // physics get functions
348
361
 
@@ -575,6 +588,136 @@ class Box2dObject extends EngineObject
575
588
  }
576
589
  }
577
590
 
591
+ ///////////////////////////////////////////////////////////////////////////////
592
+ /**
593
+ * Box2D Static Object - Box2d with a static physics body
594
+ * @extends Box2dObject
595
+ * @memberof Box2D
596
+ */
597
+ class Box2dStaticObject extends Box2dObject
598
+ {
599
+ /** Create a LittleJS object with Box2d physics
600
+ * @param {Vector2} [pos]
601
+ * @param {Vector2} [size]
602
+ * @param {TileInfo} [tileInfo]
603
+ * @param {number} [angle]
604
+ * @param {Color} [color]
605
+ * @param {number} [renderOrder] */
606
+ constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
607
+ {
608
+ const bodyType = box2d.bodyTypeStatic;
609
+ super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
610
+ }
611
+ }
612
+
613
+ ///////////////////////////////////////////////////////////////////////////////
614
+ /**
615
+ * Box2D Kiematic Object - Box2d with a kinematic physics body
616
+ * @extends Box2dObject
617
+ * @memberof Box2D
618
+ */
619
+ class Box2dKiematicObject extends Box2dObject
620
+ {
621
+ /** Create a LittleJS object with Box2d physics
622
+ * @param {Vector2} [pos]
623
+ * @param {Vector2} [size]
624
+ * @param {TileInfo} [tileInfo]
625
+ * @param {number} [angle]
626
+ * @param {Color} [color]
627
+ * @param {number} [renderOrder] */
628
+ constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
629
+ {
630
+ const bodyType = box2d.bodyTypeKinematic;
631
+ super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
632
+ }
633
+ }
634
+
635
+ ///////////////////////////////////////////////////////////////////////////////
636
+ /**
637
+ * Box2d Tile Layer
638
+ * - adds Box2d support to tile layers
639
+ * - creates static box2d fixtures for solid tiles
640
+ * @extends Box2dObject
641
+ * @memberof Box2D
642
+ */
643
+ class Box2dTileLayer extends Box2dStaticObject
644
+ {
645
+ /** Create a Box2d tile layer object
646
+ * @param {TileCollisionLayer} tileLayer - Tile layer for this object */
647
+ constructor(tileLayer)
648
+ {
649
+ ASSERT(tileLayer instanceof TileCollisionLayer, 'tileLayer must be a TileCollisionLayer');
650
+ super(tileLayer.pos, tileLayer.size);
651
+
652
+ /** @property {TileLayer} - The tile layer */
653
+ this.tileLayer = tileLayer;
654
+ this.addChild(tileLayer);
655
+ }
656
+
657
+ render()
658
+ {
659
+ // do not render fixtures, tile layer handles rendering
660
+ }
661
+
662
+ /** Create box2d collision fixtures for solid tiles
663
+ * @param {number} [friction]
664
+ * @param {number} [restitution] */
665
+ buildCollision(friction=.2, restitution=0)
666
+ {
667
+ // destroy all fixtures and create new ones
668
+ this.destroyAllFixtures();
669
+
670
+ // create box2d object for this layer
671
+ const size = this.tileLayer.size;
672
+ this.pos = this.tileLayer.pos.copy();
673
+ this.size = size.copy();
674
+
675
+ // track which tiles have been processed
676
+ const processed = [];
677
+ const getIndex = (x, y)=> x + y * size.x;
678
+ const isSolidUnprocessed = (x, y)=>
679
+ !processed[getIndex(x, y)] &&
680
+ this.tileLayer.getCollisionData(vec2(x, y)) > 0;
681
+
682
+ // combine tiles into larger boxes
683
+ for (let x = 0; x < size.x; ++x)
684
+ for (let y = 0; y < size.y; ++y)
685
+ {
686
+ if (!isSolidUnprocessed(x, y)) continue;
687
+
688
+ // find max width by scanning right
689
+ let width = 1, height = 1, canExpand = true;
690
+ while (isSolidUnprocessed(x + width, y))
691
+ ++width;
692
+
693
+ // find max height by scanning up, ensuring all rows have the same width
694
+ while (canExpand)
695
+ {
696
+ for (let checkX = 0; checkX < width; ++checkX)
697
+ {
698
+ if (!isSolidUnprocessed(x + checkX, y + height))
699
+ {
700
+ canExpand = false;
701
+ break;
702
+ }
703
+ }
704
+ if (canExpand)
705
+ ++height;
706
+ }
707
+
708
+ // mark all tiles in this rectangle as processed
709
+ for (let rectX = width; rectX--;)
710
+ for (let rectY = height; rectY--;)
711
+ processed[getIndex(x + rectX, y + rectY)] = true;
712
+
713
+ // create a single fixture for the entire rectangle
714
+ const shapeSize = vec2(width, height);
715
+ const offset = vec2(x + width/2, y + height/2);
716
+ this.addBox(shapeSize, offset, 0, 0, friction, restitution);
717
+ }
718
+ }
719
+ }
720
+
578
721
  ///////////////////////////////////////////////////////////////////////////////
579
722
  /**
580
723
  * Box2D Raycast Result
@@ -616,6 +759,7 @@ class Box2dJoint
616
759
  * @param {Object} jointDef */
617
760
  constructor(jointDef)
618
761
  {
762
+ /** @property {Object} - The Box2d joint */
619
763
  this.box2dJoint = box2d.castObjectType(box2d.world.CreateJoint(jointDef));
620
764
  }
621
765
 
@@ -962,7 +1106,7 @@ class Box2dGearJoint extends Box2dJoint
962
1106
  * @param {Box2dObject} objectB
963
1107
  * @param {Box2dJoint} joint1
964
1108
  * @param {Box2dJoint} joint2
965
- * @param {ratio} [ratio] */
1109
+ * @param {number} [ratio] */
966
1110
  constructor(objectA, objectB, joint1, joint2, ratio=1)
967
1111
  {
968
1112
  const jointDef = new box2d.instance.b2GearJointDef();
@@ -1104,50 +1248,6 @@ class Box2dPrismaticJoint extends Box2dJoint
1104
1248
  getMotorForce(time) { return this.box2dJoint.GetMotorForce(1/time); }
1105
1249
  }
1106
1250
 
1107
- ///////////////////////////////////////////////////////////////////////////////
1108
- /**
1109
- * Box2D Static Object - Box2d with a static physics body
1110
- * @extends Box2dObject
1111
- * @memberof Box2D
1112
- */
1113
- class Box2dStaticObject extends Box2dObject
1114
- {
1115
- /** Create a LittleJS object with Box2d physics
1116
- * @param {Vector2} [pos]
1117
- * @param {Vector2} [size]
1118
- * @param {TileInfo} [tileInfo]
1119
- * @param {number} [angle]
1120
- * @param {Color} [color]
1121
- * @param {number} [renderOrder] */
1122
- constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
1123
- {
1124
- const bodyType = box2d.bodyTypeStatic;
1125
- super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
1126
- }
1127
- }
1128
-
1129
- ///////////////////////////////////////////////////////////////////////////////
1130
- /**
1131
- * Box2D Kiematic Object - Box2d with a kinematic physics body
1132
- * @extends Box2dObject
1133
- * @memberof Box2D
1134
- */
1135
- class Box2dKiematicObject extends Box2dObject
1136
- {
1137
- /** Create a LittleJS object with Box2d physics
1138
- * @param {Vector2} [pos]
1139
- * @param {Vector2} [size]
1140
- * @param {TileInfo} [tileInfo]
1141
- * @param {number} [angle]
1142
- * @param {Color} [color]
1143
- * @param {number} [renderOrder] */
1144
- constructor(pos, size, tileInfo, angle=0, color, renderOrder=0)
1145
- {
1146
- const bodyType = box2d.bodyTypeKinematic;
1147
- super(pos, size, tileInfo, angle, color, bodyType, renderOrder);
1148
- }
1149
- }
1150
-
1151
1251
  ///////////////////////////////////////////////////////////////////////////////
1152
1252
  /**
1153
1253
  * Box2D Wheel Joint
@@ -1508,10 +1608,13 @@ class Box2dPlugin
1508
1608
  {
1509
1609
  ASSERT(!box2d, 'Box2D already initialized');
1510
1610
  box2d = this;
1611
+
1612
+ /** @property {Object} - The Box2d instance */
1511
1613
  this.instance = instance;
1614
+ /** @property {Object} - The Box2d world */
1512
1615
  this.world = new box2d.instance.b2World();
1616
+ /** @property {Array<Box2dObject>} - List of all Box2d objects */
1513
1617
  this.objects = [];
1514
-
1515
1618
  /** @property {number} - Velocity iterations per update*/
1516
1619
  this.velocityIterations = 8;
1517
1620
  /** @property {number} - Position iterations per update*/
@@ -1710,8 +1813,9 @@ class Box2dPlugin
1710
1813
  * @param {Color} [color]
1711
1814
  * @param {Color} [lineColor]
1712
1815
  * @param {number} [lineWidth]
1816
+ * @param {boolean} [useWebGL=glEnable]
1713
1817
  * @param {CanvasRenderingContext2D} [context] */
1714
- drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, context)
1818
+ drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, useWebgl, context)
1715
1819
  {
1716
1820
  const shape = box2d.castObjectType(fixture.GetShape());
1717
1821
  switch (shape.GetType())
@@ -1721,20 +1825,20 @@ class Box2dPlugin
1721
1825
  let points = [];
1722
1826
  for (let i=shape.GetVertexCount(); i--;)
1723
1827
  points.push(box2d.vec2From(shape.GetVertex(i)));
1724
- drawPoly(points, color, lineWidth, lineColor, pos, angle);
1828
+ drawPoly(points, color, lineWidth, lineColor, pos, angle, useWebgl, false, context);
1725
1829
  break;
1726
1830
  }
1727
1831
  case box2d.instance.b2Shape.e_circle:
1728
1832
  {
1729
1833
  const radius = shape.get_m_radius();
1730
- drawCircle(pos, radius*2, color, lineWidth, lineColor);
1834
+ drawCircle(pos, radius*2, color, lineWidth, lineColor, useWebgl, false, context);
1731
1835
  break;
1732
1836
  }
1733
1837
  case box2d.instance.b2Shape.e_edge:
1734
1838
  {
1735
1839
  const v1 = box2d.vec2From(shape.get_m_vertex1());
1736
1840
  const v2 = box2d.vec2From(shape.get_m_vertex2());
1737
- drawLine(v1, v2, lineWidth, lineColor, pos, angle);
1841
+ drawLine(v1, v2, lineWidth, lineColor, pos, angle, useWebgl, false, context);
1738
1842
  break;
1739
1843
  }
1740
1844
  }
@@ -1752,7 +1856,7 @@ class Box2dPlugin
1752
1856
  }
1753
1857
 
1754
1858
  /** converts a box2d vec2 pointer to a Vector2
1755
- * @param {Object} v */
1859
+ * @param {Object} vp */
1756
1860
  vec2FromPointer(vp)
1757
1861
  {
1758
1862
  const v = box2d.instance.wrapPointer(vp, box2d.instance.b2Vec2);
@@ -1864,7 +1968,7 @@ async function box2dInit()
1864
1968
  const box2dColorPointer = (c)=>
1865
1969
  box2dColor(box2d.instance.wrapPointer(c, box2d.instance.b2Color));
1866
1970
  const getDebugColor = (color)=>box2dColorPointer(color).scale(1,.8);
1867
- const getPointsList = (vertices, vertexCount) =>
1971
+ const getPointsList = (vertices, vertexCount)=>
1868
1972
  {
1869
1973
  const points = [];
1870
1974
  for (let i=vertexCount; i--;)
@@ -24,14 +24,16 @@ class PostProcessPlugin
24
24
  {
25
25
  /** Create global post processing shader
26
26
  * @param {string} shaderCode
27
- * @param {boolean} [includeMainCanvas]
28
- * @example
29
- * // create the post process plugin object
30
- * new PostProcessPlugin(shaderCode);
31
- */
32
- constructor(shaderCode, includeMainCanvas=true)
27
+ * @param {boolean} [includeMainCanvas] - combine mainCanvs onto glCanvas
28
+ * @param {boolean} [feedbackTexture] - use glCanvas from previous frame as the texture
29
+ * @example
30
+ * // create the post process plugin object
31
+ * new PostProcessPlugin(shaderCode);
32
+ */
33
+ constructor(shaderCode, includeMainCanvas=false, feedbackTexture=false)
33
34
  {
34
35
  ASSERT(!postProcess, 'Post process already initialized');
36
+ ASSERT(!(includeMainCanvas && feedbackTexture), 'Post process cannot both include main canvas and use feedback texture');
35
37
  postProcess = this;
36
38
 
37
39
  if (!shaderCode) // default shader pass through
@@ -39,9 +41,10 @@ class PostProcessPlugin
39
41
 
40
42
  /** @property {WebGLProgram} - Shader for post processing */
41
43
  this.shader = undefined;
42
-
43
44
  /** @property {WebGLTexture} - Texture for post processing */
44
45
  this.texture = undefined;
46
+ /** @property {WebGLVertexArrayObject} - Vertex array object */
47
+ this.vao = undefined;
45
48
 
46
49
  // setup the post processing plugin
47
50
  initPostProcess();
@@ -50,7 +53,6 @@ class PostProcessPlugin
50
53
  function initPostProcess()
51
54
  {
52
55
  if (headlessMode) return;
53
-
54
56
  if (!glEnable)
55
57
  {
56
58
  console.warn('PostProcessPlugin: WebGL not enabled!');
@@ -61,14 +63,14 @@ class PostProcessPlugin
61
63
  postProcess.texture = glCreateTexture();
62
64
  postProcess.shader = glCreateProgram(
63
65
  '#version 300 es\n' + // specify GLSL ES version
64
- 'precision highp float;'+ // use highp for better accuracy
66
+ 'precision highp float;'+ // use highp for accuracy
65
67
  'in vec2 p;'+ // position
66
68
  'void main(){'+ // shader entry point
67
69
  'gl_Position=vec4(p+p-1.,1,1);'+ // set position
68
70
  '}' // end of shader
69
71
  ,
70
72
  '#version 300 es\n' + // specify GLSL ES version
71
- 'precision highp float;'+ // use highp for better accuracy
73
+ 'precision highp float;'+ // use highp for accuracy
72
74
  'uniform sampler2D iChannel0;'+ // input texture
73
75
  'uniform vec3 iResolution;'+ // size of output texture
74
76
  'uniform float iTime;'+ // time
@@ -79,6 +81,17 @@ class PostProcessPlugin
79
81
  'c.a=1.;'+ // always use full alpha
80
82
  '}' // end of shader
81
83
  );
84
+
85
+ // setup VAO for post processing
86
+ postProcess.vao = glContext.createVertexArray();
87
+ glContext.bindVertexArray(postProcess.vao);
88
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
89
+
90
+ // configure vertex attributes
91
+ const vertexByteStride = 8;
92
+ const pLocation = glContext.getAttribLocation(postProcess.shader, 'p');
93
+ glContext.enableVertexAttribArray(pLocation);
94
+ glContext.vertexAttribPointer(pLocation, 2, glContext.FLOAT, false, vertexByteStride, 0);
82
95
  }
83
96
  function postProcessContextLost()
84
97
  {
@@ -93,14 +106,17 @@ class PostProcessPlugin
93
106
  }
94
107
  function postProcessRender()
95
108
  {
96
- if (headlessMode) return;
97
-
98
- if (!glEnable)
99
- return;
109
+ if (headlessMode || !glEnable) return;
100
110
 
101
111
  // clear out the buffer
102
112
  glFlush();
103
-
113
+
114
+ // setup shader program to draw a quad
115
+ glContext.useProgram(postProcess.shader);
116
+ glContext.bindVertexArray(postProcess.vao);
117
+ glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, true);
118
+ glContext.disable(glContext.BLEND);
119
+
104
120
  // setup texture
105
121
  glContext.activeTexture(glContext.TEXTURE0);
106
122
  glContext.bindTexture(glContext.TEXTURE_2D, postProcess.texture);
@@ -111,29 +127,32 @@ class PostProcessPlugin
111
127
  workCanvas.height = mainCanvasSize.y;
112
128
  glCopyToContext(workContext);
113
129
  workContext.drawImage(mainCanvas, 0, 0);
130
+ mainCanvas.width |= 0
114
131
 
115
132
  // copy work canvas to texture
116
133
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, workCanvas);
117
134
  }
118
-
119
- // setup shader program to draw a quad
120
- glContext.useProgram(postProcess.shader);
121
- glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
122
- glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, 1);
123
- glContext.disable(glContext.BLEND);
124
-
125
- // set vertex position attribute
126
- const vertexByteStride = 8;
127
- const pLocation = glContext.getAttribLocation(postProcess.shader, 'p');
128
- glContext.enableVertexAttribArray(pLocation);
129
- glContext.vertexAttribPointer(pLocation, 2, glContext.FLOAT, false, vertexByteStride, 0);
130
-
135
+ else if (!feedbackTexture)
136
+ {
137
+ // copy glCanvas to texture
138
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
139
+ }
140
+
131
141
  // set uniforms and draw
132
142
  const uniformLocation = (name)=>glContext.getUniformLocation(postProcess.shader, name);
133
143
  glContext.uniform1i(uniformLocation('iChannel0'), 0);
134
144
  glContext.uniform1f(uniformLocation('iTime'), time);
135
145
  glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
136
146
  glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, 4);
147
+
148
+ if (feedbackTexture)
149
+ {
150
+ // pass glCanvas back to overlay texture
151
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
152
+ }
153
+
154
+ // force it to set instanced mode
155
+ glSetInstancedMode(true);
137
156
  }
138
157
  }
139
158
  }