use colorf

This commit is contained in:
2024-12-05 12:00:12 -06:00
parent ae39e60095
commit ac9fd39cf4
9 changed files with 161 additions and 146 deletions

View File

@@ -24,12 +24,12 @@ if host_machine.system() == 'darwin'
endif
cc = meson.get_compiler('c')
# adding cblas
deps += dependency('sdl3')
if host_machine.system() == 'darwin'
deps += dependency('appleframeworks', modules: 'accelerate')
else
deps += dependency('cblas')
endif
if host_machine.system() == 'linux'
@@ -71,10 +71,12 @@ deps += dependency('qjs-layout',static:true)
deps += dependency('qjs-nota',static:true)
deps += dependency('qjs-miniz',static:true)
deps += dependency('qjs-soloud',static:true)
deps += dependency('sdl3')
deps += dependency('physfs',static:true)
deps += dependency('opencv')
deps += dependency('opencv4')
#deps += cc.find_library('opencv')
deps += dependency('threads')

View File

@@ -124,7 +124,6 @@ var tween = function (from, to, time, fn) {
}
};
var stop = Register.update.register(update);
console.log(update)
return stop;
};

View File

@@ -382,7 +382,7 @@ typedef union HMM_Vec4 {
HMM_Vec2 cp;
HMM_Vec2 wh;
};
HMM_Quat quat;
struct {float x, y, z, w; };
struct {float r, g, b, a; };

View File

@@ -2,26 +2,27 @@
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <SDL3/SDL.h>
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.");
// }
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);
cv::Mat mat(convertedSurface->h, convertedSurface->w, CV_8UC4, convertedSurface->pixels, convertedSurface->pitch);
// Convert RGBA to BGR
cv::Mat matBGR;
cv::cvtColor(mat, matBGR, cv::COLOR_RGBA2BGR);
// Free the converted surface
// SDL_DestroySurface(convertedSurface);
SDL_DestroySurface(convertedSurface);
return matBGR;
}
@@ -51,101 +52,88 @@ cv::Mat SDL_SurfaceToMat_YUY2(SDL_Surface* surface) {
// 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);
extern "C" {
// Modified function to return a pointer to Rectangle instead of a bool
SDL_FRect* 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);
// Initialize ORB detector
cv::Ptr<cv::ORB> orb = cv::ORB::create();
// 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);
// Check if descriptors are found
if (descriptorsWebcam.empty() || descriptorsTarget.empty()) {
fprintf(stderr, "No descriptors found. On webcam? %d. On input image? %d.\n",
!descriptorsWebcam.empty(), !descriptorsTarget.empty());
return NULL;
}
// 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);
// Check if any matches are found
if (matches.empty()) {
return NULL;
}
// Apply Lowe's ratio test to filter good matches
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);
}
}
// Determine if enough good matches are found
if (static_cast<double>(goodMatches.size()) >= matchThreshold) {
// Collect the locations of the matched keypoints in the webcam image
std::vector<cv::Point> pointsWebcam;
pointsWebcam.reserve(goodMatches.size());
for (const auto& match : goodMatches) {
pointsWebcam.emplace_back(keypointsWebcam[match.trainIdx].pt);
}
// Compute the bounding rectangle that encompasses all matched points
cv::Rect boundingRect = cv::boundingRect(pointsWebcam);
// Allocate memory for the Rectangle struct
SDL_FRect* rect = (SDL_FRect*)malloc(sizeof(*rect));
if (!rect) {
// Allocation failed
fprintf(stderr, "Memory allocation for Rectangle failed.\n");
return NULL;
}
// Populate the Rectangle struct with bounding rectangle data
rect->x = boundingRect.x;
rect->y = boundingRect.y;
rect->w = boundingRect.width;
rect->h = boundingRect.height;
return rect;
} else {
// Not enough matches; return NULL
return NULL;
}
}
*/
// 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);
}
}

View File

@@ -6,7 +6,7 @@
#ifdef __cplusplus
extern "C" {
#endif
bool detectImageInWebcam(SDL_Surface *webcam, SDL_Surface *img, double threshold);
SDL_FRect *detectImageInWebcam(SDL_Surface *webcam, SDL_Surface *img, double threshold);
#ifdef __cplusplus
}

View File

@@ -152,7 +152,7 @@ void sdrawCharacter(struct text_vert **buffer, stbtt_packedchar c, HMM_Vec2 curs
arrput(*buffer, vert);
}
void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cursor, float scale, struct rgba color)
void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cursor, float scale, colorf color)
{
// packedchar has
// Adds four verts: bottom left, bottom right, top left, top right
@@ -161,7 +161,7 @@ void draw_char_verts(struct text_vert **buffer, struct character c, HMM_Vec2 cur
bl.pos.y = cursor.Y + c.quad.y;
bl.uv.x = c.uv.x;
bl.uv.y = c.uv.y;
rgba2floats(bl.color.e, color);
bl.color = color;
arrput(*buffer, bl);
@@ -282,7 +282,7 @@ HMM_Vec2 measure_text(const char *text, font *f, float size, float letterSpacing
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) {
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, colorf color, float wrap) {
int wrapAtWord = 1;
text_vert *buffer = NULL;
int len = strlen(text);

View File

@@ -51,7 +51,7 @@ typedef struct Character glyph;
void font_free(JSRuntime *rt,font *f);
struct sFont *MakeFont(void *data, size_t len, int height);
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, struct rgba color, float wrap);
struct text_vert *renderText(const char *text, HMM_Vec2 pos, font *f, float scale, colorf color, float wrap);
HMM_Vec2 measure_text(const char *text, font *f, float scale, float letterSpacing, float wrap);
// Flushes all letters from renderText calls into the provided buffer

View File

@@ -339,15 +339,17 @@ double js2angle(JSContext *js,JSValue v) {
return n * HMM_TurnToRad;
}
struct rgba js2color(JSContext *js,JSValue v) {
typedef HMM_Vec4 colorf;
colorf js2color(JSContext *js,JSValue v) {
JSValue c[4];
for (int i = 0; i < 4; i++) c[i] = JS_GetPropertyUint32(js,v,i);
float a = JS_IsUndefined(c[3]) ? 1.0 : js2number(js,c[3]);
struct rgba color = {
.r = js2number(js,c[0])*RGBA_MAX,
.g = js2number(js,c[1])*RGBA_MAX,
.b = js2number(js,c[2])*RGBA_MAX,
.a = a*RGBA_MAX,
colorf color = {
.r = js2number(js,c[0]),
.g = js2number(js,c[1]),
.b = js2number(js,c[2]),
.a = a,
};
for (int i = 0; i < 4; i++) JS_FreeValue(js,c[i]);
@@ -355,13 +357,13 @@ struct rgba js2color(JSContext *js,JSValue v) {
return color;
}
JSValue color2js(JSContext *js,struct rgba color)
JSValue color2js(JSContext *js, colorf color)
{
JSValue arr = JS_NewArray(js);
JS_SetPropertyUint32(js, arr,0,number2js(js,(double)color.r/255));
JS_SetPropertyUint32(js, arr,1,number2js(js,(double)color.g/255));
JS_SetPropertyUint32(js, arr,2,number2js(js,(double)color.b/255));
JS_SetPropertyUint32(js, arr,3,number2js(js,(double)color.a/255));
JS_SetPropertyUint32(js, arr,0,number2js(js,(double)color.r));
JS_SetPropertyUint32(js, arr,1,number2js(js,(double)color.g));
JS_SetPropertyUint32(js, arr,2,number2js(js,(double)color.b));
JS_SetPropertyUint32(js, arr,3,number2js(js,(double)color.a));
return arr;
}
@@ -700,8 +702,8 @@ JSC_SCALL(render_text_rect,
JSC_CCALL(render_draw_color,
SDL_Renderer *renderer = js2SDL_Renderer(js,self);
struct rgba rgba = js2color(js,argv[0]);
SDL_SetRenderDrawColor(renderer, rgba.r, rgba.g, rgba.b, rgba.a);
colorf rgba = js2color(js,argv[0]);
SDL_SetRenderDrawColorFloat(renderer, rgba.r, rgba.g, rgba.b, rgba.a);
)
static const JSCFunctionListEntry js_render_funcs[] = {
@@ -745,7 +747,7 @@ JSC_CCALL(os_make_text_buffer,
float size = js2number(js,argv[2]);
font *f = js2font(js,argv[5]);
if (!size) size = f->height;
struct rgba c = js2color(js,argv[3]);
colorf c = js2color(js,argv[3]);
int wrap = js2number(js,argv[4]);
HMM_Vec2 startpos = {.x = rectpos.x, .y = rectpos.y };
text_vert *buffer = renderText(s, startpos, f, size, c, wrap);
@@ -1455,6 +1457,22 @@ JSC_SSCALL(game_glob,
return JS_NewBool(js, 0);
)
JSC_CCALL(game_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.", js2number(js,argv[0]));
return JS_NewString(js, name);
)
JSC_CCALL(game_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");
}
)
static const JSCFunctionListEntry js_game_funcs[] = {
MIST_FUNC_DEF(game, engine_start, 1),
MIST_FUNC_DEF(game, engine_input,1),
@@ -1462,6 +1480,8 @@ static const JSCFunctionListEntry js_game_funcs[] = {
MIST_FUNC_DEF(game, renderers, 0),
MIST_FUNC_DEF(game, cameras, 0),
MIST_FUNC_DEF(game, open_camera, 1),
MIST_FUNC_DEF(game, camera_name,1),
MIST_FUNC_DEF(game, camera_position,1),
MIST_FUNC_DEF(game, glob, 2),
};
@@ -1505,15 +1525,15 @@ JSC_CCALL(SDL_Renderer_present,
JSC_CCALL(SDL_Renderer_draw_color,
SDL_Renderer *renderer = js2SDL_Renderer(js,self);
struct rgba color = js2color(js,argv[0]);
SDL_SetRenderDrawColor(renderer, color.r,color.g,color.b,color.a);
colorf color = js2color(js,argv[0]);
SDL_SetRenderDrawColorFloat(renderer, color.r,color.g,color.b,color.a);
)
JSC_CCALL(SDL_Renderer_rect,
SDL_Renderer *r = js2SDL_Renderer(js,self);
if (!JS_IsUndefined(argv[1])) {
struct rgba color = js2color(js,argv[1]);
SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a);
colorf color = js2color(js,argv[1]);
SDL_SetRenderDrawColorFloat(r, color.r, color.g, color.b, color.a);
}
if (JS_IsArray(js,argv[0])) {
@@ -1553,8 +1573,8 @@ JSC_CCALL(renderer_load_texture,
JSC_CCALL(SDL_Renderer_fillrect,
SDL_Renderer *r = js2SDL_Renderer(js,self);
if (!JS_IsUndefined(argv[1])) {
struct rgba color = js2color(js,argv[1]);
SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a);
colorf color = js2color(js,argv[1]);
SDL_SetRenderDrawColorFloat(r, color.r, color.g, color.b, color.a);
}
if (JS_IsArray(js,argv[0])) {
@@ -1585,8 +1605,9 @@ JSC_CCALL(renderer_texture,
dst.y -= dst.h;
if (!JS_IsUndefined(argv[3])) {
struct rgba color = js2color(js,argv[3]);
SDL_SetTextureColorMod(tex, color.r, color.g, color.b);
colorf color = js2color(js,argv[3]);
SDL_SetTextureColorModFloat(tex, color.r, color.g, color.b);
SDL_SetTextureAlphaModFloat(tex,color.a);
}
if (JS_IsUndefined(argv[2]))
SDL_RenderTexture(renderer,tex,NULL,&dst);
@@ -1639,8 +1660,8 @@ JSC_CCALL(renderer_get_image,
JSC_SCALL(renderer_fasttext,
SDL_Renderer *r = js2SDL_Renderer(js,self);
if (!JS_IsUndefined(argv[2])) {
struct rgba color = js2color(js,argv[2]);
SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a);
colorf color = js2color(js,argv[2]);
SDL_SetRenderDrawColorFloat(r, color.r, color.g, color.b, color.a);
}
HMM_Vec2 pos = js2vec2(js,argv[1]);
pos.y *= -1;
@@ -1651,8 +1672,8 @@ JSC_SCALL(renderer_fasttext,
JSC_CCALL(renderer_line,
SDL_Renderer *r = js2SDL_Renderer(js,self);
if (!JS_IsUndefined(argv[1])) {
struct rgba color = js2color(js,argv[1]);
SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a);
colorf color = js2color(js,argv[1]);
SDL_SetRenderDrawColorFloat(r, color.r, color.g, color.b, color.a);
}
if (JS_IsArray(js,argv[0])) {
@@ -1671,8 +1692,8 @@ JSC_CCALL(renderer_line,
JSC_CCALL(renderer_point,
SDL_Renderer *r = js2SDL_Renderer(js,self);
if (!JS_IsUndefined(argv[1])) {
struct rgba color = js2color(js,argv[1]);
SDL_SetRenderDrawColor(r, color.r, color.g, color.b, color.a);
colorf color = js2color(js,argv[1]);
SDL_SetRenderDrawColorFloat(r, color.r, color.g, color.b, color.a);
}
if (JS_IsArray(js,argv[0])) {
@@ -1867,21 +1888,21 @@ static SDL_PixelFormatDetails pdetails = {
JSC_CCALL(surface_fill,
SDL_Surface *src = js2SDL_Surface(js,self);
struct rgba color = js2color(js,argv[0]);
colorf color = js2color(js,argv[0]);
rect r = {
.x = 0,
.y = 0,
.w = src->w,
.h = src->h
};
SDL_FillSurfaceRect(src, &r, SDL_MapRGBA(&pdetails, NULL, color.r,color.g,color.b,color.a));
//SDL_FillSurfaceRect(src, &r, SDL_MapRGBA(&pdetails, NULL, color.r,color.g,color.b,color.a));
)
JSC_CCALL(surface_rect,
SDL_Surface *dst = js2SDL_Surface(js,self);
rect r = js2rect(js,argv[0]);
struct rgba color = js2color(js,argv[1]);
SDL_FillSurfaceRect(dst,&r,SDL_MapRGBA(&pdetails,NULL,color.r,color.g,color.b,color.a));
colorf color = js2color(js,argv[1]);
//SDL_FillSurfaceRect(dst,&r,SDL_MapRGBA(&pdetails,NULL,color.r,color.g,color.b,color.a));
)
JSC_CCALL(surface_dup,
@@ -3117,12 +3138,15 @@ 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);
SDL_FRect *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));
SDL_FRect *r = detectImageInWebcam(img1,img2,threshold);
if (!r) return JS_UNDEFINED;
ret = rect2js(js, *r);
free(r);
)
static const JSCFunctionListEntry js_os_funcs[] = {

View File

@@ -44,6 +44,8 @@ struct rgba {
};
typedef struct rgba rgba;
typedef HMM_Vec4 rgbaf;
typedef HMM_Vec4 colorf;
static inline rgba vec2rgba(HMM_Vec4 v) {
return (rgba){v.e[0]*255,v.e[1]*255,v.e[2]*255,v.e[3]*255};