diff --git a/include/c-ray/c-ray.h b/include/c-ray/c-ray.h index 6c6ff34e..5017920d 100644 --- a/include/c-ray/c-ray.h +++ b/include/c-ray/c-ray.h @@ -86,7 +86,6 @@ struct cr_tile { }; struct cr_renderer_cb_info { - void *user_data; const struct cr_bitmap *fb; const struct cr_tile *tiles; size_t tiles_count; @@ -99,17 +98,20 @@ struct cr_renderer_cb_info { bool paused; }; -struct cr_renderer_callbacks { - void (*cr_renderer_on_start)(struct cr_renderer_cb_info *info); - void (*cr_renderer_on_stop)(struct cr_renderer_cb_info *info); - void (*cr_renderer_status)(struct cr_renderer_cb_info *info); - void (*cr_renderer_on_state_changed)(struct cr_renderer_cb_info *info); - void *user_data; +enum cr_renderer_callback { + cr_cb_on_start = 0, + cr_cb_on_stop, + cr_cb_status_update, + cr_cb_on_state_changed }; +CR_EXPORT bool cr_renderer_set_callback(struct cr_renderer *ext, + enum cr_renderer_callback t, + void (*callback_fn)(struct cr_renderer_cb_info *, void *), + void *user_data); + CR_EXPORT bool cr_renderer_set_num_pref(struct cr_renderer *ext, enum cr_renderer_param p, uint64_t num); CR_EXPORT bool cr_renderer_set_str_pref(struct cr_renderer *ext, enum cr_renderer_param p, const char *str); -CR_EXPORT bool cr_renderer_set_callbacks(struct cr_renderer *ext, struct cr_renderer_callbacks cb); CR_EXPORT void cr_renderer_stop(struct cr_renderer *ext, bool should_save); CR_EXPORT void cr_renderer_toggle_pause(struct cr_renderer *ext); CR_EXPORT const char *cr_renderer_get_str_pref(struct cr_renderer *ext, enum cr_renderer_param p); diff --git a/src/driver/main.c b/src/driver/main.c index 422305d1..afd74e06 100644 --- a/src/driver/main.c +++ b/src/driver/main.c @@ -26,19 +26,20 @@ struct usr_data { struct sdl_prefs p; }; -static void on_start(struct cr_renderer_cb_info *info) { - struct usr_data *d = info->user_data; +static void on_start(struct cr_renderer_cb_info *info, void *user_data) { + struct usr_data *d = user_data; if (d->p.enabled && info->fb) d->w = win_try_init(&d->p, info->fb->width, info->fb->height); } -static void on_stop(struct cr_renderer_cb_info *info) { - struct usr_data *d = info->user_data; +static void on_stop(struct cr_renderer_cb_info *info, void *user_data) { + (void)info; + struct usr_data *d = user_data; if (d->w) win_destroy(d->w); } -static void status(struct cr_renderer_cb_info *state) { +static void status(struct cr_renderer_cb_info *state, void *user_data) { static int pauser = 0; - struct usr_data *d = state->user_data; + struct usr_data *d = user_data; if (!d) return; struct input_state in = win_update(d->w, state->tiles, state->tiles_count, (struct texture *)state->fb); if (in.stop_render) cr_renderer_stop(d->r, in.should_save); @@ -178,15 +179,13 @@ int main(int argc, char *argv[]) { } } - cr_renderer_set_callbacks(renderer, (struct cr_renderer_callbacks){ - .cr_renderer_on_start = on_start, - .cr_renderer_on_stop = on_stop, - .cr_renderer_status = status, - .user_data = &(struct usr_data){ - .p = sdl_parse(cJSON_GetObjectItem(input_json, "display")), - .r = renderer - } - }); + struct usr_data usrdata = (struct usr_data){ + .p = sdl_parse(cJSON_GetObjectItem(input_json, "display")), + .r = renderer, + }; + cr_renderer_set_callback(renderer, cr_cb_on_start, on_start, &usrdata); + cr_renderer_set_callback(renderer, cr_cb_on_stop, on_stop, &usrdata); + cr_renderer_set_callback(renderer, cr_cb_status_update, status, &usrdata); const cJSON *r = cJSON_GetObjectItem(input_json, "renderer"); const cJSON *file_type = cJSON_GetObjectItem(r, "fileType"); diff --git a/src/lib/api/c-ray.c b/src/lib/api/c-ray.c index 68207d6e..58b4c18a 100644 --- a/src/lib/api/c-ray.c +++ b/src/lib/api/c-ray.c @@ -53,6 +53,18 @@ struct cr_renderer *cr_new_renderer() { return (struct cr_renderer *)renderer_new(); } +bool cr_renderer_set_callback(struct cr_renderer *ext, + enum cr_renderer_callback t, + void (*callback_fn)(struct cr_renderer_cb_info *, void *), + void *user_data) { + if (!ext) return false; + if (t > cr_cb_on_state_changed) return false; + struct renderer *r = (struct renderer *)ext; + r->state.callbacks[t].fn = callback_fn; + r->state.callbacks[t].user_data = user_data; + return true; +} + bool cr_renderer_set_num_pref(struct cr_renderer *ext, enum cr_renderer_param p, uint64_t num) { if (!ext) return false; struct renderer *r = (struct renderer *)ext; @@ -149,13 +161,6 @@ bool cr_renderer_set_str_pref(struct cr_renderer *ext, enum cr_renderer_param p, return false; } -bool cr_renderer_set_callbacks(struct cr_renderer *ext, struct cr_renderer_callbacks cb) { - if (!ext) return false; - struct renderer *r = (struct renderer *)ext; - r->state.cb = cb; - return true; -} - void cr_renderer_stop(struct cr_renderer *ext, bool should_save) { if (!ext) return; struct renderer *r = (struct renderer *)ext; diff --git a/src/lib/renderer/renderer.c b/src/lib/renderer/renderer.c index 450f7e97..29188bb9 100644 --- a/src/lib/renderer/renderer.c +++ b/src/lib/renderer/renderer.c @@ -75,7 +75,6 @@ void update_cb_info(struct renderer *r, struct tile_set *set, struct cr_renderer static uint64_t ctr = 1; static uint64_t avg_per_sample_us = 0; static uint64_t avg_tile_pass_us = 0; - i->user_data = r->state.cb.user_data; // Notice: Casting away const here memcpy((struct cr_tile *)i->tiles, set->tiles.items, sizeof(*i->tiles) * i->tiles_count); if (!r->state.workers.count) return; @@ -181,12 +180,14 @@ struct cr_bitmap *renderer_render(struct renderer *r) { struct cr_tile *info_tiles = calloc(set.tiles.count, sizeof(*info_tiles)); struct cr_renderer_cb_info cb_info = { .tiles = info_tiles, - .tiles_count = set.tiles.count + .tiles_count = set.tiles.count, + .fb = (struct cr_bitmap *)output }; - cb_info.fb = (struct cr_bitmap *)output; - if (r->state.cb.cr_renderer_on_start) { + + struct callback start = r->state.callbacks[cr_cb_on_start]; + if (start.fn) { update_cb_info(r, &set, &cb_info); - r->state.cb.cr_renderer_on_start(&cb_info); + start.fn(&cb_info, start.user_data); } logr(info, "Pathtracing%s...\n", r->prefs.iterative ? " iteratively" : ""); @@ -245,9 +246,10 @@ struct cr_bitmap *renderer_render(struct renderer *r) { r->state.render_aborted = true; } - if (r->state.cb.cr_renderer_status) { + struct callback status = r->state.callbacks[cr_cb_status_update]; + if (status.fn) { update_cb_info(r, &set, &cb_info); - r->state.cb.cr_renderer_status(&cb_info); + status.fn(&cb_info, status.user_data); } size_t inactive = 0; @@ -263,9 +265,10 @@ struct cr_bitmap *renderer_render(struct renderer *r) { for (size_t w = 0; w < r->state.workers.count; ++w) { thread_wait(&r->state.workers.items[w].thread); } - if (r->state.cb.cr_renderer_on_stop) { + struct callback stop = r->state.callbacks[cr_cb_on_stop]; + if (stop.fn) { update_cb_info(r, &set, &cb_info); - r->state.cb.cr_renderer_on_stop(&cb_info); + stop.fn(&cb_info, stop.user_data); } if (info_tiles) free(info_tiles); destroyTexture(render_buf); diff --git a/src/lib/renderer/renderer.h b/src/lib/renderer/renderer.h index 2f95b183..03ac8f59 100644 --- a/src/lib/renderer/renderer.h +++ b/src/lib/renderer/renderer.h @@ -36,6 +36,11 @@ struct worker { typedef struct worker worker; dyn_array_def(worker); +struct callback { + void (*fn)(struct cr_renderer_cb_info *, void *); + void *user_data; +}; + /// Renderer state data struct state { size_t finishedPasses; // For interactive mode @@ -44,7 +49,7 @@ struct state { bool saveImage; struct worker_arr workers; struct render_client_arr clients; - struct cr_renderer_callbacks cb; + struct callback callbacks[4]; }; /// Preferences data (Set by user) diff --git a/wrappers/c_ray.py b/wrappers/c_ray.py index 95abb079..7ffe7bae 100644 --- a/wrappers/c_ray.py +++ b/wrappers/c_ray.py @@ -267,6 +267,21 @@ def instance_new(self): def set_background(self, material): return _lib.scene_set_background(self.s_ptr, material) +class cr_cb_info(ct.Structure): + _fields_ = [ + ("fb", ct.POINTER(cr_bitmap)), + ("tiles", ct.POINTER(ct.c_void_p)), # TODO + ("tiles_count", ct.c_size_t), + ("active_threads", ct.c_size_t), + ("avg_per_ray_us", ct.c_double), + ("samples_per_sec", ct.c_int64), + ("eta_ms", ct.c_int64), + ("completion", ct.c_double), + ("paused", ct.c_bool), + ] + +cr_cb_func = ct.CFUNCTYPE(ct.c_void_p, ct.POINTER(cr_cb_info), ct.POINTER(ct.c_void_p)) + class renderer: def __init__(self, path = None): self.obj_ptr = _lib.new_renderer() @@ -277,8 +292,10 @@ def __init__(self, path = None): def close(self): del(self.obj_ptr) - def set_callbacks(self, on_start, on_stop, on_status, on_state_changed, user_data): - _lib.renderer_set_callbacks(self.obj_ptr, on_start, on_stop, on_status, on_state_changed, user_data) + def set_callback(self, type, callback_fn, user_data): + if not callable(callback_fn): + raise TypeError("callback_fn not callable") + _lib.renderer_set_callback(self.obj_ptr, type, cr_cb_func(callback_fn), user_data) def stop(should_save): _lib.renderer_stop(self.obj_ptr, should_save) diff --git a/wrappers/cray_wrap.c b/wrappers/cray_wrap.c index 6f60c49a..bc733750 100644 --- a/wrappers/cray_wrap.c +++ b/wrappers/cray_wrap.c @@ -67,42 +67,27 @@ static PyObject *py_cr_renderer_set_str_pref(PyObject *self, PyObject *args) { return PyBool_FromLong(ret); } -static PyObject *py_cr_renderer_set_callbacks(PyObject *self, PyObject *args) { +static PyObject *py_cr_renderer_set_callback(PyObject *self, PyObject *args) { (void)self; (void)args; PyObject *r_ext; - PyObject *cb_on_start; - PyObject *cb_on_stop; - PyObject *cb_status; - PyObject *cb_on_state_changed; + enum cr_renderer_callback callback_type; + PyObject *callback_fn; void *user_data = NULL; - if (!PyArg_ParseTuple(args, "OOOOO|p", &r_ext, &cb_on_start, &cb_on_stop, &cb_status, &cb_on_state_changed, &user_data)) { + if (!PyArg_ParseTuple(args, "OIO|p", &r_ext, &callback_type, &callback_fn, &user_data)) { return NULL; } - struct cr_renderer *r = PyCapsule_GetPointer(r_ext, "cray.cr_renderer"); - if (!PyCallable_Check(cb_on_start)) { - PyErr_SetString(PyExc_ValueError, "on_start must be callable"); - return NULL; - } - if (!PyCallable_Check(cb_on_stop)) { - PyErr_SetString(PyExc_ValueError, "on_stop must be callable"); - return NULL; - } - if (!PyCallable_Check(cb_status)) { - PyErr_SetString(PyExc_ValueError, "status must be callable"); + if (callback_type > cr_cb_status_update) { + PyErr_SetString(PyExc_ValueError, "Unknown callback type"); return NULL; } - if (!PyCallable_Check(cb_on_state_changed)) { - PyErr_SetString(PyExc_ValueError, "on_state_changed must be callable"); + struct cr_renderer *r = PyCapsule_GetPointer(r_ext, "cray.cr_renderer"); + if (!PyCallable_Check(callback_fn)) { + PyErr_SetString(PyExc_ValueError, "callback must be callable"); return NULL; } - bool ret = cr_renderer_set_callbacks(r, (struct cr_renderer_callbacks){ - .cr_renderer_on_start = PyCapsule_GetPointer(cb_on_start, NULL), - .cr_renderer_on_stop = PyCapsule_GetPointer(cb_on_stop, NULL), - .cr_renderer_status = PyCapsule_GetPointer(cb_status, NULL), - .cr_renderer_on_state_changed = PyCapsule_GetPointer(cb_on_state_changed, NULL), - .user_data = user_data - }); + + bool ret = cr_renderer_set_callback(r, callback_type, PyCapsule_GetPointer(callback_fn, NULL), user_data); return PyBool_FromLong(ret); } @@ -566,7 +551,7 @@ static PyMethodDef cray_methods[] = { // { "destroy_renderer", py_cr_destroy_renderer, METH_VARARGS, "" }, { "renderer_set_num_pref", py_cr_renderer_set_num_pref, METH_VARARGS, "" }, { "renderer_set_str_pref", py_cr_renderer_set_str_pref, METH_VARARGS, "" }, - { "renderer_set_callbacks", py_cr_renderer_set_callbacks, METH_VARARGS, "" }, + { "renderer_set_callback", py_cr_renderer_set_callback, METH_VARARGS, "" }, { "renderer_stop", py_cr_renderer_stop, METH_VARARGS, "" }, { "renderer_toggle_pause", py_cr_renderer_toggle_pause, METH_VARARGS, "" }, { "renderer_get_str_pref", py_cr_renderer_get_str_pref, METH_VARARGS, "" },