mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-25 06:05:52 +02:00
Archive update v0.53.2
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Sprite, Batch, SpriteBatchBase, SpriteSheet } from '../common/interfaces';
|
||||
import { Sprite, Batch, SpriteBatchBase } from '../common/interfaces';
|
||||
import { WHITE } from '../common/colors';
|
||||
import { colorToFloat, colorToFloatAlpha } from '../common/color';
|
||||
import { BaseStateBatch } from './baseStateBatch';
|
||||
@@ -38,36 +38,45 @@ export function getColorFloat(color: number, alpha: number) {
|
||||
}
|
||||
|
||||
export abstract class BaseSpriteBatch extends BaseStateBatch implements SpriteBatchBase {
|
||||
tris = 0;
|
||||
depth = 1;
|
||||
drawnTrisStats = 0;
|
||||
flushes = 0;
|
||||
index = 0;
|
||||
spritesCount = 0;
|
||||
vertices!: Float32Array;
|
||||
verticesUint32!: Uint32Array;
|
||||
vao: VAO | undefined = undefined;
|
||||
rectSprite: Sprite | undefined = undefined;
|
||||
vertexBuffer: WebGLBuffer | undefined = undefined;
|
||||
indexBuffer: WebGLBuffer | undefined = undefined;
|
||||
spriteSheet: SpriteSheet | undefined = undefined;
|
||||
floatsPerSprite: number;
|
||||
batching = false;
|
||||
vao: VAO | undefined;
|
||||
vertexBuffer: WebGLBuffer | undefined;
|
||||
protected indexBuffer: WebGLBuffer;
|
||||
protected vertices!: Float32Array;
|
||||
protected spritesCapacity: number;
|
||||
private floatsPerSprite: number;
|
||||
private batching = false;
|
||||
private startBatchIndex = 0;
|
||||
private startBatchSprites = 0;
|
||||
constructor(
|
||||
public gl: WebGLRenderingContext,
|
||||
public capacity: number,
|
||||
buffer: ArrayBuffer,
|
||||
vertexBuffer: WebGLBuffer,
|
||||
public vertexCapacityMax: number,
|
||||
indexBuffer: WebGLBuffer,
|
||||
public attributes: VAOAttributeDefinition[],
|
||||
) {
|
||||
super();
|
||||
this.floatsPerSprite = getVAOAttributesSize(gl, attributes);
|
||||
this.vertices = new Float32Array(buffer, 0, capacity * this.floatsPerSprite);
|
||||
this.verticesUint32 = new Uint32Array(buffer, 0, capacity * this.floatsPerSprite);
|
||||
|
||||
const bytesPerVertex = getVAOAttributesSize(gl, attributes);
|
||||
this.vertices = new Float32Array(vertexCapacityMax * bytesPerVertex);
|
||||
this.spritesCapacity = (vertexCapacityMax / 4) | 0; // 4 vertices per sprite
|
||||
this.floatsPerSprite = bytesPerVertex | 0; // bytesPerVertex * 4 / sizeof(float)
|
||||
|
||||
const vertexBuffer = gl.createBuffer();
|
||||
if (!vertexBuffer) {
|
||||
throw new Error(`Failed to allocate vertex buffer`);
|
||||
}
|
||||
this.vertexBuffer = vertexBuffer;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
||||
|
||||
this.indexBuffer = indexBuffer;
|
||||
this.vao = createVAO(gl, createVAOAttributes(gl, attributes, vertexBuffer), indexBuffer);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
}
|
||||
dispose() {
|
||||
disposeBuffers(this.gl, this);
|
||||
@@ -95,14 +104,13 @@ export abstract class BaseSpriteBatch extends BaseStateBatch implements SpriteBa
|
||||
|
||||
const batchSpriteCount = (batch.length / this.floatsPerSprite) | 0;
|
||||
|
||||
if (this.capacity < (this.spritesCount + batchSpriteCount)) {
|
||||
if (this.spritesCapacity < (this.spritesCount + batchSpriteCount)) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
this.vertices.set(batch, this.index);
|
||||
this.index += batch.length;
|
||||
this.spritesCount += batchSpriteCount;
|
||||
this.tris += batchSpriteCount * 2;
|
||||
}
|
||||
startBatch() {
|
||||
if (this.batching) {
|
||||
@@ -156,6 +164,7 @@ export abstract class BaseSpriteBatch extends BaseStateBatch implements SpriteBa
|
||||
this.vao.draw(this.gl.TRIANGLES, this.startBatchSprites * 6, 0);
|
||||
TIMING && timeEnd();
|
||||
|
||||
this.drawnTrisStats += this.startBatchSprites * 2;
|
||||
this.spritesCount -= this.startBatchSprites;
|
||||
this.index -= this.startBatchIndex;
|
||||
this.vertices.copyWithin(0, this.startBatchIndex, this.startBatchIndex + this.index);
|
||||
@@ -171,6 +180,7 @@ export abstract class BaseSpriteBatch extends BaseStateBatch implements SpriteBa
|
||||
this.vao.draw(this.gl.TRIANGLES, this.spritesCount * 6, 0);
|
||||
TIMING && timeEnd();
|
||||
|
||||
this.drawnTrisStats += this.spritesCount * 2;
|
||||
this.spritesCount = 0;
|
||||
this.index = 0;
|
||||
}
|
||||
@@ -184,19 +194,13 @@ function disposeBuffers(gl: WebGLRenderingContext, batch: BaseSpriteBatch) {
|
||||
if (batch.vao) {
|
||||
batch.vao.dispose();
|
||||
}
|
||||
|
||||
if (batch.vertexBuffer) {
|
||||
gl.deleteBuffer(batch.vertexBuffer);
|
||||
}
|
||||
|
||||
if (batch.indexBuffer) {
|
||||
gl.deleteBuffer(batch.indexBuffer);
|
||||
}
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.error(e);
|
||||
}
|
||||
|
||||
batch.vao = undefined;
|
||||
batch.vertexBuffer = undefined;
|
||||
batch.indexBuffer = undefined;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export function drawCanvas(
|
||||
}
|
||||
|
||||
export class ContextSpriteBatch extends BaseStateBatch implements PaletteSpriteBatch, SpriteBatch {
|
||||
depth = 1;
|
||||
pixelSize = 1;
|
||||
disableShading = false;
|
||||
ignoreColor = 0;
|
||||
@@ -137,6 +138,8 @@ export class ContextSpriteBatch extends BaseStateBatch implements PaletteSpriteB
|
||||
}
|
||||
releaseBatch() {
|
||||
}
|
||||
flush() {
|
||||
}
|
||||
}
|
||||
|
||||
const min = Math.min;
|
||||
|
||||
@@ -158,7 +158,7 @@ export class PaletteManager implements IPaletteManager {
|
||||
private initializeTexture(gl: WebGLRenderingContext, size: number) {
|
||||
try {
|
||||
if (!this.paletteTexture) {
|
||||
this.paletteTexture = createEmptyTexture(gl, size, size, gl.RGBA, gl.UNSIGNED_BYTE);
|
||||
this.paletteTexture = createEmptyTexture(gl, true, size, size, gl.RGBA, gl.UNSIGNED_BYTE);
|
||||
} else if (this.paletteTexture.width !== size) {
|
||||
resizeTexture(gl, this.paletteTexture, size, size);
|
||||
}
|
||||
|
||||
@@ -59,10 +59,12 @@ function pushQuad(
|
||||
*/
|
||||
|
||||
function pushQuad(
|
||||
vertices: Float32Array, //_verticesUint32: Uint32Array,
|
||||
vertices: Float32Array,
|
||||
transform: Matrix2D, index: number, type: number, color: number, palette: Palette,
|
||||
sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number,
|
||||
sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dz: number, dw: number, dh: number,
|
||||
) {
|
||||
index |= 0;
|
||||
|
||||
const c1 = types[type];
|
||||
|
||||
const y2 = dy + dh;
|
||||
@@ -83,63 +85,62 @@ function pushQuad(
|
||||
const t4 = transform[4];
|
||||
const t5 = transform[5];
|
||||
|
||||
// pushVertex(vertices, index, dx, dy, u1, v1, pu, pv, color, c1, transform);
|
||||
vertices[(index + 0) | 0] = t0 * dx + t2 * dy + t4;
|
||||
vertices[(index + 1) | 0] = t1 * dx + t3 * dy + t5;
|
||||
vertices[(index + 2) | 0] = u1;
|
||||
vertices[(index + 3) | 0] = v1;
|
||||
vertices[(index + 4) | 0] = pu;
|
||||
vertices[(index + 5) | 0] = pv;
|
||||
vertices[(index + 6) | 0] = color;
|
||||
vertices[(index + 7) | 0] = c1;
|
||||
vertices[index++] = t0 * dx + t2 * dy + t4;
|
||||
vertices[index++] = t1 * dx + t3 * dy + t5;
|
||||
vertices[index++] = dz;
|
||||
vertices[index++] = u1;
|
||||
vertices[index++] = v1;
|
||||
vertices[index++] = pu;
|
||||
vertices[index++] = pv;
|
||||
vertices[index++] = color;
|
||||
vertices[index++] = c1;
|
||||
|
||||
// pushVertex(vertices, index + 8, x2, dy, u2, v1, pu, pv, color, c1, transform);
|
||||
vertices[(index + 8) | 0] = t0 * x2 + t2 * dy + t4;
|
||||
vertices[(index + 9) | 0] = t1 * x2 + t3 * dy + t5;
|
||||
vertices[(index + 10) | 0] = u2;
|
||||
vertices[(index + 11) | 0] = v1;
|
||||
vertices[(index + 12) | 0] = pu;
|
||||
vertices[(index + 13) | 0] = pv;
|
||||
vertices[(index + 14) | 0] = color;
|
||||
vertices[(index + 15) | 0] = c1;
|
||||
vertices[index++] = t0 * x2 + t2 * dy + t4;
|
||||
vertices[index++] = t1 * x2 + t3 * dy + t5;
|
||||
vertices[index++] = dz;
|
||||
vertices[index++] = u2;
|
||||
vertices[index++] = v1;
|
||||
vertices[index++] = pu;
|
||||
vertices[index++] = pv;
|
||||
vertices[index++] = color;
|
||||
vertices[index++] = c1;
|
||||
|
||||
// pushVertex(vertices, index + 16, x2, y2, u2, v2, pu, pv, color, c1, transform);
|
||||
vertices[(index + 16) | 0] = t0 * x2 + t2 * y2 + t4;
|
||||
vertices[(index + 17) | 0] = t1 * x2 + t3 * y2 + t5;
|
||||
vertices[(index + 18) | 0] = u2;
|
||||
vertices[(index + 19) | 0] = v2;
|
||||
vertices[(index + 20) | 0] = pu;
|
||||
vertices[(index + 21) | 0] = pv;
|
||||
vertices[(index + 22) | 0] = color;
|
||||
vertices[(index + 23) | 0] = c1;
|
||||
vertices[index++] = t0 * x2 + t2 * y2 + t4;
|
||||
vertices[index++] = t1 * x2 + t3 * y2 + t5;
|
||||
vertices[index++] = dz;
|
||||
vertices[index++] = u2;
|
||||
vertices[index++] = v2;
|
||||
vertices[index++] = pu;
|
||||
vertices[index++] = pv;
|
||||
vertices[index++] = color;
|
||||
vertices[index++] = c1;
|
||||
|
||||
// pushVertex(vertices, index + 24, dx, y2, u1, v2, pu, pv, color, c1, transform);
|
||||
vertices[(index + 24) | 0] = t0 * dx + t2 * y2 + t4;
|
||||
vertices[(index + 25) | 0] = t1 * dx + t3 * y2 + t5;
|
||||
vertices[(index + 26) | 0] = u1;
|
||||
vertices[(index + 27) | 0] = v2;
|
||||
vertices[(index + 28) | 0] = pu;
|
||||
vertices[(index + 29) | 0] = pv;
|
||||
vertices[(index + 30) | 0] = color;
|
||||
vertices[(index + 31) | 0] = c1;
|
||||
vertices[index++] = t0 * dx + t2 * y2 + t4;
|
||||
vertices[index++] = t1 * dx + t3 * y2 + t5;
|
||||
vertices[index++] = dz;
|
||||
vertices[index++] = u1;
|
||||
vertices[index++] = v2;
|
||||
vertices[index++] = pu;
|
||||
vertices[index++] = pv;
|
||||
vertices[index++] = color;
|
||||
vertices[index++] = c1;
|
||||
|
||||
return index + 32;
|
||||
return index;
|
||||
}
|
||||
|
||||
// function colorWithAlpha(color: number, alpha: number) {
|
||||
// return ((color & 0xffffff00) | (((color & 0xff) * alpha) & 0xff)) >>> 0;
|
||||
// }
|
||||
|
||||
export const PALETTE_BATCH_BYTES_PER_VERTEX = 2 * 4 + 4 * 4 + 4 + 4;
|
||||
|
||||
export class PaletteSpriteBatch extends BaseSpriteBatch implements IPaletteSpriteBatch {
|
||||
depth = 1;
|
||||
palette = true;
|
||||
defaultPalette: Palette = createPalette(new Uint32Array(0));
|
||||
constructor(
|
||||
gl: WebGLRenderingContext, capacity: number, buffer: ArrayBuffer, vertexBuffer: WebGLBuffer, indexBuffer: WebGLBuffer
|
||||
gl: WebGLRenderingContext, vertexCapacityMax: number, indexBuffer: WebGLBuffer
|
||||
) {
|
||||
super(gl, capacity, buffer, vertexBuffer, indexBuffer, [
|
||||
{ name: 'position', size: 2 },
|
||||
super(gl, vertexCapacityMax, indexBuffer, [
|
||||
{ name: 'position', size: 3 },
|
||||
{ name: 'texcoord0', size: 4 }, //, type: gl.UNSIGNED_SHORT },
|
||||
{ name: 'color', size: 4, type: gl.UNSIGNED_BYTE, normalized: true },
|
||||
{ name: 'color1', size: 4, type: gl.UNSIGNED_BYTE, normalized: true },
|
||||
@@ -149,37 +150,35 @@ export class PaletteSpriteBatch extends BaseSpriteBatch implements IPaletteSprit
|
||||
type: number, color: number, palette: Palette | undefined,
|
||||
sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number
|
||||
) {
|
||||
if (this.capacity <= this.spritesCount) {
|
||||
if (this.spritesCapacity <= this.spritesCount) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
this.index = pushQuad(
|
||||
this.vertices, //this.verticesUint32,
|
||||
this.vertices,
|
||||
this.transform, this.index, type, getColorFloat(color, this.globalAlpha),
|
||||
palette || this.defaultPalette, sx, sy, sw, sh, dx, dy, dw, dh,
|
||||
palette || this.defaultPalette, sx, sy, sw, sh, dx, dy, this.depth, dw, dh,
|
||||
);
|
||||
this.spritesCount++;
|
||||
this.tris += 2;
|
||||
}
|
||||
drawRect(color: number, x: number, y: number, w: number, h: number) {
|
||||
if (w !== 0 && h !== 0) {
|
||||
if (this.capacity <= this.spritesCount) {
|
||||
if (this.spritesCapacity <= this.spritesCount) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
const s = this.rectSprite || defaultRectSprite;
|
||||
this.index = pushQuad(
|
||||
this.vertices, //this.verticesUint32,
|
||||
this.vertices,
|
||||
this.transform, this.index, s.type, getColorFloat(color, this.globalAlpha),
|
||||
this.defaultPalette, s.x, s.y, s.w, s.h, x, y, w, h,
|
||||
this.defaultPalette, s.x, s.y, s.w, s.h, x, y, this.depth, w, h,
|
||||
);
|
||||
this.spritesCount++;
|
||||
this.tris += 2;
|
||||
}
|
||||
}
|
||||
drawSprite(s: Sprite, color: number, palette: Palette | undefined, x: number, y: number) {
|
||||
if (s.w !== 0 && s.h !== 0) {
|
||||
if (this.capacity <= this.spritesCount) {
|
||||
if (this.spritesCapacity <= this.spritesCount) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
@@ -222,21 +221,19 @@ export class PaletteSpriteBatch extends BaseSpriteBatch implements IPaletteSprit
|
||||
|
||||
if (w > 0 && h > 0) {
|
||||
this.index = pushQuad(
|
||||
this.vertices, //this.verticesUint32,
|
||||
this.vertices,
|
||||
this.transform, this.index, s.type, getColorFloat(color, this.globalAlpha),
|
||||
palette || this.defaultPalette, sx, sy, w, h, dx, dy, w, h,
|
||||
palette || this.defaultPalette, sx, sy, w, h, dx, dy, this.depth, w, h,
|
||||
);
|
||||
this.spritesCount++;
|
||||
this.tris += 2;
|
||||
}
|
||||
} else {
|
||||
this.index = pushQuad(
|
||||
this.vertices, //this.verticesUint32,
|
||||
this.vertices,
|
||||
this.transform, this.index, s.type, getColorFloat(color, this.globalAlpha),
|
||||
palette || this.defaultPalette, s.x, s.y, s.w, s.h, x + s.ox, y + s.oy, s.w, s.h,
|
||||
palette || this.defaultPalette, s.x, s.y, s.w, s.h, x + s.ox, y + s.oy, this.depth, s.w, s.h,
|
||||
);
|
||||
this.spritesCount++;
|
||||
this.tris += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ varying vec2 textureCoord;
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
float d = clamp((1.0 - length(textureCoord)) + 0.1, 0.0, 1.0);
|
||||
float m = d * d * d;
|
||||
float d = clamp(1.1 - length(textureCoord), 0.0, 1.0);
|
||||
float m = d * d; // * d;
|
||||
|
||||
gl_FragColor = vec4(m, m, m, 1) * vColor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// VERTEX
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec2 texcoords;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec2 textureSize;
|
||||
|
||||
varying vec2 textureCoord;
|
||||
|
||||
void main() {
|
||||
textureCoord = texcoords / textureSize;
|
||||
gl_Position = transform * vec4(position, 0, 1);
|
||||
}
|
||||
|
||||
// FRAGMENT
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D sampler1;
|
||||
uniform sampler2D sampler2;
|
||||
|
||||
varying vec2 textureCoord;
|
||||
|
||||
void main() {
|
||||
vec3 color1 = texture2D(sampler1, textureCoord).rgb;
|
||||
vec3 color2 = texture2D(sampler2, textureCoord).rgb;
|
||||
gl_FragColor = vec4(color1 * color2, 1.0);
|
||||
}
|
||||
@@ -1,26 +1,33 @@
|
||||
// VERTEX
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec3 position;
|
||||
attribute vec4 texcoords;
|
||||
attribute vec4 vertexColor;
|
||||
attribute vec4 vertexColor1;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec4 lighting;
|
||||
uniform float textureSize;
|
||||
|
||||
varying vec4 textureCoord;
|
||||
varying vec4 vColor;
|
||||
varying vec4 vColor1;
|
||||
|
||||
void main() {
|
||||
textureCoord = texcoords;
|
||||
textureCoord = vec4(texcoords.xy * textureSize, texcoords.zw);
|
||||
// float f = texcoords.z;
|
||||
// float fr = fract(texcoords.z);
|
||||
// textureCoord.z = fr;
|
||||
// textureCoord.w = (f - fr) / 1024.0;
|
||||
vColor = vertexColor * lighting;
|
||||
vColor1 = vertexColor1;
|
||||
gl_Position = transform * vec4(position, 0, 1);
|
||||
float depth = position.z;
|
||||
#ifdef DEPTH_BUFFERED
|
||||
if (vColor.a < 0.975) {
|
||||
depth = 0.0;
|
||||
}
|
||||
#endif
|
||||
gl_Position = transform * vec4(position.xy, depth, 1);
|
||||
}
|
||||
|
||||
// FRAGMENT
|
||||
@@ -30,14 +37,13 @@ precision mediump float;
|
||||
uniform sampler2D sampler1; // sprite
|
||||
uniform sampler2D sampler2; // palette
|
||||
uniform float pixelSize;
|
||||
uniform float textureSize;
|
||||
|
||||
varying vec4 textureCoord;
|
||||
varying vec4 vColor;
|
||||
varying vec4 vColor1;
|
||||
|
||||
void main() {
|
||||
vec4 sprite = texture2D(sampler1, textureCoord.xy / textureSize);
|
||||
vec4 sprite = texture2D(sampler1, textureCoord.xy);
|
||||
|
||||
float shade = clamp(sprite.g + vColor1.a, 0.0, 1.0);
|
||||
|
||||
@@ -48,4 +54,10 @@ void main() {
|
||||
vec4 palette = texture2D(sampler2, vec2(paletteCoord.x + paletteIndex * pixelSize, paletteCoord.y));
|
||||
|
||||
gl_FragColor = vec4(palette.xyz * shade, palette.w) * vColor;
|
||||
|
||||
#ifdef DEPTH_BUFFERED
|
||||
if (gl_FragColor.a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
// VERTEX
|
||||
|
||||
attribute vec2 position;
|
||||
attribute vec3 position;
|
||||
attribute vec2 texcoords;
|
||||
attribute vec4 vertexColor;
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec4 lighting;
|
||||
uniform vec2 textureSize;
|
||||
|
||||
varying vec2 textureCoord;
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
textureCoord = texcoords;
|
||||
textureCoord = texcoords / textureSize;
|
||||
vColor = vertexColor * lighting;
|
||||
gl_Position = transform * vec4(position, 0, 1);
|
||||
gl_Position = transform * vec4(position, 1);
|
||||
}
|
||||
|
||||
// FRAGMENT
|
||||
@@ -21,11 +22,14 @@ void main() {
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D sampler1;
|
||||
uniform float textureSize;
|
||||
|
||||
varying vec2 textureCoord;
|
||||
varying vec4 vColor;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(sampler1, textureCoord / textureSize) * vColor;
|
||||
gl_FragColor = texture2D(sampler1, textureCoord);
|
||||
|
||||
#ifdef USE_COLOR
|
||||
gl_FragColor *= vColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ import { Sprite, SpriteBatch as ISpriteBatch, Matrix2D } from '../common/interfa
|
||||
import { BaseSpriteBatch, getColorFloat } from './baseSpriteBatch';
|
||||
|
||||
function vertex(
|
||||
vertices: Float32Array, _verticesUint32: Uint32Array, index: number,
|
||||
x: number, y: number, u: number, v: number, c: number, transform: Matrix2D
|
||||
vertices: Float32Array, index: number,
|
||||
x: number, y: number, depth: number, u: number, v: number, c: number, transform: Matrix2D
|
||||
) {
|
||||
vertices[index++] = transform[0] * x + transform[2] * y + transform[4];
|
||||
vertices[index++] = transform[1] * x + transform[3] * y + transform[5];
|
||||
vertices[index++] = depth;
|
||||
vertices[index++] = u;
|
||||
vertices[index++] = v;
|
||||
vertices[index++] = c;
|
||||
@@ -18,16 +19,9 @@ function vertex(
|
||||
|
||||
export class SpriteBatch extends BaseSpriteBatch implements ISpriteBatch {
|
||||
palette = false;
|
||||
depth = 0;
|
||||
constructor(
|
||||
gl: WebGLRenderingContext,
|
||||
capacity: number,
|
||||
buffer: ArrayBuffer,
|
||||
vertexBuffer: WebGLBuffer,
|
||||
indexBuffer: WebGLBuffer
|
||||
) {
|
||||
super(gl, capacity, buffer, vertexBuffer, indexBuffer, [
|
||||
{ name: 'position', size: 2 },
|
||||
constructor(gl: WebGLRenderingContext, vertexCapacityMax: number, indexBuffer: WebGLBuffer) {
|
||||
super(gl, vertexCapacityMax, indexBuffer, [
|
||||
{ name: 'position', size: 3 },
|
||||
{ name: 'texcoord0', size: 2 }, // , type: gl.UNSIGNED_SHORT },
|
||||
{ name: 'color', size: 4, type: gl.UNSIGNED_BYTE, normalized: true },
|
||||
]);
|
||||
@@ -36,7 +30,7 @@ export class SpriteBatch extends BaseSpriteBatch implements ISpriteBatch {
|
||||
color: number, sx: number, sy: number, sw: number, sh: number,
|
||||
dx: number, dy: number, dw: number, dh: number
|
||||
) {
|
||||
if (this.capacity <= this.spritesCount) {
|
||||
if (this.spritesCapacity <= this.spritesCount) {
|
||||
this.flush();
|
||||
}
|
||||
|
||||
@@ -51,19 +45,17 @@ export class SpriteBatch extends BaseSpriteBatch implements ISpriteBatch {
|
||||
const v2 = sy + sh;
|
||||
|
||||
const vertices = this.vertices;
|
||||
const verticesUint32 = this.verticesUint32;
|
||||
const transform = this.transform;
|
||||
|
||||
const index = this.index;
|
||||
|
||||
vertex(vertices, verticesUint32, index, dx, dy, u1, v1, c, transform);
|
||||
vertex(vertices, verticesUint32, index + 5, x2, dy, u2, v1, c, transform);
|
||||
vertex(vertices, verticesUint32, index + 10, x2, y2, u2, v2, c, transform);
|
||||
vertex(vertices, verticesUint32, index + 15, dx, y2, u1, v2, c, transform);
|
||||
vertex(vertices, index, dx, dy, this.depth, u1, v1, c, transform);
|
||||
vertex(vertices, index + 6, x2, dy, this.depth, u2, v1, c, transform);
|
||||
vertex(vertices, index + 12, x2, y2, this.depth, u2, v2, c, transform);
|
||||
vertex(vertices, index + 18, dx, y2, this.depth, u1, v2, c, transform);
|
||||
|
||||
this.index += 20;
|
||||
this.index += 24;
|
||||
this.spritesCount++;
|
||||
this.tris += 2;
|
||||
}
|
||||
drawRect(color: number, x: number, y: number, w: number, h: number) {
|
||||
if (w && h) {
|
||||
|
||||
@@ -4,7 +4,8 @@ import { createTexture, disposeTexture } from './webgl/texture2d';
|
||||
export function createTexturesForSpriteSheets(gl: WebGLRenderingContext, sheets: SpriteSheet[], texture = createTexture) {
|
||||
sheets.forEach(sheet => {
|
||||
if (sheet.data) {
|
||||
sheet.texture = texture(gl, sheet.data);
|
||||
let format = sheet.isSingleChannel ? gl.LUMINANCE : gl.RGBA;
|
||||
sheet.texture = texture(gl, sheet.data, format);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,28 +1,50 @@
|
||||
import { Texture2D, createEmptyTexture, resizeTexture } from './texture2d';
|
||||
import { Texture2D, createEmptyTexture } from './texture2d';
|
||||
|
||||
export interface FrameBuffer {
|
||||
handle: WebGLFramebuffer;
|
||||
texture: Texture2D;
|
||||
colorTexture: Texture2D;
|
||||
depthStencilRenderbuffer: WebGLRenderbuffer | null;
|
||||
width: number;
|
||||
height: number;
|
||||
owningDepthStencil: boolean;
|
||||
}
|
||||
|
||||
export function createFrameBuffer(gl: WebGLRenderingContext, width: number, height: number): FrameBuffer {
|
||||
export function createFrameBuffer(
|
||||
gl: WebGLRenderingContext, target: FrameBuffer, width: number, height: number, useLinearMagnify: boolean,
|
||||
createDepthStencil: boolean, depthStencilRenderbuffer: WebGLRenderbuffer | null
|
||||
) {
|
||||
const handle = gl.createFramebuffer();
|
||||
|
||||
if (!handle) {
|
||||
throw new Error('Failed to create frame buffer');
|
||||
}
|
||||
|
||||
const texture = createEmptyTexture(gl, width, height, gl.RGB);
|
||||
return { handle, texture, width, height };
|
||||
const resources = createFrameBufferResources(gl, width, height, createDepthStencil, useLinearMagnify);
|
||||
target.handle = handle;
|
||||
target.colorTexture = resources.colorTexture;
|
||||
target.depthStencilRenderbuffer = resources.depthStencilRenderbuffer;
|
||||
target.width = width;
|
||||
target.height = height;
|
||||
target.owningDepthStencil = createDepthStencil;
|
||||
|
||||
if (!createDepthStencil) {
|
||||
target.depthStencilRenderbuffer = depthStencilRenderbuffer;
|
||||
}
|
||||
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, handle);
|
||||
bindFrameBufferAttachments(gl, target);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
export function disposeFrameBuffer(gl: WebGLRenderingContext | undefined, buffer: FrameBuffer | undefined) {
|
||||
export function disposeFrameBuffer(gl?: WebGLRenderingContext, buffer?: FrameBuffer) {
|
||||
try {
|
||||
if (gl && buffer) {
|
||||
gl.deleteFramebuffer(buffer.handle);
|
||||
gl.deleteTexture(buffer.texture.handle);
|
||||
if (buffer.colorTexture) {
|
||||
gl.deleteTexture(buffer.colorTexture.handle);
|
||||
}
|
||||
if (buffer.depthStencilRenderbuffer && buffer.owningDepthStencil) {
|
||||
gl.deleteRenderbuffer(buffer.depthStencilRenderbuffer);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.error(e);
|
||||
@@ -31,18 +53,52 @@ export function disposeFrameBuffer(gl: WebGLRenderingContext | undefined, buffer
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function resizeFrameBuffer(gl: WebGLRenderingContext, frameBuffer: FrameBuffer, width: number, height: number) {
|
||||
resizeTexture(gl, frameBuffer.texture, width, height);
|
||||
frameBuffer.width = width;
|
||||
frameBuffer.height = height;
|
||||
}
|
||||
|
||||
export function bindFrameBuffer(gl: WebGLRenderingContext, { handle, texture }: FrameBuffer) {
|
||||
export function bindFrameBuffer(gl: WebGLRenderingContext, { handle }: FrameBuffer) {
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, handle);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture.handle, 0);
|
||||
}
|
||||
|
||||
export function unbindFrameBuffer(gl: WebGLRenderingContext) {
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
function bindFrameBufferAttachments(gl: WebGLRenderingContext, { colorTexture, depthStencilRenderbuffer }: FrameBuffer) {
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture.handle, 0);
|
||||
if (depthStencilRenderbuffer) {
|
||||
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthStencilRenderbuffer);
|
||||
}
|
||||
|
||||
gl.depthMask(true);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
gl.depthMask(false);
|
||||
|
||||
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
|
||||
throw new Error('Failed to set framebuffer attachments');
|
||||
}
|
||||
}
|
||||
|
||||
function createFrameBufferResources(
|
||||
gl: WebGLRenderingContext, width: number, height: number, createDepthBuffer: boolean, useLinearMagnify: boolean
|
||||
) {
|
||||
const colorTexture = createEmptyTexture(gl, false, width, height, gl.RGB);
|
||||
if (!colorTexture) {
|
||||
throw new Error('Failed to create frame buffer\'s color texture');
|
||||
}
|
||||
if (useLinearMagnify) {
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
}
|
||||
|
||||
let depthStencilRenderbuffer: WebGLRenderbuffer | null = null;
|
||||
if (createDepthBuffer) {
|
||||
depthStencilRenderbuffer = gl.createRenderbuffer();
|
||||
if (depthStencilRenderbuffer) {
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, depthStencilRenderbuffer);
|
||||
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
||||
}
|
||||
else {
|
||||
console.warn('depth/stencil is not available');
|
||||
}
|
||||
}
|
||||
|
||||
return { colorTexture, depthStencilRenderbuffer };
|
||||
}
|
||||
|
||||
@@ -293,9 +293,11 @@ function throwFBOError(gl: WebGL, status: number, message = '') {
|
||||
}
|
||||
|
||||
function initTexture(gl: WebGL, width: number, height: number, type: number, format: number, attachment: number) {
|
||||
const texture = createEmptyTexture(gl, width, height, format, type);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture.handle);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture.handle, 0);
|
||||
const texture = createEmptyTexture(gl, true, width, height, format, type);
|
||||
if (texture) {
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture.handle);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, texture.handle, 0);
|
||||
}
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ class VAONative implements VAO {
|
||||
}
|
||||
dispose() {
|
||||
this.ext.deleteVertexArrayOES(this.handle);
|
||||
this.handle = {};
|
||||
}
|
||||
update(attributes: VAOAttributes[], elements: WebGLBuffer | null, elementsType?: number) {
|
||||
this.bind();
|
||||
|
||||
@@ -1,85 +1,98 @@
|
||||
export interface Shader {
|
||||
export interface ShaderProgramData {
|
||||
program: WebGLProgram;
|
||||
vertexShader: WebGLShader;
|
||||
fragmentShader: WebGLShader;
|
||||
uniforms: { [key: string]: WebGLUniformLocation; };
|
||||
}
|
||||
|
||||
export function createShader(gl: WebGLRenderingContext, source: string | { vertex: string; fragment: string; }): Shader {
|
||||
if (typeof source === 'string') {
|
||||
const index = source.indexOf('// FRAGMENT');
|
||||
export class Shader {
|
||||
private programs: { [key: string]: ShaderProgramData; } = {};
|
||||
private vertexCode: string;
|
||||
private fragmentCode: string;
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error(`Missing fragment shader separator`);
|
||||
constructor(source: string | { vertex: string; fragment: string; }) {
|
||||
if (typeof source === 'string') {
|
||||
const index = source.indexOf('// FRAGMENT');
|
||||
|
||||
if (index === -1) {
|
||||
throw new Error(`Missing fragment shader separator`);
|
||||
}
|
||||
|
||||
source = {
|
||||
vertex: source.substring(0, index),
|
||||
fragment: source.substring(index),
|
||||
};
|
||||
}
|
||||
|
||||
source = {
|
||||
vertex: source.substring(0, index),
|
||||
fragment: source.substring(index),
|
||||
};
|
||||
this.vertexCode = source.vertex;
|
||||
this.fragmentCode = source.fragment;
|
||||
}
|
||||
|
||||
const vertexShader = createWebGLShader(gl, gl.VERTEX_SHADER, source.vertex);
|
||||
const fragmentShader = createWebGLShader(gl, gl.FRAGMENT_SHADER, source.fragment);
|
||||
const program = gl.createProgram();
|
||||
compile(gl: WebGLRenderingContext, defines: string[]) {
|
||||
defines.sort();
|
||||
let definesString = defines.reduce((prev, cur) => prev + cur, '');
|
||||
|
||||
if (!program) {
|
||||
throw new Error('Failed to create shader program');
|
||||
}
|
||||
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.attachShader(program, fragmentShader);
|
||||
|
||||
const attribs = source.vertex.match(/^attribute [a-zA-Z0-9_]+ ([a-zA-Z0-9_]+)/mg)!;
|
||||
|
||||
for (var i = 0; i < attribs.length; ++i) {
|
||||
const [, name] = /attribute [a-zA-Z0-9_]+ ([a-zA-Z0-9_]+)/.exec(attribs[i])!;
|
||||
gl.bindAttribLocation(program, i, name);
|
||||
}
|
||||
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
throw new Error('Failed to link shader program');
|
||||
}
|
||||
|
||||
gl.useProgram(program);
|
||||
|
||||
const uniforms: any = {};
|
||||
const samplers: string[] = [];
|
||||
|
||||
for (let i = 0; i < gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); i++) {
|
||||
const info = gl.getActiveUniform(program, i)!;
|
||||
uniforms[info.name] = gl.getUniformLocation(program, info.name);
|
||||
|
||||
if (!uniforms[info.name]) {
|
||||
throw new Error(`Failed to get uniform location (${info.name})`);
|
||||
let data = this.programs[definesString];
|
||||
if (!data) {
|
||||
data = Shader.compileShader(gl, this.vertexCode, this.fragmentCode, defines);
|
||||
this.programs[definesString] = data;
|
||||
}
|
||||
|
||||
if (info.type === gl.SAMPLER_2D) {
|
||||
samplers.push(info.name);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
samplers.sort().forEach((name, i) => gl.uniform1i(uniforms[name], i));
|
||||
|
||||
gl.useProgram(null);
|
||||
private static compileShader(gl: WebGLRenderingContext, vertexCode: string, fragmentCode: string, defines: string[]) {
|
||||
let shaderDefines = defines.reduce((prev, cur) => prev + '#define ' + cur + '\n', '');
|
||||
|
||||
return { program, vertexShader, fragmentShader, uniforms };
|
||||
}
|
||||
const vertexShader = createWebGLShader(gl, gl.VERTEX_SHADER, shaderDefines + vertexCode);
|
||||
const fragmentShader = createWebGLShader(gl, gl.FRAGMENT_SHADER, shaderDefines + fragmentCode);
|
||||
const program = gl.createProgram();
|
||||
|
||||
export function disposeShader(gl: WebGLRenderingContext | undefined, shader: Shader | undefined) {
|
||||
try {
|
||||
if (gl && shader) {
|
||||
gl.deleteProgram(shader.program);
|
||||
gl.deleteShader(shader.vertexShader);
|
||||
gl.deleteShader(shader.fragmentShader);
|
||||
if (!program) {
|
||||
throw new Error('Failed to create shader program');
|
||||
}
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.error(e);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.attachShader(program, fragmentShader);
|
||||
|
||||
const attribs = vertexCode.match(/^attribute [a-zA-Z0-9_]+ ([a-zA-Z0-9_]+)/mg)!;
|
||||
|
||||
for (var i = 0; i < attribs.length; ++i) {
|
||||
const [, name] = /attribute [a-zA-Z0-9_]+ ([a-zA-Z0-9_]+)/.exec(attribs[i])!;
|
||||
gl.bindAttribLocation(program, i, name);
|
||||
}
|
||||
|
||||
gl.linkProgram(program);
|
||||
gl.deleteShader(vertexShader);
|
||||
gl.deleteShader(fragmentShader);
|
||||
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
throw new Error('Failed to link shader program');
|
||||
}
|
||||
|
||||
gl.useProgram(program);
|
||||
|
||||
const uniforms: any = {};
|
||||
const samplers: string[] = [];
|
||||
|
||||
for (let i = 0; i < gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); i++) {
|
||||
const info = gl.getActiveUniform(program, i)!;
|
||||
uniforms[info.name] = gl.getUniformLocation(program, info.name);
|
||||
|
||||
if (!uniforms[info.name]) {
|
||||
throw new Error(`Failed to get uniform location (${info.name})`);
|
||||
}
|
||||
|
||||
if (info.type === gl.SAMPLER_2D) {
|
||||
samplers.push(info.name);
|
||||
}
|
||||
}
|
||||
|
||||
samplers.sort().forEach((name, i) => gl.uniform1i(uniforms[name], i));
|
||||
|
||||
gl.useProgram(null);
|
||||
|
||||
return {program, uniforms};
|
||||
}
|
||||
}
|
||||
|
||||
function createWebGLShader(gl: WebGLRenderingContext, type: number, source: string) {
|
||||
@@ -98,3 +111,13 @@ function createWebGLShader(gl: WebGLRenderingContext, type: number, source: stri
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
export function disposeShaderProgramData(gl: WebGLRenderingContext, data: ShaderProgramData) {
|
||||
try {
|
||||
if (gl) {
|
||||
gl.deleteProgram(data.program);
|
||||
}
|
||||
} catch (e) {
|
||||
DEVELOPMENT && console.error(e);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { clearWebGLErrors, hasWebGLErrors, isWebGL2 } from './webglUtils';
|
||||
|
||||
type WebGL = WebGLRenderingContext;
|
||||
type Pixels = ImageBitmap | ImageData | HTMLVideoElement | HTMLImageElement | HTMLCanvasElement;
|
||||
|
||||
@@ -7,9 +9,12 @@ export interface Texture2D {
|
||||
height: number;
|
||||
format: number;
|
||||
type: number;
|
||||
internalFormat: number;
|
||||
}
|
||||
|
||||
export function createEmptyTexture(gl: WebGL, width: number, height: number, format?: number, type?: number): Texture2D {
|
||||
export function createEmptyTexture(
|
||||
gl: WebGL, isResizable: boolean, width: number, height: number, format?: number, type?: number, internalFormat?: number
|
||||
) {
|
||||
if (format === undefined) {
|
||||
format = gl.RGBA;
|
||||
}
|
||||
@@ -18,6 +23,10 @@ export function createEmptyTexture(gl: WebGL, width: number, height: number, for
|
||||
type = gl.UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
if (internalFormat === undefined) {
|
||||
internalFormat = format;
|
||||
}
|
||||
|
||||
const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE) as number | null;
|
||||
|
||||
if (maxTextureSize != null && (width < 0 || width > maxTextureSize || height < 0 || height > maxTextureSize)) {
|
||||
@@ -28,12 +37,36 @@ export function createEmptyTexture(gl: WebGL, width: number, height: number, for
|
||||
throw new Error('Floating point textures not supported on this platform');
|
||||
}
|
||||
|
||||
clearWebGLErrors(gl);
|
||||
const handle = createTextureHandle(gl);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, null);
|
||||
return { handle, width, height, format, type };
|
||||
if (!isResizable && isWebGL2(gl)) {
|
||||
const gl2 = gl as WebGL2RenderingContext;
|
||||
let format2: number;
|
||||
if (internalFormat === gl.RGB) {
|
||||
format2 = gl2.RGB8;
|
||||
}
|
||||
else if (internalFormat === gl.RGBA) {
|
||||
format2 = gl2.RGBA8;
|
||||
}
|
||||
else {
|
||||
throw new Error('Cannot convert internal format into WebGL2 format');
|
||||
}
|
||||
gl2.texStorage2D(gl.TEXTURE_2D, 1, format2, width, height);
|
||||
}
|
||||
else {
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, null);
|
||||
}
|
||||
if (hasWebGLErrors(gl)) {
|
||||
console.warn('createEmptyTexture failed due to a WebGL error');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { handle, width, height, format, type, internalFormat };
|
||||
}
|
||||
|
||||
export function createTexture(gl: WebGL, data: Pixels, format?: number, type?: number): Texture2D {
|
||||
export function createTexture(
|
||||
gl: WebGL, data: Pixels, format?: number, type?: number, internalFormat?: number
|
||||
) {
|
||||
if (format === undefined) {
|
||||
format = gl.RGBA;
|
||||
}
|
||||
@@ -42,9 +75,19 @@ export function createTexture(gl: WebGL, data: Pixels, format?: number, type?: n
|
||||
type = gl.UNSIGNED_BYTE;
|
||||
}
|
||||
|
||||
if (internalFormat === undefined) {
|
||||
internalFormat = format;
|
||||
}
|
||||
|
||||
clearWebGLErrors(gl);
|
||||
const handle = createTextureHandle(gl);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, format, type, data);
|
||||
return { handle, width: data.width, height: data.height, format, type };
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, format, type, data);
|
||||
if (hasWebGLErrors(gl)) {
|
||||
console.warn('createTexture failed due to a WebGL error');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { handle, width: data.width, height: data.height, format, type, internalFormat };
|
||||
}
|
||||
|
||||
export function disposeTexture(gl: WebGL | undefined, texture: Texture2D | undefined): undefined {
|
||||
@@ -68,7 +111,7 @@ export function resizeTexture(gl: WebGL, texture: Texture2D, width: number, heig
|
||||
width = width | 0;
|
||||
height = height | 0;
|
||||
|
||||
const { format, type } = texture;
|
||||
const { format, type, internalFormat } = texture;
|
||||
const maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE) as number | null;
|
||||
|
||||
if (maxSize != null && (width < 0 || width > maxSize || height < 0 || height > maxSize)) {
|
||||
@@ -78,7 +121,7 @@ export function resizeTexture(gl: WebGL, texture: Texture2D, width: number, heig
|
||||
texture.width = width;
|
||||
texture.height = height;
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture.handle);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, null);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, null);
|
||||
}
|
||||
|
||||
function createTextureHandle(gl: WebGL) {
|
||||
|
||||
@@ -1,24 +1,16 @@
|
||||
import { makeDebugContext } from 'webgl-debug';
|
||||
import { WEBGL_CREATION_ERROR } from '../../common/errors';
|
||||
|
||||
export function getRenderTargetSize(width: number, height: number) {
|
||||
const max = Math.max(width, height);
|
||||
let pow = 256;
|
||||
|
||||
while (pow < max) {
|
||||
pow *= 2;
|
||||
}
|
||||
|
||||
return pow;
|
||||
}
|
||||
|
||||
export function getWebGLContext(canvas: HTMLCanvasElement): WebGLRenderingContext {
|
||||
const options: WebGLContextAttributes = {
|
||||
alpha: false,
|
||||
preserveDrawingBuffer: false,
|
||||
premultipliedAlpha: false,
|
||||
antialias: false,
|
||||
depth: false
|
||||
};
|
||||
|
||||
const gl = canvas.getContext('webgl2', options)
|
||||
let gl = canvas.getContext('webgl2', options)
|
||||
|| canvas.getContext('webgl', options)
|
||||
|| canvas.getContext('experimental-webgl', options);
|
||||
|
||||
@@ -26,6 +18,20 @@ export function getWebGLContext(canvas: HTMLCanvasElement): WebGLRenderingContex
|
||||
throw new Error(WEBGL_CREATION_ERROR);
|
||||
}
|
||||
|
||||
// debug context will check every GL call for errors and will
|
||||
// emit a console message with a stack trace if there was an error,
|
||||
// but it can slow execution down by more than 2x depending
|
||||
// on the platform so it isn't on by default even in DEVELOPMENT
|
||||
const useDebugContext = false;
|
||||
|
||||
if (useDebugContext) {
|
||||
gl = makeDebugContext(gl);
|
||||
|
||||
if (!gl) {
|
||||
throw new Error(WEBGL_CREATION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return gl;
|
||||
}
|
||||
|
||||
@@ -65,3 +71,11 @@ export function unbindAllTexturesAndBuffers(gl: WebGLRenderingContext) {
|
||||
DEVELOPMENT && console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export function clearWebGLErrors(gl: WebGLRenderingContext) {
|
||||
while (hasWebGLErrors(gl));
|
||||
}
|
||||
|
||||
export function hasWebGLErrors(gl: WebGLRenderingContext) {
|
||||
return gl.getError() !== gl.NO_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user