quake2源码分析(一)

灬瑷昧灬

灬瑷昧灬

2016-02-19 14:19

给自己一点时间接受自己,爱自己,趁着下午茶的时间来学习图老师推荐的quake2源码分析(一),过去的都会过去,迎接崭新的开始,释放更美好的自己。
 

quake2源码分析(一)

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

  
  我希望通过quake2的源码分析来理解这个优秀引擎的动作方式。
  由于我比较熟悉delphi的代码组织方式,故从http://www.sourceforge.net/quake2delphi/下载了quake2的delphi代码来进行分析。
  说明:为了描述的简单化,我没有对细节方面进行描述。

  下面让我们进入正题:
  起始点:
  sys_win: WinMain 这是我们非常熟悉的windows入点

(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)

    Qcommon_Init  //qcommon是通用模块,进行通用模块的初始化,这个步骤处理的东西相当多,下一步会详细讲解
    while(true)
     Qcommon_Frame(time) //绘制每一帧

  简单地说WinMain要处理的主要就是这两步操作

  
  下面让我们分析一下初始化操作:
   Qcommon_Init的内容

  //一 初始化z_chain
      z_chain.prev := @z_chain;
      z_chain.next := z_chain.prev;
  //二 初始化参数
      COM_InitArgv(argc, argv);
  //三 初始化交换算法及命令行缓冲区
      Swap_Init;
      Cbuf_Init;
  //四 命令解释器的初始化
      Cmd_Init;
  //五 变量操作的初始化
      Cvar_Init;
  //六 键盘映射表初始化
      Key_Init;

  //七 初始化命令行,然后初始化文件系统
      Cbuf_AddEarlyCommands(False);
      Cbuf_Execute;

      FS_InitFilesystem;
  //八 运行脚本
      Cbuf_AddText('exec default.cfg'#10);
      Cbuf_AddText('exec config.cfg'#10);

      Cbuf_AddEarlyCommands(True);//添加命令行并将参数清空
      Cbuf_Execute;
  //九 初始化变量
      Cmd_AddCommand('z_stats', Z_Stats_f);
      Cmd_AddCommand('error', Com_Error_f);

      host_speeds := Cvar_Get('host_speeds', '0', 0);
      log_stats := Cvar_Get('log_stats', '0', 0);
      developer := Cvar_Get('developer', '0', 0);
      timescale := Cvar_Get('timescale', '1', 0);
      fixedtime := Cvar_Get('fixedtime', '0', 0);
      logfile_active := Cvar_Get('logfile', '0', 0);
      showtrace := Cvar_Get('showtrace', '0', 0);
  {$IFDEF DEDICATED_ONLY}
      dedicated := Cvar_Get('dedicated', '1', CVAR_NOSET);
  {$ELSE}
      dedicated := Cvar_Get('dedicated', '0', CVAR_NOSET);
  {$ENDIF}
  //十 设置版本
      s := va('%4.2f %s %s %s', [VERSION, CPUSTRING, __DATE__, BUILDSTRING]);
      Cvar_Get('version', s, CVAR_SERVERINFO or CVAR_NOSET);

      if (dedicated.value 0) then
        Cmd_AddCommand('quit', Com_Quit);
  //十一:初始化系统(控制台)
      Sys_Init;
  //十二:初始化网络 及 端口
      NET_Init;
      Netchan_Init;
  //十三 初始化服务端
      SV_Init;
  //十四 初始化客户端
      CL_Init;

  //十五:如果用户没有输入+命令,而且没有要显示“献给”标志,则显示演示程序
    // add + commands from command line
      if not Cbuf_AddLateCommands then
      begin                               // if the user didn't give any commands, run default action
        if (dedicated.value = 0) then
          Cbuf_AddText('d1'#10)
        else
          Cbuf_AddText('dedicated_start'#10);
        Cbuf_Execute;
      end
      else
      begin                               // the user asked for something explicit
        // so drop the loading plaque
        SCR_EndLoadingPlaque;
      end;
  十六  结束
      Com_Printf('====== Quake2 Initialized ======'#10#10, []);

   

  接下来对qcommon_init的十六步操作进一步分析

  一:初始化z_chain
  这就引出了对z_chain的理解,z_chain是quake独创的一种数据链表,用以管理分配的内存空间,以保证临时申请的内存能正确地释放。
  每一次内存分配请求会调用common的z_malloc来分配,z_malloc调用Z_TagMalloc来分配带标志的内存空间。
  我们来看一下z_chain的类型zhead_t的定义
    zhead_s = record
      prev, next: zhead_p;//典型的链表
      magic: SmallInt; //一个标志位,保留const Z_MAGIC = $1D1D;
      tag: SmallInt;      // 用以成批释放,看来类似于gc的概念
      size: Integer; //所分配的内存块的大小(包括zhead_s的大小)
    end;
    zhead_t = zhead_s;
  二 初始化参数
   将命令行数据存入 com_argc_ 及com_argv_[]

  三 初始化交换算法及命令行缓冲区
   为了适应不同的cpu结构,在程序中判断是否大印第安格式还是小印第安格式,我的p4 cpu上是小印第安格式。
   给命令行缓冲区分配内存

  
  四 命令解释器的初始化
  初始化命令解释器。quake有一个很独特的模式,就是采用的是命令行配合全局变量驱动方式。这让我想起了古老的dos操作系统。
  这种方式的优点是模块之间的耦合度可以很低。也很容易配置。
  这一步中添加了以下几条默认命令
  cmdlist:列出所有可用的命令
  exec:运行脚本
  echo: 显示文本
  alias 显示别名
  wait  等待

  
  五 变量操作的初始化
  添加了以下用于操作变量的命令
  set  设置变量
  cvarlist 列出变量

  
  六 键盘映射表初始化
  定义了默认的键盘映射表
  添加了用于操作键盘映射表的命令
  bind 将一个键绑定到一个字符上
  unbind 取消一个键的绑定
  unbindall 取消所有键的绑定
  bindlist  显示绑定列表

  
  七 初始化命令行,然后初始化文件系统
  将命令行参数传入,设置好初始化文件系统所需的变量,然后初始化文件系统

  八 运行脚本
     运行default.cfg 
     运行config.cfg  
     用命令行传入的参数覆盖现有变量,也就是说命令行传入的参数有较高的优先级

  九 初始化变量
     添加命令:
       z_stats: 显示分配的内存大小及块数
       error:抛出一个异常,估计用于测试异常

      添加以下变量: 
      host_speeds 主机程度
      log_stats   日志状态
      developer   开发?
      timescale   时间刻度
      fixedtime   固定时间?
      logfile_active 日志是否活动
      showtrace  是否显示跟踪信息
  {$IFDEF DEDICATED_ONLY}  是否是献词版本
      dedicated := Cvar_Get('dedicated', '1', CVAR_NOSET);
  {$ELSE}
      dedicated := Cvar_Get('dedicated', '0', CVAR_NOSET);
  {$ENDIF}
  十 设置版本
     设置软件版本变量
  十一:初始化系统(控制台)
     这步操作是为了能像dos窗口一下输入命令

  十二:初始化网络 及 端口
   这里初始化端口有一个小技巧,采用了毫秒的最后四位作为端口,不过我没有看到端口冲突的解决方法。大概因为这个概率很小的原因吧。

  十三 初始化服务端
  添加了服务端要用到的命令及变量

  十四 初始化客户端
  初始化控制台
  初始化渲染模块vid_dll
  初始化声音模块
  初始化视图用的命令
  初始化菜单
  初始化屏幕
  初始化cd声音
  初始化本地操作命令
  初始化 input
  运行autoexec.cfg脚本

  
  十五:如果用户没有输入+命令,而且没有要显示“献给”标志,则显示演示程序

  至此,第一阶段分析告一段落。

展开更多 50%)
分享

猜你喜欢

quake2源码分析(一)

编程语言 网络编程
quake2源码分析(一)

源码学习:一个简单的日历控件(2)

电脑网络
源码学习:一个简单的日历控件(2)

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

Java源码分析:深入探讨Iterator模式

Java JAVA基础
Java源码分析:深入探讨Iterator模式

jsp源码实例2(获取表单参数)

Java JAVA基础
jsp源码实例2(获取表单参数)

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

jsp源码实例2(获取表单参数)

Java JAVA基础
jsp源码实例2(获取表单参数)

取得汉字的笔画的源码(2)

编程语言 网络编程
取得汉字的笔画的源码(2)

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

(delphi)程序运行过程中等待对话框的自定义组件源码(包含两个提

(delphi)程序运行过程中等待对话框的自定义组件源码(包含两个提

CSS常用技巧汇总

CSS常用技巧汇总
下拉加载更多内容 ↓