#pragma once #include #include #include #include #include #include #include #include #include #include "glm.hpp" class meshRenderBoneComposition; namespace CreatureModule { class CreatureManager; class CreatureAnimation; } namespace CreatureModule { class CreatureMetaData { public: CreatureMetaData(const std::string& json_str); virtual ~CreatureMetaData(); bool getIsValid() const { return is_valid; } bool buildSkinSwapIndices( const std::string& swap_name, meshRenderBoneComposition * bone_composition, std::function indices_callback, int& total_size ); void updateIndicesAndPoints( glm::uint32 * src_indices, std::function dst_indices_callback, int num_indices, const std::string& anim_name, int time_in ); void updateRegionColors( std::unordered_map>& animations); bool addSkinSwap(const std::string& swap_name, const std::unordered_set& set_in); bool removeSkinSwap(const std::string& swap_name); void printInfo(); void resetEvents(const std::string& anim_name); bool hasEvents(const std::string& anim_name) const; std::string runEvents(const std::string& anim_name, int time_in); void computeMorphWeights(const glm::vec2& img_pt) { morph_data.play_img_pt = img_pt; auto sampleFilterPt = []( float q11, // (x1, y1) float q12, // (x1, y2) float q21, // (x2, y1) float q22, // (x2, y2) float x1, float y1, float x2, float y2, float x, float y) { float x2x1, y2y1, x2x, y2y, yy1, xx1; x2x1 = x2 - x1; y2y1 = y2 - y1; x2x = x2 - x; y2y = y2 - y; yy1 = y - y1; xx1 = x - x1; float denom = (x2x1 * y2y1); float numerator = ( q11 * x2x * y2y + q21 * xx1 * y2y + q12 * x2x * yy1 + q22 * xx1 * yy1 ); return (denom == 0) ? q11 : (1.0f / denom * numerator); }; auto lookupVal = [this](int x_in, int y_in, int idx) { auto& cur_space = morph_data.morph_spaces[idx]; return static_cast(cur_space[y_in * morph_data.morph_res + x_in]) / 255.0f; }; float x1 = std::floor(img_pt.x); float y1 = std::floor(img_pt.y); float x2 = std::ceil(img_pt.x); float y2 = std::ceil(img_pt.y); for (int i = 0; i < static_cast(morph_data.morph_spaces.size()); i++) { float q11 = (float)lookupVal(x1, y1, i); // (x1, y1) float q12 = (float)lookupVal(x1, y2, i); // (x1, y2) float q21 = (float)lookupVal(x2, y1, i); // (x2, y1) float q22 = (float)lookupVal(x2, y2, i); // (x2, y2) float sample_val = sampleFilterPt( q11, q12, q21, q22, x1, y1, x2, y2, img_pt.x, img_pt.y); morph_data.weights[i] = sample_val; } } void computeMorphWeightsNormalised(const glm::vec2& normal_pt) { auto img_pt = normal_pt * glm::vec2(morph_data.morph_res - 1, morph_data.morph_res - 1); img_pt.x = std::max(std::min((float)morph_data.morph_res - 1.0f, img_pt.x), 0.0f); img_pt.y = std::max(std::min((float)morph_data.morph_res - 1.0f, img_pt.y), 0.0f); computeMorphWeights(img_pt); } void computeMorphWeightsWorld(const glm::vec2& world_pt, const glm::vec2& base_pt, float radius) { auto rel_pt = world_pt - base_pt; auto cur_length = glm::length(rel_pt); if (cur_length > radius) { rel_pt = glm::normalize(rel_pt); rel_pt *= radius; } glm::vec2 normal_pt = (rel_pt + glm::vec2(radius, radius)) / (radius * 2.0f); computeMorphWeightsNormalised(normal_pt); } void updateMorphStep(CreatureModule::CreatureManager * manager_in, float delta_step); struct MorphData { std::vector> morph_spaces; std::string center_clip; std::vector> morph_clips; std::vector weights; glm::vec2 bounds_min, bounds_max; int morph_res; std::vector> play_anims_data; std::pair play_center_anim_data; std::vector play_pts; glm::vec2 play_img_pt; bool isValid() const { return (morph_spaces.empty() == false); } }; MorphData& getMorphData() { return morph_data; } protected: const std::vector * sampleOrder(const std::string& anim_name, int time_in) const; std::unordered_map> mesh_map; std::unordered_map>> anim_order_map; std::unordered_map>> anim_events_map; std::unordered_map> skin_swaps; std::unordered_map>>> anim_region_colors; bool is_valid; MorphData morph_data; }; }