diff --git a/CMakeLists.txt b/CMakeLists.txt index d565e90..f73446d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ add_custom_target( ) file(GLOB srcs src/*.c src/*h) -add_executable(megapixels-gtk ${srcs} ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C}) +add_executable(megapixels-gtk ${srcs} ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} src/state.h) set_source_files_properties( ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} PROPERTIES GENERATED TRUE diff --git a/meson.build b/meson.build index c49c9ae..bcfeb4a 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('megapixels', 'c', version: '1.6.1') +project('megapixels', 'c', version: '2.0.0') gnome = import('gnome') gtkdep = dependency('gtk4') diff --git a/src/main.c b/src/main.c index fcce346..1bb5ca2 100644 --- a/src/main.c +++ b/src/main.c @@ -4,6 +4,7 @@ #include "gl_util.h" #include "io_pipeline.h" #include "process_pipeline.h" +#include "state.h" #include #include #include @@ -47,30 +48,11 @@ RENDERDOC_API_1_1_2 *rdoc_api = NULL; enum user_control { USER_CONTROL_ISO, USER_CONTROL_SHUTTER }; -libmegapixels_devconfig *configuration = { 0 }; -libmegapixels_camera *camera = NULL; -int current_camera_index = 0; +mp_state_main state; static bool camera_is_initialized = false; struct mp_main_state current_state = { 0 }; -static int preview_width = -1; -static int preview_height = -1; - -static int device_rotation = 0; - -static bool gain_is_manual = false; -static int gain; -static int gain_max; - -static bool exposure_is_manual = false; -static int exposure; - -static bool has_auto_focus_continuous; -static bool has_auto_focus_start; - -static bool flash_enabled = false; - static MPProcessPipelineBuffer *current_preview_buffer = NULL; static int preview_buffer_width = -1; static int preview_buffer_height = -1; @@ -79,8 +61,6 @@ static char last_path[260] = ""; static MPZBarScanResult *zbar_result = NULL; -static int burst_length = 4; - // Widgets GtkWidget *preview; GtkWidget *main_stack; @@ -117,22 +97,21 @@ static void update_io_pipeline() { struct mp_io_pipeline_state io_state = { - .camera = camera, - .burst_length = burst_length, - .preview_width = preview_width, - .preview_height = preview_height, - .device_rotation = device_rotation, - .gain_is_manual = gain_is_manual, - .gain = gain, - .exposure_is_manual = exposure_is_manual, - .exposure = exposure, - .flash_enabled = flash_enabled, + .camera = state.camera, + .burst_length = state.burst_length, + .preview_width = state.preview_width, + .preview_height = state.preview_height, + .device_rotation = state.device_rotation, + .gain_is_manual = state.gain_is_manual, + .gain = state.gain, + .exposure_is_manual = state.exposure_is_manual, + .exposure = state.exposure, + .flash_enabled = state.flash_enabled, }; mp_io_pipeline_update_state(&io_state); // Make the right settings available for the camera - // TODO: Implement flash again - gtk_widget_set_visible(flash_button, false); + gtk_widget_set_visible(flash_button, state.flash_enabled); } static bool @@ -145,13 +124,13 @@ update_state(const struct mp_main_state *state) if (current_state.camera == state->camera) { current_state.mode = state->mode; - if (!gain_is_manual) { - gain = state->gain; + if (!state.gain_is_manual) { + state.gain = state->gain; } - gain_max = state->gain_max; + state.gain_max = state->gain_max; - if (!exposure_is_manual) { - exposure = state->exposure; + if (!state.exposure_is_manual) { + state.exposure = state->exposure; } has_auto_focus_continuous = state->has_auto_focus_continuous; @@ -328,7 +307,7 @@ static void position_preview(float *offset_x, float *offset_y, float *size_x, float *size_y) { int buffer_width, buffer_height; - if (device_rotation == 0 || device_rotation == 180) { + if (state.device_rotation == 0 || state.device_rotation == 180) { buffer_width = preview_buffer_width; buffer_height = preview_buffer_height; } else { @@ -341,18 +320,18 @@ position_preview(float *offset_x, float *offset_y, float *size_x, float *size_y) gtk_widget_get_allocated_height(preview_top_box) * scale_factor; int bottom_height = gtk_widget_get_allocated_height(preview_bottom_box) * scale_factor; - int inner_height = preview_height - top_height - bottom_height; + int inner_height = state.preview_height - top_height - bottom_height; - double scale = MIN(preview_width / (float)buffer_width, - preview_height / (float)buffer_height); + double scale = MIN(state.preview_width / (float)buffer_width, + state.preview_height / (float)buffer_height); *size_x = scale * buffer_width; *size_y = scale * buffer_height; - *offset_x = (preview_width - *size_x) / 2.0; + *offset_x = (state.preview_width - *size_x) / 2.0; if (*size_y > inner_height) { - *offset_y = (preview_height - *size_y) / 2.0; + *offset_y = (state.preview_height - *size_y) / 2.0; } else { *offset_y = top_height + (inner_height - *size_y) / 2.0; } @@ -380,13 +359,14 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data) float offset_x, offset_y, size_x, size_y; position_preview(&offset_x, &offset_y, &size_x, &size_y); - glViewport(offset_x, preview_height - size_y - offset_y, size_x, size_y); + glViewport( + offset_x, state.preview_height - size_y - offset_y, size_x, size_y); if (current_preview_buffer) { glUseProgram(blit_program); GLfloat rotation_list[4] = { 0, -1, 0, 1 }; - int rotation_index = device_rotation / 90; + int rotation_index = state.device_rotation / 90; GLfloat sin_rot = rotation_list[rotation_index]; GLfloat cos_rot = rotation_list[(4 + rotation_index - 1) % 4]; @@ -493,9 +473,9 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data) static gboolean preview_resize(GtkWidget *widget, int width, int height, gpointer data) { - if (preview_width != width || preview_height != height) { - preview_width = width; - preview_height = height; + if (state.preview_width != width || state.preview_height != height) { + state.preview_width = width; + state.preview_height = height; update_io_pipeline(); } @@ -689,7 +669,7 @@ preview_pressed(GtkGestureClick *gesture, int n_press, double x, double y) } // Tapped preview image itself, try focussing - if (has_auto_focus_start) { + if (state.has_auto_focus_start) { mp_io_pipeline_focus(); } } @@ -697,11 +677,14 @@ preview_pressed(GtkGestureClick *gesture, int n_press, double x, double y) static void run_camera_switch_action(GSimpleAction *action, GVariant *param, gpointer user_data) { - current_camera_index++; - if (current_camera_index > configuration->count) { - current_camera_index = 0; + int new_index = state.camera->index + 1; + if (new_index > state.configuration->count) { + new_index = 0; } - camera = configuration->cameras[current_camera_index]; + + state.camera = state.configuration->cameras[new_index]; + // TODO: allow setting burst length in the config + state.burst_length = 5; update_io_pipeline(); } @@ -796,8 +779,8 @@ open_controls(GtkWidget *parent, static void set_gain(double value) { - if (gain != (int)value) { - gain = value; + if (state.gain != (int)value) { + state.gain = value; update_io_pipeline(); } } @@ -805,8 +788,8 @@ set_gain(double value) static void set_gain_auto(bool is_auto) { - if (gain_is_manual != !is_auto) { - gain_is_manual = !is_auto; + if (state.gain_is_manual != !is_auto) { + state.gain_is_manual = !is_auto; update_io_pipeline(); } } @@ -817,9 +800,9 @@ open_iso_controls(GtkWidget *button, gpointer user_data) open_controls(button, "ISO", 0, - gain_max, - gain, - !gain_is_manual, + state.gain_max, + state.gain, + !state.gain_is_manual, set_gain, set_gain_auto); } @@ -840,8 +823,8 @@ set_shutter(double value) static void set_shutter_auto(bool is_auto) { - if (exposure_is_manual != !is_auto) { - exposure_is_manual = !is_auto; + if (state.exposure_is_manual != !is_auto) { + state.exposure_is_manual = !is_auto; update_io_pipeline(); } } @@ -853,8 +836,8 @@ open_shutter_controls(GtkWidget *button, gpointer user_data) "Shutter", 1.0, 360.0, - exposure, - !exposure_is_manual, + state.exposure, + !state.exposure_is_manual, set_shutter, set_shutter_auto); } @@ -862,11 +845,11 @@ open_shutter_controls(GtkWidget *button, gpointer user_data) static void flash_button_clicked(GtkWidget *button, gpointer user_data) { - flash_enabled = !flash_enabled; + state.flash_enabled = !state.flash_enabled; update_io_pipeline(); const char *icon_name = - flash_enabled ? "flash-enabled-symbolic" : "flash-disabled-symbolic"; + state.flash_enabled ? "flash-enabled-symbolic" : "flash-disabled-symbolic"; gtk_button_set_icon_name(GTK_BUTTON(button), icon_name); } @@ -876,8 +859,7 @@ on_realize(GtkWidget *window, gpointer *data) GtkNative *native = gtk_widget_get_native(window); mp_process_pipeline_init_gl(gtk_native_get_surface(native)); - current_camera_index = 0; - camera = configuration->cameras[0]; + state.camera = state.configuration->cameras[0]; update_io_pipeline(); } @@ -893,7 +875,7 @@ create_simple_action(GtkApplication *app, const char *name, GCallback callback) static void update_ui_rotation() { - if (device_rotation == 0 || device_rotation == 180) { + if (state.device_rotation == 0 || state.device_rotation == 180) { // Portrait gtk_widget_set_halign(preview_top_box, GTK_ALIGN_FILL); gtk_orientable_set_orientation(GTK_ORIENTABLE(preview_top_box), @@ -903,7 +885,7 @@ update_ui_rotation() gtk_orientable_set_orientation(GTK_ORIENTABLE(preview_bottom_box), GTK_ORIENTATION_HORIZONTAL); - if (device_rotation == 0) { + if (state.device_rotation == 0) { gtk_widget_set_valign(preview_top_box, GTK_ALIGN_START); gtk_widget_set_valign(preview_bottom_box, GTK_ALIGN_END); } else { @@ -920,7 +902,7 @@ update_ui_rotation() gtk_orientable_set_orientation(GTK_ORIENTABLE(preview_bottom_box), GTK_ORIENTATION_VERTICAL); - if (device_rotation == 90) { + if (state.device_rotation == 90) { gtk_widget_set_halign(preview_top_box, GTK_ALIGN_END); gtk_widget_set_halign(preview_bottom_box, GTK_ALIGN_START); } else { @@ -1036,8 +1018,8 @@ wl_handle_geometry(void *data, assert(transform < 4); int new_rotation = transform * 90; - if (new_rotation != device_rotation) { - device_rotation = new_rotation; + if (new_rotation != state.device_rotation) { + state.device_rotation = new_rotation; update_io_pipeline(); update_ui_rotation(); } @@ -1110,8 +1092,8 @@ xevent_handler(GdkDisplay *display, XEvent *xevent, gpointer data) new_rotation = 270; break; } - if (new_rotation != device_rotation) { - device_rotation = new_rotation; + if (new_rotation != state.device_rotation) { + state.device_rotation = new_rotation; update_io_pipeline(); update_ui_rotation(); } @@ -1281,8 +1263,8 @@ activate(GtkApplication *app, gpointer data) new_rotation = 270; break; } - if (new_rotation != device_rotation) { - device_rotation = new_rotation; + if (new_rotation != state.device_rotation) { + state.device_rotation = new_rotation; update_ui_rotation(); } } @@ -1342,14 +1324,14 @@ main(int argc, char *argv[]) } #endif char configfile[PATH_MAX]; - libmegapixels_init(&configuration); + libmegapixels_init(&state.configuration); if (libmegapixels_find_config(configfile)) { - if (!libmegapixels_load_file(configuration, configfile)) { + if (!libmegapixels_load_file(state.configuration, configfile)) { fprintf(stderr, "Could not load config\n"); return 1; } } else { - if (!libmegapixels_load_uvc(configuration)) { + if (!libmegapixels_load_uvc(state.configuration)) { fprintf(stderr, "No config found\n"); return 1; } diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..c95e331 --- /dev/null +++ b/src/state.h @@ -0,0 +1,26 @@ +#include +#include + +typedef struct state_main { + libmegapixels_devconfig *configuration; + libmegapixels_camera *camera; + + int preview_width; + int preview_height; + int device_rotation; + + int burst_length; + + // Control state + bool gain_is_manual; + int gain; + int gain_max; + + bool exposure_is_manual; + int exposure; + + bool flash_enabled; + + bool has_auto_focus_continuous; + bool has_auto_focus_start; +} mp_state_main; \ No newline at end of file