1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 2002-2013 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #include "ui_main.h"
26 #include "ui_internal.h"
27 #include "ui_draw.h"
28 #include "ui_timer.h"
29 #include "ui_font.h"
30 #include "ui_sound.h"
31 #include "node/ui_node_abstractnode.h"
32 
33 uiGlobal_t ui_global;
34 
35 memPool_t* ui_dynStringPool;
36 memPool_t* ui_dynPool;
37 memPool_t* ui_sysPool;
38 
39 #ifdef DEBUG
40 static cvar_t* ui_debug;
41 #endif
42 
43 /**
44  * @brief Get the current debug mode (0 mean disabled)
45  * @sa UI_DisplayNotice
46  */
UI_DebugMode(void)47 int UI_DebugMode (void)
48 {
49 #ifdef DEBUG
50 	return ui_debug->integer;
51 #else
52 	return 0;
53 #endif
54 }
55 
56 #ifdef DEBUG
57 /**
58  * @brief display info about UI memory
59  * @todo it can be nice to have number of nodes per behaviours
60  */
UI_Memory_f(void)61 static void UI_Memory_f (void)
62 {
63 	int i;
64 	const size_t nodeSize = sizeof(uiNode_t);
65 	size_t size;
66 	Com_Printf("Allocation:\n");
67 	Com_Printf("\t-Window allocation: %i/%i\n", ui_global.numWindows, UI_MAX_WINDOWS);
68 	Com_Printf("\t-Rendering window stack slot: %i\n", UI_MAX_WINDOWSTACK);
69 	Com_Printf("\t-Action allocation: %i/%i\n", ui_global.numActions, UI_MAX_ACTIONS);
70 	Com_Printf("\t-Model allocation: %i/%i\n", ui_global.numModels, UI_MAX_MODELS);
71 	Com_Printf("\t-Node allocation: %i\n", ui_global.numNodes);
72 
73 	Com_Printf("Memory:\n");
74 	Com_Printf("\t-Action structure size: " UFO_SIZE_T " B\n", sizeof(uiAction_t));
75 	Com_Printf("\t-Model structure size: " UFO_SIZE_T " B\n", sizeof(uiModel_t));
76 	Com_Printf("\t-Node structure size: " UFO_SIZE_T " B x%d\n", sizeof(uiNode_t), ui_global.numNodes);
77 	for (i = 0; i < UI_GetNodeBehaviourCount(); i++) {
78 		uiBehaviour_t* b = UI_GetNodeBehaviourByIndex(i);
79 		Com_Printf("\t -Behaviour %20s structure size: " UFO_SIZE_T " (+" UFO_SIZE_T " B) x%4u\n", b->name, sizeof(uiNode_t) + b->extraDataSize, b->extraDataSize, b->count);
80 	}
81 
82 	size = 0;
83 	for (i = 0; i < UI_GetNodeBehaviourCount(); i++) {
84 		uiBehaviour_t* b = UI_GetNodeBehaviourByIndex(i);
85 		size += nodeSize * b->count + b->extraDataSize * b->count;
86 	}
87 	Com_Printf("Global memory:\n");
88 	Com_Printf("\t-System pool: %ui B\n", _Mem_PoolSize(ui_sysPool));
89 	Com_Printf("\t -AData allocation: " UFO_SIZE_T "/%i B\n", (ptrdiff_t)(ui_global.curadata - ui_global.adata), ui_global.adataize);
90 	Com_Printf("\t -AData used by nodes: " UFO_SIZE_T " B\n", size);
91 	Com_Printf("\t-Dynamic node/data pool: %ui B\n", _Mem_PoolSize(ui_dynPool));
92 	Com_Printf("\t-Dynamic strings pool: %ui B\n", _Mem_PoolSize(ui_dynStringPool));
93 
94 	size = _Mem_PoolSize(ui_sysPool) + _Mem_PoolSize(ui_dynPool) + _Mem_PoolSize(ui_dynStringPool);
95 	Com_Printf("\t-Full size: " UFO_SIZE_T " B\n", size);
96 }
97 #endif
98 
99 #define MAX_CONFUNC_SIZE 512
100 /**
101  * @brief Executes confunc - just to identify those confuncs in the code - in
102  * this frame.
103  * @param[in] fmt Construct string it will execute (command and param)
104  */
UI_ExecuteConfunc(const char * fmt,...)105 void UI_ExecuteConfunc (const char* fmt, ...)
106 {
107 	va_list ap;
108 	va_start(ap, fmt);
109 	Cmd_vExecuteString(fmt, ap);
110 	va_end(ap);
111 }
112 
113 /**
114  * Allocate memory from hunk managed by the UI code
115  * This memory is allocated one time, and never released.
116  * @param size Quantity of memory expected
117  * @param align Alignement of the expected memory
118  * @param reset If true initilize the memory with 0
119  * @return available memory, else nullptr
120  */
UI_AllocHunkMemory(size_t size,int align,bool reset)121 void* UI_AllocHunkMemory (size_t size, int align, bool reset)
122 {
123 	byte* memory = (byte*) ALIGN_PTR(ui_global.curadata, align);
124 	if (memory + size > ui_global.adata + ui_global.adataize)
125 		return nullptr;
126 	if (reset)
127 		memset(memory, 0, size);
128 	ui_global.curadata = memory + size;
129 	return memory;
130 }
131 
132 /**
133  * Reinit input and font
134  */
UI_Reinit(void)135 void UI_Reinit (void)
136 {
137 	UI_InitFonts();
138 	UI_ReleaseInput();
139 	UI_InvalidateMouse();
140 }
141 
142 /**
143  * @brief Reset and free the UI data hunk
144  * @note Even called in case of an error when CL_Shutdown was called - maybe even
145  * before CL_InitLocal (and thus UI_Init) was called
146  * @sa CL_Shutdown
147  * @sa UI_Init
148  */
UI_Shutdown(void)149 void UI_Shutdown (void)
150 {
151 	int i;
152 	const uiBehaviour_t* confunc;
153 
154 	/* MN is not yet initialized */
155 	if (ui_global.adata == nullptr)
156 		return;
157 
158 	confunc = UI_GetNodeBehaviour("confunc");
159 
160 	/* remove all confunc commands */
161 	for (i = 0; i < ui_global.numWindows; i++) {
162 		uiNode_t* node = ui_global.windows[i];
163 		while (node) {
164 
165 			/* remove the command */
166 			if (node->behaviour == confunc) {
167 				/* many nodes to one command is allowed */
168 				if (Cmd_Exists(node->name))
169 					Cmd_RemoveCommand(node->name);
170 			}
171 
172 			/* recursive next */
173 			if (node->firstChild != nullptr)
174 				node = node->firstChild;
175 			else {
176 				while (node) {
177 					if (node->next != nullptr) {
178 						node = node->next;
179 						break;
180 					}
181 					node = node->parent;
182 				}
183 			}
184 		}
185 	}
186 
187 	UI_FontShutdown();
188 	UI_ResetInput();
189 	UI_ResetTimers();
190 
191 	Mem_Free(ui_global.adata);
192 	OBJZERO(ui_global);
193 
194 	/* release pools */
195 	Mem_FreePool(ui_sysPool);
196 	Mem_FreePool(ui_dynStringPool);
197 	Mem_FreePool(ui_dynPool);
198 	ui_sysPool = nullptr;
199 	ui_dynStringPool = nullptr;
200 	ui_dynPool = nullptr;
201 }
202 
203 /**
204  * @brief Finish initialization after everything was loaded
205  * @note private function
206  */
UI_FinishInit(void)207 void UI_FinishInit (void)
208 {
209 	static bool initialized = false;
210 	if (initialized)
211 		return;
212 	initialized = true;
213 
214 	UI_FinishWindowsInit();
215 }
216 
UI_Init(void)217 void UI_Init (void)
218 {
219 	cvar_t* ui_hunkSize = Cvar_Get("ui_hunksize", "3", 0, "UI memory hunk size in megabytes");
220 
221 #ifdef DEBUG
222 	ui_debug = Cvar_Get("debug_ui", "0", CVAR_DEVELOPER, "Prints node names for debugging purposes - valid values are 1 and 2");
223 #endif
224 
225 	/* reset global UI structures */
226 	OBJZERO(ui_global);
227 
228 	ui_sounds = Cvar_Get("ui_sounds", "1", CVAR_ARCHIVE, "Activates UI sounds");
229 
230 #ifdef DEBUG
231 	Cmd_AddCommand("debug_uimemory", UI_Memory_f, "Display info about UI memory allocation");
232 #endif
233 
234 	ui_sysPool = Mem_CreatePool("Client: UI");
235 	ui_dynStringPool = Mem_CreatePool("Client: Dynamic string for UI");
236 	ui_dynPool = Mem_CreatePool("Client: Dynamic memory for UI");
237 
238 	Com_Printf("Allocate %i megabytes for the ui hunk\n", ui_hunkSize->integer);
239 	ui_global.adataize = ui_hunkSize->integer * 1024 * 1024;
240 	ui_global.adata    = Mem_PoolAllocTypeN(byte, ui_global.adataize, ui_sysPool);
241 	ui_global.curadata = ui_global.adata;
242 
243 	UI_InitData();
244 	UI_InitNodes();
245 	UI_InitWindows();
246 	UI_InitDraw();
247 	UI_InitActions();
248 }
249