import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; // Sponza geometry + albedo: CC BY 3.0, Frank Meinl (Crytek), packaged by // Jimmie Bergmann (https://github.com/jimmiebergmann/Sponza) and Morgan // McGuire (https://casual-effects.com/data). The full asset bundle is // ~280 MB — too large to live in this repo. GitFetch lands it in the // per-user crafter-build cache on first build and reuses thereafter. constexpr std::string_view kSponzaGitUrl = "https://github.com/jimmiebergmann/Sponza.git"; constexpr std::string_view kSponzaCommitSHA = "222338979d32f4f4818466291bdbc29f192b86ba"; // Every albedo is normalized to this size so they can live as layers of // one texture_2d_array on the GPU (WebGPU array textures require // identical layer dimensions). 1024 matches the majority of Sponza's // textures; the few outliers (256×1024 chain, 512² thorn, 2048² curtains) // get bilinear-resized via stb_image_resize2. constexpr std::uint16_t kAlbedoSize = 1024u; extern "C" Configuration CrafterBuildProject(std::span args) { bool isWasm = false; for (std::string_view a : args) { if (a.starts_with("--target=") && a.find("wasm") != std::string_view::npos) { isWasm = true; break; } } std::vector graphicsArgs(args.begin(), args.end()); Configuration* graphics = LocalProject({ .projectFile = "../../project.cpp", .args = graphicsArgs, }); Configuration cfg; cfg.path = "./"; cfg.name = "Sponza"; cfg.outputName = "Sponza"; cfg.type = ConfigurationType::Executable; if (isWasm) { cfg.target = "wasm32-wasip1"; cfg.defines.push_back({"CRAFTER_GRAPHICS_WINDOW_DOM", ""}); cfg.compileFlags.push_back("-msimd128"); } ApplyStandardArgs(cfg, args); cfg.dependencies = { graphics }; std::array ifaces = {}; std::array impls = { "main" }; cfg.GetInterfacesAndImplementations(ifaces, impls); // Fetch Sponza once into the shared crafter-build cache, then process // it into a per-material bundle under build/sponza-bundle-/. // Hashing on (sha, albedoSize) so changing either invalidates the // bundle without touching the rest of the example's build tree. fs::path sponzaRoot = GitFetch({ .url = std::string(kSponzaGitUrl), .commit = std::string(kSponzaCommitSHA), }); std::string bundleKey = std::format("{}|{}", kSponzaCommitSHA, kAlbedoSize); auto bundleHash = std::hash{}(bundleKey); fs::path bundleDir = fs::path("build") / std::format("sponza-bundle-{:016x}", bundleHash); if (auto err = BuildOBJBundle( sponzaRoot / "sponza.obj", sponzaRoot / "sponza.mtl", bundleDir, kAlbedoSize); !err.empty()) { std::println(std::cerr, "Sponza bundle error: {}", err); std::exit(1); } // Forward every produced file (.cmesh, .ctex, scene.txt) as a // passthrough — they're already compressed by Crafter.Asset, no // further compression needed. cfg.files copies them flat into // the executable's bin dir. for (const auto& entry : fs::directory_iterator(bundleDir)) { if (entry.is_regular_file()) cfg.files.push_back(entry.path()); } if (isWasm) { cfg.files.emplace_back(fs::path("raygen.wgsl")); cfg.files.emplace_back(fs::path("closesthit.wgsl")); cfg.files.emplace_back(fs::path("miss.wgsl")); EnableWasiBrowserRuntime(cfg); } else { cfg.shaders.emplace_back(fs::path("raygen.glsl"), std::string("main"), ShaderType::RayGen); cfg.shaders.emplace_back(fs::path("closesthit.glsl"), std::string("main"), ShaderType::ClosestHit); cfg.shaders.emplace_back(fs::path("miss.glsl"), std::string("main"), ShaderType::Miss); } return cfg; }