Skip to content

Commit

Permalink
more deformer cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
yofreke committed Sep 15, 2016
1 parent 376f1a5 commit c37985e
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 88 deletions.
196 changes: 108 additions & 88 deletions js/deformers/twgl/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import twgl from 'twgl.js/dist/twgl-full';

import { getImageData } from '../../utils/image';
import { getBoundingBox } from '../../utils/points';
import Background from './Background';


Expand All @@ -15,9 +17,13 @@ export default class Deformer {
this._tracker = null;
this._gl = null;

this._pdmModel = null;
this._verticeMap = null;

this._dynamicMaskTexture = false;
this._maskTextureSrcElement = null;
this._maskTextureCanvas = document.createElement('canvas');
this._pointBB = null;

this._maskTextureCoord = null;
this._maskProgramInfo = null;
this._maskTextures = null;
Expand All @@ -34,105 +40,127 @@ export default class Deformer {
}

loadTexture (texPath, points, tracker, bgElement) {
let element = document.createElement('img');
element.src = texPath;
element.addEventListener('load', () => {
this.load(element, points, tracker, bgElement);
}, false);
const image = new Image();
image.addEventListener('load', () => {
this.load(image, points, tracker, bgElement);
});
image.src = texPath;
}

load (element, points, tracker, bgElement) {
this._tracker = tracker;
this.background.setElement(bgElement);
this._pdmModel = tracker.model;
// Set verts for this mask
this._verticeMap = this._pdmModel.path.vertices;

// Find texture cropping from mask points
let maxx, minx, maxy, miny;
let width, height;

maxx = 0;
minx = element.width;
maxy = 0;
miny = element.height;

for (let i = 0; i < points.length; i++) {
if (points[i][0] > maxx) maxx = points[i][0];
if (points[i][0] < minx) minx = points[i][0];
if (points[i][1] > maxy) maxy = points[i][1];
if (points[i][1] < miny) miny = points[i][1];
}

minx = Math.floor(minx);
maxx = Math.ceil(maxx);
miny = Math.floor(miny);
maxy = Math.ceil(maxy);

width = maxx - minx;
height = maxy - miny;

// Get mask texture
let cc;
if (element.tagName === 'VIDEO' || element.tagName === 'IMG') {
let ca = document.createElement('canvas');
ca.width = element.width;
ca.height = element.height;
cc = ca.getContext('2d');
cc.drawImage(element, 0, 0, element.width, element.height);
} else if (element.tagName === 'CANVAS') {
cc = element.getContext('2d');
} else {
throw new Error('unknown tagName: ' + element.tagName);
_generateTextureVertices (points, vertMap, scaleX = 1, scaleY = 1) {
const tvs = [];
for (let i = 0; i < vertMap.length; i++) {
tvs.push(points[vertMap[i][0]][0] * scaleX);
tvs.push(points[vertMap[i][0]][1] * scaleY);
tvs.push(points[vertMap[i][1]][0] * scaleX);
tvs.push(points[vertMap[i][1]][1] * scaleY);
tvs.push(points[vertMap[i][2]][0] * scaleX);
tvs.push(points[vertMap[i][2]][1] * scaleY);
}
return tvs;
}

let maskImage = cc.getImageData(minx, miny, width, height);

// @TODO too many in-memory canvases, need to simplify and speed up
let crx = document.createElement('canvas').getContext('2d');
crx.canvas.width = width;
crx.canvas.height = height;
crx.putImageData(maskImage, 0, 0);
setMaskTexture (element) {
this._maskTextureSrcElement = element;

// correct points
let nupoints = [];
for (let i = 0; i < points.length; i++) {
nupoints[i] = [];
nupoints[i][0] = points[i][0] - minx;
nupoints[i][1] = points[i][1] - miny;
const tagName = this._maskTextureSrcElement.tagName;
if (tagName === 'CANVAS') {
// Use the element as texture (its dynamic!)
this._dynamicMaskTexture = true;
} else {
// We need a still frame from it
this._dynamicMaskTexture = false;
this.updateMaskTexture();
}
}

// create vertices based on points
let textureVertices = [];
for (let i = 0; i < this._verticeMap.length; i++) {
textureVertices.push(nupoints[this._verticeMap[i][0]][0] / width);
textureVertices.push(nupoints[this._verticeMap[i][0]][1] / height);
textureVertices.push(nupoints[this._verticeMap[i][1]][0] / width);
textureVertices.push(nupoints[this._verticeMap[i][1]][1] / height);
textureVertices.push(nupoints[this._verticeMap[i][2]][0] / width);
textureVertices.push(nupoints[this._verticeMap[i][2]][1] / height);
updateMaskTexture () {
if (
!this._maskTextureSrcElement ||
!this._pointBB
) { return; }

let srcElement;
if (!this._dynamicMaskTexture) {
// Draw the srcElement to the mask texture canvas
const {
minX, minY, width, height
} = this._pointBB;

const maskImage = getImageData(
this._maskTextureSrcElement,
minX,
minY,
width,
height
);

const canvas = this._maskTextureCanvas;
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.putImageData(maskImage, 0, 0);

srcElement = canvas;
} else {
srcElement = this._maskTextureSrcElement
}

this._maskTextureCoord = textureVertices;

// Update the webgl stuff
const gl = this.getGLContext();
this._maskProgramInfo = twgl.createProgramInfo(gl, [
require('raw!./shaders/deform.vert'),
require('raw!./shaders/deform.frag')
]);

this._maskTextures = twgl.createTextures(gl, {
mask: {
mag: gl.LINEAR,
min: gl.LINEAR,
src: crx.canvas
src: srcElement
}
});

this._maskUniforms = {
u_resolution: [gl.drawingBufferWidth, gl.drawingBufferHeight],
u_sampler: this._maskTextures.mask
};
}

setPoints (points) {
// Find texture cropping from mask points
this._pointBB = getBoundingBox(points);

// correct points
let nupoints = points.map(p => [
p[0] - this._pointBB.minX,
p[1] - this._pointBB.minY
]);

// create vertices based on points
this._maskTextureCoord = this._generateTextureVertices(
nupoints,
this._verticeMap,
1 / this._pointBB.width,
1 / this._pointBB.height
);

this.updateMaskTexture();
}

setTracker (tracker) {
this._tracker = tracker;
// Set verts for this mask
this._verticeMap = tracker.model.path.vertices;
}

load (element, points, tracker, bgElement) {
this.setTracker(tracker);
this.setMaskTexture(element);
this.setPoints(points);

this.background.setElement(bgElement);

const gl = this.getGLContext();
this._maskProgramInfo = twgl.createProgramInfo(gl, [
require('raw!./shaders/deform.vert'),
require('raw!./shaders/deform.frag')
]);

this._isLoaded = true;
}
Expand All @@ -156,15 +184,7 @@ export default class Deformer {
const gl = this.getGLContext();

// create drawvertices based on points
let vertices = [];
for (let i = 0; i < this._verticeMap.length; i++) {
vertices.push(points[this._verticeMap[i][0]][0]);
vertices.push(points[this._verticeMap[i][0]][1]);
vertices.push(points[this._verticeMap[i][1]][0]);
vertices.push(points[this._verticeMap[i][1]][1]);
vertices.push(points[this._verticeMap[i][2]][0]);
vertices.push(points[this._verticeMap[i][2]][1]);
}
let vertices = this._generateTextureVertices(points, this._verticeMap);

this._maskBufferInfo = twgl.createBufferInfoFromArrays(gl, {
position: {
Expand Down
17 changes: 17 additions & 0 deletions js/utils/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,20 @@ export const resizeImage = (image, opts = RESIZE_IMAGE_DEFAULT_OPTS) => {

return { canvas: c, padding: padding };
}


export const getImageData = (element, x, y, width, height) => {
let cc;
if (element.tagName === 'VIDEO' || element.tagName === 'IMG') {
const ca = document.createElement('canvas');
ca.width = element.width;
ca.height = element.height;
cc = ca.getContext('2d');
cc.drawImage(element, 0, 0, element.width, element.height);
} else if (element.tagName === 'CANVAS') {
cc = element.getContext('2d');
} else {
throw new Error('unknown tagName: ' + element.tagName);
}
return cc.getImageData(x, y, width, height);
};
30 changes: 30 additions & 0 deletions js/utils/points.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const getBoundingBox = (points) => {
let maxX = 0;
let minX = 0;
let maxY = 0;
let minY = 0;

for (let i = 0; i < points.length; i++) {
const x = points[i][0];
if (x > maxX) maxX = x;
else if (x < minX) minX = x;

const y = points[i][1];
if (y > maxY) maxY = y;
else if (y < minY) minY = y;
}

minX = Math.floor(minX);
maxX = Math.ceil(maxX);
minY = Math.floor(minY);
maxY = Math.ceil(maxY);

return {
maxX,
minX,
maxY,
minY,
width: maxX - minX,
height: maxY - minY
};
};

0 comments on commit c37985e

Please sign in to comment.