mirror of
https://github.com/libretro/RetroArch
synced 2025-02-21 09:39:56 +00:00
move prototype camera interface to libretro interface - GL texture only for now
This commit is contained in:
parent
4b7557c5ae
commit
aaff8f2648
@ -39,7 +39,8 @@ OBJ = frontend/frontend_emscripten.o \
|
|||||||
audio/sinc.o \
|
audio/sinc.o \
|
||||||
audio/null.o \
|
audio/null.o \
|
||||||
performance.o \
|
performance.o \
|
||||||
core_info.o
|
core_info.o \
|
||||||
|
camera/rwebcam.o
|
||||||
|
|
||||||
HAVE_OPENGL = 1
|
HAVE_OPENGL = 1
|
||||||
HAVE_RGUI = 1
|
HAVE_RGUI = 1
|
||||||
@ -58,8 +59,8 @@ endif
|
|||||||
libretro = libretro_emscripten.bc
|
libretro = libretro_emscripten.bc
|
||||||
|
|
||||||
LIBS = -lm
|
LIBS = -lm
|
||||||
DEFINES = -DHAVE_SCREENSHOTS -DHAVE_NULLAUDIO -DHAVE_BSV_MOVIE
|
DEFINES = -DHAVE_SCREENSHOTS -DHAVE_CAMERA -DHAVE_NULLAUDIO -DHAVE_BSV_MOVIE
|
||||||
LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) -s OUTLINING_LIMIT=50000 --js-library emscripten/library_rwebaudio.js --js-library emscripten/library_rwebinput.js --no-heap-copy
|
LDFLAGS = -L. -s TOTAL_MEMORY=$(MEMORY) -s OUTLINING_LIMIT=50000 --js-library emscripten/library_rwebaudio.js --js-library emscripten/library_rwebinput.js --js-library emscripten/library_rwebcam.js --no-heap-copy
|
||||||
|
|
||||||
ifeq ($(PERF_TEST), 1)
|
ifeq ($(PERF_TEST), 1)
|
||||||
DEFINES += -DPERF_TEST
|
DEFINES += -DPERF_TEST
|
||||||
|
53
camera/rwebcam.c
Normal file
53
camera/rwebcam.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../driver.h"
|
||||||
|
#include "../emscripten/RWebCam.h"
|
||||||
|
|
||||||
|
static void *rwebcam_init(const char *device, uint64_t caps, unsigned width, unsigned height)
|
||||||
|
{
|
||||||
|
(void)device;
|
||||||
|
return RWebCamInit(caps, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwebcam_free(void *data)
|
||||||
|
{
|
||||||
|
RWebCamFree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rwebcam_start(void *data)
|
||||||
|
{
|
||||||
|
return RWebCamStart(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rwebcam_stop(void *data)
|
||||||
|
{
|
||||||
|
RWebCamStop(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rwebcam_poll(void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb,
|
||||||
|
retro_camera_frame_opengl_texture_t frame_gl_cb)
|
||||||
|
{
|
||||||
|
return RWebCamPoll(data, frame_raw_cb, frame_gl_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
const camera_driver_t camera_rwebcam = {
|
||||||
|
rwebcam_init,
|
||||||
|
rwebcam_free,
|
||||||
|
rwebcam_start,
|
||||||
|
rwebcam_stop,
|
||||||
|
rwebcam_poll,
|
||||||
|
"rwebcam",
|
||||||
|
};
|
@ -82,6 +82,7 @@ enum
|
|||||||
INPUT_NULL,
|
INPUT_NULL,
|
||||||
|
|
||||||
CAMERA_V4L2,
|
CAMERA_V4L2,
|
||||||
|
CAMERA_RWEBCAM,
|
||||||
CAMERA_NULL,
|
CAMERA_NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,6 +184,8 @@ enum
|
|||||||
|
|
||||||
#if defined(HAVE_V4L2)
|
#if defined(HAVE_V4L2)
|
||||||
#define CAMERA_DEFAULT_DRIVER CAMERA_V4L2
|
#define CAMERA_DEFAULT_DRIVER CAMERA_V4L2
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
#define CAMERA_DEFAULT_DRIVER CAMERA_RWEBCAM
|
||||||
#else
|
#else
|
||||||
#define CAMERA_DEFAULT_DRIVER CAMERA_NULL
|
#define CAMERA_DEFAULT_DRIVER CAMERA_NULL
|
||||||
#endif
|
#endif
|
||||||
|
3
driver.c
3
driver.c
@ -183,6 +183,9 @@ static const input_driver_t *input_drivers[] = {
|
|||||||
static const camera_driver_t *camera_drivers[] = {
|
static const camera_driver_t *camera_drivers[] = {
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
&camera_v4l2,
|
&camera_v4l2,
|
||||||
|
#endif
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
&camera_rwebcam,
|
||||||
#endif
|
#endif
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
1
driver.h
1
driver.h
@ -612,6 +612,7 @@ extern const input_driver_t input_qnx;
|
|||||||
extern const input_driver_t input_rwebinput;
|
extern const input_driver_t input_rwebinput;
|
||||||
extern const input_driver_t input_null;
|
extern const input_driver_t input_null;
|
||||||
extern const camera_driver_t camera_v4l2;
|
extern const camera_driver_t camera_v4l2;
|
||||||
|
extern const camera_driver_t camera_rwebcam;
|
||||||
extern const input_osk_driver_t input_ps3_osk;
|
extern const input_osk_driver_t input_ps3_osk;
|
||||||
|
|
||||||
#include "driver_funcs.h"
|
#include "driver_funcs.h"
|
||||||
|
24
emscripten/RWebCam.h
Normal file
24
emscripten/RWebCam.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* RetroArch - A frontend for libretro.
|
||||||
|
* Copyright (C) 2010-2013 - Michael Lelli
|
||||||
|
*
|
||||||
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "../driver.h"
|
||||||
|
|
||||||
|
void *RWebCamInit(uint64_t caps, unsigned width, unsigned height);
|
||||||
|
void RWebCamFree(void *data);
|
||||||
|
bool RWebCamStart(void *data);
|
||||||
|
void RWebCamStop(void *data);
|
||||||
|
bool RWebCamPoll(void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb, retro_camera_frame_opengl_texture_t frame_gl_cb);
|
@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
var LibraryRWebCam = {
|
var LibraryRWebCam = {
|
||||||
$RWC: {
|
$RWC: {
|
||||||
/*
|
RETRO_CAMERA_BUFFER_OPENGL_TEXTURE: 0,
|
||||||
run modes:
|
RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER: 1,
|
||||||
0: not running
|
tmp: null,
|
||||||
1: waiting for user to confirm webcam
|
|
||||||
2: running
|
contexts: [],
|
||||||
*/
|
counter: 0,
|
||||||
runMode: 0,
|
|
||||||
videoElement: null
|
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;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
RWebCamInit: function() {
|
RWebCamInit__deps: ['malloc'],
|
||||||
RWC.runMode = 0;
|
RWebCamInit: function(caps1, caps2, width, height) {
|
||||||
|
|
||||||
if (!navigator) return 0;
|
if (!navigator) return 0;
|
||||||
|
|
||||||
navigator.getMedia = navigator.getUserMedia ||
|
navigator.getMedia = navigator.getUserMedia ||
|
||||||
@ -24,47 +25,93 @@ var LibraryRWebCam = {
|
|||||||
|
|
||||||
if (!navigator.getMedia) return 0;
|
if (!navigator.getMedia) return 0;
|
||||||
|
|
||||||
RWC.videoElement = document.createElement("video");
|
var c = ++RWC.counter;
|
||||||
|
|
||||||
RWC.runMode = 1;
|
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);
|
||||||
|
|
||||||
navigator.getMedia({video: true, audio: false}, function(stream) {
|
navigator.getMedia({video: true, audio: false}, function(stream) {
|
||||||
RWC.videoElement.autoplay = true;
|
RWC.contexts[c].videoElement.autoplay = true;
|
||||||
RWC.videoElement.src = URL.createObjectURL(stream);
|
RWC.contexts[c].videoElement.src = URL.createObjectURL(stream);
|
||||||
RWC.runMode = 2;
|
RWC.contexts[c].runMode = 2;
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
console.log("webcam request failed", err);
|
console.log("webcam request failed", err);
|
||||||
RWC.runMode = 0;
|
RWC.runMode = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return 1;
|
// for getting/storing texture id in GL mode
|
||||||
|
if (!RWC.tmp) RWC.tmp = _malloc(4);
|
||||||
|
return c;
|
||||||
},
|
},
|
||||||
|
|
||||||
RWebCamTexImage2D__deps: ['RWebCamReady'],
|
RWebCamFree: function(data) {
|
||||||
RWebCamTexImage2D: function(width, height) {
|
RWC.contexts[data].videoElement.pause();
|
||||||
if (!_RWebCamReady()) return 0;
|
URL.revokeObjectURL(RWC.contexts[data].videoElement.src);
|
||||||
|
RWC.contexts[data].videoElement = null;
|
||||||
Module.ctx.texImage2D(Module.ctx.TEXTURE_2D, 0, Module.ctx.RGB, Module.ctx.RGB, Module.ctx.UNSIGNED_BYTE, RWC.videoElement);
|
RWC.contexts[data] = null;
|
||||||
|
|
||||||
if (width) {{{ makeSetValue('width', '0', 'RWC.videoElement.videoWidth', 'i32') }}};
|
|
||||||
if (height) {{{ makeSetValue('height', '0', 'RWC.videoElement.videoHeight', 'i32') }}};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
RWebCamTexSubImage2D__deps: ['RWebCamReady'],
|
RWebCamStart__deps: ['glGenTextures', 'glBindTexture', 'glGetIntegerv', 'glTexParameteri'],
|
||||||
RWebCamTexSubImage2D: function(x, y) {
|
RWebCamStart: function(data) {
|
||||||
if (!_RWebCamReady()) return 0;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Module.ctx.texSubImage2D(Module.ctx.TEXTURE_2D, 0, x, y, Module.ctx.RGB, Module.ctx.UNSIGNED_BYTE, RWC.videoElement);
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
RWebCamReady: function() {
|
RWebCamStop__deps: ['glDeleteTextures'],
|
||||||
return (RWC.runMode == 2 && !RWC.videoElement.paused && RWC.videoElement.videoWidth != 0 && RWC.videoElement.videoHeight != 0) ? 1 : 0;
|
RWebCamStop: function(data) {
|
||||||
|
if (RWC.contexts[data].glTexId) {
|
||||||
|
_glDeleteTextures(1, RWC.contexts[data].glTexId);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
RWebCamFree: function() {
|
RWebCamPoll__deps: ['glBindTexture', 'glGetIntegerv'],
|
||||||
RWC.videoElement.pause();
|
RWebCamPoll: function(data, frame_raw_cb, frame_gl_cb) {
|
||||||
RWC.videoElement = null;
|
if (!RWC.ready(data)) return 0;
|
||||||
RWC.runMode = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
#include "../file.h"
|
#include "../file.h"
|
||||||
#include "../emscripten/RWebAudio.h"
|
#include "../emscripten/RWebAudio.h"
|
||||||
|
|
||||||
#ifdef HAVE_RGUI
|
#ifdef HAVE_MENU
|
||||||
#include "../frontend/menu/rgui.h"
|
#include "../frontend/menu/menu_common.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool menuloop;
|
static bool menuloop;
|
||||||
|
@ -155,6 +155,8 @@ const char *config_get_default_camera(void)
|
|||||||
{
|
{
|
||||||
case CAMERA_V4L2:
|
case CAMERA_V4L2:
|
||||||
return "video4linux2";
|
return "video4linux2";
|
||||||
|
case CAMERA_RWEBCAM:
|
||||||
|
return "rwebcam";
|
||||||
case CAMERA_NULL:
|
case CAMERA_NULL:
|
||||||
return "null";
|
return "null";
|
||||||
default:
|
default:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user