1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
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 #include "ui_local.h"
22 
23 #ifndef UI_HARD_LINKED
24 /* declare imports for this module */
25 cmdAPI_t	cmd;
26 cvarAPI_t	cvar;
27 fsAPI_t		fs;
28 commonAPI_t	com;
29 sysAPI_t	sys;
30 refAPI_t	ref;
31 keyAPI_t	keys;
32 clientAPI_t client;
33 #endif
34 
35 uiStatic_t	uis;
36 
37 cvar_t	*ui_debug;
38 cvar_t	*ui_open;
39 cvar_t	*ui_background;
40 
41 // ===========================================================================
42 
EmptyCallback(int id,int msg,int param)43 static int EmptyCallback( int id, int msg, int param ) {
44 	return QMS_NOTHANDLED;
45 }
46 
47 /*
48 =================
49 UI_PushMenu
50 =================
51 */
UI_PushMenu(menuFrameWork_t * menu)52 void UI_PushMenu( menuFrameWork_t *menu ) {
53 	int		i, keydest;
54 
55 	cvar.Set( "cl_paused", "1" );
56 
57 	// if this menu is already present, drop back to that level
58 	// to avoid stacking menus by hotkeys
59 	for( i=0 ; i<uis.menuDepth ; i++ ) {
60 		if( uis.layers[i] == menu ) {
61 			break;
62 		}
63 	}
64 
65 	if( i == uis.menuDepth ) {
66 		if( uis.menuDepth >= MAX_MENU_DEPTH )
67 			Com_Error( ERR_FATAL, "UI_PushMenu: MAX_MENU_DEPTH" );
68 		uis.layers[uis.menuDepth++] = menu;
69 	} else {
70 		uis.menuDepth = i;
71 	}
72 
73 	for( i=uis.menuDepth-1 ; i>=0 ; i-- ) {
74 		if( uis.layers[i]->transparent ) {
75 			break;
76 		}
77 	}
78 
79 	uis.transparent = qtrue;
80 	if( i < 0 ) {
81 		uis.transparent = qfalse;
82 	}
83 
84 	if( !menu->callback ) {
85 		menu->callback = EmptyCallback;
86 	}
87 
88 	if( !uis.activeMenu ) {
89 		uis.entersound = qtrue;
90 	}
91 
92 	uis.activeMenu = menu;
93 
94 	keydest = keys.GetDest();
95 	if( keydest & KEY_CONSOLE ) {
96 		keydest &= ~KEY_CONSOLE;
97 		cmd.ExecuteText( EXEC_NOW, "toggleconsole\n" );
98 	}
99 	keys.SetDest( keydest | KEY_MENU );
100 
101 	UI_DoHitTest();
102 }
103 
104 /*
105 =================
106 UI_ForceMenuOff
107 =================
108 */
UI_ForceMenuOff(void)109 void UI_ForceMenuOff( void ) {
110 	int i;
111 
112 	for( i=0 ; i<uis.menuDepth ; i++ ) {
113 		if( uis.layers[i] ) {
114 			uis.layers[i]->callback( ID_MENU, QM_DESTROY, qtrue );
115 		}
116 	}
117 
118 	keys.SetDest( keys.GetDest() & ~KEY_MENU );
119 	uis.menuDepth = 0;
120 	uis.activeMenu = NULL;
121 	uis.transparent = qfalse;
122 	//keys.ClearStates();
123 	cvar.Set( "cl_paused", "0" );
124 }
125 
126 /*
127 =================
128 UI_PopMenu
129 =================
130 */
UI_PopMenu(void)131 void UI_PopMenu( void ) {
132 	int i;
133 
134 	if( uis.menuDepth < 1 )
135 		Com_Error( ERR_FATAL, "UI_PopMenu: depth < 1" );
136 
137 	if( --uis.menuDepth == 0 ) {
138 		UI_ForceMenuOff();
139 		return;
140 	}
141 
142 	uis.layers[uis.menuDepth]->callback( ID_MENU, QM_DESTROY, qfalse );
143 	uis.layers[uis.menuDepth - 1]->callback( ID_MENU, QM_DESTROY_CHILD, qfalse );
144 
145 	uis.activeMenu = uis.layers[uis.menuDepth - 1];
146 
147 	for( i=uis.menuDepth-1 ; i>=0 ; i-- ) {
148 		if( uis.layers[i]->transparent ) {
149 			break;
150 		}
151 	}
152 
153 	uis.transparent = qtrue;
154 	if( i < 0 ) {
155 		uis.transparent = qfalse;
156 	}
157 
158 	UI_DoHitTest();
159 
160 
161 }
162 
163 /*
164 =================
165 UI_IsTransparent
166 =================
167 */
UI_IsTransparent(void)168 qboolean UI_IsTransparent( void ) {
169 	if( !( keys.GetDest() & KEY_MENU ) ) {
170 		return qtrue;
171 	}
172 
173 	if( !uis.activeMenu ) {
174 		return qtrue;
175 	}
176 
177 	return uis.transparent;
178 }
179 
180 /*
181 =================
182 UI_OpenMenu
183 =================
184 */
UI_OpenMenu(uiMenu_t menu)185 void UI_OpenMenu( uiMenu_t menu ) {
186 	// close any existing menus
187 	UI_ForceMenuOff();
188 
189 	switch( menu ) {
190 	case UIMENU_MAIN:
191 		if( ui_open->integer ) {
192 			M_Menu_Main_f();
193 		}
194 		break;
195 	case UIMENU_MAIN_FORCE:
196 		M_Menu_Main_f();
197 		break;
198 	case UIMENU_INGAME:
199 		M_Menu_Ingame_f();
200 		break;
201 	case UIMENU_NONE:
202 		break;
203 	default:
204 		Com_Error( ERR_FATAL, "UI_OpenMenu: bad menu" );
205 		break;
206 	}
207 }
208 
UI_ErrorMenu(comErrorType_t type,const char * text)209 void UI_ErrorMenu( comErrorType_t type, const char *text ) {
210 	// close any existing menus
211 	UI_ForceMenuOff();
212 
213 	if( !ui_open->integer ) {
214 		return;
215 	}
216 
217 	M_Menu_Main_f();
218 	M_Menu_Error_f( type, text );
219 }
220 
221 
222 //=============================================================================
223 
224 /*
225 =================
226 UI_FormatColumns
227 =================
228 */
UI_FormatColumns(int numArgs,...)229 char *UI_FormatColumns( int numArgs, ... ) {
230 	va_list argptr;
231 	char *buffer, *p;
232 	int i, totalLength;
233 	char *strings[MAX_COLUMNS];
234 	int lengths[MAX_COLUMNS];
235 
236 	if( ( unsigned )numArgs > MAX_COLUMNS ) {
237 		Com_Error( ERR_FATAL, "UI_FormatColumns: too many columns" );
238 	}
239 
240 	totalLength = 0;
241 
242 	va_start( argptr, numArgs );
243 	for( i = 0; i < numArgs; i++ ) {
244 		strings[i] = va_arg( argptr, char * );
245 		lengths[i] = strlen( strings[i] ) + 1;
246 		totalLength += lengths[i];
247 	}
248 	va_end( argptr );
249 
250 	buffer = p = UI_Malloc( totalLength + 1 );
251 	for( i = 0; i < numArgs; i++ ) {
252 		memcpy( p, strings[i], lengths[i] );
253 		p += lengths[i];
254 	}
255 
256 	*p = 0;
257 
258 	return buffer;
259 
260 }
261 
262 /*
263 =================
264 UI_CopyString
265 =================
266 */
UI_CopyString(const char * in)267 char *UI_CopyString( const char *in ) {
268 	char	*out;
269 
270 	if( !in ) {
271 		return NULL;
272 	}
273 
274 	out = UI_Malloc( strlen( in ) + 1 );
275 	strcpy( out, in );
276 
277 	return out;
278 }
279 
280 /*
281 =================
282 UI_SetupDefaultBanner
283 =================
284 */
UI_SetupDefaultBanner(menuStatic_t * banner,const char * name)285 void UI_SetupDefaultBanner( menuStatic_t *banner, const char *name ) {
286 	banner->generic.type = MTYPE_STATIC;
287 	banner->generic.name = name;
288 	banner->generic.uiFlags = UI_CENTER|UI_ALTCOLOR;
289 
290 	banner->generic.x = uis.glconfig.vidWidth / 2;
291 	banner->generic.y = 8;
292 }
293 
294 /*
295 =================
296 UI_CursorInRect
297 =================
298 */
UI_CursorInRect(vrect_t * rect,int mx,int my)299 qboolean UI_CursorInRect( vrect_t *rect, int mx, int my ) {
300 	if( mx > rect->x && mx < rect->x + rect->width &&
301 		my > rect->y && my < rect->y + rect->height )
302 	{
303 		return qtrue;
304 	}
305 
306 	return qfalse;
307 }
308 
UI_DrawString(int x,int y,const color_t color,uint32 flags,const char * string)309 void UI_DrawString( int x, int y, const color_t color, uint32 flags, const char *string ) {
310 	if( color ) {
311 		ref.SetColor( DRAW_COLOR_RGBA, color );
312 	}
313 
314 	if( ( flags & UI_CENTER ) == UI_CENTER ) {
315 		x -= Q_DrawStrlen( string ) * 8 / 2;
316 	} else if( flags & UI_RIGHT ) {
317 		x -= Q_DrawStrlen( string ) * 8;
318 	}
319 
320 	ref.DrawString( x, y, flags, MAX_STRING_CHARS, string, uis.fontHandle );
321 	if( color ) {
322 		ref.SetColor( DRAW_COLOR_CLEAR, NULL );
323 	}
324 }
325 
UI_DrawChar(int x,int y,uint32 flags,int ch)326 void UI_DrawChar( int x, int y, uint32 flags, int ch ) {
327 	ref.DrawChar( x, y, flags, ch, uis.fontHandle );
328 }
329 
UI_StringDimensions(vrect_t * rc,uint32 flags,const char * string)330 void UI_StringDimensions( vrect_t *rc, uint32 flags, const char *string ) {
331 	rc->height = 8;
332 	rc->width = 8 * Q_DrawStrlen( string );
333 
334 	if( ( flags & UI_CENTER ) == UI_CENTER ) {
335 		rc->x -= rc->width / 2;
336 	} else if( flags & UI_RIGHT ) {
337 		rc->x -= rc->width;
338 	}
339 }
340 
341 
342 //=============================================================================
343 /* Menu Subsystem */
344 
345 void M_Menu_Network_f( void );
346 
347 /*
348 =================
349 UI_DoHitTest
350 =================
351 */
UI_DoHitTest(void)352 qboolean UI_DoHitTest( void ) {
353 	menuCommon_t *item;
354 
355 	if( !uis.activeMenu ) {
356 		return qfalse;
357 	}
358 
359 	if( !( item = Menu_HitTest( uis.activeMenu, uis.mouseCoords[0], uis.mouseCoords[1] ) ) ) {
360 		return qfalse;
361 	}
362 	if( !UI_IsItemSelectable( item ) ) {
363 		return qfalse;
364 	}
365 
366 	Menu_MouseMove( item );
367 
368 	if( item->flags & QMF_HASFOCUS ) {
369 		return qfalse;
370 	}
371 
372 	Menu_SetFocus( item );
373 
374 	return qtrue;
375 }
376 
377 /*
378 =================
379 UI_MouseMove
380 =================
381 */
UI_MouseMove(int mx,int my)382 void UI_MouseMove( int mx, int my ) {
383 	if( !uis.activeMenu ) {
384 		return;
385 	}
386 
387 	if( !mx && !my ) {
388 		return;
389 	}
390 
391 	uis.mouseCoords[0] += mx;
392 	uis.mouseCoords[1] += my;
393 
394 	clamp( uis.mouseCoords[0], 0, uis.glconfig.vidWidth );
395 	clamp( uis.mouseCoords[1], 0, uis.glconfig.vidHeight );
396 
397 	if( UI_DoHitTest() ) {
398 		// TODO: add new mousemove sound
399 		// cl.StartLocalSound( "misc/menu2.wav" );
400 	}
401 }
402 
403 
404 /*
405 =================
406 UI_Draw
407 =================
408 */
UI_Draw(int realtime)409 void UI_Draw( int realtime ) {
410 	int i;
411 
412 	uis.realtime = realtime;
413 
414 	if( !( keys.GetDest() & KEY_MENU ) ) {
415 		return;
416 	}
417 
418 	if( !uis.activeMenu ) {
419 		return;
420 	}
421 
422 	ref.SetColor( DRAW_COLOR_CLEAR, NULL );
423     if( uis.glconfig.renderer == GL_RENDERER_SOFTWARE ) {
424         ref.SetClipRect( DRAW_CLIP_MASK, &uis.clipRect );
425     }
426 
427 	if( !uis.transparent ) {
428 		// no transparent menus
429 		if( uis.backgroundHandle ) {
430 			ref.DrawStretchPic( 0, 0, uis.glconfig.vidWidth, uis.glconfig.vidHeight,
431 				uis.backgroundHandle );
432 		} else {
433 			ref.DrawFill( 0, 0, uis.glconfig.vidWidth, uis.glconfig.vidHeight, 0 );
434 		}
435 
436 		if( uis.activeMenu->draw ) {
437 			uis.activeMenu->draw( uis.activeMenu );
438 		} else {
439 			Menu_Draw( uis.activeMenu );
440 		}
441 	} else {
442 		// draw all layers
443 		for( i = 0; i < uis.menuDepth; i++ ) {
444 			if( !uis.layers[i]->transparent ) {
445 				if( uis.backgroundHandle ) {
446 					ref.DrawStretchPic( 0, 0, uis.glconfig.vidWidth, uis.glconfig.vidHeight,
447 						uis.backgroundHandle );
448 				} else {
449 					ref.DrawFill( 0, 0, uis.glconfig.vidWidth, uis.glconfig.vidHeight, 0 );
450 				}
451 			}
452 
453 			if( uis.layers[i]->draw ) {
454 				uis.layers[i]->draw( uis.layers[i] );
455 			} else {
456 				Menu_Draw( uis.layers[i] );
457 			}
458 		}
459 	}
460 
461 	ref.DrawStretchPic( uis.mouseCoords[0] - uis.cursorWidth / 2,
462 		uis.mouseCoords[1] - uis.cursorHeight / 2,
463 		uis.cursorWidth, uis.cursorHeight, uis.cursorHandle );
464 
465 	if( ui_debug->integer ) {
466 		Menu_HitTest( uis.activeMenu, 0, 0 );
467 		UI_DrawString( uis.glconfig.vidWidth - 4, 4, NULL, UI_RIGHT,
468 			va( "%3i %3i", uis.mouseCoords[0], uis.mouseCoords[1] ) );
469 	}
470 
471 	// delay playing the enter sound until after the
472 	// menu has been drawn, to avoid delay while
473 	// caching images
474 	if( uis.entersound ) {
475 		uis.entersound = qfalse;
476 		client.StartLocalSound( "misc/menu1.wav" );
477 	}
478 
479     if( uis.glconfig.renderer == GL_RENDERER_SOFTWARE ) {
480         ref.SetClipRect( DRAW_CLIP_DISABLED, NULL );
481     }
482 	ref.SetColor( DRAW_COLOR_CLEAR, NULL );
483 }
484 
485 /*
486 =================
487 Default_MenuKey
488 =================
489 */
Default_MenuKey(menuFrameWork_t * m,int key)490 int Default_MenuKey( menuFrameWork_t *m, int key ) {
491 	menuCommon_t *item;
492 
493 	switch( key ) {
494 	case K_ESCAPE:
495 		UI_PopMenu();
496 		return QMS_OUT;
497 
498 	case K_KP_UPARROW:
499 	case K_UPARROW:
500 		return Menu_AdjustCursor( m, -1 );
501 
502 	case K_KP_DOWNARROW:
503 	case K_DOWNARROW:
504 	case K_TAB:
505 		return Menu_AdjustCursor( m, 1 );
506 
507 	case K_KP_LEFTARROW:
508 	case K_LEFTARROW:
509 	case K_MWHEELDOWN:
510 		return Menu_SlideItem( m, -1 );
511 
512 	case K_KP_RIGHTARROW:
513 	case K_RIGHTARROW:
514 	case K_MWHEELUP:
515 		return Menu_SlideItem( m, 1 );
516 
517 	case K_MOUSE1:
518 	case K_MOUSE2:
519 	case K_MOUSE3:
520 		item = Menu_HitTest( m, uis.mouseCoords[0], uis.mouseCoords[1] );
521 		if( !item ) {
522 			return QMS_NOTHANDLED;
523 		}
524 
525 		if( !( item->flags & QMF_HASFOCUS ) ) {
526 			return QMS_NOTHANDLED;
527 		}
528 
529 		// fall through
530 
531 	case K_JOY1:
532 	case K_JOY2:
533 	case K_JOY3:
534 	case K_JOY4:
535 	case K_AUX1:
536 	case K_AUX2:
537 	case K_AUX3:
538 	case K_AUX4:
539 	case K_AUX5:
540 	case K_AUX6:
541 	case K_AUX7:
542 	case K_AUX8:
543 	case K_AUX9:
544 	case K_AUX10:
545 	case K_AUX11:
546 	case K_AUX12:
547 	case K_AUX13:
548 	case K_AUX14:
549 	case K_AUX15:
550 	case K_AUX16:
551 	case K_AUX17:
552 	case K_AUX18:
553 	case K_AUX19:
554 	case K_AUX20:
555 	case K_AUX21:
556 	case K_AUX22:
557 	case K_AUX23:
558 	case K_AUX24:
559 	case K_AUX25:
560 	case K_AUX26:
561 	case K_AUX27:
562 	case K_AUX28:
563 	case K_AUX29:
564 	case K_AUX30:
565 	case K_AUX31:
566 	case K_AUX32:
567 	case K_KP_ENTER:
568 	case K_ENTER:
569 		return Menu_SelectItem( m );
570 	}
571 
572 	return QMS_NOTHANDLED;
573 }
574 
575 /*
576 =================
577 UI_Keydown
578 =================
579 */
UI_Keydown(int key)580 void UI_Keydown( int key ) {
581 	menuCommon_t *item;
582 	int sound;
583 
584 	if( !uis.activeMenu ) {
585 		return;
586 	}
587 
588 	if( ( sound = uis.activeMenu->callback( ID_MENU, QM_KEY, key ) ) == QMS_NOTHANDLED ) {
589 		if( ( item = Menu_ItemAtCursor( uis.activeMenu ) ) == NULL ||
590 			( sound = Menu_KeyEvent( item, key ) ) == QMS_NOTHANDLED )
591 		{
592 			sound = Default_MenuKey( uis.activeMenu, key );
593 		}
594 	}
595 
596 	switch( sound ) {
597 	case QMS_IN:
598 		client.StartLocalSound( "misc/menu1.wav" );
599 		break;
600 	case QMS_MOVE:
601 		client.StartLocalSound( "misc/menu2.wav" );
602 		break;
603 	case QMS_OUT:
604 		client.StartLocalSound( "misc/menu3.wav" );
605 		break;
606 	case QMS_BEEP:
607 		client.StartLocalSound( "misc/talk1.wav" );
608 		break;
609 	case QMS_NOTHANDLED:
610 	default:
611 		break;
612 	}
613 
614 }
615 
616 /*
617 =================
618 UI_CharEvent
619 =================
620 */
UI_CharEvent(int key)621 void UI_CharEvent( int key ) {
622 	menuCommon_t *item;
623 	int sound;
624 
625 	if( !uis.activeMenu ) {
626 		return;
627 	}
628 
629 	if( ( sound = uis.activeMenu->callback( ID_MENU, QM_CHAR, key ) ) == QMS_NOTHANDLED ) {
630 		if( ( item = Menu_ItemAtCursor( uis.activeMenu ) ) == NULL ||
631 			( sound = Menu_CharEvent( item, key ) ) == QMS_NOTHANDLED )
632 		{
633 			return;
634 		}
635 	}
636 
637 	switch( sound ) {
638 	case QMS_IN:
639 		client.StartLocalSound( "misc/menu1.wav" );
640 		break;
641 	case QMS_MOVE:
642 		client.StartLocalSound( "misc/menu2.wav" );
643 		break;
644 	case QMS_OUT:
645 		client.StartLocalSound( "misc/menu3.wav" );
646 		break;
647 	case QMS_BEEP:
648 		client.StartLocalSound( "misc/talk1.wav" );
649 		break;
650 	case QMS_NOTHANDLED:
651 	default:
652 		break;
653 	}
654 
655 }
656 
657 typedef struct uicmd_s {
658 	const char *name;
659 	void (*func)( void );
660 } uicmd_t;
661 
662 static const uicmd_t uicmds[] = {
663 	{ "menu_main", M_Menu_Main_f },
664 	{ "menu_game", M_Menu_Game_f },
665 	{ "menu_loadgame", M_Menu_LoadGame_f },
666 	{ "menu_savegame", M_Menu_SaveGame_f },
667 	{ "menu_addressbook", M_Menu_AddressBook_f },
668 	{ "menu_startserver", M_Menu_StartServer_f },
669 	{ "menu_dmoptions", M_Menu_DMOptions_f },
670 	{ "menu_playerconfig", M_Menu_PlayerConfig_f },
671 	{ "menu_downloadoptions", M_Menu_DownloadOptions_f },
672 	{ "menu_multiplayer", M_Menu_Multiplayer_f },
673 	{ "menu_network", M_Menu_Network_f },
674 	{ "menu_video", M_Menu_Video_f },
675 	{ "menu_options", M_Menu_Options_f },
676 	{ "menu_keys", M_Menu_Keys_f },
677 	{ "menu_quit", M_Menu_Credits_f },
678 	{ "menu_close", UI_ForceMenuOff },
679 
680 	{ NULL, NULL }
681 };
682 
UI_Background_OnChange(cvar_t * self,void * arg)683 static void UI_Background_OnChange( cvar_t *self, void *arg ) {
684 	if( self->string[0] ) {
685 		uis.backgroundHandle = ref.RegisterPic( self->string );
686 	}
687 }
688 
689 
690 /*
691 =================
692 UI_Init
693 =================
694 */
UI_Init(void)695 qboolean UI_Init( void ) {
696 	const uicmd_t *uicmd;
697 
698 	memset( &uis, 0, sizeof( uis ) );
699 
700 	for( uicmd = uicmds; uicmd->name; uicmd++ ) {
701 		cmd.AddCommand( uicmd->name, uicmd->func );
702 	}
703 
704 	ui_debug = cvar.Get( "ui_debug", "0", 0 );
705 	ui_open = cvar.Get( "ui_open", "0", CVAR_ARCHIVE );
706 	ui_background = cvar.Get( "ui_background", "", 0 );
707 
708 	ref.GetConfig( &uis.glconfig );
709     if( uis.glconfig.renderer == GL_RENDERER_SOFTWARE ) {
710         uis.clipRect.left = 0;
711         uis.clipRect.top = 0;
712         uis.clipRect.right = uis.glconfig.vidWidth;
713         uis.clipRect.bottom = uis.glconfig.vidHeight;
714     }
715 
716 	uis.fontHandle = ref.RegisterFont( "conchars" );
717 	uis.cursorHandle = ref.RegisterPic( "ch1" );
718 	ref.DrawGetPicSize( &uis.cursorWidth, &uis.cursorHeight, uis.cursorHandle );
719 
720 	if( uis.glconfig.renderer != GL_RENDERER_SOFTWARE ) {
721 		if( ui_background->string[0] ) {
722 			uis.backgroundHandle = ref.RegisterPic( ui_background->string );
723 		}
724 		ui_background->changedFunc = UI_Background_OnChange;
725 	}
726 
727 	return qtrue;
728 
729 }
730 
731 /*
732 =================
733 UI_Shutdown
734 =================
735 */
UI_Shutdown(void)736 void UI_Shutdown( void ) {
737 	const uicmd_t *uicmd;
738 
739 	ui_background->changedFunc = NULL;
740 
741 	PlayerModel_Free();
742 
743 	for( uicmd = uicmds; uicmd->name; uicmd++ ) {
744 		cmd.RemoveCommand( uicmd->name );
745 	}
746 }
747 
748 #ifndef UI_HARD_LINKED
749 
750 // this is only here so the functions in q_shared.c can link
751 
Com_Printf(const char * fmt,...)752 void Com_Printf( const char *fmt, ... ) {
753 	va_list		argptr;
754 	char		text[MAXPRINTMSG];
755 
756 	va_start( argptr, fmt );
757 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
758 	va_end( argptr );
759 
760 	com.Print( PRINT_ALL, text );
761 }
762 
Com_DPrintf(const char * fmt,...)763 void Com_DPrintf( const char *fmt, ... ) {
764 	va_list		argptr;
765 	char		text[MAXPRINTMSG];
766 
767 	va_start( argptr, fmt );
768 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
769 	va_end( argptr );
770 
771 	com.Print( PRINT_DEVELOPER, text );
772 }
773 
Com_WPrintf(const char * fmt,...)774 void Com_WPrintf( const char *fmt, ... ) {
775 	va_list		argptr;
776 	char		text[MAXPRINTMSG];
777 
778 	va_start( argptr, fmt );
779 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
780 	va_end( argptr );
781 
782 	com.Print( PRINT_WARNING, text );
783 }
784 
Com_EPrintf(const char * fmt,...)785 void Com_EPrintf( const char *fmt, ... ) {
786 	va_list		argptr;
787 	char		text[MAXPRINTMSG];
788 
789 	va_start( argptr, fmt );
790 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
791 	va_end( argptr );
792 
793 	com.Print( PRINT_ERROR, text );
794 }
795 
Com_Error(comErrorType_t type,const char * error,...)796 void Com_Error( comErrorType_t type, const char *error, ... ) {
797 	va_list		argptr;
798 	char		text[MAXPRINTMSG];
799 
800 	va_start( argptr, error );
801 	Q_vsnprintf( text, sizeof( text ), error, argptr );
802 	va_end( argptr );
803 
804 	com.Error( type, text );
805 }
806 
807 #endif
808 
809 /*
810 =================
811 UI_FillAPI
812 =================
813 */
UI_FillAPI(uiAPI_t * api)814 static void UI_FillAPI( uiAPI_t *api ) {
815 	api->Init = UI_Init;
816 	api->Shutdown = UI_Shutdown;
817 	api->Draw = UI_Draw;
818 	api->DrawLoading = UI_DrawLoading;
819 	api->MouseMove = UI_MouseMove;
820 	api->Keydown = UI_Keydown;
821 	api->CharEvent = UI_CharEvent;
822 	api->OpenMenu = UI_OpenMenu;
823 	api->ErrorMenu = UI_ErrorMenu;
824 	api->AddToServerList = UI_AddToServerList;
825 	api->IsTransparent = UI_IsTransparent;
826 }
827 
828 /*
829 =================
830 UI_APISetupCallback
831 =================
832 */
UI_APISetupCallback(api_type_t type,void * api)833 static qboolean UI_APISetupCallback( api_type_t type, void *api ) {
834 	switch( type ) {
835 	case API_UI:
836 		UI_FillAPI( ( uiAPI_t * )api );
837 		break;
838 	default:
839 		return qfalse;
840 	}
841 
842 	return qtrue;
843 }
844 
845 #ifndef UI_HARD_LINKED
846 
847 /*
848 @@@@@@@@@@@@@@@@@@@@@
849 moduleEntry
850 
851 @@@@@@@@@@@@@@@@@@@@@
852 */
moduleEntry(int query,void * data)853 void *moduleEntry( int query, void *data ) {
854 	moduleInfo_t *info;
855 	moduleCapability_t caps;
856 	APISetupCallback_t callback;
857 
858 	switch( query ) {
859 	case MQ_GETINFO:
860 		info = ( moduleInfo_t * )data;
861 		info->api_version = MODULES_APIVERSION;
862 		Q_strncpyz( info->fullname, "User interface library",
863                 sizeof( info->fullname ) );
864 		Q_strncpyz( info->author, "Andrey Nazarov", sizeof( info->author ) );
865 		return ( void * )qtrue;
866 
867 	case MQ_GETCAPS:
868 		caps = MCP_UI;
869 		return ( void * )caps;
870 
871 	case MQ_SETUPAPI:
872 		if( ( callback = ( APISetupCallback_t )data ) == NULL ) {
873 			return NULL;
874 		}
875 		callback( API_CMD, &cmd );
876 		callback( API_CVAR, &cvar );
877 		callback( API_FS, &fs );
878 		callback( API_COMMON, &com );
879 		callback( API_SYSTEM, &sys );
880 		callback( API_REFRESH, &ref );
881 		callback( API_KEYS, &keys );
882 		callback( API_CLIENT, &client );
883 
884 		return ( void * )UI_APISetupCallback;
885 
886 	}
887 
888 	/* quiet compiler warning */
889 	return NULL;
890 }
891 
892 #endif
893 
894 
895 
896 
897 
898 
899 
900