// // RedBakeSpineIO.cpp // cocos2d_libs // // Created by ZhengSong on 2023/2/16. // #include "RedBakeSpineIO.h" #include namespace spine { const static std::string REDSPINEBAKE_EXTENSION = ".rb"; RedBakeSpineIO::RedBakeSpineIO() { } RedBakeSpineIO::~RedBakeSpineIO() { } static RedBakeSpineIO* _instance = nullptr; RedBakeSpineIO* RedBakeSpineIO::getInstance() { if(_instance == nullptr) { _instance = new RedBakeSpineIO(); } return _instance; } void RedBakeSpineIO::write(const std::string& filePath, const std::unordered_map& datas) { if(datas.empty()) { CCASSERT(false, "没有数据"); return; } std::ofstream outFile(filePath, std::ios::out | std::ios::binary); ::RedSpineBakeProto::BakeDataIndex dataIndex_pb; google::protobuf::Map* bakeDataIdx_pb = dataIndex_pb.mutable_dataindex(); uint64_t currentOffset = 0; for(auto iter = datas.begin(); iter != datas.end(); iter++) { const std::string& animName = iter->first; RedAnimationBakeModel* bakeModel = iter->second; if(bakeModel == nullptr) { CCASSERT(false, "spine还没有烘培完"); return; } ::RedSpineBakeProto::RedAnimationBakeModel bakeModel_pb; _writeAnimationBakeModel(bakeModel, bakeModel_pb); std::string serializedModel; bakeModel_pb.SerializeToString(&serializedModel); // 计算每个数据的长度,并保存位置信息 ::RedSpineBakeProto::DataInfo dataInfo_pb; dataInfo_pb.set_offset(currentOffset); dataInfo_pb.set_length(serializedModel.size()); (*bakeDataIdx_pb)[animName] = dataInfo_pb; //把烘培的数据写入到指定路径 outFile.write(serializedModel.c_str(), dataInfo_pb.length()); currentOffset += dataInfo_pb.length(); } //烘培数据的索引文件写入到指定路径 string outIndex; dataIndex_pb.SerializeToString(&outIndex); outFile.write(outIndex.c_str(), outIndex.size()); uint32_t idxOffset = currentOffset; uint32_t outIndexSize = outIndex.size(); // 将两个32位整数写入文件 outFile.write(reinterpret_cast(&idxOffset), sizeof(uint32_t)); outFile.write(reinterpret_cast(&outIndexSize), sizeof(uint32_t)); // 检查是否写入成功 if (!outFile) { ///写入失败 } outFile.close(); } void RedBakeSpineIO::_writeAnimationBakeModel(RedAnimationBakeModel* model, ::RedSpineBakeProto::RedAnimationBakeModel& model_pb) { //fileName const std::string& fileName = model->getFileName(); model_pb.set_filename(fileName); //animateName const std::string& animateName = model->getAimationName(); model_pb.set_animatename(animateName); //boneAttach ::google::protobuf::Map< std::string, ::RedSpineBakeProto::Vec2Array >* boneAttachs_pb = model_pb.mutable_boneattachs(); const std::map>& boneAttachs = model->getBoneAttachs(); for(auto iter = boneAttachs.begin(); iter != boneAttachs.end(); iter++) { const std::string& boneAttachName = iter->first; const std::vector& posArray = iter->second; ::RedSpineBakeProto::Vec2Array posArray_pb; for(int i = 0; i < posArray.size(); ++i) { const Point& pos = posArray.at(i); ::RedSpineBakeProto::Vec2* pos_pb = posArray_pb.add_arr(); pos_pb->set_x(pos.x); pos_pb->set_y(pos.y); } (*boneAttachs_pb)[boneAttachName] = posArray_pb; } //slotArr ::google::protobuf::Map<::google::protobuf::int32, ::RedSpineBakeProto::RedSlotBakeModel >* slotArr_pb = model_pb.mutable_slotarr(); const std::map& slotArr = model->getSlotArr(); RedSlotBakeModel* slotModel = nullptr; for(auto iter : slotArr) { int slotIdx = iter.first; slotModel = iter.second; ::RedSpineBakeProto::RedSlotBakeModel slotModel_pb; _writeSlotBakeModel(slotModel, slotModel_pb); (*slotArr_pb)[slotIdx] = slotModel_pb; } //drawOrderArr ::RedSpineBakeProto::DrawOrderArray* drawOrderArray_pb = model_pb.mutable_draworderarr(); const std::vector>& drawOrderArray = model->getDrawOrderArr(); for(int i = 0; i < drawOrderArray.size(); ++i) { ::RedSpineBakeProto::DrawOrderArray_DrawOrders* container = drawOrderArray_pb->add_container(); const std::vector& arr = drawOrderArray.at(i); for(int j = 0; j < arr.size(); ++j) { int order = arr.at(j); container->add_draworder(order); } } //drawOrderArrIndex const std::vector& drawOrderArrIndex = model->getDrawOrderArrIndex(); for(int i = 0; i < drawOrderArrIndex.size(); ++i) { const DrawOrderMD& drawOrderMD = drawOrderArrIndex.at(i); ::RedSpineBakeProto::DrawOrderMD* drawOrderMD_pb = model_pb.add_draworderarrindex(); drawOrderMD_pb->set_frame(drawOrderMD.frame); drawOrderMD_pb->set_arrindex(drawOrderMD.arrIndex); } //eventArr const std::vector& eventArr = model->getEventArr(); for(int i = 0; i < eventArr.size(); ++i){ const EventMD& eventMD = eventArr.at(i); ::RedSpineBakeProto::EventMD* eventMD_pb = model_pb.add_eventarr(); eventMD_pb->set_frame(eventMD.frame); for(int j = 0; j < eventMD.eventNames.size(); ++j){ std::string eventName = eventMD.eventNames.at(j); eventMD_pb->add_eventname(eventName); } } //totalBakeFrame int totalBakeFrame = model->getTotalBakeFrame(); model_pb.set_totalbakeframe(totalBakeFrame); //边界 int maxXPos = model->getMaxXPos(); int maxYPos = model->getMaxYPos(); int minXPos = model->getMinXPos(); int minYPos = model->getMinYPos(); model_pb.set_maxxpos(maxXPos); model_pb.set_maxypos(maxYPos); model_pb.set_minxpos(minXPos); model_pb.set_minypos(minYPos); const Vec2& leftBottomPos = model->getLeftBottom(); const Vec2& rightTopPos = model->getRightTopPos(); const Vec2& leftBottomSubSizePos = model->getLeftBottomSubSizePos(); const Vec2& rightTopSubSizePos = model->getRightTopSubSizePos(); model_pb.mutable_leftbottompos()->set_x(leftBottomPos.x); model_pb.mutable_leftbottompos()->set_y(leftBottomPos.y); model_pb.mutable_righttoppos()->set_x(rightTopPos.x); model_pb.mutable_righttoppos()->set_y(rightTopPos.y); model_pb.mutable_leftbottomsubsizepos()->set_x(leftBottomSubSizePos.x); model_pb.mutable_leftbottomsubsizepos()->set_y(leftBottomSubSizePos.y); model_pb.mutable_righttopsubsizepos()->set_x(rightTopSubSizePos.x); model_pb.mutable_righttopsubsizepos()->set_y(rightTopSubSizePos.y); //当前帧率 int currentFrameRate = model->getCurrentFrameRate(); model_pb.set_currentframerate(currentFrameRate); //lastDrawOverTime float lastDrawOverTime = model->getLastDrawOverTime(); model_pb.set_lastdrawovertime(lastDrawOverTime); } void RedBakeSpineIO::_writeSlotBakeModel(RedSlotBakeModel* model, ::RedSpineBakeProto::RedSlotBakeModel& model_pb) { //slotName model_pb.set_slotname(model->getSlotName()); //slotIndex int slotIndex = model->getSlotIndex(); model_pb.set_slotindex(slotIndex); //posarray const std::vector>& posArray = model->getPosArray(); ::RedSpineBakeProto::PosArray* bakePosArray = model_pb.mutable_posarray(); for(int i = 0; i < posArray.size(); i++) { const vector& arr = posArray.at(i); ::RedSpineBakeProto::PosArray_BakePosArray* container = bakePosArray->add_container(); for(int j = 0; j < arr.size(); j++) { const BAKE_POS_INT& bpi = arr.at(j); ::RedSpineBakeProto::Vec2* bakePos = container->add_pos(); bakePos->set_x(bpi.xPos); bakePos->set_y(bpi.yPos); } } //blendFuncArray const std::vector& blendFuncArray = model->getBlendFuncArray(); for(int i = 0; i < blendFuncArray.size(); i++) { const BlendFunc& blend = blendFuncArray.at(i); ::RedSpineBakeProto::BlendFunc* bakeBlend = model_pb.add_blendfuncarray(); bakeBlend->set_src(blend.src); bakeBlend->set_dst(blend.dst); } //colorArray const std::vector& colorArray = model->getColorArray(); for(int i = 0; i < colorArray.size(); i++) { const Color3B& color = colorArray.at(i); ::RedSpineBakeProto::Color3B* bakeColor = model_pb.add_colorarray(); bakeColor->set_r(color.r); bakeColor->set_g(color.g); bakeColor->set_b(color.b); } //alphaArray const std::vector& alphaArray = model->getAlphaArray(); for(int i = 0; i < alphaArray.size(); i++) { GLubyte alpha = alphaArray.at(i); model_pb.add_alphaarray(alpha); } //uvArray const std::vector>& uvArray = model->getUvArray(); ::RedSpineBakeProto::UVArray* bakeUvArray = model_pb.mutable_uvarray(); for(int i = 0; i < uvArray.size(); i++) { ::RedSpineBakeProto::UVArray_TexArray* texArray= bakeUvArray->add_container(); const std::vector& arr = uvArray.at(i); for(int j = 0; j < arr.size(); j++) { const Tex2F& tex = arr.at(j); ::RedSpineBakeProto::Tex2F* bakeTex = texArray->add_texes(); bakeTex->set_u(tex.u); bakeTex->set_v(tex.v); } } //indicesArray const std::vector>& indicesArray = model->getIndicesArray(); ::RedSpineBakeProto::IndicesArray*bakeIndicesArray = model_pb.mutable_indicesarray(); for(int i = 0; i < indicesArray.size(); i++) { const std::vector& array = indicesArray.at(i); ::RedSpineBakeProto::IndicesArray_Indices* bakeIndices = bakeIndicesArray->add_container(); for(int j = 0; j < array.size(); j++) { unsigned short indice = array.at(j); bakeIndices->add_indices(indice); } } //frameChangeArr const std::vector& frameChangeArr = model->getFrameChangeArr(); for(int i = 0; i < frameChangeArr.size(); i++) { GLubyte frameChangeValue = frameChangeArr.at(i); model_pb.add_framechangearr(frameChangeValue); } //pos int maxXPos = model->getMaxXPos(); int maxYPos = model->getMaxYPos(); int minXPos = model->getMinXPos(); int minYPos = model->getMinYPos(); model_pb.set_maxxpos(maxXPos); model_pb.set_maxypos(maxYPos); model_pb.set_minxpos(minXPos); model_pb.set_minypos(minYPos); //textureArray const std::vector& textureArray = model->getTextureArray(); for (int i = 0; i < textureArray.size(); i++) { Texture2D* tex = textureArray.at(i); std::string fullPath = tex->getPath(); size_t lastPos = fullPath.find_last_of('/'); std::string fileName = fullPath.substr(lastPos + 1, fullPath.size() - lastPos); model_pb.add_texfilenamearr(fileName); } } void RedBakeSpineIO::readAnimationBakeModel(const ::RedSpineBakeProto::RedAnimationBakeModel& model_pb, RedAnimationBakeModel* model, const std::string& filePath) { _readAnimationBakeModel(model_pb, model, filePath); } void RedBakeSpineIO::_readAnimationBakeModel(const ::RedSpineBakeProto::RedAnimationBakeModel& model_pb, RedAnimationBakeModel* model, const std::string& filePath) { //fileName const std::string& fileName = model_pb.filename(); model->setFileName(fileName); //animateName const std::string& animateName = model_pb.animatename(); model->setAimationName(animateName); //boneAttach std::map> boneAttachs; const ::google::protobuf::Map& boneattachs_pb = model_pb.boneattachs(); for(auto iter = boneattachs_pb.begin(); iter != boneattachs_pb.end(); ++ iter) { const string& boneattachName = iter->first; const ::RedSpineBakeProto::Vec2Array& posArray_pb = iter->second; std::vector posArray; for (int i = 0; i < posArray_pb.arr_size(); ++i) { const ::RedSpineBakeProto::Vec2& pos_pb = posArray_pb.arr(i); Point pos; pos.x = pos_pb.x(); pos.y = pos_pb.y(); posArray.push_back(pos); } boneAttachs[boneattachName] = posArray; } model->setBoneAttachs(boneAttachs); //totalBakeFrame int totalBakeFrame = model_pb.totalbakeframe(); model->setTotalBakeFrame(totalBakeFrame); //slotArr std::map slotArr; const ::google::protobuf::Map<::google::protobuf::int32, ::RedSpineBakeProto::RedSlotBakeModel>& slotArr_pb = model_pb.slotarr(); for(auto iter = slotArr_pb.begin(); iter != slotArr_pb.end(); ++iter) { int slotIdx = iter->first; const ::RedSpineBakeProto::RedSlotBakeModel& slotModel_pb = iter->second; RedSlotBakeModel* slotModel = new RedSlotBakeModel(slotModel_pb.slotname(), slotModel_pb.slotindex()); _readSlotBakeModel(slotModel_pb, slotModel, filePath, nullptr); slotArr[slotIdx] = slotModel; } model->setSlotArr(slotArr); //drawOrderArr std::vector> drawOrderArr; const ::RedSpineBakeProto::DrawOrderArray& drawOrderArray_pb = model_pb.draworderarr(); for(int i = 0; i < drawOrderArray_pb.container_size(); ++i) { const ::RedSpineBakeProto::DrawOrderArray_DrawOrders& drawOrders_pb = drawOrderArray_pb.container(i); int draworderSize = drawOrders_pb.draworder_size(); std::vector drawOrders; drawOrders.reserve(draworderSize); for(int j = 0; j < draworderSize; ++j) { int order = drawOrders_pb.draworder(j); drawOrders.push_back(order); } drawOrderArr.push_back(drawOrders); } model->setDrawOrderArr(drawOrderArr); //drawOrderArrIndex int drawOrderArrIndexSize = model_pb.draworderarrindex().size(); std::vector drawOrderArrIndex; drawOrderArrIndex.reserve(drawOrderArrIndexSize); for(int i = 0; i < drawOrderArrIndexSize; i++) { const ::RedSpineBakeProto::DrawOrderMD& drawOrderMD_pb = model_pb.draworderarrindex(i); DrawOrderMD drawOrderMD; drawOrderMD.frame = drawOrderMD_pb.frame(); drawOrderMD.arrIndex = drawOrderMD_pb.arrindex(); drawOrderArrIndex.push_back(drawOrderMD); } model->setDrawOrderArrIndex(drawOrderArrIndex); //eventArr int eventArrSize = model_pb.eventarr().size(); std::vector eventArr; eventArr.reserve(eventArrSize); for(int i = 0; i < eventArrSize; i++) { const ::RedSpineBakeProto::EventMD& eventMD_pb = model_pb.eventarr(i); EventMD eventMD; eventMD.frame = eventMD_pb.frame(); int eventNamesSize = eventMD_pb.eventname_size(); eventMD.eventNames.reserve(eventNamesSize); for(int j = 0; j < eventNamesSize; ++j) { std::string eventName = eventMD_pb.eventname(j); eventMD.eventNames.push_back(eventName); } eventArr.push_back(eventMD); } model->setEventArr(eventArr); //帧率 int rate = model_pb.currentframerate(); model->setCurrentFrameRate(rate); //lastDrawOverTime float lastDrawOverTime = model_pb.lastdrawovertime(); model->setLastDrawOverTime(lastDrawOverTime); } void RedBakeSpineIO::_readSlotBakeModel(const ::RedSpineBakeProto::RedSlotBakeModel& model_pb, RedSlotBakeModel* model, const std::string& filePath, const std::function& finishCb) { std::string slotName = model_pb.slotname(); model->setSlotName(slotName); int slotIndex = model_pb.slotindex(); model->setSlotIndex(slotIndex); //posarray { const ::RedSpineBakeProto::PosArray& bakePosArray = model_pb.posarray(); int posArraySize = bakePosArray.container_size(); for(int i = 0; i < posArraySize; i++) { const ::RedSpineBakeProto::PosArray_BakePosArray& container = bakePosArray.container(i); int containerSize = container.pos_size(); std::vector posArray; posArray.reserve(containerSize);//预设内存 for (int j = 0; j < containerSize; j++) { const ::RedSpineBakeProto::Vec2& bakePos = container.pos(j); BAKE_POS_INT pos; pos.xPos = bakePos.x(); pos.yPos = bakePos.y(); posArray.push_back(pos); } model->addPosArray(posArray); } } //blendFuncArray { int blendFuncArraySize = model_pb.blendfuncarray_size(); for(int i = 0; i < blendFuncArraySize; i++) { const ::RedSpineBakeProto::BlendFunc& bakeBlend = model_pb.blendfuncarray(i); BlendFunc blend; blend.src = bakeBlend.src(); blend.dst = bakeBlend.dst(); model->addBlendFuncToArray(blend); } } //colorArray { int colorArraySize = model_pb.colorarray_size(); for(int i = 0; i < colorArraySize; i++) { const ::RedSpineBakeProto::Color3B& bakeColor = model_pb.colorarray(i); Color3B color; color.r = bakeColor.r(); color.g = bakeColor.g(); color.b = bakeColor.b(); model->addColorToArray(color); } } //alphaArray { int alphaArraySize = model_pb.alphaarray_size(); for(int i = 0; i < alphaArraySize; i++) { ::google::protobuf::uint32 bakeAlpha = model_pb.alphaarray(i); model->addAlphaToArray(bakeAlpha); } } //uvArray { const ::RedSpineBakeProto::UVArray& bakeUVArray = model_pb.uvarray(); int containerSize = bakeUVArray.container_size(); for(int i = 0; i < containerSize; i++) { const ::RedSpineBakeProto::UVArray_TexArray& container = bakeUVArray.container(i); int texesSize = container.texes_size(); std::vector uvArray; uvArray.reserve(texesSize);//预设内存 for(int j = 0; j < texesSize; j++) { const ::RedSpineBakeProto::Tex2F& bakeTex = container.texes(j); Tex2F tex; tex.u = bakeTex.u(); tex.v = bakeTex.v(); uvArray.push_back(tex); } model->addUvArray(uvArray); } } //indicesArray { const ::RedSpineBakeProto::IndicesArray& bakeIndices = model_pb.indicesarray(); int containerSize = bakeIndices.container_size(); for(int i = 0; i < containerSize; i++) { const ::RedSpineBakeProto::IndicesArray_Indices& container = bakeIndices.container(i); int indicesSize = container.indices_size(); std::vector indicesArray; indicesArray.reserve(indicesSize);//预设内存 for(int j = 0; j < indicesSize; j++) { ::google::protobuf::uint32 indices = container.indices(j); indicesArray.push_back(indices); } model->addIndicesArray(indicesArray); } } //frameChangeArr { int frameChangeArrSize = model_pb.framechangearr_size(); for(int i = 0; i < frameChangeArrSize; i++) { ::google::protobuf::uint32 frame = model_pb.framechangearr(i); model->addFrameChangeToArr(frame); } } //bounds { int maxXPos = model_pb.maxxpos(); int maxYPos = model_pb.maxypos(); int minXPos = model_pb.minxpos(); int minYPos = model_pb.minypos(); model->setMaxXPos(maxXPos); model->setMaxYPos(maxYPos); model->setMinXPos(minXPos); model->setMinYPos(minYPos); } //textureArray { ///会在外部指定使用的图片!!! // auto loadTexture = [=](){ // int textureArraySize = model_pb.texfilenamearr_size(); // for(int i = 0; i < textureArraySize; i++) { // const std::string& fileName = model_pb.texfilenamearr(i); // Texture2D* tex2d = Director::getInstance()->getTextureCache()->addImage(filePath+fileName); // if(tex2d == nullptr) { // CCASSERT(false, "文件路径不对"); // } // model->addTextureToArray(tex2d); // } // if(finishCb) { // finishCb(); // } // }; // loadTexture(); if(finishCb) { finishCb(); } } model->initBakeFrameInfos(); } } //namespace