@@ -59,16 +59,64 @@ retouch_copy_buffer_to_image(global float4 *in,
5959 __write_only image2d_t out ,
6060 global dt_iop_roi_t * roi_out ,
6161 const int xoffs ,
62- const int yoffs )
62+ const int yoffs ,
63+ const float angle ,
64+ const float cx ,
65+ const float cy )
6366{
6467 const int x = get_global_id (0 );
6568 const int y = get_global_id (1 );
6669
6770 if (x >= roi_out -> width || y >= roi_out -> height ) return ;
68- if (x + xoffs >= roi_in -> width || y + yoffs >= roi_in -> height ) return ;
6971
70- const int idx = mad24 (y + yoffs , roi_in -> width , x + xoffs );
71- write_imagef (out , (int2 )(x , y ), in [idx ]);
72+ if (angle == 0.0f )
73+ {
74+ if (x + xoffs >= roi_in -> width || y + yoffs >= roi_in -> height || x + xoffs < 0 || y + yoffs < 0 ) return ;
75+ const int idx = mad24 (y + yoffs , roi_in -> width , x + xoffs );
76+ write_imagef (out , (int2 )(x , y ), in [idx ]);
77+ }
78+ else
79+ {
80+ // same rotation as the on-screen source outline, so the overlay marks the
81+ // region actually copied (see rt_copy_in_to_out in retouch.c)
82+ const float c = cos (angle );
83+ const float s = sin (angle );
84+ // (cx, cy) is the mask centroid (rotation pivot), in roi_out-local coords
85+ const float cx_source = cx + xoffs ;
86+ const float cy_source = cy + yoffs ;
87+
88+ const float sx = x + xoffs ;
89+ const float sy = y + yoffs ;
90+ const float rx = sx - cx_source ;
91+ const float ry = sy - cy_source ;
92+ const float ix = cx_source + rx * c - ry * s ;
93+ const float iy = cy_source + rx * s + ry * c ;
94+
95+ // Edge-clamp (replicate) out-of-bounds samples instead of zero-filling:
96+ // rt_compute_roi_in grows roi_in to the rotation-aware source area, but not
97+ // past the image border, so a rotated source near the edge can still sample
98+ // just outside roi_in. Replicating avoids a hard black seam.
99+ const float ixc = fmin (fmax (ix , 0.0f ), (float )(roi_in -> width - 1 ));
100+ const float iyc = fmin (fmax (iy , 0.0f ), (float )(roi_in -> height - 1 ));
101+
102+ int x0 = (int )ixc ;
103+ int y0 = (int )iyc ;
104+ x0 = clamp (x0 , 0 , roi_in -> width - 2 );
105+ y0 = clamp (y0 , 0 , roi_in -> height - 2 );
106+ const float dx0 = ixc - x0 ;
107+ const float dy0 = iyc - y0 ;
108+
109+ float4 in00 = in [mad24 (y0 , roi_in -> width , x0 )];
110+ float4 in10 = in [mad24 (y0 , roi_in -> width , x0 + 1 )];
111+ float4 in01 = in [mad24 (y0 + 1 , roi_in -> width , x0 )];
112+ float4 in11 = in [mad24 (y0 + 1 , roi_in -> width , x0 + 1 )];
113+
114+ float4 val = in00 * (1.0f - dx0 ) * (1.0f - dy0 ) +
115+ in10 * dx0 * (1.0f - dy0 ) +
116+ in01 * (1.0f - dx0 ) * dy0 +
117+ in11 * dx0 * dy0 ;
118+ write_imagef (out , (int2 )(x , y ), val );
119+ }
72120}
73121
74122kernel void
@@ -77,15 +125,63 @@ retouch_copy_buffer_to_buffer(global float4 *in,
77125 global float4 * out ,
78126 global dt_iop_roi_t * roi_out ,
79127 const int xoffs ,
80- const int yoffs )
128+ const int yoffs ,
129+ const float angle ,
130+ const float cx ,
131+ const float cy )
81132{
82133 const int x = get_global_id (0 );
83134 const int y = get_global_id (1 );
84135
85136 if (x >= roi_out -> width || y >= roi_out -> height ) return ;
86- if (x + xoffs >= roi_in -> width || y + yoffs >= roi_in -> height ) return ;
87137
88- out [mad24 (y , roi_out -> width , x )] = in [mad24 (y + yoffs , roi_in -> width , x + xoffs )];
138+ if (angle == 0.0f )
139+ {
140+ if (x + xoffs >= roi_in -> width || y + yoffs >= roi_in -> height || x + xoffs < 0 || y + yoffs < 0 ) return ;
141+ out [mad24 (y , roi_out -> width , x )] = in [mad24 (y + yoffs , roi_in -> width , x + xoffs )];
142+ }
143+ else
144+ {
145+ // same rotation as the on-screen source outline, so the overlay marks the
146+ // region actually copied (see rt_copy_in_to_out in retouch.c)
147+ const float c = cos (angle );
148+ const float s = sin (angle );
149+ // (cx, cy) is the mask centroid (rotation pivot), in roi_out-local coords
150+ const float cx_source = cx + xoffs ;
151+ const float cy_source = cy + yoffs ;
152+
153+ const float sx = x + xoffs ;
154+ const float sy = y + yoffs ;
155+ const float rx = sx - cx_source ;
156+ const float ry = sy - cy_source ;
157+ const float ix = cx_source + rx * c - ry * s ;
158+ const float iy = cy_source + rx * s + ry * c ;
159+
160+ // Edge-clamp (replicate) out-of-bounds samples instead of zero-filling:
161+ // rt_compute_roi_in grows roi_in to the rotation-aware source area, but not
162+ // past the image border, so a rotated source near the edge can still sample
163+ // just outside roi_in. Replicating avoids a hard black seam.
164+ const float ixc = fmin (fmax (ix , 0.0f ), (float )(roi_in -> width - 1 ));
165+ const float iyc = fmin (fmax (iy , 0.0f ), (float )(roi_in -> height - 1 ));
166+
167+ int x0 = (int )ixc ;
168+ int y0 = (int )iyc ;
169+ x0 = clamp (x0 , 0 , roi_in -> width - 2 );
170+ y0 = clamp (y0 , 0 , roi_in -> height - 2 );
171+ const float dx0 = ixc - x0 ;
172+ const float dy0 = iyc - y0 ;
173+
174+ float4 in00 = in [mad24 (y0 , roi_in -> width , x0 )];
175+ float4 in10 = in [mad24 (y0 , roi_in -> width , x0 + 1 )];
176+ float4 in01 = in [mad24 (y0 + 1 , roi_in -> width , x0 )];
177+ float4 in11 = in [mad24 (y0 + 1 , roi_in -> width , x0 + 1 )];
178+
179+ float4 val = in00 * (1.0f - dx0 ) * (1.0f - dy0 ) +
180+ in10 * dx0 * (1.0f - dy0 ) +
181+ in01 * (1.0f - dx0 ) * dy0 +
182+ in11 * dx0 * dy0 ;
183+ out [mad24 (y , roi_out -> width , x )] = val ;
184+ }
89185}
90186
91187kernel void
0 commit comments