465{
466 auto resolved = std::filesystem::path(
resolve_path(path.string()));
467 if (!std::filesystem::exists(resolved)) {
469 "Image file not found: {}", resolved.string());
470 return std::nullopt;
471 }
472
473 std::ifstream file(resolved, std::ios::binary | std::ios::ate);
474 if (!file.is_open()) {
476 "Failed to open image file: {}", resolved.string());
477 return std::nullopt;
478 }
479
480 std::streamsize file_size = file.tellg();
481 file.seekg(0, std::ios::beg);
482
483 std::vector<unsigned char> file_buffer(file_size);
484 if (!file.read(reinterpret_cast<char*>(file_buffer.data()), file_size)) {
486 "Failed to read image file: {}", resolved.string());
487 return std::nullopt;
488 }
489 file.close();
490
491 if (extension_of(resolved) == "exr") {
492 (void)desired_channels;
493 return load_exr_from_memory(file_buffer.data(),
494 static_cast<size_t>(file_size));
495 }
496
497 int width {}, height {}, channels {};
498
499 if (desired_channels == 0) {
500 stbi_info_from_memory(file_buffer.data(), static_cast<int>(file_buffer.size()),
501 &
width, &height, &channels);
502 if (channels == 3) {
503 desired_channels = 4;
504 }
505 }
506
507 unsigned char*
pixels = stbi_load_from_memory(
508 file_buffer.data(),
509 static_cast<int>(file_buffer.size()),
510 &
width, &height, &channels,
511 desired_channels);
512
515 "Failed to decode image: {} - {}",
516 path.string(), stbi_failure_reason());
517 return std::nullopt;
518 }
519
520 int result_channels = (desired_channels != 0) ? desired_channels : channels;
521
523 "Loaded image: {} ({}x{}, {} channels{})",
524 resolved.filename().string(),
width, height, result_channels,
525 (channels == 3 && result_channels == 4) ? " [RGB→RGBA]" : "");
526
527 ImageData result;
528 auto& buf = result.pixels.emplace<std::vector<uint8_t>>();
529 size_t data_size =
static_cast<size_t>(
width) * height * result_channels;
530 buf.resize(data_size);
531 std::memcpy(buf.data(),
pixels, data_size);
532
533 result.width =
width;
534 result.height = height;
535 result.channels = result_channels;
536
537 switch (result_channels) {
538 case 1:
540 break;
541 case 2:
543 break;
544 case 4:
546 break;
547 default:
549 "Unsupported channel count: {}", result_channels);
551 return std::nullopt;
552 }
553
555 return result;
556}
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
const std::vector< float > * pixels
static std::string resolve_path(const std::string &filepath)
Resolve a filepath against the project source root if not found as-is.
@ FileIO
Filesystem I/O operations.
@ IO
Networking, file handling, streaming.
@ RGBA8
Four channel 8-bit.
@ R8
Single channel 8-bit.