QUAKE 3源代码评测:架构(第1部分,共5部分)>>

 

由于我在下一个合同(翻译可能有误)前一个星期,我决定完成我的“循环ID”。

Doom,DoomiPhoneQuake1Quake2中德军iPhone毁灭战士

 

我决定读最后一个代码库我还不审查:

 

idTech3的3D引擎,Quake III,quakelive

 

引擎主要是idTech2的演变,但有一些有趣的新奇。重点可归纳如下:

 

 

  • 第2部分:新的双核渲染器与基于物料的着色器(构建在OpenGL固定管道上)。

 

 

  • 第4部分:新型虚拟机在引擎中扮演重要角色,

 

  •  将Quake1 可移植性/安全性与 Quake2速度 (此处翻译可能有误……)相结合。

 

 

我特别印象深刻:

 

 

  • 虚拟机系统  和  相关的工具链  总共占发布的  代码  的 30%。
  •  
  • 在这种观点下,idTech3是一个小型操作系统,可以提供三个进程的系统调用。
  •  
  • 基于快照和内存自省的优雅网络系统。

 

像往常一样,我写了许多笔记

 

我已经清理并合成了图纸。

 

 

我希望能节省时间给一些人,

 

 

但也鼓励别人阅读更多的代码,成为更好的工程师。

 

 

第一次联系

 

由于最近ftp.idsoftware.com最近退役,

 

代码可以在id的GitHub帐户中找到 :

 

 

 
    git clone https://github.com/id-Software/Quake-III-Arena.git    


当谈到一个巨大的 代码库,

 

我更喜欢使用  XCode:SpotLight速度,

 

Command-click  查找   定义和字符串   高亮使得  该工具 比 Visual Studio 更强大。

 

 

 

但是打开Quake III项目表明,

 

代码腐烂   并不总是  关于代码,

 

还涉及到  这些工具:

 

XCode 4.0无法 打开   Quake III XCode 2.0项目。

 

 

最后我在  Windows 8 上      使用  Visual Studio 2010 Professional:

 

安装Visual Studio 2010生产力电动工具后 ,工具集实际上很愉快。

 

 

 

第一个引人注目的是Visual Studio工作区不是由一个项目组成的,

 

而是八个。

 

如果构建是DEBUG或RELEASE(特别gamecgameq3_ui虚拟机项目),

 

 

则不是全部使用它们。一些项目永远不会使用(splinesui)。

 

 

一个表格最好总结什么项目对哪个模块做出贡献:

 

 

项目类型DEBUG构建RELEASE构建注释
botlib静态库botlib.libbotlib.libAI
在CGame动态的Libary / Bytecodecgamex86.dll- 
game动态的Libary / Bytecodeqagamex86.dll- 
q3_ui动态的Libary / Bytecodeuix86.dll- 
QUAKE3可执行文件quake3.exe

quake3.exe

 

 
render静态库renderer.librenderer.lib

基于OpenGL的

 

splines

样条

曲线

静态库Splines.libSplines.lib使用NOWHERE!
UI动态的Libary / Bytecodeuix86_new.dll-用于Quake III Arena。

 

琐事: idTech3的工作题目是“三位一体”。

 

 

由于idTech4被称为“Neo”,

 

我认为它是从“Matrix”专营权...(电影中 取得 灵感 )

 

但是id软件在接受firingsquad.com的采访时指出,它以“达拉斯的三一河”命名:

 




    约翰:就研究而言,我有几件引擎的事情正在进行中。


    FS:那是三位一体呢?我认为“三位一体”有点混乱。


    约翰:我从来没有真的确定这是如何像所有人…………(此处有待进一步考察原文和重新翻译),


     何时我开始使用新的渲染技术 和 “所有 ”,


      每个人都称之为“下一个引擎” 


    不用太在意 。迈克尔·阿布拉斯(Michael Abrash)建议,


    我们只是采取英特尔在一条河附近命名您的下一个项目 您。


     我们在达拉斯拥有 三一river(地名),所以就像“三位一体引擎”一样,下一步。



    


约翰:就研究而言,我有几件引擎的事情正在进行中。



    FS:那是三位一体呢?我认为“三位一体”有点混乱。



    约翰:我从来没有真的确定这是如何像所有人一样混乱。震后,(此处翻译可能有误……)


     何时 我开始使用新的渲染技术和一切,每个人都称之为“下一个引擎” 



    不用太在意。迈克尔·阿布拉斯(Michael Abrash)建议,



    我们只是采取英特尔在一条河附近命名您的下一个项目


    您。我们在达拉斯拥有三一river,所以就像“三位一体引擎”一样,下一步。

    

 

 

编辑(2012年7月7日): Jeremiah Sypult在发表本文后联系了我:

 

他用“XCode 4.0”项目为“Quake3”Mac OS X构建“不动”。(此处 可能有误……)

 

我已经进一步修复了,

 

 

你可以在github上得到它。

 

 

您将需要Quake III Arenabaseq3(而不是演示版),

 

 

并确保 使用参数"+set vm_game 0 +set vm_cgame 0 +set vm_ui 0"以使用dylib虚拟机。

 

打开    /code/quake3.xcworkspace       它建立在一个点击……

 

 

 

架构 

 

 

了解架构的一个方便的方法是首先将软件视为 接收输入(左上箭头)

 

和生成输出(底部箭头)的 黑盒子:

 

然后查看输入如何以白盒方式与6个模块流向输出

quake3.exerenderer.libbot.libgamecgameq3_ui)的交互如下:

 

两个重要的事情要理解设计:

 

 

 

    1. 每个单个输入(键盘,win32消息,鼠标,UDP套接字)
  1.  
    1. 都转换成一个event_t集中的事件队列(sysEvent_t eventQue[256])。
  2.  
    1. 这允许其他事情记录(记录)每个输入,
    2.  
    3. 以重新创建错误。

      1998年10月14日约翰·卡马克的“计划”
    4.  
    5. 详细讨论了这一设计决策。

 

 

  1. 客户端和服务器的显式拆分(我在John Carmack的Q&A中概述了):
  2. 
      
      Fabien Sanglard:您认为如何总结idTech3的主要创新之外:
    
                           - 机器人IA 
    
    
                           - 虚拟机:结合QuakeC可移植性和Quake2 dll速度。
    
    
                           -  SMP&着色器渲染器。
    
    
    
                           - 新的网络代码。
    
    
    
     
        约翰·卡马克:
    
    明确将网络划分为客户端演示端和服务器逻辑端,
    
    
    这是真的对要做的事。
    
    
    我们退出了在Doom3和大部分 Rage,
    
    
    但我们正在迁移回去。
    
    
    
    所有的Tech3 许可证持有者被迫做更多的工作,
    
    以分析 架构实现单人效应,
    
    
    但事实证明  执法纪律确实有一个有价值的回报。
    
    
    Fabien Sanglard:您认为如何总结idTech3的主要创新之外:
                           - 机器人IA 
    
                           - 虚拟机:结合QuakeC可移植性和Quake2 dll速度。
                           -  SMP&着色器渲染器。
                           - 新的网络代码。
     
        
    
    约翰·卡马克:明确将网络划分为客户端演示端和服务器逻辑端,
    
    这是真的对要做的事。
    
        我们退出了在doom3和Rage的  很多做事方式?,(应该是重新制定了很多 做事方式?)
    
         但我们正在迁移回去。
    
    
    所有的Tech3 许可证持有者 “不得不”更多的 “漫撒汗水 ”,以探索 架构实现单人效应,
    
    但事实证明 “做事慎重 ”确实有一个 有价值的回报。
    
    
    
    • 服务器端负责维护游戏状态,确定客户需要什么,
    •  
    • 并通过网络传播。
    •  
    • 它是静态联系的,bot.lib因为它是一个单独的项目,
    •  
    • 因为它的《doom启示录 》第275页提到的混乱的发展历史:

       

         

          更糟糕的是,游戏的一个基本要素 “漫游器   ”失踪了。

    •  

    •    bot   机器人 是由   电脑   控制的字符。

    •  

    •   一个好的机器人会与动作和 模型 相融合

    •  

       

          像机器人的额外的场景,以及与玩家的互动。
    •  

    • 对于Quake III,终结 只有游戏,

    • 机器人是单人游戏动作所必需的。

 

    • 它们是隐含的复杂因为它们 不得不像“游戏中玩家”一样行事。

    •  

       

          

          卡马克决定第一次将创建这些bot 的工作委托给另一个机器人

          程序员在公司。但他没有跟进。卡马克再次失误……

          每个人都像自己一样自我激励和擅长。他错了

          

          当Graeme努力控制工作时,发现机器人完全无效。

          他们根本不喜欢人类。他们的行为基本上就像机器人一样。工作人员开始恐慌。

          到1999年3月,他们有理由害怕……

          (此处翻译可能有误……)

          

          最后,机器人已经被种植到荷兰知名的mod 制作者……,

    •  

    • 英国人带来了这个制造商 他们生活

    •  

    • (Fab的注释:这是Mr.Elusive:Jan Paul van Waveren)。

         

         

       

    • 客户端负责预测实体在哪里(延迟补偿)并呈现 视图。
    •  
    • 它与renderer项目静态链接:一个单独的项目,
    •  
    • 允许Direct3D甚至软件渲染器被非常容易地插入。
  1.  

代码

 

从代码的角度来看,这是一个部分展开的循环,用于说明客户端和服务器的事件生产和消耗:

    int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
    {
       
        Com_Init
        
        NET_Init
        
        而(1)
        {
            //通用代码 
            IN_Frame()   //将Win32操纵杆和鼠标输入作为event_t添加到统一的事件队列中。
            {
	             IN_JoyMove                                    
	             IN_ActivateMouse
	             IN_MouseMove
            }
	        
            Com_Frame
            {
                 //通用代码 
                 Com_EventLoop     //将win32消息,UDP套接字和控制台命令的泵送到队列(sysEvent_t eventQue [256]) 
                 Cbuf_Execute
                 
                 //服务器代码
                 SV_Frame
                 {
                     SV_BotFrame                                  //在bot.lib中跳转 
                     VM_Call(gvm,GAME_RUN_FRAME,svs.time)     //在游戏虚拟机中跳转,执行游戏逻辑
                     
                     SV_CheckTimeouts
                     SV_SendClientMessages                        //向连接的客户端发送快照或增量快照
                 } 
                 
                 //通用代码
                 Com_EventLoop
                 Cbuf_Execute
                  
                 //客户端代码
                 CL_Frame
                 {
                     CL_SendCmd                                  //泵送事件队列并发送命令到服务器。
                     
                     SCR_UpdateScreen
                        VM_Call(cgvm,CG_DRAW_ACTIVE_FRAME);   //发送消息到客户端虚拟机(做预测)。
                             要么
                        VM_Call(uivm,UI_DRAW_CONNECT_SCREEN); //如果菜单可见,则会将消息发送到UI虚拟机。
                     
                     S_Update                                    //更新声音缓冲区
                 }
            }
            
        }
    }

这是一个完全展开的循环,我在挖掘源代码时使用了一个地图。

 

一个有趣的事情要注意到,这完全说明了虚拟机的重要性:

 

没有任何地方可以看到RE_RenderScene:执行剔除和发出OpenGL命令的功能。

 

相反,发生的是:

 

  1. Quake3.exe向  客户端VM  发送 消息:CG_DRAW_ACTIVE_FRAME哪个表示需要刷新。

 

 

  1. 虚拟机执行一些  实体剔除  和  预测,

 

 

  1. 然后通过Quake3系统调用(CG_R_RENDERSCENE)调用OpenGL再现。

 

  1.  
  2. Quake3.exe接收系统调用,实际调用 RE_RenderScene

 

    OpenGL Quake3.exe客户端虚拟机
   -------- ---------- ----------------------
      | | |
      | | |
      | VM_Call(CG_DRAW_ACTIVE_FRAME)-----------------> CG_DrawActiveFrame
      | | CG_DrawActive
      | | trap_R_RenderScene
      | | 系统调用(CG_R_RENDERSCENE,fd)
      | RE_RenderScene <-------------------------------------- |
      | | |
      | <---------------------- | |
      | | |
      
              

 

统计

 

这里有一些来自cloc的统计资料:

    -------------------------------------------------- ---------------------------------------------
                                                 文件空白评论代码
    -------------------------------------------------- ---------------------------------------------
    cloc-1.56.exe代码共享559 48630 73501 233952
    cloc-1.56.exe lcc 116 2270 1513 28067
    cloc-1.56.exe q3asm q3map 44 4987 5565 22877
    cloc-1.56.exe q3radiant 206 11870 13113 54922
    -------------------------------------------------- ---------------------------------------------
    共计919 68293 95509 341994
    -------------------------------------------------- ---------------------------------------------

 

在 饼图上,我们可以生动地看到这个比例是多么 的不寻常,

 

因为30%的代码库专门用于工具:


部分原因是 因为idtech3具有ANSI C编译器:开源Little C Compiler(LCC)用于为虚拟机生成字节码。

 

内存分配

 

两个定制分配器在这里工作:

 

  • 区域分配器:负责运行时,小型和短期内存分配。

 

  • Hunk分配器:负责从pak文件(几何,地图,纹理,动画)的级别负载,
  •  
  • 大型和长期分配。

 

更美好的明天

 

 

有了这个代码审查,似乎我跑出了伟大的3D引擎源代码阅读。

 

但是CG世界正在走很多伟大的事情。

 

我特别期待着Occulus Rift VR工具包:

 

构建,编码和 理解测试台将会很有趣。它应该在7月下旬直到那时止:快乐的技巧 !

 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐