diff --git a/gnome/src/virtualmonitorsactor.js b/gnome/src/virtualmonitorsactor.js index f8db098..e0bd4fc 100644 --- a/gnome/src/virtualmonitorsactor.js +++ b/gnome/src/virtualmonitorsactor.js @@ -325,13 +325,6 @@ export const VirtualMonitorEffect = GObject.registerClass({ 'Ratios to convert actor coordinates to display coordinates', GObject.ParamFlags.READWRITE ), - 'monitor-actor': GObject.ParamSpec.object( - 'monitor-actor', - 'Monitor Actor', - 'The actor that represents the monitor', - GObject.ParamFlags.READWRITE, - Clutter.Actor.$gtype - ), 'is-closest': GObject.ParamSpec.boolean( 'is-closest', 'Is Closest', @@ -365,21 +358,35 @@ export const VirtualMonitorEffect = GObject.registerClass({ const mid_distance = (this.display_distance_default + desired_distance) / 2; + // if we're the focused display, we'll double the timeline and wait for the first half to let other + // displays ease out first + this._distance_ease_focus = this._is_focused(); + const timeline_ms = this._distance_ease_focus ? 500 : 150; + this._distance_ease_start = this._current_display_distance; - this._distance_ease_timeline = Clutter.Timeline.new_for_actor(this.get_actor(), 250); + this._distance_ease_timeline = Clutter.Timeline.new_for_actor(this.get_actor(), timeline_ms); this._distance_ease_target = desired_distance; this._distance_ease_timeline.connect('new-frame', (() => { + let progress = this._distance_ease_timeline.get_progress(); + if (this._distance_ease_focus) { + // if we're the focused display, wait for the first half of the timeline to pass + if (progress < 0.5) return; + + // treat the second half of the timeline as its own full progression + progress = (progress - 0.5) * 2; + + // put this display in front as it starts to easy in + this.is_closest = true; + } else { + this.is_closest = false; + } + this._current_display_distance = this._distance_ease_start + - this._distance_ease_timeline.get_progress() * - (this._distance_ease_target - this._distance_ease_start); - this.is_closest = this._current_display_distance < mid_distance; + progress * (this._distance_ease_target - this._distance_ease_start); }).bind(this)); this._distance_ease_timeline.start(); - - this.monitor_actor.set_z_position(this.monitor_index); - this.monitor_actor.queue_redraw(); } perspective(fovDiagonalRadians, aspect, near, far) { @@ -408,14 +415,14 @@ export const VirtualMonitorEffect = GObject.registerClass({ uniform float u_display_distance; uniform float u_rotation_x_radians; uniform float u_rotation_y_radians; - uniform float u_aspect_ratio; + uniform vec2 u_display_resolution; // for some reason the vector positions are relative to the width and height of the uiGroup actor uniform vec2 u_actor_to_display_ratios; // constants that help me adjust CoGL vector positions so their components are at the ratios intended, for proper rotation - float cogl_position_width = 51.7; // no idea... - float cogl_z_factor = 34.66; // no idea... + float cogl_position_width_factor = 29.09; // no idea... + float cogl_z_factor = 55.41; // no idea... float vectorLength(vec3 v) { return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); @@ -525,33 +532,34 @@ export const VirtualMonitorEffect = GObject.registerClass({ const main = ` vec4 world_pos = cogl_position_in; vec4 look_ahead_quaternion = nwuToESU(imuDataToLookAheadQuaternion(u_imu_data, u_look_ahead_ms)); + float aspect_ratio = u_display_resolution.x / u_display_resolution.y; - float cogl_position_height = cogl_position_width / u_aspect_ratio; + float cogl_position_width = cogl_position_width_factor * aspect_ratio; + float cogl_position_height = cogl_position_width / aspect_ratio; float position_width_adjustment_count = u_actor_to_display_ratios.x - 1.0; float position_height_adjustment_count = u_actor_to_display_ratios.y - 1.0; - world_pos.z = - u_display_distance / cogl_z_factor; + world_pos.z = - u_display_distance * cogl_z_factor / u_display_resolution.x; // if the perspective includes more than just our actor, move vertices towards the center of the perspective so they'll be properly rotated world_pos.x += position_width_adjustment_count * cogl_position_width; world_pos.y += position_height_adjustment_count * cogl_position_height; - world_pos.z *= u_aspect_ratio; + world_pos.z *= aspect_ratio; world_pos = applyXRotationToVector(world_pos, u_rotation_x_radians); world_pos = applyYRotationToVector(world_pos, u_rotation_y_radians); world_pos = applyQuaternionToVector(world_pos, quatConjugate(look_ahead_quaternion)); - world_pos.z /= u_aspect_ratio; + world_pos.z /= aspect_ratio; world_pos.x /= u_actor_to_display_ratios.x; world_pos.y /= u_actor_to_display_ratios.y; world_pos = u_projection_matrix * world_pos; - world_pos /= u_display_distance; // if the perspective includes more than just our actor, move the vertices back to just the area we can see. // this needs to be done after the projection matrix multiplication so it will be projected as if centered in our vision - world_pos.x -= 0.5 * position_width_adjustment_count * world_pos.w; - world_pos.y -= 0.5 * position_height_adjustment_count * world_pos.w; + world_pos.x -= (position_width_adjustment_count / u_actor_to_display_ratios.x) * world_pos.w; + world_pos.y -= (position_height_adjustment_count / u_actor_to_display_ratios.y) * world_pos.w; cogl_position_out = world_pos; @@ -573,7 +581,7 @@ export const VirtualMonitorEffect = GObject.registerClass({ this.set_uniform_matrix(this.get_uniform_location("u_projection_matrix"), false, 4, projection_matrix); this.set_uniform_float(this.get_uniform_location("u_rotation_x_radians"), 1, [this.monitor_wrapping_scheme === 'vertical' ? this.monitor_wrapping_rotation_radians : 0.0]); this.set_uniform_float(this.get_uniform_location("u_rotation_y_radians"), 1, [this.monitor_wrapping_scheme === 'horizontal' ? this.monitor_wrapping_rotation_radians : 0.0]); - this.set_uniform_float(this.get_uniform_location("u_aspect_ratio"), 1, [aspect]); + this.set_uniform_float(this.get_uniform_location("u_display_resolution"), 2, [this.get_actor().width, this.get_actor().height]); this.set_uniform_float(this.get_uniform_location("u_actor_to_display_ratios"), 2, this.actor_to_display_ratios); this._initialized = true; } @@ -726,8 +734,7 @@ export const VirtualMonitorsActor = GObject.registerClass({ display_distance_default: Math.max(this.toggle_display_distance_start, this.toggle_display_distance_end), monitor_wrapping_scheme: 'horizontal', monitor_wrapping_rotation_radians: this._monitorPlacements[index].rotationAngleRadians, - actor_to_display_ratios: actorToDisplayRatios, - monitor_actor: containerActor + actor_to_display_ratios: actorToDisplayRatios }); containerActor.add_effect_with_name('viewport-effect', effect); this.add_child(containerActor); @@ -735,7 +742,7 @@ export const VirtualMonitorsActor = GObject.registerClass({ this.bind_property('focused-monitor-index', effect, 'focused-monitor-index', GObject.BindingFlags.DEFAULT); this.bind_property('display-distance', effect, 'display-distance', GObject.BindingFlags.DEFAULT); - // in addition to rendering distance property in the shader, the parent actor determines overlap based on child ordering + // in addition to rendering distance properly in the shader, the parent actor determines overlap based on child ordering effect.connect('notify::is-closest', ((actor, _pspec) => { if (actor.is_closest) this.set_child_above_sibling(containerActor, null); }).bind(this));