mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-11 01:24:01 +02:00
3rdParty: apply SDL3 gameboy camera backend patch to mupen64plus-core
This commit is contained in:
@@ -355,9 +355,13 @@ ifeq ($(origin SDL_CFLAGS) $(origin SDL_LDLIBS), undefined undefined)
|
||||
ifeq ($(shell $(PKG_CONFIG) --modversion sdl2 2>/dev/null),)
|
||||
$(error No SDL3 or SDL2 development libraries found!)
|
||||
endif
|
||||
ifeq ($(SDL3_CAMERA), 1)
|
||||
$(error SDL3_CAMERA requires SDL3!)
|
||||
endif
|
||||
SDL_CFLAGS += $(shell $(PKG_CONFIG) --cflags sdl2)
|
||||
SDL_LDLIBS += $(shell $(PKG_CONFIG) --libs sdl2)
|
||||
else
|
||||
SDL3_CAMERA := 1
|
||||
SDL_CFLAGS += -DUSE_SDL3
|
||||
SDL_CFLAGS += $(shell $(PKG_CONFIG) --cflags sdl3)
|
||||
SDL_LDLIBS += $(shell $(PKG_CONFIG) --libs sdl3)
|
||||
@@ -762,6 +766,10 @@ ifeq ($(OPENCV), 1)
|
||||
CFLAGS += -DM64P_OPENCV
|
||||
endif
|
||||
|
||||
ifeq ($(SDL3_CAMERA), 1)
|
||||
SOURCE += $(SRCDIR)/backends/sdl3_video_capture.cpp
|
||||
CFLAGS += -DSDL3_CAMERA
|
||||
endif
|
||||
|
||||
# generate a list of object files to build, make a temporary directory for them
|
||||
OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter $(SRCDIR)/%.c, $(SOURCE)))
|
||||
|
||||
@@ -28,12 +28,18 @@ extern const struct video_capture_backend_interface g_idummy_video_capture_backe
|
||||
#if defined(M64P_OPENCV)
|
||||
extern const struct video_capture_backend_interface g_iopencv_video_capture_backend;
|
||||
#endif
|
||||
#if defined(SDL3_CAMERA)
|
||||
extern const struct video_capture_backend_interface g_isdl3_video_capture_backend;
|
||||
#endif
|
||||
|
||||
|
||||
const struct video_capture_backend_interface* g_video_capture_backend_interfaces[] =
|
||||
{
|
||||
#if defined(M64P_OPENCV)
|
||||
&g_iopencv_video_capture_backend,
|
||||
#endif
|
||||
#if defined(SDL3_CAMERA)
|
||||
&g_isdl3_video_capture_backend,
|
||||
#endif
|
||||
&g_idummy_video_capture_backend,
|
||||
NULL /* sentinel - must be last element */
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#if !defined(DEFAULT_VIDEO_CAPTURE_BACKEND)
|
||||
#if defined(M64P_OPENCV)
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND "opencv"
|
||||
#elif defined(SDL3_CAMERA)
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND "sdl3"
|
||||
#else
|
||||
#define DEFAULT_VIDEO_CAPTURE_BACKEND ""
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - sdl3_video_capture.cpp *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2025 Rosalie Wanders *
|
||||
* *
|
||||
* This program 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 Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
struct sdl3_video_capture
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
SDL_Camera* camera;
|
||||
SDL_CameraID camera_id;
|
||||
|
||||
char* target_camera_name;
|
||||
};
|
||||
|
||||
#include "backends/api/video_capture_backend.h"
|
||||
|
||||
#define M64P_CORE_PROTOTYPES 1
|
||||
#include "api/callbacks.h"
|
||||
#include "api/m64p_types.h"
|
||||
#include "api/m64p_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
const struct video_capture_backend_interface g_isdl3_video_capture_backend;
|
||||
|
||||
static m64p_error sdl3_init(void** vcap, const char* section)
|
||||
{
|
||||
/* initialize data */
|
||||
*vcap = malloc(sizeof(struct sdl3_video_capture));
|
||||
if (*vcap == NULL)
|
||||
{
|
||||
return M64ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(*vcap, 0, sizeof(struct sdl3_video_capture));
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(*vcap);
|
||||
|
||||
if (!SDL_Init(SDL_INIT_CAMERA))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to initialize SDL camera subsystem: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
/* default parameters */
|
||||
const char* device = NULL;
|
||||
|
||||
if (section && strlen(section) > 0)
|
||||
{
|
||||
m64p_handle config = NULL;
|
||||
|
||||
if (ConfigOpenSection(section, &config) != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to open video configuration section: %s, falling back to default video device", section);
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
/* set default parameters */
|
||||
ConfigSetDefaultString(config, "device", "", "Device name to use for capture or empty for default.");
|
||||
|
||||
/* get parameters */
|
||||
device = ConfigGetParamString(config, "device");
|
||||
|
||||
/* fallback to NULL when default value has been used */
|
||||
if (strlen(device) == 0)
|
||||
{
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* store device name for later */
|
||||
if (device != NULL)
|
||||
{
|
||||
sdl->target_camera_name = strdup(device);
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void sdl3_release(void* vcap)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl != NULL)
|
||||
{
|
||||
if (sdl->target_camera_name != NULL)
|
||||
{
|
||||
free(sdl->target_camera_name);
|
||||
}
|
||||
|
||||
free(sdl);
|
||||
}
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_CAMERA))
|
||||
{
|
||||
SDL_QuitSubSystem(SDL_INIT_CAMERA);
|
||||
}
|
||||
}
|
||||
|
||||
static m64p_error sdl3_open(void* vcap, unsigned int width, unsigned int height)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL)
|
||||
{
|
||||
return M64ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
sdl->width = width;
|
||||
sdl->height = height;
|
||||
|
||||
int cameras_count = 0;
|
||||
SDL_CameraID* cameras = SDL_GetCameras(&cameras_count);
|
||||
if (cameras == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to retrieve list of video devices: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
if (cameras_count == 0)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to find video devices");
|
||||
return M64ERR_INPUT_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* fallback to default camera */
|
||||
sdl->camera_id = cameras[0];
|
||||
|
||||
/* print name of every camera to user, and
|
||||
* attempt to find the camera that the user
|
||||
* specified in the config */
|
||||
int found_camera = 0;
|
||||
for (int i = 0; i < cameras_count; i++)
|
||||
{
|
||||
const char* name = SDL_GetCameraName(cameras[i]);
|
||||
if (name == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to retrieve video device name: %s", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Found video device: \"%s\"", name);
|
||||
|
||||
if (sdl->target_camera_name != NULL &&
|
||||
strcmp(sdl->target_camera_name, name) == 0)
|
||||
{
|
||||
sdl->camera_id = cameras[i];
|
||||
found_camera = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* show warning when device was not found */
|
||||
if (sdl->target_camera_name != NULL && found_camera == 0)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Failed to find video device with name \"%s\", falling back to default", sdl->target_camera_name);
|
||||
}
|
||||
|
||||
SDL_free(cameras);
|
||||
|
||||
/* attempt to open camera */
|
||||
sdl->camera = SDL_OpenCamera(sdl->camera_id, NULL);
|
||||
if (sdl->camera == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to open video device: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
/* attempt to get permission for the camera */
|
||||
int permission_state = SDL_GetCameraPermissionState(sdl->camera);
|
||||
if (permission_state == 0)
|
||||
{
|
||||
DebugMessage(M64MSG_INFO, "Waiting until user has approved video access");
|
||||
do
|
||||
{
|
||||
SDL_Delay(250);
|
||||
permission_state = SDL_GetCameraPermissionState(sdl->camera);
|
||||
} while (permission_state == 0);
|
||||
}
|
||||
|
||||
if (permission_state == -1)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to open video device: permission denied");
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Video successfully opened: %s", SDL_GetCameraName(sdl->camera_id));
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
static void sdl3_close(void* vcap)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sdl->camera != NULL)
|
||||
{
|
||||
SDL_CloseCamera(sdl->camera);
|
||||
}
|
||||
|
||||
DebugMessage(M64MSG_INFO, "Video closed");
|
||||
}
|
||||
|
||||
static m64p_error sdl3_grab_image(void* vcap, void* data)
|
||||
{
|
||||
struct sdl3_video_capture* sdl = (struct sdl3_video_capture*)(vcap);
|
||||
if (sdl == NULL || sdl->camera == NULL)
|
||||
{
|
||||
return M64ERR_NOT_INIT;
|
||||
}
|
||||
|
||||
SDL_Surface* frame_surface = SDL_AcquireCameraFrame(sdl->camera, NULL);
|
||||
if (frame_surface == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to grab video frame: %s", SDL_GetError());
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
SDL_Surface* target_surface = SDL_CreateSurface(sdl->width, sdl->height, SDL_PIXELFORMAT_BGR24);
|
||||
if (target_surface == NULL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to create target surface: %s\n", SDL_GetError());
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
int frame_size = SDL_min(frame_surface->w, frame_surface->h);
|
||||
SDL_Rect frame_rect;
|
||||
frame_rect.x = (frame_surface->w / 2) - (frame_size / 2);
|
||||
frame_rect.y = 0;
|
||||
frame_rect.w = frame_size;
|
||||
frame_rect.h = frame_size;
|
||||
|
||||
if (!SDL_BlitSurfaceScaled(frame_surface, &frame_rect, target_surface, NULL, SDL_SCALEMODE_NEAREST))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "Failed to blit surface: %s", SDL_GetError());
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
SDL_DestroySurface(target_surface);
|
||||
return M64ERR_SYSTEM_FAIL;
|
||||
}
|
||||
|
||||
memcpy(data, target_surface->pixels, target_surface->w * target_surface->h * 3);
|
||||
|
||||
SDL_ReleaseCameraFrame(sdl->camera, frame_surface);
|
||||
SDL_DestroySurface(target_surface);
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const struct video_capture_backend_interface g_isdl3_video_capture_backend =
|
||||
{
|
||||
"sdl3",
|
||||
sdl3_init,
|
||||
sdl3_release,
|
||||
sdl3_open,
|
||||
sdl3_close,
|
||||
sdl3_grab_image
|
||||
};
|
||||
|
||||
@@ -715,6 +715,9 @@ static void init_pocket_cam(struct pocket_cam* cam, uint8_t* ram, void* vcap, co
|
||||
|
||||
cam->vcap = vcap;
|
||||
cam->ivcap = ivcap;
|
||||
|
||||
/* open video device */
|
||||
cam->ivcap->open(cam->vcap, M64282FP_SENSOR_W, M64282FP_SENSOR_H);
|
||||
}
|
||||
|
||||
static void poweron_pocket_cam(struct pocket_cam* cam)
|
||||
|
||||
+1
-4
@@ -1704,10 +1704,7 @@ m64p_error main_run(void)
|
||||
|
||||
/* init GbCamera backend specified in the configuration file */
|
||||
init_video_capture_backend(&igbcam_backend, &gbcam_backend,
|
||||
g_CoreConfig, "GbCameraVideoCaptureBackend1");
|
||||
|
||||
/* open GB cam video device */
|
||||
igbcam_backend->open(gbcam_backend, M64282FP_SENSOR_W, M64282FP_SENSOR_H);
|
||||
g_CoreConfig, "GbCameraVideoCaptureBackend1");
|
||||
|
||||
/* open storage files, provide default content if not present */
|
||||
open_mpk_file(&mpk);
|
||||
|
||||
Reference in New Issue
Block a user