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