瀏覽代碼

Preview rotation follows device

Benjamin Schaaf 3 年之前
父節點
當前提交
64b75bcbe5
共有 6 個文件被更改,包括 142 次插入15 次删除
  1. 3 1
      data/blit.vert
  2. 6 1
      src/io_pipeline.c
  3. 2 0
      src/io_pipeline.h
  4. 106 8
      src/main.c
  5. 23 5
      src/process_pipeline.c
  6. 2 0
      src/process_pipeline.h

+ 3 - 1
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);
 }

+ 6 - 1
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 - 0
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;
 

+ 106 - 8
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));

+ 23 - 5
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 - 0
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;