littlejsengine 1.4.0 → 1.4.6
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/build.bat +1 -1
- package/buildSetup.bat +2 -2
- package/engine/engine.all.js +244 -161
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.module.js +4812 -0
- package/engine/engine.all.release.js +228 -138
- package/engine/engine.all.release.module.js +4457 -0
- package/engine/engine.js +12 -8
- package/engine/engineBuild.bat +21 -2
- package/engine/engineDebug.js +16 -23
- package/engine/engineDraw.js +13 -13
- package/engine/engineExport.js +333 -0
- package/engine/engineInput.js +8 -7
- package/engine/engineMedals.js +10 -6
- package/engine/engineObject.js +4 -4
- package/engine/engineParticles.js +45 -21
- package/engine/engineTileLayer.js +1 -1
- package/engine/engineUtilities.js +21 -25
- package/engine/engineWebGL.js +114 -54
- package/engine/index.d.ts +41 -30
- package/examples/breakout/game.js +63 -11
- package/examples/breakout/gameObjects.js +14 -12
- package/examples/breakout/index.html +3 -3
- package/examples/empty/game.js +35 -0
- package/examples/empty/index.html +9 -0
- package/examples/empty/tiles.png +0 -0
- package/examples/module/game.js +122 -0
- package/examples/module/index.html +9 -0
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +14 -14
- package/examples/particles/tiles.png +0 -0
- package/examples/platformer/gameObjects.js +5 -5
- package/examples/platformer/gamePlayer.js +7 -5
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/index.html +2 -2
- package/examples/stress/index.html +2 -2
- package/game.js +9 -11
- package/index.html +13 -13
- package/package.json +35 -25
- package/README.md +0 -54
|
@@ -54,6 +54,7 @@ class ParticleEmitter extends EngineObject
|
|
|
54
54
|
* @param {Boolean} [additive=0] - Should particles use addtive blend
|
|
55
55
|
* @param {Boolean} [randomColorLinear=1] - Should color be randomized linearly or across each component
|
|
56
56
|
* @param {Number} [renderOrder=0] - Render order for particles (additive is above other stuff by default)
|
|
57
|
+
* @param {Boolean} [localSpace=0] - Should it be in local space of emitter (world space is default)
|
|
57
58
|
*/
|
|
58
59
|
constructor
|
|
59
60
|
(
|
|
@@ -83,7 +84,8 @@ class ParticleEmitter extends EngineObject
|
|
|
83
84
|
collideTiles,
|
|
84
85
|
additive,
|
|
85
86
|
randomColorLinear = 1,
|
|
86
|
-
renderOrder = additive ? 1e9 : 0
|
|
87
|
+
renderOrder = additive ? 1e9 : 0,
|
|
88
|
+
localSpace
|
|
87
89
|
)
|
|
88
90
|
{
|
|
89
91
|
super(pos, new Vector2, tileIndex, tileSize, angle, undefined, renderOrder);
|
|
@@ -137,6 +139,8 @@ class ParticleEmitter extends EngineObject
|
|
|
137
139
|
this.collideTiles = collideTiles;
|
|
138
140
|
/** @property {Number} - Should particles use addtive blend */
|
|
139
141
|
this.additive = additive;
|
|
142
|
+
/** @property {Boolean} - Should it be in local space of emitter */
|
|
143
|
+
this.localSpace = localSpace;
|
|
140
144
|
/** @property {Number} - If set the partile is drawn as a trail, stretched in the drection of velocity */
|
|
141
145
|
this.trailScale = 0;
|
|
142
146
|
|
|
@@ -172,30 +176,38 @@ class ParticleEmitter extends EngineObject
|
|
|
172
176
|
emitParticle()
|
|
173
177
|
{
|
|
174
178
|
// spawn a particle
|
|
175
|
-
|
|
176
|
-
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
|
|
180
|
+
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
181
|
+
.multiply(this.emitSize).rotate(this.angle) // box emitter
|
|
182
|
+
: randInCircle(this.emitSize * .5); // circle emitter
|
|
183
|
+
let angle = rand(this.particleConeAngle, -this.particleConeAngle);
|
|
184
|
+
if (!this.localSpace)
|
|
185
|
+
{
|
|
186
|
+
pos = this.pos.add(pos);
|
|
187
|
+
angle += this.angle;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const particle = new Particle(pos, this.tileIndex, this.tileSize, angle);
|
|
180
191
|
|
|
181
192
|
// randomness scales each paremeter by a percentage
|
|
182
193
|
const randomness = this.randomness;
|
|
183
194
|
const randomizeScale = (v)=> v + v*rand(randomness, -randomness);
|
|
184
195
|
|
|
185
196
|
// randomize particle settings
|
|
186
|
-
const particleTime
|
|
187
|
-
const sizeStart
|
|
188
|
-
const sizeEnd
|
|
189
|
-
const speed
|
|
190
|
-
const angleSpeed
|
|
191
|
-
const coneAngle
|
|
192
|
-
const colorStart
|
|
193
|
-
const colorEnd
|
|
197
|
+
const particleTime = randomizeScale(this.particleTime);
|
|
198
|
+
const sizeStart = randomizeScale(this.sizeStart);
|
|
199
|
+
const sizeEnd = randomizeScale(this.sizeEnd);
|
|
200
|
+
const speed = randomizeScale(this.speed);
|
|
201
|
+
const angleSpeed = randomizeScale(this.angleSpeed) * randSign();
|
|
202
|
+
const coneAngle = rand(this.emitConeAngle, -this.emitConeAngle);
|
|
203
|
+
const colorStart = randColor(this.colorStartA, this.colorStartB, this.randomColorLinear);
|
|
204
|
+
const colorEnd = randColor(this.colorEndA, this.colorEndB, this.randomColorLinear);
|
|
205
|
+
const velocityAngle = this.localSpace ? coneAngle : this.angle + coneAngle;
|
|
194
206
|
|
|
195
207
|
// build particle settings
|
|
196
208
|
particle.colorStart = colorStart;
|
|
197
209
|
particle.colorEndDelta = colorEnd.subtract(colorStart);
|
|
198
|
-
particle.velocity = (new Vector2).setAngle(
|
|
210
|
+
particle.velocity = (new Vector2).setAngle(velocityAngle, speed);
|
|
199
211
|
particle.angleVelocity = angleSpeed;
|
|
200
212
|
particle.lifeTime = particleTime;
|
|
201
213
|
particle.sizeStart = sizeStart;
|
|
@@ -211,6 +223,7 @@ class ParticleEmitter extends EngineObject
|
|
|
211
223
|
particle.renderOrder = this.renderOrder;
|
|
212
224
|
particle.trailScale = this.trailScale;
|
|
213
225
|
particle.mirror = rand()<.5;
|
|
226
|
+
particle.localSpaceEmitter = this.localSpace && this;
|
|
214
227
|
|
|
215
228
|
// setup callbacks for particles
|
|
216
229
|
particle.destroyCallback = this.particleDestroyCallback;
|
|
@@ -257,20 +270,31 @@ class Particle extends EngineObject
|
|
|
257
270
|
|
|
258
271
|
// draw the particle
|
|
259
272
|
this.additive && setBlendMode(1);
|
|
273
|
+
|
|
274
|
+
let pos = this.pos, angle = this.angle;
|
|
275
|
+
if (this.localSpaceEmitter)
|
|
276
|
+
{
|
|
277
|
+
// in local space of emitter
|
|
278
|
+
pos = this.localSpaceEmitter.pos.add(pos.rotate(-this.localSpaceEmitter.angle));
|
|
279
|
+
angle += this.localSpaceEmitter.angle;
|
|
280
|
+
}
|
|
260
281
|
if (this.trailScale)
|
|
261
282
|
{
|
|
262
283
|
// trail style particles
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
let velocity = this.velocity;
|
|
285
|
+
if (this.localSpaceEmitter)
|
|
286
|
+
velocity = velocity.rotate(-this.localSpaceEmitter.angle);
|
|
287
|
+
const speed = velocity.length();
|
|
288
|
+
const direction = velocity.scale(1/speed);
|
|
265
289
|
const trailLength = speed * this.trailScale;
|
|
266
290
|
size.y = max(size.x, trailLength);
|
|
267
|
-
|
|
268
|
-
drawTile(
|
|
291
|
+
angle = direction.angle();
|
|
292
|
+
drawTile(pos.add(direction.multiply(vec2(0,-trailLength/2))), size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
269
293
|
}
|
|
270
294
|
else
|
|
271
|
-
drawTile(
|
|
295
|
+
drawTile(pos, size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
272
296
|
this.additive && setBlendMode();
|
|
273
|
-
debugParticles && debugRect(
|
|
297
|
+
debugParticles && debugRect(pos, size, '#f005', 0, angle);
|
|
274
298
|
|
|
275
299
|
if (p == 1)
|
|
276
300
|
{
|
|
@@ -254,7 +254,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
254
254
|
redrawEnd()
|
|
255
255
|
{
|
|
256
256
|
ASSERT(mainContext == this.context); // must call redrawStart() before drawing tiles
|
|
257
|
-
glCopyToContext(mainContext, 1);
|
|
257
|
+
glEnable && glCopyToContext(mainContext, 1);
|
|
258
258
|
//debugSaveCanvas(this.canvas);
|
|
259
259
|
|
|
260
260
|
// set stuff back to normal
|
|
@@ -435,10 +435,10 @@ class Color
|
|
|
435
435
|
* @return {Array} */
|
|
436
436
|
getHSLA()
|
|
437
437
|
{
|
|
438
|
-
const r = this.r;
|
|
439
|
-
const g = this.g;
|
|
440
|
-
const b = this.b;
|
|
441
|
-
const a = this.a;
|
|
438
|
+
const r = clamp(this.r);
|
|
439
|
+
const g = clamp(this.g);
|
|
440
|
+
const b = clamp(this.b);
|
|
441
|
+
const a = clamp(this.a);
|
|
442
442
|
const max = Math.max(r, g, b);
|
|
443
443
|
const min = Math.min(r, g, b);
|
|
444
444
|
const l = (max + min) / 2;
|
|
@@ -474,20 +474,13 @@ class Color
|
|
|
474
474
|
).clamp();
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
/** Returns this color expressed as
|
|
477
|
+
/** Returns this color expressed as a hex color code
|
|
478
|
+
* @param {Boolean} [useAlpha=1] - if alpha should be included in result
|
|
478
479
|
* @return {String} */
|
|
479
|
-
toString()
|
|
480
|
+
toString(useAlpha = 1)
|
|
480
481
|
{
|
|
481
|
-
|
|
482
|
-
return
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
/** Returns this color expressed as 32 bit integer RGBA value
|
|
486
|
-
* @return {Number} */
|
|
487
|
-
rgbaInt()
|
|
488
|
-
{
|
|
489
|
-
ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
|
|
490
|
-
return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
|
|
482
|
+
const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
|
|
483
|
+
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
491
484
|
}
|
|
492
485
|
|
|
493
486
|
/** Set this color from a hex code
|
|
@@ -495,21 +488,24 @@ class Color
|
|
|
495
488
|
* @return {Color} */
|
|
496
489
|
setHex(hex)
|
|
497
490
|
{
|
|
498
|
-
const fromHex = (
|
|
491
|
+
const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
|
|
499
492
|
this.r = fromHex(1);
|
|
500
493
|
this.g = fromHex(3),
|
|
501
494
|
this.b = fromHex(5);
|
|
502
|
-
this.a = 1;
|
|
503
|
-
ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
|
|
495
|
+
this.a = hex.length > 7 ? fromHex(7) : 1;
|
|
504
496
|
return this;
|
|
505
497
|
}
|
|
506
|
-
|
|
507
|
-
/** Returns this color expressed as
|
|
508
|
-
* @return {
|
|
509
|
-
|
|
498
|
+
|
|
499
|
+
/** Returns this color expressed as 32 bit RGBA value
|
|
500
|
+
* @return {Number} */
|
|
501
|
+
rgbaInt()
|
|
510
502
|
{
|
|
511
|
-
const
|
|
512
|
-
|
|
503
|
+
const toByte = (c)=> clamp(c)*255|0;
|
|
504
|
+
const r = toByte(this.r);
|
|
505
|
+
const g = toByte(this.g)<<8;
|
|
506
|
+
const b = toByte(this.b)<<16;
|
|
507
|
+
const a = toByte(this.a)<<24;
|
|
508
|
+
return r + g + b + a;
|
|
513
509
|
}
|
|
514
510
|
}
|
|
515
511
|
|
package/engine/engineWebGL.js
CHANGED
|
@@ -27,15 +27,13 @@ let glContext;
|
|
|
27
27
|
let glTileTexture;
|
|
28
28
|
|
|
29
29
|
// WebGL internal variables not exposed to documentation
|
|
30
|
-
let glActiveTexture, glShader, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
30
|
+
let glActiveTexture, glShader, glArrayBuffer, glVertexData, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
31
31
|
|
|
32
32
|
///////////////////////////////////////////////////////////////////////////////
|
|
33
33
|
|
|
34
34
|
// Init WebGL, called automatically by the engine
|
|
35
35
|
function glInit()
|
|
36
36
|
{
|
|
37
|
-
if (!glEnable) return;
|
|
38
|
-
|
|
39
37
|
// create the canvas and tile texture
|
|
40
38
|
glCanvas = document.createElement('canvas');
|
|
41
39
|
glContext = glCanvas.getContext('webgl', {antialias: false});
|
|
@@ -68,24 +66,11 @@ function glInit()
|
|
|
68
66
|
);
|
|
69
67
|
|
|
70
68
|
// init buffers
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
glVertexData = new ArrayBuffer(gl_MAX_BATCH * gl_VERTICES_PER_QUAD * gl_VERTEX_BYTE_STRIDE);
|
|
70
|
+
glArrayBuffer = glContext.createBuffer();
|
|
73
71
|
glPositionData = new Float32Array(glVertexData);
|
|
74
72
|
glColorData = new Uint32Array(glVertexData);
|
|
75
|
-
|
|
76
|
-
// setup the vertex data array
|
|
77
|
-
let offset = glBatchCount = 0;
|
|
78
|
-
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
79
|
-
{
|
|
80
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
81
|
-
glContext.enableVertexAttribArray(location);
|
|
82
|
-
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
83
|
-
offset += size*typeSize;
|
|
84
|
-
}
|
|
85
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
86
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
87
|
-
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
88
|
-
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
73
|
+
glBatchCount = 0;
|
|
89
74
|
}
|
|
90
75
|
|
|
91
76
|
/** Set the WebGl blend mode, normally you should call setBlendMode instead
|
|
@@ -93,8 +78,6 @@ function glInit()
|
|
|
93
78
|
* @memberof WebGL */
|
|
94
79
|
function glSetBlendMode(additive)
|
|
95
80
|
{
|
|
96
|
-
if (!glEnable) return;
|
|
97
|
-
|
|
98
81
|
// setup blending
|
|
99
82
|
glAdditive = additive;
|
|
100
83
|
}
|
|
@@ -105,8 +88,6 @@ function glSetBlendMode(additive)
|
|
|
105
88
|
* @memberof WebGL */
|
|
106
89
|
function glSetTexture(texture=glTileTexture)
|
|
107
90
|
{
|
|
108
|
-
if (!glEnable) return;
|
|
109
|
-
|
|
110
91
|
// must flush cache with the old texture to set a new one
|
|
111
92
|
if (texture != glActiveTexture)
|
|
112
93
|
glFlush();
|
|
@@ -121,8 +102,6 @@ function glSetTexture(texture=glTileTexture)
|
|
|
121
102
|
* @memberof WebGL */
|
|
122
103
|
function glCompileShader(source, type)
|
|
123
104
|
{
|
|
124
|
-
if (!glEnable) return;
|
|
125
|
-
|
|
126
105
|
// build the shader
|
|
127
106
|
const shader = glContext.createShader(type);
|
|
128
107
|
glContext.shaderSource(shader, source);
|
|
@@ -141,8 +120,6 @@ function glCompileShader(source, type)
|
|
|
141
120
|
* @memberof WebGL */
|
|
142
121
|
function glCreateProgram(vsSource, fsSource)
|
|
143
122
|
{
|
|
144
|
-
if (!glEnable) return;
|
|
145
|
-
|
|
146
123
|
// build the program
|
|
147
124
|
const program = glContext.createProgram();
|
|
148
125
|
glContext.attachShader(program, glCompileShader(vsSource, gl_VERTEX_SHADER));
|
|
@@ -155,35 +132,16 @@ function glCreateProgram(vsSource, fsSource)
|
|
|
155
132
|
return program;
|
|
156
133
|
}
|
|
157
134
|
|
|
158
|
-
/** Create WebGL buffer
|
|
159
|
-
* @param bufferType
|
|
160
|
-
* @param size
|
|
161
|
-
* @param usage
|
|
162
|
-
* @return {WebGLBuffer}
|
|
163
|
-
* @memberof WebGL */
|
|
164
|
-
function glCreateBuffer(bufferType, size, usage)
|
|
165
|
-
{
|
|
166
|
-
if (!glEnable) return;
|
|
167
|
-
|
|
168
|
-
// build the buffer
|
|
169
|
-
const buffer = glContext.createBuffer();
|
|
170
|
-
glContext.bindBuffer(bufferType, buffer);
|
|
171
|
-
glContext.bufferData(bufferType, size, usage);
|
|
172
|
-
return buffer;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
135
|
/** Create WebGL texture from an image and set the texture settings
|
|
176
136
|
* @param {Image} image
|
|
177
137
|
* @return {WebGLTexture}
|
|
178
138
|
* @memberof WebGL */
|
|
179
139
|
function glCreateTexture(image)
|
|
180
140
|
{
|
|
181
|
-
if (!glEnable || !image || !image.width) return;
|
|
182
|
-
|
|
183
141
|
// build the texture
|
|
184
142
|
const texture = glContext.createTexture();
|
|
185
143
|
glContext.bindTexture(gl_TEXTURE_2D, texture);
|
|
186
|
-
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
144
|
+
image && image.width && glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
187
145
|
|
|
188
146
|
// use point filtering for pixelated rendering
|
|
189
147
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, cavasPixelated ? gl_NEAREST : gl_LINEAR);
|
|
@@ -196,16 +154,31 @@ function glCreateTexture(image)
|
|
|
196
154
|
// called automatically by engine before render
|
|
197
155
|
function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
198
156
|
{
|
|
199
|
-
if (!glEnable) return;
|
|
200
|
-
|
|
201
157
|
// clear and set to same size as main canvas
|
|
202
158
|
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height);
|
|
203
159
|
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
204
160
|
|
|
205
161
|
// set up the shader
|
|
206
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
207
162
|
glContext.useProgram(glShader);
|
|
163
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
164
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
165
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
166
|
+
glContext.bufferData(gl_ARRAY_BUFFER, glVertexData.byteLength, gl_DYNAMIC_DRAW);
|
|
208
167
|
glSetBlendMode();
|
|
168
|
+
|
|
169
|
+
// set vertex attributes
|
|
170
|
+
let offset = 0;
|
|
171
|
+
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
172
|
+
{
|
|
173
|
+
const location = glContext.getAttribLocation(glShader, name);
|
|
174
|
+
glContext.enableVertexAttribArray(location);
|
|
175
|
+
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
176
|
+
offset += size*typeSize;
|
|
177
|
+
}
|
|
178
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
179
|
+
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
180
|
+
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
181
|
+
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
209
182
|
|
|
210
183
|
// build the transform matrix
|
|
211
184
|
const sx = 2 * cameraScale / width;
|
|
@@ -224,7 +197,7 @@ function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
|
224
197
|
* @memberof WebGL */
|
|
225
198
|
function glFlush()
|
|
226
199
|
{
|
|
227
|
-
if (!
|
|
200
|
+
if (!glBatchCount) return;
|
|
228
201
|
|
|
229
202
|
const destBlend = glBatchAdditive ? gl_ONE : gl_ONE_MINUS_SRC_ALPHA;
|
|
230
203
|
glContext.blendFuncSeparate(gl_SRC_ALPHA, destBlend, gl_ONE, destBlend);
|
|
@@ -244,7 +217,7 @@ function glFlush()
|
|
|
244
217
|
* @memberof WebGL */
|
|
245
218
|
function glCopyToContext(context, forceDraw)
|
|
246
219
|
{
|
|
247
|
-
if (!
|
|
220
|
+
if (!glBatchCount && !forceDraw) return;
|
|
248
221
|
|
|
249
222
|
glFlush();
|
|
250
223
|
|
|
@@ -268,8 +241,6 @@ function glCopyToContext(context, forceDraw)
|
|
|
268
241
|
* @memberof WebGL */
|
|
269
242
|
function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffffff, rgbaAdditive=0)
|
|
270
243
|
{
|
|
271
|
-
if (!glEnable) return;
|
|
272
|
-
|
|
273
244
|
// flush if there is no room for more verts or if different blend mode
|
|
274
245
|
if (glBatchCount == gl_MAX_BATCH || glBatchAdditive != glAdditive)
|
|
275
246
|
glFlush();
|
|
@@ -318,6 +289,90 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffff
|
|
|
318
289
|
glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
|
|
319
290
|
}
|
|
320
291
|
|
|
292
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
293
|
+
// post processing - can be enabled to pass other canvases through a final shader
|
|
294
|
+
|
|
295
|
+
let glPostShader, glPostArrayBuffer, glPostTexture;
|
|
296
|
+
|
|
297
|
+
/** Set up a post processing shader
|
|
298
|
+
* @param {String} shaderCode
|
|
299
|
+
* @memberof WebGL */
|
|
300
|
+
function glInitPostProcess(shaderCode)
|
|
301
|
+
{
|
|
302
|
+
ASSERT(!glPostShader); // can only have 1 post effects shader
|
|
303
|
+
|
|
304
|
+
if (!shaderCode) // default shader
|
|
305
|
+
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}';
|
|
306
|
+
|
|
307
|
+
// create the shader
|
|
308
|
+
glPostShader = glCreateProgram(
|
|
309
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
310
|
+
'attribute vec2 p;'+ // position
|
|
311
|
+
'void main(){'+ // shader entry point
|
|
312
|
+
'gl_Position=vec4(p,1,1);'+ // set position
|
|
313
|
+
'}' // end of shader
|
|
314
|
+
,
|
|
315
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
316
|
+
'uniform sampler2D iChannel0;'+ // input texture
|
|
317
|
+
'uniform vec3 iResolution;'+ // size of output texture
|
|
318
|
+
'uniform float iTime;'+ // time passed
|
|
319
|
+
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
320
|
+
'void main(){'+ // shader entry point
|
|
321
|
+
'mainImage(gl_FragColor,gl_FragCoord.xy);'+ // call post process function
|
|
322
|
+
'gl_FragColor.a=1.;'+ // always use full alpha
|
|
323
|
+
'}' // end of shader
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
// create buffer and texture
|
|
327
|
+
glPostArrayBuffer = glContext.createBuffer();
|
|
328
|
+
glPostTexture = glCreateTexture();
|
|
329
|
+
|
|
330
|
+
// hide the original 2d canvas
|
|
331
|
+
mainCanvas.style.visibility = 'hidden';
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Render the post processing shader, called automatically by the engine
|
|
335
|
+
function glRenderPostProcess()
|
|
336
|
+
{
|
|
337
|
+
if (!glPostShader)
|
|
338
|
+
return;
|
|
339
|
+
|
|
340
|
+
// prepare to render post process shader
|
|
341
|
+
const width = mainCanvas.width, height = mainCanvas.height;
|
|
342
|
+
if (glEnable)
|
|
343
|
+
{
|
|
344
|
+
glFlush(); // clear out the buffer
|
|
345
|
+
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
346
|
+
}
|
|
347
|
+
else
|
|
348
|
+
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height); // set viewport
|
|
349
|
+
|
|
350
|
+
// setup shader program to draw one triangle
|
|
351
|
+
glContext.useProgram(glPostShader);
|
|
352
|
+
glContext.disable(gl_BLEND);
|
|
353
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glPostArrayBuffer);
|
|
354
|
+
glContext.bufferData(gl_ARRAY_BUFFER, new Float32Array([-3,1,1,-3,1,1]), gl_STATIC_DRAW);
|
|
355
|
+
glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL, true);
|
|
356
|
+
|
|
357
|
+
// set textures, pass in the 2d canvas and gl canvas in separate texture channels
|
|
358
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
359
|
+
glContext.bindTexture(gl_TEXTURE_2D, glPostTexture);
|
|
360
|
+
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, mainCanvas);
|
|
361
|
+
|
|
362
|
+
// set vertex position attribute
|
|
363
|
+
const vertexByteStride = 8;
|
|
364
|
+
const pLocation = glContext.getAttribLocation(glPostShader, 'p');
|
|
365
|
+
glContext.enableVertexAttribArray(pLocation);
|
|
366
|
+
glContext.vertexAttribPointer(pLocation, 2, gl_FLOAT, 0, vertexByteStride, 0);
|
|
367
|
+
|
|
368
|
+
// set uniforms and draw
|
|
369
|
+
const uniformLocation = (name)=>glContext.getUniformLocation(glPostShader, name);
|
|
370
|
+
glContext.uniform1i(uniformLocation('iChannel0'), 0);
|
|
371
|
+
glContext.uniform1f(uniformLocation('iTime'), time);
|
|
372
|
+
glContext.uniform3f(uniformLocation('iResolution'), width, height, 1);
|
|
373
|
+
glContext.drawArrays(gl_TRIANGLES, 0, 3);
|
|
374
|
+
}
|
|
375
|
+
|
|
321
376
|
///////////////////////////////////////////////////////////////////////////////
|
|
322
377
|
// store gl constants as integers so their name doesn't use space in minifed
|
|
323
378
|
const
|
|
@@ -328,6 +383,7 @@ gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
|
328
383
|
gl_BLEND = 3042,
|
|
329
384
|
gl_TEXTURE_2D = 3553,
|
|
330
385
|
gl_UNSIGNED_BYTE = 5121,
|
|
386
|
+
gl_BYTE = 5120,
|
|
331
387
|
gl_FLOAT = 5126,
|
|
332
388
|
gl_RGBA = 6408,
|
|
333
389
|
gl_NEAREST = 9728,
|
|
@@ -338,12 +394,16 @@ gl_TEXTURE_WRAP_S = 10242,
|
|
|
338
394
|
gl_TEXTURE_WRAP_T = 10243,
|
|
339
395
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
340
396
|
gl_CLAMP_TO_EDGE = 33071,
|
|
397
|
+
gl_TEXTURE0 = 33984,
|
|
398
|
+
gl_TEXTURE1 = 33985,
|
|
341
399
|
gl_ARRAY_BUFFER = 34962,
|
|
400
|
+
gl_STATIC_DRAW = 35044,
|
|
342
401
|
gl_DYNAMIC_DRAW = 35048,
|
|
343
402
|
gl_FRAGMENT_SHADER = 35632,
|
|
344
403
|
gl_VERTEX_SHADER = 35633,
|
|
345
404
|
gl_COMPILE_STATUS = 35713,
|
|
346
405
|
gl_LINK_STATUS = 35714,
|
|
406
|
+
gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
347
407
|
|
|
348
408
|
// constants for batch rendering
|
|
349
409
|
gl_VERTICES_PER_QUAD = 6,
|