#include "sdl.h" #include "qjs_macros.h" #include "cell.h" #include "stb_ds.h" #include "qjs_actor.h" #include // 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; )