Skip to content

Commit

Permalink
Add experimental support for filters
Browse files Browse the repository at this point in the history
Filters are a bit similar to tools, with a few difference:

- they only have a UI callback, but no ability to draw (for now at
  least).

- They don't require any icon or fixed action id, so we can more easily
  add filters: just need to add a c file with the FILTER_REGISTER macro.

- They show up in a special menu, instead of in the tool panel.

The idea is to use the filters for operations that don't require a full
drawing tool, like color correction, voxel effects, etc.

Still a work in progress.
  • Loading branch information
guillaumechereau committed Mar 23, 2024
1 parent cb56198 commit c591d94
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/filters.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* Goxel 3D voxels editor
*
* copyright (c) 2024 Guillaume Chereau <guillaume@noctua-software.com>
*
* Goxel is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
* Goxel is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* You should have received a copy of the GNU General Public License along
* with goxel. If not, see <http://www.gnu.org/licenses/>.
*/

#include "goxel.h"
#include "../ext_src/stb/stb_ds.h"

// stb array of registered filters.
static filter_t **g_filters = NULL;

static void a_filter_open(void *data)
{
filter_t *filter = data;
LOG_D("Open filter %s", filter->name);
goxel.gui.current_filter = (filter_t*)data;
}

void filter_register_(filter_t *filter)
{
action_t action;
action = (action_t) {
.id = filter->action_id,
.default_shortcut = filter->default_shortcut,
.cfunc_data = a_filter_open,
.data = (void*)filter,
.flags = ACTION_CAN_EDIT_SHORTCUT,
};
action_register(&action, 0);
arrput(g_filters, filter);
}


void filters_iter_all(
void *arg, void (*f)(void *arg, const filter_t *filter))
{
int i;
for (i = 0; i < arrlen(g_filters); i++) {
f(arg, g_filters[i]);
}
}
50 changes: 50 additions & 0 deletions src/filters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* Goxel 3D voxels editor
*
* copyright (c) 2024 Guillaume Chereau <guillaume@noctua-software.com>
*
* Goxel is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
* Goxel is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* You should have received a copy of the GNU General Public License along with
* goxel. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef FILTERS_H
#define FILTERS_H

typedef struct filter filter_t;

struct filter {
int (*gui_fn)(filter_t *filter);
const char *name;
const char *action_id;
const char *default_shortcut;
};

#define FILTER_REGISTER(id_, klass_, ...) \
static klass_ GOX_filter_##id_ = {\
.filter = { \
.action_id = "filter_open_" #id_, __VA_ARGS__ \
} \
}; \
__attribute__((constructor)) \
static void GOX_register_filter_##id_(void) { \
filter_register_(&GOX_filter_##id_.filter); \
}

void filter_register_(filter_t *filter);

/**
* Iter all the registered filters
*/
void filters_iter_all(
void *arg, void (*f)(void *arg, const filter_t *filter));

#endif // FILTERS_H
41 changes: 41 additions & 0 deletions src/filters/dummy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* Goxel 3D voxels editor
*
* copyright (c) 2024-present Guillaume Chereau <guillaume@noctua-software.com>
*
* Goxel is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
* Goxel is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* You should have received a copy of the GNU General Public License along with
* goxel. If not, see <http://www.gnu.org/licenses/>.
*/

#include "goxel.h"

/*
* Dummy filter, just here for now until we have real filters.
*/

typedef struct {
filter_t filter;
int x;
} filter_dummy_t;

static int gui(filter_t *filter)
{
filter_dummy_t *dummy = (void*)filter;
gui_text_wrapped("Just a test of a filter that does nothing.");
gui_input_int("X", &dummy->x, 0, 0);
return 0;
}

FILTER_REGISTER(dummy, filter_dummy_t,
.name = "Dummy",
.gui_fn = gui,
)
2 changes: 2 additions & 0 deletions src/goxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "assets.h"
#include "block_def.h"
#include "camera.h"
#include "filters.h"
#include "gesture.h"
#include "gesture3d.h"
#include "gui.h"
Expand Down Expand Up @@ -534,6 +535,7 @@ typedef struct goxel
int current_panel; // Index of the current visible control panel.
float panel_width;
float viewport[4];
filter_t *current_filter;
} gui;

char **recent_files; // stb arraw of most recently used files.
Expand Down
13 changes: 13 additions & 0 deletions src/gui/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ void gui_app(void)
const float spacing = 8;
int flags;
int i;
filter_t *filter;

goxel.show_export_viewport = false;

Expand Down Expand Up @@ -178,6 +179,18 @@ void gui_app(void)
gui_window_end();
}

filter = goxel.gui.current_filter;
if (filter) {
// XXX: we should have a way to center the filter window.
gui_window_begin(filter->name, 100, 100, goxel.gui.panel_width, 0,
GUI_WINDOW_MOVABLE);
if (gui_panel_header(filter->name)) {
goxel.gui.current_filter = NULL;
}
filter->gui_fn(filter);
gui_window_end();
}

goxel.pathtrace = goxel.pathtracer.status &&
(goxel.gui.current_panel == PANEL_RENDER ||
PANELS[PANEL_RENDER].detached);
Expand Down
14 changes: 14 additions & 0 deletions src/gui/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ static void on_script(void *user, const char *name)
script_execute(name);
}

static void on_filter(void *user, const filter_t *filter)
{
const action_t *action;
if (gui_menu_item(0, filter->name, true)) {
action = action_get_by_name(filter->action_id);
assert(action);
action_exec(action);
}
}

void gui_menu(void)
{
camera_t *cam;
Expand Down Expand Up @@ -151,6 +161,10 @@ void gui_menu(void)
gui_menu_item(ACTION_view_default, _(RESET), true);
gui_menu_end();
}
if (gui_menu_begin("Filters", true)) { // Note: to translate.
filters_iter_all(NULL, on_filter);
gui_menu_end();
}
if (gui_menu_begin("Scripts", true)) {
if (gui_menu_item(0, "About Scripts", true))
gui_open_popup("Scripts", 0, NULL, gui_about_scripts_popup);
Expand Down

0 comments on commit c591d94

Please sign in to comment.