Skip to content

Instantly share code, notes, and snippets.

@ivanpopelyshev
Last active March 20, 2019 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivanpopelyshev/5ea0bfc2ba73bfea8ef204ccf093e582 to your computer and use it in GitHub Desktop.
Save ivanpopelyshev/5ea0bfc2ba73bfea8ef204ccf093e582 to your computer and use it in GitHub Desktop.
Shumway + WebGL partial texture upload
// Its a custom renderer, pixi fork, it'll be easy to port on vanilla v5
// Careful: Method names differ from V5. Find appropriate fields.
export class Canvas2DSurface implements ISurface, gobi.core.ITextureResource {
width: number;
height: number;
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
private _regionAllocator: RegionAllocator.IRegionAllocator;
regions: Array<TextureRegion> = [];
updated: Array<TextureRegion> = [];
updateBounds = new core.Bounds();
constructor(canvas: HTMLCanvasElement, regionAllocator?: RegionAllocator.IRegionAllocator) {
this.canvas = canvas;
this.context = canvas.getContext("2d");
this.width = canvas.width;
this.height = canvas.height;
this._regionAllocator = regionAllocator;
new core.BaseTexture(this);
}
allocate(w: number, h: number): TextureRegion {
let region = this._regionAllocator.allocate(w, h);
if (region) {
let res = new TextureRegion(this, region);
this.regions.push(res);
return res;
}
return null;
}
free(surfaceRegion: TextureRegion) {
let ind = this.regions.indexOf(surfaceRegion);
if (ind >= 0) {
this._regionAllocator.free(surfaceRegion.region);
this.regions.splice(ind, 1);
}
}
baseTexture: gobi.core.BaseTexture = null;
onTextureNew(baseTexture: gobi.core.BaseTexture) {
this.baseTexture = baseTexture;
baseTexture.mipmap = false;
baseTexture.premultiplyAlpha = true;
baseTexture.setSize(this.width, this.height);
}
fixImageData(imageData: ImageData, fix: boolean = true) {
if (!fix) {
return imageData;
}
const data = imageData.data;
let opaque = 0;
let transparent = 0;
for (let i = 3; i < data.length; i += 4) {
if (data[i] > 0) {
if (data[i] == 255) {
opaque++;
} else {
transparent++;
}
}
}
if (opaque * 99 > transparent) {
for (let i = 3; i < data.length; i += 4) {
if (data[i] > 153) {
data[i] = data[i] * 10 - 153 * 9;
}
}
}
return imageData;
}
onTextureUpload(renderer: gobi.pixi.WebGLRenderer, baseTexture: gobi.core.BaseTexture, glTexture: gobi.glCore.GLTexture) {
const gl = renderer.gl;
if (glTexture._updateID < 0) {
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.fixImageData(this.context.getImageData(0, 0, baseTexture.width, baseTexture.height))
);
glTexture.width = baseTexture.width;
glTexture.height = baseTexture.height;
return true;
}
const regions = this.regions;
const updated = this.updated;
const _updateID = glTexture._updateID;
const bounds = this.updateBounds;
bounds.clear();
let area = 0;
updated.length = 0;
for (let i = 0; i < regions.length; i++) {
const region = regions[i];
if (region._baseTexUpdateID > _updateID) {
updated.push(region);
bounds.addRect(region.region);
area += region.region.width * region.region.height;
}
}
let sq = (bounds.maxX - bounds.minX) * (bounds.maxY - bounds.minY);
if (area * 2 < sq) {
// multiple rects
for (let i = 0; i < updated.length; i++) {
const region = updated[i].region;
gl.texSubImage2D(
gl.TEXTURE_2D,
0,
region.x,
region.y,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.fixImageData(this.context.getImageData(region.x, region.y, region.width, region.height))
);
}
} else
/*if (sq * 2 < this.width * this.height)*/ {
// one rect
gl.texSubImage2D(
gl.TEXTURE_2D,
0,
bounds.minX,
bounds.minY,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.fixImageData(this.context.getImageData(bounds.minX, bounds.minY, bounds.maxX - bounds.minX, bounds.maxY - bounds.minY))
);
}
/* else {
// full canvas
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
this.canvas
);
} */
updated.length = 0;
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment