Add explicit PPI project writer
This commit is contained in:
@@ -651,71 +651,72 @@ pp::foundation::Result<PpiDecodedProjectImages> decode_ppi_project_images(std::s
|
||||
return pp::foundation::Result<PpiDecodedProjectImages>::success(std::move(decoded));
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMinimalProjectConfig config)
|
||||
pp::foundation::Result<std::vector<std::byte>> create_ppi_project(PpiProjectConfig config)
|
||||
{
|
||||
const auto canvas_status = validate_canvas_size(config.width, config.height);
|
||||
if (!canvas_status.ok()) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(canvas_status);
|
||||
}
|
||||
|
||||
if (config.layer_name.empty()) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI layer name must not be empty"));
|
||||
}
|
||||
|
||||
if (config.layer_name.size() > max_ppi_layer_name_length) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer name exceeds the configured limit"));
|
||||
}
|
||||
|
||||
if (config.layer_metadata.opacity < 0.0F || config.layer_metadata.opacity > 1.0F) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer opacity is outside the supported range"));
|
||||
}
|
||||
|
||||
if (config.layer_metadata.blend_mode > 4U) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer blend mode is outside the supported range"));
|
||||
}
|
||||
|
||||
if (config.layer_count == 0 || config.layer_count > max_ppi_layer_count) {
|
||||
if (config.layers.empty() || config.layers.size() > max_ppi_layer_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer count is outside the configured range"));
|
||||
}
|
||||
|
||||
if (config.frame_duration_ms == 0) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI frame duration must be greater than zero"));
|
||||
}
|
||||
|
||||
if (config.frame_count == 0 || config.frame_count > max_ppi_frame_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI frame count is outside the configured range"));
|
||||
}
|
||||
|
||||
if (config.layer_count > max_ppi_frame_count / config.frame_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI total layer frame count exceeds the configured range"));
|
||||
}
|
||||
|
||||
for (std::uint32_t layer = 0; layer < config.layer_count; ++layer) {
|
||||
const auto name = generated_layer_name(config.layer_name, layer, config.layer_count);
|
||||
if (name.size() > max_ppi_layer_name_length) {
|
||||
std::uint32_t total_frame_count = 0;
|
||||
std::vector<std::size_t> layer_frame_offsets;
|
||||
layer_frame_offsets.reserve(config.layers.size());
|
||||
for (const auto& layer : config.layers) {
|
||||
if (layer.name.empty()) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI generated layer name exceeds the configured limit"));
|
||||
pp::foundation::Status::invalid_argument("PPI layer name must not be empty"));
|
||||
}
|
||||
|
||||
if (layer.name.size() > max_ppi_layer_name_length) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer name exceeds the configured limit"));
|
||||
}
|
||||
|
||||
if (layer.metadata.opacity < 0.0F || layer.metadata.opacity > 1.0F) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer opacity is outside the supported range"));
|
||||
}
|
||||
|
||||
if (layer.metadata.blend_mode > 4U) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer blend mode is outside the supported range"));
|
||||
}
|
||||
|
||||
if (layer.frames.empty() || layer.frames.size() > max_ppi_frame_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer frame count is outside the configured range"));
|
||||
}
|
||||
|
||||
if (layer.frames.size() > max_ppi_frame_count - total_frame_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI total layer frame count exceeds the configured range"));
|
||||
}
|
||||
|
||||
layer_frame_offsets.push_back(total_frame_count);
|
||||
total_frame_count += static_cast<std::uint32_t>(layer.frames.size());
|
||||
|
||||
for (const auto& frame : layer.frames) {
|
||||
if (frame.duration_ms == 0) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI frame duration must be greater than zero"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::array<bool, 6>> seen_faces(
|
||||
static_cast<std::size_t>(config.layer_count) * static_cast<std::size_t>(config.frame_count));
|
||||
std::vector<std::array<bool, 6>> seen_faces(total_frame_count);
|
||||
std::uint64_t total_payload_bytes = 0;
|
||||
for (const auto& face : config.dirty_faces) {
|
||||
if (face.layer_index >= config.layer_count) {
|
||||
if (face.layer_index >= config.layers.size()) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI dirty face layer index is outside the layer list"));
|
||||
}
|
||||
|
||||
if (face.frame_index >= config.frame_count) {
|
||||
if (face.frame_index >= config.layers[face.layer_index].frames.size()) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI dirty face frame index is outside the frame list"));
|
||||
}
|
||||
@@ -725,9 +726,7 @@ pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMin
|
||||
pp::foundation::Status::out_of_range("PPI dirty face index is outside the cube face list"));
|
||||
}
|
||||
|
||||
const auto slot_index =
|
||||
static_cast<std::size_t>(face.layer_index) * static_cast<std::size_t>(config.frame_count)
|
||||
+ static_cast<std::size_t>(face.frame_index);
|
||||
const auto slot_index = layer_frame_offsets[face.layer_index] + static_cast<std::size_t>(face.frame_index);
|
||||
if (seen_faces[slot_index][face.face_index]) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI dirty face slot is duplicated"));
|
||||
@@ -789,20 +788,20 @@ pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMin
|
||||
|
||||
append_u32(bytes, config.width);
|
||||
append_u32(bytes, config.height);
|
||||
append_u32(bytes, config.layer_count);
|
||||
append_u32(bytes, config.layer_count * config.frame_count);
|
||||
for (std::uint32_t layer = 0; layer < config.layer_count; ++layer) {
|
||||
const auto name = generated_layer_name(config.layer_name, layer, config.layer_count);
|
||||
append_u32(bytes, static_cast<std::uint32_t>(config.layers.size()));
|
||||
append_u32(bytes, total_frame_count);
|
||||
for (std::uint32_t layer = 0; layer < config.layers.size(); ++layer) {
|
||||
const auto& layer_config = config.layers[layer];
|
||||
append_u32(bytes, layer);
|
||||
append_f32(bytes, config.layer_metadata.opacity);
|
||||
append_u32(bytes, static_cast<std::uint32_t>(name.size()));
|
||||
append_ascii(bytes, name);
|
||||
append_u32(bytes, config.layer_metadata.blend_mode);
|
||||
bytes.push_back(config.layer_metadata.alpha_locked ? std::byte { 1 } : std::byte { 0 });
|
||||
bytes.push_back(config.layer_metadata.visible ? std::byte { 1 } : std::byte { 0 });
|
||||
append_u32(bytes, config.frame_count);
|
||||
for (std::uint32_t frame = 0; frame < config.frame_count; ++frame) {
|
||||
append_u32(bytes, config.frame_duration_ms);
|
||||
append_f32(bytes, layer_config.metadata.opacity);
|
||||
append_u32(bytes, static_cast<std::uint32_t>(layer_config.name.size()));
|
||||
append_ascii(bytes, layer_config.name);
|
||||
append_u32(bytes, layer_config.metadata.blend_mode);
|
||||
bytes.push_back(layer_config.metadata.alpha_locked ? std::byte { 1 } : std::byte { 0 });
|
||||
bytes.push_back(layer_config.metadata.visible ? std::byte { 1 } : std::byte { 0 });
|
||||
append_u32(bytes, static_cast<std::uint32_t>(layer_config.frames.size()));
|
||||
for (std::uint32_t frame = 0; frame < layer_config.frames.size(); ++frame) {
|
||||
append_u32(bytes, layer_config.frames[frame].duration_ms);
|
||||
for (std::uint32_t face = 0; face < 6U; ++face) {
|
||||
const PpiDirtyFacePayloadConfig* dirty_face = nullptr;
|
||||
for (const auto& candidate : config.dirty_faces) {
|
||||
@@ -833,4 +832,41 @@ pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMin
|
||||
return pp::foundation::Result<std::vector<std::byte>>::success(std::move(bytes));
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMinimalProjectConfig config)
|
||||
{
|
||||
if (config.layer_count == 0 || config.layer_count > max_ppi_layer_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI layer count is outside the configured range"));
|
||||
}
|
||||
|
||||
if (config.frame_count == 0 || config.frame_count > max_ppi_frame_count) {
|
||||
return pp::foundation::Result<std::vector<std::byte>>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI frame count is outside the configured range"));
|
||||
}
|
||||
|
||||
std::vector<std::string> names;
|
||||
names.reserve(config.layer_count);
|
||||
std::vector<std::vector<PpiFrameConfig>> frame_lists;
|
||||
frame_lists.reserve(config.layer_count);
|
||||
std::vector<PpiLayerConfig> layers;
|
||||
layers.reserve(config.layer_count);
|
||||
for (std::uint32_t layer = 0; layer < config.layer_count; ++layer) {
|
||||
names.push_back(generated_layer_name(config.layer_name, layer, config.layer_count));
|
||||
auto& frames = frame_lists.emplace_back();
|
||||
frames.assign(config.frame_count, PpiFrameConfig { .duration_ms = config.frame_duration_ms });
|
||||
layers.push_back(PpiLayerConfig {
|
||||
.name = names.back(),
|
||||
.metadata = config.layer_metadata,
|
||||
.frames = std::span<const PpiFrameConfig>(frames.data(), frames.size()),
|
||||
});
|
||||
}
|
||||
|
||||
return create_ppi_project(PpiProjectConfig {
|
||||
.width = config.width,
|
||||
.height = config.height,
|
||||
.layers = std::span<const PpiLayerConfig>(layers.data(), layers.size()),
|
||||
.dirty_faces = config.dirty_faces,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user