程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> quake2源碼分析(一)

quake2源碼分析(一)

編輯:Delphi
 

quake2源碼分析(一)

  
  我希望通過quake2的源碼分析來理解這個優秀引擎的動作方式。
  由於我比較熟悉delphi的代碼組織方式,故從http://www.sourceforge.net/quake2delphi/下載了quake2的delphi代碼來進行分析。
  說明:為了描述的簡單化,我沒有對細節方面進行描述。

  下面讓我們進入正題:
  起始點:
  sys_win: WinMain 這是我們非常熟悉的windows入點

    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腳本

  
  十五:如果用戶沒有輸入+命令,而且沒有要顯示“獻給”標志,則顯示演示程序

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved