2243 lines
56 KiB
C++
2243 lines
56 KiB
C++
#include "dl_factory.h"
|
||
|
||
#ifndef DL_DISABLE_RENDER
|
||
#include "dl_factory_imp.h"
|
||
#include "io/dl_file.h"
|
||
#include "system/dl_time.h"
|
||
#include "vk/dl_vk.h"
|
||
#include "dl_free_type.h"
|
||
#include "io/dl_json.h"
|
||
#include "system/dl_audio.h"
|
||
#include "render/dl_render_def.h"
|
||
#include "io/dl_input.h"
|
||
#include "system/dl_engine.h"
|
||
#include "system/dl_system.h"
|
||
#include "io/dl_thread_task.h"
|
||
|
||
//#ifdef NDEBUG
|
||
#define DL_2D_TEXTURE_USE_KTX
|
||
//#endif
|
||
|
||
namespace dl
|
||
{
|
||
|
||
Factory* g_factory;
|
||
|
||
void Factory::LoadModel(std::string_view path_name, std::string_view name)
|
||
{
|
||
//-------------------------资源名字防止重复-----------------------
|
||
std::string path_name_real;
|
||
std::string res_name;
|
||
if (!String::GetPathAndRes(_strPathModel, path_name, path_name_real, res_name, name))
|
||
return;
|
||
|
||
auto iter = _imp->_mapName2Model.find(res_name);
|
||
if (iter != _imp->_mapName2Model.end())
|
||
{
|
||
log_warn("资源名字已经存在:{},id:{}", res_name, iter->second);
|
||
return;
|
||
}
|
||
//-------------------------判断从文件还是从缓存读取-----------------------
|
||
bool b_read_cache;// 是否从缓存读取
|
||
bool b_exist = File::IsExist(path_name_real);// 文件是否存在
|
||
ModelCache::Node* cache_node = _imp->_modelCache.Get(path_name_real);// 缓存是否存在
|
||
if(!b_exist && !cache_node)
|
||
{// 不存在
|
||
log_err("加载模型失败(文件不存在,并且没有缓存文件):{}", path_name_real);
|
||
return;
|
||
}
|
||
if (!b_exist && cache_node)
|
||
{// 不存在,缓冲文件存在
|
||
b_read_cache = true;
|
||
}
|
||
else if (b_exist && cache_node)
|
||
{// 都存在
|
||
// 检查是否需要更新
|
||
time_t t = File::GetLastWriteTime(path_name_real);
|
||
if (cache_node->_t == t)
|
||
b_read_cache = true;
|
||
else
|
||
{
|
||
uint32_t crc32 = File::GetCrc32(path_name_real);
|
||
if (crc32 == cache_node->_crc32)
|
||
{
|
||
b_read_cache = true;
|
||
cache_node->_t = t;
|
||
}
|
||
else
|
||
{
|
||
cache_node->_crc32 = crc32;
|
||
cache_node->_t = t;
|
||
b_read_cache = false;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{// 只文件存在
|
||
b_read_cache = false;
|
||
cache_node = _imp->_modelCache.Add(path_name_real);
|
||
if (!cache_node)
|
||
{
|
||
log_err("添加缓存文件失败:{}", path_name_real);
|
||
return;
|
||
}
|
||
cache_node->_crc32 = File::GetCrc32(path_name_real);
|
||
cache_node->_t = File::GetLastWriteTime(path_name_real);
|
||
}
|
||
|
||
FloatTime t0 = g_time->GetCurrent();
|
||
std::vector<Model*> mul_model;
|
||
if (b_read_cache)
|
||
{
|
||
// 加载所有子模型
|
||
for (std::string& str : cache_node->_allSub)
|
||
{
|
||
// 加载model_object
|
||
ModelObject* model_object = new ModelObject;
|
||
model_object->Load(str);
|
||
// model_object -> model
|
||
Model* model = g_vk->CreateModel(model_object);
|
||
delete model_object;
|
||
// 记录model
|
||
mul_model.push_back(model);
|
||
}
|
||
if (mul_model.empty())
|
||
{
|
||
log_err("模型加载失败(从缓存,没有sub):{}", res_name);
|
||
return;
|
||
}
|
||
size_t id = g_vk->GetMulModelSize();
|
||
_imp->_mapName2Model[res_name] = id;
|
||
g_vk->AddMulModel(mul_model);
|
||
}
|
||
else
|
||
{// 从文件加载
|
||
std::vector<ModelObject*> mul_model_object = ModelObject::Create(path_name_real, res_name);
|
||
if (mul_model_object.empty())
|
||
return;
|
||
|
||
// 转换所有子模型
|
||
for (ModelObject* model_object : mul_model_object)
|
||
{
|
||
// model_object -> model
|
||
Model* model = g_vk->CreateModel(model_object);
|
||
// 记录model
|
||
mul_model.push_back(model);
|
||
}
|
||
if (mul_model.empty())
|
||
{
|
||
log_err("模型加载失败(从文件,没有sub):{}", path_name_real);
|
||
return;
|
||
}
|
||
size_t id = g_vk->GetMulModelSize();
|
||
_imp->_mapName2Model[res_name] = id;
|
||
g_vk->AddMulModel(mul_model);
|
||
|
||
// 更新子模型
|
||
size_t i = 0;
|
||
for (ModelObject* model_object : mul_model_object)
|
||
{// 资源名+id
|
||
// 文件名
|
||
std::string file_name = fmt::format("{}#{}", res_name, i);
|
||
// model文件
|
||
const std::string PATH_CACHE = GetPathBinary3D();
|
||
std::string path_child = PATH_CACHE + file_name + ".model";
|
||
if (model_object->IsHaveTexture())
|
||
{// 存在贴图则转存
|
||
// tex文件路径
|
||
std::string path_tex = PATH_CACHE + "texture/" + file_name + "/";
|
||
File::CreateFolder(path_tex);
|
||
// 复制贴图文件,并转换路径
|
||
model_object->ConvertTexturePath(path_tex);
|
||
}
|
||
model_object->SaveToFile(path_child);
|
||
cache_node->_allSub.push_back(path_child);
|
||
delete model_object;
|
||
++i;
|
||
}
|
||
}
|
||
FloatTime t1 = g_time->GetCurrent();
|
||
log_msg("成功加载一个模型文件:{},子模型数量:{},从缓存:{},耗时:{}",
|
||
res_name, mul_model.size(), b_read_cache, t1 - t0);
|
||
}
|
||
|
||
std::vector<std::string> Factory::GetAllModel()
|
||
{
|
||
std::vector<std::string> ret;
|
||
for (auto& iter : _imp->_mapName2Model)
|
||
ret.push_back(iter.first);
|
||
return ret;
|
||
}
|
||
|
||
gcActor Factory::CreateActor(std::string_view name)
|
||
{
|
||
gcActor act = get_gc<Actor>();
|
||
act->_idModel = _imp->_get_model_id(name);
|
||
act->_trans = Transform::Create();
|
||
act->_color = nullptr;
|
||
act->_modelAnimationInstance = _imp->_create_model_bone_animation(name);
|
||
act->_rigidBody = nullptr;
|
||
|
||
return act;
|
||
}
|
||
|
||
|
||
Camera* Factory::GetCamera()
|
||
{
|
||
return g_vk->GetCamera();
|
||
}
|
||
|
||
|
||
size_t Factory::LoadSkybox(std::string_view path)
|
||
{
|
||
return g_vk->LoadSkybox(path);
|
||
}
|
||
|
||
void Factory::SetSkybox(size_t id)
|
||
{
|
||
g_vk->SetSkybox(id);
|
||
}
|
||
|
||
void Factory::SetDebugView3D(DebugView3D type)
|
||
{
|
||
g_vk->SetDebugView(type);
|
||
}
|
||
|
||
dl::DebugView3D Factory::GetDebugView3D()
|
||
{
|
||
return g_vk->GetDebugView();
|
||
}
|
||
|
||
void Factory::UpdateDebugView()
|
||
{
|
||
//
|
||
bool ctrl = g_input->KeyState(KeyCode::LEFT_CONTROL);
|
||
bool alt = g_input->KeyState(KeyCode::LEFT_ALT);
|
||
|
||
if (!ctrl && !alt)
|
||
{
|
||
if (g_input->KeyDown(KeyCode::KP_0))
|
||
SetDebugView3D((DebugView3D)0);
|
||
else if (g_input->KeyDown(KeyCode::KP_1))
|
||
SetDebugView3D((DebugView3D)1);
|
||
else if (g_input->KeyDown(KeyCode::KP_2))
|
||
SetDebugView3D((DebugView3D)2);
|
||
else if (g_input->KeyDown(KeyCode::KP_3))
|
||
SetDebugView3D((DebugView3D)3);
|
||
else if (g_input->KeyDown(KeyCode::KP_4))
|
||
SetDebugView3D((DebugView3D)4);
|
||
else if (g_input->KeyDown(KeyCode::KP_5))
|
||
SetDebugView3D((DebugView3D)5);
|
||
else if (g_input->KeyDown(KeyCode::KP_6))
|
||
SetDebugView3D((DebugView3D)6);
|
||
else if (g_input->KeyDown(KeyCode::KP_7))
|
||
SetDebugView3D((DebugView3D)7);
|
||
else if (g_input->KeyDown(KeyCode::KP_8))
|
||
SetDebugView3D((DebugView3D)8);
|
||
else if (g_input->KeyDown(KeyCode::KP_9))
|
||
SetDebugView3D((DebugView3D)9);
|
||
}
|
||
else if (ctrl)
|
||
{
|
||
if (g_input->KeyDown(KeyCode::KP_0))
|
||
SetDebugView3D((DebugView3D)10);
|
||
else if (g_input->KeyDown(KeyCode::KP_1))
|
||
SetDebugView3D((DebugView3D)11);
|
||
else if (g_input->KeyDown(KeyCode::KP_2))
|
||
SetDebugView3D((DebugView3D)12);
|
||
else if (g_input->KeyDown(KeyCode::KP_3))
|
||
SetDebugView3D((DebugView3D)13);
|
||
else if (g_input->KeyDown(KeyCode::KP_4))
|
||
SetDebugView3D((DebugView3D)14);
|
||
else if (g_input->KeyDown(KeyCode::KP_5))
|
||
SetDebugView3D((DebugView3D)15);
|
||
else if (g_input->KeyDown(KeyCode::KP_6))
|
||
SetDebugView3D((DebugView3D)16);
|
||
else if (g_input->KeyDown(KeyCode::KP_7))
|
||
SetDebugView3D((DebugView3D)17);
|
||
else if (g_input->KeyDown(KeyCode::KP_8))
|
||
SetDebugView3D((DebugView3D)18);
|
||
else if (g_input->KeyDown(KeyCode::KP_9))
|
||
SetDebugView3D((DebugView3D)19);
|
||
}
|
||
else if (alt)
|
||
{
|
||
if (g_input->KeyDown(KeyCode::KP_0))
|
||
SetDebugView3D((DebugView3D)20);
|
||
else if (g_input->KeyDown(KeyCode::KP_1))
|
||
SetDebugView3D((DebugView3D)21);
|
||
else if (g_input->KeyDown(KeyCode::KP_2))
|
||
SetDebugView3D((DebugView3D)22);
|
||
else if (g_input->KeyDown(KeyCode::KP_3))
|
||
SetDebugView3D((DebugView3D)23);
|
||
else if (g_input->KeyDown(KeyCode::KP_4))
|
||
SetDebugView3D((DebugView3D)24);
|
||
else if (g_input->KeyDown(KeyCode::KP_5))
|
||
SetDebugView3D((DebugView3D)25);
|
||
else if (g_input->KeyDown(KeyCode::KP_6))
|
||
SetDebugView3D((DebugView3D)26);
|
||
else if (g_input->KeyDown(KeyCode::KP_7))
|
||
SetDebugView3D((DebugView3D)27);
|
||
else if (g_input->KeyDown(KeyCode::KP_8))
|
||
SetDebugView3D((DebugView3D)28);
|
||
else if (g_input->KeyDown(KeyCode::KP_9))
|
||
SetDebugView3D((DebugView3D)29);
|
||
}
|
||
}
|
||
|
||
gcSprite Factory::CreateSpriteDefault(const Color& col /*= ColorDef::WHITE*/)
|
||
{
|
||
auto spr = get_gc<Sprite>();
|
||
|
||
bool b_solid = col[3] == 0.0f || col[3] == 1.0f;
|
||
//等于0时,用户很有可能随后修改透明度
|
||
spr->_id = b_solid ? _imp->_idSolid : _imp->_idSolidTrans;
|
||
spr->_quad = QUAD_DEFAULT_SPRITE;
|
||
spr->_order = Z_DEFAULT;
|
||
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr->_id);
|
||
assert(spr_info && "可能是忘了关闭发布模式");
|
||
|
||
for (int i = 0; i != 4; ++i)
|
||
{
|
||
spr->_col[i] = col;
|
||
spr->_uv[i] = spr_info->_uv[i];
|
||
}
|
||
#ifndef NDEBUG
|
||
spr->_name = ":";
|
||
#endif
|
||
return spr;
|
||
}
|
||
|
||
|
||
gcSprite Factory::CreateSprite(const SpriteID& spr_id)
|
||
{
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr_id);
|
||
if (!spr_info)
|
||
{
|
||
log_err("获取SpriteInfo失败:{}", to_string(spr_id));
|
||
return g_factory->CreateSpriteDefault();
|
||
}
|
||
|
||
auto spr = get_gc<Sprite>();
|
||
|
||
spr->SetColor(spr_info->_color);
|
||
spr->_id = spr_id;
|
||
|
||
// 如果旋转过
|
||
Size size = Align::GetSize(spr_info->_rect);
|
||
if (spr_info->_bRightAngle)
|
||
std::swap(size[0], size[1]);
|
||
|
||
spr->_quad = createQuad(size, false)
|
||
- spr_info->_anchor;//偏移锚点
|
||
spr->_order = Z_DEFAULT;
|
||
for (int i = 0; i != 4; ++i)
|
||
spr->_uv[i] = spr_info->_uv[i];
|
||
#ifndef NDEBUG
|
||
spr->_name = GetSpriteName(spr_id);
|
||
#endif
|
||
return spr;
|
||
}
|
||
|
||
|
||
gcSprite Factory::CreateSprite(std::string_view name, size_t index /*= 0*/)
|
||
{
|
||
return CreateSprite(GetSpriteId(name, index));
|
||
}
|
||
|
||
dl::gcSprite Factory::CreateSprite(size_t rt_id)
|
||
{
|
||
auto spr = get_gc<Sprite>();
|
||
|
||
spr->_id._tex = rt_id;
|
||
spr->_id._rect = (size_t)-1;
|
||
spr->_bRenderTarget = true;
|
||
spr->_quad = createQuad(g_system->GetWindowSize(), false);
|
||
spr->_order = Z_DEFAULT_RENDER_TARGET;
|
||
|
||
for (int i = 0; i != 4; ++i)
|
||
{
|
||
spr->_col[i] = ColorDef::WHITE;
|
||
}
|
||
spr->_uv[0] = { 0.0f, 0.0f };
|
||
spr->_uv[1] = { 1.0f, 0.0f };
|
||
spr->_uv[2] = { 1.0f, 1.0f };
|
||
spr->_uv[3] = { 0.0f, 1.0f };
|
||
|
||
#ifndef NDEBUG
|
||
spr->_name = fmt::format("RenderTarget: {}", rt_id);
|
||
#endif
|
||
return spr;
|
||
}
|
||
|
||
bool Factory::RegisterSprite(std::string_view name, size_t index, Image* img, const Position& anchor)
|
||
{
|
||
if (!img)
|
||
{
|
||
log_err("传入图像为空:{}", name);
|
||
return false;
|
||
}
|
||
//--------------------记录Rect到Factory的_vecRectInfo----------------
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
if (iter != _imp->_sprGroup._mapName2SpriteID.end())
|
||
{
|
||
log_warn("精灵名字已存在:{}", name);
|
||
return false;
|
||
}
|
||
|
||
//
|
||
size_t id_tex;
|
||
size_t id_rect;
|
||
|
||
// 旋转精灵使w更大
|
||
bool right_angle = false;
|
||
{
|
||
Image img_r;
|
||
if (img->GetHeight() > img->GetWidth())
|
||
{
|
||
img_r = Image::RotateRightAngle1(*img);
|
||
img = &img_r;
|
||
right_angle = true;
|
||
}
|
||
if (!_imp->_reg_image(img, SIZE_BORDER_SPRITE, true, id_tex, id_rect))
|
||
{
|
||
log_err0("注册图像失败!");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
// 创建 sprite_id
|
||
std::vector<SpriteID>& vec_spr_id = _imp->_sprGroup._mapName2SpriteID[std::string{ name }];
|
||
SpriteID& spr_id = Select::CreateIfEmpty(vec_spr_id, index);
|
||
spr_id._tex = id_tex;
|
||
spr_id._rect = id_rect;
|
||
|
||
//{纹理id,区域id} -> { SpriteInfo }
|
||
FactoryImp::SpriteInfo& info = Select::CreateIfEmpty(
|
||
_imp->_sprGroup._allSpriteInfo, id_tex, id_rect);
|
||
|
||
RectU rect = _imp->_get_rect(id_tex, id_rect, SIZE_BORDER_SPRITE);
|
||
info._rect = rect;
|
||
_imp->_rect_to_uv(rect, info._uv, right_angle);
|
||
info._anchor = anchor;
|
||
info._color = ColorDef::WHITE;
|
||
info._bRightAngle = right_angle;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool Factory::UpdateSprite(std::string_view name, size_t index, Image* img, const Position& anchor /*= {}*/)
|
||
{
|
||
if (!img)
|
||
{
|
||
log_err("传入图像为空:{}", name);
|
||
return false;
|
||
}
|
||
|
||
// 返回已存在的
|
||
SpriteID spr_id;
|
||
if (!GetSpriteId(name, index, spr_id))
|
||
{
|
||
log_err("精灵不存在:{},{}", name, index);
|
||
return false;
|
||
}
|
||
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr_id);
|
||
if (!spr_info)
|
||
{
|
||
log_err("返回精灵信息失败:{}, {}", name, index);
|
||
return false;
|
||
}
|
||
// 检查大小是否匹配
|
||
Size size_old = Align::GetSize(spr_info->_rect);
|
||
if (spr_info->_bRightAngle)
|
||
{
|
||
std::swap(size_old.w, size_old.h);
|
||
}
|
||
|
||
if (img->GetSize() != size_old)
|
||
{
|
||
log_err("更新精灵失败,大小不匹配:{}, {}, {} -> {}", name, index, size_old, img->GetSize());
|
||
return false;
|
||
}
|
||
|
||
// 注册图像
|
||
Image img_r;
|
||
if (spr_info->_bRightAngle)
|
||
{
|
||
img_r = Image::RotateRightAngle1(*img);
|
||
img = &img_r;
|
||
}
|
||
if (!_imp->_update_image(img, SIZE_BORDER_SPRITE, spr_id._tex, spr_id._rect))
|
||
{
|
||
log_err0("注册图像失败!");
|
||
return false;
|
||
}
|
||
// 信息更新
|
||
spr_info->_anchor = anchor;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool Factory::HasSprite(std::string_view name)
|
||
{
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
return iter != _imp->_sprGroup._mapName2SpriteID.end();
|
||
}
|
||
|
||
std::vector<gcSprite> Factory::CreateSpriteMulti(std::string_view name, size_t num /*= 0*/, size_t index /*= 0*/)
|
||
{
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
if (iter == _imp->_sprGroup._mapName2SpriteID.end())
|
||
{
|
||
log_warn("SpriteSheet不存在:{}", name);
|
||
return {};
|
||
}
|
||
|
||
std::vector<SpriteID>& all_id = iter->second;
|
||
if (num == 0)
|
||
num = all_id.size();
|
||
|
||
std::vector<gcSprite> ret;
|
||
ret.resize(num);
|
||
for (size_t i = 0; i < num; ++i)
|
||
{
|
||
ret[i] = CreateSprite(all_id[i]);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
gcSprite Factory::CloneSprite(gcSprite& spr)
|
||
{
|
||
auto ret = get_gc<Sprite>(*(spr.operator->()));
|
||
// 如果是拥有Coor,则需要深拷贝
|
||
if (ret->_bOwnCoor)
|
||
ret->_coor = spr->_coor->Clone();
|
||
|
||
ret->_reset_not_copy();
|
||
|
||
return ret;
|
||
}
|
||
|
||
std::vector<std::string> Factory::GetFolderAllSpriteName(std::string_view folder_name)
|
||
{
|
||
std::vector<std::string> ret;
|
||
for (auto& iter : _imp->_sprGroup._mapName2SpriteID)
|
||
{
|
||
std::string_view name = iter.first;
|
||
if (Sub::IsBegin(name, folder_name))
|
||
ret.push_back(std::string{ name });
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
size_t Factory::GetSpriteSheetNum(std::string_view name)
|
||
{
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
if (iter == _imp->_sprGroup._mapName2SpriteID.end())
|
||
{
|
||
log_warn("SpriteSheet不存在:{}", name);
|
||
return 0;
|
||
}
|
||
return iter->second.size();
|
||
}
|
||
|
||
SpriteID Factory::GetSpriteId(std::string_view name, size_t index)
|
||
{
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
if (iter == _imp->_sprGroup._mapName2SpriteID.end())
|
||
{
|
||
log_warn("SpriteSheet不存在:{}", name);
|
||
return _imp->_idSolid;
|
||
}
|
||
|
||
std::vector<SpriteID>& all_id = iter->second;
|
||
|
||
if (index >= all_id.size())
|
||
{
|
||
log_warn("下标越界:{},{}/{},", name, index, all_id.size());
|
||
return _imp->_idSolid;
|
||
}
|
||
|
||
return all_id[index];
|
||
}
|
||
|
||
bool Factory::GetSpriteId(std::string_view name, size_t index, SpriteID& id)
|
||
{
|
||
auto iter = _imp->_sprGroup._mapName2SpriteID.find(std::string{ name });
|
||
if (iter == _imp->_sprGroup._mapName2SpriteID.end())
|
||
return false;
|
||
|
||
std::vector<SpriteID>& all_id = iter->second;
|
||
|
||
if (index >= all_id.size())
|
||
return false;
|
||
|
||
id = all_id[index];
|
||
return true;
|
||
}
|
||
|
||
Size Factory::GetSpriteTexSize(const SpriteID &spr_id)
|
||
{
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr_id);
|
||
if (!spr_info)
|
||
{
|
||
log_err0("返回精灵信息失败!");
|
||
return toSizeNeg2Zero(SIZE_DEFAULT_SPRITE);
|
||
}
|
||
return Align::GetSize(spr_info->_rect);
|
||
}
|
||
|
||
|
||
std::string Factory::GetSpriteName(const SpriteID& spr_id)
|
||
{
|
||
for (auto& iter : _imp->_sprGroup._mapName2SpriteID)
|
||
{
|
||
for (SpriteID& iter1 : iter.second)
|
||
{
|
||
if (iter1._tex == spr_id._tex
|
||
&& iter1._rect == spr_id._rect)
|
||
{
|
||
return iter.first;
|
||
}
|
||
}
|
||
}
|
||
return "error";
|
||
}
|
||
|
||
Position Factory::GetSpriteAnchor(const SpriteID& spr_id)
|
||
{
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr_id);
|
||
if (!spr_info)
|
||
{
|
||
log_err0("返回精灵信息失败!");
|
||
return {};
|
||
}
|
||
return spr_info->_anchor;
|
||
}
|
||
|
||
dl::Color Factory::GetSpriteColor(const SpriteID& spr_id)
|
||
{
|
||
FactoryImp::SpriteInfo* spr_info = _imp->_get_sprite_info(spr_id);
|
||
if (!spr_info)
|
||
{
|
||
log_err0("返回精灵信息失败!");
|
||
return {};
|
||
}
|
||
return spr_info->_color;
|
||
}
|
||
|
||
dl::gcAnimation Factory::CreateAnimation(std::string_view name, std::string_view state, unsigned dir)
|
||
{
|
||
auto iter = _mapAnimationInfo.find(name);
|
||
if (iter == _mapAnimationInfo.end())
|
||
{
|
||
log_err("创建精灵动画失败:{}:{}", name, state);
|
||
return {};
|
||
}
|
||
AnimationInfo& info = iter->second;
|
||
|
||
auto iter1 = info._allAni.find(state);
|
||
if (iter1 == info._allAni.end())
|
||
{
|
||
log_err("创建精灵动画失败:{},没有:{}", name, state);
|
||
return {};
|
||
}
|
||
AnimationInfo::Node& node = iter1->second;
|
||
|
||
|
||
gcAnimation ret = get_gc<Animation>(name, dir);
|
||
if (info._type == "sheet")
|
||
{
|
||
std::string name_spr = name + "." + fmt::vformat(info._format,
|
||
fmt::make_format_args(state));
|
||
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 if (info._type == "multi")
|
||
{
|
||
unsigned count = node._count;
|
||
unsigned beg = node._beg + (count + node._skip) * dir;
|
||
|
||
for (unsigned i = beg; i < beg + count; ++i)
|
||
{
|
||
std::string name_spr = name + "." + fmt::vformat(info._format,
|
||
fmt::make_format_args(state, i));
|
||
|
||
gcSprite spr = g_factory->CreateSprite(name_spr, 0);
|
||
spr->DtQuadOffset(info._offset);
|
||
ret->PushBack(spr);
|
||
}
|
||
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;
|
||
}
|
||
|
||
dl::gcAnimation Factory::CloneAnimation(gcAnimation ani)
|
||
{
|
||
auto ret = get_gc<Animation>(*(ani.operator->()));
|
||
if (ani->_coor)
|
||
ret->_coor = ani->_coor->Clone();
|
||
ret->_vecSpr.clear();
|
||
for (auto& iter : ani->_vecSpr)
|
||
{
|
||
gcSprite spr = g_factory->CloneSprite(iter);
|
||
spr->SetCoor(ret->_coor);
|
||
ret->_vecSpr.push_back(spr);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
dl::gcSprite Factory::RenderSprite(std::string_view name, size_t index)
|
||
{
|
||
gcSprite ret = CreateSprite(name, index);
|
||
_vecSprite.push_back(ret);
|
||
return ret;
|
||
}
|
||
|
||
dl::gcSprite Factory::RenderSpriteDefault()
|
||
{
|
||
gcSprite ret = CreateSpriteDefault();
|
||
_vecSprite.push_back(ret);
|
||
return ret;
|
||
}
|
||
|
||
dl::gcText Factory::RenderText()
|
||
{
|
||
gcText ret = CreateTextDefault();
|
||
_vecText.push_back(ret);
|
||
return ret;
|
||
}
|
||
|
||
dl::gcAnimation Factory::RenderAnimation(std::string_view name, std::string_view state, unsigned dir)
|
||
{
|
||
// todo animation不是一帧
|
||
gcAnimation ret = CreateAnimation(name, state, dir);
|
||
ret->Render();
|
||
_vecAnimation.push_back(ret);
|
||
return ret;
|
||
}
|
||
|
||
size_t Factory::LoadFont(std::string_view path_name)
|
||
{
|
||
return g_freetype->LoadFace(path_name);
|
||
}
|
||
|
||
size_t Factory::GetFontSize()
|
||
{
|
||
return g_freetype->GetFontSize();
|
||
}
|
||
|
||
|
||
gcText Factory::CreateText(size_t font_id /*= 0*/,
|
||
unsigned font_size, const Color& col,
|
||
unsigned font_outline, const Color& col_outline,
|
||
unsigned font_shadow, const Color& col_shadow)
|
||
{
|
||
auto txt = get_gc<Text>();
|
||
|
||
if (font_id >= g_freetype->GetFontSize())
|
||
{
|
||
log_err0("字体id越界,将使用0号!");
|
||
assert(font_id);
|
||
font_id = 0;
|
||
}
|
||
|
||
txt->_fontId = font_id;
|
||
txt->_fontSize[TextParam::NORMAL] = font_size;
|
||
txt->_fontSize[TextParam::OUTLINE] = font_outline;
|
||
txt->_fontSize[TextParam::SHADOW] = font_shadow;
|
||
txt->_fontSizeReal = txt->_fontSize;
|
||
txt->_col[TextParam::NORMAL] = col;
|
||
txt->_col[TextParam::OUTLINE] = col_outline;
|
||
txt->_col[TextParam::SHADOW] = col_shadow;
|
||
txt->_coor = Coor::Create();
|
||
|
||
return txt;
|
||
}
|
||
|
||
|
||
CharImage* Factory::GetChar(const CharInfo& info)
|
||
{
|
||
// 缓存工作由CreateSpriteChar完成
|
||
return g_freetype->GetChar(info);
|
||
}
|
||
|
||
float Factory::CreateSpriteChar(const CharInfo& info, gcSprite& spr, gcSprite& spr_outline)
|
||
{
|
||
auto fn_failed = [&]()
|
||
{
|
||
spr = CreateSpriteDefault();
|
||
spr->SetQuad(createQuad(info._size, false));
|
||
|
||
spr_outline = CreateSpriteDefault();
|
||
spr_outline->SetQuad(createQuad(info._size, false));
|
||
};
|
||
|
||
if (info._font >= g_freetype->GetFontSize())
|
||
{
|
||
log_err("字体id不存在:{}", info._font);
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
|
||
if (info._size == 0)
|
||
{
|
||
log_err0("字体大小不能为0!");
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
|
||
// 排除控制字符
|
||
if ((info._ch >= 0 && info._ch <= 31)
|
||
|| info._ch == 127)
|
||
{
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
|
||
FactoryImp::CharSprite& char_spr = _imp->_hashCharImage[info];
|
||
FactoryImp::CharSprite::Data& d0 = char_spr._data[0];
|
||
FactoryImp::CharSprite::Data& d1 = char_spr._data[1];
|
||
RectU rect0;
|
||
RectU rect1;
|
||
// 注册图像(普通和描边一起注册)
|
||
if (d0._idTex == 0)
|
||
{
|
||
CharImage* char_img = g_freetype->GetChar(info);
|
||
if (char_img == nullptr)
|
||
{
|
||
log_err0("GetChar失败!");
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
|
||
char_spr._advance = char_img->_advance;
|
||
char_spr._anchor = { -char_img->_bearingX, char_img->_bearingY };
|
||
|
||
//0
|
||
if (!_imp->_reg_image(char_img->_image, SIZE_BORDER_FONT, true, d0._idTex, d0._idRect))
|
||
{
|
||
delete char_img;
|
||
log_err0("注册图像失败!");
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
rect0 = _imp->_get_rect(d0._idTex, d0._idRect, SIZE_BORDER_FONT);
|
||
_imp->_rect_to_uv(rect0, d0._uv);
|
||
|
||
//1
|
||
if (info._outline > 0)
|
||
{
|
||
if (!_imp->_reg_image(char_img->_imageOutline, SIZE_BORDER_FONT, true, d1._idTex, d1._idRect))
|
||
{
|
||
delete char_img;
|
||
log_err0("注册图像(描边)失败!");
|
||
fn_failed();
|
||
return 0;
|
||
}
|
||
rect1 = _imp->_get_rect(d1._idTex, d1._idRect, SIZE_BORDER_FONT);
|
||
_imp->_rect_to_uv(rect1, d1._uv);
|
||
}
|
||
|
||
delete char_img;
|
||
}
|
||
else
|
||
{
|
||
rect0 = _imp->_get_rect(d0._idTex, d0._idRect, SIZE_BORDER_FONT);
|
||
if (info._outline > 0)
|
||
{
|
||
rect1 = _imp->_get_rect(d1._idTex, d1._idRect, SIZE_BORDER_FONT);
|
||
}
|
||
}
|
||
|
||
//0
|
||
spr = MemoryPool::GetGC<Sprite>();
|
||
|
||
spr->SetColor(ColorDef::WHITE);
|
||
spr->_id = { d0._idTex, d0._idRect};
|
||
spr->_quad = createQuad(Align::GetSize(rect0), false)
|
||
- char_spr._anchor;//偏移锚点
|
||
spr->_order = Z_DEFAULT;
|
||
for (int i = 0; i != 4; ++i)
|
||
spr->_uv[i] = d0._uv[i];
|
||
|
||
//1
|
||
if (info._outline > 0)
|
||
{
|
||
spr_outline = MemoryPool::GetGC<Sprite>();
|
||
|
||
spr_outline->SetColor(ColorDef::WHITE);
|
||
spr_outline->_id = { d1._idTex, d1._idRect };
|
||
spr_outline->_quad = createQuad(Align::GetSize(rect1), false)
|
||
- char_spr._anchor;//偏移锚点
|
||
spr_outline->_order = Z_DEFAULT;
|
||
for (int i = 0; i != 4; ++i)
|
||
spr_outline->_uv[i] = d1._uv[i];
|
||
}
|
||
|
||
return char_spr._advance;
|
||
}
|
||
|
||
dl::Coor* Factory::GetRootCoor(size_t i)
|
||
{
|
||
return g_vk->GetRootCoor(i);
|
||
}
|
||
|
||
void Factory::AddColor(std::string_view name, const Color& col)
|
||
{
|
||
_hashTagColor[std::string{ name }] = col;
|
||
}
|
||
|
||
|
||
Color Factory::GetColor(std::string_view name)
|
||
{
|
||
if (name.size() == 10
|
||
&& name[0] == '0'
|
||
&& name[1] == 'x')
|
||
{//尝试十六进制
|
||
return createColor(name);
|
||
}
|
||
|
||
auto iter = _hashTagColor.find(std::string{ name });
|
||
if (iter == _hashTagColor.end())
|
||
{
|
||
log_err("Tag颜色查找失败:{}", name);
|
||
return ColorDef::WHITE;
|
||
}
|
||
else
|
||
return iter->second;
|
||
}
|
||
|
||
std::optional<Color> Factory::GetColorCheck(std::string_view name)
|
||
{
|
||
auto iter = _hashTagColor.find(std::string{ name });
|
||
if (iter == _hashTagColor.end())
|
||
{
|
||
return std::nullopt;
|
||
}
|
||
else
|
||
return iter->second;
|
||
}
|
||
|
||
|
||
void Factory::ExportTexture2D()
|
||
{
|
||
g_vk->ExportTextureCanvas(_strPathTemp);
|
||
}
|
||
|
||
|
||
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;
|
||
VK::Canvas* canvas = nullptr;
|
||
if (!spr->_bRenderTarget)
|
||
canvas = g_vk->GetCanvasByTexture(spr->_id._tex);
|
||
else
|
||
canvas = g_vk->GetCanvasByRenderTarget(spr->_id._tex);
|
||
assert(canvas);
|
||
|
||
if (spr->_id._rect == -1
|
||
|| !spr->IsColorOne()
|
||
|| (spr->_id._tex >= id._tex))
|
||
{ //可能是半透明
|
||
canvas->_allSpriteTrans.push_back(spr);
|
||
}
|
||
else
|
||
canvas->_allSprite.push_back(spr);
|
||
}
|
||
|
||
void Factory::_render_pickup()
|
||
{
|
||
if (g_input->KeyDown(KeyCode::DELETE))
|
||
log_pause0("拾取检测");
|
||
if (_bOrderPickupShow)
|
||
{
|
||
if (!_vecPickupSprite.empty())
|
||
{
|
||
_vecPickupSprite.back()->RenderDebug();
|
||
}
|
||
if (!_vecPickupText.empty())
|
||
{
|
||
_vecPickupText.back()->RenderDebug();
|
||
}
|
||
}
|
||
}
|
||
|
||
struct ColorTag
|
||
{
|
||
char _name[32];
|
||
uint32_t _color;
|
||
};
|
||
|
||
void Factory::LoadColorCsv(std::string_view name)
|
||
{
|
||
assert(0);
|
||
/*std::vector<ColorTag> all;
|
||
CsvFile::Deserialize(name, all);
|
||
|
||
for (auto& iter : all)
|
||
{
|
||
AddColor(iter._name, ABGR::CreateColor(iter._color));
|
||
}*/
|
||
}
|
||
|
||
|
||
void Factory::SetOrderPickup(float order)
|
||
{
|
||
if (g_input->KeyState(KeyCode::RIGHT_CONTROL)
|
||
&& g_input->KeyDown(KeyCode::DELETE))
|
||
log_pause("当前拾取设置!");
|
||
_orderPickup = order;
|
||
}
|
||
|
||
void Factory::DeleteBinary(bool b_all, bool b_2d, bool b_3d)
|
||
{
|
||
if (!_bSetPath)
|
||
{
|
||
log_err0("尚未指定输出目录!");
|
||
return;
|
||
}
|
||
if (b_all)
|
||
File::DeleteContent(GetPathBinary());
|
||
else
|
||
{
|
||
if (b_2d)
|
||
File::DeleteContent(GetPathBinary2D());
|
||
if (b_3d)
|
||
File::DeleteContent(GetPathBinary3D());
|
||
}
|
||
}
|
||
|
||
constexpr std::string_view NAME_CACHE_MODEL = "model.cache";
|
||
|
||
void Factory::_auto_render()
|
||
{
|
||
for (auto& iter : _vecSprite)
|
||
iter->Render();
|
||
for (auto& iter : _vecText)
|
||
iter->Render();
|
||
}
|
||
|
||
void Factory::_clear_render()
|
||
{
|
||
_vecSprite.clear();
|
||
_vecText.clear();
|
||
_vecAnimation.clear();
|
||
}
|
||
|
||
void Factory::_render_rt()
|
||
{
|
||
if(Engine::GetParamRef()._show3D)
|
||
_sprRenderTarget0->Render();
|
||
}
|
||
|
||
void Factory::_resize()
|
||
{
|
||
_sprRenderTarget0->SetQuad(createQuad(g_system->GetWindowSize(), false));
|
||
}
|
||
|
||
void Factory::_init_path()
|
||
{
|
||
if (!_bSetPath)
|
||
{
|
||
SetPath(
|
||
File::PathCurrent(),
|
||
File::PathCurrent(),
|
||
File::PathStorage(),
|
||
File::PathTemp());
|
||
}
|
||
// File::CreateFolder(File::PathCurrent());
|
||
// File::CreateFolder(File::PathStorage());
|
||
// File::CreateFolder(File::PathTemp());
|
||
// File::CreateFolder(File::PathPrivate());
|
||
File::CreateFolder(_mapPathImage[""]);
|
||
File::CreateFolder(_strPathModel);
|
||
File::CreateFolder(_strPathVoice);
|
||
File::CreateFolder(_strPathBinary);
|
||
File::CreateFolder(_strPathTemp);
|
||
File::CreateFolder(GetPathBinary2D());
|
||
File::CreateFolder(GetPathBinary3D());
|
||
|
||
{
|
||
File::SearchRule& rule = _ruleCheckImage;
|
||
rule._vecFmt.push_back("jpg");
|
||
rule._vecFmt.push_back("jpeg");
|
||
rule._vecFmt.push_back("png");
|
||
rule._vecFmt.push_back("tag");
|
||
rule._vecFmt.push_back("bmp");
|
||
rule._vecFmt.push_back("gif");
|
||
rule._vecFmt.push_back("hdr");
|
||
rule._vecFmt.push_back("pic");
|
||
rule._vecFmt.push_back("json");
|
||
rule._vecFmt.push_back("txt");
|
||
rule._vecFilter.push_back("__animation.json");
|
||
rule._vecFilterFolder.push_back(".work");
|
||
}
|
||
{
|
||
File::SearchRule& rule = _ruleLoadImage;
|
||
rule._vecFmt.push_back("jpg");
|
||
rule._vecFmt.push_back("jpeg");
|
||
rule._vecFmt.push_back("png");
|
||
rule._vecFmt.push_back("tag");
|
||
rule._vecFmt.push_back("bmp");
|
||
rule._vecFmt.push_back("gif");
|
||
rule._vecFmt.push_back("hdr");
|
||
rule._vecFmt.push_back("pic");
|
||
rule._vecFilterFolder.push_back(".work");
|
||
}
|
||
|
||
// 因为每个模型单独存放,不会合并,所以算法不一样
|
||
// 针对每一个模型文件,缓存 效验值、中间文件路径
|
||
// 如果效验值不同,则生成中间文件,并更新效验值
|
||
_imp->_modelCache.Load(GetPathBinary3D() + NAME_CACHE_MODEL);
|
||
|
||
// 合并大图纹理,生成Canvas
|
||
_load_sprite();
|
||
}
|
||
|
||
void Factory::_init_defualt_res()
|
||
{
|
||
// 先使用一下,保证gcSprite后于gcText析构
|
||
//gcSprite spr = CreateSpriteDefault();
|
||
//spr->SetColor(ColorDef::RED);
|
||
|
||
_sprRenderTarget0 = CreateSprite(0);
|
||
|
||
// 默认颜色
|
||
AddColor("red", ColorDef::RED);
|
||
AddColor("green", ColorDef::GREEN);
|
||
AddColor("blue", ColorDef::BLUE);
|
||
AddColor("white", ColorDef::WHITE);
|
||
AddColor("black", ColorDef::BLACK);
|
||
AddColor("yellow", ColorDef::YELLOW);
|
||
AddColor("purple", ColorDef::PURPLE);
|
||
AddColor("cyan", ColorDef::CYAN);
|
||
|
||
// 默认字体
|
||
LoadFont("dl/default.ttf");
|
||
|
||
//-------------默认模型-------------------
|
||
if (true)
|
||
{
|
||
//加载model_object
|
||
ModelObject* model_object = new ModelObject;
|
||
model_object->Load("dl/default.model");
|
||
//model_object -> model
|
||
Model* model = g_vk->CreateModel(model_object);
|
||
delete model_object;
|
||
assert(model);
|
||
|
||
size_t id = g_vk->GetMulModelSize();
|
||
_imp->_mapName2Model[":box"] = id;
|
||
std::vector<Model*> vec_model{ model };
|
||
g_vk->AddMulModel(vec_model);
|
||
}
|
||
}
|
||
|
||
|
||
void FactoryImp::_rect_to_uv(const RectU& rect, UV* uv, bool right_angle)
|
||
{
|
||
using namespace Align;
|
||
Position4 ltrb;
|
||
for (int i = 0; i != 4; ++i)
|
||
ltrb[i] = rect[i] / (Float)SIZE_TEXTURE_2D;
|
||
|
||
if (!right_angle)
|
||
{
|
||
uv[(size_t)Corner::LT] = GetLT(ltrb);
|
||
uv[(size_t)Corner::RT] = GetRT(ltrb);
|
||
uv[(size_t)Corner::RB] = GetRB(ltrb);
|
||
uv[(size_t)Corner::LB] = GetLB(ltrb);
|
||
}
|
||
else
|
||
{
|
||
uv[(size_t)Corner::LT] = GetRT(ltrb);
|
||
uv[(size_t)Corner::RT] = GetRB(ltrb);
|
||
uv[(size_t)Corner::RB] = GetLB(ltrb);
|
||
uv[(size_t)Corner::LB] = GetLT(ltrb);
|
||
}
|
||
|
||
/*for (int i = 0; i != 4; ++i)
|
||
uv[i][1] = 1.0f - uv[i][1];*/
|
||
}
|
||
//
|
||
//void to_json(json& j, const FactoryImp::SpriteInfo& info)
|
||
//{
|
||
// j = json{
|
||
// {"rect", info._rect},
|
||
// {"uv", info._uv},
|
||
// {"color", info._color},
|
||
// {"anchor", info._anchor},
|
||
// {"right_angle", info._bRightAngle}
|
||
// };
|
||
//}
|
||
//void from_json(const json& j, FactoryImp::SpriteInfo& info)
|
||
//{
|
||
// j.at("rect").get_to(info._rect);
|
||
// j.at("uv").get_to(info._uv);
|
||
// j.at("color").get_to(info._color);
|
||
// j.at("anchor").get_to(info._anchor);
|
||
// j.at("right_angle").get_to(info._bRightAngle);
|
||
//}
|
||
//void to_json(json& j, const SpriteID& id)
|
||
//{
|
||
// j = json{
|
||
// {"tex", id._tex},
|
||
// {"rect", id._rect}
|
||
// };
|
||
//}
|
||
//void from_json(const json& j, SpriteID& id)
|
||
//{
|
||
// j.at("tex").get_to(id._tex);
|
||
// j.at("rect").get_to(id._rect);
|
||
//}
|
||
//
|
||
//void to_json(json& j, const FactoryImp::SpriteGroup& group)
|
||
//{
|
||
// j = json{
|
||
// {"id_trans", group._idTrans},
|
||
// {"sprite_info", group._allSpriteInfo},
|
||
// {"sprite_id", group._mapName2SpriteID},
|
||
// };
|
||
//}
|
||
//void from_json(const json& j, FactoryImp::SpriteGroup& group)
|
||
//{
|
||
// j.at("id_trans").get_to(group._idTrans);
|
||
// j.at("sprite_info").get_to(group._allSpriteInfo);
|
||
// j.at("sprite_id").get_to(group._mapName2SpriteID);
|
||
//}
|
||
|
||
ModelAnimationInstance* FactoryImp::_create_model_bone_animation(std::string_view name)
|
||
{
|
||
auto iter = _mapName2Model.find(std::string{ name });
|
||
if (iter == _mapName2Model.end())
|
||
{
|
||
log_err("未知模型名称: {}", name);
|
||
return nullptr;
|
||
}
|
||
// 现在只有一个model
|
||
std::vector<Model*>& mul_model = g_vk->GetMulModel(iter->second);
|
||
// assert(mul_model.size() == 1);
|
||
Model* model = mul_model[0];
|
||
// 存在骨骼动画,则生成实例
|
||
if (model->_allAnimation.empty())
|
||
{
|
||
if(!model->_allSkin.empty())
|
||
log_warn("模型没有任何动画,但存在骨骼绑定:{}", name);
|
||
return nullptr;
|
||
}
|
||
ModelAnimationInstance* ret = new ModelAnimationInstance;
|
||
ret->_model = model;
|
||
ret->_treeNode = model->_treeNode;
|
||
ret->_treeNodeParent = model->_treeNodeParent;
|
||
ret->UpdateNode();
|
||
//for (size_t i = 0; i < ret->_treeNode.size(); ++i)
|
||
//{
|
||
// ret->_finalTrans[i] = Mat::CreateIdentity();
|
||
//}
|
||
|
||
ret->_id = g_vk->GetUboBoneFree();
|
||
if (ret->_id == -1)
|
||
{
|
||
return nullptr;
|
||
}
|
||
g_vk->SetUboBoneUse(ret->_id);
|
||
return ret;
|
||
}
|
||
|
||
|
||
|
||
constexpr PointU SPRITE_EXTEND_XY = { SIZE_BORDER_SPRITE, SIZE_BORDER_SPRITE };
|
||
constexpr Size SPRITE_EXTEND_SIZE = { SIZE_BORDER_SPRITE * 2, SIZE_BORDER_SPRITE * 2 };
|
||
|
||
bool FactoryImp::_reg_image(Image* image_src, unsigned border, bool border_fill, size_t& id_tex, size_t& id_rect)
|
||
{
|
||
RectU rect; // 包含border
|
||
// 扩展图像
|
||
Size size = image_src->GetSize() + toLonger(border * 2);
|
||
Image* image = Img::Create(size, ColorDef::NONE);
|
||
Img::AddRect(image, image_src, createRectU(image_src->GetSize()), toLonger(border));
|
||
if (border_fill)
|
||
Img::BuildBorder(image, border);
|
||
bool b_add = false;
|
||
for (size_t i = 0; i < _allTexPack.size(); ++i)
|
||
{
|
||
if (_allTexPack[i].Add(size, rect))
|
||
{
|
||
b_add = true;
|
||
id_tex = _numTexStatic + i;
|
||
id_rect = _allTexRect[i].size();
|
||
|
||
_allTexRect[i].push_back(rect);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!b_add)
|
||
{//分配一个新的
|
||
TexPack tex_pack;
|
||
tex_pack.Reset({ SIZE_TEXTURE_2D, SIZE_TEXTURE_2D });
|
||
if (!tex_pack.Add(size, rect))
|
||
{
|
||
log_err0("注册图像失败!可能是图像太大。需要小于SIZE_TEXTURE_2D。");
|
||
return false;
|
||
}
|
||
id_tex = _numTexStatic + _allTexPack.size();
|
||
id_rect = 0;
|
||
_allTexPack.push_back(tex_pack);
|
||
_allTexRect.push_back({ rect });
|
||
|
||
std::array<Image*, NUM_MIPMAP_2D> vec_image;
|
||
unsigned size_big = SIZE_TEXTURE_2D;
|
||
for (size_t i = 0; i < vec_image.size(); ++i)
|
||
{
|
||
vec_image[i] = Img::Create(toLonger(size_big), ColorDef::NONE);
|
||
size_big >>= 1;
|
||
assert(size_big);
|
||
}
|
||
g_vk->CreateCanvasImage(id_tex, vec_image);
|
||
for (size_t i = 0; i < vec_image.size(); ++i)
|
||
{
|
||
delete vec_image[i];
|
||
}
|
||
}
|
||
|
||
Texture tex = g_vk->GetCanvasByTexture(id_tex)->_texture;
|
||
|
||
g_vk->UpdateTexture2D(tex, Align::GetLT(rect),
|
||
image, createRectU(image->GetSize()));
|
||
|
||
delete image;
|
||
return true;
|
||
}
|
||
|
||
|
||
bool FactoryImp::_update_image(Image* image_src, unsigned border, size_t id_tex, size_t id_rect)
|
||
{
|
||
// 扩展图像
|
||
Size size = image_src->GetSize() + toLonger(border * 2);
|
||
Image* image = Img::Create(size, ColorDef::NONE);
|
||
Img::AddRect(image, image_src, createRectU(image_src->GetSize()), toLonger(border));
|
||
Img::BuildBorder(image, border);
|
||
|
||
// 更新纹理
|
||
Texture tex = g_vk->GetCanvasByTexture(id_tex)->_texture;
|
||
|
||
RectU rect = _get_rect_border(id_tex, id_rect);
|
||
|
||
g_vk->UpdateTexture2D(tex, Align::GetLT(rect),
|
||
image, createRectU(image->GetSize()));
|
||
|
||
delete image;
|
||
return true;
|
||
}
|
||
|
||
void Factory::_save_cache()
|
||
{
|
||
if(!_imp->_modelCache.Empty())
|
||
_imp->_modelCache.Save(GetPathBinary3D() + NAME_CACHE_MODEL);
|
||
}
|
||
|
||
void Factory::_load_sprite()
|
||
{
|
||
assert(_bSetPath);
|
||
// cache目录创建
|
||
const std::string PATH_CACHE = GetPathBinary2D();
|
||
File::CreateFolder(PATH_CACHE);
|
||
|
||
#if DL_PLATFORM == DL_PLATFORM_ANDROID
|
||
//_bUseBinary = true; // 提高加载速度
|
||
#endif
|
||
// 如果文件没有修改(或发布模式),则尝试从out目录加载纹理
|
||
if (!_bUseBinary)
|
||
{
|
||
for (auto& iter : _mapPathImage)
|
||
{
|
||
std::string name = iter.first;
|
||
std::string path = iter.second;
|
||
|
||
std::string path_out = PATH_CACHE + name;
|
||
if (!name.empty())
|
||
path_out += '/';
|
||
|
||
File::CreateFolder(path_out);
|
||
if (File::CheckPathFileModified(path, _ruleCheckImage, path_out + "files.json", true))
|
||
{
|
||
log_msg("开始读取2d资源从:{},并生成到:{} -> {}", path, path_out, name);
|
||
_load_sprite_sub(path, name, path_out);
|
||
}
|
||
else
|
||
{
|
||
log_msg("跳过读取2d资源从:{},{} -> {}", path, path_out, name);
|
||
}
|
||
}
|
||
}
|
||
_load_sprite_binary();
|
||
_load_animation();
|
||
}
|
||
|
||
void Factory::_load_sprite_binary()
|
||
{
|
||
const std::string PATH_CACHE = GetPathBinary2D();
|
||
|
||
_imp->_numTexStatic = 0;
|
||
|
||
// 纹理id映射
|
||
std::unordered_map<std::string, std::unordered_map<size_t, size_t>> map_tex_id;
|
||
|
||
auto fn_load = [&](bool trans){
|
||
for (auto& iter : _mapPathImage)
|
||
{
|
||
std::string name = iter.first;
|
||
std::string path = iter.second;
|
||
|
||
std::string path_out = PATH_CACHE + name;
|
||
if (!name.empty())
|
||
path_out += '/';
|
||
|
||
/*Json::DisableLog l;
|
||
json j = Json::ParseFile(path_out + "sprite.json", true);
|
||
if (j.is_null())
|
||
{
|
||
log_err("从缓存目录读取2d资源失败:{}", path_out);
|
||
continue;
|
||
}
|
||
FactoryImp::SpriteGroup spr_group;
|
||
if (!Json::Get(j, spr_group))
|
||
{
|
||
log_err("从缓存目录解析2d资源失败:{}", path_out);
|
||
continue;
|
||
}*/
|
||
|
||
StreamInput s;
|
||
if (!s.LoadFromFile(path_out + "sprite.json", true))
|
||
{
|
||
log_err("从缓存目录读取2d资源失败:{}", path_out);
|
||
continue;
|
||
}
|
||
FactoryImp::SpriteGroup spr_group;
|
||
s.Read(&spr_group._idTrans);
|
||
s.Read(&spr_group._allSpriteInfo);
|
||
s.Read(&spr_group._mapName2SpriteID);
|
||
|
||
size_t i, tex_size;
|
||
if (!trans)
|
||
{
|
||
i = 0;
|
||
tex_size = spr_group._idTrans._tex;
|
||
}
|
||
else
|
||
{
|
||
i = spr_group._idTrans._tex;
|
||
tex_size = spr_group._allSpriteInfo.size();
|
||
}
|
||
|
||
#ifndef DL_2D_TEXTURE_USE_KTX
|
||
for (; i < tex_size; ++i)
|
||
{
|
||
bool fail = false;
|
||
std::array<Image*, NUM_MIPMAP_2D> vec_image;
|
||
for (size_t j = 0; j < vec_image.size(); ++j)
|
||
{
|
||
std::string tex_path = fmt::format("{}{}_{}.png", path_out, i, j);
|
||
vec_image[j] = Img::Create(tex_path);
|
||
if (vec_image[j] == nullptr)
|
||
{
|
||
log_err("纹理加载失败:{}", tex_path);
|
||
fail = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!fail)
|
||
{
|
||
map_tex_id[name][i] = _imp->_numTexStatic;
|
||
log_msg("创建显存2d纹理:{},{}", _imp->_numTexStatic, path_out);
|
||
// 创建纹理资源(创建Canvas,并创建纹理)
|
||
g_vk->CreateCanvasImage(_imp->_numTexStatic++, vec_image);
|
||
}
|
||
for (size_t j = 0; j < vec_image.size(); ++j)
|
||
{
|
||
delete vec_image[j];
|
||
}
|
||
}
|
||
#else
|
||
for (; i < tex_size; ++i)
|
||
{
|
||
std::string tex_path = fmt::format("{}{}_fast.ktx", path_out, i);
|
||
std::string tex_path_full = fmt::format("{}{}.ktx", path_out, i);
|
||
map_tex_id[name][i] = _imp->_numTexStatic;
|
||
// 创建纹理资源(创建Canvas,并创建纹理)
|
||
g_vk->CreateCanvasImageKtx(_imp->_numTexStatic++, tex_path, tex_path_full);
|
||
}
|
||
#endif
|
||
if (trans)
|
||
{// 第二步再统一生成
|
||
assert(map_tex_id.contains(name));
|
||
std::unordered_map<size_t, size_t> map_id = map_tex_id[name];
|
||
|
||
// 生成全局名字,全局精灵id
|
||
for (auto& iter : spr_group._mapName2SpriteID)
|
||
{
|
||
std::string spr_name = iter.first;
|
||
std::vector<SpriteID>& vec_spr_id = iter.second;
|
||
|
||
if (!name.empty())
|
||
spr_name = name + '.' + spr_name;
|
||
|
||
for (auto& iter1 : vec_spr_id)
|
||
{
|
||
SpriteID id;
|
||
assert(map_id.contains(iter1._tex));
|
||
id._tex = map_id[iter1._tex];
|
||
id._rect = iter1._rect;
|
||
_imp->_sprGroup._mapName2SpriteID[spr_name].push_back(id);
|
||
|
||
// 特殊精灵处理
|
||
if (name.empty())
|
||
{
|
||
if (spr_name == ":white")
|
||
_imp->_idSolid = id;
|
||
else if (spr_name == ":white_trans")
|
||
_imp->_idSolidTrans = id;
|
||
}
|
||
}
|
||
}
|
||
// 生成全局精灵信息
|
||
for (size_t j = 0; j < spr_group._allSpriteInfo.size(); ++j)
|
||
{
|
||
std::vector<FactoryImp::SpriteInfo>& vec_info = spr_group._allSpriteInfo[j];
|
||
assert(map_id.contains(j));
|
||
size_t g_tex_id = map_id[j];
|
||
if (g_tex_id >= _imp->_sprGroup._allSpriteInfo.size())
|
||
_imp->_sprGroup._allSpriteInfo.resize(g_tex_id + 1);
|
||
|
||
std::vector<FactoryImp::SpriteInfo>& vec_info_g = _imp->_sprGroup._allSpriteInfo[g_tex_id];
|
||
vec_info_g = vec_info;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
fn_load(false);
|
||
_imp->_idTrans._tex = _imp->_numTexStatic;
|
||
fn_load(true);
|
||
|
||
log_msg("从缓存目录读取所有2d资源完成:\n"
|
||
"资源目录:{}\n"
|
||
"图像路径数:{}\n"
|
||
"纹理数:{}", PATH_CACHE, _mapPathImage.size(), _imp->_numTexStatic);
|
||
}
|
||
|
||
void Factory::_load_sprite_sub(std::string_view path, std::string_view name, std::string_view path_out)
|
||
{
|
||
// 遍历所有图像
|
||
std::vector<std::string> mul_file;
|
||
File::GetPathFileAll(path, mul_file, _ruleLoadImage);
|
||
|
||
std::list<FactoryImp::SheetNode> list_sheet_node_normal;
|
||
std::list<FactoryImp::SheetNode> list_sheet_node_trans;
|
||
|
||
|
||
//double USE_TIME = 0;
|
||
|
||
|
||
for (std::string& path_name : mul_file)
|
||
{
|
||
log_info("开始加载图片:{}", path_name);
|
||
// 0.image
|
||
Image* image = Img::Create(path_name);
|
||
if (!image)
|
||
continue;
|
||
|
||
// 公共数据
|
||
struct SheetInfo
|
||
{
|
||
std::string _anchor;
|
||
std::string _color;
|
||
};
|
||
// 划分为N个精灵
|
||
struct SheetNodeInfo
|
||
{
|
||
RectU _rect;
|
||
std::string _anchor;
|
||
std::string _color;
|
||
};
|
||
SheetInfo sheet_info;
|
||
std::vector<SheetNodeInfo> vec_node;
|
||
Size img_size = image->GetSize();
|
||
|
||
// 不同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");
|
||
Json::DisableLog l;
|
||
json j = Json::ParseFile(meta_name);
|
||
if (!j.is_null())
|
||
{
|
||
read_meta = true;
|
||
|
||
Json::Get(j, "anchor", sheet_info._anchor);// 公共锚点
|
||
Json::Get(j, "color", sheet_info._color);// 公共颜色
|
||
|
||
int split_mode = -1;
|
||
if(split_mode == -1)
|
||
{
|
||
// 平均分割
|
||
Size split;
|
||
if (Json::Get(j, "split", split))
|
||
{// 平均分割
|
||
split_mode = 0;
|
||
// 单图大小
|
||
Size wh = img_size / split;
|
||
// 子元素信息
|
||
for (unsigned y = 0; y < split.h; ++y)
|
||
for (unsigned x = 0; x < split.w; ++x)
|
||
{
|
||
size_t index = (size_t)(y * split.w + x);
|
||
SheetNodeInfo node;
|
||
node._rect = createRectU(PointU{ x * wh[0], y * wh[1] }, wh);
|
||
// 进一步获取独立信息
|
||
json j_spr;
|
||
if (Json::Get(j, "sprite_" + to_string(index), j_spr))
|
||
{
|
||
Json::Get(j_spr, "anchor", node._anchor);// 锚点
|
||
Json::Get(j_spr, "color", node._color);// 颜色
|
||
}
|
||
vec_node.push_back(node);
|
||
}
|
||
}
|
||
}
|
||
if (split_mode == -1)
|
||
{
|
||
// 按x、y线分割
|
||
std::vector<unsigned> vec_split_x;
|
||
std::vector<unsigned> vec_split_y;
|
||
Json::Get(j, "split_x", vec_split_x);
|
||
Json::Get(j, "split_y", vec_split_y);
|
||
if (!vec_split_x.empty() || !vec_split_y.empty())
|
||
{
|
||
std::vector<unsigned> vec_x;
|
||
vec_x.push_back(0);
|
||
vec_x.append_range(vec_split_x);
|
||
vec_x.push_back(img_size.w);
|
||
|
||
std::vector<unsigned> vec_y;
|
||
vec_y.push_back(0);
|
||
vec_y.append_range(vec_split_y);
|
||
vec_y.push_back(img_size.h);
|
||
|
||
size_t index = 0;
|
||
for (unsigned j = 0; j < vec_y.size() - 1; ++j)
|
||
{
|
||
unsigned top = vec_y[j];
|
||
unsigned bottom = vec_y[j + 1];
|
||
for (unsigned i = 0; i < vec_x.size() - 1; ++i)
|
||
{
|
||
unsigned left = vec_x[i];
|
||
unsigned right = vec_x[i + 1];
|
||
|
||
SheetNodeInfo node;
|
||
node._rect = { left, top, right, bottom };
|
||
// 进一步获取独立信息
|
||
json j_spr;
|
||
if (Json::Get(j, "sprite_" + to_string(index), j_spr))
|
||
{
|
||
Json::Get(j_spr, "anchor", node._anchor);// 锚点
|
||
Json::Get(j_spr, "color", node._color);// 颜色
|
||
}
|
||
vec_node.push_back(node);
|
||
++index;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!read_meta)
|
||
{
|
||
// Placements meta
|
||
std::string meta_name = String::EraseFilename(std::string_view{ path_name });
|
||
meta_name = fmt::format("{}Placements/{}.txt", meta_name, String::GetFileStem(path_name));
|
||
std::string str = File::GetString(meta_name);
|
||
if (!str.empty())
|
||
{
|
||
read_meta = true;
|
||
Position pos = String::toPosition2(str, '\n');
|
||
sheet_info._anchor = dl::to_string(-pos);
|
||
}
|
||
}
|
||
// 如果没有配置、或只有一个精灵
|
||
if (vec_node.empty())
|
||
{
|
||
SheetNodeInfo node;
|
||
node._rect = createRectU(img_size);
|
||
vec_node.push_back(node);
|
||
}
|
||
|
||
// 2.record
|
||
for (size_t i = 0; i < vec_node.size(); ++i)
|
||
{
|
||
SheetNodeInfo& node = vec_node[i];
|
||
FactoryImp::SheetNode img_rect;
|
||
img_rect._pathName = path_name;
|
||
img_rect._rect = node._rect;
|
||
img_rect._index = i;
|
||
img_rect._color = ColorDef::WHITE;
|
||
|
||
// 使用公共或独立锚点
|
||
if (!node._anchor.empty())
|
||
img_rect._anchor = Align::Anchor2Position(toPosition(Align::GetSize(node._rect)), node._anchor);
|
||
else
|
||
img_rect._anchor = Align::Anchor2Position(toPosition(Align::GetSize(node._rect)), sheet_info._anchor);
|
||
|
||
// 使用公共或独立颜色
|
||
if (!node._color.empty())
|
||
img_rect._color = createColor(node._color);
|
||
else
|
||
img_rect._color = createColor(sheet_info._color);
|
||
|
||
|
||
// 去透明空白部分
|
||
PointU lt = Align::GetLT(img_rect._rect);
|
||
//double t0 = g_time->GetCurrent64();
|
||
Img::CalcLeastRect(image, img_rect._rect);
|
||
//double t1 = g_time->GetCurrent64();
|
||
//USE_TIME += t1 - t0;
|
||
|
||
// 更新锚点
|
||
img_rect._anchor -= toPosition(Align::GetLT(img_rect._rect) - lt);
|
||
// 是否含有半透明颜色
|
||
bool is_have_translucent = Img::IsHaveTranslucent(image, img_rect._rect);
|
||
if (is_have_translucent)
|
||
list_sheet_node_trans.push_back(img_rect);
|
||
else
|
||
list_sheet_node_normal.push_back(img_rect);
|
||
}
|
||
delete image;
|
||
}
|
||
|
||
//log_test("拆切花费时间:{}", USE_TIME);
|
||
|
||
log_msg("开始加载图片路径资源:{}\n"
|
||
"非半透精灵:{}\n"
|
||
"半透精灵:{}\n"
|
||
"即将开始合并图集……", name, list_sheet_node_normal.size(), list_sheet_node_trans.size());
|
||
// 特殊精灵 添加到默认图集
|
||
if (name.empty())
|
||
{
|
||
list_sheet_node_normal.push_back({ ":white", 0,
|
||
createRectU(SIZE_SPRITE_DEFAULT), {}, ColorDef::WHITE });
|
||
list_sheet_node_trans.push_back({ ":white_trans", 0,
|
||
createRectU(SIZE_SPRITE_DEFAULT), {}, ColorDef::WHITE });
|
||
}
|
||
|
||
// 3.合并图集
|
||
TexturePack::Static pack;
|
||
pack.SetSize(SIZE_TEXTURE_2D_SIZE);
|
||
size_t pack_id = 0;//当前操作图集id
|
||
|
||
// tex id -> nrit
|
||
std::vector<std::list<FactoryImp::SheetNodeTarget>> all_snt;
|
||
|
||
// 获得大小(扩展像素)
|
||
auto fn_get_size = [](const FactoryImp::SheetNode& nri) {
|
||
return Align::GetSize(nri._rect) + SPRITE_EXTEND_SIZE;
|
||
};
|
||
// 成功加入操作
|
||
auto fn_call_back = [&](const FactoryImp::SheetNode& nri, const PointU& lt) {
|
||
// rect未变,lt为扩展后位置
|
||
all_snt[pack_id].push_back({ nri, lt });
|
||
};
|
||
// 直到全部添加
|
||
while (!list_sheet_node_normal.empty())
|
||
{
|
||
all_snt.push_back({});
|
||
pack.Calc(list_sheet_node_normal, fn_get_size, fn_call_back);
|
||
++pack_id;
|
||
}
|
||
// 记录id
|
||
size_t tex_id_trans = pack_id;
|
||
size_t rect_id_trans = 0;
|
||
//直到全部添加
|
||
while (!list_sheet_node_trans.empty())
|
||
{
|
||
all_snt.push_back({});
|
||
pack.Calc(list_sheet_node_trans, fn_get_size, fn_call_back);
|
||
++pack_id;
|
||
}
|
||
// 4.创建纹理、保存信息
|
||
|
||
// 多线程缩放图片
|
||
struct TaskResize
|
||
{
|
||
std::shared_ptr<Image> _img;
|
||
Image* _imgBig;
|
||
Size _size;
|
||
RectU _rect;
|
||
PointU _xy;
|
||
};
|
||
MultiThreadTask<TaskResize> mtt_resize;
|
||
auto fn_resize = [](const TaskResize& task)
|
||
{
|
||
Image* img_scale = Img::Resize(task._img.get(), task._size);
|
||
assert(img_scale);
|
||
Img::AddRect(task._imgBig, img_scale, task._rect, task._xy);
|
||
delete img_scale;
|
||
|
||
//log_info("mtt resize: {}", mtt_resize.GetTaskNum());
|
||
};
|
||
mtt_resize.Init(fn_resize);
|
||
|
||
// 多线程保存图片
|
||
struct TaskSave
|
||
{
|
||
#ifndef DL_2D_TEXTURE_USE_KTX
|
||
Image* _img;
|
||
#else
|
||
std::array<Image*, NUM_MIPMAP_2D> _vecImg;
|
||
#endif
|
||
std::string _pathName;
|
||
};
|
||
MultiThreadTask<TaskSave> mtt_save;
|
||
auto fn_save = [&](TaskSave& task)
|
||
{
|
||
#ifndef DL_2D_TEXTURE_USE_KTX
|
||
Img::Save(task._img, task._pathName);
|
||
log_info("输出图像: {}", task._pathName);
|
||
delete task._img;
|
||
#else
|
||
Img::SaveKtx(task._vecImg, task._pathName + ".ktx");
|
||
Img::SaveKtx(task._vecImg[2], task._pathName + "_fast.ktx");
|
||
log_info("输出图像: {}", task._pathName);
|
||
for (auto& iter : task._vecImg)
|
||
delete iter;
|
||
#endif
|
||
};
|
||
mtt_save.Init(fn_save);
|
||
|
||
|
||
//------------------------------------------
|
||
FactoryImp::SpriteGroup group;
|
||
size_t id_tex = 0;
|
||
for (auto& iter : all_snt)
|
||
{
|
||
// 整个大图 包含mipmap
|
||
std::array<Image*, NUM_MIPMAP_2D> vec_image_big;
|
||
unsigned size_big = SIZE_TEXTURE_2D;
|
||
for (size_t i = 0; i < vec_image_big.size(); ++i)
|
||
{
|
||
vec_image_big[i] = Img::Create(toLonger(size_big), ColorDef::NONE);
|
||
size_big >>= 1;
|
||
assert(size_big);
|
||
}
|
||
size_t id_rect = 0;
|
||
for (FactoryImp::SheetNodeTarget& snt : iter)
|
||
{
|
||
Image* p_image = nullptr;
|
||
bool b_reg_special = false;//是否以特殊精灵创建
|
||
if (snt._sheetNode._pathName == ":white")
|
||
{// 纯色精灵
|
||
p_image = Img::Create(SIZE_SPRITE_DEFAULT + SPRITE_EXTEND_SIZE,
|
||
ColorDef::WHITE);
|
||
b_reg_special = true;
|
||
_imp->_idSolid = { id_tex, id_rect };
|
||
}
|
||
else if (snt._sheetNode._pathName == ":white_trans")
|
||
{
|
||
p_image = Img::Create(SIZE_SPRITE_DEFAULT + SPRITE_EXTEND_SIZE,
|
||
ColorDef::WHITE);
|
||
b_reg_special = true;
|
||
_imp->_idSolidTrans = { id_tex, id_rect };
|
||
}
|
||
else
|
||
{
|
||
Image* image_src = Img::Create(snt._sheetNode._pathName);
|
||
Size size = Align::GetSize(snt._sheetNode._rect) + SPRITE_EXTEND_SIZE;
|
||
p_image = Img::Create(size, ColorDef::NONE);
|
||
Img::AddRect(p_image, image_src, snt._sheetNode._rect, SPRITE_EXTEND_XY);
|
||
Img::BuildBorder(p_image, SIZE_BORDER_SPRITE);
|
||
delete image_src;
|
||
}
|
||
std::shared_ptr<Image> image{ p_image };
|
||
assert(p_image);// image现在为处理后的小图
|
||
// 加入到大图
|
||
constexpr unsigned EDGE = 1;
|
||
Size image_size = image->GetSize();
|
||
RectU image_rect = createRectU(image->GetSize());
|
||
for (size_t i = 0; i < vec_image_big.size(); ++i)
|
||
{
|
||
if (i == 0)
|
||
Img::AddRect(vec_image_big[i], image.get(), image_rect, snt._lt);
|
||
else
|
||
{
|
||
Float scale = 1.0f / Math::Pow(2u, (unsigned)i);
|
||
Size size = image_size / Math::Pow(2u, (unsigned)i);
|
||
Every::ClampFloor(size, 1u);
|
||
RectU rect = toSize(toPosition(image_rect) * scale);
|
||
PointU lt = toSize(toPosition(snt._lt) * scale);
|
||
|
||
TaskResize task;
|
||
task._img = image;
|
||
task._imgBig = vec_image_big[i];
|
||
task._rect = rect;
|
||
task._size = size;
|
||
task._xy = lt;
|
||
|
||
//log_info("add task: {}, {}", rect, size);
|
||
mtt_resize.AddTask(task);
|
||
|
||
/*Image* img_scale = Img::Resize(image, size);
|
||
assert(img_scale);
|
||
Img::AddRect(vec_image_big[i], img_scale, rect, lt);
|
||
delete img_scale;*/
|
||
}
|
||
}
|
||
//--------------------记录Rect到Factory的_vecRectInfo----------------
|
||
//名字转换
|
||
std::string name;
|
||
if (!b_reg_special)
|
||
{// 不是特殊精灵才生成资源名
|
||
name = String::GetResName(path, snt._sheetNode._pathName);
|
||
}
|
||
else
|
||
name = snt._sheetNode._pathName;
|
||
|
||
// 构建 name,index -> SpriteID
|
||
std::vector<SpriteID>& vec_spr_id = group._mapName2SpriteID[std::string{ name }];
|
||
if (snt._sheetNode._index >= vec_spr_id.size())
|
||
vec_spr_id.resize(snt._sheetNode._index + 1);
|
||
SpriteID& spr_id = vec_spr_id[snt._sheetNode._index];
|
||
spr_id._tex = id_tex;
|
||
spr_id._rect = id_rect;
|
||
|
||
// 构建 SpriteID -> SpriteInfo
|
||
if (id_tex >= group._allSpriteInfo.size())
|
||
group._allSpriteInfo.resize(id_tex + 1);
|
||
std::vector<FactoryImp::SpriteInfo>& vec_info = group._allSpriteInfo[id_tex];
|
||
if (id_rect >= vec_info.size())
|
||
vec_info.resize(id_rect + 1);
|
||
FactoryImp::SpriteInfo& info = vec_info[id_rect];
|
||
|
||
snt._lt += SPRITE_EXTEND_XY;// 还原到图像扩展之前位置
|
||
info._rect = createRectU(snt._lt, Align::GetSize(snt._sheetNode._rect));
|
||
_imp->_rect_to_uv(info._rect, info._uv);
|
||
info._anchor = snt._sheetNode._anchor;
|
||
info._color = snt._sheetNode._color;
|
||
|
||
//delete image;
|
||
++id_rect;
|
||
}
|
||
|
||
mtt_resize.Wait();
|
||
|
||
#ifndef DL_2D_TEXTURE_USE_KTX
|
||
for (size_t i = 0; i < vec_image_big.size(); ++i)
|
||
{
|
||
TaskSave task;
|
||
task._img = vec_image_big[i];
|
||
task._pathName = fmt::format("{}{}_{}.png", path_out, id_tex, i);
|
||
mtt_save.AddTask(task);
|
||
}
|
||
|
||
#else
|
||
TaskSave task;
|
||
task._vecImg = vec_image_big;
|
||
task._pathName = fmt::format("{}{}", path_out, id_tex);
|
||
mtt_save.AddTask(task);
|
||
#endif
|
||
++id_tex;
|
||
}
|
||
|
||
mtt_save.Wait();
|
||
/*json j;
|
||
j = group;
|
||
|
||
Json::SaveFile(j, path_out + "sprite.json", true);*/
|
||
|
||
{
|
||
StreamOutput s;
|
||
s.Write(&group._idTrans);
|
||
s.Write(&group._allSpriteInfo);
|
||
s.Write(&group._mapName2SpriteID);
|
||
s.Save(path_out + "sprite.json", true);
|
||
}
|
||
|
||
|
||
log_msg("合并图集并导出信息完成:{} -> {}", name, path_out);
|
||
}
|
||
|
||
void Factory::_load_animation()
|
||
{
|
||
// 动画加载
|
||
for (auto& iter : _mapPathImage)
|
||
{
|
||
std::string name = iter.first;
|
||
std::string path = iter.second;
|
||
|
||
// 遍历所有文件夹下的 __animation.json
|
||
std::vector<std::string> mul_file;
|
||
File::GetPathFileAll(path, mul_file, "__animation.json");
|
||
|
||
for (std::string& path_name : mul_file)
|
||
{
|
||
log_info("开始加载动画:{}", path_name);
|
||
json j = Json::ParseFile(path_name);
|
||
if(j.is_null())
|
||
continue;
|
||
std::string res_name;
|
||
if (!name.empty())
|
||
{
|
||
res_name = fmt::format("{}.{}", name,
|
||
String::GetResName(path, path_name));
|
||
}
|
||
else
|
||
res_name = String::GetResName(path, path_name);
|
||
|
||
String::EraseExtension(res_name);
|
||
auto iter = _mapAnimationInfo.find(res_name);
|
||
if (iter != _mapAnimationInfo.end())
|
||
{
|
||
log_err("重复添加动画:{}", path_name);
|
||
continue;
|
||
}
|
||
|
||
AnimationInfo info = j;
|
||
_mapAnimationInfo[res_name] = info;
|
||
log_info("加载动画成功:{}\n"
|
||
"资源名:{}\n"
|
||
"数量:{}", path_name, res_name, info._allAni.size());
|
||
}
|
||
}
|
||
}
|
||
|
||
Factory::Factory() :
|
||
_bSetPath{ false },
|
||
_bUseBinary{ false },
|
||
_bOrderPickupShow{ false },
|
||
_idTemp{ 0 },
|
||
_orderPickup{ 1.0f }
|
||
{
|
||
_imp = new FactoryImp;
|
||
}
|
||
|
||
Factory::~Factory()
|
||
{
|
||
_save_cache();
|
||
delete _imp;
|
||
}
|
||
|
||
}
|
||
#endif |