在HL引擎中制作自定义高清贴花
你是不是想过要做自定义的子弹孔、喷漆或者一些自定义的痕迹呢?
如果按照HL引擎的基本FA,首先要在decals.wad里加入我们自定义的纹理,然后利用gEngfuncs.pEfxAPI->R_DecalShoot或者服务端发送TE_DECAL消息来使用。
这种方法有许多限制,首先你不能往一个WAD文件加太多纹理,其次,WAD只能保存索引色的纹理(图像质量非常LOW)。如果我们要更进一步定制,比方说做个会动的喷漆,那么WAD就不行了。
首先我要声明一下名词:
Decal 即 贴花,指贴在地图表面的图像。
这篇文章给出一种方法让你能够使用自己加载的纹理进行贴花,还可以做到实时更新贴花,做出动态效果。
首先我们认识一下引擎提供的一个贴花函数 R_DecalShoot ,它的原型如下:
void R_DecalShoot( int textureIndex, int entity, int modelIndex, vec3_t position, int flags )
第1个参数 textureIndex 通常你必须这样来获得: pEfxAPI->Draw_DecalIndex( pEfxAPI->Draw_DecalIndexFromName("{yblood6") ) ,这个名称必须是decals.wad里存在的,否则函数将会失败。
第2个参数 entity 贴花将会贴到该实体的模型上,该实体的模型必须是 mod_brush ,你必须提供这个实体,否则函数将会失败。
第3个参数 modelIndex ,如果 entity 参数提供的实体没有设置模型,将会使用此参数指定的模型 ,否则忽略此参数。
第4个参数 position 贴花的坐标。世界坐标。
第5个参数 flags 该参数可以指定为 FDECAL_ 相关的标志。
我们并不想通过这个 textureIndex 来指定纹理,我们需要自己改造一个 R_DecalShoot 。非常幸运的是,HL引擎的写法让我们可以简单地实现。
我们来看看 R_DecalShoot 内部是怎么实现的:
可以看到,它首先通过调用一个名为 Draw_DecalTexture 的函数获得一个 texture_t 的指针,然后将该指针传给一个名为 R_DecalShoot_ 的函数(注意,后面有个下划线)。
可以猜测,我们自己创建一个 texture_t 然后调用 R_DecalShoot_ 应该是没问题的。
所以我先提供这个结构体的定义:
typedef struct texture_s
{
char name[];
unsigned int width, height;
unsigned int gl_texturenum;
void *texturechain;
int anim_total;
int anim_min, anim_max;
void *anim_next;
void *alternate_anims;
unsigned int offsets[];
void *pPal;
} texture_t;
看似很复杂,其实只需要指定其中的 width、height、gl_texturenum 这3个即可,其它的全部设为0。
既然我们要调用 R_DecalShoot_ ,那么就得知道它的原型:
void R_DecalShoot_( texture_t *ptexture, int textureIndex, int entity, int modelIndex, float *position, int flags, float scale )
可以看出这个函数和 R_DecalShoot 非常像,但聪明的你可能已经发现了问题,既然都有一个 ptexture 来指定纹理了,干嘛还需要一个 textureIndex 呢,不是多此一举吗?
解释如下:引擎为了节省内存占用,时不时会将一些不经常访问的资源丢弃掉,这时 ptexture 就可能会被丢掉(释放掉),所以引擎只为贴花存储一个 textureIndex 当引擎绘制贴花时,
会使用 textureIndex 来查找一个 texture_t ,如果这个 texture_t 已经被丢弃了,那么引擎会重新载入它。
可能你还有疑问,既然传 textureIndex 一本万利,干嘛要传 ptexture 呢。那是因为 R_DecalShoot_ 需要 texture_t 里的 width 和 height 。
但是,根据上面的解释,引擎在绘制贴花时才通过 textureIndex 来查找 texture_t ,所以我们需要Hook那个查找函数,返回我们自己的 texture_t 才行。
那个函数上面已经出现过了,它就是 Draw_DecalTexture ,它的原型如下:
texture_t * Draw_DecalTexture( int textureIndex )
你可以看到它只有一个 int 参数,当引擎需要绘制一个贴花时,会调用这个函数来获取一个 texture_t ,而参数的 textureIndex 正是我们传入 R_DecalShoot 的那个。
现在尝试一下,首先我们要自己造一个 R_DecalShoot ,例如:
void R_My_DecalShoot( texture_t *ptexture, int textureIndex, int entity, int modelIndex, float *position, int flags )
{
R_DecalShoot_( ptexture, textureIndex, entity, modelIndex, position, flags, 1.0f );
}
然后还要Hook Draw_DecalTexture 函数,例如:
texture_t * Draw_DecalTexture( int textureIndex )
{
if ( textureIndex == )
{
return &g_my_texture;
} return g_callback_Draw_DecalTexture( textureIndex );
}
我这里判断 textureIndex 如果是999那么返回我们自己创建的一个 texture_t
然后调用 R_My_DecalShoot ,例如:
void Decal_Test( void )
{
R_My_DecalShoot( &g_my_texture, , ent, , tr.endpos, );
}
这里我给 textureIndex 传了 999 这个数值,如果贴花创建成功,引擎会把这个值存储到引擎内部的神秘数组里。
等到引擎需要绘制这个贴花时,便会调用 Draw_DecalTexture 来获取 texture_t 用于绘制。这时我们检查 textureIndex 是不是我们定义的,
如果是我们定义的,那就返回我们自己创建的 texture_t 给引擎绘制。
大功告成!
附上一张效果图:
附加:
你可能想立刻删掉一个贴花,那么你可以使用如下方法:
gEngfuncs.pEfxAPI->R_DecalRemoveAll( textureIndex )
注意:该方法会删除所有 textureIndex 为指定的值的贴花,所以建议给 textureIndex 再包装一层,使得每个贴花拥有独立的索引,而不是靠纹理索引来区分。
核能注意: textureIndex 是 short 型的,能存储的数值范围有限!
函数 R_DecalShoot_ 的地址:
0x01D4B530 //
0x01D49750 //
函数 Draw_DecalTexture 的地址:
0x01D321F0 //
0x01D2EB30 //
在HL引擎中制作自定义高清贴花的更多相关文章
- Android中制作自定义dialog对话框的实例
http://www.jb51.net/article/83319.htm 这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继 ...
- Cocos2D iOS之旅:如何写一个敲地鼠游戏(二):Cocos2D中的高清支持
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...
- 如何在Google上下载高清原图
在我们学习和生活中常常一些高清图片作为相关的素材,比如制作PPT.写博文.制作视频都需要大量图片.我们常常会在百度上下载一些图片,但是百度上提供的图片存在很多问题:存在水印.清晰度不够等.而Googl ...
- cocos2d-x 2.0.3 设置高清模式注意事项(已移除-hd方式)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=304 在cocos2d-x 2. ...
- 故障解决 | win10没声音及找不到Realtek高清音频管理器
重装 win10 系统后,电脑没声音,更新驱动以及万不得已下载驱动精灵都没有解决. 后来发现在“硬件和声音”中没有Realtek高清音频管理器,之后找到解决办法如下: 1. 找到Realtek高清音频 ...
- 面包板入门电子制作(class1)视频 全套30集高清
面包板入门电子制作(class1)套件(30集高清) 本套件以电子制作中最基础的元器件在面包板上搭建电路,用启发性的视频教学方式,使学习者熟悉电子电路基础.发挥想像力.在创新设计和制作中学会独立设计和 ...
- cocos2D v3.4 在TileMap中开启高清显示
在Tiled中制作一幅地图,用的图片砖块分辨率为32x32. iOS设备为iPhone 4s. 在未打开高清屏支持的cocos2d v2.x版本中,运行log显示480x320.遂启用高清屏支持: [ ...
- 第二十八篇、自定义的UITableViewCell上有图片需要显示,要求网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示图片缩略图
1)SDWebImage会自动帮助开发者缓存图片(包括内存缓存,沙盒缓存),所以我们需要设置用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图. 2)许多 ...
- 高清语音技术(WBS)及其在手机和蓝牙耳机中的实现
高清语音也被称为宽带语音,是一种能为蜂窝网络.移动电话和无线耳机传输高清.自然语音质量的音频技术.与传统的窄带电话相比,高清语音很大程度上提高了语音质量,减少了听觉负担. 通信产业链上的所有网络和设备 ...
随机推荐
- 神器 Tmux 的超绝便利
服务器的任务不间断运行,就是利用了 tmux 的特性.就是说,一般 ssh 是断开就会停止所有之前连接 ssh 期间运行的所有 processes,而 tmux 的核心业务不在于把屏幕分成几块好看,而 ...
- ATmega8仿真——键盘扫描的学习
1.按键的使用特点 按键的应用主要是在按键闭合时改变电路的电平,但是一般情况下按键的开关都是机械弹性触点开关,即利用触点的接触和分离来实现电路的通断,所以在按键按下和释放时往往会产生抖动干扰. 消除抖 ...
- Qt-网易云音乐界面实现-8 主导航的实现-QtabWidget
哎呀,堕落了,快有小两周没哟更新了,是在是没有动力了,浏览量连三位数都没有,是在是没有写下去的信心. 还有就是这个网易云音乐的代码量绝对是不可小视的,完全低估了这个软件的能量.昨天仔细想了一下,写不下 ...
- SecureCRT 用法总结
SecureCRT 用法总结 1.下载与破解方法: Mac:https://www.jianshu.com/p/9427f12b1fdb Window:https://drive.google.c ...
- 通俗理解BFS和DFS,附基本模板
1.BFS(宽度优先搜索):使用队列来保存未被检测的节点,按照宽度优先的顺序被访问和进出队列 打个比方:(1)类似于树的按层次遍历 (2)你的眼镜掉在了地上,你趴在地上,你总是先摸离你最近的地方,如果 ...
- Jenkins管理插件(备份插件)
Jenkins管理插件 为了让所有的插件在 Jenkins 内可用,所有插件的列表可以访问链接 − https://wiki.jenkins-ci.org/display/JENKINS/Plugin ...
- shell中与运算 cut切分行 if while综合在一起的一个例子
前言: 公司要统计 treasury库hive表磁盘空间,写了个脚本,如下: 查询hive仓库表占用hdfs文件大小: hadoop fs -du -h /user/hive/warehouse/t ...
- 占位符golang
定义示例类型和变量 type Human struct { Name string } var people = Human{Name:"zhangsan"} 普通占位符 占位符 ...
- Vue.js 相关知识(组件)
1. 组件介绍 组件(component),vue.js最强大的功能之一 作用:封装可重用的代码,通常一个组件就是一个功能体,便于在多个地方都能调用该功能体 根组件:我们实例化的Vue对象就是一个组件 ...
- IE10不能显示JSON文件内容
IE7,8,9下Ajax返回后,再执行跳转,会弹出阻止提示框. 所以我采用WebForm 提交思想: //导出 jv.postOpen = jv.PostOpen = jv.Export = func ...