#include "creaturegodot.h" #include #include #include #include #include #include static std::map > global_animations; static std::map > global_load_data_packets; //#define _CREATURE_DEBUG static bool is_file_exist(const char *fileName) { Ref<_File> file; file.instance(); return file->file_exists(fileName); } static std::string GetAnimationToken(const std::string& filename_in, const std::string& name_in) { return filename_in + std::string("_") + name_in; } static bool LoadDataPacket(const std::string& filename_in) { if(!is_file_exist(filename_in.c_str())) { return false; } if (global_load_data_packets.count(filename_in) > 0) { // file already loaded, just return return true; } ////////////////////////////////////////////////////////////////////////// //Changed! ////////////////////////////////////////////////////////////////////////// std::shared_ptr new_packet = std::make_shared(); // load regular JSON Ref<_File> file; file.instance(); if (file->open(filename_in.c_str(), _File::READ) == Error::OK) { String data = file->get_as_text(); std::string text(data.utf8().get_data()); CreatureModule::LoadCreatureJSONDataFromString(text, *new_packet); file->close(); } global_load_data_packets[filename_in] = new_packet; return true; } static void load_animation(const std::string& filename_in, const std::string& name_in) { auto cur_token = GetAnimationToken(filename_in, name_in); if (global_animations.count(cur_token) > 0) { // animation already exists, just return return; } auto load_data = global_load_data_packets[filename_in]; std::shared_ptr new_animation = std::make_shared(*load_data, name_in); global_animations[cur_token] = new_animation; } static bool add_loaded_animation(CreatureModule::CreatureManager * creature_manager, const std::string& filename_in, const std::string& name_in) { auto cur_token = GetAnimationToken(filename_in, name_in); if (global_animations.count(cur_token) > 0) { creature_manager->AddAnimation(global_animations[cur_token]); creature_manager->SetIsPlaying(true); creature_manager->SetShouldLoop(true); return true; } else { #ifdef _CREATURE_DEBUG std::cout << "ERROR! ACreatureActor::AddLoadedAnimation() Animation with filename: " << filename_in << " and name: " << name_in << " not loaded!" << std::endl; #endif } return false; } // CreatureGodot CreatureGodot::CreatureGodot() { color=Color(1,1,1); rect_cache_dirty=true; anim_speed = 2.0f; mirror_y = false; anim_frame = 0.0f; indices_process_mode = INDICES_MODE_NONE; reload_data = false; run_morph_targets = false; } bool CreatureGodot::load_json(const String filename_in) { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot::load_json() - Loading file: "<(new CreatureModule::Creature(*json_data)); manager = std::unique_ptr (new CreatureModule::CreatureManager(cur_creature)); auto all_animation_names = manager->GetCreature()->GetAnimationNames(); auto first_animation_name = all_animation_names[0]; for (auto& cur_name : all_animation_names) { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot::load_json() - Trying to load animation: "<SetActiveAnimationName(first_animation_name); if(!Engine::get_singleton()->is_editor_hint()) { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot::load_json() -Enabling AutoBlending for: "<SetAutoBlending(true); } else { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot::load_json() -In Editor, Disabling Autoblending for: "<GetAllAnimations().count(real_anim_name) == 0) { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot::blend_to_animation() - ERROR! Animation name: "<AutoBlendTo(real_anim_name, blend_delta); return true; } void CreatureGodot::set_skinswap_name(String name_in) { skinswap_name = name_in; } void CreatureGodot::set_should_loop(bool flag_in) { manager->SetShouldLoop(flag_in); } void CreatureGodot::set_anim_speed(float value_in) { anim_speed = value_in; } float CreatureGodot::get_anim_speed() const{ return anim_speed; } void CreatureGodot::set_anim_frame(float frame_in) { if(manager) { anim_frame = frame_in; manager->setRunTime(frame_in); update_animation(0.0f); } } float CreatureGodot::get_anim_frame() const { return anim_frame; } void CreatureGodot::set_anim_name(String name_in) { if(manager) { auto retval = blend_to_animation(name_in, 1.0f); if(retval) { update_animation(0.0f); anim_name = name_in; } } } String CreatureGodot::get_anim_name() const { return anim_name; } void CreatureGodot::enable_skinswap() { indices_process_mode = INDICES_MODE_SKINSWAP; } void CreatureGodot::enable_layerorder() { indices_process_mode = INDICES_MODE_ORDER; } void CreatureGodot::disable_skinswap_or_order() { indices_process_mode = INDICES_MODE_NONE; } void CreatureGodot::update_colors() { if(manager) { if(fill_colors.size() != manager->GetCreature()->GetTotalNumPoints()) { fill_colors.resize(manager->GetCreature()->GetTotalNumPoints()); } auto& regions_map = manager->GetCreature()->GetRenderComposition()->getRegionsMap(); for (auto& cur_region_pair : regions_map) { auto cur_region = cur_region_pair.second; auto start_pt_index = cur_region->getStartPtIndex(); auto end_pt_index = cur_region->getEndPtIndex(); auto cur_alpha = cur_region->getOpacity() / 100.0f; auto cur_red = cur_region->getRed() / 100.0f; auto cur_green = cur_region->getGreen() / 100.0f; auto cur_blue = cur_region->getBlue() / 100.0f; // Check for custom color overrides if(!custom_region_colors.empty()) { auto c_iter = custom_region_colors.find(cur_region->getName()); if(c_iter != custom_region_colors.end()) { auto& custom_color = c_iter->second; cur_red = custom_color.r; cur_green = custom_color.g; cur_blue = custom_color.b; cur_alpha = custom_color.a; } } // Write final colors for (auto i = start_pt_index; i <= end_pt_index; i++) { fill_colors.write[i].r = color.r * cur_red * cur_alpha; fill_colors.write[i].g = color.g * cur_green * cur_alpha; fill_colors.write[i].b = color.b * cur_blue * cur_alpha; fill_colors.write[i].a = color.a * cur_alpha; } } } } void CreatureGodot::update_animation(float delta) { auto hasEvents = [&]() { if(metadata) { if(metadata->hasEvents(manager->GetActiveAnimationName())) { return true; } } return false; }; auto processEvents = [&]() { std::string evt_name = metadata->runEvents( manager->GetActiveAnimationName(), static_cast(manager->getActualRunTime())); if(!evt_name.empty()) { emit_signal("CreatureEvent", String(evt_name.c_str())); } }; if(manager) { auto old_time = manager->getActualRunTime(); bool has_events = hasEvents(); if(has_events) { processEvents(); } bool morph_targets_valid = false; if (run_morph_targets && metadata) { morph_targets_valid = metadata->getMorphData().isValid(); } auto real_delta = delta * anim_speed; if (morph_targets_valid) { metadata->updateMorphStep(manager.get(), real_delta); } else { manager->Update(real_delta); } if((old_time > manager->getActualRunTime()) && has_events) { metadata->resetEvents(manager->GetActiveAnimationName()); } // resize points, uvs and indices array if(reload_data) { points.resize(manager->GetCreature()->GetTotalNumPoints()); uvs.resize(points.size()); indices.resize(manager->GetCreature()->GetTotalNumIndices()); meta_indices.resize(manager->GetCreature()->GetTotalNumIndices()); reload_data = false; } // fill in rendering data // colors update_colors(); // indices/topology auto cur_indices = manager->GetCreature()->GetGlobalIndices(); for(size_t i = 0; i < indices.size(); i++) { indices.write[i] = cur_indices[i]; } // MetaData indices processing if(indices_process_mode == INDICES_MODE_ORDER) { process_layerorder(static_cast(manager->getActualRunTime())); } else if(indices_process_mode == INDICES_MODE_SKINSWAP) { process_skinswap(); } // points and uvs auto cur_pts = manager->GetCreature()->GetRenderPts(); auto cur_uvs = manager->GetCreature()->GetGlobalUvs(); for(size_t i = 0; i < points.size(); i++) { glm::float32 cur_x = cur_pts[i * 3]; glm::float32 cur_y = cur_pts[i * 3 + 1]; points.write[i] = Vector2(cur_x, -cur_y); glm::float32 cur_u = cur_uvs[i * 2]; glm::float32 cur_v = cur_uvs[i * 2 + 1]; uvs.write[i] = Vector2(cur_u, cur_v); } update(); } } Rect2 CreatureGodot::_edit_get_rect() const { if (rect_cache_dirty){ int l =points.size(); item_rect=Rect2(); for(int i=0;iSetMirrorY(mirror_y); } RenderingServer::get_singleton()->canvas_item_add_triangle_array( get_canvas_item(), use_meta_indices ? real_meta_indices : indices, points, fill_colors, uvs, Vector(), Vector(), texture.is_valid()?texture->get_rid():RID() ); } break; } } void CreatureGodot::set_color(Color p_color){ color=p_color; update(); } Color CreatureGodot::get_color() const{ return color; } void CreatureGodot::set_asset_filename(String filename_in) { auto retval = load_json(filename_in); if(retval) { reload_data = true; asset_filename = filename_in; update_animation(0.1f); rect_cache_dirty = true; } } String CreatureGodot::get_asset_filename() const { return asset_filename; } void CreatureGodot::set_metadata_filename(String filename_in) { #ifdef _CREATURE_DEBUG std::cout<<"CreatureGodot - Loading MetaData: "< file; file.instance(); std::string metaStr; if (file->open(filename_in.c_str(), _File::READ) == Error::OK) { String data = file->get_as_text(); metaStr = std::string(data.utf8().get_data()); file->close(); } metadata_filename = filename_in; metadata = std::unique_ptr( new CreatureModule::CreatureMetaData(metaStr)); // Load Animated Region Colors if(manager) { metadata->updateRegionColors(manager->GetAllAnimations()); } } String CreatureGodot::get_metadata_filename() const { return metadata_filename; } void CreatureGodot::set_texture(const Ref& p_texture){ texture=p_texture; /*if (texture.is_valid()) { uint32_t flags=texture->get_flags(); flags&=~Texture::FLAG_REPEAT; if (tex_tile) flags|=Texture::FLAG_REPEAT; texture->set_flags(flags); }*/ update(); } Ref CreatureGodot::get_texture() const{ return texture; } void CreatureGodot::set_mirror_y(bool flag_in) { mirror_y = flag_in; update(); } bool CreatureGodot::get_mirror_y() const { return mirror_y; } void CreatureGodot::set_active_item_swap(String region_name, int swap_idx) { if(manager) { manager->GetCreature()->SetActiveItemSwap(std::string(region_name.utf8()), swap_idx); } } void CreatureGodot::remove_active_item_swap(String region_name) { if(manager) { manager->GetCreature()->RemoveActiveItemSwap(std::string(region_name.utf8())); } } void CreatureGodot::set_anchor_points_active(bool flag_in) { if(manager) { manager->GetCreature()->SetAnchorPointsActive(flag_in); } } void CreatureGodot::make_point_cache(String animation_name_in, int gap_step) { if(manager) { manager->MakePointCache(std::string(animation_name_in.utf8()), gap_step); } } void CreatureGodot::add_skinswap(String name_in, Vector custom_swap) { if(metadata) { std::unordered_set swap_set; for(int i = 0; i < custom_swap.size(); i++) { swap_set.insert(std::string(custom_swap[i].utf8())); } metadata->addSkinSwap(std::string(name_in.utf8()), swap_set); } } void CreatureGodot::remove_skinswap(String name_in) { if(metadata) { metadata->removeSkinSwap(std::string(name_in.utf8())); } } void CreatureGodot::process_skinswap() { int real_indices_size = 0; auto render_composition = manager->GetCreature()->GetRenderComposition(); auto retval = metadata->buildSkinSwapIndices( std::string(skinswap_name.utf8()), render_composition, [&](int idx, int value) { meta_indices.write[idx] = value; }, real_indices_size ); if(retval) { if(real_meta_indices.size() != real_indices_size) { real_meta_indices.resize(real_indices_size); } for(int i = 0; i < real_indices_size; i++) { real_meta_indices.write[i] = meta_indices[i]; } } } void CreatureGodot::process_layerorder(int time_in) { metadata->updateIndicesAndPoints( manager->GetCreature()->GetGlobalIndices(), [&](int idx, int value) { meta_indices.write[idx] = value; }, manager->GetCreature()->GetTotalNumIndices(), manager->GetActiveAnimationName(), time_in ); if(real_meta_indices.size() != meta_indices.size()) { real_meta_indices.resize(meta_indices.size()); } for(int i = 0; i < real_meta_indices.size(); i++) { real_meta_indices.write[i] = meta_indices[i]; } } Vector2 CreatureGodot::get_bone_pos(String bone_name, float slide_factor) { Vector2 ret_pt(0,0); if(manager) { auto render_composition = manager->GetCreature()->GetRenderComposition(); auto& bones_map = render_composition->getBonesMap(); std::string real_name(bone_name.utf8()); if(bones_map.count(real_name) == 0) { return Vector2(0,0); } auto cur_bone = bones_map[real_name]; auto pt1 = cur_bone->getWorldStartPt(); auto pt2 = cur_bone->getWorldEndPt(); auto rel_vec = (pt2 - pt1) * slide_factor; auto set_vec = pt1 + rel_vec; // local coords ret_pt = Vector2(set_vec.x, set_vec.y); // transform to world coords get_transform().xform(ret_pt); } return ret_pt; } Vector CreatureGodot::get_anim_clips() const { Vector ret_names; if(manager) { const auto& all_anims = manager->GetCreature()->GetAnimationNames(); for(const auto& cur_name : all_anims) { ret_names.push_back(String(cur_name.c_str())); } } return ret_names; } void CreatureGodot::set_morph_targets_active(bool flag_in) { run_morph_targets = flag_in; if(run_morph_targets) { manager->SetBlending(false); } } bool CreatureGodot::get_morph_targets_active() const { return run_morph_targets; } void CreatureGodot::set_morph_targets_pt(const Vector2& pt_in, const Vector2& base_pt, float radius) { // transform to local coords auto char_base_pos = get_transform().xform_inv(base_pt); auto char_pt_pos = get_transform().xform_inv(pt_in); if(metadata) { if (metadata->getMorphData().isValid()) { metadata->computeMorphWeightsWorld( glm::vec2(char_pt_pos.x, char_pt_pos.y), glm::vec2(char_base_pos.x, char_base_pos.y), radius ); } } } void CreatureGodot::set_custom_region_color(String region_name, Color color_in) { custom_region_colors[std::string(region_name.utf8().ptr())] = color_in; } void CreatureGodot::clear_custom_region_color(String region_name) { auto c_iter = custom_region_colors.find(std::string(region_name.utf8().ptr())); if(c_iter != custom_region_colors.end()) { custom_region_colors.erase(c_iter); } } void CreatureGodot::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color","color"),&CreatureGodot::set_color); ClassDB::bind_method(D_METHOD("get_color"),&CreatureGodot::get_color); ClassDB::bind_method(D_METHOD("set_texture","texture"),&CreatureGodot::set_texture); ClassDB::bind_method(D_METHOD("get_texture"),&CreatureGodot::get_texture); ClassDB::bind_method(D_METHOD("set_anim_speed","texture"),&CreatureGodot::set_anim_speed); ClassDB::bind_method(D_METHOD("get_anim_speed"),&CreatureGodot::get_anim_speed); ClassDB::bind_method(D_METHOD("set_asset_filename","asset_filename"),&CreatureGodot::set_asset_filename); ClassDB::bind_method(D_METHOD("get_asset_filename"),&CreatureGodot::get_asset_filename); ClassDB::bind_method(D_METHOD("set_metadata_filename","metadata_filename"),&CreatureGodot::set_metadata_filename); ClassDB::bind_method(D_METHOD("get_metadata_filename"),&CreatureGodot::get_metadata_filename); ClassDB::bind_method(D_METHOD("set_offset","offset"),&CreatureGodot::set_offset); ClassDB::bind_method(D_METHOD("get_offset"),&CreatureGodot::get_offset); ClassDB::bind_method(D_METHOD("set_mirror_y","offset"),&CreatureGodot::set_mirror_y); ClassDB::bind_method(D_METHOD("get_mirror_y"),&CreatureGodot::get_mirror_y); ClassDB::bind_method(D_METHOD("set_anim_frame","offset"),&CreatureGodot::set_anim_frame); ClassDB::bind_method(D_METHOD("get_anim_frame"),&CreatureGodot::get_anim_frame); ClassDB::bind_method(D_METHOD("set_anim_name","offset"),&CreatureGodot::set_anim_name); ClassDB::bind_method(D_METHOD("get_anim_name"),&CreatureGodot::get_anim_name); ClassDB::bind_method(D_METHOD("load_json"),&CreatureGodot::load_json); ClassDB::bind_method(D_METHOD("update_animation","delta"),&CreatureGodot::update_animation); ClassDB::bind_method(D_METHOD("blend_to_animation","animation_name","blend_delta"),&CreatureGodot::blend_to_animation); ClassDB::bind_method(D_METHOD("set_should_loop","flag_in"),&CreatureGodot::set_should_loop); ClassDB::bind_method(D_METHOD("get_anim_clips"),&CreatureGodot::get_anim_clips); ClassDB::bind_method(D_METHOD("set_skinswap_name","name_in"),&CreatureGodot::set_skinswap_name); ClassDB::bind_method(D_METHOD("add_skinswap","name_in","custom_swap"),&CreatureGodot::add_skinswap); ClassDB::bind_method(D_METHOD("remove_skinswap","name_in"),&CreatureGodot::remove_skinswap); ClassDB::bind_method(D_METHOD("enable_skinswap"),&CreatureGodot::enable_skinswap); ClassDB::bind_method(D_METHOD("enable_layerorder"),&CreatureGodot::enable_layerorder); ClassDB::bind_method(D_METHOD("disable_skinswap_or_order"),&CreatureGodot::disable_skinswap_or_order); ClassDB::bind_method(D_METHOD("set_active_item_swap","region_name","swap_idx"),&CreatureGodot::set_active_item_swap); ClassDB::bind_method(D_METHOD("remove_active_item_swap","region_name"),&CreatureGodot::remove_active_item_swap); ClassDB::bind_method(D_METHOD("set_anchor_points_active","flag_in"),&CreatureGodot::set_anchor_points_active); ClassDB::bind_method(D_METHOD("set_morph_targets_active","flag_in"),&CreatureGodot::set_morph_targets_active); ClassDB::bind_method(D_METHOD("get_morph_targets_active"),&CreatureGodot::get_morph_targets_active); ClassDB::bind_method(D_METHOD("set_morph_targets_pt","pt_in","base_pt","radius"),&CreatureGodot::set_morph_targets_pt); ClassDB::bind_method(D_METHOD("make_point_cache","animation_name_in","gap_step"),&CreatureGodot::make_point_cache); ClassDB::bind_method(D_METHOD("get_bone_pos","bone_name","slide_factor"),&CreatureGodot::get_bone_pos); ClassDB::bind_method(D_METHOD("set_custom_region_color","region_name","color_in"),&CreatureGodot::set_custom_region_color); ClassDB::bind_method(D_METHOD("clear_custom_region_color","region_name"),&CreatureGodot::clear_custom_region_color); ADD_PROPERTY( PropertyInfo(Variant::STRING,"anim_name"), "set_anim_name", "get_anim_name"); ADD_PROPERTY( PropertyInfo(Variant::REAL,"anim_frame"), "set_anim_frame", "get_anim_frame"); ADD_PROPERTY( PropertyInfo(Variant::REAL,"anim_speed"), "set_anim_speed", "get_anim_speed"); ADD_PROPERTY( PropertyInfo(Variant::STRING,"asset_filename"), "set_asset_filename", "get_asset_filename"); ADD_PROPERTY( PropertyInfo(Variant::STRING,"metadata_filename"), "set_metadata_filename", "get_metadata_filename"); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"mirror_y"), "set_mirror_y", "get_mirror_y"); ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"), "set_color", "get_color"); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"), "set_offset", "get_offset"); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), "set_texture", "get_texture"); }