Browse Source

Preview rotation follows device

opengl
Benjamin Schaaf 1 year ago
parent
commit
64b75bcbe5
  1. 4
      data/blit.vert
  2. 7
      src/io_pipeline.c
  3. 2
      src/io_pipeline.h
  4. 114
      src/main.c
  5. 28
      src/process_pipeline.c
  6. 2
      src/process_pipeline.h

4
data/blit.vert

@ -5,10 +5,12 @@ precision mediump float;
attribute vec2 vert;
attribute vec2 tex_coord;
uniform mat3 transform;
varying vec2 uv;
void main() {
uv = tex_coord;
gl_Position = vec4(vert, 0, 1);
gl_Position = vec4(transform * vec3(vert, 1), 1);
}

7
src/io_pipeline.c

@ -75,6 +75,8 @@ static int captures_remaining = 0;
static int preview_width;
static int preview_height;
static int device_rotation;
struct control_state {
bool gain_is_manual;
int gain;
@ -275,6 +277,7 @@ update_process_pipeline()
.burst_length = burst_length,
.preview_width = preview_width,
.preview_height = preview_height,
.device_rotation = device_rotation,
.gain_is_manual = current_controls.gain_is_manual,
.gain = current_controls.gain,
.gain_max = info->gain_max,
@ -521,11 +524,13 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state)
has_changed = has_changed || burst_length != state->burst_length ||
preview_width != state->preview_width ||
preview_height != state->preview_height;
preview_height != state->preview_height ||
device_rotation != state->device_rotation;
burst_length = state->burst_length;
preview_width = state->preview_width;
preview_height = state->preview_height;
device_rotation = state->device_rotation;
if (camera) {
struct control_state previous_desired = desired_controls;

2
src/io_pipeline.h

@ -10,6 +10,8 @@ struct mp_io_pipeline_state {
int preview_width;
int preview_height;
int device_rotation;
bool gain_is_manual;
int gain;

114
src/main.c

@ -40,6 +40,8 @@ static MPCameraMode mode;
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;
@ -95,6 +97,7 @@ update_io_pipeline()
.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,
@ -215,6 +218,7 @@ mp_main_capture_completed(GdkTexture *thumb, const char *fname)
}
static GLuint blit_program;
static GLuint blit_uniform_transform;
static GLuint blit_uniform_texture;
static GLuint solid_program;
static GLuint solid_uniform_color;
@ -247,6 +251,7 @@ preview_realize(GtkGLArea *area)
glBindAttribLocation(blit_program, GL_UTIL_TEX_COORD_ATTRIBUTE, "tex_coord");
check_gl();
blit_uniform_transform = glGetUniformLocation(blit_program, "transform");
blit_uniform_texture = glGetUniformLocation(blit_program, "texture");
GLuint solid_shaders[] = {
@ -266,17 +271,26 @@ preview_realize(GtkGLArea *area)
static void
position_preview(float *offset_x, float *offset_y, float *size_x, float *size_y)
{
int scale = gtk_widget_get_scale_factor(preview);
int preview_height = gtk_widget_get_allocated_height(preview) * scale;
int top_height = gtk_widget_get_allocated_height(preview_top_box) * scale;
int bottom_height = gtk_widget_get_allocated_height(preview_bottom_box) * scale;
int buffer_width, buffer_height;
if (device_rotation == 0 || device_rotation == 180) {
buffer_width = preview_buffer_width;
buffer_height = preview_buffer_height;
} else {
buffer_width = preview_buffer_height;
buffer_height = preview_buffer_width;
}
int scale_factor = gtk_widget_get_scale_factor(preview);
int top_height = 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;
double ratio = preview_buffer_height / (double)preview_buffer_width;
double scale = MIN(preview_width / (float) buffer_width, preview_height / (float) buffer_height);
*offset_x = 0;
*size_x = preview_width;
*size_y = preview_width * ratio;
*size_x = scale * buffer_width;
*size_y = scale * buffer_height;
*offset_x = (preview_width - *size_x) / 2.0;
if (*size_y > inner_height) {
*offset_y = (preview_height - *size_y) / 2.0;
@ -314,6 +328,19 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data)
if (current_preview_buffer) {
glUseProgram(blit_program);
GLfloat rotation_list[4] = { 0, -1, 0, 1 };
int rotation_index = device_rotation / 90;
GLfloat sin_rot = rotation_list[rotation_index];
GLfloat cos_rot = rotation_list[(4 + rotation_index - 1) % 4];
GLfloat matrix[9] = {
cos_rot, sin_rot, 0,
-sin_rot, cos_rot, 0,
0, 0, 1,
};
glUniformMatrix3fv(blit_uniform_transform, 1, GL_FALSE, matrix);
check_gl();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mp_process_pipeline_buffer_get_texture_id(current_preview_buffer));
glUniform1i(blit_uniform_texture, 0);
@ -719,6 +746,62 @@ create_simple_action(GtkApplication *app, const char *name, GCallback callback)
return action;
}
static void display_config_received(GDBusConnection *conn, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
GVariant *result = g_dbus_connection_call_finish(conn, res, &error);
if (!result) {
printf("Failed to get display configuration: %s\n", error->message);
return;
}
GVariant *configs = g_variant_get_child_value(result, 1);
if (g_variant_n_children(configs) == 0) {
return;
}
GVariant *config = g_variant_get_child_value(configs, 0);
GVariant *rot_config = g_variant_get_child_value(config, 7);
uint32_t rotation_index = g_variant_get_uint32(rot_config);
assert(rotation_index < 4);
int new_rotation = rotation_index * 90;
if (new_rotation != device_rotation) {
device_rotation = new_rotation;
update_io_pipeline();
}
}
static void update_screen_rotation(GDBusConnection *conn)
{
g_dbus_connection_call(conn,
"org.gnome.Mutter.DisplayConfig",
"/org/gnome/Mutter/DisplayConfig",
"org.gnome.Mutter.DisplayConfig",
"GetResources",
NULL,
NULL,
G_DBUS_CALL_FLAGS_NO_AUTO_START,
-1,
NULL,
(GAsyncReadyCallback)display_config_received,
NULL);
}
static void on_screen_rotate(
GDBusConnection *conn,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
update_screen_rotation(conn);
}
static void
activate(GtkApplication *app, gpointer data)
{
@ -779,6 +862,21 @@ activate(GtkApplication *app, gpointer data)
const char *quit_accels[] = { "<Ctrl>q", "<Ctrl>w", NULL };
gtk_application_set_accels_for_action(app, "app.quit", quit_accels);
// Listen for phosh rotation
GDBusConnection *conn = g_application_get_dbus_connection(G_APPLICATION(app));
g_dbus_connection_signal_subscribe(
conn,
NULL,
"org.gnome.Mutter.DisplayConfig",
"MonitorsChanged",
"/org/gnome/Mutter/DisplayConfig",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
&on_screen_rotate,
NULL,
NULL);
update_screen_rotation(conn);
mp_io_pipeline_start();
gtk_application_add_window(app, GTK_WINDOW(window));

28
src/process_pipeline.c

@ -31,6 +31,7 @@ static volatile int frames_processed = 0;
static volatile int frames_received = 0;
static const struct mp_camera_config *camera;
static int camera_rotation;
static MPCameraMode mode;
@ -40,6 +41,8 @@ static int captures_remaining = 0;
static int preview_width;
static int preview_height;
static int device_rotation;
static int output_buffer_width = -1;
static int output_buffer_height = -1;
@ -370,13 +373,13 @@ process_image_for_capture(const uint8_t *image, int count)
TIFFSetField(tif, TIFFTAG_MAKE, mp_get_device_make());
TIFFSetField(tif, TIFFTAG_MODEL, mp_get_device_model());
uint16_t orientation;
if (camera->rotate == 0) {
if (camera_rotation == 0) {
orientation = camera->mirrored ? ORIENTATION_TOPRIGHT :
ORIENTATION_TOPLEFT;
} else if (camera->rotate == 90) {
} else if (camera_rotation == 90) {
orientation = camera->mirrored ? ORIENTATION_RIGHTBOT :
ORIENTATION_LEFTBOT;
} else if (camera->rotate == 180) {
} else if (camera_rotation == 180) {
orientation = camera->mirrored ? ORIENTATION_BOTLEFT :
ORIENTATION_BOTRIGHT;
} else {
@ -583,7 +586,7 @@ process_image(MPPipeline *pipeline, const MPBuffer *buffer)
memcpy(image, buffer->data, size);
mp_io_pipeline_release_buffer(buffer->index);
MPZBarImage *zbar_image = mp_zbar_image_new(image, mode.pixel_format, mode.width, mode.height, camera->rotate, camera->mirrored);
MPZBarImage *zbar_image = mp_zbar_image_new(image, mode.pixel_format, mode.width, mode.height, camera_rotation, camera->mirrored);
mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image));
#ifdef PROFILE_PROCESS
@ -692,10 +695,21 @@ on_output_changed()
camera->blacklevel);
}
static int
mod(int a, int b)
{
int r = a % b;
return r < 0 ? r + b : r;
}
static void
update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
{
const bool output_changed = (!mp_camera_mode_is_equivalent(&mode, &state->mode) || preview_width != state->preview_width || preview_height != state->preview_height);
const bool output_changed =
!mp_camera_mode_is_equivalent(&mode, &state->mode)
|| preview_width != state->preview_width
|| preview_height != state->preview_height
|| device_rotation != state->device_rotation;
camera = state->camera;
mode = state->mode;
@ -703,6 +717,8 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state
preview_width = state->preview_width;
preview_height = state->preview_height;
device_rotation = state->device_rotation;
burst_length = state->burst_length;
// gain_is_manual = state->gain_is_manual;
@ -713,6 +729,8 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state
exposure = state->exposure;
if (output_changed) {
camera_rotation = mod(camera->rotate - device_rotation, 360);
on_output_changed();
}

2
src/process_pipeline.h

@ -13,6 +13,8 @@ struct mp_process_pipeline_state {
int preview_width;
int preview_height;
int device_rotation;
bool gain_is_manual;
int gain;
int gain_max;

Loading…
Cancel
Save