以前 Simple2D 使用 TextureManager,现在将它改为 TexturePool (纹理池)。主要是负责加载和管理纹理,这次为 TexturePool 添加纹理集的功能,纹理集就是将大量的图片拼合成一张纹理。

  纹理集的制作

  你可以使用软件 TexturePacher 来创建纹理集:

  将图片文件拖曳到左边的窗口,然后将 Output 的 DataFormat 设置为 cocos2d,最后选择 Data File 和 Texture File 的输出路径,点击工具栏的 Publish 按钮后得到两个文件 xxx.plist 和 xxx.png,再将这两个文件放置在 Assert 文件夹即可。

  解析 Plist 文件

  由于 Plist 文件时 xml 格式的,所以可以使用 Tinyxml 库来解析,其中只需要读取 plist 文件的三个信息即可:

  1、纹理文件名,与小图相关联的标签

  2、小图的大小和小图在大图中的位置偏移,用来计算纹理坐标

  3、小图是否旋转,TexturePacher 在合并小图时为了合理分配空间位置,必要时会对小图旋转 90o,计算纹理坐标时要进行旋转

  OpenGL 为每个纹理分配一个唯一的 ID,而纹理集的多张小图都来自于一张纹理,为了管理这些纹理,需要两个结构:TextureUnique 和 Texture2D。TextureUnique 对于着一张纹理,而 Texture2D 则对应小图:

    struct Texture2D
{
TextureUnique* textureUnique; int width;
int height;
Vec2 uv[];
};

  Texture2D 保存图片的大小(该大小是小图的大小,不是纹理的大小)、纹理坐标和 TextureUnique 对象。

  TexturePool 使用 ParsePlistFile( ) 函数来解析 plist 文件:

bool TexturePool::ParsePlistFile(const std::string& filename, std::vector<PlistParseData>& ppd_list)
{
tinyxml2::XMLDocument doc; auto path = PathHelper::fullPath(filename);
if ( doc.LoadFile(path.c_str()) != tinyxml2::XML_NO_ERROR ) {
LOG_WRITE_DEBUG("不存在 plist 文件:%s", filename.c_str());
return false;
} tinyxml2::XMLElement* frame_ele = nullptr;
tinyxml2::XMLElement* context_ele = nullptr; tinyxml2::XMLNode* plist_node = doc.RootElement(); plist_node = plist_node->FirstChildElement();
frame_ele = plist_node->FirstChildElement(); tinyxml2::XMLElement* begin_node = frame_ele->NextSiblingElement()->FirstChildElement(); std::string left, right; while ( begin_node ) {
PlistParseData ppd; ppd.filename = begin_node->GetText();
context_ele = begin_node->NextSiblingElement(); context_ele = context_ele->FirstChildElement("string");
std::string size = context_ele->GetText(); /* {{xx, xx},{xx, xx}} */
left = size.substr(, size.find_first_of("}") - );
right = left.substr(left.find_first_of(",") + , left.size() - left.find_first_of(","));
left = left.substr(, left.find_first_of(",")); ppd.offsetx = atoi(left.c_str());
ppd.offsety = atoi(right.c_str()); right = size.substr(size.find_last_of("{") + , size.size() - size.find_last_of("{") - );
left = right.substr(, right.find_first_of(","));
right = right.substr(right.find_first_of(",") + , right.size() - right.find_first_of(",")); ppd.width = atoi(left.c_str());
ppd.height = atoi(right.c_str()); context_ele = context_ele->NextSiblingElement();
context_ele = context_ele->NextSiblingElement();
context_ele = context_ele->NextSiblingElement();
context_ele = context_ele->NextSiblingElement(); std::string rotate = context_ele->Name();
ppd.rotate = (rotate.compare("true") == ); begin_node = begin_node->NextSiblingElement();
begin_node = begin_node->NextSiblingElement(); ppd_list.push_back(ppd);
}
/* 获取图像文件名 */
frame_ele = frame_ele->NextSiblingElement();
frame_ele = frame_ele->NextSiblingElement();
frame_ele = frame_ele->NextSiblingElement(); tinyxml2::XMLElement* metadata = frame_ele->FirstChildElement("string");
std::string texture_name = metadata->GetText(); metadata = metadata->NextSiblingElement("string");
std::string texture_size = metadata->GetText(); int dot = texture_size.find_first_of(","); PlistParseData ppd;
ppd.filename = texture_name;
ppd.width = atoi(texture_size.substr(, dot - ).c_str());
ppd.height = atoi(texture_size.substr(dot + , texture_size.size() - dot - ).c_str()); ppd_list.push_back(ppd);
return true;
}

  将解析得到的小图数据保存到 PlistParseData 结构中,然后得到一个 PlistParseData 数组:

        struct PlistParseData
{
std::string filename;
bool rotate; int offsetx;
int offsety; int width;
int height;
};

  通过 PlistParseData 数组就可以创建 TextureUnique 和 Texture2D 对象了:

bool TexturePool::LoadFileFromPlist(const std::string& filename)
{
std::vector<PlistParseData> ppd_list;
if ( ParsePlistFile(filename, ppd_list) == false ) {
LOG_WRITE("解析文件 %s 失败!", filename.c_str());
return false;
} TextureUnique* texture_unique = new TextureUnique(ppd_list.back().filename.c_str()); for ( int i = ; i < ppd_list.size() - ; i++ ) {
PlistParseData& ppd = ppd_list[i]; Texture2D* texture_2d = new Texture2D;
texture_2d->textureUnique = texture_unique;
texture_2d->width = ppd.width;
texture_2d->height = ppd.height; /* 计算纹理坐标 */
Vec2 p1, p2;
if ( ppd.rotate ) {
p1.x = ( float ) ppd.offsetx / texture_unique->width;
p1.y = - ( float ) (ppd.offsety + ppd.width) / texture_unique->height; p2.x = ( float ) (ppd.offsetx + ppd.height) / texture_unique->width;
p2.y = - ( float ) ppd.offsety / texture_unique->height; texture_2d->uv[].set(p1.x, p1.y);
texture_2d->uv[].set(p1.x, p2.y);
texture_2d->uv[].set(p2.x, p2.y);
texture_2d->uv[].set(p2.x, p1.y);
}
else {
p1.x = ( float ) ppd.offsetx / texture_unique->width;
p1.y = - ( float ) (ppd.offsety + ppd.height) / texture_unique->height; p2.x = ( float ) (ppd.offsetx + ppd.width) / texture_unique->width;
p2.y = - ( float ) ppd.offsety / texture_unique->height; texture_2d->uv[].set(p1.x, p1.y);
texture_2d->uv[].set(p1.x, p2.y);
texture_2d->uv[].set(p2.x, p2.y);
texture_2d->uv[].set(p2.x, p1.y);
}
vTextureMap.insert(std::make_pair(ppd.filename, texture_2d));
}
return true;
}

  将得到的 Texture2D 对象保存到一个数组中,最后通过 TexturePool 提供的函数 Texture2D* GetTexture(const std::string& filename) 获取 Texture2D 对象。而 TextureUnique 则用于纹理的删除,但 TexturePool 并没有提供纹理的删除操作,也就是你无法再不需要纹理时删除纹理,只能在程序结束后删除。

  Texture2D 是 Sprite、Painter 和 ImGui 使用的图片渲染对象,而 TextureUnique 只是在 TexturePool 内部使用。

  源码下载:Simple2D-20.rar

最新文章

  1. LeetCode:Move Zeroes
  2. kafka设计原理介绍
  3. iOS开发——UI进阶篇(十)导航控制器、微博详情页、控制器的View的生命周期
  4. Scrum会议5(Beta版本)
  5. JNI函数复杂对象传递
  6. 【Javascript下载文件的Post实现】
  7. SQL表名,应该用复数还是单数
  8. HDU 5741 Helter Skelter(构造法)
  9. boostrap-非常好用但是容易让人忽略的地方------Font Awesome
  10. NOIP2014-普及组复赛-第一题-珠心算测验
  11. 定时任务schedule(quartz)
  12. DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)
  13. idea使用eclipse 代码format风格
  14. LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal 由前序和中序遍历建立二叉树 C++
  15. Caused by: java.io.FileNotFoundException: velocity.log (No such file or directory)
  16. Oracle数据块深入分析总结
  17. Python文本处理
  18. 潭州课堂25班:Ph201805201 并发(进程,线程)二 第十二课 (课堂笔记
  19. 微软Power BI 每月功能更新系列——12月Power BI 新功能学习
  20. 多线程系列(3)任务Task

热门文章

  1. log parser 微软iis 日志分析
  2. docker 知识点
  3. Tomcat 去除项目名称
  4. mysql 微信用户昵称emoji 完整保存
  5. jcFlexible.js的小Demo
  6. Android自动化测试中AccessibilityService获取控件信息(2)-三种方式对比
  7. Android免费短信验证
  8. lwip调试记录
  9. vmware linux NAT CON
  10. bzoj 3768: spoj 4660 Binary palindrome二进制回文串