/* Copyright (C) 2011 azazello and ezQuake team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ // // HUD commands // #include "../plugin.h" #include "ezquakeisms.h" //#include "common_draw.h" //#include "keys.h" #include "hud.h" #include "hud_common.h" #include "hud_editor.h" //#include "utils.h" //#include "sbar.h" #define sbar_last_width 320 // yeah yeah I know, *garbage* -> leave it be :> char *align_strings_x[] = { "left", "center", "right", "before", "after" }; #define num_align_strings_x (sizeof(align_strings_x) / sizeof(align_strings_x[0])) char *align_strings_y[] = { "top", "center", "bottom", "before", "after", "console" }; #define num_align_strings_y (sizeof(align_strings_y) / sizeof(align_strings_y[0])) char *snap_strings[] = { "screen", "top", "view", "sbar", "ibar", "hbar", "sfree", "ifree", "hfree", }; #define num_snap_strings (sizeof(snap_strings) / sizeof(snap_strings[0])) // Hud elements list. hud_t *hud_huds = NULL; qbool doreorder; // // Hud plus func - show element. // void HUD_Plus_f(void) { char *t; hud_t *hud; if (Cmd_Argc() < 1) return; t = Cmd_Argv(0); if (strncmp(t, "+hud_", 5)) return; hud = HUD_Find(t + 5); if (!hud) { // This should never happen... return; } if (!hud->show) { // This should never happen... return; } Cvar_Set(hud->show, "1"); } // // Hud minus func - hide element. // void HUD_Minus_f(void) { char *t; hud_t *hud; if (Cmd_Argc() < 1) return; t = Cmd_Argv(0); if (strncmp(t, "-hud_", 5)) return; hud = HUD_Find(t + 5); if (!hud) { // this should never happen... return; } if (!hud->show) { // this should never happen... return; } Cvar_Set(hud->show, "0"); } // // Hud element func - describe it // this also solves the TAB completion problem // void HUD_Func_f(void) { int i; hud_t *hud; hud = HUD_Find(Cmd_Argv(0)); if (!hud) { // This should never happen... Com_Printf("Hud element not found\n"); return; } if (Cmd_Argc() > 1) { char buf[512]; snprintf(buf, sizeof(buf), "hud_%s_%s", hud->name, Cmd_Argv(1)); if (Cvar_Find(buf) != NULL) { Cbuf_AddText(buf); if (Cmd_Argc() > 2) { Cbuf_AddText(" "); Cbuf_AddText(Cmd_Argv(2)); } Cbuf_AddText("\n"); } else { Com_Printf("Trying \"%s\" - no such variable\n", buf); } return; } // Description. Com_Printf("%s\n\n", hud->description); // Status. if (hud->show != NULL) { Com_Printf("Current status: %s\n", hud->show->value ? "shown" : "hidden"); } if (hud->frame != NULL) { Com_Printf("Frame: %s\n\n", hud->frame->string); } if (hud->frame_color != NULL) { Com_Printf("Frame color: %s\n\n", hud->frame_color->string); } // Placement. Com_Printf("Placement: %s\n", hud->place->string); // Alignment. Com_Printf("Alignment (x y): %s %s\n", hud->align_x->string, hud->align_y->string); // Position. Com_Printf("Offset (x y): %d %d\n", (int)(hud->pos_x->value), (int)(hud->pos_y->value)); // Ordering. Com_Printf("Draw Order (z): %d\n", (int)hud->order->value); // Additional parameters. if (hud->num_params > 0) { int prefix_l = strlen(va("hud_%s_", hud->name)); Com_Printf("\nParameters:\n"); for (i=0; i < hud->num_params; i++) { if (strlen(hud->params[i]->name) > prefix_l) Com_Printf(" %-15s %s\n", hud->params[i]->name + prefix_l, hud->params[i]->string); } } } // // Find the elements with the max and min z-order. // void HUD_FindMaxMinOrder(int *max, int *min) { hud_t *hud = hud_huds; while(hud) { (*min) = ((int)hud->order->value < (*min)) ? (int)hud->order->value : (*min); (*max) = ((int)hud->order->value > (*max)) ? (int)hud->order->value : (*max); hud = hud->next; } } // // Find hud placement by string // return 0 if error // int HUD_FindPlace(hud_t *hud) { int i; hud_t *par; qbool out; char *t; // First try standard strings. for (i=0; i < num_snap_strings; i++) { if (!strcasecmp(hud->place->string, snap_strings[i])) { break; } } if (i < num_snap_strings) { // Found. hud->place_num = i+1; hud->place_hud = NULL; return 1; } // then try another HUD element out = true; t = hud->place->string; if (hud->place->string[0] == '@') { // place inside out = false; t++; } par = hud_huds; while (par) { if (par != hud && !strcmp(t, par->name)) { hud->place_outside = out; hud->place_hud = par; hud->place_num = HUD_PLACE_SCREEN; return 1; } par = par->next; } // No way. hud->place_num = HUD_PLACE_SCREEN; hud->place_hud = NULL; return 0; } // // Find hud alignment by strings // return 0 if error // int HUD_FindAlignX(hud_t *hud) { int i; // First try standard strings. for (i=0; i < num_align_strings_x; i++) { if (!strcasecmp(hud->align_x->string, align_strings_x[i])) { break; } } if (i < num_align_strings_x) { // Found. hud->align_x_num = i+1; return 1; } else { // Error. hud->align_x_num = HUD_ALIGN_LEFT; // left return 0; } } // // Find the alignment for a hud element. // int HUD_FindAlignY(hud_t *hud) { int i; // First try standard strings. for (i=0; i < num_align_strings_y; i++) { if (!strcasecmp(hud->align_y->string, align_strings_y[i])) { break; } } if (i < num_align_strings_y) { // Found. hud->align_y_num = i + 1; return 1; } else { // Error. hud->align_y_num = HUD_ALIGN_TOP; // Left. return 0; } } int Hud_HudCompare (const void *p1, const void *p2) { return strcmp((*((hud_t **) p1))->name, (*((hud_t **) p2))->name); } // // List hud elements // void HUD_List (void) { static hud_t *sorted_huds[256]; int i, count; hud_t *hud; #define MAX_SORTED_HUDS (sizeof (sorted_huds) / sizeof (sorted_huds[0])) for (hud = hud_huds, count = 0; hud && count < MAX_SORTED_HUDS; hud = hud->next, count++) sorted_huds[count] = hud; qsort (sorted_huds, count, sizeof (hud_t *), Hud_HudCompare); if (count == MAX_SORTED_HUDS) assert(!"count == MAX_SORTED_HUDS"); Com_Printf("name status\n"); Com_Printf("--------------- ------\n"); for (i = 0; i < count; i++) { hud = sorted_huds[i]; Com_Printf("%-15s %s\n", hud->name, hud->show->value ? "shown" : "hidden"); } } // // Show the specified hud element. // void HUD_Show_f (void) { hud_t *hud; if (Cmd_Argc() != 2) { Com_Printf("Usage: show [<name> | all]\n"); Com_Printf("Show given HUD element.\n"); Com_Printf("use \"show all\" to show all elements.\n"); Com_Printf("Current elements status:\n\n"); HUD_List(); return; } if (!strcasecmp(Cmd_Argv(1), "all")) { hud = hud_huds; while (hud) { Cvar_SetValue(hud->show, 1); hud = hud->next; } } else { hud = HUD_Find(Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } Cvar_SetValue(hud->show, 1); } } // // Hide the specified hud element. // void HUD_Hide_f (void) { hud_t *hud; if (Cmd_Argc() != 2) { Com_Printf("Usage: hide [<name> | all]\n"); Com_Printf("Hide given HUD element\n"); Com_Printf("use \"hide all\" to hide all elements.\n"); Com_Printf("Current elements status:\n\n"); HUD_List(); return; } if (!strcasecmp(Cmd_Argv(1), "all")) { hud = hud_huds; while (hud) { Cvar_SetValue(hud->show, 0); hud = hud->next; } } else { hud = HUD_Find(Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } Cvar_SetValue(hud->show, 0); } } // // Toggles specified hud element. // void HUD_Toggle_f (void) { hud_t *hud; if (Cmd_Argc() != 2) { Com_Printf("Usage: togglehud <name> | <variable>\n"); Com_Printf("Show/hide given HUD element, or toggles variable value.\n"); return; } hud = HUD_Find(Cmd_Argv(1)); if (!hud) { // look for cvar cvar_t *var = Cvar_Find(Cmd_Argv(1)); if (!var) { Com_Printf("No such element or variable: %s\n", Cmd_Argv(1)); return; } Cvar_Set (var, var->value ? "0" : "1"); return; } Cvar_Set (hud->show, hud->show->value ? "0" : "1"); } // // Move the specified hud element relative to placement/alignment. // void HUD_Move_f (void) { hud_t *hud; if (Cmd_Argc() != 4 && Cmd_Argc() != 2) { Com_Printf("Usage: move <name> [<x> <y>]\n"); Com_Printf("Set offset for given HUD element\n"); return; } hud = HUD_Find(Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } if (Cmd_Argc() == 2) { Com_Printf("Current %s offset is:\n", Cmd_Argv(1)); Com_Printf(" x: %s\n", hud->pos_x->string); Com_Printf(" y: %s\n", hud->pos_y->string); return; } Cvar_SetValue(hud->pos_x, atof(Cmd_Argv(2))); Cvar_SetValue(hud->pos_y, atof(Cmd_Argv(3))); } // // Resets a hud item to the center of the screen. // void HUD_Reset_f (void) { hud_t *hud = NULL; char *hudname = NULL; if (Cmd_Argc() != 2) { Com_Printf("Usage: reset <name>\n"); Com_Printf("Resets the position of the given HUD element to the center of the screen.\n"); return; } hudname = Cmd_Argv(1); hud = HUD_Find(hudname); if (!hud) { Com_Printf("No such HUD element %s.\n", hudname); return; } Cbuf_AddText(va("place %s screen\n", hudname)); Cbuf_AddText(va("move %s 0 0\n", hudname)); Cbuf_AddText(va("align %s center center\n", hudname)); } // // Reorders children so that they are place infront of their parent. // void HUD_ReorderChildren(void) { hud_t *hud = hud_huds; // Give all children a higher Z-order. while(hud) { if(hud->place_hud && hud->order->value <= hud->place_hud->order->value) { Cvar_SetValue(hud->order, hud->place_hud->order->value + 1); } hud = hud->next; } } // // Place the specified hud element. // void HUD_Place_f (void) { hud_t *hud; char temp[512]; if (Cmd_Argc() < 2 || Cmd_Argc() > 3) { Com_Printf("Usage: move <name> [<area>]\n"); Com_Printf("Place HUD element at given area.\n"); Com_Printf("\nPossible areas are:\n"); Com_Printf(" screen - screen area\n"); Com_Printf(" top - screen minus status bar\n"); Com_Printf(" view - view\n"); Com_Printf(" sbar - status bar\n"); Com_Printf(" ibar - inventory bar\n"); Com_Printf(" hbar - health bar\n"); Com_Printf(" sfree - status bar free area\n"); Com_Printf(" ifree - inventory bar free area\n"); Com_Printf(" hfree - health bar free area\n"); Com_Printf("You can also use any other HUD element as a base alignment. In such case you should specify area as:\n"); Com_Printf(" @elem - if you want to place\n"); Com_Printf(" it inside elem\n"); Com_Printf(" elem - if you want to place\n"); Com_Printf(" it outside elem\n"); Com_Printf("Examples:\n"); Com_Printf(" place fps view\n"); Com_Printf(" place fps @ping\n"); return; } hud = HUD_Find(Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } if (Cmd_Argc() == 2) { Com_Printf("Current %s placement: %s\n", hud->name, hud->place->string); return; } // Place with helper. strlcpy(temp, hud->place->string, sizeof(temp)); Cvar_Set(hud->place, Cmd_Argv(2)); if (!HUD_FindPlace(hud)) { Com_Printf("place: invalid area argument: %s\n", Cmd_Argv(2)); Cvar_Set(hud->place, temp); // Restore old value. } else { HUD_ReorderChildren(); } } // // Sets the z-order of a HUD element. // void HUD_Order_f (void) { int max = 0; int min = 0; char *option = NULL; hud_t *hud = NULL; if (Cmd_Argc() < 2 || Cmd_Argc() > 3) { Com_Printf("Usage: order <name> [<option>]\n"); Com_Printf("Set HUD element draw order\n"); Com_Printf("\nPossible values for option:\n"); Com_Printf(" # - An integer representing the order.\n"); Com_Printf(" backward - Send the element backwards in the order.\n"); Com_Printf(" forward - Send the element forward in the order.\n"); Com_Printf(" front - Bring the element to the front.\n"); Com_Printf(" back - Put the element at the far back.\n"); return; } hud = HUD_Find (Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } if (Cmd_Argc() == 2) { Com_Printf("Current order for %s is:\n", Cmd_Argv(1)); Com_Printf(" order: %d\n", (int)hud->order->value); return; } option = Cmd_Argv(2); HUD_FindMaxMinOrder (&max, &min); if (!strncasecmp (option, "backward", 8)) { // Send backward one step. Cvar_SetValue(hud->order, (int)hud->order->value - 1); } else if (!strncasecmp (option, "forward", 7)) { // Move forward one step. Cvar_SetValue(hud->order, (int)hud->order->value + 1); } else if (!strncasecmp (option, "front", 5)) { // Bring to front. Cvar_SetValue(hud->order, max + 1); } else if (!strncasecmp (option, "back", 8)) { // Send to far back. Cvar_SetValue(hud->order, min - 1); } else { // Order # Cvar_SetValue (hud->order, atoi(Cmd_Argv(2))); } } // // Align the specified hud element // void HUD_Align_f (void) { hud_t *hud; if (Cmd_Argc() != 4 && Cmd_Argc() != 2) { Com_Printf("Usage: align <name> [<ax> <ay>]\n"); Com_Printf("Set HUD element alignment\n"); Com_Printf("\nPossible values for ax are:\n"); Com_Printf(" left - left area edge\n"); Com_Printf(" center - area center\n"); Com_Printf(" right - right area edge\n"); Com_Printf(" before - before area (left)\n"); Com_Printf(" after - after area (right)\n"); Com_Printf("\nPossible values for ay are:\n"); Com_Printf(" top - screen top\n"); Com_Printf(" center - screen center\n"); Com_Printf(" bottom - screen bottom\n"); Com_Printf(" before - before area (top)\n"); Com_Printf(" after - after area (bottom)\n"); Com_Printf(" console - below console\n"); return; } hud = HUD_Find(Cmd_Argv(1)); if (!hud) { Com_Printf("No such element: %s\n", Cmd_Argv(1)); return; } if (Cmd_Argc() == 2) { Com_Printf("Current alignment for %s is:\n", Cmd_Argv(1)); Com_Printf(" horizontal (x): %s\n", hud->align_x->string); Com_Printf(" vertical (y): %s\n", hud->align_y->string); return; } // validate and set Cvar_Set(hud->align_x, Cmd_Argv(2)); if (!HUD_FindAlignX(hud)) Com_Printf("align: invalid X alignment: %s\n", Cmd_Argv(2)); Cvar_Set(hud->align_y, Cmd_Argv(3)); if (!HUD_FindAlignY(hud)) Com_Printf("align: invalid Y alignment: %s\n", Cmd_Argv(3)); } // // Recalculate all elements // should be called if some HUD parameters (like place) // were changed directly by vars, not comands (like place) // - after execing cfg or sth // void HUD_Recalculate(void) { hud_t *hud = hud_huds; while (hud) { HUD_FindPlace(hud); HUD_FindAlignX(hud); HUD_FindAlignY(hud); hud = hud->next; } } void HUD_Recalculate_f(void) { HUD_Recalculate(); } void HUD_Export_f(void) { char line[8192]; qhandle_t handle; hud_t *hud; cvar_t *var; int i; char fname[64]; char fdesc[256]; cmdfuncs->Argv(1, fname, sizeof(fname)); cmdfuncs->Argv(2, fdesc, sizeof(fdesc)); if (!*fdesc) snprintf(fdesc, sizeof(fdesc), "%s", fname); snprintf(line, sizeof(line), "configs/hud_%s.cfg", fname); if (filefuncs->Open(line, &handle, 2) < 0) Com_Printf("Couldn't open %s\n", line); else { //FIXME: should print the result of an flocate, but plugins are not really aware of that stuff. Com_Printf("Writing %s\n", line); snprintf(line, sizeof(line), "//desc:%s\n\n//hud cvar settings, for use with FTEQW's ezhud plugin.\n", fdesc); filefuncs->Write(handle, line, strlen(line)); for (hud = hud_huds; hud; hud = hud->next) { for (i = 0; i < hud->num_params; i++) { var = hud->params[i]; //fixme: deal with " and \n snprintf(line, sizeof(line), "set %s \"%s\"\n", var->name, var->string); filefuncs->Write(handle, line, strlen(line)); } } filefuncs->Close(handle); } } // // Initialize HUD. // void HUD_Init(void) { // from hud.c, doesn't suit anywhere void HUD_Inputlag_hit_f(void); // Commands. Cmd_AddCommand ("show", HUD_Show_f); Cmd_AddCommand ("hide", HUD_Hide_f); Cmd_AddCommand ("move", HUD_Move_f); Cmd_AddCommand ("place", HUD_Place_f); Cmd_AddCommand ("reset", HUD_Reset_f); Cmd_AddCommand ("order", HUD_Order_f); Cmd_AddCommand ("togglehud", HUD_Toggle_f); Cmd_AddCommand ("align", HUD_Align_f); Cmd_AddCommand ("hud_recalculate", HUD_Recalculate_f); Cmd_AddCommand ("hud_export", HUD_Export_f); // Register the hud items. CommonDraw_Init(); // Sort the elements. HUD_Sort(); } // // Calculate frame extents. // void HUD_CalcFrameExtents(hud_t *hud, int width, int height, // In. int *frame_left, int *frame_right, int *frame_top, int *frame_bottom) // Out. { if ((hud->flags & HUD_NO_GROW) && hud->frame->value != 2) { *frame_left = *frame_right = *frame_top = *frame_bottom = 0; return; } if (hud->frame->value == 2) // Treat text box separately. { int ax = (width % 16); int ay = (height % 8); *frame_left = 8 + ax / 2; *frame_top = 8 + ay / 2; *frame_right = 8 + ax - ax / 2; *frame_bottom = 8 + ay - ay / 2; } else if (hud->frame->value > 0 && hud->frame->value <= 1) { int frame_x, frame_y; frame_x = 2; frame_y = 2; if (width > 8) { frame_x <<= 1; } if (height > 8) { frame_y <<= 1; } *frame_left = frame_x; *frame_right = frame_x; *frame_top = frame_y; *frame_bottom = frame_y; } else { // No frame at all. *frame_left = *frame_right = *frame_top = *frame_bottom = 0; } } void HUD_OnChangeFrameColor(cvar_t *var, char *oldval) { // Converts "red" into "255 0 0", etc. or returns input as it was. const char *new_color = ColorNameToRGBString (var->string); char buf[256], buf2[128]; size_t hudname_len; hud_t* hud_elem; byte* b_colors; hudname_len = min (sizeof (buf), strlen (var->name) - strlen ("_frame_color") - strlen ("hud_") + 1); strlcpy (buf, var->name + 4, hudname_len); hud_elem = HUD_Find (buf); strlcpy(buf2,new_color,sizeof(buf2)); b_colors = StringToRGB (buf2); memcpy (hud_elem->frame_color_cache, b_colors, sizeof (byte) * 3); } // // Draw frame for HUD element. // void HUD_DrawFrame(hud_t *hud, int x, int y, int width, int height) { if (!hud->frame->value) return; if (hud->frame->value > 0 && hud->frame->value <= 1) { hud->frame_color_cache[3] = (byte)(255 * hud->frame->value); Draw_AlphaFillRGB(x, y, width, height, hud->frame_color_cache[0], hud->frame_color_cache[1], hud->frame_color_cache[2], hud->frame_color_cache[3]); return; } else { switch ((int)(hud->frame->value)) { case 2: // Text box. Draw_TextBox(x, y, width/8-2, height/8-2); break; default: // More will probably come. break; } } } // // Calculate element placement. // qbool HUD_PrepareDrawByName(char *name, int width, int height, // In. int *ret_x, int *ret_y) // Out (Position). { hud_t *hud = HUD_Find(name); if (hud == NULL) { return false; // error in C code } return HUD_PrepareDraw(hud, width, height, ret_x, ret_y); } // // Calculate object extents and draws frame if needed. // qbool HUD_PrepareDraw(hud_t *hud, int width, int height, // In. int *ret_x, int *ret_y) // Out (Position). { extern vrect_t scr_vrect; int x, y; int frame_left, frame_right, frame_top, frame_bottom; // Frame left, right, top and bottom. int area_x, area_y, area_width, area_height; // Area coordinates & sizes to align. int bounds_x, bounds_y, bounds_width, bounds_height; // Bounds to draw within. // Don't show the hud element. if (cls.state < hud->min_state || !hud->show->value) { return false; } HUD_CalcFrameExtents(hud, width, height, &frame_left, &frame_right, &frame_top, &frame_bottom); width += frame_left + frame_right; height += frame_top + frame_bottom; // // Placement. // switch (hud->place_num) { default: case HUD_PLACE_SCREEN: bounds_x = bounds_y = 0; bounds_width = vid.width; bounds_height = vid.height; break; case HUD_PLACE_TOP: // Top = screen - sbar bounds_x = bounds_y = 0; bounds_width = vid.width; bounds_height = vid.height - sb_lines; break; case HUD_PLACE_VIEW: bounds_x = scr_vrect.x; bounds_y = scr_vrect.y; bounds_width = scr_vrect.width; bounds_height = scr_vrect.height; break; case HUD_PLACE_SBAR: bounds_x = 0; bounds_y = vid.height - sb_lines; bounds_width = sbar_last_width; bounds_height = sb_lines; break; case HUD_PLACE_IBAR: bounds_width = sbar_last_width; bounds_height = max(sb_lines - SBAR_HEIGHT, 0); bounds_x = 0; bounds_y = vid.height - sb_lines; break; case HUD_PLACE_HBAR: bounds_width = sbar_last_width; bounds_height = min(SBAR_HEIGHT, sb_lines); bounds_x = 0; bounds_y = vid.height - bounds_height; break; case HUD_PLACE_SFREE: bounds_x = sbar_last_width; bounds_y = vid.height - sb_lines; bounds_width = vid.width - sbar_last_width; bounds_height = sb_lines; break; case HUD_PLACE_IFREE: bounds_width = vid.width - sbar_last_width; bounds_height = max(sb_lines - SBAR_HEIGHT, 0); bounds_x = sbar_last_width; bounds_y = vid.height - sb_lines; break; case HUD_PLACE_HFREE: bounds_width = vid.width - sbar_last_width; bounds_height = min(SBAR_HEIGHT, sb_lines); bounds_x = sbar_last_width; bounds_y = vid.height - bounds_height; break; } if (hud->place_hud == NULL) { // Accepted boundaries are our area. area_x = bounds_x; area_y = bounds_y; area_width = bounds_width; area_height = bounds_height; } else { // Out area is our parent area. area_x = hud->place_hud->lx; area_y = hud->place_hud->ly; area_width = hud->place_hud->lw; area_height = hud->place_hud->lh; if (hud->place_outside) { area_x -= hud->place_hud->al; area_y -= hud->place_hud->at; area_width += hud->place_hud->al + hud->place_hud->ar; area_height += hud->place_hud->at + hud->place_hud->ab; } } // // Horizontal pos. // switch (hud->align_x_num) { default: case HUD_ALIGN_LEFT: x = area_x; break; case HUD_ALIGN_CENTER: x = area_x + (area_width - width) / 2; break; case HUD_ALIGN_RIGHT: x = area_x + area_width - width; break; case HUD_ALIGN_BEFORE: x = area_x - width; break; case HUD_ALIGN_AFTER: x = area_x + area_width; break; } x += hud->pos_x->value; // // Vertical pos. // switch (hud->align_y_num) { default: case HUD_ALIGN_TOP: y = area_y; break; case HUD_ALIGN_CENTER: y = area_y + (area_height - height) / 2; break; case HUD_ALIGN_BOTTOM: y = area_y + area_height - height; break; case HUD_ALIGN_BEFORE: y = area_y - height; break; case HUD_ALIGN_AFTER: y = area_y + area_height; break; case HUD_ALIGN_CONSOLE: y = max(area_y, scr_con_current); break; } y += hud->pos_y->value; if (ret_x) { // Draw frame. HUD_DrawFrame(hud, x, y, width, height); // Assign values. *ret_x = x + frame_left; *ret_y = y + frame_top; } // Remember values for children. hud->lx = x + frame_left; hud->ly = y + frame_top; hud->lw = width - frame_left - frame_right; hud->lh = height - frame_top - frame_bottom; hud->al = frame_left; hud->ar = frame_right; hud->at = frame_top; hud->ab = frame_bottom; // Check if we're supposed to draw the entire item or just the outline/frame. // (If we're in hud editor align/place mode) if(!HUD_Editor_ConfirmDraw(hud)) { return false; } // Remember drawing sequence. hud->last_draw_sequence = host_screenupdatecount; return true; } // // Creates a HUD variable based on a name. // cvar_t * HUD_CreateVar(char *hud_name, char *subvar, char *value) { char buf[128]; snprintf (buf, sizeof (buf), "hud_%s_%s", hud_name, subvar); return cvarfuncs->GetNVFDG(buf, value, 0, NULL, "ezhud"); } // // Onchange for when z-order changes for a hud element. Resorts the elements. // void HUD_OnChangeOrder(cvar_t *var, char *val) { doreorder = true; } // // Registers a new HUD element to the list of HUD elements. // hud_t * HUD_Register(char *name, char *var_alias, char *description, int flags, cactive_t min_state, int draw_order, hud_func_type draw_func, char *show, char *place, char *align_x, char *align_y, char *pos_x, char *pos_y, char *frame, char *frame_color, char *item_opacity, char *params, ...) { int i; va_list argptr; hud_t *hud; char *subvar; // We want to include Frame, frame_color, item_opacity in the list of // available cvar's for the user also. If any additional cvars that // common for all hud elements are added this needs to be increased. int num_params = 3; // Allocate room for the HUD. hud = (hud_t *) Q_malloc(sizeof(hud_t)); memset(hud, 0, sizeof(hud_t)); hud->next = hud_huds; hud_huds = hud; hud->min_state = min_state; hud->draw_func = draw_func; // Name. hud->name = (char *) Q_malloc(strlen(name)+1); strcpy(hud->name, name); // Description. hud->description = (char *) Q_malloc(strlen(description)+1); strcpy(hud->description, description); // Count the number of params. subvar = params; va_start (argptr, params); while(subvar) { num_params++; subvar = va_arg(argptr, char *); } va_end (argptr); // Allocate the params array. hud->params = Q_calloc(num_params, sizeof(cvar_t *)); // Set flags. hud->flags = flags; Cmd_AddCommand(name, HUD_Func_f); // // Create standard variables. // // // Ordering // { char order[18]; snprintf (order, sizeof(order), "%d", draw_order); hud->order = HUD_CreateVar(name, "order", order); hud->order->callback = HUD_OnChangeOrder; } // // Place. // hud->place = HUD_CreateVar(name, "place", place); i = HUD_FindPlace(hud); if (i == 0) { // Probably parent should be registered earlier. // (This doesn't matter, since we'll re-place all elements after // all the elements have been registered) hud->place_num = 0; hud->place_hud = NULL; } // // Show. // if (show) { hud->show = HUD_CreateVar(name, "show", show); if (flags & HUD_PLUSMINUS) { // Add plus and minus commands. Cmd_AddCommand(Q_strdup(va("+hud_%s", name)), HUD_Plus_f); Cmd_AddCommand(Q_strdup(va("-hud_%s", name)), HUD_Minus_f); } } else { hud->flags |= HUD_NO_SHOW; } // // X align & pos. // if (pos_x && align_x) { hud->pos_x = HUD_CreateVar(name, "pos_x", pos_x); hud->align_x = HUD_CreateVar(name, "align_x", align_x); } else { hud->flags |= HUD_NO_POS_X; } // // Y align & pos. // if (pos_y && align_y) { hud->pos_y = HUD_CreateVar(name, "pos_y", pos_y); hud->align_y = HUD_CreateVar(name, "align_y", align_y); } else { hud->flags |= HUD_NO_POS_Y; } // // Frame. // if (frame) { hud->frame = HUD_CreateVar(name, "frame", frame); hud->params[hud->num_params++] = hud->frame; hud->frame_color = HUD_CreateVar(name, "frame_color", frame_color); hud->frame_color->callback = HUD_OnChangeFrameColor; hud->params[hud->num_params++] = hud->frame_color; } else { hud->flags |= HUD_NO_FRAME; } // // Item Opacity. // { hud->opacity = HUD_CreateVar(name, "item_opacity", (item_opacity) ? item_opacity : "0.99"); hud->flags |= HUD_OPACITY; hud->params[hud->num_params++] = hud->opacity; } // // Create parameters. // subvar = params; va_start (argptr, params); while (subvar) { char *value = va_arg(argptr, char *); if (value == NULL || hud->num_params >= HUD_MAX_PARAMS || hud->num_params >= num_params) { Sys_Error("HUD_Register: HUD_MAX_PARAMS overflow"); } hud->params[hud->num_params] = HUD_CreateVar(name, subvar, value); hud->num_params ++; subvar = va_arg(argptr, char *); } va_end (argptr); return hud; } void HUD_ParamsCleanup(void) { // int i = 0; hud_t *hud = hud_huds; while (hud) { /* for (i=0; i < hud->num_params; i++) { Cvar_Delete(hud->params[i]->name); } */ Q_free(hud->params); hud = hud->next; } } // // Find element in list. // hud_t * HUD_Find(char *name) { hud_t *hud = hud_huds; while (hud) { if (!strcasecmp(hud->name, name)) { return hud; } hud = hud->next; } return NULL; } // // Retrieve hud cvar. // cvar_t *HUD_FindVar(hud_t *hud, char *subvar) { int i; char buf[128]; snprintf(buf, sizeof(buf), "hud_%s_%s", hud->name, subvar); for (i=0; i < hud->num_params; i++) { if (!strcmp(buf, hud->params[i]->name)) { return hud->params[i]; } } return NULL; } // // Draws single HUD element. // void HUD_DrawObject(hud_t *hud) { extern qbool sb_showscores, sb_showteamscores; // Already tried to draw this frame. if (hud->last_try_sequence == host_screenupdatecount) { return; } hud->last_try_sequence = host_screenupdatecount; // Check if we should draw this. if (!hud->show->value) { return; } if (cls.state < hud->min_state) { return; } if (cl.intermission == 1 && !(hud->flags & HUD_ON_INTERMISSION)) { return; } if (cl.intermission == 2 && !(hud->flags & HUD_ON_FINALE)) { return; } if ((sb_showscores || sb_showteamscores) && !(hud->flags & HUD_ON_SCORES)) { return; } if (hud->place_hud) { // Parent should be drawn it should be first. HUD_DrawObject(hud->place_hud); // If parent was not drawn, we refuse to draw too if (hud->place_hud->last_draw_sequence < host_screenupdatecount) { return; } } // // Let the HUD element draw itself - updates last_draw_sequence itself. // Draw_SetOverallAlpha(hud->opacity->value); hud->draw_func(hud); Draw_SetOverallAlpha(1.0); // last_draw_sequence is update by HUD_PrepareDraw // if object was succesfully drawn (wasn't outside area etc..) } // // Draw all active elements. // void HUD_Draw(void) { hud_t *hud; if (doreorder) { doreorder = false; HUD_ReorderChildren(); HUD_Sort(); } // Only draw the hud once in multiview. /* if (cl_multiview.integer && cls.mvdplayback) { if (CURRVIEW != 1) { return; } } */ if (mvd_autohud->ival && !autohud_loaded) { HUD_AutoLoad_MVD(mvd_autohud->ival); Com_DPrintf("Loading AUTOHUD...\n"); autohud_loaded = true; } /* if (scr_newHud->value == 0) { return; } */ hud = hud_huds; HUD_BeforeDraw(); while (hud) { // Draw. HUD_DrawObject(hud); // Go to next. hud = hud->next; } HUD_AfterDraw(); } // // Compares two hud elements. // int HUD_OrderFunc(const void * p_h1, const void * p_h2) { const hud_t *h1 = *((hud_t **)p_h1); const hud_t *h2 = *((hud_t **)p_h2); return (int)h1->order->value - (int)h2->order->value; } // // Last phase of initialization. // void HUD_Sort(void) { // Sort elements based on their draw order. int i; hud_t *huds[MAX_HUD_ELEMENTS]; int count = 0; hud_t *hud; // Copy to table. hud = hud_huds; while (hud) { huds[count++] = hud; hud = hud->next; } if (count <= 0) return; // Sort table. qsort(huds, count, sizeof(huds[0]), HUD_OrderFunc); // Back to list. hud_huds = huds[0]; hud = hud_huds; hud->next = NULL; for (i=1; i < count; i++) { hud->next = huds[i]; hud = hud->next; hud->next = NULL; } // Recalculate elements so vars are parsed. HUD_Recalculate(); }