心血来潮,突然想看Quake 2的代码,折腾一下,终于在VS 2015编译成功,项目在oraoto/quake2-vs2015。
这篇文章记录一下实现的过程。
下载Quake 2源码
Quake 2代码已经开源,可以在Github或id Software的FTP下载。我从FTP下的,所以没fork Github上的仓库。
升级项目
解压后找到quake2.dsw
,这是VC++ 6的项目,用VS 2015打开会提示升级项目:
确认升级即可。
修复编译错误
先尝试在Debug模式下编译,会有很多错误,这些错误都是升级项目过程中产生的。
- '/ZI' and '/Gy-' command-line options are incompatible
每个项目都打开Enable function-level Linking
即可。 - LNK1181 cannot open input file '...\debug\.obj'
编译ref_soft
软件渲染器时会出现这个错误,没有正确输出汇编的编译结果,要打开ref_soft.vcxproj
手工修改
找到CustomBuild
,里面有些这样的项:
把<Outputs Condition="...">$(OUTDIR)\$(InputName).obj;%(Outputs)</Outputs>
$(InputName)
改成%(Filename)
就可以了 - LNK 2026 module unsafe for SAFESEH image
把ref_soft
项目的Linker->Advanced->Image Has Safe Exception Handlers
改成No即可。 - 关闭DEP
把每个项目的Linker->Advanced->Data Execuation Prevention
关掉。
经过这些修改,就能正常跑起软件渲染器了。
支持OpenGL渲染器
不管是Steam上卖的Quake 2和上面编译的都跑不了OpenGL,调试发现是在打印日志的时候出错。
在初始化OpenGL的时候有这么两句(在ref_gl/gl_rmain.c/R_Init
):
gl_config.extensions_string = qglGetString (GL_EXTENSIONS);
ri.Con_Printf (PRINT_ALL, "GL_EXTENSIONS: %s\n", gl_config.extensions_string );
就是获取显卡支持的OpenGL扩展,然后打印。现在的显卡都支持很多扩展,我的有300多个,整个字符串就超过了打印函数定义的4096字节,就溢出了。
所以把vid_dll.c
里的MAXPRINTMSG
和qcommon/common.c
的MAXPRINTMSG
改到足够大就可以了。也可以去掉打印语句,更简单。
重新编译后就可以用OpenGL了:
回顾
做了很多第一次做的事,有时只是凭感觉去尝试。
例如改DEP设置,是因为看到错误信息:Access violation **executing** location
,我猜是程序去执行了非代码的内存,去看触发的代码是这样的:
align 4
public _R_Surf8Patch
_R_Surf8Patch:
push ebx
mov eax,ds:dword ptr[_colormap]
mov ebx,offset LPatchTable8
mov ecx,32
LPatchLoop8:
mov edx,ds:dword ptr[ebx]
add ebx,4
mov ds:dword ptr[edx],eax
dec ecx
jnz LPatchLoop8
pop ebx
ret
居然是汇编,一脸懵逼啊。还好想到ASLR和DEP,于是试一试,发现可以。
再说OpenGL,起初怕有很复杂的原因导致跑不了,一调试才发现居然只是普通的内存溢出。
试一试总比直接放弃好。
接下来就要看代码了,感觉自己水平不够,好难啊……