// 2nd pass: which roi would this operation need as input to fill the given output region? void modify_roi_in(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in) { *roi_in = *roi_out; const float scale = roi_in->scale / piece->iscale; float aabb[4] = { roi_out->x, roi_out->y, roi_out->x + roi_out->width, roi_out->y + roi_out->height }; float aabb_in[4] = { INFINITY, INFINITY, -INFINITY, -INFINITY }; for(int c = 0; c < 4; c++) { float p[2], o[2]; // get corner points of roi_out get_corner(aabb, c, p); backtransform(piece, scale, p, o); // transform to roi_in space, get aabb. adjust_aabb(o, aabb_in); } const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); const float IW = interpolation->width * scale; // adjust roi_in to minimally needed region roi_in->x = aabb_in[0] - IW; roi_in->y = aabb_in[1] - IW; roi_in->width = aabb_in[2] - roi_in->x + IW; roi_in->height = aabb_in[3] - roi_in->y + IW; }
int distort_backtransform(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count) { const float scale = piece->buf_in.scale / piece->iscale; for(size_t i = 0; i < points_count * 2; i += 2) { float pi[2], po[2]; pi[0] = points[i]; pi[1] = points[i + 1]; backtransform(piece, scale, pi, po); points[i] = po[0]; points[i + 1] = po[1]; } return 1; }
// 2nd pass: which roi would this operation need as input to fill the given output region? void modify_roi_in(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in) { *roi_in = *roi_out; const float scale = roi_in->scale / piece->iscale; float aabb[4] = { roi_out->x, roi_out->y, roi_out->x + roi_out->width, roi_out->y + roi_out->height }; float aabb_in[4] = { INFINITY, INFINITY, -INFINITY, -INFINITY }; for(int c = 0; c < 4; c++) { float p[2], o[2]; // get corner points of roi_out get_corner(aabb, c, p); backtransform(piece, scale, p, o); // transform to roi_in space, get aabb. adjust_aabb(o, aabb_in); } const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); const float IW = (float)interpolation->width * scale; const float orig_w = roi_in->scale * piece->buf_in.width, orig_h = roi_in->scale * piece->buf_in.height; // adjust roi_in to minimally needed region roi_in->x = fmaxf(0.0f, aabb_in[0] - IW); roi_in->y = fmaxf(0.0f, aabb_in[1] - IW); roi_in->width = fminf(orig_w - roi_in->x, aabb_in[2] - roi_in->x + IW); roi_in->height = fminf(orig_h - roi_in->y, aabb_in[3] - roi_in->y + IW); // sanity check. roi_in->x = CLAMP(roi_in->x, 0, (int)floorf(orig_w)); roi_in->y = CLAMP(roi_in->y, 0, (int)floorf(orig_h)); roi_in->width = CLAMP(roi_in->width, 1, (int)ceilf(orig_w) - roi_in->x); roi_in->height = CLAMP(roi_in->height, 1, (int)ceilf(orig_h) - roi_in->y); }
// 3rd (final) pass: you get this input region (may be different from what was requested above), // do your best to fill the output region! void process(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { const int ch = piece->colors; const int ch_width = ch * roi_in->width; const float scale = roi_in->scale / piece->iscale; assert(ch == 4); const struct dt_interpolation *interpolation = dt_interpolation_new(DT_INTERPOLATION_USERPREF); #ifdef _OPENMP #pragma omp parallel for schedule(static) default(none) shared(piece, interpolation) #endif // (slow) point-by-point transformation. // TODO: optimize with scanlines and linear steps between? for(int j = 0; j < roi_out->height; j++) { float *out = ((float *)ovoid) + (size_t)ch * j * roi_out->width; for(int i = 0; i < roi_out->width; i++, out += ch) { float pi[2], po[2]; pi[0] = roi_out->x + i; pi[1] = roi_out->y + j; backtransform(piece, scale, pi, po); po[0] -= roi_in->x; po[1] -= roi_in->y; dt_interpolation_compute_pixel4c(interpolation, (float *)ivoid, out, po[0], po[1], roi_in->width, roi_in->height, ch_width); } } }