285 lines
8.9 KiB
C
285 lines
8.9 KiB
C
#include "qjs_sdl.h"
|
|
#include "qjs_macros.h"
|
|
#include "cell.h"
|
|
#include "stb_ds.h"
|
|
#include "qjs_actor.h"
|
|
#include "qjs_sdl_surface.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
// SDL Free functions
|
|
void SDL_Camera_free(JSRuntime *rt, SDL_Camera *cam)
|
|
{
|
|
SDL_CloseCamera(cam);
|
|
}
|
|
|
|
// Class definitions for SDL types
|
|
QJSCLASS(SDL_Camera,)
|
|
|
|
|
|
// CAMERA FUNCTIONS
|
|
|
|
// Pixel format enum conversion using the new system
|
|
ENUM_MAPPING_TABLE(SDL_PixelFormat) = {
|
|
{SDL_PIXELFORMAT_UNKNOWN, "unknown"},
|
|
{SDL_PIXELFORMAT_INDEX1LSB, "index1lsb"},
|
|
{SDL_PIXELFORMAT_INDEX1MSB, "index1msb"},
|
|
{SDL_PIXELFORMAT_INDEX2LSB, "index2lsb"},
|
|
{SDL_PIXELFORMAT_INDEX2MSB, "index2msb"},
|
|
{SDL_PIXELFORMAT_INDEX4LSB, "index4lsb"},
|
|
{SDL_PIXELFORMAT_INDEX4MSB, "index4msb"},
|
|
{SDL_PIXELFORMAT_INDEX8, "index8"},
|
|
{SDL_PIXELFORMAT_RGB332, "rgb332"},
|
|
{SDL_PIXELFORMAT_XRGB4444, "xrgb4444"},
|
|
{SDL_PIXELFORMAT_XBGR4444, "xbgr4444"},
|
|
{SDL_PIXELFORMAT_XRGB1555, "xrgb1555"},
|
|
{SDL_PIXELFORMAT_XBGR1555, "xbgr1555"},
|
|
{SDL_PIXELFORMAT_ARGB4444, "argb4444"},
|
|
{SDL_PIXELFORMAT_RGBA4444, "rgba4444"},
|
|
{SDL_PIXELFORMAT_ABGR4444, "abgr4444"},
|
|
{SDL_PIXELFORMAT_BGRA4444, "bgra4444"},
|
|
{SDL_PIXELFORMAT_ARGB1555, "argb1555"},
|
|
{SDL_PIXELFORMAT_RGBA5551, "rgba5551"},
|
|
{SDL_PIXELFORMAT_ABGR1555, "abgr1555"},
|
|
{SDL_PIXELFORMAT_BGRA5551, "bgra5551"},
|
|
{SDL_PIXELFORMAT_RGB565, "rgb565"},
|
|
{SDL_PIXELFORMAT_BGR565, "bgr565"},
|
|
{SDL_PIXELFORMAT_RGB24, "rgb24"},
|
|
{SDL_PIXELFORMAT_BGR24, "bgr24"},
|
|
{SDL_PIXELFORMAT_XRGB8888, "xrgb8888"},
|
|
{SDL_PIXELFORMAT_RGBX8888, "rgbx8888"},
|
|
{SDL_PIXELFORMAT_XBGR8888, "xbgr8888"},
|
|
{SDL_PIXELFORMAT_BGRX8888, "bgrx8888"},
|
|
{SDL_PIXELFORMAT_ARGB8888, "argb8888"},
|
|
{SDL_PIXELFORMAT_RGBA8888, "rgba8888"},
|
|
{SDL_PIXELFORMAT_ABGR8888, "abgr8888"},
|
|
{SDL_PIXELFORMAT_BGRA8888, "bgra8888"},
|
|
{SDL_PIXELFORMAT_XRGB2101010, "xrgb2101010"},
|
|
{SDL_PIXELFORMAT_XBGR2101010, "xbgr2101010"},
|
|
{SDL_PIXELFORMAT_ARGB2101010, "argb2101010"},
|
|
{SDL_PIXELFORMAT_ABGR2101010, "abgr2101010"},
|
|
{SDL_PIXELFORMAT_RGB48, "rgb48"},
|
|
{SDL_PIXELFORMAT_BGR48, "bgr48"},
|
|
{SDL_PIXELFORMAT_RGBA64, "rgba64"},
|
|
{SDL_PIXELFORMAT_ARGB64, "argb64"},
|
|
{SDL_PIXELFORMAT_BGRA64, "bgra64"},
|
|
{SDL_PIXELFORMAT_ABGR64, "abgr64"},
|
|
{SDL_PIXELFORMAT_RGB48_FLOAT, "rgb48_float"},
|
|
{SDL_PIXELFORMAT_BGR48_FLOAT, "bgr48_float"},
|
|
{SDL_PIXELFORMAT_RGBA64_FLOAT, "rgba64_float"},
|
|
{SDL_PIXELFORMAT_ARGB64_FLOAT, "argb64_float"},
|
|
{SDL_PIXELFORMAT_BGRA64_FLOAT, "bgra64_float"},
|
|
{SDL_PIXELFORMAT_ABGR64_FLOAT, "abgr64_float"},
|
|
{SDL_PIXELFORMAT_RGB96_FLOAT, "rgb96_float"},
|
|
{SDL_PIXELFORMAT_BGR96_FLOAT, "bgr96_float"},
|
|
{SDL_PIXELFORMAT_RGBA128_FLOAT, "rgba128_float"},
|
|
{SDL_PIXELFORMAT_ARGB128_FLOAT, "argb128_float"},
|
|
{SDL_PIXELFORMAT_BGRA128_FLOAT, "bgra128_float"},
|
|
{SDL_PIXELFORMAT_ABGR128_FLOAT, "abgr128_float"},
|
|
{SDL_PIXELFORMAT_YV12, "yv12"},
|
|
{SDL_PIXELFORMAT_IYUV, "iyuv"},
|
|
{SDL_PIXELFORMAT_YUY2, "yuy2"},
|
|
{SDL_PIXELFORMAT_UYVY, "uyvy"},
|
|
{SDL_PIXELFORMAT_YVYU, "yvyu"},
|
|
{SDL_PIXELFORMAT_NV12, "nv12"},
|
|
{SDL_PIXELFORMAT_NV21, "nv21"},
|
|
{SDL_PIXELFORMAT_P010, "p010"},
|
|
{SDL_PIXELFORMAT_RGBA32, "rgba32"}
|
|
};
|
|
JS2ENUM(SDL_PixelFormat)
|
|
|
|
static JSValue cameraspec2js(JSContext *js, const SDL_CameraSpec *spec) {
|
|
JSValue obj = JS_NewObject(js);
|
|
|
|
JS_SetPropertyStr(js, obj, "format", SDL_PixelFormat2js(js, spec->format));
|
|
JS_SetPropertyStr(js, obj, "colorspace", JS_NewInt32(js, spec->colorspace));
|
|
JS_SetPropertyStr(js, obj, "width", JS_NewInt32(js, spec->width));
|
|
JS_SetPropertyStr(js, obj, "height", JS_NewInt32(js, spec->height));
|
|
JS_SetPropertyStr(js, obj, "framerate_numerator", JS_NewInt32(js, spec->framerate_numerator));
|
|
JS_SetPropertyStr(js, obj, "framerate_denominator", JS_NewInt32(js, spec->framerate_denominator));
|
|
|
|
return obj;
|
|
}
|
|
|
|
static SDL_CameraSpec js2cameraspec(JSContext *js, JSValue obj) {
|
|
SDL_CameraSpec spec = {0};
|
|
|
|
JSValue v;
|
|
|
|
v = JS_GetPropertyStr(js, obj, "format");
|
|
if (!JS_IsNull(v)) {
|
|
spec.format = js2SDL_PixelFormat(js, v);
|
|
}
|
|
JS_FreeValue(js, v);
|
|
|
|
v = JS_GetPropertyStr(js, obj, "colorspace");
|
|
if (!JS_IsNull(v)) JS_ToInt32(js, &spec.colorspace, v);
|
|
JS_FreeValue(js, v);
|
|
|
|
v = JS_GetPropertyStr(js, obj, "width");
|
|
if (!JS_IsNull(v)) JS_ToInt32(js, &spec.width, v);
|
|
JS_FreeValue(js, v);
|
|
|
|
v = JS_GetPropertyStr(js, obj, "height");
|
|
if (!JS_IsNull(v)) JS_ToInt32(js, &spec.height, v);
|
|
JS_FreeValue(js, v);
|
|
|
|
v = JS_GetPropertyStr(js, obj, "framerate_numerator");
|
|
if (!JS_IsNull(v)) JS_ToInt32(js, &spec.framerate_numerator, v);
|
|
JS_FreeValue(js, v);
|
|
|
|
v = JS_GetPropertyStr(js, obj, "framerate_denominator");
|
|
if (!JS_IsNull(v)) JS_ToInt32(js, &spec.framerate_denominator, v);
|
|
JS_FreeValue(js, v);
|
|
|
|
return spec;
|
|
}
|
|
|
|
JSC_CCALL(camera_list,
|
|
int num;
|
|
JSValue jsids = JS_NewArray(js);
|
|
SDL_CameraID *ids = SDL_GetCameras(&num);
|
|
for (int i = 0; i < num; i++)
|
|
JS_SetPropertyUint32(js,jsids, i, number2js(js,ids[i]));
|
|
|
|
return jsids;
|
|
)
|
|
|
|
JSC_CCALL(camera_open,
|
|
int id = js2number(js,argv[0]);
|
|
SDL_CameraSpec *spec_ptr = NULL;
|
|
SDL_CameraSpec spec;
|
|
|
|
// Check if a format spec was provided
|
|
if (argc > 1 && !JS_IsNull(argv[1])) {
|
|
spec = js2cameraspec(js, argv[1]);
|
|
spec_ptr = &spec;
|
|
}
|
|
|
|
SDL_Camera *cam = SDL_OpenCamera(id, spec_ptr);
|
|
if (!cam) ret = JS_ThrowReferenceError(js, "Could not open camera %d: %s\n", id, SDL_GetError());
|
|
else
|
|
ret = SDL_Camera2js(js,cam);
|
|
)
|
|
|
|
JSC_CCALL(camera_name,
|
|
const char *name = SDL_GetCameraName(js2number(js,argv[0]));
|
|
if (!name) return JS_ThrowReferenceError(js, "Could not get camera name from id %d.", (int)js2number(js,argv[0]));
|
|
|
|
return JS_NewString(js, name);
|
|
)
|
|
|
|
JSC_CCALL(camera_position,
|
|
SDL_CameraPosition pos = SDL_GetCameraPosition(js2number(js,argv[0]));
|
|
switch(pos) {
|
|
case SDL_CAMERA_POSITION_UNKNOWN: return JS_NewString(js,"unknown");
|
|
case SDL_CAMERA_POSITION_FRONT_FACING: return JS_NewString(js,"front");
|
|
case SDL_CAMERA_POSITION_BACK_FACING: return JS_NewString(js,"back");
|
|
}
|
|
)
|
|
|
|
JSC_CCALL(camera_drivers,
|
|
int num = SDL_GetNumCameraDrivers();
|
|
JSValue arr = JS_NewArray(js);
|
|
for (int i = 0; i < num; i++)
|
|
JS_SetPropertyUint32(js, arr, i, JS_NewString(js, SDL_GetCameraDriver(i)));
|
|
return arr;
|
|
)
|
|
|
|
JSC_CCALL(camera_supported_formats,
|
|
SDL_CameraID id = js2number(js,argv[0]);
|
|
int num;
|
|
SDL_CameraSpec **specs = SDL_GetCameraSupportedFormats(id, &num);
|
|
|
|
if (!specs)
|
|
return JS_ThrowReferenceError(js, "Could not get supported formats for camera %d: %s", id, SDL_GetError());
|
|
|
|
JSValue arr = JS_NewArray(js);
|
|
for (int i = 0; i < num; i++) {
|
|
JS_SetPropertyUint32(js, arr, i, cameraspec2js(js, specs[i]));
|
|
}
|
|
|
|
SDL_free(specs);
|
|
return arr;
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_camera_funcs[] = {
|
|
MIST_FUNC_DEF(camera, list, 0),
|
|
MIST_FUNC_DEF(camera, open, 2),
|
|
MIST_FUNC_DEF(camera, name, 1),
|
|
MIST_FUNC_DEF(camera, position, 1),
|
|
MIST_FUNC_DEF(camera, drivers, 0),
|
|
MIST_FUNC_DEF(camera, supported_formats, 1),
|
|
};
|
|
|
|
JSC_CCALL(camera_capture,
|
|
SDL_ClearError();
|
|
SDL_Camera *cam = js2SDL_Camera(js,self);
|
|
if (!cam) return JS_ThrowReferenceError(js,"Self was not a camera: %s", SDL_GetError());
|
|
|
|
SDL_Surface *surf = SDL_AcquireCameraFrame(cam, NULL);
|
|
if (!surf) {
|
|
const char *msg = SDL_GetError();
|
|
if (msg[0] != 0)
|
|
return JS_ThrowReferenceError(js,"Could not get camera frame: %s", SDL_GetError());
|
|
else return JS_NULL;
|
|
}
|
|
|
|
// Create a copy of the surface
|
|
SDL_Surface *newsurf = SDL_CreateSurface(surf->w, surf->h, surf->format);
|
|
|
|
if (!newsurf) {
|
|
SDL_ReleaseCameraFrame(cam, surf);
|
|
return JS_ThrowReferenceError(js, "Could not create surface: %s", SDL_GetError());
|
|
}
|
|
|
|
// Copy the surface data
|
|
int result = SDL_BlitSurface(surf, NULL, newsurf, NULL);
|
|
|
|
// Release the camera frame
|
|
SDL_ReleaseCameraFrame(cam, surf);
|
|
|
|
if (result != 0) {
|
|
SDL_DestroySurface(newsurf);
|
|
return JS_ThrowReferenceError(js, "Could not blit surface: %s", SDL_GetError());
|
|
}
|
|
|
|
return SDL_Surface2js(js,newsurf);
|
|
)
|
|
|
|
JSC_CCALL(camera_get_driver,
|
|
SDL_Camera *cam = js2SDL_Camera(js,self);
|
|
if (!cam) return JS_ThrowReferenceError(js,"Self was not a camera: %s", SDL_GetError());
|
|
|
|
const char *driver = SDL_GetCurrentCameraDriver();
|
|
if (!driver) return JS_NULL;
|
|
|
|
return JS_NewString(js, driver);
|
|
)
|
|
|
|
JSC_CCALL(camera_get_format,
|
|
SDL_Camera *cam = js2SDL_Camera(js,self);
|
|
if (!cam) return JS_ThrowReferenceError(js,"Self was not a camera: %s", SDL_GetError());
|
|
|
|
SDL_CameraSpec spec;
|
|
if (!SDL_GetCameraFormat(cam, &spec))
|
|
return JS_ThrowReferenceError(js, "Could not get camera format: %s", SDL_GetError());
|
|
|
|
return cameraspec2js(js, &spec);
|
|
)
|
|
|
|
static const JSCFunctionListEntry js_SDL_Camera_funcs[] =
|
|
{
|
|
MIST_FUNC_DEF(camera, capture, 0),
|
|
MIST_FUNC_DEF(camera, get_driver, 0),
|
|
MIST_FUNC_DEF(camera, get_format, 0),
|
|
};
|
|
|
|
CELL_USE_INIT(
|
|
SDL_Init(SDL_INIT_CAMERA);
|
|
JSValue mod = JS_NewObject(js);
|
|
JS_SetPropertyFunctionList(js,mod,js_camera_funcs,countof(js_camera_funcs));
|
|
QJSCLASSPREP_FUNCS(SDL_Camera)
|
|
return mod;
|
|
)
|