#include "BaseFactory.h" DRAGONBONES_NAMESPACE_BEGIN JSONDataParser BaseFactory::_jsonParser; BinaryDataParser BaseFactory::_binaryParser; TextureData* BaseFactory::_getTextureData(std::string_view textureAtlasName, std::string_view textureName) const { const auto iterator = _textureAtlasDataMap.find(textureAtlasName); if (iterator != _textureAtlasDataMap.end()) { for (const auto textureAtlasData : iterator->second) { const auto textureData = textureAtlasData->getTexture(textureName); if (textureData != nullptr) { return textureData; } } } if (autoSearch) { for (const auto& pair : _textureAtlasDataMap) { for (const auto textureAtlasData : pair.second) { if (textureAtlasData->autoSearch) { const auto textureData = textureAtlasData->getTexture(textureName); if (textureData != nullptr) { return textureData; } } } } } return nullptr; } bool BaseFactory::_fillBuildArmaturePackage(BuildArmaturePackage& dataPackage, std::string_view dragonBonesName, std::string_view armatureName, std::string_view skinName, std::string_view textureAtlasName) const { auto mapName = dragonBonesName; DragonBonesData* dragonBonesData = nullptr; ArmatureData* armatureData = nullptr; if (!mapName.empty()) { const auto iterator = _dragonBonesDataMap.find(mapName); if (iterator != _dragonBonesDataMap.end()) { dragonBonesData = iterator->second; armatureData = dragonBonesData->getArmature(armatureName); } } if (armatureData == nullptr && (mapName.empty() || autoSearch)) { for (const auto& pair : _dragonBonesDataMap) { dragonBonesData = pair.second; if (mapName.empty() || dragonBonesData->autoSearch) { armatureData = dragonBonesData->getArmature(armatureName); if (armatureData != nullptr) { mapName = pair.first; break; } } } } if (armatureData != nullptr) { dataPackage.dataName = mapName; dataPackage.textureAtlasName = textureAtlasName; dataPackage.data = dragonBonesData; dataPackage.armature = armatureData; dataPackage.skin = nullptr; if (!skinName.empty()) { dataPackage.skin = armatureData->getSkin(skinName); if (dataPackage.skin == nullptr && autoSearch) { for (const auto& pair : _dragonBonesDataMap) { const auto skinDragonBonesData = pair.second; const auto skinArmatureData = skinDragonBonesData->getArmature(skinName); if (skinArmatureData != nullptr) { dataPackage.skin = skinArmatureData->defaultSkin; break; } } } } if (dataPackage.skin == nullptr) { dataPackage.skin = armatureData->defaultSkin; } return true; } return false; } void BaseFactory::_buildBones(const BuildArmaturePackage& dataPackage, Armature* armature) const { for (const auto boneData : dataPackage.armature->sortedBones) { const auto bone = BaseObject::borrowObject(); bone->init(boneData, armature); } for (const auto& pair : dataPackage.armature->constraints) { // TODO more constraint type. const auto constraint = BaseObject::borrowObject(); constraint->init(pair.second, armature); armature->_addConstraint(constraint); } } void BaseFactory::_buildSlots(const BuildArmaturePackage& dataPackage, Armature* armature) const { const auto currentSkin = dataPackage.skin; const auto defaultSkin = dataPackage.armature->defaultSkin; if (currentSkin == nullptr || defaultSkin == nullptr) { return; } hlookup::string_map*> skinSlots; for (auto& pair : defaultSkin->displays) { auto& displays = pair.second; skinSlots[pair.first] = &displays; } if (currentSkin != defaultSkin) { for (auto& pair : currentSkin->displays) { auto& displays = pair.second; skinSlots[pair.first] = &displays; } } for (const auto slotData : dataPackage.armature->sortedSlots) { const auto displayDatas = skinSlots[slotData->name]; const auto slot = _buildSlot(dataPackage, slotData, armature); slot->setRawDisplayDatas(displayDatas); if (displayDatas != nullptr) { std::vector> displayList; for (const auto displayData : *displayDatas) { if (displayData != nullptr) { displayList.push_back(_getSlotDisplay(&dataPackage, displayData, nullptr, slot)); } else { displayList.push_back(std::make_pair(nullptr, DisplayType::Image)); } } slot->_setDisplayList(displayList); } slot->_setDisplayIndex(slotData->displayIndex, true); } } Armature* BaseFactory::_buildChildArmature(const BuildArmaturePackage* dataPackage, Slot* slot, DisplayData* displayData) const { return buildArmature(displayData->path, dataPackage != nullptr ? dataPackage->dataName : "", "", dataPackage != nullptr ? dataPackage->textureAtlasName : ""); } std::pair BaseFactory::_getSlotDisplay(const BuildArmaturePackage* dataPackage, DisplayData* displayData, DisplayData* rawDisplayData, Slot* slot) const { std::string dataName = ""; if (dataPackage != nullptr) { dataName = dataPackage->dataName; } else { for (const auto& pair : _dragonBonesDataMap) { if (pair.second == displayData->parent->parent->parent) { dataName = pair.first; } } if (dataName.empty()) { dataName = displayData->parent->parent->parent->name; } } std::pair display(nullptr, DisplayType::Image); switch (displayData->type) { case DisplayType::Image: { auto imageDisplayData = static_cast(displayData); if (imageDisplayData->texture == nullptr) { imageDisplayData->texture = _getTextureData(dataName, displayData->path); } else if (dataPackage != nullptr && !dataPackage->textureAtlasName.empty()) { imageDisplayData->texture = _getTextureData(dataPackage->textureAtlasName, displayData->path); } display.first = slot->_rawDisplay; display.second = DisplayType::Image; break; } case DisplayType::Mesh: { auto meshDisplayData = static_cast(displayData); if (meshDisplayData->texture == nullptr) { meshDisplayData->texture = _getTextureData(dataName, meshDisplayData->path); } else if (dataPackage != nullptr && !dataPackage->textureAtlasName.empty()) { meshDisplayData->texture = _getTextureData(dataPackage->textureAtlasName, meshDisplayData->path); } if (_isSupportMesh()) { display.first = slot->_meshDisplay; display.second = DisplayType::Mesh; } else { display.first = slot->_rawDisplay; display.second = DisplayType::Image; } break; } case DisplayType::Armature: { auto armatureDisplayData = static_cast(displayData); const auto childArmature = _buildChildArmature(dataPackage, slot, displayData); if (childArmature != nullptr) { childArmature->inheritAnimation = armatureDisplayData->inheritAnimation; if (!childArmature->inheritAnimation) { const auto actions = !armatureDisplayData->actions.empty() ? &(armatureDisplayData->actions) : &(childArmature->_armatureData->defaultActions); if (!actions->empty()) { for (const auto action : *actions) { childArmature->getAnimation()->fadeIn(action->name); } } else { childArmature->getAnimation()->play(); } } armatureDisplayData->armature = childArmature->_armatureData; // } display.first = childArmature; display.second = DisplayType::Armature; break; } case DisplayType::BoundingBox: break; default: break; } return display; } DragonBonesData* BaseFactory::parseDragonBonesData(const char* rawData, std::string_view name, float scale) { DRAGONBONES_ASSERT(rawData != nullptr, ""); DataParser* dataParser = nullptr; if (rawData[0] == 'D' && rawData[1] == 'B' && rawData[2] == 'D' && rawData[3] == 'T') { dataParser = &_binaryParser; } else { dataParser = _dataParser; } const auto dragonBonesData = dataParser->parseDragonBonesData(rawData, scale); while (true) { const auto textureAtlasData = _buildTextureAtlasData(nullptr, nullptr); if (dataParser->parseTextureAtlasData(nullptr, *textureAtlasData, scale)) { addTextureAtlasData(textureAtlasData, name); } else { textureAtlasData->returnToPool(); break; } } if (dragonBonesData != nullptr) { addDragonBonesData(dragonBonesData, name); } return dragonBonesData; } TextureAtlasData* BaseFactory::parseTextureAtlasData(const char* rawData, void* textureAtlas, std::string_view name, float scale) { const auto textureAtlasData = _buildTextureAtlasData(nullptr, nullptr); _dataParser->parseTextureAtlasData(rawData, *textureAtlasData, scale); _buildTextureAtlasData(textureAtlasData, textureAtlas); addTextureAtlasData(textureAtlasData, name); return textureAtlasData; } void BaseFactory::addDragonBonesData(DragonBonesData* data, std::string_view name) { const auto& mapName = !name.empty() ? name : data->name; if (_dragonBonesDataMap.find(mapName) != _dragonBonesDataMap.cend()) { if (_dragonBonesDataMap[name] == data) { return; } DRAGONBONES_ASSERT(false, "Can not add same name data: " + name); return; } _dragonBonesDataMap[mapName] = data; } void BaseFactory::removeDragonBonesData(std::string_view name, bool disposeData) { const auto iterator = _dragonBonesDataMap.find(name); if (iterator != _dragonBonesDataMap.cend()) { if (disposeData) { iterator->second->returnToPool(); } _dragonBonesDataMap.erase(iterator); } } void BaseFactory::addTextureAtlasData(TextureAtlasData* data, std::string_view name) { const auto& mapName = !name.empty() ? name : data->name; auto& textureAtlasList = _textureAtlasDataMap[mapName]; if (std::find(textureAtlasList.cbegin(), textureAtlasList.cend(), data) == textureAtlasList.cend()) { textureAtlasList.push_back(data); } } void BaseFactory::removeTextureAtlasData(std::string_view name, bool disposeData) { const auto iterator = _textureAtlasDataMap.find(name); if (iterator != _textureAtlasDataMap.end()) { if (disposeData) { for (const auto textureAtlasData : iterator->second) { textureAtlasData->returnToPool(); } } _textureAtlasDataMap.erase(iterator); } } ArmatureData* BaseFactory::getArmatureData(std::string_view name, std::string_view dragonBonesName) const { BuildArmaturePackage dataPackage; if (!_fillBuildArmaturePackage(dataPackage, dragonBonesName, name, "", "")) { return nullptr; } return dataPackage.armature; } void BaseFactory::clear(bool disposeData) { if (disposeData) { for (const auto& pair : _dragonBonesDataMap) { pair.second->returnToPool(); } for (const auto& pair : _textureAtlasDataMap) { for (const auto textureAtlasData : pair.second) { textureAtlasData->returnToPool(); } } } _dragonBonesDataMap.clear(); _textureAtlasDataMap.clear(); } Armature* BaseFactory::buildArmature(std::string_view armatureName, std::string_view dragonBonesName, std::string_view skinName, std::string_view textureAtlasName) const { BuildArmaturePackage dataPackage; if (!_fillBuildArmaturePackage(dataPackage, dragonBonesName, armatureName, skinName, textureAtlasName)) { DRAGONBONES_ASSERT( false, "No armature data: " + armatureName + ", " + (!dragonBonesName.empty() ? dragonBonesName : "")); return nullptr; } const auto armature = _buildArmature(dataPackage); _buildBones(dataPackage, armature); _buildSlots(dataPackage, armature); armature->invalidUpdate("", true); armature->advanceTime(0.0f); // Update armature pose. return armature; } void BaseFactory::replaceDisplay(Slot* slot, DisplayData* displayData, int displayIndex) const { if (displayIndex < 0) { displayIndex = slot->getDisplayIndex(); } if (displayIndex < 0) { displayIndex = 0; } slot->replaceDisplayData(displayData, displayIndex); auto displayList = slot->getDisplayList(); // Copy. if (displayList.size() <= (unsigned)displayIndex) { displayList.resize(displayIndex + 1, std::make_pair(nullptr, DisplayType::Image)); } if (displayData != nullptr) { const auto rawDisplayDatas = slot->getRawDisplayDatas(); displayList[displayIndex] = _getSlotDisplay(nullptr, displayData, rawDisplayDatas != nullptr && (unsigned)displayIndex < rawDisplayDatas->size() ? rawDisplayDatas->at(displayIndex) : nullptr, slot); } else { displayList[displayIndex] = std::make_pair(nullptr, DisplayType::Image); } slot->setDisplayList(displayList); } bool BaseFactory::replaceSlotDisplay(std::string_view dragonBonesName, std::string_view armatureName, std::string_view slotName, std::string_view displayName, Slot* slot, int displayIndex) const { DRAGONBONES_ASSERT(slot, "Arguments error."); const auto armatureData = getArmatureData(armatureName, dragonBonesName); if (!armatureData || !armatureData->defaultSkin) { return false; } const auto displayData = armatureData->defaultSkin->getDisplay(slotName, displayName); if (!displayData) { return false; } replaceDisplay(slot, displayData, displayIndex); return true; } bool BaseFactory::replaceSlotDisplayList(std::string_view dragonBonesName, std::string_view armatureName, std::string_view slotName, Slot* slot) const { DRAGONBONES_ASSERT(slot, "Arguments error."); const auto armatureData = getArmatureData(armatureName, dragonBonesName); if (!armatureData || !armatureData->defaultSkin) { return false; } const auto displays = armatureData->defaultSkin->getDisplays(slotName); if (!displays) { return false; } auto displayIndex = 0; for (const auto displayData : *displays) { replaceDisplay(slot, displayData, displayIndex++); } return true; } bool BaseFactory::replaceSkin(Armature* armature, SkinData* skin, bool isOverride, const std::vector* exclude) const { DRAGONBONES_ASSERT(armature && skin, "Arguments error."); auto success = false; const auto defaultSkin = skin->parent->defaultSkin; for (const auto slot : armature->getSlots()) { if (exclude != nullptr && std::find(exclude->cbegin(), exclude->cend(), slot->getName()) != exclude->cend()) { continue; } auto displays = skin->getDisplays(slot->getName()); if (displays == nullptr) { if (defaultSkin != nullptr && skin != defaultSkin) { displays = defaultSkin->getDisplays(slot->getName()); } if (isOverride) { std::vector> displayList; slot->setRawDisplayDatas(nullptr); slot->setDisplayList(displayList); } continue; } auto displayList = slot->getDisplayList(); // Copy. displayList.resize(displays->size(), std::make_pair(nullptr, DisplayType::Image)); for (std::size_t i = 0, l = displays->size(); i < l; ++i) { const auto displayData = displays->at(i); if (displayData != nullptr) { displayList[i] = _getSlotDisplay(nullptr, displayData, nullptr, slot); } else { displayList[i] = std::make_pair(nullptr, DisplayType::Image); } } success = true; slot->setRawDisplayDatas(displays); slot->setDisplayList(displayList); } return success; } bool BaseFactory::replaceAnimation(Armature* armature, ArmatureData* armatureData, bool isReplaceAll) const { const auto skinData = armatureData->defaultSkin; if (skinData == nullptr) { return false; } if (isReplaceAll) { armature->getAnimation()->setAnimations(armatureData->animations); } else { auto animations = armature->getAnimation()->getAnimations(); // Copy. for (const auto& pair : armatureData->animations) { animations[pair.first] = pair.second; } armature->getAnimation()->setAnimations(animations); } for (const auto slot : armature->getSlots()) { unsigned index = 0; for (const auto& pair : slot->getDisplayList()) { if (pair.second == DisplayType::Armature) { auto displayDatas = skinData->getDisplays(slot->getName()); if (displayDatas != nullptr && index < displayDatas->size()) { const auto displayData = (*displayDatas)[index]; if (displayData != nullptr && displayData->type == DisplayType::Armature) { const auto childArmatureData = getArmatureData(displayData->path, displayData->parent->parent->parent->name); if (childArmatureData != nullptr) { replaceAnimation((Armature*)pair.first, childArmatureData, isReplaceAll); } } } } index++; } } return true; } DRAGONBONES_NAMESPACE_END