2013-11-09 05:16:28 +00:00
|
|
|
//"use strict";
|
|
|
|
|
|
|
|
var LibraryRWebCam = {
|
|
|
|
$RWC: {
|
2013-11-13 00:48:36 +00:00
|
|
|
RETRO_CAMERA_BUFFER_OPENGL_TEXTURE: 0,
|
|
|
|
RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER: 1,
|
|
|
|
tmp: null,
|
|
|
|
|
|
|
|
contexts: [],
|
|
|
|
counter: 0,
|
2013-11-09 05:16:28 +00:00
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
ready: function(data) {
|
|
|
|
return RWC.contexts[data].runMode == 2 && !RWC.contexts[data].videoElement.paused && RWC.contexts[data].videoElement.videoWidth != 0 && RWC.contexts[data].videoElement.videoHeight != 0;
|
|
|
|
}
|
|
|
|
},
|
2013-11-09 05:16:28 +00:00
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
RWebCamInit__deps: ['malloc'],
|
|
|
|
RWebCamInit: function(caps1, caps2, width, height) {
|
2013-11-09 05:16:28 +00:00
|
|
|
if (!navigator) return 0;
|
|
|
|
|
|
|
|
navigator.getMedia = navigator.getUserMedia ||
|
|
|
|
navigator.webkitGetUserMedia ||
|
|
|
|
navigator.mozGetUserMedia ||
|
|
|
|
navigator.msGetUserMedia;
|
|
|
|
|
|
|
|
if (!navigator.getMedia) return 0;
|
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
var c = ++RWC.counter;
|
2013-11-09 05:16:28 +00:00
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
RWC.contexts[c] = [];
|
|
|
|
RWC.contexts[c].videoElement = document.createElement("video");
|
|
|
|
if (width !== 0 && height !== 0) {
|
|
|
|
RWC.contexts[c].videoElement.width = width;
|
|
|
|
RWC.contexts[c].videoElement.height = height;
|
|
|
|
}
|
|
|
|
RWC.contexts[c].runMode = 1;
|
|
|
|
RWC.contexts[c].glTex = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_OPENGL_TEXTURE);
|
|
|
|
RWC.contexts[c].rawFb = caps1 & (1 << RWC.RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);
|
2013-11-09 05:16:28 +00:00
|
|
|
|
|
|
|
navigator.getMedia({video: true, audio: false}, function(stream) {
|
2013-11-13 00:48:36 +00:00
|
|
|
RWC.contexts[c].videoElement.autoplay = true;
|
|
|
|
RWC.contexts[c].videoElement.src = URL.createObjectURL(stream);
|
|
|
|
RWC.contexts[c].runMode = 2;
|
2013-11-09 05:16:28 +00:00
|
|
|
}, function (err) {
|
|
|
|
console.log("webcam request failed", err);
|
|
|
|
RWC.runMode = 0;
|
|
|
|
});
|
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
// for getting/storing texture id in GL mode
|
|
|
|
if (!RWC.tmp) RWC.tmp = _malloc(4);
|
|
|
|
return c;
|
2013-11-09 05:16:28 +00:00
|
|
|
},
|
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
RWebCamFree: function(data) {
|
|
|
|
RWC.contexts[data].videoElement.pause();
|
|
|
|
URL.revokeObjectURL(RWC.contexts[data].videoElement.src);
|
|
|
|
RWC.contexts[data].videoElement = null;
|
|
|
|
RWC.contexts[data] = null;
|
2013-11-09 05:16:28 +00:00
|
|
|
},
|
|
|
|
|
2013-11-15 02:08:05 +00:00
|
|
|
RWebCamStart__deps: ['glGenTextures', 'glBindTexture', 'glGetIntegerv', 'glTexParameteri', 'malloc'],
|
2013-11-13 00:48:36 +00:00
|
|
|
RWebCamStart: function(data) {
|
|
|
|
var ret = 0;
|
|
|
|
if (RWC.contexts[data].glTex) {
|
|
|
|
_glGenTextures(1, RWC.tmp);
|
|
|
|
RWC.contexts[data].glTexId = {{{ makeGetValue('RWC.tmp', '0', 'i32') }}};
|
|
|
|
if (RWC.contexts[data].glTexId !== 0) {
|
|
|
|
// save previous texture
|
|
|
|
_glGetIntegerv(0x8069 /* GL_TEXTURE_BINDING_2D */, RWC.tmp);
|
|
|
|
var prev = {{{ makeGetValue('RWC.tmp', '0', 'i32') }}};
|
|
|
|
_glBindTexture(0x0DE1 /* GL_TEXTURE_2D */, RWC.contexts[data].glTexId);
|
|
|
|
/* NPOT textures in WebGL must have these filters and clamping settings */
|
|
|
|
_glTexParameteri(0x0DE1 /* GL_TEXTURE_2D */, 0x2800 /* GL_TEXTURE_MAG_FILTER */, 0x2601 /* GL_LINEAR */);
|
|
|
|
_glTexParameteri(0x0DE1 /* GL_TEXTURE_2D */, 0x2801 /* GL_TEXTURE_MIN_FILTER */, 0x2601 /* GL_LINEAR */);
|
|
|
|
_glTexParameteri(0x0DE1 /* GL_TEXTURE_2D */, 0x2802 /* GL_TEXTURE_WRAP_S */, 0x812F /* GL_CLAMP_TO_EDGE */);
|
|
|
|
_glTexParameteri(0x0DE1 /* GL_TEXTURE_2D */, 0x2803 /*GL_TEXTURE_WRAP_T */, 0x812F /* GL_CLAMP_TO_EDGE */);
|
|
|
|
_glBindTexture(0x0DE1 /* GL_TEXTURE_2D */, prev);
|
|
|
|
RWC.contexts[data].glFirstFrame = true;
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
}
|
2013-11-15 02:08:05 +00:00
|
|
|
if (RWC.contexts[data].rawFb) {
|
|
|
|
RWC.contexts[data].rawFbCanvas = document.createElement("canvas");
|
|
|
|
ret = 1;
|
|
|
|
}
|
2013-11-13 00:48:36 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-11-09 05:16:28 +00:00
|
|
|
},
|
|
|
|
|
2013-11-15 02:08:05 +00:00
|
|
|
RWebCamStop__deps: ['glDeleteTextures', 'free'],
|
2013-11-13 00:48:36 +00:00
|
|
|
RWebCamStop: function(data) {
|
|
|
|
if (RWC.contexts[data].glTexId) {
|
|
|
|
_glDeleteTextures(1, RWC.contexts[data].glTexId);
|
|
|
|
}
|
2013-11-15 02:08:05 +00:00
|
|
|
|
|
|
|
if (RWC.contexts[data].rawFbCanvas) {
|
|
|
|
if (RWC.contexts[data].rawBuffer) {
|
|
|
|
_free(RWC.contexts[data].rawBuffer);
|
|
|
|
RWC.contexts[data].rawBuffer = 0;
|
|
|
|
RWC.contexts[data].rawFbCanvasCtx = null
|
|
|
|
}
|
|
|
|
RWC.contexts[data].rawFbCanvas = null;
|
|
|
|
}
|
2013-11-09 05:16:28 +00:00
|
|
|
},
|
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
RWebCamPoll__deps: ['glBindTexture', 'glGetIntegerv'],
|
|
|
|
RWebCamPoll: function(data, frame_raw_cb, frame_gl_cb) {
|
|
|
|
if (!RWC.ready(data)) return 0;
|
|
|
|
var ret = 0;
|
|
|
|
|
|
|
|
if (RWC.contexts[data].glTexId !== 0 && frame_gl_cb !== 0) {
|
|
|
|
_glGetIntegerv(0x8069 /* GL_TEXTURE_BINDING_2D */, RWC.tmp);
|
|
|
|
var prev = {{{ makeGetValue('RWC.tmp', '0', 'i32') }}};
|
|
|
|
_glBindTexture(0x0DE1 /* GL_TEXTURE_2D */, RWC.contexts[data].glTexId);
|
|
|
|
if (RWC.contexts[data].glFirstFrame) {
|
|
|
|
Module.ctx.texImage2D(Module.ctx.TEXTURE_2D, 0, Module.ctx.RGB, Module.ctx.RGB, Module.ctx.UNSIGNED_BYTE, RWC.contexts[data].videoElement);
|
|
|
|
RWC.contexts[data].glFirstFrame = false;
|
|
|
|
} else {
|
|
|
|
Module.ctx.texSubImage2D(Module.ctx.TEXTURE_2D, 0, 0, 0, Module.ctx.RGB, Module.ctx.UNSIGNED_BYTE, RWC.contexts[data].videoElement);
|
|
|
|
}
|
|
|
|
_glBindTexture(0x0DE1 /* GL_TEXTURE_2D */, prev);
|
|
|
|
Runtime.dynCall('viii', frame_gl_cb, [RWC.contexts[data].glTexId, 0x0DE1 /* GL_TEXTURE_2D */, 0]);
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
2013-11-15 02:08:05 +00:00
|
|
|
if (RWC.contexts[data].rawFbCanvas && frame_raw_cb !== 0)
|
|
|
|
{
|
|
|
|
if (!RWC.contexts[data].rawFbCanvasCtx) {
|
|
|
|
RWC.contexts[data].rawFbCanvas.width = RWC.contexts[data].videoElement.videoWidth;
|
|
|
|
RWC.contexts[data].rawFbCanvas.height = RWC.contexts[data].videoElement.videoHeight;
|
|
|
|
RWC.contexts[data].rawFbCanvasCtx = RWC.contexts[data].rawFbCanvas.getContext("2d");
|
|
|
|
RWC.contexts[data].rawBuffer = _malloc(RWC.contexts[data].videoElement.videoWidth * RWC.contexts[data].videoElement.videoHeight * 4);
|
|
|
|
}
|
|
|
|
RWC.contexts[data].rawFbCanvasCtx.drawImage(RWC.contexts[data].videoElement, 0, 0, RWC.contexts[data].rawFbCanvas.width, RWC.contexts[data].rawFbCanvas.height);
|
|
|
|
var image = RWC.contexts[data].rawFbCanvasCtx.getImageData(0, 0, RWC.contexts[data].videoElement.videoWidth, RWC.contexts[data].videoElement.videoHeight);
|
|
|
|
Module.HEAPU8.set(image.data, RWC.contexts[data].rawBuffer);
|
|
|
|
Runtime.dynCall('viiii', frame_raw_cb, [RWC.contexts[data].rawBuffer, RWC.contexts[data].videoElement.videoWidth, RWC.contexts[data].videoElement.videoHeight, RWC.contexts[data].videoElement.videoWidth * 4]);
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
|
2013-11-13 00:48:36 +00:00
|
|
|
return ret;
|
2013-11-09 05:16:28 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
autoAddDeps(LibraryRWebCam, '$RWC');
|
|
|
|
mergeInto(LibraryManager.library, LibraryRWebCam);
|