1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 //
21 // cl_cgapi.c
22 // Client-Game API
23 //
24 
25 #include "cl_local.h"
26 #include "../cgame/cg_api.h"
27 
28 static cgExport_t		*cge;
29 
30 /*
31 =============================================================================
32 
33 	CGAME EXPORT FUNCTIONS
34 
35 =============================================================================
36 */
37 
38 /*
39 ===============
40 CL_CGModule_LoadMap
41 ===============
42 */
CL_CGModule_LoadMap(void)43 void CL_CGModule_LoadMap (void)
44 {
45 	uint32		initTime;
46 
47 	if (!cge)
48 		Com_Error (ERR_FATAL, "CL_CGModule_LoadMap: CGame not initialized!");
49 
50 	cls.mapLoading = qTrue;
51 	cls.mapLoaded = qFalse;
52 
53 	initTime = Sys_UMilliseconds ();
54 
55 	// Update connection info
56 	CL_CGModule_UpdateConnectInfo ();
57 
58 	// Begin registration
59 	GUI_BeginRegistration ();
60 	R_BeginRegistration ();
61 	Snd_BeginRegistration ();
62 
63 	R_GetRefConfig (&cls.refConfig);
64 
65 	CL_ImageMediaInit ();
66 	CL_SoundMediaInit ();
67 	SCR_UpdateScreen ();
68 
69 	// Load the map and media in CGame
70 	cge->LoadMap (cl.playerNum, cls.serverProtocol, cl.attractLoop, cl.strafeHack, &cls.refConfig);
71 
72 	// Touch before registration ends
73 	R_MediaInit ();
74 
75 	// Start the cd track
76 	CDAudio_Play (atoi (cl.configStrings[CS_CDTRACK]), qTrue);
77 
78 	// The subsystems can now free unneeded stuff
79 	GUI_EndRegistration ();
80 	R_EndRegistration ();
81 	Snd_EndRegistration ();
82 
83 	// Clear notify lines
84 	CL_ClearNotifyLines ();
85 
86 	// Update the screen
87 	SCR_UpdateScreen ();
88 
89 	// Pump message loop
90 	Sys_SendKeyEvents ();
91 
92 	// All done!
93 	cls.refreshPrepped = qTrue;
94 	cls.mapLoading = qFalse;
95 	cls.mapLoaded = qTrue;
96 	Com_Printf (0, "Map loaded in: %ums\n", Sys_UMilliseconds()-initTime);
97 }
98 
99 
100 /*
101 ===============
102 CL_CGModule_UpdateConnectInfo
103 ===============
104 */
CL_CGModule_UpdateConnectInfo(void)105 void CL_CGModule_UpdateConnectInfo (void)
106 {
107 	if (!cge)
108 		return;
109 
110 	// Update download info
111 	if (cls.download.file) {
112 		float	size = (float)ftell (cls.download.file);
113 
114 		cge->UpdateConnectInfo (cls.serverName, cls.serverMessage, cls.connectCount, cls.download.name, cls.download.percent, size);
115 		return;
116 	}
117 
118 	// Nothing downloading
119 	cge->UpdateConnectInfo (cls.serverName, cls.serverMessage, cls.connectCount, NULL, -1, -1);
120 }
121 
122 
123 /*
124 ===============
125 CL_CGModule_BeginFrameSequence
126 ===============
127 */
CL_CGModule_BeginFrameSequence(void)128 void CL_CGModule_BeginFrameSequence (void)
129 {
130 	if (cge)
131 		cge->BeginFrameSequence (cl.frame);
132 }
133 
134 
135 /*
136 ===============
137 CL_CGModule_NewPacketEntityState
138 ===============
139 */
CL_CGModule_NewPacketEntityState(int entNum,entityState_t state)140 void CL_CGModule_NewPacketEntityState (int entNum, entityState_t state)
141 {
142 	if (cge)
143 		cge->NewPacketEntityState (entNum, state);
144 }
145 
146 
147 /*
148 ===============
149 CL_CGModule_EndFrameSequence
150 ===============
151 */
CL_CGModule_EndFrameSequence(void)152 void CL_CGModule_EndFrameSequence (void)
153 {
154 	if (cge)
155 		cge->EndFrameSequence (cl.frame.numEntities);
156 }
157 
158 
159 /*
160 ===============
161 CL_CGModule_GetEntitySoundOrigin
162 ===============
163 */
CL_CGModule_GetEntitySoundOrigin(int entNum,vec3_t origin,vec3_t velocity)164 void CL_CGModule_GetEntitySoundOrigin (int entNum, vec3_t origin, vec3_t velocity)
165 {
166 	if (cge)
167 		cge->GetEntitySoundOrigin (entNum, origin, velocity);
168 }
169 
170 
171 /*
172 ===============
173 CL_CGModule_ParseConfigString
174 ===============
175 */
CL_CGModule_ParseConfigString(int num,char * str)176 void CL_CGModule_ParseConfigString (int num, char *str)
177 {
178 	if (cge)
179 		cge->ParseConfigString (num, str);
180 }
181 
182 
183 /*
184 ===============
185 CL_CGModule_DebugGraph
186 ===============
187 */
CL_CGModule_DebugGraph(float value,int color)188 void CL_CGModule_DebugGraph (float value, int color)
189 {
190 	if (cge)
191 		cge->DebugGraph (value, color);
192 }
193 
194 
195 /*
196 ===============
197 CL_CGModule_StartServerMessage
198 ===============
199 */
CL_CGModule_StartServerMessage(void)200 void CL_CGModule_StartServerMessage (void)
201 {
202 	if (cge)
203 		cge->StartServerMessage ();
204 }
205 
206 
207 /*
208 ===============
209 CL_CGModule_ParseServerMessage
210 ===============
211 */
CL_CGModule_ParseServerMessage(int command)212 qBool CL_CGModule_ParseServerMessage (int command)
213 {
214 	if (cge)
215 		return cge->ParseServerMessage (command);
216 
217 	return qFalse;
218 }
219 
220 
221 /*
222 ===============
223 CL_CGModule_EndServerMessage
224 ===============
225 */
CL_CGModule_EndServerMessage(void)226 void CL_CGModule_EndServerMessage (void)
227 {
228 	if (cge)
229 		cge->EndServerMessage (cls.realTime);
230 }
231 
232 
233 /*
234 ===============
235 CL_CGModule_Pmove
236 ===============
237 */
CL_CGModule_Pmove(pMoveNew_t * pMove,float airAcceleration)238 qBool CL_CGModule_Pmove (pMoveNew_t *pMove, float airAcceleration)
239 {
240 	if (cge) {
241 		cge->Pmove (pMove, airAcceleration);
242 		return qTrue;
243 	}
244 
245 	return qFalse;
246 }
247 
248 
249 /*
250 ===============
251 CL_CGModule_RegisterSounds
252 ===============
253 */
CL_CGModule_RegisterSounds(void)254 void CL_CGModule_RegisterSounds (void)
255 {
256 	if (cge)
257 		cge->RegisterSounds ();
258 }
259 
260 
261 /*
262 ===============
263 CL_CGModule_RenderView
264 ===============
265 */
CL_CGModule_RenderView(float stereoSeparation)266 void CL_CGModule_RenderView (float stereoSeparation)
267 {
268 	if (cge)
269 		cge->RenderView (cls.realTime, cls.trueNetFrameTime, cls.trueRefreshFrameTime, stereoSeparation, cls.refreshPrepped);
270 }
271 
272 
273 /*
274 ===============
275 CL_CGModule_SetRefConfig
276 ===============
277 */
CL_CGModule_SetRefConfig(void)278 void CL_CGModule_SetRefConfig (void)
279 {
280 	if (cge)
281 		cge->SetRefConfig (&cls.refConfig);
282 }
283 
284 
285 /*
286 ===============
287 CL_CGModule_MainMenu
288 ===============
289 */
CL_CGModule_MainMenu(void)290 void CL_CGModule_MainMenu (void)
291 {
292 	if (cge)
293 		cge->MainMenu ();
294 }
295 
296 
297 /*
298 ===============
299 CL_CGModule_ForceMenuOff
300 ===============
301 */
CL_CGModule_ForceMenuOff(void)302 void CL_CGModule_ForceMenuOff (void)
303 {
304 	if (cge)
305 		cge->ForceMenuOff ();
306 }
307 
308 
309 /*
310 ===============
311 CL_CGModule_MoveMouse
312 ===============
313 */
CL_CGModule_MoveMouse(float mx,float my)314 void CL_CGModule_MoveMouse (float mx, float my)
315 {
316 	if (cge)
317 		cge->MoveMouse (mx, my);
318 }
319 
320 
321 /*
322 ===============
323 CL_CGModule_KeyEvent
324 ===============
325 */
CL_CGModule_KeyEvent(keyNum_t keyNum,qBool isDown)326 void CL_CGModule_KeyEvent (keyNum_t keyNum, qBool isDown)
327 {
328 	if (cge)
329 		cge->KeyEvent (keyNum, isDown);
330 }
331 
332 
333 /*
334 ===============
335 CL_CGModule_ParseServerInfo
336 ===============
337 */
CL_CGModule_ParseServerInfo(char * adr,char * info)338 qBool CL_CGModule_ParseServerInfo (char *adr, char *info)
339 {
340 	if (cge)
341 		return cge->ParseServerInfo (adr, info);
342 	return qFalse;
343 }
344 
345 
346 /*
347 ===============
348 CL_CGModule_ParseServerStatus
349 ===============
350 */
CL_CGModule_ParseServerStatus(char * adr,char * info)351 qBool CL_CGModule_ParseServerStatus (char *adr, char *info)
352 {
353 	if (cge)
354 		return cge->ParseServerStatus (adr, info);
355 	return qFalse;
356 }
357 
358 
359 /*
360 ===============
361 CL_CGModule_StartSound
362 ===============
363 */
CL_CGModule_StartSound(vec3_t origin,int entNum,entChannel_t entChannel,int soundNum,float volume,float attenuation,float timeOffset)364 void CL_CGModule_StartSound (vec3_t origin, int entNum, entChannel_t entChannel, int soundNum, float volume, float attenuation, float timeOffset)
365 {
366 	if (cge)
367 		cge->StartSound (origin, entNum, entChannel, soundNum, volume, attenuation, timeOffset);
368 }
369 
370 /*
371 =============================================================================
372 
373 	CGAME IMPORT API
374 
375 =============================================================================
376 */
377 
378 /*
379 ==================
380 CGI_Cmd_AddCommand
381 ==================
382 */
CGI_Cmd_AddCommand(char * name,void (* function)(void),const char * description)383 static void *CGI_Cmd_AddCommand (char *name, void (*function) (void), const char *description)
384 {
385 	return _Cmd_AddCommand (qTrue, name, function, description);
386 }
387 
388 
389 /*
390 ==================
391 CGI_Com_Error
392 ==================
393 */
CGI_Com_Error(comError_t code,char * text)394 static void CGI_Com_Error (comError_t code, char *text)
395 {
396 	Com_Error (code, "%s", text);
397 }
398 
399 
400 /*
401 ==================
402 CGI_Com_Printf
403 ==================
404 */
CGI_Com_Printf(comPrint_t flags,char * text)405 static void CGI_Com_Printf (comPrint_t flags, char *text)
406 {
407 	Com_ConPrint (flags, text);
408 }
409 
410 
411 /*
412 ==================
413 CGI_Com_DevPrintf
414 ==================
415 */
CGI_Com_DevPrintf(comPrint_t flags,char * text)416 static void CGI_Com_DevPrintf (comPrint_t flags, char *text)
417 {
418 	if (!cg_developer->intVal && !developer->intVal)
419 		return;
420 
421 	Com_ConPrint (flags, text);
422 }
423 
424 
425 /*
426 ===============
427 CGI_NET_GetCurrentUserCmdNum
428 ===============
429 */
CGI_NET_GetCurrentUserCmdNum(void)430 static int CGI_NET_GetCurrentUserCmdNum (void)
431 {
432 	return cl.cmdNum;
433 }
434 
435 
436 /*
437 ===============
438 CGI_NET_GetPacketDropCount
439 ===============
440 */
CGI_NET_GetPacketDropCount(void)441 static int CGI_NET_GetPacketDropCount (void)
442 {
443 	return cls.netChan.dropped;
444 }
445 
446 
447 /*
448 ===============
449 CGI_NET_GetRateDropCount
450 ===============
451 */
CGI_NET_GetRateDropCount(void)452 static int CGI_NET_GetRateDropCount (void)
453 {
454 	return cl.surpressCount;
455 }
456 
457 
458 /*
459 ===============
460 CGI_NET_GetSequenceState
461 ===============
462 */
CGI_NET_GetSequenceState(int * outgoingSequence,int * incomingAcknowledged)463 static void CGI_NET_GetSequenceState (int *outgoingSequence, int *incomingAcknowledged)
464 {
465 	if (outgoingSequence)
466 		*outgoingSequence = cls.netChan.outgoingSequence;
467 	if (incomingAcknowledged)
468 		*incomingAcknowledged = cls.netChan.incomingAcknowledged;
469 }
470 
471 
472 /*
473 ===============
474 CGI_NET_GetUserCmd
475 ===============
476 */
CGI_NET_GetUserCmd(int frame,userCmd_t * cmd)477 static void CGI_NET_GetUserCmd (int frame, userCmd_t *cmd)
478 {
479 	if (cmd)
480 		*cmd = cl.cmds[frame & CMD_MASK];
481 }
482 
483 
484 /*
485 ===============
486 CGI_NET_GetUserCmdTime
487 ===============
488 */
CGI_NET_GetUserCmdTime(int frame)489 static int CGI_NET_GetUserCmdTime (int frame)
490 {
491 	return cl.cmdTime[frame & CMD_MASK];
492 }
493 
494 // ==========================================================================
495 
496 /*
497 ===============
498 CGI_GetConfigString
499 ===============
500 */
CGI_GetConfigString(int i,char * str,int size)501 static void CGI_GetConfigString (int i, char *str, int size)
502 {
503 	if (i < 0 || i >= MAX_CFGSTRINGS) {
504 		Com_Printf (PRNT_ERROR, "CGI_GetConfigString: i > MAX_CFGSTRINGS");
505 		return;
506 	}
507 	if (!str || size <= 0) {
508 		Com_Printf (PRNT_ERROR, "CGI_GetConfigString: NULL string");
509 		return;
510 	}
511 
512 	strncpy (str, cl.configStrings[i], size);
513 }
514 
515 // ==========================================================================
516 
CGI_MSG_ReadChar(void)517 static int CGI_MSG_ReadChar (void)			{ return MSG_ReadChar (&cls.netMessage); }
CGI_MSG_ReadByte(void)518 static int CGI_MSG_ReadByte (void)			{ return MSG_ReadByte (&cls.netMessage); }
CGI_MSG_ReadShort(void)519 static int CGI_MSG_ReadShort (void)			{ return MSG_ReadShort (&cls.netMessage); }
CGI_MSG_ReadLong(void)520 static int CGI_MSG_ReadLong (void)			{ return MSG_ReadLong (&cls.netMessage); }
CGI_MSG_ReadFloat(void)521 static float CGI_MSG_ReadFloat (void)		{ return MSG_ReadFloat (&cls.netMessage); }
CGI_MSG_ReadDir(vec3_t dir)522 static void CGI_MSG_ReadDir (vec3_t dir)	{ MSG_ReadDir (&cls.netMessage, dir); }
CGI_MSG_ReadPos(vec3_t pos)523 static void CGI_MSG_ReadPos (vec3_t pos)	{ MSG_ReadPos (&cls.netMessage, pos); }
CGI_MSG_ReadString(void)524 static char *CGI_MSG_ReadString (void)		{ return MSG_ReadString (&cls.netMessage); }
525 
526 // ==========================================================================
527 
528 /*
529 ===============
530 CGI_R_RenderScene
531 ===============
532 */
CGI_R_RenderScene(refDef_t * rd)533 static void CGI_R_RenderScene (refDef_t *rd)
534 {
535 	cl.refDef = *rd;
536 	R_RenderScene (rd);
537 }
538 
539 // ==========================================================================
540 
541 /*
542 ===============
543 CGI_Alloc
544 ===============
545 */
CGI_Alloc(size_t size,qBool zeroFill,const int tagNum,const char * fileName,const int fileLine)546 static void *CGI_Alloc (size_t size, qBool zeroFill, const int tagNum, const char *fileName, const int fileLine)
547 {
548 	return _Mem_Alloc (size, zeroFill, cl_cGameSysPool, tagNum, fileName, fileLine);
549 }
550 
551 
552 /*
553 ===============
554 CGI_ChangeTag
555 ===============
556 */
CGI_ChangeTag(const int tagFrom,const int tagTo)557 uint32 CGI_ChangeTag (const int tagFrom, const int tagTo)
558 {
559 	return _Mem_ChangeTag (cl_cGameSysPool, tagFrom, tagTo);
560 }
561 
562 
563 /*
564 ===============
565 CGI_Free
566 ===============
567 */
CGI_Free(const void * ptr,const char * fileName,const int fileLine)568 static uint32 CGI_Free (const void *ptr, const char *fileName, const int fileLine)
569 {
570 	return _Mem_Free (ptr, fileName, fileLine);
571 }
572 
573 
574 /*
575 ===============
576 CGI_FreeTag
577 ===============
578 */
CGI_FreeTag(const int tagNum,const char * fileName,const int fileLine)579 static uint32 CGI_FreeTag (const int tagNum, const char *fileName, const int fileLine)
580 {
581 	return _Mem_FreeTag (cl_cGameSysPool, tagNum, fileName, fileLine);
582 }
583 
584 
585 /*
586 ===============
587 CGI_StrDup
588 ===============
589 */
CGI_StrDup(const char * in,const int tagNum,const char * fileName,const int fileLine)590 static char *CGI_StrDup (const char *in, const int tagNum, const char *fileName, const int fileLine)
591 {
592 	return _Mem_PoolStrDup (in, cl_cGameSysPool, tagNum, fileName, fileLine);
593 }
594 
595 
596 /*
597 ===============
598 CGI_TagSize
599 ===============
600 */
CGI_TagSize(const int tagNum)601 static uint32 CGI_TagSize (const int tagNum)
602 {
603 	return _Mem_TagSize (cl_cGameSysPool, tagNum);
604 }
605 
606 // ==========================================================================
607 
608 /*
609 ===============
610 CL_CGameAPI_Init
611 ===============
612 */
CL_CGameAPI_Init(void)613 void CL_CGameAPI_Init (void)
614 {
615 	cgImport_t	cgi;
616 
617 	// Shutdown if already active
618 	CL_CGameAPI_Shutdown ();
619 
620 	CGI_Com_DevPrintf (0, "\n--------- CGame Initialization ---------\n");
621 
622 	// Initialize pointers
623 	cgi.Cbuf_AddText				= Cbuf_AddText;
624 	cgi.Cbuf_Execute				= Cbuf_Execute;
625 	cgi.Cbuf_ExecuteString			= Cmd_ExecuteString;
626 	cgi.Cbuf_InsertText				= Cbuf_InsertText;
627 
628 	cgi.CL_ForwardCmdToServer		= CL_ForwardCmdToServer;
629 	cgi.CL_ResetServerCount			= CL_ResetServerCount;
630 
631 	cgi.CM_BoxTrace					= CM_BoxTrace;
632 	cgi.CM_HeadnodeForBox			= CM_HeadnodeForBox;
633 	cgi.CM_InlineModel				= CM_InlineModel;
634 	cgi.CM_InlineModelBounds		= CM_InlineModelBounds;
635 	cgi.CM_InlineModelHeadNode		= CM_InlineModelHeadNode;
636 	cgi.CM_PointContents			= CM_PointContents;
637 	cgi.CM_Trace					= CM_Trace;
638 	cgi.CM_TransformedBoxTrace		= CM_TransformedBoxTrace;
639 	cgi.CM_TransformedPointContents = CM_TransformedPointContents;
640 
641 	cgi.Cmd_AddCommand				= CGI_Cmd_AddCommand;
642 	cgi.Cmd_RemoveCommand			= Cmd_RemoveCommand;
643 
644 	cgi.Cmd_TokenizeString			= Cmd_TokenizeString;
645 	cgi.Cmd_Argc					= Cmd_Argc;
646 	cgi.Cmd_Args					= Cmd_Args;
647 	cgi.Cmd_Argv					= Cmd_Argv;
648 
649 	cgi.Com_Error					= CGI_Com_Error;
650 	cgi.Com_Printf					= CGI_Com_Printf;
651 	cgi.Com_DevPrintf				= CGI_Com_DevPrintf;
652 	cgi.Com_ClientState				= Com_ClientState;
653 	cgi.Com_ServerState				= Com_ServerState;
654 
655 	cgi.Cvar_Register				= Cvar_Register;
656 	cgi.Cvar_Exists					= Cvar_Exists;
657 
658 	cgi.Cvar_GetIntegerValue		= Cvar_GetIntegerValue;
659 	cgi.Cvar_GetStringValue			= Cvar_GetStringValue;
660 	cgi.Cvar_GetFloatValue			= Cvar_GetFloatValue;
661 
662 	cgi.Cvar_VariableSet			= Cvar_VariableSet;
663 	cgi.Cvar_VariableSetValue		= Cvar_VariableSetValue;
664 	cgi.Cvar_VariableReset			= Cvar_VariableReset;
665 
666 	cgi.Cvar_Set					= Cvar_Set;
667 	cgi.Cvar_SetValue				= Cvar_SetValue;
668 	cgi.Cvar_Reset					= Cvar_Reset;
669 
670 	cgi.FS_CreatePath				= FS_CreatePath;
671 	cgi.FS_Gamedir					= FS_Gamedir;
672 	cgi.FS_FileExists				= FS_FileExists;
673 	cgi.FS_FindFiles				= FS_FindFiles;
674 	cgi.FS_FreeFileList				= _FS_FreeFileList;
675 	cgi.FS_LoadFile					= FS_LoadFile;
676 	cgi.FS_FreeFile					= _FS_FreeFile;
677 	cgi.FS_NextPath					= FS_NextPath;
678 	cgi.FS_Read						= FS_Read;
679 	cgi.FS_Write					= FS_Write;
680 	cgi.FS_Seek						= FS_Seek;
681 	cgi.FS_OpenFile					= FS_OpenFile;
682 	cgi.FS_CloseFile				= FS_CloseFile;
683 
684 	cgi.GetConfigString				= CGI_GetConfigString;
685 
686 	cgi.GUI_RegisterGUI				= GUI_RegisterGUI;
687 	cgi.GUI_OpenGUI					= GUI_OpenGUI;
688 	cgi.GUI_CloseGUI				= GUI_CloseGUI;
689 	cgi.GUI_CloseAllGUIs			= GUI_CloseAllGUIs;
690 	cgi.GUI_NamedGlobalEvent		= GUI_NamedGlobalEvent;
691 	cgi.GUI_NamedGUIEvent			= GUI_NamedGUIEvent;
692 
693 	cgi.GUIVar_Register				= GUIVar_Register;
694 	cgi.GUIVar_GetFloatValue		= GUIVar_GetFloatValue;
695 	cgi.GUIVar_GetStrValue			= GUIVar_GetStrValue;
696 	cgi.GUIVar_GetVecValue			= GUIVar_GetVecValue;
697 	cgi.GUIVar_SetFloatValue		= GUIVar_SetFloatValue;
698 	cgi.GUIVar_SetStrValue			= GUIVar_SetStrValue;
699 	cgi.GUIVar_SetVecValue			= GUIVar_SetVecValue;
700 
701 	cgi.Key_ClearStates				= Key_ClearStates;
702 	cgi.Key_GetDest					= Key_GetDest;
703 	cgi.Key_GetBindingBuf			= Key_GetBindingBuf;
704 	cgi.Key_IsDown					= Key_IsDown;
705 	cgi.Key_KeynumToString			= Key_KeynumToString;
706 	cgi.Key_SetBinding				= Key_SetBinding;
707 	cgi.Key_SetDest					= Key_SetDest;
708 	cgi.Key_InsertOn				= Key_InsertOn;
709 	cgi.Key_CapslockOn				= Key_CapslockOn;
710 	cgi.Key_ShiftDown				= Key_ShiftDown;
711 
712 	cgi.Mem_Alloc					= CGI_Alloc;
713 	cgi.Mem_Free					= CGI_Free;
714 	cgi.Mem_FreeTag					= CGI_FreeTag;
715 	cgi.Mem_StrDup					= CGI_StrDup;
716 	cgi.Mem_TagSize					= CGI_TagSize;
717 	cgi.Mem_ChangeTag				= CGI_ChangeTag;
718 
719 	cgi.MSG_ReadChar				= CGI_MSG_ReadChar;
720 	cgi.MSG_ReadByte				= CGI_MSG_ReadByte;
721 	cgi.MSG_ReadShort				= CGI_MSG_ReadShort;
722 	cgi.MSG_ReadLong				= CGI_MSG_ReadLong;
723 	cgi.MSG_ReadFloat				= CGI_MSG_ReadFloat;
724 	cgi.MSG_ReadDir					= CGI_MSG_ReadDir;
725 	cgi.MSG_ReadPos					= CGI_MSG_ReadPos;
726 	cgi.MSG_ReadString				= CGI_MSG_ReadString;
727 
728 	cgi.NET_GetCurrentUserCmdNum	= CGI_NET_GetCurrentUserCmdNum;
729 	cgi.NET_GetPacketDropCount		= CGI_NET_GetPacketDropCount;
730 	cgi.NET_GetRateDropCount		= CGI_NET_GetRateDropCount;
731 	cgi.NET_GetSequenceState		= CGI_NET_GetSequenceState;
732 	cgi.NET_GetUserCmd				= CGI_NET_GetUserCmd;
733 	cgi.NET_GetUserCmdTime			= CGI_NET_GetUserCmdTime;
734 
735 	cgi.R_AddDecal					= R_AddDecal;
736 	cgi.R_AddEntity					= R_AddEntity;
737 	cgi.R_AddPoly					= R_AddPoly;
738 	cgi.R_AddLight					= R_AddLight;
739 	cgi.R_AddLightStyle				= R_AddLightStyle;
740 
741 	cgi.R_ClearScene				= R_ClearScene;
742 
743 	cgi.R_CullBox					= R_CullBox;
744 	cgi.R_CullSphere				= R_CullSphere;
745 
746 	cgi.R_RegisterFont				= R_RegisterFont;
747 	cgi.R_GetFontDimensions			= R_GetFontDimensions;
748 	cgi.R_DrawChar					= R_DrawChar;
749 	cgi.R_DrawString				= R_DrawString;
750 	cgi.R_DrawStringLen				= R_DrawStringLen;
751 
752 	cgi.R_DrawPic					= R_DrawPic;
753 	cgi.R_DrawRectangle				= R_DrawRectangle;
754 
755 	cgi.R_GetRefConfig				= R_GetRefConfig;
756 	cgi.R_GetImageSize				= R_GetImageSize;
757 
758 	cgi.R_CreateDecal				= R_CreateDecal;
759 	cgi.R_FreeDecal					= R_FreeDecal;
760 
761 	cgi.R_RegisterMap				= R_RegisterMap;
762 	cgi.R_RegisterModel				= R_RegisterModel;
763 	cgi.R_ModelBounds				= R_ModelBounds;
764 
765 	cgi.R_UpdateScreen				= SCR_UpdateScreen;
766 	cgi.R_RenderScene				= CGI_R_RenderScene;
767 	cgi.R_BeginFrame				= R_BeginFrame;
768 	cgi.R_EndFrame					= R_EndFrame;
769 
770 	cgi.R_LightPoint				= R_LightPoint;
771 	cgi.R_TransformVectorToScreen	= R_TransformVectorToScreen;
772 	cgi.R_SetSky					= R_SetSky;
773 
774 	cgi.R_RegisterPic				= R_RegisterPic;
775 	cgi.R_RegisterPoly				= R_RegisterPoly;
776 	cgi.R_RegisterSkin				= R_RegisterSkin;
777 
778 	cgi.Snd_RegisterSound			= Snd_RegisterSound;
779 	cgi.Snd_StartLocalSound			= Snd_StartLocalSound;
780 	cgi.Snd_StartSound				= Snd_StartSound;
781 	cgi.Snd_Update					= Snd_Update;
782 
783 	cgi.Sys_FindClose				= Sys_FindClose;
784 	cgi.Sys_FindFirst				= Sys_FindFirst;
785 	cgi.Sys_GetClipboardData		= Sys_GetClipboardData;
786 	cgi.Sys_Milliseconds			= Sys_Milliseconds;
787 	cgi.Sys_SendKeyEvents			= Sys_SendKeyEvents;
788 
789 	// Get the cgame api
790 	CGI_Com_DevPrintf (0, "LoadLibrary()\n");
791 	cge = (cgExport_t *) Sys_LoadLibrary (LIB_CGAME, &cgi);
792 	if (!cge)
793 		Com_Error (ERR_FATAL, "CL_CGameAPI_Init: Find/load of CGame library failed!");
794 
795 	// Check the api version
796 	if (cge->apiVersion != CGAME_APIVERSION) {
797 		Sys_UnloadLibrary (LIB_CGAME);
798 		Com_Error (ERR_FATAL, "CL_CGameAPI_Init: incompatible apiVersion (%i != %i)", cge->apiVersion, CGAME_APIVERSION);
799 	}
800 
801 	// Check for exports
802 	if (!cge->Init || !cge->Shutdown
803 	|| !cge->UpdateConnectInfo || !cge->LoadMap || !cge->DebugGraph || !cge->BeginFrameSequence
804 	|| !cge->EndFrameSequence || !cge->NewPacketEntityState || !cge->GetEntitySoundOrigin || !cge->ParseConfigString
805 	|| !cge->StartServerMessage || !cge->ParseServerMessage || !cge->EndServerMessage || !cge->StartSound
806 	|| !cge->Pmove || !cge->RegisterSounds || !cge->RenderView || !cge->SetRefConfig
807 	|| !cge->MainMenu || !cge->ForceMenuOff || !cge->MoveMouse || !cge->KeyEvent
808 	|| !cge->ParseServerInfo || !cge->ParseServerStatus)
809 		Com_Error (ERR_FATAL, "CL_CGameAPI_Init: Failed to find all CGame exports!");
810 
811 	// Call to init
812 	CGI_Com_DevPrintf (0, "cgame->Init()\n");
813 	cge->Init ();
814 
815 	CGI_Com_DevPrintf (0, "----------------------------------------\n");
816 }
817 
818 
819 /*
820 ===============
821 CL_CGameAPI_Shutdown
822 ===============
823 */
CL_CGameAPI_Shutdown(void)824 void CL_CGameAPI_Shutdown (void)
825 {
826 	uint32	size;
827 
828 	if (!cge)
829 		return;
830 
831 	CGI_Com_DevPrintf (0, "\n------------ CGame Shutdown ------------\n");
832 
833 	// Tell the module to shutdown locally and unload dll
834 	CGI_Com_DevPrintf (0, "cgame->Shutdown()\n");
835 	cge->Shutdown ();
836 
837 	CGI_Com_DevPrintf (0, "UnloadLibrary()\n");
838 	Sys_UnloadLibrary (LIB_CGAME);
839 	cls.mapLoaded = qFalse;
840 	cge = NULL;
841 
842 	// Notify of memory leaks
843 	size = Mem_PoolSize (cl_cGameSysPool);
844 	if (size > 0)
845 		Com_Printf (PRNT_WARNING, "WARNING: CGame memory leak (%u bytes)\n", size);
846 
847 	// Remove CGame-created console command functions
848 	Cmd_RemoveCGameCmds ();
849 
850 	CGI_Com_DevPrintf (0, "----------------------------------------\n");
851 }
852