ioquake笔记

wiki :http://wiki.ioquake3.org

目录结构

  • misc:各个工程和配置文件
    • msvc/msvc10
    • nsis
    • osxfe/setup
    • ico图标和照片文件
  • code:代码文件
    • AL:OpenAL的头文件
    • asm:汇编代码
    • botlib
    • cgame
    • client
    • game
    • 相关lib:jpeg-8c、libcurl、zlib、libspeex音频编解码库
    • null:内容和sdl目录下基本对应
    • q3_ui
    • qcommon
    • renderer
    • sdl:对sdl的部分包装,glimp、gamma、icon、input、snd
    • SDL12: SDL的头文件
    • server
    • sys:主程序的入口出
    • tools
    • ui
  • ui:txt文件存放得是要加载的菜单名
  • Makefile
  • cross-make-*
  • pak0.pk3
  • README
  • TODO
    主要的代码在code下的sdl、qcommon、server、client、sys、renderer、game、cgame、botlib中

主流程框架

windwos中的主入口是在WinMain函数中,Winmain函数还是调用的main函数。linux的main函数在:code/sys/sys_main.c,后面的代码分析只看linux平台的。

main函数流程

  • SDL最小版本判断
  • Sys_PlatformInit,平台初始化,根据平台两个函数实现不太一样
    Windows: code/sys/sys_win32.c
    Unix: code/sys/sys_unix.c
	const char* term = getenv( "TERM" );  //获取环境变量, getenv是系统函数
	signal( SIGHUP, Sys_SigHandler );  //创建信号,signal是系统函数,
	其他几个信号,也是关联到了Sys_SigHandler上,SIGQUIT、SIGTRAP、SIGIOT、SIGBUS
	stdinIsATTY = isatty( STDIN_FILENO ) &&
		!( term && ( !strcmp( term, "raw" ) || !strcmp( term, "dumb" ) ) ); 

isatty:检查设备类型 , 判断文件描述词是否是为终端机。stdinIsATTY 是true
STDIN_FILENO:三个流(标准输入、标准输出和标准出错)中的一个。UNIX系统shell使用文件描述符0与进程的标 准输入相关联,文件描述符1与标准输出相关联,文件描述符2与标准出错相关联。
Sys_SigHandler:信号处理,推测出程序,CL_Shutdown和SV_Shutdown和Sys_Exit

  • Sys_Milliseconds: 获取当前时间,用gettimeofday,然后做一次时间转换
  • Sys_ParseArgs: main中输入的参数解释,只解释了–version和-v
  • 获取应用程序路经存放在binaryPath,获取安装路径放在installPath,unix下是一样的。
  • 命令行参数截取存放在commandLine中
  • Com_Init
  • NET_Init :qcommon目录下,网络初始化
  • CON_Init
  • 中断信号关联:SIGILL、SIGFPE、SIGSEGV、SIGTERM、SIGINT。
    详细意义可以参考信号列表,都是中断信号:非法指令、浮点例外、段非法错误、终止、来自键盘的中断信号
  • 后面开启while 1循环 IN_Frame和Com_Frame函数

Com_Init 初始化过程

  • 清空event队列eventQueue
  • 初始化随机数种子
qboolean Sys_RandomBytes( byte *string, int len )
{
	FILE *fp;

	fp = fopen( "/dev/urandom", "r" );
	if( !fp )
		return qfalse;

	if( !fread( string, sizeof( byte ), len, fp ) )
	{
		fclose( fp );
		return qfalse;
	}

	fclose( fp );
	return qtrue;
}
static void Com_InitRand(void)
{
	unsigned int seed;

	if(Sys_RandomBytes((byte *) &seed, sizeof(seed)))
		srand(seed);
	else
		srand(time(NULL));
}
  • 初始化 com_pushedEvents :清空队列,头尾设置为0
    类型:
typedef enum {
	// SE_NONE must be zero
	SE_NONE = 0,		// evTime is still valid
	SE_KEY,			// evValue is a key code, evValue2 is the down flag
	SE_CHAR,		// evValue is an ascii char
	SE_MOUSE,		// evValue and evValue2 are reletive signed x / y moves
	SE_JOYSTICK_AXIS,	// evValue is an axis number and evValue2 is the current state (-127 to 127)
	SE_CONSOLE		// evPtr is a char*
} sysEventType_t;

typedef struct {
	int				evTime;
	sysEventType_t	evType;
	int				evValue, evValue2;
	int				evPtrLength;	// bytes of data pointed to by evPtr, for journaling
	void			*evPtr;			// this must be manually freed if not NULL
} sysEvent_t;
  • 创建和初始化内存池ZoneMemory:
	s_smallZoneTotal = 512 * 1024;
	smallzone = calloc( s_smallZoneTotal, 1 );
	Z_ClearZone( smallzone, s_smallZoneTotal );
	// 初始化memory zone,这个zone中存放的是debug信息
	void Z_ClearZone( memzone_t *zone, int size ) {
	memblock_t	*block;
	zone->blocklist.next = zone->blocklist.prev = block =
		(memblock_t *)( (byte *)zone + sizeof(memzone_t) );
	zone->blocklist.tag = 1;	// in use block
	zone->blocklist.id = 0;
	zone->blocklist.size = 0;
	zone->rover = block;
	zone->size = size;
	zone->used = 0;
	
	block->prev = block->next = &zone->blocklist;
	block->tag = 0;			// free block
	block->id = ZONEID;
	block->size = size - sizeof(memzone_t);

结构组成:zone中包含一堆block,block用blocklist管理,其他的rover、zise、used是blocklist的属性。
初始化将blocklist初始化成一个空的双向循环链表,里面只放一个block,作为和blocklist的彼此头尾,block也包含自己的属性

  • 初始化环境变量参数
    调用Cvar_Get函数 获取sv_cheats,所有的环境变量用hash table进行管理的搜索
    用Cmd_AddCommand将对应的命令挂载到制定的函数上,每一个命令结构体是一个循环的链表
    所有的cmd存在static变量cmd_functions中,是个单向链表,每次新来的存到头部,cmd_functions永远指向的是第一个。
  • Com_ParseCommandLine:只是将前面的commandLine存放到数组com_consoleLines中
  • 初始化 cmd_text : cmd_text.data = cmd_text_buf;
  • Com_DetectSSE:判断CPU是否支持SSE,调用的是SDL_XXX 函数,这些函数最终调用的是CPU_XXX函数,这些函数中调用的是汇编语言
	if( SDL_HasRDTSC( ) )    features |= CF_RDTSC;
	if( SDL_HasMMX( ) )      features |= CF_MMX;
	if( SDL_HasMMXExt( ) )   features |= CF_MMX_EXT;
	if( SDL_Has3DNow( ) )    features |= CF_3DNOW;
	if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT;
	if( SDL_HasSSE( ) )      features |= CF_SSE;
	if( SDL_HasSSE2( ) )     features |= CF_SSE2;
	if( SDL_HasAltiVec( ) )  features |= CF_ALTIVEC;

支持了SSE之后实现这三个函数
Q_ftol = qftolx87;
Q_VMftol = qvmftolx87;
Q_SnapVector = qsnapvectorx87;
后面的函数都是用汇编指令实现的

  • 把命令你行的参数全部写进 cmd list 中,cmd list是一对的,前面是命令,后面是命令的参数
    初始化的后面操作也是在设置和写cmd list,这些list存放的是游戏的相关设置,
  • 根据命令行的com_zoneMegs,创建内存池 mainzone,创建方法和上面的一样
  • Com_ExecuteCfg函数中执行所有的配置cmd函数,后面Cvar_Get一系列的参数
  • 渲染开始在函数注册CL_StartHunkUsers中CL_InitRenderer,初始化UI界面CL_InitUI
    在这个函数里创建窗口

动画播放在函数CL_InitUI中执行
re.BeginRegistration = RE_BeginRegistration;

OpenGL初始化流程

RE_BeginRegistration
R_Init(); //初始化生成相关的数据,fog,noise,注册render相关参数;初始化场景的顺序;
R_Register函数中所有的参数进行初始化,包括全屏参数r_fullscreen = ri.Cvar_Get( “r_fullscreen”, “1”, CVAR_ARCHIVE );
// InitOpenGL,其中GLimp_Init来实现OpenGL相关的初始化

*glconfigOut = glConfig;

R_SyncRenderThread();

tr.viewCluster = -1;		// force markleafs to regenerate
R_ClearFlares();
RE_ClearScene();

tr.registered = qtrue;
InitOpenGL
  • GLimp_Init:

GLimp_StartDriverAndSetMode创建窗口,这里调用GLimp_SetMode,设置相关属性,SDL_CreateRGBSurfaceFrom创建窗口,获取opengl context GLimp_GetCurrentContext
gdb调试过程中全屏窗口的显示是再函数SDL_SetVideoMode时
IN_ActivateMouse到这里等待鼠标卡住

其他信息

  • wiki[http://wiki.ioquake3.org/Main_Page]页面中包含了详细的编译和开发介绍
  • log输出中用宏定义写固定的信息:
fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
#define Q3_VERSION PRODUCT_NAME " " PRODUCT_VERSION
#define PRODUCT_VERSION "1.36"
#define PRODUCT_NAME			"ioq3"
  • exit进行了包装:Sys_Exit

NET_Init

网络是否启用的控制参数:net_enabled->integer

	NET_Config( qtrue );
	Cmd_AddCommand ("net_restart", NET_Restart_f);

NET_Config 流程

  • 判断网络参数是否修改
  • enableNetworking 和 networkingEnabled分别表示网络是否开始、网络是否已经开启。如果两个状态相同,并且网络参数没有修改,就可以保持现状退出改配置函数。
  • 否则根据enableNetworking 和 networkingEnabled的值配置stop和start的状态,状态组合情况如下:
enableNetworking/networkingEnabledT/TF/FT/FF/T
stopTFTF
startTFFT
  • if stop:调用closesocket关闭网络
  • if start && net_enabled->integer:调用NET_OpenIP和NET_SetMulticast6函数。
    • NET_OpenIP:
      NET_GetLocalAddress:获取ip地址,调用getifaddrs函数获取ip地址的链表;然后遍历,ip中有标志IFF_UP,表示网络装置正常启用;NET_AddLocalAddress区分IPv4和IPv6然后填充LocalIP数组;freeifaddrs释放链表;Sys_ShowIP调用getnameinfo将地址转换成字符串显示。
      根据net_enabled->integer & NET_ENABLEV6或NET_ENABLEV分别进行获取socket端口,进行遍历,调用socket、ioctlsocket、setsocketopt、bind函数
    • NET_SetMulticast6:
      只是做一个地址拷贝
  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值