#include #include #include namespace extra2d { // ======================================== // MaterialLayout 实现 // ======================================== MaterialLayout::MaterialLayout() = default; /** * @brief 添加参数到布局 * @param name 参数名称 * @param type 参数类型 */ 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; } /** * @brief 完成布局定义,计算 std140 布局偏移 * * std140 布局规则: * - 标量和向量:偏移必须是其大小的倍数 * - 数组和结构体:偏移必须是 16 的倍数 * - vec3 后面需要填充到 16 字节边界 */ void MaterialLayout::finalize() { if (finalized_) return; uint32_t offset = 0; for (auto& pair : params_) { auto& info = pair.second; // 计算对齐要求 uint32_t alignment = 4; // 默认 4 字节对齐 switch (info.type) { case MaterialParamType::Float: alignment = 4; // float: 4 字节对齐 break; case MaterialParamType::Vec2: alignment = 8; // vec2: 8 字节对齐 break; case MaterialParamType::Vec3: case MaterialParamType::Vec4: case MaterialParamType::Color: alignment = 16; // vec3/vec4/color: 16 字节对齐(std140 规则) break; case MaterialParamType::Mat4: alignment = 16; // mat4: 16 字节对齐 break; default: alignment = 4; break; } // 对齐偏移 offset = (offset + alignment - 1) & ~(alignment - 1); info.offset = offset; offset += info.size; } // 最终大小对齐到 16 字节 bufferSize_ = (offset + 15) & ~15; finalized_ = true; } /** * @brief 获取参数信息 * @param name 参数名称 * @return 参数信息指针,不存在返回 nullptr */ 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; /** * @brief 设置材质布局 * @param layout 材质布局 */ void Material::setLayout(Ptr layout) { layout_ = layout; if (layout_ && layout_->isFinalized()) { data_.resize(layout_->getBufferSize(), 0); } } /** * @brief 设置着色器 * @param shader 着色器 */ void Material::setShader(Ptr shader) { shader_ = shader; } /** * @brief 获取 RHI 管线句柄 * @return RHI 管线句柄 */ PipelineHandle Material::getPipeline() const { if (shader_) { return shader_->getPipeline(); } return PipelineHandle{}; } /** * @brief 设置 float 参数 * @param name 参数名称 * @param value 值 */ 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)); } } /** * @brief 设置 vec2 参数 * @param name 参数名称 * @param value 值 */ 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); } } /** * @brief 设置 vec4 参数 * @param name 参数名称 * @param x X 分量 * @param y Y 分量 * @param z Z 分量 * @param w W 分量 */ 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); } } /** * @brief 设置颜色参数 * @param name 参数名称 * @param value 颜色值 */ 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); } } /** * @brief 设置 mat4 参数 * @param name 参数名称 * @param value 矩阵数据指针 */ 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); } } /** * @brief 设置纹理 * @param uniformName 着色器中的采样器 uniform 名称 * @param texture 纹理 * @param slot 纹理槽位(0-15) */ void Material::setTexture(const std::string& uniformName, Ptr texture, uint32_t slot) { // 查找是否已存在相同名称的纹理 for (auto& texSlot : textures_) { if (texSlot.uniformName == uniformName) { texSlot.texture = texture; texSlot.slot = slot; return; } } // 添加新的纹理槽位 textures_.push_back({texture, slot, uniformName}); } /** * @brief 清除所有纹理 */ void Material::clearTextures() { textures_.clear(); } } // namespace extra2d