Work out how a source extent maps onto a destination extent.
Pure arithmetic, no device needed. Zero in any extent yields an empty plan. Tiling produces one blit per tile, so a source much smaller than the destination produces many.
277{
278 FitPlan plan;
279 plan.sampler.mag_filter = filter;
280 plan.sampler.min_filter = filter;
281
282 if (src_width == 0 || src_height == 0 || dst_width == 0 || dst_height == 0) {
283 return plan;
284 }
285
287 plan.sampler.address_mode_u = address;
288 plan.sampler.address_mode_v = address;
289 plan.sampler.address_mode_w = address;
290 plan.sampler.border_color = border;
291 };
292
293 const auto place = [&plan, filter](
294 vk::Rect2D
src, vk::Rect2D
dst,
bool flip_x =
false,
bool flip_y =
false) {
295 plan.blits.push_back(LayerBlit {
296 .src =
src, .dst =
dst, .filter = filter, .flip_x = flip_x, .flip_y = flip_y });
297 };
298
299 const auto region = [](int32_t x, int32_t y, uint32_t
width, uint32_t
height) {
300 return vk::Rect2D { vk::Offset2D { x, y }, vk::Extent2D {
width,
height } };
301 };
302
303 const auto centered = [](uint32_t outer, uint32_t inner) {
304 return static_cast<int32_t>((outer - inner) / 2);
305 };
306
307 const auto extent = [](
double value, uint32_t limit) {
308 return std::clamp(
static_cast<uint32_t
>(std::lround(
value)), 1U, limit);
309 };
310
311 const auto sw = static_cast<double>(src_width);
312 const auto sh = static_cast<double>(src_height);
313 const auto dw = static_cast<double>(dst_width);
314 const auto dh = static_cast<double>(dst_height);
315
319 place(region(0, 0, src_width, src_height), region(0, 0, dst_width, dst_height));
320 break;
321
323 const double scale = std::min(dw / sw, dh / sh);
324 const uint32_t w = extent(sw * scale, dst_width);
325 const uint32_t
h = extent(sh * scale, dst_height);
327 place(region(0, 0, src_width, src_height),
328 region(centered(dst_width, w), centered(dst_height,
h), w,
h));
329 break;
330 }
331
333 const double scale = std::max(dw / sw, dh / sh);
334 const uint32_t w = extent(dw / scale, src_width);
335 const uint32_t
h = extent(dh / scale, src_height);
337 place(region(centered(src_width, w), centered(src_height,
h), w,
h),
338 region(0, 0, dst_width, dst_height));
339 break;
340 }
341
343 const uint32_t w = std::min(src_width, dst_width);
344 const uint32_t
h = std::min(src_height, dst_height);
346 place(region(centered(src_width, w), centered(src_height,
h), w,
h),
347 region(centered(dst_width, w), centered(dst_height,
h), w,
h));
348 break;
349 }
350
355
356 uint32_t row = 0;
357 for (uint32_t y = 0; y < dst_height; y += src_height, ++row) {
358 const uint32_t
h = std::min(src_height, dst_height - y);
359 const bool flip_y = mirrored && (row % 2 == 1);
360
361 uint32_t column = 0;
362 for (uint32_t x = 0; x < dst_width; x += src_width, ++column) {
363 const uint32_t w = std::min(src_width, dst_width - x);
364 const bool flip_x = mirrored && (column % 2 == 1);
365
366 place(region(flip_x ?
static_cast<int32_t
>(src_width - w) : 0,
367 flip_y ? static_cast<int32_t>(src_height -
h) : 0, w,
h),
368 region(static_cast<int32_t>(x), static_cast<int32_t>(y), w,
h),
369 flip_x, flip_y);
370 }
371 }
372 break;
373 }
374 }
375
376 return plan;
377}
AABB2D place(AABB2D anchor, Side side, float w, float h, float gap=0.F, Align align=Align::Center) noexcept
Compute a region of size (w, h) positioned relative to anchor.
Tendency< D, float > scale(const Tendency< D, float > &t, float factor)
Uniform scaling of a scalar-output tendency.
AddressMode
Texture addressing mode (wrapping)
@ CLAMP_TO_EDGE
Clamp to edge color.
@ MIRRORED_REPEAT
Mirror and repeat.
@ CLAMP_TO_BORDER
Clamp to border color.
BorderColor
Color read outside the texture when an address mode is CLAMP_TO_BORDER.
@ TRANSPARENT_BLACK
Zero in every channel.
@ DEFAULT
The sampler's historical border, opaque black.
@ TILE_MIRRORED
Source repeated, every other tile mirrored.
@ STRETCH
Whole source onto whole destination, aspect ignored.
@ CONTAIN
Whole source, aspect kept, centered, the rest left uncovered.
@ COVER
Aspect kept, destination filled, source cropped.
@ CENTER
No scaling, centered, clipped to the destination.
@ TILE
Source repeated at its own size.