littlejsengine 1.16.1 → 1.17.1
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.
- package/dist/littlejs.d.ts +287 -240
- package/dist/littlejs.esm.js +1419 -1259
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1076 -910
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +977 -815
- package/examples/box2d/gameObjects.js +6 -6
- package/examples/breakout/game.js +5 -6
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +1 -1
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/tiles.png +0 -0
- package/examples/platformer/gameEffects.js +24 -23
- package/examples/platformer/gameLevel.js +24 -25
- package/examples/shorts/base.html +2 -1
- package/examples/shorts/clock.js +3 -3
- package/examples/shorts/fontImage.js +4 -3
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +1 -1
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/texture.js +10 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +2 -0
- package/examples/starter/index.html +3 -2
- package/examples/starter/tiles.png +0 -0
- package/examples/typescript/tiles.png +0 -0
- package/examples/uiSystem/game.js +1 -1
- package/examples/uiSystem/tiles.png +0 -0
- package/package.json +1 -1
- package/plugins/postProcess.js +47 -28
- package/plugins/uiSystem.js +16 -16
- package/reference.md +6 -6
- package/src/engine.js +186 -198
- package/src/engineAudio.js +6 -10
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +100 -98
- package/src/engineDraw.js +185 -148
- package/src/engineExport.js +327 -333
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +17 -26
- package/src/engineMath.js +1112 -0
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +27 -27
- package/src/engineParticles.js +2 -2
- package/src/engineRelease.js +1 -3
- package/src/engineSettings.js +2 -2
- package/src/engineTileLayer.js +200 -176
- package/src/engineUtilities.js +48 -1097
- package/src/engineWebGL.js +127 -79
|
@@ -76,7 +76,7 @@ export function spawnRandomEdges()
|
|
|
76
76
|
edgePoints.push(vec2(40,0));
|
|
77
77
|
for (let i=40, y=0; i--;)
|
|
78
78
|
edgePoints.push(vec2(i, y=LJS.clamp(y+LJS.rand(-2,2),0,5)));
|
|
79
|
-
edgePoints.push(vec2(
|
|
79
|
+
edgePoints.push(vec2());
|
|
80
80
|
const o = new LJS.Box2dStaticObject;
|
|
81
81
|
o.addEdgeList(edgePoints);
|
|
82
82
|
}
|
|
@@ -478,11 +478,11 @@ export function explosion(pos, radius=3, strength=300)
|
|
|
478
478
|
|
|
479
479
|
// fire
|
|
480
480
|
new LJS.ParticleEmitter(
|
|
481
|
-
pos, 0,
|
|
482
|
-
radius, .1, 100*radius, 3.14,
|
|
483
|
-
Game.spriteAtlas.dot,
|
|
484
|
-
hsl(0
|
|
485
|
-
hsl(0,1,.5,0), hsl(.1, 1,.5,0)
|
|
481
|
+
pos, 0, // pos, angle
|
|
482
|
+
radius, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
|
|
483
|
+
Game.spriteAtlas.dot, // tileInfo
|
|
484
|
+
hsl(0,.8,.5), hsl(.15,.8,.5), // colorStartA, colorStartB
|
|
485
|
+
hsl(0,1,.5,0), hsl(.1, 1,.5,0),// colorEndA, colorEndB
|
|
486
486
|
.7, 1, .5, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
487
487
|
.9, 1, 0, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
488
488
|
1, 0, 1, 0, 1e9 // randomness, collide, additive, colorLinear, renderOrder
|
|
@@ -103,13 +103,12 @@ function gameRender()
|
|
|
103
103
|
function gameRenderPost()
|
|
104
104
|
{
|
|
105
105
|
// use built in image font for text
|
|
106
|
-
const font =
|
|
107
|
-
|
|
108
|
-
font.drawText('Score: ' + score, LJS.cameraPos.add(vec2(0,9.7)), .15, true);
|
|
106
|
+
const font = LJS.engineFontImage;
|
|
107
|
+
font.drawText('Score: ' + score, LJS.cameraPos.add(vec2(0,9.2)), 1);
|
|
109
108
|
if (!brickCount)
|
|
110
|
-
font.drawText('You Win!', LJS.cameraPos.add(vec2(0,-5)),
|
|
109
|
+
font.drawText('You Win!', LJS.cameraPos.add(vec2(0,-5)), 2);
|
|
111
110
|
else if (!ball)
|
|
112
|
-
font.drawText('Click to Play', LJS.cameraPos.add(vec2(0,-5)),
|
|
111
|
+
font.drawText('Click to Play', LJS.cameraPos.add(vec2(0,-5)), 2);
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -138,7 +137,7 @@ function setupPostProcess()
|
|
|
138
137
|
|
|
139
138
|
// scan lines
|
|
140
139
|
const float scanlineScale = 2.;
|
|
141
|
-
const float scanlineAlpha = .
|
|
140
|
+
const float scanlineAlpha = .6;
|
|
142
141
|
c *= 1. - scanlineAlpha*cos(p.y*2.*iResolution.y/scanlineScale);
|
|
143
142
|
|
|
144
143
|
{
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.17.1></script>
|
|
11
11
|
|
|
12
12
|
<!-- Add your game scripts here -->
|
|
13
|
-
<script src=game.js?1.
|
|
13
|
+
<script src=game.js?1.17.1></script>
|
|
Binary file
|
|
Binary file
|
package/examples/index.html
CHANGED
|
@@ -113,7 +113,6 @@ const exampleList =
|
|
|
113
113
|
new ExampleInfo('Piano', 'piano.js', 'Interactive piano keyboard', false, 'music, sound, audio, notes, ui, instrument'),
|
|
114
114
|
new ExampleInfo('Step Sequencer', 'sequencer.js', 'Simple music loop creation tool', false, 'music, sound, audio, notes, ui, instrument'),
|
|
115
115
|
new ExampleInfo('Music Player', 'musicPlayer.js', 'Music player with audio seeking and drag and drop', false, 'sound, loading, audio, ui'),
|
|
116
|
-
new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
|
|
117
116
|
new ExampleInfo('--- MINI GAMES ---'),
|
|
118
117
|
new ExampleInfo('Pong Game', 'pongGame.js', 'Classic paddle ball bouncing', false, 'objects, collision'),
|
|
119
118
|
new ExampleInfo('Platformer Game', 'platformer.js', 'Jump and run side view', false, 'objects, gravity, level, tiles, camera'),
|
|
@@ -129,6 +128,7 @@ const exampleList =
|
|
|
129
128
|
new ExampleInfo('Box2d Demo', 'box2d.js', 'Box2D physics plugin', false, 'objects, mouse'),
|
|
130
129
|
new ExampleInfo('Box2d Car', 'box2dCar.js', 'Drivable car with Box2D physics', false, 'objects, vehicle, suspension, wheels'),
|
|
131
130
|
new ExampleInfo('Box2d Pool', 'box2dPool.js', 'Billiard table pool game with physics', false, 'objects, game'),
|
|
131
|
+
new ExampleInfo('WebGL Shader', 'shader.js', 'Full canvas webgl shader', false, 'webgl, visual, effect'),
|
|
132
132
|
new ExampleInfo('Post Processing', 'postProcess.js', 'Shader effects and filters', false, 'webgl, visual, effect'),
|
|
133
133
|
new ExampleInfo('UI System', 'uiSystem.js', 'Buttons, sliders, and checkboxes', false, 'objects, widgets, interactive'),
|
|
134
134
|
new ExampleInfo('Nine Slice', 'nineSlice.js', 'Scalable UI panels', false, 'three slice, stretch, corners, text, tiles'),
|
package/examples/logo.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -43,8 +43,6 @@ export const persistentParticleDestroyCallback = (particle)=>
|
|
|
43
43
|
if (particle.groundObject)
|
|
44
44
|
{
|
|
45
45
|
GameLevel.foregroundTileLayer.drawTile(particle.pos, particle.size, particle.tileInfo, particle.color, particle.angle, particle.mirror);
|
|
46
|
-
// update WebGL texture
|
|
47
|
-
GameLevel.foregroundTileLayer.useWebGL();
|
|
48
46
|
}
|
|
49
47
|
}
|
|
50
48
|
|
|
@@ -74,26 +72,27 @@ export function explosion(pos, radius=3)
|
|
|
74
72
|
|
|
75
73
|
sound_explosion.play(pos);
|
|
76
74
|
|
|
77
|
-
// destroy level
|
|
78
|
-
for (let x = -radius; x < radius; ++x)
|
|
79
75
|
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
76
|
+
// destroy level
|
|
77
|
+
const layer = GameLevel.tileLayers[1];
|
|
78
|
+
layer.redrawStart();
|
|
79
|
+
for (let x = -radius; x < radius; ++x)
|
|
80
|
+
{
|
|
81
|
+
const h = (radius*radius - x*x)**.5;
|
|
82
|
+
for (let y = -h; y <= h; ++y)
|
|
83
|
+
destroyTile(pos.add(vec2(x,y)), 0, 0);
|
|
84
|
+
}
|
|
85
|
+
// cleanup neighbors
|
|
86
|
+
const cleanupRadius = radius + 2;
|
|
87
|
+
for (let x = -cleanupRadius; x < cleanupRadius; ++x)
|
|
88
|
+
{
|
|
89
|
+
const h = (cleanupRadius**2 - x**2)**.5;
|
|
90
|
+
for (let y = -h; y < h; ++y)
|
|
91
|
+
GameLevel.decorateTile(pos.add(vec2(x,y)).floor(), layer);
|
|
92
|
+
}
|
|
93
|
+
layer.redrawEnd();
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
// update WebGL texture
|
|
95
|
-
GameLevel.foregroundTileLayer.useWebGL();
|
|
96
|
-
|
|
97
96
|
// kill/push objects
|
|
98
97
|
LJS.engineObjectsCallback(pos, radius*3, (o)=>
|
|
99
98
|
{
|
|
@@ -128,7 +127,7 @@ export function explosion(pos, radius=3)
|
|
|
128
127
|
pos, 0, // pos, angle
|
|
129
128
|
radius/2, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
|
|
130
129
|
0, // tileInfo
|
|
131
|
-
rgb(1,.5,.1),
|
|
130
|
+
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
132
131
|
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
133
132
|
.7, .8, .2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
134
133
|
.9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
@@ -165,10 +164,12 @@ export function destroyTile(pos, makeSound = 1, cleanup = 1)
|
|
|
165
164
|
// cleanup neighbors and rebuild WebGL
|
|
166
165
|
if (cleanup)
|
|
167
166
|
{
|
|
167
|
+
const layer = GameLevel.tileLayers[1];
|
|
168
|
+
layer.redrawStart();
|
|
168
169
|
for (let i=-1;i<=1;++i)
|
|
169
170
|
for (let j=-1;j<=1;++j)
|
|
170
|
-
GameLevel.decorateTile(pos.add(vec2(i,j)));
|
|
171
|
-
layer.
|
|
171
|
+
GameLevel.decorateTile(pos.add(vec2(i,j)), layer);
|
|
172
|
+
layer.redrawEnd();
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
return true;
|
|
@@ -260,7 +261,7 @@ export class ParallaxLayer extends LJS.CanvasLayer
|
|
|
260
261
|
this.context.clearRect(0,0,1,h);
|
|
261
262
|
|
|
262
263
|
// make WebGL texture
|
|
263
|
-
this.
|
|
264
|
+
this.updateWebGL();
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
render()
|
|
@@ -126,28 +126,25 @@ function loadLevelData()
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
+
|
|
130
|
+
tileLayer.onRedraw = ()=>
|
|
131
|
+
{
|
|
132
|
+
// apply decoration to level tiles
|
|
133
|
+
for (let x=levelSize.x; x--;)
|
|
134
|
+
for (let y=levelSize.y; y--;)
|
|
135
|
+
decorateTile(vec2(x,y), tileLayer);
|
|
136
|
+
}
|
|
129
137
|
tileLayer.redraw();
|
|
130
138
|
}
|
|
131
|
-
|
|
132
|
-
// apply decoration to all level tiles
|
|
133
|
-
const pos = vec2();
|
|
134
|
-
const layerCount = tileMapData.layers.length;
|
|
135
|
-
for (let layer=layerCount; layer--;)
|
|
136
|
-
{
|
|
137
|
-
for (pos.x=levelSize.x; pos.x--;)
|
|
138
|
-
for (pos.y=levelSize.y; pos.y--;)
|
|
139
|
-
decorateTile(pos, layer);
|
|
140
|
-
tileLayers[layer].useWebGL();
|
|
141
|
-
}
|
|
142
139
|
}
|
|
143
140
|
|
|
144
|
-
export function decorateTile(pos,
|
|
141
|
+
export function decorateTile(pos, tileLayer)
|
|
145
142
|
{
|
|
146
143
|
LJS.ASSERT((pos.x|0) == pos.x && (pos.y|0)== pos.y);
|
|
147
|
-
const tileLayer = tileLayers[layer];
|
|
148
144
|
if (!tileLayer)
|
|
149
145
|
return;
|
|
150
146
|
|
|
147
|
+
const w = tileLayer.tileInfo.size.x;
|
|
151
148
|
if (tileLayer == foregroundTileLayer)
|
|
152
149
|
{
|
|
153
150
|
const tileType = tileLayer.getCollisionData(pos);
|
|
@@ -167,12 +164,11 @@ export function decorateTile(pos, layer=1)
|
|
|
167
164
|
|
|
168
165
|
// make pixel perfect outlines
|
|
169
166
|
const size = i&1 ? vec2(2, 16) : vec2(16, 2);
|
|
170
|
-
tileLayer.context.fillStyle = levelOutlineColor.mutate(.1);
|
|
171
167
|
const drawPos = pos.scale(16)
|
|
172
168
|
.add(vec2(i==1?14:0,(i==0?14:0)))
|
|
173
169
|
.subtract((i&1? vec2(0,8-size.y/2) : vec2(8-size.x/2,0)));
|
|
174
|
-
|
|
175
|
-
|
|
170
|
+
const color = levelOutlineColor.mutate(.1);
|
|
171
|
+
tileLayer.drawLayerRect(drawPos, size, color);
|
|
176
172
|
}
|
|
177
173
|
}
|
|
178
174
|
else
|
|
@@ -185,15 +181,18 @@ export function decorateTile(pos, layer=1)
|
|
|
185
181
|
const neighborTileDataB = tileLayer.getData(pos.add(vec2().setDirection((i+1)%4))).tile;
|
|
186
182
|
if (neighborTileDataA > 0 || neighborTileDataB > 0)
|
|
187
183
|
continue;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
184
|
+
|
|
185
|
+
// get direction of corner
|
|
186
|
+
const directionVector = vec2();
|
|
187
|
+
if (i==0) directionVector.set(w-1,w-1);
|
|
188
|
+
if (i==1) directionVector.set(w-1,1);
|
|
189
|
+
if (i==2) directionVector.set(1,1);
|
|
190
|
+
if (i==3) directionVector.set(1,w-1);
|
|
191
|
+
|
|
192
|
+
// clear rect from corner
|
|
193
|
+
const s = vec2(2);
|
|
194
|
+
const drawPos = pos.scale(w).add(directionVector).subtract(s.scale(.5));
|
|
195
|
+
tileLayer.clearLayerRect(drawPos, s);
|
|
197
196
|
}
|
|
198
197
|
}
|
|
199
198
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<!DOCTYPE html><meta charset=utf-8><body>
|
|
2
|
-
<script src=../../dist/littlejs.js?1.
|
|
2
|
+
<script src=../../dist/littlejs.js?1.17.1></script>
|
|
3
3
|
<script src=../../dist/box2d.wasm.js></script>
|
|
4
4
|
|
|
5
5
|
<!-- LittleJS Engine Source
|
|
6
6
|
<script src=../../src/engine.js></script>
|
|
7
7
|
<script src=../../src/engineDebug.js></script>
|
|
8
|
+
<script src=../../src/engineMath.js></script>
|
|
8
9
|
<script src=../../src/engineUtilities.js></script>
|
|
9
10
|
<script src=../../src/engineSettings.js></script>
|
|
10
11
|
<script src=../../src/engineObject.js></script>
|
package/examples/shorts/clock.js
CHANGED
|
@@ -15,7 +15,7 @@ function gameRender()
|
|
|
15
15
|
const h = (d.slice(0,2)|0) + m/60;
|
|
16
16
|
|
|
17
17
|
// draw clock hands
|
|
18
|
-
drawLine(vec2(
|
|
19
|
-
drawLine(vec2(
|
|
20
|
-
drawLine(vec2(
|
|
18
|
+
drawLine(vec2(), vec2(0,4).rotate(h/12*2*PI), 1);
|
|
19
|
+
drawLine(vec2(), vec2(0,6).rotate(m/60*2*PI), .4);
|
|
20
|
+
drawLine(vec2(), vec2(0,8).rotate(s/60*2*PI), .1);
|
|
21
21
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
function gameRender()
|
|
2
2
|
{
|
|
3
3
|
// draw text with built in engine font image
|
|
4
|
-
const font =
|
|
5
|
-
font.drawText('Engine Font
|
|
4
|
+
const font = engineFontImage
|
|
5
|
+
font.drawText('Engine Font', vec2(0,3), 2);
|
|
6
6
|
|
|
7
7
|
// show every character in the font
|
|
8
8
|
let s = '';
|
|
@@ -12,5 +12,6 @@ function gameRender()
|
|
|
12
12
|
s += '\n';
|
|
13
13
|
s += String.fromCharCode(i);
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
font.drawText(s, vec2());
|
|
16
17
|
}
|
|
@@ -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(
|
|
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(
|
|
5
|
-
let size = vec2(15);
|
|
6
|
-
let color = hsl(0,0,1);
|
|
7
|
-
let tilePos = vec2(
|
|
8
|
-
let tileSize = vec2(256);
|
|
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
|
-
|
|
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
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.17.1></script>
|
|
11
11
|
|
|
12
12
|
<!-- LittleJS Engine Source
|
|
13
13
|
<script src=../../src/engine.js></script>
|
|
14
14
|
<script src=../../src/engineDebug.js></script>
|
|
15
|
+
<script src=../../src/engineMath.js></script>
|
|
15
16
|
<script src=../../src/engineUtilities.js></script>
|
|
16
17
|
<script src=../../src/engineSettings.js></script>
|
|
17
18
|
<script src=../../src/engineObject.js></script>
|
|
@@ -31,4 +32,4 @@
|
|
|
31
32
|
-->
|
|
32
33
|
|
|
33
34
|
<!-- Add your game scripts here -->
|
|
34
|
-
<script src=game.js?1.
|
|
35
|
+
<script src=game.js?1.17.1></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(
|
|
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
package/plugins/postProcess.js
CHANGED
|
@@ -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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
}
|