// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. // Copyright (C) 2014-2023 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file lua_hudlib_drawlist.c /// \brief a data structure for managing cached drawlists for the Lua hud lib #include "lua_hudlib_drawlist.h" #include #include "v_video.h" #include "z_zone.h" enum drawitem_e { DI_Draw = 0, DI_DrawScaled, DI_DrawStretched, DI_DrawCropped, DI_DrawNum, DI_DrawPaddedNum, DI_DrawFill, DI_DrawString, DI_DrawNameTag, DI_DrawScaledNameTag, DI_DrawLevelTitle, DI_FadeScreen, DI_MAX, }; // A single draw item with all possible arguments needed for a draw call. typedef struct drawitem_s { enum drawitem_e type; fixed_t x; fixed_t y; fixed_t w; fixed_t h; INT32 c; fixed_t scale; fixed_t hscale; fixed_t vscale; patch_t *patch; INT32 flags; UINT16 basecolor; UINT16 outlinecolor; UINT8 *colormap; UINT8 *basecolormap; UINT8 *outlinecolormap; fixed_t sx; fixed_t sy; INT32 num; INT32 digits; const char *str; UINT16 color; UINT8 strength; INT32 align; } drawitem_t; // The internal structure of a drawlist. struct huddrawlist_s { drawitem_t *items; size_t items_capacity; size_t items_len; char *strbuf; size_t strbuf_capacity; size_t strbuf_len; }; // alignment types for v.drawString enum align { align_left = 0, align_center, align_right, align_fixed, align_fixedcenter, align_fixedright, align_small, align_smallfixed, align_smallfixedcenter, align_smallfixedright, align_smallcenter, align_smallright, align_smallthin, align_smallthincenter, align_smallthinright, align_smallthinfixed, align_smallthinfixedcenter, align_smallthinfixedright, align_thin, align_thinfixed, align_thinfixedcenter, align_thinfixedright, align_thincenter, align_thinright }; huddrawlist_h LUA_HUD_CreateDrawList(void) { huddrawlist_h drawlist; drawlist = (huddrawlist_h) Z_Calloc(sizeof(struct huddrawlist_s), PU_STATIC, NULL); drawlist->items = NULL; drawlist->items_capacity = 0; drawlist->items_len = 0; drawlist->strbuf = NULL; drawlist->strbuf_capacity = 0; drawlist->strbuf_len = 0; return drawlist; } void LUA_HUD_ClearDrawList(huddrawlist_h list) { // rather than deallocate, we'll just save the existing allocation and empty // it out for reuse // this memset probably isn't necessary if (list->items) { memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity); } list->items_len = 0; if (list->strbuf) { list->strbuf[0] = 0; } list->strbuf_len = 0; } void LUA_HUD_DestroyDrawList(huddrawlist_h list) { if (list == NULL) return; if (list->items) { Z_Free(list->items); } Z_Free(list); } boolean LUA_HUD_IsDrawListValid(huddrawlist_h list) { if (!list) return false; // that's all we can really do to check the validity of the handle right now return true; } static size_t AllocateDrawItem(huddrawlist_h list) { if (!list) I_Error("can't allocate draw item: invalid list"); if (list->items_capacity <= list->items_len + 1) { if (list->items_capacity == 0) list->items_capacity = 128; else list->items_capacity *= 2; list->items = (drawitem_t *) Z_Realloc(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL); } return list->items_len++; } // copy string to list's internal string buffer // lua can deallocate the string before we get to use it, so it's important to // keep our own copy static const char *CopyString(huddrawlist_h list, const char* str) { size_t lenstr; if (!list) I_Error("can't allocate string; invalid list"); lenstr = strlen(str); if (list->strbuf_capacity <= list->strbuf_len + lenstr + 1) { const char *old_offset = list->strbuf; size_t i; if (list->strbuf_capacity == 0) list->strbuf_capacity = 256; else list->strbuf_capacity *= 2; list->strbuf = (char*) Z_Realloc(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL); // align the string pointers to make sure old pointers don't point towards invalid addresses // this is necessary since Z_ReallocAlign might actually move the string buffer in memory for (i = 0; i < list->items_len; i++) { list->items[i].str += list->strbuf - old_offset; } } const char *result = (const char *) &list->strbuf[list->strbuf_len]; strncpy(&list->strbuf[list->strbuf_len], str, lenstr + 1); list->strbuf_len += lenstr + 1; return result; } void LUA_HUD_AddDraw( huddrawlist_h list, INT32 x, INT32 y, patch_t *patch, INT32 flags, UINT8 *colormap ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_Draw; item->x = x; item->y = y; item->patch = patch; item->flags = flags; item->colormap = colormap; } void LUA_HUD_AddDrawScaled( huddrawlist_h list, fixed_t x, fixed_t y, fixed_t scale, patch_t *patch, INT32 flags, UINT8 *colormap ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawScaled; item->x = x; item->y = y; item->scale = scale; item->patch = patch; item->flags = flags; item->colormap = colormap; } void LUA_HUD_AddDrawStretched( huddrawlist_h list, fixed_t x, fixed_t y, fixed_t hscale, fixed_t vscale, patch_t *patch, INT32 flags, UINT8 *colormap ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawStretched; item->x = x; item->y = y; item->hscale = hscale; item->vscale = vscale; item->patch = patch; item->flags = flags; item->colormap = colormap; } void LUA_HUD_AddDrawCropped( huddrawlist_h list, fixed_t x, fixed_t y, fixed_t hscale, fixed_t vscale, patch_t *patch, INT32 flags, UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawCropped; item->x = x; item->y = y; item->hscale = hscale; item->vscale = vscale; item->patch = patch; item->flags = flags; item->colormap = colormap; item->sx = sx; item->sy = sy; item->w = w; item->h = h; } void LUA_HUD_AddDrawNum( huddrawlist_h list, INT32 x, INT32 y, INT32 num, INT32 flags ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawNum; item->x = x; item->y = y; item->num = num; item->flags = flags; } void LUA_HUD_AddDrawPaddedNum( huddrawlist_h list, INT32 x, INT32 y, INT32 num, INT32 digits, INT32 flags ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawPaddedNum; item->x = x; item->y = y; item->num = num; item->digits = digits; item->flags = flags; } void LUA_HUD_AddDrawFill( huddrawlist_h list, INT32 x, INT32 y, INT32 w, INT32 h, INT32 c ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawFill; item->x = x; item->y = y; item->w = w; item->h = h; item->c = c; } void LUA_HUD_AddDrawString( huddrawlist_h list, fixed_t x, fixed_t y, const char *str, INT32 flags, INT32 align ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawString; item->x = x; item->y = y; item->str = CopyString(list, str); item->flags = flags; item->align = align; } void LUA_HUD_AddDrawNameTag( huddrawlist_h list, INT32 x, INT32 y, const char *str, INT32 flags, UINT16 basecolor, UINT16 outlinecolor, UINT8 *basecolormap, UINT8 *outlinecolormap ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawNameTag; item->x = x; item->y = y; item->str = CopyString(list, str); item->flags = flags; item->basecolor = basecolor; item->outlinecolor = outlinecolor; item->basecolormap = basecolormap; item->outlinecolormap = outlinecolormap; } void LUA_HUD_AddDrawScaledNameTag( huddrawlist_h list, fixed_t x, fixed_t y, const char *str, INT32 flags, fixed_t scale, UINT16 basecolor, UINT16 outlinecolor, UINT8 *basecolormap, UINT8 *outlinecolormap ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawScaledNameTag; item->x = x; item->y = y; item->str = CopyString(list, str); item->flags = flags; item->scale = scale; item->basecolor = basecolor; item->outlinecolor = outlinecolor; item->basecolormap = basecolormap; item->outlinecolormap = outlinecolormap; } void LUA_HUD_AddDrawLevelTitle( huddrawlist_h list, INT32 x, INT32 y, const char *str, INT32 flags ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_DrawLevelTitle; item->x = x; item->y = y; item->str = CopyString(list, str); item->flags = flags; } void LUA_HUD_AddFadeScreen( huddrawlist_h list, UINT16 color, UINT8 strength ) { size_t i = AllocateDrawItem(list); drawitem_t *item = &list->items[i]; item->type = DI_FadeScreen; item->color = color; item->strength = strength; } void LUA_HUD_DrawList(huddrawlist_h list) { size_t i; if (!list) I_Error("HUD drawlist invalid"); if (list->items_len <= 0) return; if (!list->items) I_Error("HUD drawlist->items invalid"); for (i = 0; i < list->items_len; i++) { drawitem_t *item = &list->items[i]; switch (item->type) { case DI_Draw: V_DrawFixedPatch(item->x<y<flags, item->patch, item->colormap); break; case DI_DrawScaled: V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap); break; case DI_DrawStretched: V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap); break; case DI_DrawCropped: V_DrawCroppedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap, item->sx, item->sy, item->w, item->h); break; case DI_DrawNum: V_DrawTallNum(item->x, item->y, item->flags, item->num); break; case DI_DrawPaddedNum: V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits); break; case DI_DrawFill: V_DrawFill(item->x, item->y, item->w, item->h, item->c); break; case DI_DrawString: switch(item->align) { // hu_font case align_left: V_DrawString(item->x, item->y, item->flags, item->str); break; case align_center: V_DrawCenteredString(item->x, item->y, item->flags, item->str); break; case align_right: V_DrawRightAlignedString(item->x, item->y, item->flags, item->str); break; case align_fixed: V_DrawStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_fixedcenter: V_DrawCenteredStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_fixedright: V_DrawRightAlignedStringAtFixed(item->x, item->y, item->flags, item->str); break; // hu_font, 0.5x scale case align_small: V_DrawSmallString(item->x, item->y, item->flags, item->str); break; case align_smallfixed: V_DrawSmallStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_smallfixedcenter: V_DrawCenteredSmallStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_smallfixedright: V_DrawRightAlignedSmallStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_smallcenter: V_DrawCenteredSmallString(item->x, item->y, item->flags, item->str); break; case align_smallright: V_DrawRightAlignedSmallString(item->x, item->y, item->flags, item->str); break; case align_smallthin: V_DrawSmallThinString(item->x, item->y, item->flags, item->str); break; case align_smallthincenter: V_DrawCenteredSmallThinString(item->x, item->y, item->flags, item->str); break; case align_smallthinright: V_DrawRightAlignedSmallThinString(item->x, item->y, item->flags, item->str); break; case align_smallthinfixed: V_DrawSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_smallthinfixedcenter: V_DrawCenteredSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_smallthinfixedright: V_DrawRightAlignedSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); break; // tny_font case align_thin: V_DrawThinString(item->x, item->y, item->flags, item->str); break; case align_thincenter: V_DrawCenteredThinString(item->x, item->y, item->flags, item->str); break; case align_thinright: V_DrawRightAlignedThinString(item->x, item->y, item->flags, item->str); break; case align_thinfixed: V_DrawThinStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_thinfixedcenter: V_DrawCenteredThinStringAtFixed(item->x, item->y, item->flags, item->str); break; case align_thinfixedright: V_DrawRightAlignedThinStringAtFixed(item->x, item->y, item->flags, item->str); break; } break; case DI_DrawNameTag: V_DrawNameTag(item->x, item->y, item->flags, FRACUNIT, item->basecolormap, item->outlinecolormap, item->str); break; case DI_DrawScaledNameTag: V_DrawNameTag(FixedInt(item->x), FixedInt(item->y), item->flags, item->scale, item->basecolormap, item->outlinecolormap, item->str); break; case DI_DrawLevelTitle: V_DrawLevelTitle(item->x, item->y, item->flags, item->str); break; case DI_FadeScreen: V_DrawFadeScreen(item->color, item->strength); break; default: I_Error("can't draw draw list item: invalid draw list item type"); continue; } } }