windows build

This commit is contained in:
2024-12-13 14:35:46 -06:00
parent ecbab2a2e4
commit 27ce4cd9e2
12 changed files with 230 additions and 292 deletions

View File

@@ -12,6 +12,8 @@ endif
add_project_arguments('-Wno-incompatible-pointer-types', language: 'c') add_project_arguments('-Wno-incompatible-pointer-types', language: 'c')
add_project_arguments('-Wno-narrowing', language: 'cpp') add_project_arguments('-Wno-narrowing', language: 'cpp')
add_project_arguments('-Wno-missing-braces', language:'c') add_project_arguments('-Wno-missing-braces', language:'c')
add_project_arguments('-Wl,--disable-new-dtags', language:'cpp')
add_project_arguments('-Wl,--disable-new-dtags', language:'c')
deps = [] deps = []
@@ -24,14 +26,12 @@ if host_machine.system() == 'darwin'
endif endif
cc = meson.get_compiler('c') cc = meson.get_compiler('c')
deps += dependency('sdl3') deps += dependency('sdl3')
if host_machine.system() == 'darwin' if host_machine.system() == 'darwin'
deps += dependency('appleframeworks', modules: 'accelerate') deps += dependency('appleframeworks', modules: 'accelerate')
add_project_arguments('-DACCELERATE_NEW_LAPACK=1', language:'c') add_project_arguments('-DACCELERATE_NEW_LAPACK=1', language:'c')
add_project_arguments('-DACCELERATE_LAPACK_ILP64=1', language:'c') add_project_arguments('-DACCELERATE_LAPACK_ILP64=1', language:'c')
else
deps += dependency('cblas')
endif endif
if host_machine.system() == 'linux' if host_machine.system() == 'linux'
@@ -43,7 +43,7 @@ endif
if host_machine.system() == 'windows' if host_machine.system() == 'windows'
deps += cc.find_library('d3d11') deps += cc.find_library('d3d11')
# these are for tracy # these are for tracy
deps += cc.find_library('ws2_32') deps += cc.find_library('ws2_32', required:true)
deps += cc.find_library('dbghelp') deps += cc.find_library('dbghelp')
#end #end
link += '-static' # Required to pack in mingw dlls on cross compilation link += '-static' # Required to pack in mingw dlls on cross compilation
@@ -74,10 +74,9 @@ deps += dependency('qjs-nota',static:true)
deps += dependency('qjs-miniz',static:true) deps += dependency('qjs-miniz',static:true)
deps += dependency('qjs-soloud',static:true) deps += dependency('qjs-soloud',static:true)
deps += dependency('physfs',static:true) deps += dependency('physfs')
#deps += dependency('opencv4')
deps += dependency('opencv4')
#deps += cc.find_library('opencv') #deps += cc.find_library('opencv')
deps += dependency('threads') deps += dependency('threads')
@@ -91,7 +90,7 @@ if get_option('enet')
endif endif
sources = [] 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', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c', 'cv.cpp'] 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', 'timer.c', 'transform.c','warp.c','yugine.c', 'wildmatch.c']
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', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.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', 'imgui_impl_sdlrenderer3.cpp', 'imgui_impl_sdl3.cpp']

View File

@@ -14,6 +14,5 @@ cpu = 'x86_64'
endian = 'little' endian = 'little'
[properties] [properties]
link_args = ['-static']
needs_exe_wrapper = false needs_exe_wrapper = false
pkg_config_libdir = '/usr/local/lib64/pkgconfig'

View File

@@ -258,6 +258,15 @@ debug.break_var = function(obj,vars)
}); });
} }
debug.try = function(fn)
{
try {
fn();
} catch(e) {
console.error(e)
}
}
return { return {
debug, debug,
Gizmos, Gizmos,

View File

@@ -151,6 +151,12 @@ Resources.is_image = function (path) {
return Resources.images.some(x => x === ext); return Resources.images.some(x => x === ext);
}; };
Resources.shaders = ["hlsl", "glsl", "cg"]
Resources.is_shader = function(path) {
var ext = path.ext();
return Resources.shaders.some(x => x === ext)
}
var res_cache = {}; var res_cache = {};
// ext is a list of extensions to search // ext is a list of extensions to search
@@ -268,11 +274,14 @@ console.info = function info(msg) {
console.warn = function warn(msg) { console.warn = function warn(msg) {
console.pprint(msg, 3); console.pprint(msg, 3);
}; };
console.error = function error (msg) { console.error = function error (e) {
console.pprint(msg + "\n" + console.stackstr(2), 4); console.log(e);
console.log(e.stack);
}; };
console.panic = function (msg) { console.panic = function (e) {
console.pprint(msg + "\n" + console.stackstr(2), 5); console.log("PANIC!")
console.error(e);
os.quit();
}; };
console.stackstr = function (skip = 0) { console.stackstr = function (skip = 0) {
var err = new Error(); var err = new Error();

View File

@@ -169,42 +169,75 @@ function calc_image_size(img)
return [img.texture.width*img.rect.width, img.texture.height*img.rect.height]; return [img.texture.width*img.rect.width, img.texture.height*img.rect.height];
} }
function create_image(path)
{
var data = io.slurpbytes(path);
var newimg;
switch(path.ext()) {
case 'gif':
newimg = os.make_gif(data);
if (newimg.surface) {
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
}
else
for (var frame of newimg.frames) {
frame.texture = render._main.load_texture(frame.surface);
frame.texture.mode(0);
}
break;
case 'ase':
case 'aseprite':
console.log(`loading aseprite file ${path}`)
console.log(`buffer size is ${data.byteLength}`)
newimg = os.make_aseprite(data);
if (newimg.surface) {
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
} else {
for (var anim in newimg) {
var a = newimg[anim];
for (var frame of a.frames) {
frame.texture = render._main.load_texture(frame.surface);
frame.texture.mode(0)
}
}
}
break;
default:
newimg = {
surface: os.make_texture(data)
};
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
break;
}
return newimg;
}
function merge_objects(oldobj,newobj, properties) {
function recursive_merge(target,src) {
for (var key of Object.keys(src)) {
if (properties.includes(key)) {
target[key] = src[key];
continue;
}
if (src[key] && typeof src[key] === 'object' && target[key] && typeof target[key] === 'object')
recursive_merge(target[key],src[key])
}
}
recursive_merge(oldobj,newobj);
}
game.tex_hotreload = function tex_hotreload(file) { game.tex_hotreload = function tex_hotreload(file) {
if (!(file in game.texture.cache)) return; if (!(file in game.texture.cache)) return;
var data = io.slurpbytes(file);
var tex; var img = create_image(file);
if (file.endsWith('.gif')) { var oldimg = game.texture.cache[file];
var anim = os.make_gif(data); console.log(json.encode(img))
if (anim.frames.length !== 1) return;
console.info(json.encode(anim)); merge_objects(oldimg,img, ['surface', 'texture', 'loop', 'time']);
tex = anim.frames[0].texture; game.texture.cache[file] = img;
} else if (file.endsWith('.ase') || file.endsWith('.aseprite')) {
var anim = os.make_aseprite(data);
if (anim.texture) // single picture
tex = anim.texture;
else {
var oldanim = game.texture.cache[file];
// load all into gpu
for (var a in anim) {
oldanim[a] = anim[a];
for (let frame of anim[a].frames)
frame.texture.load_gpu();
}
return;
}
} else
tex = os.make_texture(data);
var img = game.texture.cache[file];
tex.load_gpu();
console.info(`replacing ${json.encode(img)}`)
img.texture = tex;
img.rect = {
x:0,
y:0,
width:1,
height:1
};
}; };
var image = {}; var image = {};
@@ -264,48 +297,8 @@ game.texture = function texture(path) {
var parts = path.split(':'); var parts = path.split(':');
path = Resources.find_image(parts[0]); path = Resources.find_image(parts[0]);
if (game.texture.cache[path]) return game.texture.cache[path]; game.texture.cache[path] ??= create_image(path);
var data = io.slurpbytes(path); return game.texture.cache[path];
var newimg;
switch(path.ext()) {
case 'gif':
newimg = os.make_gif(data);
if (newimg.surface) {
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
}
else
for (var frame of newimg.frames) {
frame.texture = render._main.load_texture(frame.surface);
frame.texture.mode(0);
}
break;
case 'ase':
case 'aseprite':
newimg = os.make_aseprite(data);
if (newimg.surface) {
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
} else {
for (var anim in newimg) {
var a = newimg[anim];
for (var frame of a.frames) {
frame.texture = render._main.load_texture(frame.surface);
frame.texture.mode(0)
}
}
}
break;
default:
newimg = {
surface: os.make_texture(data)
};
newimg.texture = render._main.load_texture(newimg.surface);
newimg.texture.mode(0);
break;
}
game.texture.cache[path] = newimg;
return newimg;
// Look for a cached version // Look for a cached version
var frame; var frame;

View File

@@ -1053,7 +1053,7 @@ render.tile = function tile(image, rect = [0,0], color = Color.white)
return; return;
} }
render.geometry = function(material, geometry) render.geometry = function geometry(material, geometry)
{ {
render._main.geometry(material.diffuse.texture, geometry); render._main.geometry(material.diffuse.texture, geometry);
} }
@@ -1395,20 +1395,27 @@ var imgui_fn = function imgui_fn() {
prosperon.menu_hook?.(); prosperon.menu_hook?.();
}); });
/*
if (observed_tex) { if (observed_tex) {
imgui.window("texture", _ => { imgui.window("texture", _ => {
imgui.image(observed_tex.texture); imgui.image(observed_tex);
}); });
} }
var texs = {};
for (var path in game.texture.cache) {
var image = game.texture.cache[path];
if (image.texture && !texs[image.texture])
texs[image.texture] = image.texture;
}
imgui.window("textures", _ => { imgui.window("textures", _ => {
for (var img in game.texture.cache) { for (var img in texs) {
imgui.button(img, _ => { imgui.button(img, _ => {
observed_tex = game.texture.cache[img]; observed_tex = texs[img];
}); });
} }
}); });
*/
prosperon.imgui(); prosperon.imgui();
imgui.endframe(render._main); imgui.endframe(render._main);
}; };
@@ -1433,17 +1440,15 @@ var present_thread = undefined;
var clearcolor = [100,149,237,255].scale(1/255); var clearcolor = [100,149,237,255].scale(1/255);
prosperon.render = function prosperon_render() { prosperon.render = function prosperon_render() {
try{ try{
render._main.draw_color(clearcolor); render._main.draw_color(clearcolor);
render._main.clear(); render._main.clear();
// render each camera
prosperon.camera.render(); try { prosperon.camera.render(); } catch(e) { console.error(e) }
// prosperon.app(); try { prosperon.app(); } catch(e) { console.error(e) }
if (debug.show) imgui_fn(); if (debug.show) try { imgui_fn(); } catch(e) { console.error(e) }
} catch(e) { } catch(e) {
console.log(e); console.error(e)
console.log(e.stack)
// throw e;
} finally { } finally {
if (present_thread) present_thread.wait(); if (present_thread) present_thread.wait();
present_thread = render._main.present(); present_thread = render._main.present();
@@ -1455,38 +1460,40 @@ if (dmon) dmon.watch('.');
function dmon_cb(e) function dmon_cb(e)
{ {
io.invalidated(); try {
io.invalidate();
if (e.file.startsWith('.')) return; if (e.file.startsWith('.')) return;
if (e.file.endsWith('.js')) if (e.file.endsWith('.js'))
actor.hotreload(e.file); actor.hotreload(e.file);
else if (Resources.is_image(e.file)) else if (Resources.is_image(e.file))
game.tex_hotreload(e.file); game.tex_hotreload(e.file);
else if (e.file.endsWith('.cg')) // shader } catch(e) { console.error(e); }
render.hotreload(e.file);
} }
// Ran once per frame // Ran once per frame
prosperon.process = function process() { prosperon.process = function process() {
try {
layout.newframe(); layout.newframe();
// check for hot reloading // check for hot reloading
if (dmon) dmon.poll(dmon_cb); if (dmon) dmon.poll(dmon_cb);
var dt = profile.now() - frame_t; var dt = profile.now() - frame_t;
frame_t = profile.now(); frame_t = profile.now();
prosperon.appupdate(dt);
input.procdown();
game.engine_input(e => { game.engine_input(e => {
prosperon[e.type]?.(e); prosperon[e.type]?.(e);
}); });
try { prosperon.appupdate(dt); } catch(e) { console.error(e) }
input.procdown();
try {
update_emitters(dt * game.timescale); update_emitters(dt * game.timescale);
os.update_timers(dt * game.timescale); os.update_timers(dt * game.timescale);
prosperon.update(dt*game.timescale); prosperon.update(dt*game.timescale);
if (sim.mode === "step") sim.pause(); } catch(e) { console.error(e) }
if (sim.mode === "step") sim.pause();
if (sim.mode === "play" || sim.mode === "step") { if (sim.mode === "play" || sim.mode === "step") {
/* /*
physlag += dt; physlag += dt;
@@ -1501,8 +1508,9 @@ prosperon.process = function process() {
prosperon.render(); prosperon.render();
// tracy.gpu_zone(prosperon.render); // tracy.gpu_zone(prosperon.render);
} catch(e) {
console.error(e)
}
}; };
return { render }; return { render };

View File

@@ -1,7 +1,6 @@
/* This file runs after the audio system is initiated */ soloud.init();
var audio = {}; var audio = {};
soloud.init();
var pcms = {}; var pcms = {};
audio.pcm = function pcm(file) audio.pcm = function pcm(file)

View File

@@ -232,27 +232,6 @@ Cmdline.register_order(
prosperon.width = 1280; prosperon.width = 1280;
prosperon.height = 720; prosperon.height = 720;
prosperon.size = [1280, 720]; prosperon.size = [1280, 720];
prosperon.cleanup = function(){}
prosperon.event = function(e){
console.log(json.encode(e))
prosperon[e.type]?.(e);
switch(e.type) {
case "key_down":
prosperon.keydown(e.key_code, e.key_repeat);
break;
case "key_up":
prosperon.keyup(e.key_code);
break;
case "quit_requested":
os.exit(0);
break;
case "files_dropped":
console.log(json.encode(e));
break;
}
}
prosperon.frame = prosperon.process;
prosperon.icon = os.make_texture(io.slurpbytes('core/icons/moon.gif')); prosperon.icon = os.make_texture(io.slurpbytes('core/icons/moon.gif'));
prosperon.high_dpi = 0; prosperon.high_dpi = 0;
prosperon.alpha = 1; prosperon.alpha = 1;

View File

@@ -306,12 +306,32 @@ struct ase_t
void* mem_ctx; void* mem_ctx;
}; };
#define ASEPRITE_ERROR_MAX 256
static char aseprite_error[ASEPRITE_ERROR_MAX] = {0};
static const char *aseprite_GetError() {
return aseprite_error;
}
static void aseprite_clear_error() {
aseprite_error[0] = 0;
}
static void aseprite_set_error(const char *msg) {
if (msg) {
strncpy(aseprite_error, msg, ASEPRITE_ERROR_MAX-1);
aseprite_error[ASEPRITE_ERROR_MAX-1] = 0;
} else
aseprite_error[0] = 0;
}
#endif // CUTE_ASEPRITE_H #endif // CUTE_ASEPRITE_H
#ifdef CUTE_ASEPRITE_IMPLEMENTATION #ifdef CUTE_ASEPRITE_IMPLEMENTATION
#ifndef CUTE_ASEPRITE_IMPLEMENTATION_ONCE #ifndef CUTE_ASEPRITE_IMPLEMENTATION_ONCE
#define CUTE_ASEPRITE_IMPLEMENTATION_ONCE #define CUTE_ASEPRITE_IMPLEMENTATION_ONCE
#ifndef _CRT_SECURE_NO_WARNINGS #ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
@@ -925,9 +945,12 @@ static ase_color_t s_color(ase_t* ase, void* src, int index)
ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ctx) ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ctx)
{ {
ase_t* ase = (ase_t*)CUTE_ASEPRITE_ALLOC(sizeof(ase_t), mem_ctx); aseprite_clear_error();
CUTE_ASEPRITE_MEMSET(ase, 0, sizeof(*ase)); if (!memory || size < 6) {
aseprite_set_error("Invalid memory buffer or size too small.");
return NULL;
}
ase_state_t state = { 0, 0, 0 }; ase_state_t state = { 0, 0, 0 };
ase_state_t* s = &state; ase_state_t* s = &state;
s->in = (uint8_t*)memory; s->in = (uint8_t*)memory;
@@ -936,7 +959,19 @@ ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ct
s_skip(s, sizeof(uint32_t)); // File size. s_skip(s, sizeof(uint32_t)); // File size.
int magic = (int)s_read_uint16(s); int magic = (int)s_read_uint16(s);
CUTE_ASEPRITE_ASSERT(magic == 0xA5E0); if (magic != 0xA5E0) {
aseprite_set_error("Incorrect magic number. Not a valid Aseprite file.");
return NULL;
}
#define LOAD_ERROR(msg) { aseprite_set_error(msg); cute_aseprite_free(ase); return NULL; }
ase_t* ase = (ase_t*)CUTE_ASEPRITE_ALLOC(sizeof(ase_t), mem_ctx);
if (!ase) {
aseprite_set_error("Failed to allocate memory for aseprite import.");
return NULL;
}
CUTE_ASEPRITE_MEMSET(ase, 0, sizeof(*ase));
ase->frame_count = (int)s_read_uint16(s); ase->frame_count = (int)s_read_uint16(s);
ase->w = s_read_uint16(s); ase->w = s_read_uint16(s);
@@ -944,10 +979,11 @@ ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ct
uint16_t bpp = s_read_uint16(s) / 8; uint16_t bpp = s_read_uint16(s) / 8;
if (bpp == 4) ase->mode = ASE_MODE_RGBA; if (bpp == 4) ase->mode = ASE_MODE_RGBA;
else if (bpp == 2) ase->mode = ASE_MODE_GRAYSCALE; else if (bpp == 2) ase->mode = ASE_MODE_GRAYSCALE;
else { else if (bpp == 1)
CUTE_ASEPRITE_ASSERT(bpp == 1); ase->mode = ASE_MODE_INDEXED;
ase->mode = ASE_MODE_INDEXED; else
} LOAD_ERROR("Unsupported bits per pixel.");
uint32_t valid_layer_opacity = s_read_uint32(s) & 1; uint32_t valid_layer_opacity = s_read_uint32(s) & 1;
int speed = s_read_uint16(s); int speed = s_read_uint16(s);
s_skip(s, sizeof(uint32_t) * 2); // Spec says skip these bytes, as they're zero'd. s_skip(s, sizeof(uint32_t) * 2); // Spec says skip these bytes, as they're zero'd.
@@ -963,6 +999,9 @@ ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ct
s_skip(s, 84); // For future use (set to zero). s_skip(s, 84); // For future use (set to zero).
ase->frames = (ase_frame_t*)CUTE_ASEPRITE_ALLOC((int)(sizeof(ase_frame_t)) * ase->frame_count, mem_ctx); ase->frames = (ase_frame_t*)CUTE_ASEPRITE_ALLOC((int)(sizeof(ase_frame_t)) * ase->frame_count, mem_ctx);
if (!ase->frames)
LOAD_ERROR("Failed to allocate memory for frames.");
CUTE_ASEPRITE_MEMSET(ase->frames, 0, sizeof(ase_frame_t) * (size_t)ase->frame_count); CUTE_ASEPRITE_MEMSET(ase->frames, 0, sizeof(ase_frame_t) * (size_t)ase->frame_count);
ase_udata_t* last_udata = NULL; ase_udata_t* last_udata = NULL;
@@ -977,7 +1016,9 @@ ase_t* cute_aseprite_load_from_memory(const void* memory, int size, void* mem_ct
frame->ase = ase; frame->ase = ase;
s_skip(s, sizeof(uint32_t)); // Frame size. s_skip(s, sizeof(uint32_t)); // Frame size.
magic = (int)s_read_uint16(s); magic = (int)s_read_uint16(s);
CUTE_ASEPRITE_ASSERT(magic == 0xF1FA); if (magic != 0xF1FA)
LOAD_ERROR("Frame is not an aseprite magic number.");
int chunk_count = (int)s_read_uint16(s); int chunk_count = (int)s_read_uint16(s);
frame->duration_milliseconds = s_read_uint16(s); frame->duration_milliseconds = s_read_uint16(s);
if (frame->duration_milliseconds == 0) frame->duration_milliseconds = speed; if (frame->duration_milliseconds == 0) frame->duration_milliseconds = speed;

View File

@@ -1,108 +0,0 @@
#include "cv.hpp"
#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.");
}
// Create a cv::Mat with the same size and type
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);
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" {
int detectImageInWebcam(SDL_Surface* webcamSurface, SDL_Surface* targetSurface) {
// 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
return goodMatches.size();
}
}

View File

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

View File

@@ -32,12 +32,10 @@
#include <SDL3/SDL_gpu.h> #include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_error.h> #include <SDL3/SDL_error.h>
#include <cv.hpp>
#ifdef __APPLE__ #ifdef __APPLE__
#include <Accelerate/Accelerate.h> #include <Accelerate/Accelerate.h>
#else //#else
#include <cblas.h> //#include <cblas.h>
#endif #endif
static JSAtom width_atom; static JSAtom width_atom;
@@ -244,10 +242,6 @@ void SDL_Renderer_free(JSRuntime *rt, SDL_Renderer *r)
SDL_DestroyRenderer(r); SDL_DestroyRenderer(r);
} }
void SDL_Texture_free(JSRuntime *rt, SDL_Texture *t){
TracyCFreeN(t, "vram");
SDL_DestroyTexture(t);
}
void SDL_Surface_free(JSRuntime *rt, SDL_Surface *s) { void SDL_Surface_free(JSRuntime *rt, SDL_Surface *s) {
if (s->flags & SDL_SURFACE_PREALLOCATED) if (s->flags & SDL_SURFACE_PREALLOCATED)
free(s->pixels); free(s->pixels);
@@ -298,11 +292,18 @@ QJSCLASS(skin)
QJSCLASS(SDL_Window) QJSCLASS(SDL_Window)
QJSCLASS(SDL_Renderer) QJSCLASS(SDL_Renderer)
QJSCLASS(SDL_Camera) QJSCLASS(SDL_Camera)
void SDL_Texture_free(JSRuntime *rt, SDL_Texture *t){
TracyCFreeN(t, "vram");
SDL_DestroyTexture(t);
}
QJSCLASS(SDL_Texture, QJSCLASS(SDL_Texture,
TracyCAllocN(n, n->w*n->h*4, "vram"); TracyCAllocN(n, n->w*n->h*4, "vram");
JS_SetProperty(js, j, width_atom, number2js(js,n->w)); JS_SetProperty(js, j, width_atom, number2js(js,n->w));
JS_SetProperty(js,j,height_atom,number2js(js,n->h)); JS_SetProperty(js,j,height_atom,number2js(js,n->h));
) )
QJSCLASS(SDL_Surface, QJSCLASS(SDL_Surface,
TracyCAllocN(n, n->pitch*n->h, "texture memory"); TracyCAllocN(n, n->pitch*n->h, "texture memory");
JS_SetProperty(js, j, width_atom, number2js(js,n->w)); JS_SetProperty(js, j, width_atom, number2js(js,n->w));
@@ -883,10 +884,10 @@ JSValue js_vector_dot(JSContext *js, JSValue self, int argc, JSValue *argv) {
size_t alen, blen; size_t alen, blen;
float *a = js2floats(js,argv[0], &alen); float *a = js2floats(js,argv[0], &alen);
float *b = js2floats(js,argv[1], &blen); float *b = js2floats(js,argv[1], &blen);
JSValue ret = number2js(js, cblas_sdot(alen, a, 1, b,1)); // JSValue ret = number2js(js, cblas_sdot(alen, a, 1, b,1));
free(a); free(a);
free(b); free(b);
return ret; return JS_UNDEFINED;
}; };
JSC_CCALL(vector_project, return vec22js(js,HMM_ProjV2(js2vec2(js,argv[0]), js2vec2(js,argv[1])))) JSC_CCALL(vector_project, return vec22js(js,HMM_ProjV2(js2vec2(js,argv[0]), js2vec2(js,argv[1]))))
@@ -967,10 +968,12 @@ JSC_CCALL(vector_rotate,
double angle = js2angle(js, argv[1]); double angle = js2angle(js, argv[1]);
HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(js,argv[2]); HMM_Vec2 pivot = JS_IsUndefined(argv[2]) ? v2zero : js2vec2(js,argv[2]);
// vec = vec - pivot // vec = vec - pivot
cblas_saxpy(2, -1.0f, pivot.e, 1, vec.e, 1); // cblas_saxpy(2, -1.0f, pivot.e, 1, vec.e, 1);
vec = HMM_SubV2(vec,pivot);
// Length of the vector (r) // Length of the vector (r)
float r = sqrtf(cblas_sdot(2, vec.e, 1, vec.e, 1)); // float r = sqrtf(cblas_sdot(2, vec.e, 1, vec.e, 1));
float r = HMM_LenV2(vec);
// Update angle // Update angle
angle += atan2f(vec.y, vec.x); angle += atan2f(vec.y, vec.x);
@@ -980,7 +983,8 @@ JSC_CCALL(vector_rotate,
vec.y = r * sinf(angle); vec.y = r * sinf(angle);
// vec = vec + pivot // vec = vec + pivot
cblas_saxpy(2, 1.0f, pivot.e, 1, vec.e, 1); // cblas_saxpy(2, 1.0f, pivot.e, 1, vec.e, 1);
vec = HMM_AddV2(vec,pivot);
// Convert back to JS and return // Convert back to JS and return
return vec22js(js, vec); return vec22js(js, vec);
@@ -1140,7 +1144,7 @@ JSC_CCALL(vector_fastsum,
float sum = 0.0; float sum = 0.0;
size_t len; size_t len;
float *a = get_typed_buffer(js, argv[0], &len); float *a = get_typed_buffer(js, argv[0], &len);
sum = cblas_sasum(len, a,1); // sum = cblas_sasum(len, a,1);
ret = number2js(js,sum); ret = number2js(js,sum);
) )
@@ -1224,7 +1228,7 @@ JSC_CCALL(vector_float32add,
size_t len; size_t len;
float *vec_a = get_typed_buffer(js,self, &len); float *vec_a = get_typed_buffer(js,self, &len);
float *vec_b = get_typed_buffer(js,argv[0], &len); float *vec_b = get_typed_buffer(js,argv[0], &len);
cblas_saxpy(len,1.0f,vec_b,1,vec_a,1); // cblas_saxpy(len,1.0f,vec_b,1,vec_a,1);
JSValue tstack[3]; JSValue tstack[3];
tstack[0] = JS_NewArrayBufferCopy(js,vec_a,sizeof(float)*4); tstack[0] = JS_NewArrayBufferCopy(js,vec_a,sizeof(float)*4);
tstack[1] = JS_UNDEFINED; tstack[1] = JS_UNDEFINED;
@@ -1738,6 +1742,10 @@ static JSValue event2js(JSContext *js, SDL_Event event)
JS_SetPropertyStr(js,e,"sensor", number2js(js,event.gsensor.sensor)); JS_SetPropertyStr(js,e,"sensor", number2js(js,event.gsensor.sensor));
JS_SetPropertyStr(js,e,"sensor_timestamp", number2js(js,event.gsensor.sensor_timestamp)); JS_SetPropertyStr(js,e,"sensor_timestamp", number2js(js,event.gsensor.sensor_timestamp));
break; break;
case SDL_EVENT_USER:
JS_SetPropertyStr(js,e,"cb", JS_DupValue(js,*(JSValue*)event.user.data1));
JS_FreeValue(js,*(JSValue*)event.user.data1);
break;
} }
return e; return e;
} }
@@ -2533,9 +2541,22 @@ JSC_SCALL(prosperon_openurl,
ret = JS_ThrowReferenceError(js, "unable to open url %s: %s\n", str, SDL_GetError()); ret = JS_ThrowReferenceError(js, "unable to open url %s: %s\n", str, SDL_GetError());
) )
JSC_CCALL(prosperon_push_event,
SDL_UserEvent e;
SDL_zero(e);
e.type = SDL_EVENT_USER;
e.timestamp = SDL_GetTicksNS();
e.code = 0;
JSValue fn = JS_DupValue(js,argv[0]);
e.data1 = malloc(sizeof(JSValue));
*(JSValue*)e.data1 = fn;
SDL_PushEvent(&e);
)
static const JSCFunctionListEntry js_prosperon_funcs[] = { static const JSCFunctionListEntry js_prosperon_funcs[] = {
MIST_FUNC_DEF(prosperon, guid, 0), MIST_FUNC_DEF(prosperon, guid, 0),
MIST_FUNC_DEF(prosperon, openurl, 1), MIST_FUNC_DEF(prosperon, openurl, 1),
MIST_FUNC_DEF(prosperon, push_event, 1),
}; };
JSC_CCALL(time_now, JSC_CCALL(time_now,
@@ -2993,7 +3014,9 @@ JSC_CCALL(geometry_rect_pos,
JSC_CCALL(geometry_rect_move, JSC_CCALL(geometry_rect_move,
rect r = js2rect(js,argv[0]); rect r = js2rect(js,argv[0]);
HMM_Vec2 move = js2vec2(js,argv[1]); HMM_Vec2 move = js2vec2(js,argv[1]);
cblas_saxpy(2, 1.0f, move.e, 1, &r, 1); // cblas_saxpy(2, 1.0f, move.e, 1, &r, 1);
r.x += move.x;
r.y += move.y;
return rect2js(js,r); return rect2js(js,r);
) )
@@ -3294,10 +3317,12 @@ JSValue aseframe2js(JSContext *js, ase_frame_t aframe)
JSC_CCALL(os_make_aseprite, JSC_CCALL(os_make_aseprite,
size_t rawlen; size_t rawlen;
void *raw = JS_GetArrayBuffer(js,&rawlen,argv[0]); void *raw = JS_GetArrayBuffer(js,&rawlen,argv[0]);
if (!raw) return JS_ThrowReferenceError(js, "could not load aseprite from supplied array buffer");
ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL); ase_t *ase = cute_aseprite_load_from_memory(raw, rawlen, NULL);
if (!ase)
return JS_ThrowReferenceError(js, "could not load aseprite from supplied array buffer: %s", aseprite_GetError());
int w = ase->w; int w = ase->w;
int h = ase->h; int h = ase->h;
@@ -3700,13 +3725,13 @@ JSC_CCALL(os_make_sprite_mesh,
) )
int detectImageInWebcam(SDL_Surface *a, SDL_Surface *b); int detectImageInWebcam(SDL_Surface *a, SDL_Surface *b);
JSC_CCALL(os_match_img, /*JSC_CCALL(os_match_img,
SDL_Surface *img1 = js2SDL_Surface(js,argv[0]); SDL_Surface *img1 = js2SDL_Surface(js,argv[0]);
SDL_Surface *img2 = js2SDL_Surface(js,argv[1]); SDL_Surface *img2 = js2SDL_Surface(js,argv[1]);
int n = detectImageInWebcam(img1,img2); int n = detectImageInWebcam(img1,img2);
return number2js(js,n); return number2js(js,n);
) )
*/
JSC_CCALL(os_sleep, JSC_CCALL(os_sleep,
double time = js2number(js,argv[0]); double time = js2number(js,argv[0]);
time *= 1000000000.; time *= 1000000000.;
@@ -3768,7 +3793,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, gltf_skin, 1), MIST_FUNC_DEF(os, gltf_skin, 1),
MIST_FUNC_DEF(os, skin_calculate, 1), MIST_FUNC_DEF(os, skin_calculate, 1),
MIST_FUNC_DEF(os, kill, 1), MIST_FUNC_DEF(os, kill, 1),
MIST_FUNC_DEF(os, match_img, 2), // MIST_FUNC_DEF(os, match_img, 2),
MIST_FUNC_DEF(os, sleep, 1), MIST_FUNC_DEF(os, sleep, 1),
}; };