Files
Vivid2DRenderer/Vivid2DRenderer/model/Model2D.cpp
tzdwindows 7 f4e10bcccc feat(animation): implement animation clip and layer systems
- Added AnimationClip class with curve and keyframe management
- Implemented AnimationCurve with multiple interpolation types
- Created AnimationEventMarker for timeline events
- Added AnimationLayer with track and clip playback support
- Implemented blending modes for animation mixing
- Added event system with listeners and triggers
- Included utility functions for time/frame conversion
- Added copy and merge functionality for clips
- Implemented loop and playback control mechanisms
- Added metadata support including author and description
- Included UUID generation for unique identification
- Added frame rate and duration management
- Implemented parameter override system
- Added physics system integration support
2025-11-15 16:24:52 +08:00

459 lines
15 KiB
C++

#include "pch.h"
#include "Model2D.h"
#include <algorithm>
#include <cmath>
#include <stdexcept>
#include <utility>
#include <set>
#include <stduuid/uuid.h>
#include "util/BoundingBox.h"
#include "util/PhysicsSystem.h"
#include "util/ModelPose.h"
#include "util/AnimationLayer.h"
#include "ModelPart.h"
namespace Vivid2D {
// ==================== 构造器 ====================
Model2D::Model2D()
: m_uuid(generate_new_uuid()),
m_physics(std::make_unique<util::PhysicsSystem>()),
m_bounds(std::make_unique<util::BoundingBox>()),
m_currentPose("default")
{
initializeDefaultPose();
}
Model2D::Model2D(const std::string& name)
: Model2D()
{
m_name = name;
}
Model2D::~Model2D() = default;
Model2D::Model2D(Model2D&& other) noexcept
: m_name(std::move(other.m_name)),
m_version(std::move(other.m_version)),
m_uuid(other.m_uuid),
// m_metadata 移除
m_parts(std::move(other.m_parts)),
m_partMap(std::move(other.m_partMap)),
m_rootPart(other.m_rootPart),
m_meshes(std::move(other.m_meshes)),
m_textures(std::move(other.m_textures)),
m_parameters(std::move(other.m_parameters)),
m_animationLayers(std::move(other.m_animationLayers)),
m_physics(std::move(other.m_physics)),
m_needsUpdate(other.m_needsUpdate),
m_bounds(std::move(other.m_bounds)),
m_poses(std::move(other.m_poses)),
m_currentPoseName(std::move(other.m_currentPoseName)),
m_currentPose(std::move(other.m_currentPose)),
m_blendTargetPose(std::move(other.m_blendTargetPose)),
m_blendProgress(other.m_blendProgress),
m_blendSpeed(other.m_blendSpeed),
m_lights(std::move(other.m_lights))
{
other.m_rootPart = nullptr;
// 重新构建 m_partMap 以确保指针正确
m_partMap.clear();
for (const auto& part : m_parts) {
m_partMap[part->getName()] = part.get();
}
if (!m_parts.empty()) {
m_rootPart = m_parts[0].get();
}
else {
m_rootPart = nullptr;
}
}
// 移动赋值运算符
Model2D& Model2D::operator=(Model2D&& other) noexcept {
if (this != &other) {
using std::swap;
swap(m_name, other.m_name);
swap(m_version, other.m_version);
swap(m_uuid, other.m_uuid);
m_name = std::move(other.m_name);
m_version = std::move(other.m_version);
m_uuid = other.m_uuid;
m_parts = std::move(other.m_parts);
m_partMap = std::move(other.m_partMap);
m_rootPart = other.m_rootPart;
m_meshes = std::move(other.m_meshes);
m_textures = std::move(other.m_textures);
m_parameters = std::move(other.m_parameters);
m_animationLayers = std::move(other.m_animationLayers);
m_physics = std::move(other.m_physics);
m_needsUpdate = other.m_needsUpdate;
m_bounds = std::move(other.m_bounds);
m_poses = std::move(other.m_poses);
m_currentPoseName = std::move(other.m_currentPoseName);
m_currentPose = std::move(other.m_currentPose);
m_blendTargetPose = std::move(other.m_blendTargetPose);
m_blendProgress = other.m_blendProgress;
m_blendSpeed = other.m_blendSpeed;
m_lights = std::move(other.m_lights);
other.m_rootPart = nullptr;
Model2D temp(std::move(other));
swap(*this, temp);
}
return *this;
}
// ==================== 姿态管理 ====================
void Model2D::addPose(const util::ModelPose& pose) {
if (pose.getName().empty()) {
throw std::invalid_argument("Pose name cannot be empty");
}
m_poses.emplace(pose.getName(), pose);
markNeedsUpdate();
}
const util::ModelPose* Model2D::getPose(const std::string& name) const {
auto it = m_poses.find(name);
return (it != m_poses.end()) ? &it->second : nullptr;
}
void Model2D::applyPose(const std::string& poseName) {
auto it = m_poses.find(poseName);
if (it != m_poses.end()) {
applyPoseInternal(it->second);
m_currentPoseName = poseName;
m_currentPose = it->second;
m_blendProgress = 1.0f;
markNeedsUpdate();
}
}
void Model2D::blendToPose(const std::string& targetPoseName, float blendTime) {
auto it = m_poses.find(targetPoseName);
if (it != m_poses.end()) {
m_blendTargetPose = it->second;
m_blendProgress = 0.0f;
m_blendSpeed = (blendTime > 0.0f) ? 1.0f / blendTime : 10.0f;
markNeedsUpdate();
}
}
void Model2D::saveCurrentPose(const std::string& poseName) {
util::ModelPose newPose(poseName);
captureCurrentPose(newPose);
addPose(newPose);
}
std::set<std::string> Model2D::getPoseNames() const {
std::set<std::string> names;
for (const auto& pair : m_poses) {
names.insert(pair.first);
}
return names;
}
void Model2D::removePose(const std::string& poseName) {
if (poseName != "default") {
m_poses.erase(poseName);
if (m_currentPoseName == poseName) {
applyPose("default");
}
}
}
void Model2D::setPoseBlend(const std::string& poseName, float blendFactor) {
auto it = m_poses.find(poseName);
if (it != m_poses.end()) {
util::ModelPose blendedPose = util::ModelPose::lerp(m_currentPose, it->second, blendFactor, "manual_blend");
applyPoseInternal(blendedPose);
markNeedsUpdate();
}
}
// ==================== 光源管理 ====================
const std::vector<util::LightSource>& Model2D::getLights() const {
return m_lights;
}
void Model2D::addLight(const util::LightSource& light) {
m_lights.push_back(light);
markNeedsUpdate();
}
void Model2D::removeLight(const util::LightSource& light) {
auto it = std::remove(this->m_lights.begin(), this->m_lights.end(), light);
if (it != this->m_lights.end()) {
this->m_lights.erase(it, this->m_lights.end());
markNeedsUpdate();
}
}
void Model2D::clearLights() {
m_lights.clear();
markNeedsUpdate();
}
// ==================== 部件管理 ====================
std::unique_ptr<ModelPart> Model2D::createPart(const std::string& name) {
return std::make_unique<ModelPart>(name);
}
void Model2D::addPart(std::unique_ptr<ModelPart> part) {
if (!part) return;
const std::string& name = part->getName();
if (m_partMap.count(name)) {
throw std::invalid_argument("Part already exists: " + name);
}
ModelPart* rawPtr = part.get();
m_parts.push_back(std::move(part));
m_partMap[name] = rawPtr;
if (m_rootPart == nullptr) {
m_rootPart = rawPtr;
}
}
ModelPart* Model2D::getPart(const std::string& name) const {
auto it = m_partMap.find(name);
return (it != m_partMap.end()) ? it->second : nullptr;
}
const std::map<std::string, ModelPart*>& Model2D::getPartMap() const {
return m_partMap;
}
const std::vector<std::unique_ptr<ModelPart>>& Model2D::getParts() const {
return m_parts;
}
// ==================== 参数管理 ====================
AnimationParameter* Model2D::createParameter(const std::string& id, float min, float max, float defaultValue) {
auto [it, inserted] = m_parameters.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(id, min, max, defaultValue));
return &it->second;
}
AnimationParameter* Model2D::getParameter(const std::string& id) {
auto it = m_parameters.find(id);
return (it != m_parameters.end()) ? &it->second : nullptr;
}
void Model2D::addParameter(const AnimationParameter& param) {
m_parameters[param.getId()] = param;
}
void Model2D::setParameterValue(const std::string& paramId, float value) {
if (auto param = getParameter(paramId)) {
param->setValue(value);
markNeedsUpdate();
}
}
float Model2D::getParameterValue(const std::string& paramId) const {
auto it = m_parameters.find(paramId);
return (it != m_parameters.end()) ? it->second.getValue() : 0.0f;
}
const std::map<std::string, AnimationParameter>& Model2D::getParameters() const {
return m_parameters;
}
// ==================== 网格管理 ====================
std::unique_ptr<Mesh2D> Model2D::createMesh(const std::string& name, const std::vector<float>& vertices,
const std::vector<float>& uvs, const std::vector<int>& indices) {
return std::make_unique<Mesh2D>(name, vertices, uvs, indices);
}
void Model2D::addMesh(std::unique_ptr<Mesh2D> mesh) {
m_meshes.push_back(std::move(mesh));
}
Mesh2D* Model2D::getMesh(const std::string& name) const {
for (const auto& mesh : m_meshes) {
if (mesh->getName() == name) {
return mesh.get();
}
}
return nullptr;
}
const std::vector<std::unique_ptr<Mesh2D>>& Model2D::getMeshes() const {
return m_meshes;
}
// ==================== 纹理管理 ====================
void Model2D::addTexture(std::shared_ptr<Render::Texture::Texture> texture) {
if (!texture) {
throw std::invalid_argument("Texture cannot be null");
}
const std::string& textureName = texture->getName();
if (textureName.empty()) {
throw std::invalid_argument("Texture name cannot be empty");
}
m_textures[textureName] = std::move(texture);
}
std::shared_ptr<Render::Texture::Texture> Model2D::getTexture(const std::string& name) const {
auto it = m_textures.find(name);
return (it != m_textures.end()) ? it->second : nullptr;
}
const std::map<std::string, std::shared_ptr<Render::Texture::Texture>>& Model2D::getTextures() const {
return m_textures;
}
// ==================== 动画层管理 ====================
std::unique_ptr<util::AnimationLayer> Model2D::createAnimationLayer(const std::string& name) {
auto layer = std::make_unique<util::AnimationLayer>(name);
m_animationLayers.push_back(std::move(layer));
return std::move(m_animationLayers.back());
}
const std::vector<std::unique_ptr<util::AnimationLayer>>& Model2D::getAnimationLayers() const {
return m_animationLayers;
}
void Model2D::setAnimationLayers(std::vector<std::unique_ptr<util::AnimationLayer>> animationLayers) {
m_animationLayers = std::move(animationLayers);
}
// ==================== 更新系统 ====================
void Model2D::update(float deltaTime) {
updatePoseBlending(deltaTime);
if (!m_needsUpdate && !m_physics->hasActivePhysics()) {
return;
}
updateParameterDeformations();
applyCurrentPoseToModel();
updateHierarchyTransforms();
updateBoundingBox();
m_needsUpdate = false;
}
void Model2D::updatePoseBlending(float deltaTime) {
if (m_blendProgress < 1.0f) {
m_blendProgress += deltaTime * m_blendSpeed;
if (m_blendProgress >= 1.0f) {
m_blendProgress = 1.0f;
m_currentPose = m_blendTargetPose;
m_currentPoseName = m_blendTargetPose.getName();
}
markNeedsUpdate();
}
}
void Model2D::applyCurrentPoseToModel() {
if (m_blendProgress < 1.0f) {
util::ModelPose blendedPose = util::ModelPose::lerp(m_currentPose, m_blendTargetPose, m_blendProgress, "blended");
applyPoseInternal(blendedPose);
}
else {
applyPoseInternal(m_currentPose);
}
}
void Model2D::applyPoseInternal(const util::ModelPose& pose) const {
for (const auto& pair : pose.getPartPoses()) {
const std::string& partName = pair.first;
const util::PartPose& partPose = pair.second;
if (ModelPart* part = getPart(partName)) {
part->setPosition(partPose.getPosition());
part->setRotation(partPose.getRotation());
part->setScale(partPose.getScale());
part->setOpacity(partPose.getOpacity());
part->setVisible(partPose.isVisible());
}
}
}
void Model2D::captureCurrentPose(util::ModelPose& pose) {
for (const auto& partPtr : m_parts) {
const ModelPart& part = *partPtr;
util::PartPose partPose(
part.getPosition(),
part.getRotation(),
part.getScale(),
part.getOpacity(),
part.isVisible(),
glm::vec3(1.0f, 1.0f, 1.0f)
);
pose.setPartPose(part.getName(), partPose);
}
}
void Model2D::initializeDefaultPose() {
util::ModelPose defaultPose = util::ModelPose::createDefaultPose();
captureCurrentPose(defaultPose);
m_poses.emplace("default", defaultPose);
m_currentPose = defaultPose;
}
void Model2D::updateParameterDeformations() {
for (auto& pair : m_parameters) {
AnimationParameter& param = pair.second;
if (param.hasChanged()) {
applyParameterDeformations(&param);
param.markClean();
}
}
}
void Model2D::applyParameterDeformations(AnimationParameter* param) {
for (const auto& partPtr : m_parts) {
// 假设 ModelPart::applyParameter(AnimationParameter*) 已实现
// partPtr->applyParameter(param);
}
}
void Model2D::updateHierarchyTransforms() {
if (m_rootPart) {
m_rootPart->recomputeWorldTransformRecursive();
}
}
void Model2D::updateBoundingBox() {
if (!m_bounds) {
m_bounds = std::make_unique<util::BoundingBox>();
}
m_bounds->reset();
for (const auto& partPtr : m_parts) {
m_bounds->expand(partPtr->getWorldBounds());
}
}
// ==================== 工具方法 ====================
bool Model2D::isVisible() const {
return m_rootPart != nullptr && m_rootPart->isVisible();
}
void Model2D::setVisible(bool visible) {
if (m_rootPart) {
m_rootPart->setVisible(visible);
}
}
} // namespace Vivid2D