void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const { // transform into joint space glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE; // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; const Skeleton& skeleton = _avatar->getSkeleton(); for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { AvatarJointID parent = skeleton.joint[i].parent; float distance = glm::length(computeVectorFromPointToSegment(jointVertex, skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, skeleton.joint[i].absoluteBindPosePosition)); if (!MODES[_mode].includeBonesOutsideBindRadius && distance > skeleton.joint[i].bindRadius) { continue; } for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) { nearest[k] = nearest[k - 1]; } nearest[j] = IndexDistance(i, distance); break; } } } // compute the weights based on inverse distance float totalWeight = 0.0f; for (int i = 0; i < MODES[_mode].maxBonesPerBind; i++) { indices[i] = nearest[i].index; if (nearest[i].distance != FLT_MAX) { weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); totalWeight += weights[i]; } else { weights[i] = 0.0f; } } // if it's not attached to anything, consider it attached to the hip if (totalWeight == 0.0f) { weights[0] = 1.0f; return; } // ortherwise, normalize the weights for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { weights[i] /= totalWeight; } }
void AIHeroesAddedTask(Heroes & hero) { AIHero & ai_hero = AIHeroes::Get(hero); AIKingdom & ai_kingdom = AIKingdoms::Get(hero.GetColor()); Queue & task = ai_hero.sheduled_visit; IndexObjectMap & ai_objects = ai_kingdom.scans; // load minimal distance tasks std::vector<IndexDistance> objs; objs.reserve(ai_objects.size()); for(std::map<s32, int>::const_iterator it = ai_objects.begin(); it != ai_objects.end(); ++it) { const Maps::Tiles & tile = world.GetTiles((*it).first); if(hero.isShipMaster()) { if(MP2::OBJ_COAST != tile.GetObject() && ! tile.isWater()) continue; // check previous positions if(MP2::OBJ_COAST == (*it).second && hero.isVisited(world.GetTiles((*it).first))) continue; } else { if(tile.isWater() && MP2::OBJ_BOAT != tile.GetObject()) continue; } objs.push_back(IndexDistance((*it).first, Maps::GetApproximateDistance(hero.GetIndex(), (*it).first))); } DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", task prepare: " << objs.size()); std::sort(objs.begin(), objs.end(), IndexDistance::Shortest); for(std::vector<IndexDistance>::const_iterator it = objs.begin(); it != objs.end(); ++it) { if(task.size() >= HERO_MAX_SHEDULED_TASK) break; const bool validobj = AI::HeroesValidObject(hero, (*it).first); if(validobj && hero.GetPath().Calculate((*it).first)) { DEBUG(DBG_AI, DBG_INFO, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << ", added tasks: " << MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first << ", distance: " << (*it).second); task.push_back((*it).first); ai_objects.erase((*it).first); } else { DEBUG(DBG_AI, DBG_TRACE, Color::String(hero.GetColor()) << ", hero: " << hero.GetName() << (!validobj ? ", invalid: " : ", impossible: ") << MP2::StringObject(ai_objects[(*it).first]) << ", index: " << (*it).first << ", distance: " << (*it).second); } } if(task.empty()) AIHeroesAddedRescueTask(hero); }