增加打包图片函数

This commit is contained in:
2026-07-31 18:57:15 +08:00
parent 4af37b499b
commit 162dccbf79
17 changed files with 289 additions and 62 deletions
View File
+10 -9
View File
@@ -215,17 +215,18 @@ if (CMAKE_SYSTEM_NAME MATCHES "Android")
endif()
# 创建软链接到项目根目录
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_BINARY_DIR}/compile_commands.json
${CMAKE_SOURCE_DIR}/compile_commands.json
COMMENT "创建软链接:`compile_commands.json"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
if(NOT MSVC)
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_BINARY_DIR}/compile_commands.json
${CMAKE_SOURCE_DIR}/compile_commands.json
COMMENT "创建软链接:`compile_commands.json"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
# 安装(方便修改,可以直接使用头文件)
install(DIRECTORY "./"
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/dl/
FILES_MATCHING PATTERN "*.h")
+2 -2
View File
@@ -50,7 +50,7 @@ namespace dl::File
void GetPathFileAll(std::string_view path, std::vector<std::string>& ret,
std::string_view regex = "", bool recursion = true);
//! 过滤规则,兼容大小写(传入需要填小写)
//! 过滤规则,不兼容大小写
struct SearchRule
{
std::vector<std::string> _vecFmt; //!< 要求的格式 png
@@ -72,7 +72,7 @@ void GetPathFileAll(std::string_view path, std::vector<std::string>& ret,
* @brief 获取文件夹当前内容
* @param[in] path 路径
* @param[out] ret 返回的目录
* @param[in] regex 正则表达式,例如 .(png|jpg)$
* @param[in] regex 正则表达式,例如 .(png|jpg|PNG)$
* @param[in] folder 是否包含目录
* @param[in] file 是否包含文件
* @note 排除特定文件写法:^(?!a.png$|b.jpg$).*.(png|jpg)$
+6
View File
@@ -45,6 +45,12 @@ json ParseString(std::string_view str)
json ParseFile(std::string_view path_name, bool binary)
{
if (!File::IsExist(path_name))
{
if (g_bJsonLog)
log_warn("文件不存在:{}", path_name);
return {};
}
if (binary)
{
Buffer buf = File::GetBuffer(path_name);
+2 -2
View File
@@ -62,7 +62,7 @@ json ParseString(std::string_view str);
/**
* @brief 从json返回值,不存在则返回false,打印日志
* @brief 从json返回子元素值,不存在则返回false,打印日志
*/
template<typename T>
bool Get(const json& j, const std::string& name, T& t)
@@ -90,7 +90,7 @@ bool Get(const json& j, const std::string& name, T& t)
* @brief 从json返回值,不存在则返回false,打印日志
*/
template<typename T>
bool Get(const json& j, T& t)
bool Cast(const json& j, T& t)
{
try
{
+196 -4
View File
@@ -684,6 +684,21 @@ dl::gcAnimation Factory::CreateAnimation(std::string_view name, std::string_view
ret->SetFrameTime(node._ftime);
log_msg("创建动画:{}({}),{}", name, dir, ret->GetFrameCount());
}
else if (info._type == "packed")
{
std::string name_spr = name + "." + "__packed";
unsigned count = node._count ? node._count : (unsigned)g_factory->GetSpriteSheetNum(name_spr);
unsigned beg = node._beg + (count + node._skip) * dir;
for (unsigned i = beg; i < beg + count; ++i)
{
gcSprite spr = g_factory->CreateSprite(name_spr, i);
spr->DtQuadOffset(info._offset);
ret->PushBack(spr);
}
ret->SetFrameTime(node._ftime);
log_msg("创建动画:{}({}),{}", name, dir, ret->GetFrameCount());
}
else
assert(0);
return ret;
@@ -943,6 +958,157 @@ void Factory::ExportTexture2D()
}
bool Factory::CompressMir2Res(std::string_view path)
{
if (!File::IsExist(path))
{
log_err("目录不存在:{}", path);
return false;
}
// 收集所有图片
std::vector<std::string> all_image_path;
File::GetPathContent(path, all_image_path, ".(png|PNG)$", false);
// input
struct ImageNode
{
Image* _img;
int _index; // 旧index
};
std::list<ImageNode> all_image;
for (auto& iter : all_image_path)
{
ImageNode node;
node._img = Img::Create(iter);
if (!node._img || node._img->size() <= 1)
{
delete node._img;
log_msg("跳过图像:{}", iter);
continue;
}
node._index = String::toInt(String::GetFileStem(iter), -1);
if (node._index == -1)
{
delete node._img;
log_msg("获取图标下标失败:{}", String::GetFileStem(iter));
continue;
}
all_image.push_back(node);
}
// output
struct SrpiteOut
{
RectU _rect = {};
Point _anchor = {};
size_t _newIndex = -1;
};
// 旧index -> Out
std::unordered_map<int, SrpiteOut> map_sprite_out;
Image* img_big = Img::Create(SIZE_TEXTURE_2D_SIZE, ColorDef::NONE);
// 合图
TexturePack::Static pack;
pack.SetSize(SIZE_TEXTURE_2D_SIZE);
// 获得大小
auto fn_get_size = [](const ImageNode& node) {
return node._img->GetSize();
};
// 成功加入操作
size_t index = 0;
auto fn_call_back = [&](const ImageNode& node, const PointU& lt) {
RectU rect = createRectU(node._img->GetSize());
Img::AddRect(img_big, node._img, rect, lt);
delete node._img;
Align::OffsetRect(rect, lt);
SrpiteOut out;
out._rect = rect;
out._newIndex = index++;
map_sprite_out[node._index] = out;
};
// 直到全部添加
pack.Calc(all_image, fn_get_size, fn_call_back);
assert(all_image.empty());
Img::Save(img_big, path + "__packed.png");
delete img_big;
// 精灵信息记录
if (File::IsExist(path + "Placements/"))
{
// 收集所有图片
std::vector<std::string> all_txt_path;
File::GetPathContent(path + "Placements/", all_txt_path, ".txt", false);
for (auto& iter : all_txt_path)
{
std::string str = File::GetString(iter);
Position pos = String::toPosition2(str, '\n');
int index = String::toInt(String::GetFileStem(iter), -1);
auto iter = map_sprite_out.find(index);
if (iter == map_sprite_out.end())
{
log_warn("无效的旧下标:{}", index);
continue;
}
iter->second._anchor = toPoint(-pos);
}
}
// 保存精灵信息
{
json j;
json j_arr = {};
for (auto& iter : map_sprite_out)
{
SrpiteOut& spr = iter.second;
{
json j_spr;
j_spr["rect"] = spr._rect;
j_spr["anchor"] = spr._anchor;
j_arr[spr._newIndex] = j_spr;
}
}
j["packed"] = j_arr;
Json::SaveFile(j, path + "__packed.json");
}
// 更新动画信息
{
json j = Json::ParseFile(path + "__animation_old.json");
if (!j.is_null())
{
AnimationInfo info = j;
info._skip = 0;
info._type = "packed";
info._format = "";
for (auto& iter : info._allAni)
{
AnimationInfo::Node& node = iter.second;
node._skip = 0;
auto iter1 = map_sprite_out.find(node._beg);
if (iter1 == map_sprite_out.end())
{
log_warn("无效的beg值:{}", node._beg);
continue;
}
node._beg = (unsigned)iter1->second._newIndex;
}
j = info;
Json::SaveFile(j, path + "__animation.json");
}
}
return true;
}
void Factory::_render_sprite(Sprite* spr)
{
const SpriteID& id = g_factory->GetImp()->_idTrans;
@@ -1585,17 +1751,43 @@ void Factory::_load_sprite_sub(std::string_view path, std::string_view name, std
// 不同meta处理
bool read_meta = false;
if (!read_meta)
{
std::string file_name = String::GetFileStem(path_name);
if (file_name == "__packed")
{
std::string meta_name = path_name;
String::ReplaceExtension(meta_name, "json");
Json::DisableLog l;
json j = Json::ParseFile(meta_name);
if (!j.is_null())
{
read_meta = true;
json j_arr = {};
Json::Get(j, "packed", j_arr);
for (auto& iter : j_arr)
{
SheetNodeInfo node;
Point anchor;
Json::Get(iter, "anchor", anchor);
Json::Get(iter, "rect", node._rect);
node._anchor = dl::to_string(anchor);
vec_node.push_back(node);
}
}
}
}
if(!read_meta)
{
// json meta
std::string meta_name = path_name;
String::ReplaceExtension(meta_name, "json");
std::ifstream ifs = File::Get(meta_name);
if (ifs.is_open())
Json::DisableLog l;
json j = Json::ParseFile(meta_name);
if (!j.is_null())
{
read_meta = true;
json j = json::parse(ifs);
Json::DisableLog l;
Json::Get(j, "anchor", sheet_info._anchor);// 公共锚点
Json::Get(j, "color", sheet_info._color);// 公共颜色
+4
View File
@@ -462,6 +462,10 @@ public:
* @brief 导出所有2d纹理
*/
void ExportTexture2D();
//! 打包传奇补丁包(TODO 有问题不要使用)
bool CompressMir2Res(std::string_view path);
FactoryImp* GetImp() { return _imp; }
void _render_sprite(Sprite* spr);
+1
View File
@@ -347,6 +347,7 @@ namespace dl
luabridge::overload<std::string_view, size_t>(&Factory::CreateSprite),
luabridge::overload<const SpriteID&>(&Factory::CreateSprite))
.addFunction("SetPath", &Factory::SetPath)
.addFunction("CompressMir2Res", &Factory::CompressMir2Res)
.endClass();
auto result = luabridge::push(L, g_factory);
+11
View File
@@ -0,0 +1,11 @@
/log
/*.ilk
/*.pdb
/*.exe
/memory_leak_report.txt
/vld.ini
/temp
/binary
/dl
/Microsoft.DTfW.DHL.manifest
/out
Binary file not shown.
@@ -0,0 +1,31 @@
-- 你的资源根目录
local rootPath = "D:/work/base_actor/image/ani/"
-- 所有需要压缩的文件夹列表
local folders = {
"刀盾兵重甲",
"双刀兵",
"大刀兵中甲",
"大锤兵",
"女琴师",
"弓箭手",
"弓箭手中甲",
"弓箭手轻甲",
"弓船",
"搬运工",
"标枪",
"树木倒塌",
"武将",
"祭司",
"蛮族侦察兵",
"蛮族步兵",
"酒者",
"黑骑士"
}
-- 遍历并压缩
for _, folder in ipairs(folders) do
local fullPath = rootPath .. folder
g_factory:CompressMir2Res(fullPath)
print("已压缩: " .. folder)
end
+11
View File
@@ -0,0 +1,11 @@
/log
/*.ilk
/*.pdb
/*.exe
/memory_leak_report.txt
/vld.ini
/temp
/binary
/dl
/Microsoft.DTfW.DHL.manifest
/out
Binary file not shown.
+13 -43
View File
@@ -95,53 +95,21 @@ set(DL_PATH_VLD ${CMAKE_SOURCE_DIR}/third/vld/bin/${ARCH})
# CrashRpt资源文件夹
set(DL_PATH_CR ${CMAKE_SOURCE_DIR}/third/CrashRpt/${ARCH})
## 复制资源
#add_custom_command(TARGET ${PROJECT_NAME}
# PRE_BUILD
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
# COMMENT "清理资源完成")
#add_custom_command(TARGET ${PROJECT_NAME}
# POST_BUILD
# COMMAND ${CMAKE_COMMAND} -E copy_directory ${PATH_RES} ${PATH_OUT}
# COMMENT "复制资源完成")
# 资源软链接
# if (CMAKE_SYSTEM_NAME MATCHES "Windows")
# add_custom_command(TARGET ${PROJECT_NAME}
# PRE_BUILD
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
# COMMAND cmd /c ${CMAKE_SOURCE_DIR}/project/copy_res.bat ${PATH_RES} ${PATH_OUT}
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${PATH_OUT}/.gitignore)
# elseif(CMAKE_SYSTEM_NAME MATCHES "Android")
# add_custom_command(TARGET ${PROJECT_NAME}
# PRE_BUILD
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
# #COMMAND cmd /c ${CMAKE_SOURCE_DIR}/project/copy_res.bat ${PATH_RES} ${PATH_OUT}
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${PATH_OUT}/.gitignore)
# elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# add_custom_command(TARGET ${PROJECT_NAME}
# PRE_BUILD
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
# COMMAND bash ${CMAKE_SOURCE_DIR}/project/copy_res.sh ${PATH_RES} ${PATH_OUT}
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${PATH_OUT}/.gitignore)
# elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin")
# add_custom_command(TARGET ${PROJECT_NAME}
# PRE_BUILD
# COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
# COMMAND bash ${CMAKE_SOURCE_DIR}/project/copy_res.sh ${PATH_RES} ${PATH_OUT}
# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${PATH_OUT}/.gitignore)
# endif()
# 创建软链接、复制必要资源
add_custom_command(
TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${PATH_OUT}
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PATH_RES} ${PATH_OUT}
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${PATH_OUT}/.gitignore
COMMENT "创建资源软链接,并复制资源"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# 复制必要资源
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.gitignore")
add_custom_command(
TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/project/template.gitignore ${CMAKE_CURRENT_SOURCE_DIR}/.gitignore
COMMENT "复制.gitignore文件模板"
)
endif()
# 复制dl必要资源(重新生成代码的时候才会触发)
if (USE_RENDER)
@@ -156,9 +124,11 @@ if(MSVC)
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${DL_PATH_VLD} ${PATH_OUT})
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/third/vld/vld.ini ${PATH_OUT})
if(NOT EXISTS "${PATH_OUT}/vld.ini")
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/third/vld/vld.ini ${PATH_OUT})
endif()
endif()
# 复制CrashRpt
if (CMAKE_BUILD_TYPE MATCHES "Release")