text: /*
   * Copyright (c) Contributors to the Open 3D Engine Project.
   * For complete copyright and license terms please see the LICENSE at the root of this distribution.
   *
   * SPDX-License-Identifier: Apache-2.0 OR MIT
   *
   */
  
  #pragma once
  
  #include <Atom/Feature/MorphTargets/MorphTargetInputBuffers.h>
  
  #include <Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h>
  #include <Atom/RHI/DispatchItem.h>
  #include <Atom/RHI/ConstantsData.h>
  #include <AtomCore/Instance/Instance.h>
  
  namespace AZ
  {
      namespace RHI
      {
          class BufferView;
          class PipelineState;
      }
  
      namespace RPI
      {
          class Buffer;
          class ModelLod;
          class Shader;
          class ShaderResourceGroup;
      }
  
      namespace Render
      {
          class SkinnedMeshFeatureProcessor;
  
          //! Holds and manages an RHI DispatchItem for a specific morph target, and the resources that are needed to build and maintain it.
          class MorphTargetDispatchItem
              : private RPI::ShaderReloadNotificationBus::Handler
          {
          public:
              AZ_CLASS_ALLOCATOR(MorphTargetDispatchItem, AZ::SystemAllocator, 0);
  
              MorphTargetDispatchItem() = delete;
              //! Create one dispatch item per morph target
              explicit MorphTargetDispatchItem(
                  const AZStd::intrusive_ptr<MorphTargetInputBuffers> inputBuffers,
                  const MorphTargetMetaData& morphTargetMetaData,
                  SkinnedMeshFeatureProcessor* skinnedMeshFeatureProcessor,
                  MorphTargetInstanceMetaData morphInstanceMetaData,
                  float accumulatedDeltaRange
              );
              ~MorphTargetDispatchItem();
  
              // The event handler cannot be copied
              AZ_DISABLE_COPY_MOVE(MorphTargetDispatchItem);
  
              bool Init();
  
              const RHI::DispatchItem& GetRHIDispatchItem() const;
  
              void SetWeight(float weight);
              float GetWeight() const;
          private:
              bool InitPerInstanceSRG();
              void InitRootConstants(const RHI::ConstantsLayout* rootConstantsLayout);
  
              // ShaderInstanceNotificationBus::Handler overrides
              void OnShaderReinitialized(const RPI::Shader& shader) override;
              void OnShaderAssetReinitialized(const Data::Asset<RPI::ShaderAsset>& shaderAsset) override;
              void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override;
  
              RHI::DispatchItem m_dispatchItem;
  
              // The morph target shader used for this instance
              Data::Instance<RPI::Shader> m_morphTargetShader;
  
              // The vertex deltas
              AZStd::intrusive_ptr<MorphTargetInputBuffers> m_inputBuffers;
  
              // The per-object shader resource group
              Data::Instance<RPI::ShaderResourceGroup> m_instanceSrg;
  
              // Metadata used to set the root constants for the shader
              MorphTargetMetaData m_morphTargetMetaData;
  
              AZ::RHI::ConstantsData m_rootConstantData;
  
              // Per-SkinnedMeshInstancenstance constants for morph targets
              MorphTargetInstanceMetaData m_morphInstanceMetaData;
              // A conservative value for encoding/decoding the accumulated deltas
              float m_accumulatedDeltaIntegerEncoding;
  
              // Keep track of the constant index of m_weight since it is updated frequently
              RHI::ShaderInputConstantIndex m_weightIndex;
          };
  
          float ComputeMorphTargetIntegerEncoding(const AZStd::vector<MorphTargetMetaData>& morphTargetMetaDatas);
      } // namespace Render
  } // namespace AZ
  