#pragma once #include "BoneAnimatedModelNew.h" #include "render/Renderer.h" #include "render/TextureManager.h" #include "items/Item.h" #include #include #include #include #include #include #include namespace ZL { enum class AnimationState { STAND = 0, WALK = 1, STAND_TO_ACTION = 2, ACTION_ATTACK = 3, ACTION_ATTACK_2 = 4, ACTION_IDLE = 5, ACTION_TO_STAND = 6 }; class Character { public: using PathPlanner = std::function( const Eigen::Vector3f& start, const Eigen::Vector3f& end)>; void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = ""); void loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = ""); // Assigns the given texture to a specific mesh (by name, as defined in the animation file). void setTexture(const std::string& meshName, std::shared_ptr texture); // Assigns the given texture to every mesh in every loaded animation. // Call AFTER loading animations so the mesh names are known. void setTexture(std::shared_ptr texture); void update(int64_t deltaMs); // onArrived is called once when the character reaches this target. // From Python you can chain further commands (walk, wait, trigger others). void setTarget(const Eigen::Vector3f& target, std::function onArrived = nullptr); void setPathPlanner(PathPlanner planner); void draw(Renderer& renderer); void drawShadowDepth(Renderer& renderer); void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera); // Public: read by Game for camera tracking and ray-cast origin Eigen::Vector3f position = Eigen::Vector3f(0.f, 0.f, 0.f); float facingAngle = 0.0f; // Per-character tuning — set after construction, before first update float walkSpeed = 3.0f; float rotationSpeed = 4.0f; float modelScale = 0.12f; // Applied after scale, fixes model-space orientation (e.g. Blender Z-up exports) Eigen::Quaternionf modelCorrectionRotation = Eigen::Quaternionf::Identity(); // NPC Gift Item giftItem; std::string npcId; std::string npcName; bool giftReceived = false; int battle_state = 0; bool resetAnim = false; int attack = 0; AnimationState currentState = AnimationState::STAND; float attack_cooldown = 0.f; bool canAttack = false; Character* attackTarget = nullptr; bool isPlayer = false; bool useGpuSkinning = true; //bool useGpuSkinning = false; float interactionRadius = 0.0f; VertexRenderStruct weaponMesh; std::shared_ptr weaponTexture; Eigen::Matrix3f weaponInitialRotation = Eigen::Matrix3f::Identity(); Eigen::Vector3f weaponInitialPosition = Eigen::Vector3f::Zero(); std::string weaponAttachBoneName = "RightHand"; bool showWeapon = true; private: std::map animations; VertexRenderStruct modelMutable; std::unordered_map> meshTextures; Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f); Eigen::Vector3f requestedWalkTarget = Eigen::Vector3f(0.f, 0.f, 0.f); std::vector pathWaypoints; size_t currentWaypointIndex = 0; PathPlanner pathPlanner; float targetFacingAngle = 0.0f; std::function onArrivedCallback; static constexpr float WALK_THRESHOLD = 0.05f; static constexpr float TARGET_REPLAN_THRESHOLD = 0.25f; // Returns the animation state to actually play/draw, falling back to IDLE // if the requested state has no loaded animation. AnimationState resolveActiveState() const; bool prepareGpuSkinning(); // Draws the weapon mesh attached to weaponAttachBoneName. // Caller must ensure the right shader is active with matching uniforms. void drawAttachedWeapon(Renderer& renderer); // GPU skinning: draw using shader-based skinning void drawGpuSkinning(Renderer& renderer); // Shadow: draw into depth map (no texture, no projection push) void drawShadowDepthGpuSkinning(Renderer& renderer); void drawShadowDepthCpu(Renderer& renderer); // Shadow: draw with shadow-aware shaders void drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera); void drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera); }; } // namespace ZL