This commit is contained in:
2024-12-03 22:33:30 -06:00
parent edc29cc28c
commit 92e07b3018
10 changed files with 370 additions and 133 deletions

View File

@@ -11,6 +11,7 @@ endif
add_project_arguments('-Wno-incompatible-pointer-types', language: 'c')
add_project_arguments('-Wno-narrowing', language: 'cpp')
add_project_arguments('-Wno-missing-braces', language:'c')
deps = []
@@ -73,6 +74,8 @@ deps += dependency('qjs-soloud',static:true)
deps += dependency('sdl3')
deps += dependency('physfs',static:true)
deps += dependency('opencv')
deps += dependency('threads')
if get_option('chipmunk')
@@ -84,7 +87,7 @@ if get_option('enet')
endif
sources = []
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c','texture.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c']
src += ['anim.c', 'config.c', 'datastream.c','font.c','gameobject.c','HandmadeMath.c','jsffi.c','model.c','render.c','script.c','simplex.c','spline.c','texture.c', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c', 'cv.cpp']
imsrc = ['GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp','imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp','implot_items.cpp','implot.cpp']
@@ -132,4 +135,4 @@ prosperon_dep = declare_dependency(
link_with:prosperon
)
test('sanity', prosperon)
test('sanity', prosperon)

View File

@@ -192,8 +192,8 @@ clay.image = function image(path, ...configs)
clay.text = function text(str, ...configs)
{
var config = rectify_configs(configs);
var tsize = render.text_size(str, config.font);
config.size ??= [0,0];
var tsize = render.text_size(str, config.font, 0, 0, config.size.x);
config.size = config.size.map((x,i) => Math.max(x, tsize[i]));
config.text = str;
add_item(config);
@@ -245,7 +245,7 @@ layout.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos)
render.rectangle(boundingbox, config.background_color);
if (config.text)
render.text(config.text, content, config.font, config.font_size, config.color);
render.text(config.text, content, config.font, config.font_size, config.color, config.size.x);
if (config.image)
render.image(config.image, content, 0, config.color);
}

View File

@@ -89,7 +89,7 @@ prosperon.init = function () {
prosperon.camera.mode = "keep";
prosperon.camera.break = "fit";
prosperon.camera.size = game.size;
shape.quad = {
/* shape.quad = {
pos: os.make_buffer([
0, 0, 0,
0, 1, 0,
@@ -111,7 +111,7 @@ prosperon.init = function () {
verts: 3,
count: 3,
index: os.make_buffer([0, 1, 2], 1),
};
};*/
if (io.exists("game.js")) global.app = actor.spawn("game.js");
else global.app = actor.spawn("nogame.js");
};
@@ -299,7 +299,10 @@ game.is_image = function(obj)
// Any request to it returns an image, which is a texture and rect. But they can
game.texture = function texture(path) {
if (typeof path !== 'string') throw new Error('need a string for game.texture')
if (typeof path !== 'string') {
return path;
throw new Error('need a string for game.texture')
}
var parts = path.split(':');
path = Resources.find_image(parts[0]);

View File

@@ -864,7 +864,7 @@ render.rectangle = function render_rectangle(rect, color = Color.white, shader =
render._main.fillrect(rect,color);
};
render.text = function text(str, rect, font = cur_font, size = 0, color = Color.white, wrap = -1, ) {
render.text = function text(str, rect, font = cur_font, size = 0, color = Color.white, wrap = 0) {
if (typeof font === 'string')
font = render.get_font(font)
var mesh = os.make_text_buffer(str, rect, 0, color, wrap, font);
@@ -885,11 +885,11 @@ render.text = function text(str, rect, font = cur_font, size = 0, color = Color.
};
var tttsize = render.text_size;
render.text_size = function(str, font)
render.text_size = function(str, font, ...args)
{
if (typeof font === 'string')
font = render.get_font(font);
return tttsize(str,font);
return tttsize(str,font, ...args);
}
var lasttex = undefined;

View File

@@ -301,7 +301,7 @@ Cmdline.register_order(
if (io.exists("config.js")) global.mixin("config.js");
else console.warn("No config.js file found. Starting with default parameters.");
var window = game.engine_start(prosperon);
var renderer = window.make_renderer("gpu");
var renderer = window.make_renderer("vulkan");
render._main = renderer;
prosperon.init();

151
source/cv.cpp Normal file
View File

@@ -0,0 +1,151 @@
#include "cv.hpp"
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
cv::Mat SDL_SurfaceToMat(SDL_Surface* surface) {
if (!surface) {
throw std::invalid_argument("SDL_Surface pointer is null.");
}
// Convert the surface to a known pixel format (e.g., RGBA32)
// SDL_Surface* convertedSurface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
// if (!convertedSurface) {
// throw std::runtime_error("Failed to convert SDL_Surface to RGBA32 format.");
// }
// Create a cv::Mat with the same size and type
cv::Mat mat(surface->h, surface->w, CV_8UC4, surface->pixels, surface->pitch);
// Convert RGBA to BGR
cv::Mat matBGR;
cv::cvtColor(mat, matBGR, cv::COLOR_RGBA2BGR);
// Free the converted surface
// SDL_DestroySurface(convertedSurface);
return matBGR;
}
cv::Mat SDL_SurfaceToMat_YUY2(SDL_Surface* surface) {
if (!surface) {
throw std::invalid_argument("SDL_Surface pointer is null.");
}
// Ensure the surface format is YUY2
if (surface->format!= SDL_PIXELFORMAT_YUY2) {
throw std::runtime_error("SDL_Surface is not in YUY2 format.");
}
// Create a cv::Mat with the raw data from the SDL_Surface
// YUY2 format has 2 bytes per pixel
cv::Mat yuy2Mat(surface->h, surface->w, CV_8UC2, surface->pixels, surface->pitch);
// Convert YUY2 to BGR format
cv::Mat bgrMat;
cv::cvtColor(yuy2Mat, bgrMat, cv::COLOR_YUV2BGR_YUY2);
return bgrMat;
}
// Function to perform feature matching
extern "C" {bool detectImageInWebcam(SDL_Surface* webcamSurface, SDL_Surface* targetSurface, double matchThreshold = 10.0) {
// Convert SDL_Surface to cv::Mat
cv::Mat webcamMat = SDL_SurfaceToMat(webcamSurface);
cv::Mat targetMat = SDL_SurfaceToMat(targetSurface);
// cv::imshow("Webcam Image", webcamMat); // uncomment when testing image appearance
//cv::waitKey(0);
// Initialize ORB detector
cv::Ptr<cv::ORB> orb = cv::ORB::create();
/* 1500, // nfeatures
1.2f, // scaleFactor
8, // nlevels
31, // edgeThreshold
0, // firstLevel
2, // WTA_K
cv::ORB::HARRIS_SCORE, // scoreType
31, // patchSize
20 // fastThreshold
);*/
// Detect keypoints and compute descriptors
std::vector<cv::KeyPoint> keypointsWebcam, keypointsTarget;
cv::Mat descriptorsWebcam, descriptorsTarget;
orb->detectAndCompute(webcamMat, cv::noArray(), keypointsWebcam, descriptorsWebcam);
orb->detectAndCompute(targetMat, cv::noArray(), keypointsTarget, descriptorsTarget);
if (descriptorsWebcam.empty() || descriptorsTarget.empty()) {
fprintf(stderr, "No descriptors found. On webcam? %d. On input image? %d.\n", !descriptorsWebcam.empty(), !descriptorsTarget.empty());
return false;
}
// Match descriptors using Brute-Force matcher with Hamming distance
/* cv::BFMatcher matcher(cv::NORM_HAMMING, true); // crossCheck=true
std::vector<cv::DMatch> matches;
matcher.match(descriptorsTarget, descriptorsWebcam, matches);
*/
// Initialize BFMatcher without crossCheck
cv::BFMatcher matcher(cv::NORM_HAMMING);
// Perform k-NN matching with k=2
std::vector<std::vector<cv::DMatch>> matches;
matcher.knnMatch(descriptorsTarget, descriptorsWebcam, matches, 2);
if (matches.empty()) {
return false;
}
/*
// Filter good matches based on distance
double max_dist = 0; double min_dist = 100;
// Find min and max distances
for (const auto& match : matches) {
double dist = match.distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
// Define a threshold to identify good matches
std::vector<cv::DMatch> goodMatches;
for (const auto& match : matches) {
if (match.distance <= std::max(2 * min_dist, 30.0)) {
goodMatches.push_back(match);
}
}
*/
// Apply Lowe's ratio test
const float ratioThresh = 0.75f;
std::vector<cv::DMatch> goodMatches;
for (size_t i = 0; i < matches.size(); i++) {
if (matches[i].size() < 2)
continue; // Not enough matches
const cv::DMatch& bestMatch = matches[i][0];
const cv::DMatch& betterMatch = matches[i][1];
float ratio = bestMatch.distance / betterMatch.distance;
if (ratio < ratioThresh) {
goodMatches.push_back(bestMatch);
}
}
// Debug: Print number of good matches
// std::cout << "Good Matches: " << goodMatches.size() << std::endl;
// Optionally, visualize matches
/*
cv::Mat imgMatches;
cv::drawMatches(targetMat, keypointsTarget, webcamMat, keypointsWebcam, goodMatches, imgMatches);
cv::imshow("Good Matches", imgMatches);
cv::waitKey(30);
*/
// Determine if enough good matches are found
return (goodMatches.size() >= matchThreshold);
}
}

15
source/cv.hpp Normal file
View File

@@ -0,0 +1,15 @@
#ifndef CV_H
#define CV_H
#include <SDL3/SDL.h>
#ifdef __cplusplus
extern "C" {
#endif
bool detectImageInWebcam(SDL_Surface *webcam, SDL_Surface *img, double threshold);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -211,35 +211,79 @@ const char *esc_color(const char *c, struct rgba *color, struct rgba defc)
// text is a string, font f, size is height in pixels, wrap is how long a line is before wrapping. -1to not wrap
HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing, float wrap)
{
HMM_Vec2 dim = {0};
float maxWidth = 0; // max width of any line
float lineWidth = 0; // current line width
float scale = size/f->height;
scale = 1;
float lineHeight = f->ascent - f->descent;
lineHeight *= scale;
letterSpacing *= scale;
int breakAtWord = 0;
HMM_Vec2 dim = {0};
float maxWidth = 0; // Maximum width of any line
float lineWidth = 0; // Current line width
float scale = size / f->height;
float lineHeight = (f->ascent - f->descent) * scale;
letterSpacing *= scale;
float height = lineHeight; // total height
float height = lineHeight; // Total height
const char *wordStart = text; // Start of the current word for word wrapping
float wordWidth = 0; // Width of the current word
float spaceWidth = f->Characters[' '].advance + letterSpacing; // Space character width
for (char *c = text; *c != 0; c++) {
if (*c == '\n') {
maxWidth = fmaxf(maxWidth, lineWidth);
lineWidth = 0;
height += lineHeight + f->linegap;
continue;
for (const char *c = text; *c != '\0'; c++) {
if (*c == '\n') {
// Handle explicit line breaks
maxWidth = fmaxf(maxWidth, lineWidth);
lineWidth = 0;
height += lineHeight + f->linegap;
wordStart = c + 1;
wordWidth = 0;
continue;
}
float charWidth = f->Characters[*c].advance + letterSpacing;
// Handle wrapping
if (wrap > 0 && lineWidth + charWidth > wrap) {
if (breakAtWord && *c != ' ') {
// Roll back to the last word if breaking at word boundaries
if (wordWidth > 0) {
lineWidth -= wordWidth + spaceWidth;
c = wordStart - 1; // Reset to start of the word
}
}
// Finish the current line and reset
maxWidth = fmaxf(maxWidth, lineWidth);
lineWidth = 0;
height += lineHeight + f->linegap;
wordStart = c + 1; // Start a new word
wordWidth = 0;
// Skip to next character if wrapping on letters
if (!breakAtWord) {
lineWidth += charWidth;
continue;
}
}
lineWidth += charWidth;
// Update word width if breaking at word boundaries
if (breakAtWord) {
if (*c == ' ') {
wordWidth = 0;
wordStart = c + 1;
} else {
wordWidth += charWidth;
}
}
}
lineWidth += f->Characters[*c].advance + letterSpacing;
}
maxWidth = fmaxf(maxWidth, lineWidth);
dim.x = maxWidth;
dim.y = height;
return dim;
// Finalize dimensions
maxWidth = fmaxf(maxWidth, lineWidth);
dim.x = maxWidth;
dim.y = height;
return dim;
}
/* pos given in screen coordinates */
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap) {
int wrapAtWord = 1;
text_vert *buffer = NULL;
int len = strlen(text);
@@ -250,57 +294,23 @@ struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scal
for (char *c = text; *c != 0; c++) {
if (*c == '\n') {
cursor.x = pos.x;
cursor.y += lineHeight + f->linegap;
cursor.y -= lineHeight + f->linegap;
lineWidth = 0;
continue;
}
draw_char_verts(&buffer, f->Characters[*c], cursor, scale, color);
cursor.x += f->Characters[*c].advance;
}
return buffer;
/*
const char *line, *wordstart, *drawstart;
line = drawstart = text;
struct rgba usecolor = color;
while (*line != '\0') {
if (isblank(*line)) {
sdrawCharacter(f->Characters[*line], cursor, scale, usecolor);
cursor.X += f->Characters[*line].advance * scale;
line++;
} else if (isspace(*line)) {
sdrawCharacter(f->Characters[*line], cursor, scale, usecolor);
cursor.Y -= scale * f->linegap;
cursor.X = pos.X;
line++;
} else {
if (*line == '\e')
line = esc_color(line, &usecolor, color);
wordstart = line;
int wordWidth = 0;
while (!isspace(*line) && *line != '\0') {
wordWidth += f->Characters[*line].advance * scale;
line++;
}
if (wrap > 0 && (cursor.X + wordWidth - pos.X) >= wrap) {
cursor.X = pos.X;
cursor.Y -= scale * f->linegap;
}
while (wordstart < line) {
if (*wordstart == '\e')
wordstart = esc_color(wordstart, &usecolor, color);
sdrawCharacter(f->Characters[*wordstart], cursor, scale, usecolor);
cursor.X += f->Characters[*wordstart].advance * scale;
wordstart++;
}
struct character chara = f->Characters[*c];
if (wrap > 0 && lineWidth + chara.advance > wrap) {
cursor.x = pos.x;
cursor.y -= lineHeight + f->linegap;
lineWidth = 0;
}
}*/
draw_char_verts(&buffer, chara, cursor, scale, color);
lineWidth += chara.advance;
cursor.x += chara.advance;
}
return buffer;
}

View File

@@ -32,6 +32,8 @@
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_error.h>
#include <cv.hpp>
#ifdef __APPLE__
#include <Accelerate/Accelerate.h>
#else
@@ -256,6 +258,11 @@ void SDL_Surface_free(JSRuntime *rt, SDL_Surface *s) {
SDL_DestroySurface(s);
}
void SDL_Camera_free(JSRuntime *rt, SDL_Camera *cam)
{
SDL_CloseCamera(cam);
}
QJSCLASS(transform)
QJSCLASS(font)
//QJSCLASS(warp_gravity)
@@ -265,8 +272,18 @@ QJSCLASS(timer)
QJSCLASS(skin)
QJSCLASS(SDL_Window)
QJSCLASS(SDL_Renderer)
QJSCLASS(SDL_Texture, TracyCAllocN(n, n->w*n->h*4, "vram");)
QJSCLASS(SDL_Surface, TracyCAllocN(n, n->pitch*n->h, "texture memory");)
QJSCLASS(SDL_Camera)
QJSCLASS(SDL_Texture,
TracyCAllocN(n, n->w*n->h*4, "vram");
JS_SetProperty(js, j, width_atom, number2js(js,n->w));
JS_SetProperty(js,j,height_atom,number2js(js,n->h));
)
QJSCLASS(SDL_Surface,
TracyCAllocN(n, n->pitch*n->h, "texture memory");
JS_SetProperty(js, j, width_atom, number2js(js,n->w));
JS_SetProperty(js,j,height_atom,number2js(js,n->h));
)
static inline HMM_Mat4 js2transform_mat(JSContext *js, JSValue v)
{
@@ -672,6 +689,15 @@ JSC_SCALL(render_text_size,
ret = vec22js(js,measure_text(str, f, size, letterSpacing, wrap));
)
JSC_SCALL(render_text_rect,
rect r = {0};
font *f = js2font(js,argv[1]);
float wrap = js2number(js,argv[2]);
HMM_Vec2 dim = measure_text(str, f, 0, 0, wrap);
r.w = dim.x;
r.h = dim.y;
)
JSC_CCALL(render_draw_color,
SDL_Renderer *renderer = js2SDL_Renderer(js,self);
struct rgba rgba = js2color(js,argv[0]);
@@ -683,6 +709,7 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, set_projection_ortho, 3),
MIST_FUNC_DEF(render, set_projection_perspective, 4),
MIST_FUNC_DEF(render, set_view, 1),
MIST_FUNC_DEF(render, draw_color, 1),
};
static JSValue idx_buffer = JS_UNDEFINED;
@@ -1372,6 +1399,9 @@ static JSValue event2js(JSContext *js, SDL_Event event)
JS_SetPropertyStr(js,e,"window", number2js(js,event.text.windowID));
JS_SetPropertyStr(js,e,"text", JS_NewString(js,event.text.text));
break;
case SDL_EVENT_CAMERA_DEVICE_APPROVED:
JS_SetPropertyStr(js,e,"type", JS_NewString(js, "camera approved"));
break;
}
return e;
}
@@ -1399,23 +1429,23 @@ JSC_CCALL(game_renderers,
)
JSC_CCALL(game_cameras,
SDL_CameraID *ids = SDL_GetCameras(NULL);
int num;
SDL_CameraID *ids = SDL_GetCameras(&num);
JSValue jsids = JS_NewArray(js);
SDL_CameraID *id = ids;
while (*id) {
printf("camera %d\n", *id);
id++;
}
/* for (int i = 0; i < num; i++) {
for (int i = 0; i < num; i++)
JS_SetPropertyUint32(js,jsids, i, number2js(js,ids[i]));
}
SDL_OpenCamera(ids[0], NULL);*/
return jsids;
)
JSC_CCALL(game_open_camera,
int id = js2number(js,argv[0]);
SDL_Camera *cam = SDL_OpenCamera(id, NULL);
if (!cam) ret = JS_ThrowReferenceError(js, "Could not open camera %d: %s\n", id, SDL_GetError());
else
ret = SDL_Camera2js(js,cam);
)
#include "wildmatch.h"
JSC_SSCALL(game_glob,
if (wildmatch(str, str2, WM_PATHNAME | WM_PERIOD | WM_WILDSTAR) == WM_MATCH)
@@ -1430,6 +1460,7 @@ static const JSCFunctionListEntry js_game_funcs[] = {
MIST_FUNC_DEF(game, engine_delay, 1),
MIST_FUNC_DEF(game, renderers, 0),
MIST_FUNC_DEF(game, cameras, 0),
MIST_FUNC_DEF(game, open_camera, 1),
MIST_FUNC_DEF(game, glob, 2),
};
@@ -1510,7 +1541,9 @@ JSC_CCALL(SDL_Renderer_rect,
JSC_CCALL(renderer_load_texture,
SDL_Renderer *r = js2SDL_Renderer(js,self);
SDL_Surface *surf = js2SDL_Surface(js,argv[0]);
if (!surf) return JS_ThrowReferenceError(js, "Surface was not a surface.");
SDL_Texture *tex = SDL_CreateTextureFromSurface(r,surf);
if (!tex) return JS_ThrowReferenceError(js, "Could not create texture from surface: %s", SDL_GetError());
ret = SDL_Texture2js(js,tex);
JS_SetProperty(js,ret,width_atom, number2js(js,tex->w));
JS_SetProperty(js,ret,height_atom, number2js(js,tex->h));
@@ -1587,7 +1620,7 @@ JSC_CCALL(renderer_9slice,
SDL_Texture *tex = js2SDL_Texture(js,argv[0]);
rect *dst, *src = NULL;
lrtb bounds = js2lrtb(js,argv[2]);
SDL_RenderTexture9Grid(renderer, tex, src, bounds.l, bounds.r, bounds.t, bounds.b, 0.0, dst);
)
JSC_CCALL(renderer_get_image,
@@ -1665,10 +1698,6 @@ void Translate2DPoints(HMM_Vec2 *points, int count, HMM_Vec3 position, HMM_Quat
float yy = rotation.y * rotation.y;
float zz = rotation.z * rotation.z;
float xy = rotation.x * rotation.y;
float xz = rotation.x * rotation.z;
float yz = rotation.y * rotation.z;
float xw = rotation.x * rotation.w;
float yw = rotation.y * rotation.w;
float zw = rotation.z * rotation.w;
// Extract 2D affine rotation and scaling
@@ -1854,11 +1883,57 @@ JSC_CCALL(surface_rect,
SDL_FillSurfaceRect(dst,&r,SDL_MapRGBA(&pdetails,NULL,color.r,color.g,color.b,color.a));
)
JSC_CCALL(surface_dup,
SDL_Surface *surf = js2SDL_Surface(js,self);
SDL_Surface *conv = SDL_ConvertSurface(surf, SDL_PIXELFORMAT_RGBA8888);
if (!conv)
return JS_ThrowReferenceError(js, "could not blit to dup'd surface: %s", SDL_GetError());
return SDL_Surface2js(js,conv);
)
static const JSCFunctionListEntry js_SDL_Surface_funcs[] = {
MIST_FUNC_DEF(surface, blit, 3),
MIST_FUNC_DEF(surface, scale, 1),
MIST_FUNC_DEF(surface,fill,1),
MIST_FUNC_DEF(surface,rect,2),
MIST_FUNC_DEF(surface, dup, 0),
};
JSC_CCALL(camera_frame,
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_UNDEFINED;
}
return SDL_Surface2js(js,surf);
SDL_Surface *newsurf = SDL_CreateSurface(surf->w, surf->h, surf->format);
SDL_ReleaseCameraFrame(cam,surf);
int didit = SDL_BlitSurface(surf, NULL, newsurf, NULL);
if (!didit) {
SDL_DestroySurface(newsurf);
return JS_ThrowReferenceError(js, "Could not blit: %s", SDL_GetError());
}
return SDL_Surface2js(js,newsurf);
)
JSC_CCALL(camera_release_frame,
SDL_Camera *cam = js2SDL_Camera(js,self);
SDL_Surface *surf = js2SDL_Surface(js,argv[0]);
SDL_ReleaseCameraFrame(cam,surf);
)
static const JSCFunctionListEntry js_SDL_Camera_funcs[] =
{
MIST_FUNC_DEF(camera, frame, 0),
MIST_FUNC_DEF(camera, release_frame, 1),
};
JSC_CCALL(texture_mode,
@@ -1941,7 +2016,6 @@ int iiihandle(JSRuntime *rt, void *data)
}
JSC_CCALL(profile_gather,
int count = js2number(js,argv[0]);
instr_v = JS_DupValue(js, argv[1]);
JS_SetInterruptHandler(JS_GetRuntime(js), iiihandle, NULL);
)
@@ -2604,7 +2678,7 @@ JSC_CCALL(os_make_texture,
FMT = SDL_PIXELFORMAT_RGB24;
else {
free(data);
return JS_ThrowReferenceError(js, "unknown pixel format");
return JS_ThrowReferenceError(js, "unknown pixel format. got %d channels", n);
}
SDL_Surface *surf = SDL_CreateSurfaceFrom(width,height,FMT, data, width*n);
@@ -2614,8 +2688,6 @@ JSC_CCALL(os_make_texture,
}
ret = SDL_Surface2js(js,surf);
JS_SetProperty(js,ret,width_atom,number2js(js,surf->w));
JS_SetProperty(js,ret,height_atom,number2js(js,surf->h));
)
JSC_CCALL(os_make_gif,
@@ -2777,33 +2849,6 @@ JSC_SCALL(os_gltf_skin,
cgltf_free(data);
)
JSC_CCALL(os_make_buffer,
int type = js2number(js,argv[1]);
float *b = malloc(sizeof(float)*js_arrlen(js,argv[0]));
for (int i = 0; i < js_arrlen(js,argv[0]); i++)
b[i] = js_getnum_uint32(js, argv[0],i);
/*
sg_buffer *p = malloc(sizeof(sg_buffer));
switch(type) {
case 0:
*p = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(float)*js_arrlen(js,argv[0]),
.data = b
});
break;
case 1:
*p = index_buffer(b, js_arrlen(js,argv[0]));
break;
case 2:
*p = texcoord_floats(b, js_arrlen(js,argv[0]));
break;
}
free(b);
return sg_buffer2js(js,p);*/
)
JSC_CCALL(os_make_color_buffer,
int count = js2number(js,argv[1]);
HMM_Vec4 color = js2vec4(js,argv[0]);
@@ -3074,6 +3119,14 @@ JSC_CCALL(os_make_sprite_mesh,
JS_SetProperty(js, ret, count_atom, number2js(js, count));
)
bool detectImageInWebcam(SDL_Surface *a, SDL_Surface *b, double t);
JSC_CCALL(os_match_img,
SDL_Surface *img1 = js2SDL_Surface(js,argv[0]);
SDL_Surface *img2 = js2SDL_Surface(js,argv[1]);
double threshold = js2number(js,argv[2]);
return JS_NewBool(js, detectImageInWebcam(img1,img2,threshold));
)
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, turbulence, 4),
MIST_FUNC_DEF(os, fbm, 4),
@@ -3097,7 +3150,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, make_surface, 1),
MIST_FUNC_DEF(os, make_font, 2),
MIST_FUNC_DEF(os, make_transform, 0),
MIST_FUNC_DEF(os, make_buffer, 1),
MIST_FUNC_DEF(os, make_line_prim, 4),
MIST_FUNC_DEF(os, make_cylinder, 2),
MIST_FUNC_DEF(os, make_cone, 2),
@@ -3130,6 +3182,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, gltf_skin, 1),
MIST_FUNC_DEF(os, skin_calculate, 1),
MIST_FUNC_DEF(os, kill, 1),
MIST_FUNC_DEF(os, match_img, 3),
};
#define JSSTATIC(NAME, PARENT) \
@@ -3193,6 +3246,7 @@ void ffi_load(JSContext *js) {
QJSCLASSPREP_FUNCS(SDL_Surface)
QJSCLASSPREP_FUNCS(SDL_Texture)
QJSCLASSPREP_FUNCS(SDL_Renderer)
QJSCLASSPREP_FUNCS(SDL_Camera)
QJSGLOBALCLASS(os);
@@ -3204,6 +3258,7 @@ void ffi_load(JSContext *js) {
QJSCLASSPREP_FUNCS(timer);
QJSGLOBALCLASS(input);
QJSGLOBALCLASS(io);
QJSGLOBALCLASS(prosperon);

View File

@@ -96,9 +96,9 @@ static inline TYPE *js2##TYPE (JSContext *js, JSValue val) { \
return JS_GetOpaque(val,js_##TYPE##_id); \
}\
static inline JSValue TYPE##2js(JSContext *js, TYPE *n) { \
__VA_ARGS__ \
JSValue j = JS_NewObjectClass(js,js_##TYPE##_id);\
JS_SetOpaque(j,n);\
__VA_ARGS__ \
return j; }\
\