| 395 | } |
| 396 | |
| 397 | void Corkscrew::readFromMulti(const fl::Grid<CRGB>& source_grid) const { |
| 398 | // Get the target surface and clear it |
| 399 | auto target_surface = const_cast<Corkscrew*>(this)->getOrCreateInputSurface(); |
| 400 | target_surface->clear(); |
| 401 | const u16 width = static_cast<u16>(source_grid.width()); |
| 402 | const u16 height = static_cast<u16>(source_grid.height()); |
| 403 | |
| 404 | // Iterate through each LED in the corkscrew |
| 405 | for (fl::size led_idx = 0; led_idx < mNumLeds; ++led_idx) { |
| 406 | // Get the wrapped tile for this LED position |
| 407 | Tile2x2_u8_wrap tile = at_wrap(static_cast<float>(led_idx)); |
| 408 | |
| 409 | // Accumulate color from the 4 sample points with their weights |
| 410 | fl::u32 r_accum = 0, g_accum = 0, b_accum = 0; |
| 411 | fl::u32 total_weight = 0; |
| 412 | |
| 413 | // Sample from each of the 4 corners of the tile |
| 414 | for (fl::u8 x = 0; x < 2; x++) { |
| 415 | for (fl::u8 y = 0; y < 2; y++) { |
| 416 | const auto& entry = tile.at(x, y); |
| 417 | vec2<u16> pos = entry.first; // position is the first element of the pair |
| 418 | fl::u8 weight = entry.second; // weight is the second element of the pair |
| 419 | |
| 420 | // Bounds check for the source grid |
| 421 | if (pos.x < width && pos.y < height) { |
| 422 | |
| 423 | // Sample from the source grid |
| 424 | CRGB sample_color = source_grid.at(pos.x, pos.y); |
| 425 | |
| 426 | // Accumulate weighted color components |
| 427 | r_accum += static_cast<fl::u32>(sample_color.r) * weight; |
| 428 | g_accum += static_cast<fl::u32>(sample_color.g) * weight; |
| 429 | b_accum += static_cast<fl::u32>(sample_color.b) * weight; |
| 430 | total_weight += weight; |
| 431 | } |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | // Calculate final color by dividing by total weight |
| 436 | CRGB final_color = CRGB::Black; |
| 437 | if (total_weight > 0) { |
| 438 | final_color.r = static_cast<fl::u8>(r_accum / total_weight); |
| 439 | final_color.g = static_cast<fl::u8>(g_accum / total_weight); |
| 440 | final_color.b = static_cast<fl::u8>(b_accum / total_weight); |
| 441 | } |
| 442 | |
| 443 | // Store the result in the target surface at the LED index position |
| 444 | auto target_surface = const_cast<Corkscrew*>(this)->getOrCreateInputSurface(); |
| 445 | if (led_idx < target_surface->size()) { |
| 446 | target_surface->span()[led_idx] = final_color; |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // Iterator implementation |
| 452 | vec2f Corkscrew::iterator::operator*() const { |