#include #include #include namespace extra2d { // MaterialLayout 实现 MaterialLayout::MaterialLayout() = default; void MaterialLayout::addParam(const std::string& name, MaterialParamType type) { if (finalized_) { E2D_LOG_WARN("Cannot add param to finalized MaterialLayout"); return; } MaterialParamInfo info; info.type = type; info.size = getMaterialParamSize(type); info.offset = 0; // 将在 finalize 时计算 params_[name] = info; } void MaterialLayout::finalize() { if (finalized_) return; // 计算 std140 布局的偏移 // std140 规则: // - 标量和向量:偏移必须是其大小的倍数 // - 数组和结构体:偏移必须是 16 的倍数 // - vec3 后面需要填充到 16 字节边界 uint32_t offset = 0; for (auto& pair : params_) { auto& info = pair.second; // 对齐到参数大小的倍数 uint32_t alignment = info.size; if (info.type == MaterialParamType::Mat4) { alignment = 16; // mat4 需要 16 字节对齐 } else if (info.type == MaterialParamType::Vec3) { alignment = 16; // vec3 在 std140 中占 16 字节 } else if (alignment < 4) { alignment = 4; // 最小 4 字节对齐 } // 对齐偏移 offset = (offset + alignment - 1) & ~(alignment - 1); info.offset = offset; offset += info.size; } // 最终大小对齐到 16 字节 bufferSize_ = (offset + 15) & ~15; finalized_ = true; } const MaterialParamInfo* MaterialLayout::getParam(const std::string& name) const { auto it = params_.find(name); if (it != params_.end()) { return &it->second; } return nullptr; } // Material 实现 Material::Material() = default; void Material::setLayout(Ptr layout) { layout_ = layout; if (layout_ && layout_->isFinalized()) { data_.resize(layout_->getBufferSize(), 0); } } void Material::setShader(Ptr shader) { shader_ = shader; } void Material::setFloat(const std::string& name, float value) { if (!layout_) return; const auto* param = layout_->getParam(name); if (param && param->type == MaterialParamType::Float) { std::memcpy(data_.data() + param->offset, &value, sizeof(float)); } } void Material::setVec2(const std::string& name, const Vec2& value) { if (!layout_) return; const auto* param = layout_->getParam(name); if (param && param->type == MaterialParamType::Vec2) { std::memcpy(data_.data() + param->offset, &value.x, sizeof(float) * 2); } } void Material::setVec4(const std::string& name, float x, float y, float z, float w) { if (!layout_) return; const auto* param = layout_->getParam(name); if (param && param->type == MaterialParamType::Vec4) { float values[4] = {x, y, z, w}; std::memcpy(data_.data() + param->offset, values, sizeof(float) * 4); } } void Material::setColor(const std::string& name, const Color& value) { if (!layout_) return; const auto* param = layout_->getParam(name); if (param && param->type == MaterialParamType::Color) { std::memcpy(data_.data() + param->offset, &value.r, sizeof(float) * 4); } } void Material::setMat4(const std::string& name, const float* value) { if (!layout_) return; const auto* param = layout_->getParam(name); if (param && param->type == MaterialParamType::Mat4) { std::memcpy(data_.data() + param->offset, value, sizeof(float) * 16); } } void Material::setTexture(const std::string& name, TextureHandle texture, uint32_t slot) { // 纹理存储在单独的列表中 textures_.push_back({texture, slot}); } void Material::apply(UniformBufferManager& uboManager) { if (!shader_) return; // 绑定着色器 shader_->bind(); // 上传材质数据到 UBO if (!data_.empty()) { auto* ubo = uboManager.acquireMaterialUBO(static_cast(data_.size())); if (ubo) { ubo->update(data_.data(), static_cast(data_.size())); ubo->bind(MATERIAL_UBO_BINDING); } } // 设置 Uniform Block 绑定(如果着色器支持) shader_->setUniformBlock("MaterialUBO", MATERIAL_UBO_BINDING); // TODO: 绑定纹理 // for (const auto& [texture, slot] : textures_) { // // 通过纹理句柄获取纹理并绑定 // } } } // namespace extra2d