Extra2D/src/renderer/material.cpp

233 lines
5.9 KiB
C++
Raw Normal View History

#include <renderer/material.h>
#include <utils/logger.h>
#include <cstring>
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<MaterialLayout> layout) {
layout_ = layout;
if (layout_ && layout_->isFinalized()) {
data_.resize(layout_->getBufferSize(), 0);
}
}
/**
* @brief
* @param shader
*/
void Material::setShader(Ptr<Shader> 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> 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